1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/dom/HTMLTextAreaElement.h"
8
9 #include "mozAutoDocUpdate.h"
10 #include "mozilla/AsyncEventDispatcher.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/dom/FormData.h"
13 #include "mozilla/dom/HTMLTextAreaElementBinding.h"
14 #include "mozilla/dom/MutationEventBinding.h"
15 #include "mozilla/EventDispatcher.h"
16 #include "mozilla/EventStates.h"
17 #include "mozilla/MappedDeclarations.h"
18 #include "mozilla/MouseEvents.h"
19 #include "mozilla/PresState.h"
20 #include "mozilla/TextControlState.h"
21 #include "nsAttrValueInlines.h"
22 #include "nsBaseCommandController.h"
23 #include "nsContentCID.h"
24 #include "nsContentCreatorFunctions.h"
25 #include "nsError.h"
26 #include "nsFocusManager.h"
27 #include "nsIConstraintValidation.h"
28 #include "nsIControllers.h"
29 #include "mozilla/dom/Document.h"
30 #include "nsIFormControlFrame.h"
31 #include "nsIFormControl.h"
32 #include "nsIFrame.h"
33 #include "nsITextControlFrame.h"
34 #include "nsLayoutUtils.h"
35 #include "nsLinebreakConverter.h"
36 #include "nsMappedAttributes.h"
37 #include "nsPIDOMWindow.h"
38 #include "nsPresContext.h"
39 #include "nsReadableUtils.h"
40 #include "nsStyleConsts.h"
41 #include "nsTextControlFrame.h"
42 #include "nsXULControllers.h"
43
44 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
45
46 namespace mozilla::dom {
47
HTMLTextAreaElement(already_AddRefed<mozilla::dom::NodeInfo> && aNodeInfo,FromParser aFromParser)48 HTMLTextAreaElement::HTMLTextAreaElement(
49 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
50 FromParser aFromParser)
51 : TextControlElement(std::move(aNodeInfo), aFromParser,
52 FormControlType::Textarea),
53 mValueChanged(false),
54 mLastValueChangeWasInteractive(false),
55 mHandlingSelect(false),
56 mDoneAddingChildren(!aFromParser),
57 mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
58 mDisabledChanged(false),
59 mCanShowInvalidUI(true),
60 mCanShowValidUI(true),
61 mIsPreviewEnabled(false),
62 mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
63 mState(TextControlState::Construct(this)) {
64 AddMutationObserver(this);
65
66 // Set up our default state. By default we're enabled (since we're
67 // a control type that can be disabled but not actually disabled
68 // right now), optional, and valid. We are NOT readwrite by default
69 // until someone calls UpdateEditableState on us, apparently! Also
70 // by default we don't have to show validity UI and so forth.
71 AddStatesSilently(NS_EVENT_STATE_ENABLED | NS_EVENT_STATE_OPTIONAL |
72 NS_EVENT_STATE_VALID);
73 }
74
~HTMLTextAreaElement()75 HTMLTextAreaElement::~HTMLTextAreaElement() {
76 mState->Destroy();
77 mState = nullptr;
78 }
79
80 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLTextAreaElement)
81
82 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLTextAreaElement,
83 TextControlElement)
84 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
85 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
86 if (tmp->mState) {
87 tmp->mState->Traverse(cb);
88 }
89 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
90
91 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLTextAreaElement,
92 TextControlElement)
93 NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
94 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
95 if (tmp->mState) {
96 tmp->mState->Unlink();
97 }
98 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
99
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement,TextControlElement,nsIMutationObserver,nsIConstraintValidation)100 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement,
101 TextControlElement,
102 nsIMutationObserver,
103 nsIConstraintValidation)
104
105 // nsIDOMHTMLTextAreaElement
106
107 nsresult HTMLTextAreaElement::Clone(dom::NodeInfo* aNodeInfo,
108 nsINode** aResult) const {
109 *aResult = nullptr;
110 RefPtr<HTMLTextAreaElement> it = new (aNodeInfo->NodeInfoManager())
111 HTMLTextAreaElement(do_AddRef(aNodeInfo));
112
113 nsresult rv = const_cast<HTMLTextAreaElement*>(this)->CopyInnerTo(it);
114 NS_ENSURE_SUCCESS(rv, rv);
115
116 if (mValueChanged) {
117 // Set our value on the clone.
118 nsAutoString value;
119 GetValueInternal(value, true);
120
121 // SetValueInternal handles setting mValueChanged for us
122 if (NS_WARN_IF(
123 NS_FAILED(rv = it->SetValueInternal(
124 value, {ValueSetterOption::SetValueChanged})))) {
125 return rv;
126 }
127 }
128
129 it->SetLastValueChangeWasInteractive(mLastValueChangeWasInteractive);
130 it.forget(aResult);
131 return NS_OK;
132 }
133
134 // nsIContent
135
Select()136 void HTMLTextAreaElement::Select() {
137 if (FocusState() != FocusTristate::eUnfocusable) {
138 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
139 fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
140 }
141 }
142
143 SetSelectionRange(0, UINT32_MAX, mozilla::dom::Optional<nsAString>(),
144 IgnoreErrors());
145 }
146
147 NS_IMETHODIMP
SelectAll(nsPresContext * aPresContext)148 HTMLTextAreaElement::SelectAll(nsPresContext* aPresContext) {
149 nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
150
151 if (formControlFrame) {
152 formControlFrame->SetFormProperty(nsGkAtoms::select, u""_ns);
153 }
154
155 return NS_OK;
156 }
157
IsHTMLFocusable(bool aWithMouse,bool * aIsFocusable,int32_t * aTabIndex)158 bool HTMLTextAreaElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
159 int32_t* aTabIndex) {
160 if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
161 aWithMouse, aIsFocusable, aTabIndex)) {
162 return true;
163 }
164
165 // disabled textareas are not focusable
166 *aIsFocusable = !IsDisabled();
167 return false;
168 }
169
TabIndexDefault()170 int32_t HTMLTextAreaElement::TabIndexDefault() { return 0; }
171
GetType(nsAString & aType)172 void HTMLTextAreaElement::GetType(nsAString& aType) {
173 aType.AssignLiteral("textarea");
174 }
175
GetValue(nsAString & aValue)176 void HTMLTextAreaElement::GetValue(nsAString& aValue) {
177 GetValueInternal(aValue, true);
178 MOZ_ASSERT(aValue.FindChar(static_cast<char16_t>('\r')) == -1);
179 }
180
GetValueInternal(nsAString & aValue,bool aIgnoreWrap) const181 void HTMLTextAreaElement::GetValueInternal(nsAString& aValue,
182 bool aIgnoreWrap) const {
183 MOZ_ASSERT(mState);
184 mState->GetValue(aValue, aIgnoreWrap);
185 }
186
ValueEquals(const nsAString & aValue) const187 bool HTMLTextAreaElement::ValueEquals(const nsAString& aValue) const {
188 MOZ_ASSERT(mState);
189 return mState->ValueEquals(aValue);
190 }
191
GetEditorForBindings()192 nsIEditor* HTMLTextAreaElement::GetEditorForBindings() {
193 if (!GetPrimaryFrame()) {
194 GetPrimaryFrame(FlushType::Frames);
195 }
196 return GetTextEditor();
197 }
198
GetTextEditor()199 TextEditor* HTMLTextAreaElement::GetTextEditor() {
200 MOZ_ASSERT(mState);
201 return mState->GetTextEditor();
202 }
203
GetTextEditorWithoutCreation()204 TextEditor* HTMLTextAreaElement::GetTextEditorWithoutCreation() {
205 MOZ_ASSERT(mState);
206 return mState->GetTextEditorWithoutCreation();
207 }
208
GetSelectionController()209 nsISelectionController* HTMLTextAreaElement::GetSelectionController() {
210 MOZ_ASSERT(mState);
211 return mState->GetSelectionController();
212 }
213
GetConstFrameSelection()214 nsFrameSelection* HTMLTextAreaElement::GetConstFrameSelection() {
215 MOZ_ASSERT(mState);
216 return mState->GetConstFrameSelection();
217 }
218
BindToFrame(nsTextControlFrame * aFrame)219 nsresult HTMLTextAreaElement::BindToFrame(nsTextControlFrame* aFrame) {
220 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
221 MOZ_ASSERT(mState);
222 return mState->BindToFrame(aFrame);
223 }
224
UnbindFromFrame(nsTextControlFrame * aFrame)225 void HTMLTextAreaElement::UnbindFromFrame(nsTextControlFrame* aFrame) {
226 MOZ_ASSERT(mState);
227 if (aFrame) {
228 mState->UnbindFromFrame(aFrame);
229 }
230 }
231
CreateEditor()232 nsresult HTMLTextAreaElement::CreateEditor() {
233 MOZ_ASSERT(mState);
234 return mState->PrepareEditor();
235 }
236
SetPreviewValue(const nsAString & aValue)237 void HTMLTextAreaElement::SetPreviewValue(const nsAString& aValue) {
238 MOZ_ASSERT(mState);
239 mState->SetPreviewText(aValue, true);
240 }
241
GetPreviewValue(nsAString & aValue)242 void HTMLTextAreaElement::GetPreviewValue(nsAString& aValue) {
243 MOZ_ASSERT(mState);
244 mState->GetPreviewText(aValue);
245 }
246
EnablePreview()247 void HTMLTextAreaElement::EnablePreview() {
248 if (mIsPreviewEnabled) {
249 return;
250 }
251
252 mIsPreviewEnabled = true;
253 // Reconstruct the frame to append an anonymous preview node
254 nsLayoutUtils::PostRestyleEvent(this, RestyleHint{0},
255 nsChangeHint_ReconstructFrame);
256 }
257
IsPreviewEnabled()258 bool HTMLTextAreaElement::IsPreviewEnabled() { return mIsPreviewEnabled; }
259
SetValueInternal(const nsAString & aValue,const ValueSetterOptions & aOptions)260 nsresult HTMLTextAreaElement::SetValueInternal(
261 const nsAString& aValue, const ValueSetterOptions& aOptions) {
262 MOZ_ASSERT(mState);
263
264 // Need to set the value changed flag here if our value has in fact changed
265 // (i.e. if ValueSetterOption::SetValueChanged is in aOptions), so that
266 // retrieves the correct value if needed.
267 if (aOptions.contains(ValueSetterOption::SetValueChanged)) {
268 SetValueChanged(true);
269 }
270
271 if (!mState->SetValue(aValue, aOptions)) {
272 return NS_ERROR_OUT_OF_MEMORY;
273 }
274
275 return NS_OK;
276 }
277
SetValue(const nsAString & aValue,ErrorResult & aError)278 void HTMLTextAreaElement::SetValue(const nsAString& aValue,
279 ErrorResult& aError) {
280 // If the value has been set by a script, we basically want to keep the
281 // current change event state. If the element is ready to fire a change
282 // event, we should keep it that way. Otherwise, we should make sure the
283 // element will not fire any event because of the script interaction.
284 //
285 // NOTE: this is currently quite expensive work (too much string
286 // manipulation). We should probably optimize that.
287 nsAutoString currentValue;
288 GetValueInternal(currentValue, true);
289
290 nsresult rv = SetValueInternal(
291 aValue,
292 {ValueSetterOption::ByContentAPI, ValueSetterOption::SetValueChanged,
293 ValueSetterOption::MoveCursorToEndIfValueChanged});
294 if (NS_WARN_IF(NS_FAILED(rv))) {
295 aError.Throw(rv);
296 return;
297 }
298
299 if (mFocusedValue.Equals(currentValue)) {
300 GetValueInternal(mFocusedValue, true);
301 }
302 }
303
SetUserInput(const nsAString & aValue,nsIPrincipal & aSubjectPrincipal)304 void HTMLTextAreaElement::SetUserInput(const nsAString& aValue,
305 nsIPrincipal& aSubjectPrincipal) {
306 SetValueInternal(aValue, {ValueSetterOption::BySetUserInputAPI,
307 ValueSetterOption::SetValueChanged,
308 ValueSetterOption::MoveCursorToEndIfValueChanged});
309 }
310
SetValueChanged(bool aValueChanged)311 nsresult HTMLTextAreaElement::SetValueChanged(bool aValueChanged) {
312 MOZ_ASSERT(mState);
313
314 bool previousValue = mValueChanged;
315
316 mValueChanged = aValueChanged;
317 if (!aValueChanged && !mState->IsEmpty()) {
318 mState->EmptyValue();
319 }
320
321 if (mValueChanged != previousValue) {
322 UpdateTooLongValidityState();
323 UpdateTooShortValidityState();
324 // We need to do this unconditionally because the validity ui bits depend on
325 // this.
326 UpdateState(true);
327 }
328
329 return NS_OK;
330 }
331
SetLastValueChangeWasInteractive(bool aWasInteractive)332 void HTMLTextAreaElement::SetLastValueChangeWasInteractive(
333 bool aWasInteractive) {
334 if (aWasInteractive == mLastValueChangeWasInteractive) {
335 return;
336 }
337 mLastValueChangeWasInteractive = aWasInteractive;
338 const bool wasValid = IsValid();
339 UpdateTooLongValidityState();
340 UpdateTooShortValidityState();
341 if (wasValid != IsValid()) {
342 UpdateState(true);
343 }
344 }
345
GetDefaultValue(nsAString & aDefaultValue,ErrorResult & aError)346 void HTMLTextAreaElement::GetDefaultValue(nsAString& aDefaultValue,
347 ErrorResult& aError) {
348 if (!nsContentUtils::GetNodeTextContent(this, false, aDefaultValue,
349 fallible)) {
350 aError.Throw(NS_ERROR_OUT_OF_MEMORY);
351 }
352 }
353
SetDefaultValue(const nsAString & aDefaultValue,ErrorResult & aError)354 void HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue,
355 ErrorResult& aError) {
356 nsresult rv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true);
357 if (NS_SUCCEEDED(rv) && !mValueChanged) {
358 Reset();
359 }
360 if (NS_FAILED(rv)) {
361 aError.Throw(rv);
362 }
363 }
364
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)365 bool HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID,
366 nsAtom* aAttribute,
367 const nsAString& aValue,
368 nsIPrincipal* aMaybeScriptedPrincipal,
369 nsAttrValue& aResult) {
370 if (aNamespaceID == kNameSpaceID_None) {
371 if (aAttribute == nsGkAtoms::maxlength ||
372 aAttribute == nsGkAtoms::minlength) {
373 return aResult.ParseNonNegativeIntValue(aValue);
374 } else if (aAttribute == nsGkAtoms::cols) {
375 aResult.ParseIntWithFallback(aValue, DEFAULT_COLS);
376 return true;
377 } else if (aAttribute == nsGkAtoms::rows) {
378 aResult.ParseIntWithFallback(aValue, DEFAULT_ROWS_TEXTAREA);
379 return true;
380 } else if (aAttribute == nsGkAtoms::autocomplete) {
381 aResult.ParseAtomArray(aValue);
382 return true;
383 }
384 }
385 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
386 aMaybeScriptedPrincipal, aResult);
387 }
388
MapAttributesIntoRule(const nsMappedAttributes * aAttributes,MappedDeclarations & aDecls)389 void HTMLTextAreaElement::MapAttributesIntoRule(
390 const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
391 // wrap=off
392 if (!aDecls.PropertyIsSet(eCSSProperty_white_space)) {
393 const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::wrap);
394 if (value && value->Type() == nsAttrValue::eString &&
395 value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
396 aDecls.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre);
397 }
398 }
399
400 nsGenericHTMLFormControlElementWithState::MapDivAlignAttributeInto(
401 aAttributes, aDecls);
402 nsGenericHTMLFormControlElementWithState::MapCommonAttributesInto(aAttributes,
403 aDecls);
404 }
405
GetAttributeChangeHint(const nsAtom * aAttribute,int32_t aModType) const406 nsChangeHint HTMLTextAreaElement::GetAttributeChangeHint(
407 const nsAtom* aAttribute, int32_t aModType) const {
408 nsChangeHint retval =
409 nsGenericHTMLFormControlElementWithState::GetAttributeChangeHint(
410 aAttribute, aModType);
411
412 const bool isAdditionOrRemoval =
413 aModType == MutationEvent_Binding::ADDITION ||
414 aModType == MutationEvent_Binding::REMOVAL;
415
416 if (aAttribute == nsGkAtoms::rows || aAttribute == nsGkAtoms::cols) {
417 retval |= NS_STYLE_HINT_REFLOW;
418 } else if (aAttribute == nsGkAtoms::wrap) {
419 retval |= nsChangeHint_ReconstructFrame;
420 } else if (aAttribute == nsGkAtoms::placeholder && isAdditionOrRemoval) {
421 retval |= nsChangeHint_ReconstructFrame;
422 }
423 return retval;
424 }
425
NS_IMETHODIMP_(bool)426 NS_IMETHODIMP_(bool)
427 HTMLTextAreaElement::IsAttributeMapped(const nsAtom* aAttribute) const {
428 static const MappedAttributeEntry attributes[] = {{nsGkAtoms::wrap},
429 {nullptr}};
430
431 static const MappedAttributeEntry* const map[] = {
432 attributes,
433 sDivAlignAttributeMap,
434 sCommonAttributeMap,
435 };
436
437 return FindAttributeDependence(aAttribute, map);
438 }
439
GetAttributeMappingFunction() const440 nsMapRuleToAttributesFunc HTMLTextAreaElement::GetAttributeMappingFunction()
441 const {
442 return &MapAttributesIntoRule;
443 }
444
IsDisabledForEvents(WidgetEvent * aEvent)445 bool HTMLTextAreaElement::IsDisabledForEvents(WidgetEvent* aEvent) {
446 nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
447 nsIFrame* formFrame = do_QueryFrame(formControlFrame);
448 return IsElementDisabledForEvents(aEvent, formFrame);
449 }
450
GetEventTargetParent(EventChainPreVisitor & aVisitor)451 void HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
452 aVisitor.mCanHandle = false;
453 if (IsDisabledForEvents(aVisitor.mEvent)) {
454 return;
455 }
456
457 // Don't dispatch a second select event if we are already handling
458 // one.
459 if (aVisitor.mEvent->mMessage == eFormSelect) {
460 if (mHandlingSelect) {
461 return;
462 }
463 mHandlingSelect = true;
464 }
465
466 if (aVisitor.mEvent->mMessage == eBlur) {
467 // Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
468 // prevent it breaks event target chain creation.
469 aVisitor.mWantsPreHandleEvent = true;
470 }
471
472 nsGenericHTMLFormControlElementWithState::GetEventTargetParent(aVisitor);
473 }
474
PreHandleEvent(EventChainVisitor & aVisitor)475 nsresult HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor) {
476 if (aVisitor.mEvent->mMessage == eBlur) {
477 // Fire onchange (if necessary), before we do the blur, bug 370521.
478 FireChangeEventIfNeeded();
479 }
480 return nsGenericHTMLFormControlElementWithState::PreHandleEvent(aVisitor);
481 }
482
FireChangeEventIfNeeded()483 void HTMLTextAreaElement::FireChangeEventIfNeeded() {
484 nsString value;
485 GetValueInternal(value, true);
486
487 if (mFocusedValue.Equals(value)) {
488 return;
489 }
490
491 // Dispatch the change event.
492 mFocusedValue = value;
493 nsContentUtils::DispatchTrustedEvent(
494 OwnerDoc(), static_cast<nsIContent*>(this), u"change"_ns, CanBubble::eYes,
495 Cancelable::eNo);
496 }
497
PostHandleEvent(EventChainPostVisitor & aVisitor)498 nsresult HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
499 if (aVisitor.mEvent->mMessage == eFormSelect) {
500 mHandlingSelect = false;
501 }
502
503 if (aVisitor.mEvent->mMessage == eFocus ||
504 aVisitor.mEvent->mMessage == eBlur) {
505 if (aVisitor.mEvent->mMessage == eFocus) {
506 // If the invalid UI is shown, we should show it while focusing (and
507 // update). Otherwise, we should not.
508 GetValueInternal(mFocusedValue, true);
509 mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
510
511 // If neither invalid UI nor valid UI is shown, we shouldn't show the
512 // valid UI while typing.
513 mCanShowValidUI = ShouldShowValidityUI();
514 } else { // eBlur
515 mCanShowInvalidUI = true;
516 mCanShowValidUI = true;
517 }
518
519 UpdateState(true);
520 }
521
522 return NS_OK;
523 }
524
DoneAddingChildren(bool aHaveNotified)525 void HTMLTextAreaElement::DoneAddingChildren(bool aHaveNotified) {
526 if (!mValueChanged) {
527 if (!mDoneAddingChildren) {
528 // Reset now that we're done adding children if the content sink tried to
529 // sneak some text in without calling AppendChildTo.
530 Reset();
531 }
532
533 if (!mInhibitStateRestoration) {
534 GenerateStateKey();
535 RestoreFormControlState();
536 }
537 }
538
539 mDoneAddingChildren = true;
540 }
541
IsDoneAddingChildren()542 bool HTMLTextAreaElement::IsDoneAddingChildren() { return mDoneAddingChildren; }
543
544 // Controllers Methods
545
GetControllers(ErrorResult & aError)546 nsIControllers* HTMLTextAreaElement::GetControllers(ErrorResult& aError) {
547 if (!mControllers) {
548 mControllers = new nsXULControllers();
549 if (!mControllers) {
550 aError.Throw(NS_ERROR_FAILURE);
551 return nullptr;
552 }
553
554 RefPtr<nsBaseCommandController> commandController =
555 nsBaseCommandController::CreateEditorController();
556 if (!commandController) {
557 aError.Throw(NS_ERROR_FAILURE);
558 return nullptr;
559 }
560
561 mControllers->AppendController(commandController);
562
563 commandController = nsBaseCommandController::CreateEditingController();
564 if (!commandController) {
565 aError.Throw(NS_ERROR_FAILURE);
566 return nullptr;
567 }
568
569 mControllers->AppendController(commandController);
570 }
571
572 return mControllers;
573 }
574
GetControllers(nsIControllers ** aResult)575 nsresult HTMLTextAreaElement::GetControllers(nsIControllers** aResult) {
576 NS_ENSURE_ARG_POINTER(aResult);
577
578 ErrorResult error;
579 *aResult = GetControllers(error);
580 NS_IF_ADDREF(*aResult);
581
582 return error.StealNSResult();
583 }
584
GetTextLength()585 uint32_t HTMLTextAreaElement::GetTextLength() {
586 nsAutoString val;
587 GetValue(val);
588 return val.Length();
589 }
590
GetSelectionStart(ErrorResult & aError)591 Nullable<uint32_t> HTMLTextAreaElement::GetSelectionStart(ErrorResult& aError) {
592 uint32_t selStart, selEnd;
593 GetSelectionRange(&selStart, &selEnd, aError);
594 return Nullable<uint32_t>(selStart);
595 }
596
SetSelectionStart(const Nullable<uint32_t> & aSelectionStart,ErrorResult & aError)597 void HTMLTextAreaElement::SetSelectionStart(
598 const Nullable<uint32_t>& aSelectionStart, ErrorResult& aError) {
599 MOZ_ASSERT(mState);
600 mState->SetSelectionStart(aSelectionStart, aError);
601 }
602
GetSelectionEnd(ErrorResult & aError)603 Nullable<uint32_t> HTMLTextAreaElement::GetSelectionEnd(ErrorResult& aError) {
604 uint32_t selStart, selEnd;
605 GetSelectionRange(&selStart, &selEnd, aError);
606 return Nullable<uint32_t>(selEnd);
607 }
608
SetSelectionEnd(const Nullable<uint32_t> & aSelectionEnd,ErrorResult & aError)609 void HTMLTextAreaElement::SetSelectionEnd(
610 const Nullable<uint32_t>& aSelectionEnd, ErrorResult& aError) {
611 MOZ_ASSERT(mState);
612 mState->SetSelectionEnd(aSelectionEnd, aError);
613 }
614
GetSelectionRange(uint32_t * aSelectionStart,uint32_t * aSelectionEnd,ErrorResult & aRv)615 void HTMLTextAreaElement::GetSelectionRange(uint32_t* aSelectionStart,
616 uint32_t* aSelectionEnd,
617 ErrorResult& aRv) {
618 MOZ_ASSERT(mState);
619 return mState->GetSelectionRange(aSelectionStart, aSelectionEnd, aRv);
620 }
621
GetSelectionDirection(nsAString & aDirection,ErrorResult & aError)622 void HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection,
623 ErrorResult& aError) {
624 MOZ_ASSERT(mState);
625 mState->GetSelectionDirectionString(aDirection, aError);
626 }
627
SetSelectionDirection(const nsAString & aDirection,ErrorResult & aError)628 void HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection,
629 ErrorResult& aError) {
630 MOZ_ASSERT(mState);
631 mState->SetSelectionDirection(aDirection, aError);
632 }
633
SetSelectionRange(uint32_t aSelectionStart,uint32_t aSelectionEnd,const Optional<nsAString> & aDirection,ErrorResult & aError)634 void HTMLTextAreaElement::SetSelectionRange(
635 uint32_t aSelectionStart, uint32_t aSelectionEnd,
636 const Optional<nsAString>& aDirection, ErrorResult& aError) {
637 MOZ_ASSERT(mState);
638 mState->SetSelectionRange(aSelectionStart, aSelectionEnd, aDirection, aError);
639 }
640
SetRangeText(const nsAString & aReplacement,ErrorResult & aRv)641 void HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
642 ErrorResult& aRv) {
643 MOZ_ASSERT(mState);
644 mState->SetRangeText(aReplacement, aRv);
645 }
646
SetRangeText(const nsAString & aReplacement,uint32_t aStart,uint32_t aEnd,SelectionMode aSelectMode,ErrorResult & aRv)647 void HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
648 uint32_t aStart, uint32_t aEnd,
649 SelectionMode aSelectMode,
650 ErrorResult& aRv) {
651 MOZ_ASSERT(mState);
652 mState->SetRangeText(aReplacement, aStart, aEnd, aSelectMode, aRv);
653 }
654
GetValueFromSetRangeText(nsAString & aValue)655 void HTMLTextAreaElement::GetValueFromSetRangeText(nsAString& aValue) {
656 GetValueInternal(aValue, false);
657 }
658
SetValueFromSetRangeText(const nsAString & aValue)659 nsresult HTMLTextAreaElement::SetValueFromSetRangeText(
660 const nsAString& aValue) {
661 return SetValueInternal(aValue, {ValueSetterOption::ByContentAPI,
662 ValueSetterOption::BySetRangeTextAPI,
663 ValueSetterOption::SetValueChanged});
664 }
665
Reset()666 nsresult HTMLTextAreaElement::Reset() {
667 nsAutoString resetVal;
668 GetDefaultValue(resetVal, IgnoreErrors());
669 SetValueChanged(false);
670
671 nsresult rv = SetValueInternal(resetVal, ValueSetterOption::ByInternalAPI);
672 NS_ENSURE_SUCCESS(rv, rv);
673
674 return NS_OK;
675 }
676
677 NS_IMETHODIMP
SubmitNamesValues(FormData * aFormData)678 HTMLTextAreaElement::SubmitNamesValues(FormData* aFormData) {
679 //
680 // Get the name (if no name, no submit)
681 //
682 nsAutoString name;
683 GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
684 if (name.IsEmpty()) {
685 return NS_OK;
686 }
687
688 //
689 // Get the value
690 //
691 nsAutoString value;
692 GetValueInternal(value, false);
693
694 //
695 // Submit
696 //
697 return aFormData->AddNameValuePair(name, value);
698 }
699
SaveState()700 void HTMLTextAreaElement::SaveState() {
701 // Only save if value != defaultValue (bug 62713)
702 PresState* state = nullptr;
703 if (mValueChanged) {
704 state = GetPrimaryPresState();
705 if (state) {
706 nsAutoString value;
707 GetValueInternal(value, true);
708
709 if (NS_FAILED(nsLinebreakConverter::ConvertStringLineBreaks(
710 value, nsLinebreakConverter::eLinebreakPlatform,
711 nsLinebreakConverter::eLinebreakContent))) {
712 NS_ERROR("Converting linebreaks failed!");
713 return;
714 }
715
716 state->contentData() =
717 TextContentData(value, mLastValueChangeWasInteractive);
718 }
719 }
720
721 if (mDisabledChanged) {
722 if (!state) {
723 state = GetPrimaryPresState();
724 }
725 if (state) {
726 // We do not want to save the real disabled state but the disabled
727 // attribute.
728 state->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
729 state->disabledSet() = true;
730 }
731 }
732 }
733
RestoreState(PresState * aState)734 bool HTMLTextAreaElement::RestoreState(PresState* aState) {
735 const PresContentData& state = aState->contentData();
736
737 if (state.type() == PresContentData::TTextContentData) {
738 ErrorResult rv;
739 SetValue(state.get_TextContentData().value(), rv);
740 ENSURE_SUCCESS(rv, false);
741 if (state.get_TextContentData().lastValueChangeWasInteractive()) {
742 SetLastValueChangeWasInteractive(true);
743 }
744 }
745 if (aState->disabledSet() && !aState->disabled()) {
746 SetDisabled(false, IgnoreErrors());
747 }
748
749 return false;
750 }
751
IntrinsicState() const752 EventStates HTMLTextAreaElement::IntrinsicState() const {
753 EventStates state =
754 nsGenericHTMLFormControlElementWithState::IntrinsicState();
755
756 if (IsCandidateForConstraintValidation()) {
757 if (IsValid()) {
758 state |= NS_EVENT_STATE_VALID;
759 } else {
760 state |= NS_EVENT_STATE_INVALID;
761 // :-moz-ui-invalid always apply if the element suffers from a custom
762 // error.
763 if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
764 (mCanShowInvalidUI && ShouldShowValidityUI())) {
765 state |= NS_EVENT_STATE_MOZ_UI_INVALID;
766 }
767 }
768
769 // :-moz-ui-valid applies if all the following are true:
770 // 1. The element is not focused, or had either :-moz-ui-valid or
771 // :-moz-ui-invalid applying before it was focused ;
772 // 2. The element is either valid or isn't allowed to have
773 // :-moz-ui-invalid applying ;
774 // 3. The element has already been modified or the user tried to submit the
775 // form owner while invalid.
776 if (mCanShowValidUI && ShouldShowValidityUI() &&
777 (IsValid() || (state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
778 !mCanShowInvalidUI))) {
779 state |= NS_EVENT_STATE_MOZ_UI_VALID;
780 }
781 }
782
783 if (HasAttr(nsGkAtoms::placeholder) && IsValueEmpty()) {
784 state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
785 }
786
787 return state;
788 }
789
BindToTree(BindContext & aContext,nsINode & aParent)790 nsresult HTMLTextAreaElement::BindToTree(BindContext& aContext,
791 nsINode& aParent) {
792 nsresult rv =
793 nsGenericHTMLFormControlElementWithState::BindToTree(aContext, aParent);
794 NS_ENSURE_SUCCESS(rv, rv);
795
796 // If there is a disabled fieldset in the parent chain, the element is now
797 // barred from constraint validation and can't suffer from value missing.
798 UpdateValueMissingValidityState();
799 UpdateBarredFromConstraintValidation();
800
801 // And now make sure our state is up to date
802 UpdateState(false);
803
804 return rv;
805 }
806
UnbindFromTree(bool aNullParent)807 void HTMLTextAreaElement::UnbindFromTree(bool aNullParent) {
808 nsGenericHTMLFormControlElementWithState::UnbindFromTree(aNullParent);
809
810 // We might be no longer disabled because of parent chain changed.
811 UpdateValueMissingValidityState();
812 UpdateBarredFromConstraintValidation();
813
814 // And now make sure our state is up to date
815 UpdateState(false);
816 }
817
BeforeSetAttr(int32_t aNameSpaceID,nsAtom * aName,const nsAttrValueOrString * aValue,bool aNotify)818 nsresult HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
819 const nsAttrValueOrString* aValue,
820 bool aNotify) {
821 if (aNotify && aName == nsGkAtoms::disabled &&
822 aNameSpaceID == kNameSpaceID_None) {
823 mDisabledChanged = true;
824 }
825
826 return nsGenericHTMLFormControlElementWithState::BeforeSetAttr(
827 aNameSpaceID, aName, aValue, aNotify);
828 }
829
CharacterDataChanged(nsIContent * aContent,const CharacterDataChangeInfo &)830 void HTMLTextAreaElement::CharacterDataChanged(nsIContent* aContent,
831 const CharacterDataChangeInfo&) {
832 ContentChanged(aContent);
833 }
834
ContentAppended(nsIContent * aFirstNewContent)835 void HTMLTextAreaElement::ContentAppended(nsIContent* aFirstNewContent) {
836 ContentChanged(aFirstNewContent);
837 }
838
ContentInserted(nsIContent * aChild)839 void HTMLTextAreaElement::ContentInserted(nsIContent* aChild) {
840 ContentChanged(aChild);
841 }
842
ContentRemoved(nsIContent * aChild,nsIContent * aPreviousSibling)843 void HTMLTextAreaElement::ContentRemoved(nsIContent* aChild,
844 nsIContent* aPreviousSibling) {
845 ContentChanged(aChild);
846 }
847
ContentChanged(nsIContent * aContent)848 void HTMLTextAreaElement::ContentChanged(nsIContent* aContent) {
849 if (!mValueChanged && mDoneAddingChildren &&
850 nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
851 // Hard to say what the reset can trigger, so be safe pending
852 // further auditing.
853 nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
854 Reset();
855 }
856 }
857
AfterSetAttr(int32_t aNameSpaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aSubjectPrincipal,bool aNotify)858 nsresult HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
859 const nsAttrValue* aValue,
860 const nsAttrValue* aOldValue,
861 nsIPrincipal* aSubjectPrincipal,
862 bool aNotify) {
863 if (aNameSpaceID == kNameSpaceID_None) {
864 if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
865 aName == nsGkAtoms::readonly) {
866 if (aName == nsGkAtoms::disabled) {
867 // This *has* to be called *before* validity state check because
868 // UpdateBarredFromConstraintValidation and
869 // UpdateValueMissingValidityState depend on our disabled state.
870 UpdateDisabledState(aNotify);
871 }
872
873 if (aName == nsGkAtoms::required) {
874 // This *has* to be called *before* UpdateValueMissingValidityState
875 // because UpdateValueMissingValidityState depends on our required
876 // state.
877 UpdateRequiredState(!!aValue, aNotify);
878 }
879
880 UpdateValueMissingValidityState();
881
882 // This *has* to be called *after* validity has changed.
883 if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
884 UpdateBarredFromConstraintValidation();
885 }
886 } else if (aName == nsGkAtoms::autocomplete) {
887 // Clear the cached @autocomplete attribute state.
888 mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
889 } else if (aName == nsGkAtoms::maxlength) {
890 UpdateTooLongValidityState();
891 } else if (aName == nsGkAtoms::minlength) {
892 UpdateTooShortValidityState();
893 } else if (aName == nsGkAtoms::placeholder) {
894 if (nsTextControlFrame* f = do_QueryFrame(GetPrimaryFrame())) {
895 f->PlaceholderChanged(aOldValue, aValue);
896 }
897 }
898 }
899
900 return nsGenericHTMLFormControlElementWithState::AfterSetAttr(
901 aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
902 }
903
CopyInnerTo(Element * aDest)904 nsresult HTMLTextAreaElement::CopyInnerTo(Element* aDest) {
905 nsresult rv = nsGenericHTMLFormControlElementWithState::CopyInnerTo(aDest);
906 NS_ENSURE_SUCCESS(rv, rv);
907
908 if (aDest->OwnerDoc()->IsStaticDocument()) {
909 nsAutoString value;
910 GetValueInternal(value, true);
911 ErrorResult ret;
912 static_cast<HTMLTextAreaElement*>(aDest)->SetValue(value, ret);
913 return ret.StealNSResult();
914 }
915 return NS_OK;
916 }
917
IsMutable() const918 bool HTMLTextAreaElement::IsMutable() const {
919 return (!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) && !IsDisabled());
920 }
921
IsValueEmpty() const922 bool HTMLTextAreaElement::IsValueEmpty() const {
923 nsAutoString value;
924 GetValueInternal(value, true);
925
926 return value.IsEmpty();
927 }
928
SetCustomValidity(const nsAString & aError)929 void HTMLTextAreaElement::SetCustomValidity(const nsAString& aError) {
930 ConstraintValidation::SetCustomValidity(aError);
931
932 UpdateState(true);
933 }
934
IsTooLong()935 bool HTMLTextAreaElement::IsTooLong() {
936 if (!mValueChanged || !mLastValueChangeWasInteractive ||
937 !HasAttr(nsGkAtoms::maxlength)) {
938 return false;
939 }
940
941 int32_t maxLength = MaxLength();
942
943 // Maxlength of -1 means parsing error.
944 if (maxLength == -1) {
945 return false;
946 }
947
948 int32_t textLength = GetTextLength();
949
950 return textLength > maxLength;
951 }
952
IsTooShort()953 bool HTMLTextAreaElement::IsTooShort() {
954 if (!mValueChanged || !mLastValueChangeWasInteractive ||
955 !HasAttr(nsGkAtoms::minlength)) {
956 return false;
957 }
958
959 int32_t minLength = MinLength();
960
961 // Minlength of -1 means parsing error.
962 if (minLength == -1) {
963 return false;
964 }
965
966 int32_t textLength = GetTextLength();
967
968 return textLength && textLength < minLength;
969 }
970
IsValueMissing() const971 bool HTMLTextAreaElement::IsValueMissing() const {
972 if (!Required() || !IsMutable()) {
973 return false;
974 }
975
976 return IsValueEmpty();
977 }
978
UpdateTooLongValidityState()979 void HTMLTextAreaElement::UpdateTooLongValidityState() {
980 SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
981 }
982
UpdateTooShortValidityState()983 void HTMLTextAreaElement::UpdateTooShortValidityState() {
984 SetValidityState(VALIDITY_STATE_TOO_SHORT, IsTooShort());
985 }
986
UpdateValueMissingValidityState()987 void HTMLTextAreaElement::UpdateValueMissingValidityState() {
988 SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
989 }
990
UpdateBarredFromConstraintValidation()991 void HTMLTextAreaElement::UpdateBarredFromConstraintValidation() {
992 SetBarredFromConstraintValidation(
993 HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
994 HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR) || IsDisabled());
995 }
996
GetValidationMessage(nsAString & aValidationMessage,ValidityStateType aType)997 nsresult HTMLTextAreaElement::GetValidationMessage(
998 nsAString& aValidationMessage, ValidityStateType aType) {
999 nsresult rv = NS_OK;
1000
1001 switch (aType) {
1002 case VALIDITY_STATE_TOO_LONG: {
1003 nsAutoString message;
1004 int32_t maxLength = MaxLength();
1005 int32_t textLength = GetTextLength();
1006 nsAutoString strMaxLength;
1007 nsAutoString strTextLength;
1008
1009 strMaxLength.AppendInt(maxLength);
1010 strTextLength.AppendInt(textLength);
1011
1012 rv = nsContentUtils::FormatMaybeLocalizedString(
1013 message, nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong",
1014 OwnerDoc(), strMaxLength, strTextLength);
1015 aValidationMessage = message;
1016 } break;
1017 case VALIDITY_STATE_TOO_SHORT: {
1018 nsAutoString message;
1019 int32_t minLength = MinLength();
1020 int32_t textLength = GetTextLength();
1021 nsAutoString strMinLength;
1022 nsAutoString strTextLength;
1023
1024 strMinLength.AppendInt(minLength);
1025 strTextLength.AppendInt(textLength);
1026
1027 rv = nsContentUtils::FormatMaybeLocalizedString(
1028 message, nsContentUtils::eDOM_PROPERTIES,
1029 "FormValidationTextTooShort", OwnerDoc(), strMinLength,
1030 strTextLength);
1031 aValidationMessage = message;
1032 } break;
1033 case VALIDITY_STATE_VALUE_MISSING: {
1034 nsAutoString message;
1035 rv = nsContentUtils::GetMaybeLocalizedString(
1036 nsContentUtils::eDOM_PROPERTIES, "FormValidationValueMissing",
1037 OwnerDoc(), message);
1038 aValidationMessage = message;
1039 } break;
1040 default:
1041 rv =
1042 ConstraintValidation::GetValidationMessage(aValidationMessage, aType);
1043 }
1044
1045 return rv;
1046 }
1047
IsSingleLineTextControl() const1048 bool HTMLTextAreaElement::IsSingleLineTextControl() const { return false; }
1049
IsTextArea() const1050 bool HTMLTextAreaElement::IsTextArea() const { return true; }
1051
IsPasswordTextControl() const1052 bool HTMLTextAreaElement::IsPasswordTextControl() const { return false; }
1053
GetCols()1054 int32_t HTMLTextAreaElement::GetCols() { return Cols(); }
1055
GetWrapCols()1056 int32_t HTMLTextAreaElement::GetWrapCols() {
1057 nsHTMLTextWrap wrapProp;
1058 TextControlElement::GetWrapPropertyEnum(this, wrapProp);
1059 if (wrapProp == TextControlElement::eHTMLTextWrap_Off) {
1060 // do not wrap when wrap=off
1061 return 0;
1062 }
1063
1064 // Otherwise we just wrap at the given number of columns
1065 return GetCols();
1066 }
1067
GetRows()1068 int32_t HTMLTextAreaElement::GetRows() {
1069 const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::rows);
1070 if (attr && attr->Type() == nsAttrValue::eInteger) {
1071 int32_t rows = attr->GetIntegerValue();
1072 return (rows <= 0) ? DEFAULT_ROWS_TEXTAREA : rows;
1073 }
1074
1075 return DEFAULT_ROWS_TEXTAREA;
1076 }
1077
GetDefaultValueFromContent(nsAString & aValue)1078 void HTMLTextAreaElement::GetDefaultValueFromContent(nsAString& aValue) {
1079 GetDefaultValue(aValue, IgnoreErrors());
1080 }
1081
ValueChanged() const1082 bool HTMLTextAreaElement::ValueChanged() const { return mValueChanged; }
1083
GetTextEditorValue(nsAString & aValue,bool aIgnoreWrap) const1084 void HTMLTextAreaElement::GetTextEditorValue(nsAString& aValue,
1085 bool aIgnoreWrap) const {
1086 MOZ_ASSERT(mState);
1087 mState->GetValue(aValue, aIgnoreWrap);
1088 }
1089
InitializeKeyboardEventListeners()1090 void HTMLTextAreaElement::InitializeKeyboardEventListeners() {
1091 MOZ_ASSERT(mState);
1092 mState->InitializeKeyboardEventListeners();
1093 }
1094
OnValueChanged(ValueChangeKind aKind)1095 void HTMLTextAreaElement::OnValueChanged(ValueChangeKind aKind) {
1096 if (aKind != ValueChangeKind::Internal) {
1097 mLastValueChangeWasInteractive = aKind == ValueChangeKind::UserInteraction;
1098 }
1099
1100 // Update the validity state
1101 bool validBefore = IsValid();
1102 UpdateTooLongValidityState();
1103 UpdateTooShortValidityState();
1104 UpdateValueMissingValidityState();
1105
1106 if (validBefore != IsValid() || HasAttr(nsGkAtoms::placeholder)) {
1107 UpdateState(true);
1108 }
1109 }
1110
HasCachedSelection()1111 bool HTMLTextAreaElement::HasCachedSelection() {
1112 MOZ_ASSERT(mState);
1113 return mState->IsSelectionCached();
1114 }
1115
FieldSetDisabledChanged(bool aNotify)1116 void HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify) {
1117 // This *has* to be called before UpdateBarredFromConstraintValidation and
1118 // UpdateValueMissingValidityState because these two functions depend on our
1119 // disabled state.
1120 nsGenericHTMLFormControlElementWithState::FieldSetDisabledChanged(aNotify);
1121
1122 UpdateValueMissingValidityState();
1123 UpdateBarredFromConstraintValidation();
1124 UpdateState(aNotify);
1125 }
1126
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)1127 JSObject* HTMLTextAreaElement::WrapNode(JSContext* aCx,
1128 JS::Handle<JSObject*> aGivenProto) {
1129 return HTMLTextAreaElement_Binding::Wrap(aCx, this, aGivenProto);
1130 }
1131
GetAutocomplete(DOMString & aValue)1132 void HTMLTextAreaElement::GetAutocomplete(DOMString& aValue) {
1133 const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
1134
1135 mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(
1136 attributeVal, aValue, mAutocompleteAttrState);
1137 }
1138
1139 } // namespace mozilla::dom
1140