Line data Source code
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/ArrayUtils.h"
8 : #include "mozilla/DeclarationBlockInlines.h"
9 : #include "mozilla/EventDispatcher.h"
10 : #include "mozilla/EventListenerManager.h"
11 : #include "mozilla/EventStateManager.h"
12 : #include "mozilla/EventStates.h"
13 : #include "mozilla/GenericSpecifiedValuesInlines.h"
14 : #include "mozilla/Likely.h"
15 : #include "mozilla/MouseEvents.h"
16 : #include "mozilla/TextEditor.h"
17 :
18 : #include "nscore.h"
19 : #include "nsGenericHTMLElement.h"
20 : #include "nsAttrValueInlines.h"
21 : #include "nsCOMPtr.h"
22 : #include "nsIAtom.h"
23 : #include "nsQueryObject.h"
24 : #include "nsIContentInlines.h"
25 : #include "nsIContentViewer.h"
26 : #include "mozilla/css/Declaration.h"
27 : #include "nsIDocument.h"
28 : #include "nsIDocumentEncoder.h"
29 : #include "nsIDOMHTMLDocument.h"
30 : #include "nsIDOMAttr.h"
31 : #include "nsIDOMDocumentFragment.h"
32 : #include "nsIDOMHTMLElement.h"
33 : #include "nsIDOMHTMLMenuElement.h"
34 : #include "nsIDOMWindow.h"
35 : #include "nsIDOMDocument.h"
36 : #include "nsMappedAttributes.h"
37 : #include "nsHTMLStyleSheet.h"
38 : #include "nsIHTMLDocument.h"
39 : #include "nsPIDOMWindow.h"
40 : #include "nsIURL.h"
41 : #include "nsEscape.h"
42 : #include "nsIFrameInlines.h"
43 : #include "nsIScrollableFrame.h"
44 : #include "nsView.h"
45 : #include "nsViewManager.h"
46 : #include "nsIWidget.h"
47 : #include "nsRange.h"
48 : #include "nsIPresShell.h"
49 : #include "nsPresContext.h"
50 : #include "nsIDocShell.h"
51 : #include "nsNameSpaceManager.h"
52 : #include "nsError.h"
53 : #include "nsIPrincipal.h"
54 : #include "nsContainerFrame.h"
55 : #include "nsStyleUtil.h"
56 :
57 : #include "nsPresState.h"
58 : #include "nsILayoutHistoryState.h"
59 :
60 : #include "nsHTMLParts.h"
61 : #include "nsContentUtils.h"
62 : #include "mozilla/dom/DirectionalityUtils.h"
63 : #include "nsString.h"
64 : #include "nsUnicharUtils.h"
65 : #include "nsGkAtoms.h"
66 : #include "nsIDOMEvent.h"
67 : #include "nsDOMCSSDeclaration.h"
68 : #include "nsITextControlFrame.h"
69 : #include "nsIForm.h"
70 : #include "nsIFormControl.h"
71 : #include "nsIDOMHTMLFormElement.h"
72 : #include "mozilla/dom/HTMLFormElement.h"
73 : #include "nsFocusManager.h"
74 : #include "nsAttrValueOrString.h"
75 :
76 : #include "mozilla/InternalMutationEvent.h"
77 : #include "nsDOMStringMap.h"
78 :
79 : #include "nsIEditor.h"
80 : #include "nsLayoutUtils.h"
81 : #include "mozAutoDocUpdate.h"
82 : #include "nsHtml5Module.h"
83 : #include "nsITextControlElement.h"
84 : #include "mozilla/dom/Element.h"
85 : #include "HTMLFieldSetElement.h"
86 : #include "nsTextNode.h"
87 : #include "HTMLBRElement.h"
88 : #include "HTMLMenuElement.h"
89 : #include "nsDOMMutationObserver.h"
90 : #include "mozilla/Preferences.h"
91 : #include "mozilla/dom/FromParser.h"
92 : #include "mozilla/dom/Link.h"
93 : #include "mozilla/BloomFilter.h"
94 : #include "mozilla/dom/ScriptLoader.h"
95 :
96 : #include "nsVariant.h"
97 : #include "nsDOMTokenList.h"
98 : #include "nsThreadUtils.h"
99 : #include "nsTextFragment.h"
100 : #include "mozilla/dom/BindingUtils.h"
101 : #include "mozilla/dom/TouchEvent.h"
102 : #include "mozilla/ErrorResult.h"
103 : #include "nsHTMLDocument.h"
104 : #include "nsGlobalWindow.h"
105 : #include "mozilla/dom/HTMLBodyElement.h"
106 : #include "imgIContainer.h"
107 : #include "nsComputedDOMStyle.h"
108 : #include "mozilla/StyleSetHandle.h"
109 : #include "mozilla/StyleSetHandleInlines.h"
110 : #include "ReferrerPolicy.h"
111 : #include "mozilla/dom/HTMLLabelElement.h"
112 :
113 : using namespace mozilla;
114 : using namespace mozilla::dom;
115 :
116 : /**
117 : * nsAutoFocusEvent is used to dispatch a focus event when a
118 : * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute
119 : * enabled.
120 : */
121 0 : class nsAutoFocusEvent : public Runnable
122 : {
123 : public:
124 0 : explicit nsAutoFocusEvent(nsGenericHTMLFormElement* aElement)
125 0 : : mozilla::Runnable("nsAutoFocusEvent")
126 0 : , mElement(aElement)
127 : {
128 0 : }
129 :
130 0 : NS_IMETHOD Run() override {
131 0 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
132 0 : if (!fm) {
133 0 : return NS_ERROR_NULL_POINTER;
134 : }
135 :
136 0 : nsIDocument* document = mElement->OwnerDoc();
137 :
138 0 : nsPIDOMWindowOuter* window = document->GetWindow();
139 0 : if (!window) {
140 0 : return NS_OK;
141 : }
142 :
143 : // Trying to found the top window (equivalent to window.top).
144 0 : if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetTop()) {
145 0 : window = top;
146 : }
147 :
148 0 : if (window->GetFocusedNode()) {
149 0 : return NS_OK;
150 : }
151 :
152 0 : nsCOMPtr<nsIDocument> topDoc = window->GetExtantDoc();
153 0 : if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
154 0 : return NS_OK;
155 : }
156 :
157 : // If something is focused in the same document, ignore autofocus.
158 0 : if (!fm->GetFocusedContent() ||
159 0 : fm->GetFocusedContent()->OwnerDoc() != document) {
160 0 : mozilla::ErrorResult rv;
161 0 : mElement->Focus(rv);
162 0 : return rv.StealNSResult();
163 : }
164 :
165 0 : return NS_OK;
166 : }
167 : private:
168 : // NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement
169 : // because AddRef/Release are ambiguous with nsGenericHTMLFormElement
170 : // and Focus() is declared (and defined) in nsGenericHTMLElement class.
171 : RefPtr<nsGenericHTMLElement> mElement;
172 : };
173 :
174 1088 : NS_IMPL_ADDREF_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
175 889 : NS_IMPL_RELEASE_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
176 :
177 1038 : NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)
178 1038 : NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement)
179 1026 : NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
180 1007 : NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
181 985 : NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)
182 :
183 : nsresult
184 4 : nsGenericHTMLElement::CopyInnerTo(Element* aDst, bool aPreallocateChildren)
185 : {
186 4 : MOZ_ASSERT(!aDst->GetUncomposedDoc(),
187 : "Should not CopyInnerTo an Element in a document");
188 : nsresult rv;
189 :
190 4 : bool reparse = (aDst->OwnerDoc() != OwnerDoc());
191 :
192 : rv = static_cast<nsGenericHTMLElement*>(aDst)->mAttrsAndChildren.
193 4 : EnsureCapacityToClone(mAttrsAndChildren, aPreallocateChildren);
194 4 : NS_ENSURE_SUCCESS(rv, rv);
195 :
196 4 : int32_t i, count = GetAttrCount();
197 14 : for (i = 0; i < count; ++i) {
198 10 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
199 10 : const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
200 :
201 10 : if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
202 0 : value->Type() == nsAttrValue::eCSSDeclaration) {
203 : // We still clone CSS attributes, even in the cross-document case.
204 : // https://github.com/w3c/webappsec-csp/issues/212
205 :
206 : // We can't just set this as a string, because that will fail
207 : // to reparse the string into style data until the node is
208 : // inserted into the document. Clone the Rule instead.
209 0 : nsAttrValue valueCopy(*value);
210 0 : rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
211 0 : name->GetPrefix(), valueCopy, false);
212 0 : NS_ENSURE_SUCCESS(rv, rv);
213 :
214 0 : DeclarationBlock* cssDeclaration = value->GetCSSDeclarationValue();
215 0 : cssDeclaration->SetImmutable();
216 10 : } else if (reparse) {
217 20 : nsAutoString valStr;
218 10 : value->ToString(valStr);
219 :
220 10 : rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
221 20 : name->GetPrefix(), valStr, false);
222 10 : NS_ENSURE_SUCCESS(rv, rv);
223 : } else {
224 0 : nsAttrValue valueCopy(*value);
225 0 : rv = aDst->SetParsedAttr(name->NamespaceID(), name->LocalName(),
226 0 : name->GetPrefix(), valueCopy, false);
227 0 : NS_ENSURE_SUCCESS(rv, rv);
228 : }
229 : }
230 :
231 4 : return NS_OK;
232 : }
233 :
234 : NS_IMETHODIMP
235 0 : nsGenericHTMLElement::GetDataset(nsISupports** aDataset)
236 : {
237 0 : *aDataset = Dataset().take();
238 0 : return NS_OK;
239 : }
240 :
241 : static const nsAttrValue::EnumTable kDirTable[] = {
242 : { "ltr", eDir_LTR },
243 : { "rtl", eDir_RTL },
244 : { "auto", eDir_Auto },
245 : { nullptr, 0 }
246 : };
247 :
248 : void
249 0 : nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel)
250 : {
251 0 : nsAutoString suffix;
252 0 : GetAccessKey(suffix);
253 0 : if (!suffix.IsEmpty()) {
254 0 : EventStateManager::GetAccessKeyLabelPrefix(this, aLabel);
255 0 : aLabel.Append(suffix);
256 : }
257 0 : }
258 :
259 : static bool
260 0 : IS_TABLE_CELL(LayoutFrameType frameType)
261 : {
262 0 : return LayoutFrameType::TableCell == frameType ||
263 0 : LayoutFrameType::BCTableCell == frameType;
264 : }
265 :
266 : static bool
267 0 : IsOffsetParent(nsIFrame* aFrame)
268 : {
269 0 : LayoutFrameType frameType = aFrame->Type();
270 :
271 0 : if (IS_TABLE_CELL(frameType) || frameType == LayoutFrameType::Table) {
272 : // Per the IDL for Element, only td, th, and table are acceptable offsetParents
273 : // apart from body or positioned elements; we need to check the content type as
274 : // well as the frame type so we ignore anonymous tables created by an element
275 : // with display: table-cell with no actual table
276 0 : nsIContent* content = aFrame->GetContent();
277 :
278 0 : return content->IsAnyOfHTMLElements(nsGkAtoms::table,
279 : nsGkAtoms::td,
280 0 : nsGkAtoms::th);
281 : }
282 0 : return false;
283 : }
284 :
285 : Element*
286 0 : nsGenericHTMLElement::GetOffsetRect(CSSIntRect& aRect)
287 : {
288 0 : aRect = CSSIntRect();
289 :
290 0 : nsIFrame* frame = GetStyledFrame();
291 0 : if (!frame) {
292 0 : return nullptr;
293 : }
294 :
295 0 : nsIFrame* parent = frame->GetParent();
296 0 : nsPoint origin(0, 0);
297 :
298 0 : if (parent && parent->IsTableWrapperFrame() && frame->IsTableFrame()) {
299 0 : origin = parent->GetPositionIgnoringScrolling();
300 0 : parent = parent->GetParent();
301 : }
302 :
303 0 : nsIContent* offsetParent = nullptr;
304 0 : Element* docElement = GetComposedDoc()->GetRootElement();
305 0 : nsIContent* content = frame->GetContent();
306 :
307 0 : if (content && (content->IsHTMLElement(nsGkAtoms::body) ||
308 : content == docElement)) {
309 0 : parent = frame;
310 : }
311 : else {
312 0 : const bool isPositioned = frame->IsAbsPosContainingBlock();
313 0 : const bool isAbsolutelyPositioned = frame->IsAbsolutelyPositioned();
314 0 : origin += frame->GetPositionIgnoringScrolling();
315 :
316 0 : for ( ; parent ; parent = parent->GetParent()) {
317 0 : content = parent->GetContent();
318 :
319 : // Stop at the first ancestor that is positioned.
320 0 : if (parent->IsAbsPosContainingBlock()) {
321 0 : offsetParent = content;
322 0 : break;
323 : }
324 :
325 : // Add the parent's origin to our own to get to the
326 : // right coordinate system.
327 0 : const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
328 0 : if (!isAbsolutelyPositioned && !isOffsetParent) {
329 0 : origin += parent->GetPositionIgnoringScrolling();
330 : }
331 :
332 0 : if (content) {
333 : // If we've hit the document element, break here.
334 0 : if (content == docElement) {
335 0 : break;
336 : }
337 :
338 : // Break if the ancestor frame type makes it suitable as offset parent
339 : // and this element is *not* positioned or if we found the body element.
340 0 : if (isOffsetParent || content->IsHTMLElement(nsGkAtoms::body)) {
341 0 : offsetParent = content;
342 0 : break;
343 : }
344 : }
345 : }
346 :
347 0 : if (isAbsolutelyPositioned && !offsetParent) {
348 : // If this element is absolutely positioned, but we don't have
349 : // an offset parent it means this element is an absolutely
350 : // positioned child that's not nested inside another positioned
351 : // element, in this case the element's frame's parent is the
352 : // frame for the HTML element so we fail to find the body in the
353 : // parent chain. We want the offset parent in this case to be
354 : // the body, so we just get the body element from the document.
355 :
356 0 : nsCOMPtr<nsIDOMHTMLDocument> html_doc(do_QueryInterface(GetComposedDoc()));
357 :
358 0 : if (html_doc) {
359 0 : offsetParent = static_cast<nsHTMLDocument*>(html_doc.get())->GetBody();
360 : }
361 : }
362 : }
363 :
364 : // Subtract the parent border unless it uses border-box sizing.
365 0 : if (parent &&
366 0 : parent->StylePosition()->mBoxSizing != StyleBoxSizing::Border) {
367 0 : const nsStyleBorder* border = parent->StyleBorder();
368 0 : origin.x -= border->GetComputedBorderWidth(eSideLeft);
369 0 : origin.y -= border->GetComputedBorderWidth(eSideTop);
370 : }
371 :
372 : // XXX We should really consider subtracting out padding for
373 : // content-box sizing, but we should see what IE does....
374 :
375 : // Get the union of all rectangles in this and continuation frames.
376 : // It doesn't really matter what we use as aRelativeTo here, since
377 : // we only care about the size. We just have to use something non-null.
378 0 : nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, frame);
379 0 : rcFrame.MoveTo(origin);
380 0 : aRect = CSSIntRect::FromAppUnitsRounded(rcFrame);
381 :
382 0 : return offsetParent ? offsetParent->AsElement() : nullptr;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : nsGenericHTMLElement::InsertAdjacentHTML(const nsAString& aPosition,
387 : const nsAString& aText)
388 : {
389 0 : ErrorResult rv;
390 0 : Element::InsertAdjacentHTML(aPosition, aText, rv);
391 0 : return rv.StealNSResult();
392 : }
393 :
394 : bool
395 4 : nsGenericHTMLElement::Spellcheck()
396 : {
397 : // Has the state has been explicitly set?
398 : nsIContent* node;
399 52 : for (node = this; node; node = node->GetParent()) {
400 48 : if (node->IsHTMLElement()) {
401 : static nsIContent::AttrValuesArray strings[] =
402 : {&nsGkAtoms::_true, &nsGkAtoms::_false, nullptr};
403 4 : switch (node->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::spellcheck,
404 4 : strings, eCaseMatters)) {
405 : case 0: // spellcheck = "true"
406 0 : return true;
407 : case 1: // spellcheck = "false"
408 0 : return false;
409 : }
410 : }
411 : }
412 :
413 : // contenteditable/designMode are spellchecked by default
414 4 : if (IsEditable()) {
415 0 : return true;
416 : }
417 :
418 : // Is this a chrome element?
419 4 : if (nsContentUtils::IsChromeDoc(OwnerDoc())) {
420 4 : return false; // Not spellchecked by default
421 : }
422 :
423 : // Anything else that's not a form control is not spellchecked by default
424 0 : nsCOMPtr<nsIFormControl> formControl = do_QueryObject(this);
425 0 : if (!formControl) {
426 0 : return false; // Not spellchecked by default
427 : }
428 :
429 : // Is this a multiline plaintext input?
430 0 : int32_t controlType = formControl->ControlType();
431 0 : if (controlType == NS_FORM_TEXTAREA) {
432 0 : return true; // Spellchecked by default
433 : }
434 :
435 : // Is this anything other than an input text?
436 : // Other inputs are not spellchecked.
437 0 : if (controlType != NS_FORM_INPUT_TEXT) {
438 0 : return false; // Not spellchecked by default
439 : }
440 :
441 : // Does the user want input text spellchecked by default?
442 : // NOTE: Do not reflect a pref value of 0 back to the DOM getter.
443 : // The web page should not know if the user has disabled spellchecking.
444 : // We'll catch this in the editor itself.
445 0 : int32_t spellcheckLevel = Preferences::GetInt("layout.spellcheckDefault", 1);
446 0 : return spellcheckLevel == 2; // "Spellcheck multi- and single-line"
447 : }
448 :
449 : bool
450 0 : nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
451 : {
452 0 : return aDoc && aDoc->GetCompatibilityMode() == eCompatibility_NavQuirks;
453 : }
454 :
455 : void
456 130 : nsGenericHTMLElement::UpdateEditableState(bool aNotify)
457 : {
458 : // XXX Should we do this only when in a document?
459 130 : ContentEditableTristate value = GetContentEditableValue();
460 130 : if (value != eInherit) {
461 0 : DoSetEditableFlag(!!value, aNotify);
462 0 : return;
463 : }
464 :
465 130 : nsStyledElement::UpdateEditableState(aNotify);
466 : }
467 :
468 : EventStates
469 187 : nsGenericHTMLElement::IntrinsicState() const
470 : {
471 187 : EventStates state = nsGenericHTMLElementBase::IntrinsicState();
472 :
473 187 : if (GetDirectionality() == eDir_RTL) {
474 0 : state |= NS_EVENT_STATE_RTL;
475 0 : state &= ~NS_EVENT_STATE_LTR;
476 : } else { // at least for HTML, directionality is exclusively LTR or RTL
477 187 : NS_ASSERTION(GetDirectionality() == eDir_LTR,
478 : "HTML element's directionality must be either RTL or LTR");
479 187 : state |= NS_EVENT_STATE_LTR;
480 187 : state &= ~NS_EVENT_STATE_RTL;
481 : }
482 :
483 187 : return state;
484 : }
485 :
486 : uint32_t
487 121 : nsGenericHTMLElement::EditableInclusiveDescendantCount()
488 : {
489 126 : bool isEditable = IsInUncomposedDoc() && HasFlag(NODE_IS_EDITABLE) &&
490 126 : GetContentEditableValue() == eTrue;
491 121 : return EditableDescendantCount() + isEditable;
492 : }
493 :
494 : nsresult
495 130 : nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
496 : nsIContent* aBindingParent,
497 : bool aCompileEventHandlers)
498 : {
499 130 : nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
500 : aBindingParent,
501 130 : aCompileEventHandlers);
502 130 : NS_ENSURE_SUCCESS(rv, rv);
503 :
504 130 : if (aDocument) {
505 97 : RegAccessKey();
506 97 : if (HasName()) {
507 : aDocument->
508 0 : AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
509 : }
510 :
511 97 : if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
512 0 : nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
513 0 : if (htmlDocument) {
514 0 : htmlDocument->ChangeContentEditableCount(this, +1);
515 : }
516 : }
517 : }
518 :
519 : // We need to consider a labels element is moved to another subtree
520 : // with different root, it needs to update labels list and its root
521 : // as well.
522 130 : nsDOMSlots* slots = GetExistingDOMSlots();
523 130 : if (slots && slots->mLabelsList) {
524 0 : slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
525 : }
526 :
527 130 : return rv;
528 : }
529 :
530 : void
531 10 : nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
532 : {
533 10 : if (IsInUncomposedDoc()) {
534 6 : UnregAccessKey();
535 : }
536 :
537 10 : RemoveFromNameTable();
538 :
539 10 : if (GetContentEditableValue() == eTrue) {
540 : //XXXsmaug Fix this for Shadow DOM, bug 1066965.
541 0 : nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetUncomposedDoc());
542 0 : if (htmlDocument) {
543 0 : htmlDocument->ChangeContentEditableCount(this, -1);
544 : }
545 : }
546 :
547 : // We need to consider a labels element is removed from tree,
548 : // it needs to update labels list and its root as well.
549 10 : nsDOMSlots* slots = GetExistingDOMSlots();
550 10 : if (slots && slots->mLabelsList) {
551 0 : slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
552 : }
553 :
554 10 : nsStyledElement::UnbindFromTree(aDeep, aNullParent);
555 10 : }
556 :
557 : HTMLFormElement*
558 29 : nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm)
559 : {
560 29 : NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
561 : IsHTMLElement(nsGkAtoms::img),
562 : "FindAncestorForm should not be called if @form is set!");
563 :
564 : // Make sure we don't end up finding a form that's anonymous from
565 : // our point of view.
566 29 : nsIContent* bindingParent = GetBindingParent();
567 :
568 29 : nsIContent* content = this;
569 291 : while (content != bindingParent && content) {
570 : // If the current ancestor is a form, return it as our form
571 131 : if (content->IsHTMLElement(nsGkAtoms::form)) {
572 : #ifdef DEBUG
573 0 : if (!nsContentUtils::IsInSameAnonymousTree(this, content)) {
574 : // It's possible that we started unbinding at |content| or
575 : // some ancestor of it, and |content| and |this| used to all be
576 : // anonymous. Check for this the hard way.
577 0 : for (nsIContent* child = this; child != content;
578 0 : child = child->GetParent()) {
579 0 : NS_ASSERTION(child->GetParent()->IndexOf(child) != -1,
580 : "Walked too far?");
581 : }
582 : }
583 : #endif
584 0 : return static_cast<HTMLFormElement*>(content);
585 : }
586 :
587 131 : nsIContent *prevContent = content;
588 131 : content = prevContent->GetParent();
589 :
590 131 : if (!content && aCurrentForm) {
591 : // We got to the root of the subtree we're in, and we're being removed
592 : // from the DOM (the only time we get into this method with a non-null
593 : // aCurrentForm). Check whether aCurrentForm is in the same subtree. If
594 : // it is, we want to return aCurrentForm, since this case means that
595 : // we're one of those inputs-in-a-table that have a hacked mForm pointer
596 : // and a subtree containing both us and the form got removed from the
597 : // DOM.
598 0 : if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) {
599 0 : return aCurrentForm;
600 : }
601 : }
602 : }
603 :
604 29 : return nullptr;
605 : }
606 :
607 : bool
608 0 : nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
609 : EventChainVisitor& aVisitor)
610 : {
611 0 : NS_PRECONDITION(nsCOMPtr<Link>(do_QueryObject(this)),
612 : "should be called only when |this| implements |Link|");
613 :
614 0 : if (!aVisitor.mPresContext) {
615 : // We need a pres context to do link stuff. Some events (e.g. mutation
616 : // events) don't have one.
617 : // XXX: ideally, shouldn't we be able to do what we need without one?
618 0 : return false;
619 : }
620 :
621 : //Need to check if we hit an imagemap area and if so see if we're handling
622 : //the event on that map or on a link farther up the tree. If we're on a
623 : //link farther up, do nothing.
624 0 : nsCOMPtr<nsIContent> target = aVisitor.mPresContext->EventStateManager()->
625 0 : GetEventTargetContent(aVisitor.mEvent);
626 :
627 0 : return !target || !target->IsHTMLElement(nsGkAtoms::area) ||
628 0 : IsHTMLElement(nsGkAtoms::area);
629 : }
630 :
631 : nsresult
632 0 : nsGenericHTMLElement::GetEventTargetParentForAnchors(EventChainPreVisitor& aVisitor)
633 : {
634 0 : nsresult rv = nsGenericHTMLElementBase::GetEventTargetParent(aVisitor);
635 0 : NS_ENSURE_SUCCESS(rv, rv);
636 :
637 0 : if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
638 0 : return NS_OK;
639 : }
640 :
641 0 : return GetEventTargetParentForLinks(aVisitor);
642 : }
643 :
644 : nsresult
645 0 : nsGenericHTMLElement::PostHandleEventForAnchors(EventChainPostVisitor& aVisitor)
646 : {
647 0 : if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
648 0 : return NS_OK;
649 : }
650 :
651 0 : return PostHandleEventForLinks(aVisitor);
652 : }
653 :
654 : bool
655 0 : nsGenericHTMLElement::IsHTMLLink(nsIURI** aURI) const
656 : {
657 0 : NS_PRECONDITION(aURI, "Must provide aURI out param");
658 :
659 0 : *aURI = GetHrefURIForAnchors().take();
660 : // We promise out param is non-null if we return true, so base rv on it
661 0 : return *aURI != nullptr;
662 : }
663 :
664 : already_AddRefed<nsIURI>
665 0 : nsGenericHTMLElement::GetHrefURIForAnchors() const
666 : {
667 : // This is used by the three Link implementations and
668 : // nsHTMLStyleElement.
669 :
670 : // Get href= attribute (relative URI).
671 :
672 : // We use the nsAttrValue's copy of the URI string to avoid copying.
673 0 : nsCOMPtr<nsIURI> uri;
674 0 : GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(uri));
675 :
676 0 : return uri.forget();
677 : }
678 :
679 : nsresult
680 139 : nsGenericHTMLElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
681 : const nsAttrValueOrString* aValue,
682 : bool aNotify)
683 : {
684 139 : if (aNamespaceID == kNameSpaceID_None) {
685 129 : if (aName == nsGkAtoms::accesskey) {
686 : // Have to unregister before clearing flag. See UnregAccessKey
687 0 : UnregAccessKey();
688 0 : if (!aValue) {
689 0 : UnsetFlags(NODE_HAS_ACCESSKEY);
690 : }
691 129 : } else if (aName == nsGkAtoms::name) {
692 : // Have to do this before clearing flag. See RemoveFromNameTable
693 0 : RemoveFromNameTable();
694 0 : if (!aValue || aValue->IsEmpty()) {
695 0 : ClearHasName();
696 : }
697 129 : } else if (aName == nsGkAtoms::contenteditable) {
698 0 : if (aValue) {
699 : // Set this before the attribute is set so that any subclass code that
700 : // runs before the attribute is set won't think we're missing a
701 : // contenteditable attr when we actually have one.
702 0 : SetMayHaveContentEditableAttr();
703 : }
704 : }
705 129 : if (!aValue && IsEventAttributeName(aName)) {
706 0 : if (EventListenerManager* manager = GetExistingListenerManager()) {
707 0 : manager->RemoveEventHandler(aName, EmptyString());
708 : }
709 : }
710 : }
711 :
712 139 : return nsGenericHTMLElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
713 139 : aNotify);
714 : }
715 :
716 : nsresult
717 139 : nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
718 : const nsAttrValue* aValue,
719 : const nsAttrValue* aOldValue, bool aNotify)
720 : {
721 139 : if (aNamespaceID == kNameSpaceID_None) {
722 129 : if (IsEventAttributeName(aName) && aValue) {
723 1 : MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
724 : "Expected string value for script body");
725 1 : nsresult rv = SetEventHandler(aName, aValue->GetStringValue());
726 1 : NS_ENSURE_SUCCESS(rv, rv);
727 : }
728 128 : else if (aNotify && aName == nsGkAtoms::spellcheck) {
729 0 : SyncEditorsOnSubtree(this);
730 : }
731 128 : else if (aName == nsGkAtoms::dir) {
732 0 : Directionality dir = eDir_LTR;
733 : // A boolean tracking whether we need to recompute our directionality.
734 : // This needs to happen after we update our internal "dir" attribute
735 : // state but before we call SetDirectionalityOnDescendants.
736 0 : bool recomputeDirectionality = false;
737 : // We don't want to have to keep getting the "dir" attribute in
738 : // IntrinsicState, so we manually recompute our dir-related event states
739 : // here and send the relevant update notifications.
740 0 : EventStates dirStates;
741 0 : if (aValue && aValue->Type() == nsAttrValue::eEnum) {
742 0 : SetHasValidDir();
743 0 : dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
744 0 : Directionality dirValue = (Directionality)aValue->GetEnumValue();
745 0 : if (dirValue == eDir_Auto) {
746 0 : dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
747 : } else {
748 0 : dir = dirValue;
749 0 : SetDirectionality(dir, aNotify);
750 0 : if (dirValue == eDir_LTR) {
751 0 : dirStates |= NS_EVENT_STATE_DIR_ATTR_LTR;
752 : } else {
753 0 : MOZ_ASSERT(dirValue == eDir_RTL);
754 0 : dirStates |= NS_EVENT_STATE_DIR_ATTR_RTL;
755 : }
756 : }
757 : } else {
758 0 : if (aValue) {
759 : // We have a value, just not a valid one.
760 0 : dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
761 : }
762 0 : ClearHasValidDir();
763 0 : if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
764 0 : dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
765 : } else {
766 0 : recomputeDirectionality = true;
767 : }
768 : }
769 : // Now figure out what's changed about our dir states.
770 0 : EventStates oldDirStates = State() & DIR_ATTR_STATES;
771 0 : EventStates changedStates = dirStates ^ oldDirStates;
772 0 : ToggleStates(changedStates, aNotify);
773 0 : if (recomputeDirectionality) {
774 0 : dir = RecomputeDirectionality(this, aNotify);
775 : }
776 0 : SetDirectionalityOnDescendants(this, dir, aNotify);
777 128 : } else if (aName == nsGkAtoms::contenteditable) {
778 0 : int32_t editableCountDelta = 0;
779 0 : if (aOldValue &&
780 0 : (aOldValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
781 0 : aOldValue->Equals(EmptyString(), eIgnoreCase))) {
782 0 : editableCountDelta = -1;
783 : }
784 0 : if (aValue && (aValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
785 0 : aValue->Equals(EmptyString(), eIgnoreCase))) {
786 0 : ++editableCountDelta;
787 : }
788 0 : ChangeEditableState(editableCountDelta);
789 128 : } else if (aName == nsGkAtoms::accesskey) {
790 0 : if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase)) {
791 0 : SetFlags(NODE_HAS_ACCESSKEY);
792 0 : RegAccessKey();
793 : }
794 128 : } else if (aName == nsGkAtoms::name) {
795 0 : if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase) &&
796 0 : CanHaveName(NodeInfo()->NameAtom())) {
797 : // This may not be quite right because we can have subclass code run
798 : // before here. But in practice subclasses don't care about this flag,
799 : // and in particular selector matching does not care. Otherwise we'd
800 : // want to handle it like we handle id attributes (in PreIdMaybeChange
801 : // and PostIdMaybeChange).
802 0 : SetHasName();
803 0 : AddToNameTable(aValue->GetAtomValue());
804 : }
805 : }
806 : }
807 :
808 139 : return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
809 139 : aValue, aOldValue, aNotify);
810 : }
811 :
812 : EventListenerManager*
813 1 : nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
814 : bool* aDefer)
815 : {
816 : // Attributes on the body and frameset tags get set on the global object
817 3 : if ((mNodeInfo->Equals(nsGkAtoms::body) ||
818 1 : mNodeInfo->Equals(nsGkAtoms::frameset)) &&
819 : // We only forward some event attributes from body/frameset to window
820 : (0
821 : #define EVENT(name_, id_, type_, struct_) /* nothing */
822 : #define FORWARDED_EVENT(name_, id_, type_, struct_) \
823 : || nsGkAtoms::on##name_ == aAttrName
824 : #define WINDOW_EVENT FORWARDED_EVENT
825 : #include "mozilla/EventNameList.h" // IWYU pragma: keep
826 : #undef WINDOW_EVENT
827 : #undef FORWARDED_EVENT
828 : #undef EVENT
829 : )
830 : ) {
831 : nsPIDOMWindowInner *win;
832 :
833 : // If we have a document, and it has a window, add the event
834 : // listener on the window (the inner window). If not, proceed as
835 : // normal.
836 : // XXXbz sXBL/XBL2 issue: should we instead use GetComposedDoc() here,
837 : // override BindToTree for those classes and munge event listeners there?
838 0 : nsIDocument *document = OwnerDoc();
839 :
840 0 : *aDefer = false;
841 0 : if ((win = document->GetInnerWindow())) {
842 0 : nsCOMPtr<EventTarget> piTarget(do_QueryInterface(win));
843 :
844 0 : return piTarget->GetOrCreateListenerManager();
845 : }
846 :
847 0 : return nullptr;
848 : }
849 :
850 1 : return nsGenericHTMLElementBase::GetEventListenerManagerForAttr(aAttrName,
851 1 : aDefer);
852 : }
853 :
854 : #define EVENT(name_, id_, type_, struct_) /* nothing; handled by nsINode */
855 : #define FORWARDED_EVENT(name_, id_, type_, struct_) \
856 : EventHandlerNonNull* \
857 : nsGenericHTMLElement::GetOn##name_() \
858 : { \
859 : if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
860 : /* XXXbz note to self: add tests for this! */ \
861 : if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
862 : nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
863 : return globalWin->GetOn##name_(); \
864 : } \
865 : return nullptr; \
866 : } \
867 : \
868 : return nsINode::GetOn##name_(); \
869 : } \
870 : void \
871 : nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
872 : { \
873 : if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
874 : nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
875 : if (!win) { \
876 : return; \
877 : } \
878 : \
879 : nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
880 : return globalWin->SetOn##name_(handler); \
881 : } \
882 : \
883 : return nsINode::SetOn##name_(handler); \
884 : }
885 : #define ERROR_EVENT(name_, id_, type_, struct_) \
886 : already_AddRefed<EventHandlerNonNull> \
887 : nsGenericHTMLElement::GetOn##name_() \
888 : { \
889 : if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
890 : /* XXXbz note to self: add tests for this! */ \
891 : if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
892 : nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
893 : OnErrorEventHandlerNonNull* errorHandler = globalWin->GetOn##name_(); \
894 : if (errorHandler) { \
895 : RefPtr<EventHandlerNonNull> handler = \
896 : new EventHandlerNonNull(errorHandler); \
897 : return handler.forget(); \
898 : } \
899 : } \
900 : return nullptr; \
901 : } \
902 : \
903 : RefPtr<EventHandlerNonNull> handler = nsINode::GetOn##name_(); \
904 : return handler.forget(); \
905 : } \
906 : void \
907 : nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
908 : { \
909 : if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
910 : nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
911 : if (!win) { \
912 : return; \
913 : } \
914 : \
915 : nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
916 : RefPtr<OnErrorEventHandlerNonNull> errorHandler; \
917 : if (handler) { \
918 : errorHandler = new OnErrorEventHandlerNonNull(handler); \
919 : } \
920 : return globalWin->SetOn##name_(errorHandler); \
921 : } \
922 : \
923 : return nsINode::SetOn##name_(handler); \
924 : }
925 : #include "mozilla/EventNameList.h" // IWYU pragma: keep
926 : #undef ERROR_EVENT
927 : #undef FORWARDED_EVENT
928 : #undef EVENT
929 :
930 : void
931 0 : nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
932 : {
933 0 : OwnerDoc()->GetBaseTarget(aBaseTarget);
934 0 : }
935 :
936 : //----------------------------------------------------------------------
937 :
938 : bool
939 86 : nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
940 : nsIAtom* aAttribute,
941 : const nsAString& aValue,
942 : nsAttrValue& aResult)
943 : {
944 86 : if (aNamespaceID == kNameSpaceID_None) {
945 76 : if (aAttribute == nsGkAtoms::dir) {
946 0 : return aResult.ParseEnumValue(aValue, kDirTable, false);
947 : }
948 :
949 76 : if (aAttribute == nsGkAtoms::tabindex) {
950 0 : return aResult.ParseIntValue(aValue);
951 : }
952 :
953 76 : if (aAttribute == nsGkAtoms::referrerpolicy) {
954 0 : return ParseReferrerAttribute(aValue, aResult);
955 : }
956 :
957 76 : if (aAttribute == nsGkAtoms::name) {
958 : // Store name as an atom. name="" means that the element has no name,
959 : // not that it has an empty string as the name.
960 0 : if (aValue.IsEmpty()) {
961 0 : return false;
962 : }
963 0 : aResult.ParseAtom(aValue);
964 0 : return true;
965 : }
966 :
967 76 : if (aAttribute == nsGkAtoms::contenteditable) {
968 0 : aResult.ParseAtom(aValue);
969 0 : return true;
970 : }
971 :
972 76 : if (aAttribute == nsGkAtoms::rel) {
973 0 : aResult.ParseAtomArray(aValue);
974 0 : return true;
975 : }
976 : }
977 :
978 86 : return nsGenericHTMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
979 86 : aValue, aResult);
980 : }
981 :
982 : bool
983 0 : nsGenericHTMLElement::ParseBackgroundAttribute(int32_t aNamespaceID,
984 : nsIAtom* aAttribute,
985 : const nsAString& aValue,
986 : nsAttrValue& aResult)
987 : {
988 0 : if (aNamespaceID == kNameSpaceID_None &&
989 0 : aAttribute == nsGkAtoms::background &&
990 0 : !aValue.IsEmpty()) {
991 : // Resolve url to an absolute url
992 0 : nsIDocument* doc = OwnerDoc();
993 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
994 0 : nsCOMPtr<nsIURI> uri;
995 0 : nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
996 0 : getter_AddRefs(uri), aValue, doc, baseURI);
997 0 : if (NS_FAILED(rv)) {
998 0 : return false;
999 : }
1000 :
1001 : mozilla::css::URLValue *url =
1002 0 : new mozilla::css::URLValue(uri, aValue, baseURI, doc->GetDocumentURI(),
1003 0 : NodePrincipal());
1004 0 : aResult.SetTo(url, &aValue);
1005 0 : return true;
1006 : }
1007 :
1008 0 : return false;
1009 : }
1010 :
1011 : bool
1012 26 : nsGenericHTMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
1013 : {
1014 : static const MappedAttributeEntry* const map[] = {
1015 : sCommonAttributeMap
1016 : };
1017 :
1018 26 : return FindAttributeDependence(aAttribute, map);
1019 : }
1020 :
1021 : nsMapRuleToAttributesFunc
1022 0 : nsGenericHTMLElement::GetAttributeMappingFunction() const
1023 : {
1024 0 : return &MapCommonAttributesInto;
1025 : }
1026 :
1027 : nsIFormControlFrame*
1028 0 : nsGenericHTMLElement::GetFormControlFrame(bool aFlushFrames)
1029 : {
1030 0 : if (aFlushFrames && IsInComposedDoc()) {
1031 : // Cause a flush of the frames, so we get up-to-date frame information
1032 0 : GetComposedDoc()->FlushPendingNotifications(FlushType::Frames);
1033 : }
1034 0 : nsIFrame* frame = GetPrimaryFrame();
1035 0 : if (frame) {
1036 0 : nsIFormControlFrame* form_frame = do_QueryFrame(frame);
1037 0 : if (form_frame) {
1038 0 : return form_frame;
1039 : }
1040 :
1041 : // If we have generated content, the primary frame will be a
1042 : // wrapper frame.. out real frame will be in its child list.
1043 0 : for (frame = frame->PrincipalChildList().FirstChild();
1044 0 : frame;
1045 : frame = frame->GetNextSibling()) {
1046 0 : form_frame = do_QueryFrame(frame);
1047 0 : if (form_frame) {
1048 0 : return form_frame;
1049 : }
1050 : }
1051 : }
1052 :
1053 0 : return nullptr;
1054 : }
1055 :
1056 : nsPresContext*
1057 0 : nsGenericHTMLElement::GetPresContext(PresContextFor aFor)
1058 : {
1059 : // Get the document
1060 0 : nsIDocument* doc = (aFor == eForComposedDoc) ?
1061 0 : GetComposedDoc() : GetUncomposedDoc();
1062 0 : if (doc) {
1063 : // Get presentation shell.
1064 0 : nsIPresShell *presShell = doc->GetShell();
1065 0 : if (presShell) {
1066 0 : return presShell->GetPresContext();
1067 : }
1068 : }
1069 :
1070 0 : return nullptr;
1071 : }
1072 :
1073 : static const nsAttrValue::EnumTable kDivAlignTable[] = {
1074 : { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
1075 : { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
1076 : { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1077 : { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1078 : { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
1079 : { nullptr, 0 }
1080 : };
1081 :
1082 : static const nsAttrValue::EnumTable kFrameborderTable[] = {
1083 : { "yes", NS_STYLE_FRAME_YES },
1084 : { "no", NS_STYLE_FRAME_NO },
1085 : { "1", NS_STYLE_FRAME_1 },
1086 : { "0", NS_STYLE_FRAME_0 },
1087 : { nullptr, 0 }
1088 : };
1089 :
1090 : static const nsAttrValue::EnumTable kScrollingTable[] = {
1091 : { "yes", NS_STYLE_FRAME_YES },
1092 : { "no", NS_STYLE_FRAME_NO },
1093 : { "on", NS_STYLE_FRAME_ON },
1094 : { "off", NS_STYLE_FRAME_OFF },
1095 : { "scroll", NS_STYLE_FRAME_SCROLL },
1096 : { "noscroll", NS_STYLE_FRAME_NOSCROLL },
1097 : { "auto", NS_STYLE_FRAME_AUTO },
1098 : { nullptr, 0 }
1099 : };
1100 :
1101 : static const nsAttrValue::EnumTable kTableVAlignTable[] = {
1102 : { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
1103 : { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1104 : { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
1105 : { "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
1106 : { nullptr, 0 }
1107 : };
1108 :
1109 : bool
1110 0 : nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
1111 : nsAttrValue& aResult)
1112 : {
1113 : static const nsAttrValue::EnumTable kAlignTable[] = {
1114 : { "left", NS_STYLE_TEXT_ALIGN_LEFT },
1115 : { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
1116 :
1117 : { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
1118 : { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
1119 : { "bottom", NS_STYLE_VERTICAL_ALIGN_BASELINE },
1120 :
1121 : { "center", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
1122 : { "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE },
1123 :
1124 : { "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
1125 : { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1126 : { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1127 : { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
1128 : { nullptr, 0 }
1129 : };
1130 :
1131 0 : return aResult.ParseEnumValue(aString, kAlignTable, false);
1132 : }
1133 :
1134 : //----------------------------------------
1135 :
1136 : static const nsAttrValue::EnumTable kTableHAlignTable[] = {
1137 : { "left", NS_STYLE_TEXT_ALIGN_LEFT },
1138 : { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
1139 : { "center", NS_STYLE_TEXT_ALIGN_CENTER },
1140 : { "char", NS_STYLE_TEXT_ALIGN_CHAR },
1141 : { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
1142 : { nullptr, 0 }
1143 : };
1144 :
1145 : bool
1146 0 : nsGenericHTMLElement::ParseTableHAlignValue(const nsAString& aString,
1147 : nsAttrValue& aResult)
1148 : {
1149 0 : return aResult.ParseEnumValue(aString, kTableHAlignTable, false);
1150 : }
1151 :
1152 : //----------------------------------------
1153 :
1154 : // This table is used for td, th, tr, col, thead, tbody and tfoot.
1155 : static const nsAttrValue::EnumTable kTableCellHAlignTable[] = {
1156 : { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
1157 : { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
1158 : { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1159 : { "char", NS_STYLE_TEXT_ALIGN_CHAR },
1160 : { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
1161 : { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1162 : { "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
1163 : { nullptr, 0 }
1164 : };
1165 :
1166 : bool
1167 0 : nsGenericHTMLElement::ParseTableCellHAlignValue(const nsAString& aString,
1168 : nsAttrValue& aResult)
1169 : {
1170 0 : return aResult.ParseEnumValue(aString, kTableCellHAlignTable, false);
1171 : }
1172 :
1173 : //----------------------------------------
1174 :
1175 : bool
1176 0 : nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
1177 : nsAttrValue& aResult)
1178 : {
1179 0 : return aResult.ParseEnumValue(aString, kTableVAlignTable, false);
1180 : }
1181 :
1182 : bool
1183 0 : nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
1184 : nsAttrValue& aResult)
1185 : {
1186 0 : return aResult.ParseEnumValue(aString, kDivAlignTable, false);
1187 : }
1188 :
1189 : bool
1190 20 : nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
1191 : const nsAString& aString,
1192 : nsAttrValue& aResult)
1193 : {
1194 40 : if ((aAttribute == nsGkAtoms::width) ||
1195 20 : (aAttribute == nsGkAtoms::height)) {
1196 0 : return aResult.ParseSpecialIntValue(aString);
1197 : }
1198 40 : if ((aAttribute == nsGkAtoms::hspace) ||
1199 40 : (aAttribute == nsGkAtoms::vspace) ||
1200 20 : (aAttribute == nsGkAtoms::border)) {
1201 0 : return aResult.ParseIntWithBounds(aString, 0);
1202 : }
1203 20 : return false;
1204 : }
1205 :
1206 : bool
1207 0 : nsGenericHTMLElement::ParseReferrerAttribute(const nsAString& aString,
1208 : nsAttrValue& aResult)
1209 : {
1210 : static const nsAttrValue::EnumTable kReferrerTable[] = {
1211 : { net::kRPS_No_Referrer, static_cast<int16_t>(net::RP_No_Referrer) },
1212 : { net::kRPS_Origin, static_cast<int16_t>(net::RP_Origin) },
1213 : { net::kRPS_Origin_When_Cross_Origin, static_cast<int16_t>(net::RP_Origin_When_Crossorigin) },
1214 : { net::kRPS_No_Referrer_When_Downgrade, static_cast<int16_t>(net::RP_No_Referrer_When_Downgrade) },
1215 : { net::kRPS_Unsafe_URL, static_cast<int16_t>(net::RP_Unsafe_URL) },
1216 : { net::kRPS_Strict_Origin, static_cast<int16_t>(net::RP_Strict_Origin) },
1217 : { net::kRPS_Same_Origin, static_cast<int16_t>(net::RP_Same_Origin) },
1218 : { net::kRPS_Strict_Origin_When_Cross_Origin, static_cast<int16_t>(net::RP_Strict_Origin_When_Cross_Origin) },
1219 : { nullptr, 0 }
1220 : };
1221 0 : return aResult.ParseEnumValue(aString, kReferrerTable, false);
1222 : }
1223 :
1224 : bool
1225 0 : nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
1226 : nsAttrValue& aResult)
1227 : {
1228 0 : return aResult.ParseEnumValue(aString, kFrameborderTable, false);
1229 : }
1230 :
1231 : bool
1232 0 : nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
1233 : nsAttrValue& aResult)
1234 : {
1235 0 : return aResult.ParseEnumValue(aString, kScrollingTable, false);
1236 : }
1237 :
1238 : static inline void
1239 172 : MapLangAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData)
1240 : {
1241 172 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font) |
1242 : NS_STYLE_INHERIT_BIT(Text))) {
1243 160 : return;
1244 : }
1245 :
1246 12 : const nsAttrValue* langValue = aAttributes->GetAttr(nsGkAtoms::lang);
1247 12 : if (!langValue) {
1248 12 : return;
1249 : }
1250 0 : MOZ_ASSERT(langValue->Type() == nsAttrValue::eAtom);
1251 0 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font))) {
1252 0 : aData->SetIdentAtomValueIfUnset(eCSSProperty__x_lang,
1253 0 : langValue->GetAtomValue());
1254 : }
1255 0 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
1256 0 : if (!aData->PropertyIsSet(eCSSProperty_text_emphasis_position)) {
1257 0 : const nsIAtom* lang = langValue->GetAtomValue();
1258 0 : if (nsStyleUtil::MatchesLanguagePrefix(lang, u"zh")) {
1259 : aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
1260 0 : NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH);
1261 0 : } else if (nsStyleUtil::MatchesLanguagePrefix(lang, u"ja") ||
1262 0 : nsStyleUtil::MatchesLanguagePrefix(lang, u"mn")) {
1263 : // This branch is currently no part of the spec.
1264 : // See bug 1040668 comment 69 and comment 75.
1265 : aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
1266 0 : NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT);
1267 : }
1268 : }
1269 : }
1270 : }
1271 :
1272 : /**
1273 : * Handle attributes common to all html elements
1274 : */
1275 : void
1276 172 : nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(const nsMappedAttributes* aAttributes,
1277 : GenericSpecifiedValues* aData)
1278 : {
1279 172 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(UserInterface))) {
1280 38 : if (!aData->PropertyIsSet(eCSSProperty__moz_user_modify)) {
1281 : const nsAttrValue* value =
1282 35 : aAttributes->GetAttr(nsGkAtoms::contenteditable);
1283 35 : if (value) {
1284 0 : if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
1285 0 : value->Equals(nsGkAtoms::_true, eIgnoreCase)) {
1286 : aData->SetKeywordValue(eCSSProperty__moz_user_modify,
1287 0 : StyleUserModify::ReadWrite);
1288 : }
1289 0 : else if (value->Equals(nsGkAtoms::_false, eIgnoreCase)) {
1290 : aData->SetKeywordValue(eCSSProperty__moz_user_modify,
1291 0 : StyleUserModify::ReadOnly);
1292 : }
1293 : }
1294 : }
1295 : }
1296 :
1297 172 : MapLangAttributeInto(aAttributes, aData);
1298 172 : }
1299 :
1300 : void
1301 172 : nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
1302 : GenericSpecifiedValues* aData)
1303 : {
1304 172 : MapCommonAttributesIntoExceptHidden(aAttributes, aData);
1305 :
1306 172 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
1307 33 : if (!aData->PropertyIsSet(eCSSProperty_display)) {
1308 33 : if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
1309 28 : aData->SetKeywordValue(eCSSProperty_display, StyleDisplay::None);
1310 : }
1311 : }
1312 : }
1313 172 : }
1314 :
1315 : /* static */ const nsGenericHTMLElement::MappedAttributeEntry
1316 : nsGenericHTMLElement::sCommonAttributeMap[] = {
1317 : { &nsGkAtoms::contenteditable },
1318 : { &nsGkAtoms::lang },
1319 : { &nsGkAtoms::hidden },
1320 : { nullptr }
1321 : };
1322 :
1323 : /* static */ const Element::MappedAttributeEntry
1324 : nsGenericHTMLElement::sImageMarginSizeAttributeMap[] = {
1325 : { &nsGkAtoms::width },
1326 : { &nsGkAtoms::height },
1327 : { &nsGkAtoms::hspace },
1328 : { &nsGkAtoms::vspace },
1329 : { nullptr }
1330 : };
1331 :
1332 : /* static */ const Element::MappedAttributeEntry
1333 : nsGenericHTMLElement::sImageAlignAttributeMap[] = {
1334 : { &nsGkAtoms::align },
1335 : { nullptr }
1336 : };
1337 :
1338 : /* static */ const Element::MappedAttributeEntry
1339 : nsGenericHTMLElement::sDivAlignAttributeMap[] = {
1340 : { &nsGkAtoms::align },
1341 : { nullptr }
1342 : };
1343 :
1344 : /* static */ const Element::MappedAttributeEntry
1345 : nsGenericHTMLElement::sImageBorderAttributeMap[] = {
1346 : { &nsGkAtoms::border },
1347 : { nullptr }
1348 : };
1349 :
1350 : /* static */ const Element::MappedAttributeEntry
1351 : nsGenericHTMLElement::sBackgroundAttributeMap[] = {
1352 : { &nsGkAtoms::background },
1353 : { &nsGkAtoms::bgcolor },
1354 : { nullptr }
1355 : };
1356 :
1357 : /* static */ const Element::MappedAttributeEntry
1358 : nsGenericHTMLElement::sBackgroundColorAttributeMap[] = {
1359 : { &nsGkAtoms::bgcolor },
1360 : { nullptr }
1361 : };
1362 :
1363 : void
1364 0 : nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
1365 : GenericSpecifiedValues* aData)
1366 : {
1367 0 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
1368 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
1369 0 : if (value && value->Type() == nsAttrValue::eEnum) {
1370 0 : int32_t align = value->GetEnumValue();
1371 0 : if (!aData->PropertyIsSet(eCSSProperty_float_)) {
1372 0 : if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
1373 0 : aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Left);
1374 0 : } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
1375 0 : aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Right);
1376 : }
1377 : }
1378 0 : if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
1379 0 : switch (align) {
1380 : case NS_STYLE_TEXT_ALIGN_LEFT:
1381 : case NS_STYLE_TEXT_ALIGN_RIGHT:
1382 0 : break;
1383 : default:
1384 0 : aData->SetKeywordValue(eCSSProperty_vertical_align, align);
1385 0 : break;
1386 : }
1387 : }
1388 : }
1389 : }
1390 0 : }
1391 :
1392 : void
1393 88 : nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
1394 : GenericSpecifiedValues* aData)
1395 : {
1396 88 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
1397 0 : if (!aData->PropertyIsSet(eCSSProperty_text_align)) {
1398 : // align: enum
1399 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
1400 0 : if (value && value->Type() == nsAttrValue::eEnum)
1401 0 : aData->SetKeywordValue(eCSSProperty_text_align, value->GetEnumValue());
1402 : }
1403 : }
1404 88 : }
1405 :
1406 : void
1407 0 : nsGenericHTMLElement::MapVAlignAttributeInto(const nsMappedAttributes* aAttributes,
1408 : GenericSpecifiedValues* aData)
1409 : {
1410 0 : if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
1411 0 : if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
1412 : // align: enum
1413 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::valign);
1414 0 : if (value && value->Type() == nsAttrValue::eEnum)
1415 0 : aData->SetKeywordValue(eCSSProperty_vertical_align, value->GetEnumValue());
1416 : }
1417 : }
1418 0 : }
1419 :
1420 : void
1421 0 : nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
1422 : GenericSpecifiedValues* aData)
1423 : {
1424 0 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Margin)))
1425 0 : return;
1426 :
1427 : const nsAttrValue* value;
1428 :
1429 : // hspace: value
1430 0 : value = aAttributes->GetAttr(nsGkAtoms::hspace);
1431 0 : if (value) {
1432 0 : if (value->Type() == nsAttrValue::eInteger) {
1433 0 : aData->SetPixelValueIfUnset(eCSSProperty_margin_left,
1434 0 : (float)value->GetIntegerValue());
1435 0 : aData->SetPixelValueIfUnset(eCSSProperty_margin_right,
1436 0 : (float)value->GetIntegerValue());
1437 0 : } else if (value->Type() == nsAttrValue::ePercent) {
1438 0 : aData->SetPercentValueIfUnset(eCSSProperty_margin_left,
1439 0 : value->GetPercentValue());
1440 0 : aData->SetPercentValueIfUnset(eCSSProperty_margin_right,
1441 0 : value->GetPercentValue());
1442 : }
1443 : }
1444 :
1445 : // vspace: value
1446 0 : value = aAttributes->GetAttr(nsGkAtoms::vspace);
1447 0 : if (value) {
1448 0 : if (value->Type() == nsAttrValue::eInteger) {
1449 0 : aData->SetPixelValueIfUnset(eCSSProperty_margin_top,
1450 0 : (float)value->GetIntegerValue());
1451 0 : aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom,
1452 0 : (float)value->GetIntegerValue());
1453 0 : } else if (value->Type() == nsAttrValue::ePercent) {
1454 0 : aData->SetPercentValueIfUnset(eCSSProperty_margin_top,
1455 0 : value->GetPercentValue());
1456 0 : aData->SetPercentValueIfUnset(eCSSProperty_margin_bottom,
1457 0 : value->GetPercentValue());
1458 : }
1459 : }
1460 : }
1461 :
1462 : void
1463 0 : nsGenericHTMLElement::MapWidthAttributeInto(const nsMappedAttributes* aAttributes,
1464 : GenericSpecifiedValues* aData)
1465 : {
1466 0 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Position))) {
1467 0 : return;
1468 : }
1469 :
1470 : // width: value
1471 0 : if (!aData->PropertyIsSet(eCSSProperty_width)) {
1472 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
1473 0 : if (value && value->Type() == nsAttrValue::eInteger) {
1474 0 : aData->SetPixelValue(eCSSProperty_width,
1475 0 : (float)value->GetIntegerValue());
1476 0 : } else if (value && value->Type() == nsAttrValue::ePercent) {
1477 0 : aData->SetPercentValue(eCSSProperty_width,
1478 0 : value->GetPercentValue());
1479 : }
1480 : }
1481 : }
1482 :
1483 : void
1484 0 : nsGenericHTMLElement::MapHeightAttributeInto(const nsMappedAttributes* aAttributes,
1485 : GenericSpecifiedValues* aData)
1486 : {
1487 0 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Position)))
1488 0 : return;
1489 :
1490 : // height: value
1491 0 : if (!aData->PropertyIsSet(eCSSProperty_height)) {
1492 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
1493 0 : if (value && value->Type() == nsAttrValue::eInteger) {
1494 0 : aData->SetPixelValue(eCSSProperty_height,
1495 0 : (float)value->GetIntegerValue());
1496 0 : } else if (value && value->Type() == nsAttrValue::ePercent) {
1497 0 : aData->SetPercentValue(eCSSProperty_height,
1498 0 : value->GetPercentValue());
1499 : }
1500 : }
1501 : }
1502 :
1503 : void
1504 0 : nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
1505 : GenericSpecifiedValues* aData)
1506 : {
1507 0 : nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aData);
1508 0 : nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aData);
1509 0 : }
1510 :
1511 : void
1512 0 : nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
1513 : GenericSpecifiedValues* aData)
1514 : {
1515 0 : if (!(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Border))))
1516 0 : return;
1517 :
1518 : // border: pixels
1519 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
1520 0 : if (!value)
1521 0 : return;
1522 :
1523 0 : nscoord val = 0;
1524 0 : if (value->Type() == nsAttrValue::eInteger)
1525 0 : val = value->GetIntegerValue();
1526 :
1527 0 : aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)val);
1528 0 : aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)val);
1529 0 : aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)val);
1530 0 : aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)val);
1531 :
1532 : aData->SetKeywordValueIfUnset(eCSSProperty_border_top_style,
1533 0 : NS_STYLE_BORDER_STYLE_SOLID);
1534 : aData->SetKeywordValueIfUnset(eCSSProperty_border_right_style,
1535 0 : NS_STYLE_BORDER_STYLE_SOLID);
1536 : aData->SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
1537 0 : NS_STYLE_BORDER_STYLE_SOLID);
1538 : aData->SetKeywordValueIfUnset(eCSSProperty_border_left_style,
1539 0 : NS_STYLE_BORDER_STYLE_SOLID);
1540 :
1541 0 : aData->SetCurrentColorIfUnset(eCSSProperty_border_top_color);
1542 0 : aData->SetCurrentColorIfUnset(eCSSProperty_border_right_color);
1543 0 : aData->SetCurrentColorIfUnset(eCSSProperty_border_bottom_color);
1544 0 : aData->SetCurrentColorIfUnset(eCSSProperty_border_left_color);
1545 : }
1546 :
1547 : void
1548 51 : nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
1549 : GenericSpecifiedValues* aData)
1550 : {
1551 :
1552 51 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
1553 48 : return;
1554 :
1555 6 : if (!aData->PropertyIsSet(eCSSProperty_background_image) &&
1556 3 : aData->PresContext()->UseDocumentColors()) {
1557 : // background
1558 : nsAttrValue* value =
1559 3 : const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
1560 3 : if (value) {
1561 0 : aData->SetBackgroundImage(*value);
1562 : }
1563 : }
1564 : }
1565 :
1566 : void
1567 51 : nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
1568 : GenericSpecifiedValues* aData)
1569 : {
1570 51 : if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
1571 48 : return;
1572 :
1573 6 : if (!aData->PropertyIsSet(eCSSProperty_background_color) &&
1574 3 : aData->PresContext()->UseDocumentColors()) {
1575 3 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
1576 : nscolor color;
1577 3 : if (value && value->GetColorValue(color)) {
1578 0 : aData->SetColorValue(eCSSProperty_background_color, color);
1579 : }
1580 : }
1581 : }
1582 :
1583 : void
1584 51 : nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
1585 : GenericSpecifiedValues* aData)
1586 : {
1587 51 : MapBackgroundInto(aAttributes, aData);
1588 51 : MapBGColorInto(aAttributes, aData);
1589 51 : }
1590 :
1591 : //----------------------------------------------------------------------
1592 :
1593 : nsresult
1594 0 : nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
1595 : {
1596 0 : return SetAttr(kNameSpaceID_None, aAttr, aValue, true);
1597 : }
1598 :
1599 : int32_t
1600 0 : nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, int32_t aDefault) const
1601 : {
1602 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
1603 0 : if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
1604 0 : return attrVal->GetIntegerValue();
1605 : }
1606 0 : return aDefault;
1607 : }
1608 :
1609 : nsresult
1610 0 : nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, int32_t aValue)
1611 : {
1612 0 : nsAutoString value;
1613 0 : value.AppendInt(aValue);
1614 :
1615 0 : return SetAttr(kNameSpaceID_None, aAttr, value, true);
1616 : }
1617 :
1618 : uint32_t
1619 0 : nsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom* aAttr,
1620 : uint32_t aDefault) const
1621 : {
1622 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
1623 0 : if (!attrVal || attrVal->Type() != nsAttrValue::eInteger) {
1624 0 : return aDefault;
1625 : }
1626 :
1627 0 : return attrVal->GetIntegerValue();
1628 : }
1629 :
1630 : void
1631 0 : nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr,
1632 : nsAString& aResult) const
1633 : {
1634 0 : nsCOMPtr<nsIURI> uri;
1635 0 : bool hadAttr = GetURIAttr(aAttr, aBaseAttr, getter_AddRefs(uri));
1636 0 : if (!hadAttr) {
1637 0 : aResult.Truncate();
1638 0 : return;
1639 : }
1640 :
1641 0 : if (!uri) {
1642 : // Just return the attr value
1643 0 : GetAttr(kNameSpaceID_None, aAttr, aResult);
1644 0 : return;
1645 : }
1646 :
1647 0 : nsAutoCString spec;
1648 0 : uri->GetSpec(spec);
1649 0 : CopyUTF8toUTF16(spec, aResult);
1650 : }
1651 :
1652 : bool
1653 0 : nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aURI) const
1654 : {
1655 0 : *aURI = nullptr;
1656 :
1657 0 : const nsAttrValue* attr = mAttrsAndChildren.GetAttr(aAttr);
1658 0 : if (!attr) {
1659 0 : return false;
1660 : }
1661 :
1662 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
1663 :
1664 0 : if (aBaseAttr) {
1665 0 : nsAutoString baseAttrValue;
1666 0 : if (GetAttr(kNameSpaceID_None, aBaseAttr, baseAttrValue)) {
1667 0 : nsCOMPtr<nsIURI> baseAttrURI;
1668 : nsresult rv =
1669 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(baseAttrURI),
1670 : baseAttrValue, OwnerDoc(),
1671 0 : baseURI);
1672 0 : if (NS_FAILED(rv)) {
1673 0 : return true;
1674 : }
1675 0 : baseURI.swap(baseAttrURI);
1676 : }
1677 : }
1678 :
1679 : // Don't care about return value. If it fails, we still want to
1680 : // return true, and *aURI will be null.
1681 0 : nsContentUtils::NewURIWithDocumentCharset(aURI,
1682 0 : attr->GetStringValue(),
1683 0 : OwnerDoc(), baseURI);
1684 0 : return true;
1685 : }
1686 :
1687 : HTMLMenuElement*
1688 0 : nsGenericHTMLElement::GetContextMenu() const
1689 : {
1690 0 : nsAutoString value;
1691 0 : GetHTMLAttr(nsGkAtoms::contextmenu, value);
1692 0 : if (!value.IsEmpty()) {
1693 : //XXXsmaug How should this work in Shadow DOM?
1694 0 : nsIDocument* doc = GetUncomposedDoc();
1695 0 : if (doc) {
1696 0 : return HTMLMenuElement::FromContentOrNull(doc->GetElementById(value));
1697 : }
1698 : }
1699 0 : return nullptr;
1700 : }
1701 :
1702 : NS_IMETHODIMP
1703 0 : nsGenericHTMLElement::GetContextMenu(nsIDOMHTMLMenuElement** aContextMenu)
1704 : {
1705 0 : NS_IF_ADDREF(*aContextMenu = GetContextMenu());
1706 0 : return NS_OK;
1707 : }
1708 :
1709 : bool
1710 0 : nsGenericHTMLElement::IsLabelable() const
1711 : {
1712 0 : return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
1713 : }
1714 :
1715 : /* static */ bool
1716 0 : nsGenericHTMLElement::MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
1717 : nsIAtom* aAtom, void* aData)
1718 : {
1719 0 : HTMLLabelElement* element = HTMLLabelElement::FromContent(aElement);
1720 0 : return element && element->GetControl() == aData;
1721 : }
1722 :
1723 : already_AddRefed<nsINodeList>
1724 0 : nsGenericHTMLElement::Labels()
1725 : {
1726 0 : MOZ_ASSERT(IsLabelable(),
1727 : "Labels() only allow labelable elements to use it.");
1728 0 : nsDOMSlots* slots = DOMSlots();
1729 :
1730 0 : if (!slots->mLabelsList) {
1731 0 : slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement,
1732 0 : nullptr, this);
1733 : }
1734 :
1735 0 : RefPtr<nsLabelsNodeList> labels = slots->mLabelsList;
1736 0 : return labels.forget();
1737 : }
1738 :
1739 : bool
1740 0 : nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
1741 : {
1742 0 : return IsAnyOfHTMLElements(nsGkAtoms::details, nsGkAtoms::embed,
1743 0 : nsGkAtoms::keygen) ||
1744 0 : (!aIgnoreTabindex && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
1745 : }
1746 :
1747 : // static
1748 : bool
1749 24 : nsGenericHTMLElement::TouchEventsEnabled(JSContext* aCx, JSObject* aGlobal)
1750 : {
1751 24 : return TouchEvent::PrefEnabled(aCx, aGlobal);
1752 : }
1753 :
1754 : //----------------------------------------------------------------------
1755 :
1756 9 : nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
1757 9 : uint8_t aType)
1758 : : nsGenericHTMLElement(aNodeInfo)
1759 : , nsIFormControl(aType)
1760 : , mForm(nullptr)
1761 9 : , mFieldSet(nullptr)
1762 : {
1763 : // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
1764 : // that depends on our type, which is not initialized yet. So we
1765 : // have to do this in subclasses.
1766 9 : }
1767 :
1768 0 : nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
1769 : {
1770 0 : if (mFieldSet) {
1771 0 : mFieldSet->RemoveElement(this);
1772 : }
1773 :
1774 : // Check that this element doesn't know anything about its form at this point.
1775 0 : NS_ASSERTION(!mForm, "mForm should be null at this point!");
1776 0 : }
1777 :
1778 161 : NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement,
1779 : nsGenericHTMLElement,
1780 : nsIFormControl)
1781 :
1782 : nsINode*
1783 0 : nsGenericHTMLFormElement::GetScopeChainParent() const
1784 : {
1785 0 : return mForm ? mForm : nsGenericHTMLElement::GetScopeChainParent();
1786 : }
1787 :
1788 : bool
1789 1044 : nsGenericHTMLFormElement::IsNodeOfType(uint32_t aFlags) const
1790 : {
1791 1044 : return !(aFlags & ~(eCONTENT | eHTML_FORM_CONTROL));
1792 : }
1793 :
1794 : void
1795 0 : nsGenericHTMLFormElement::SaveSubtreeState()
1796 : {
1797 0 : SaveState();
1798 :
1799 0 : nsGenericHTMLElement::SaveSubtreeState();
1800 0 : }
1801 :
1802 : void
1803 0 : nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
1804 : {
1805 0 : NS_PRECONDITION(aForm, "Don't pass null here");
1806 0 : NS_ASSERTION(!mForm,
1807 : "We don't support switching from one non-null form to another.");
1808 :
1809 0 : SetForm(static_cast<HTMLFormElement*>(aForm), false);
1810 0 : }
1811 :
1812 25 : void nsGenericHTMLFormElement::SetForm(HTMLFormElement* aForm, bool aBindToTree)
1813 : {
1814 25 : if (aForm) {
1815 0 : BeforeSetForm(aBindToTree);
1816 : }
1817 :
1818 : // keep a *weak* ref to the form here
1819 25 : mForm = aForm;
1820 25 : }
1821 :
1822 : void
1823 0 : nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete)
1824 : {
1825 0 : NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM),
1826 : "Form control should have had flag set correctly");
1827 :
1828 0 : if (!mForm) {
1829 0 : return;
1830 : }
1831 :
1832 0 : if (aRemoveFromForm) {
1833 0 : nsAutoString nameVal, idVal;
1834 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
1835 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
1836 :
1837 0 : mForm->RemoveElement(this, true);
1838 :
1839 0 : if (!nameVal.IsEmpty()) {
1840 0 : mForm->RemoveElementFromTable(this, nameVal);
1841 : }
1842 :
1843 0 : if (!idVal.IsEmpty()) {
1844 0 : mForm->RemoveElementFromTable(this, idVal);
1845 : }
1846 : }
1847 :
1848 0 : UnsetFlags(ADDED_TO_FORM);
1849 0 : mForm = nullptr;
1850 :
1851 0 : AfterClearForm(aUnbindOrDelete);
1852 : }
1853 :
1854 : Element*
1855 0 : nsGenericHTMLFormElement::GetFormElement()
1856 : {
1857 0 : return mForm;
1858 : }
1859 :
1860 : HTMLFieldSetElement*
1861 0 : nsGenericHTMLFormElement::GetFieldSet()
1862 : {
1863 0 : return mFieldSet;
1864 : }
1865 :
1866 : nsresult
1867 0 : nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
1868 : {
1869 0 : NS_ENSURE_ARG_POINTER(aForm);
1870 0 : NS_IF_ADDREF(*aForm = mForm);
1871 0 : return NS_OK;
1872 : }
1873 :
1874 : nsIContent::IMEState
1875 0 : nsGenericHTMLFormElement::GetDesiredIMEState()
1876 : {
1877 0 : TextEditor* textEditor = GetTextEditorInternal();
1878 0 : if (!textEditor) {
1879 0 : return nsGenericHTMLElement::GetDesiredIMEState();
1880 : }
1881 0 : IMEState state;
1882 0 : nsresult rv = textEditor->GetPreferredIMEState(&state);
1883 0 : if (NS_FAILED(rv)) {
1884 0 : return nsGenericHTMLElement::GetDesiredIMEState();
1885 : }
1886 0 : return state;
1887 : }
1888 :
1889 : nsresult
1890 25 : nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
1891 : nsIContent* aParent,
1892 : nsIContent* aBindingParent,
1893 : bool aCompileEventHandlers)
1894 : {
1895 25 : nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
1896 : aBindingParent,
1897 25 : aCompileEventHandlers);
1898 25 : NS_ENSURE_SUCCESS(rv, rv);
1899 :
1900 : // An autofocus event has to be launched if the autofocus attribute is
1901 : // specified and the element accept the autofocus attribute. In addition,
1902 : // the document should not be already loaded and the "browser.autofocus"
1903 : // preference should be 'true'.
1904 25 : if (IsAutofocusable() && HasAttr(kNameSpaceID_None, nsGkAtoms::autofocus) &&
1905 0 : nsContentUtils::AutoFocusEnabled()) {
1906 0 : nsCOMPtr<nsIRunnable> event = new nsAutoFocusEvent(this);
1907 0 : rv = NS_DispatchToCurrentThread(event);
1908 0 : NS_ENSURE_SUCCESS(rv, rv);
1909 : }
1910 :
1911 : // If @form is set, the element *has* to be in a document, otherwise it
1912 : // wouldn't be possible to find an element with the corresponding id.
1913 : // If @form isn't set, the element *has* to have a parent, otherwise it
1914 : // wouldn't be possible to find a form ancestor.
1915 : // We should not call UpdateFormOwner if none of these conditions are
1916 : // fulfilled.
1917 25 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetUncomposedDoc()
1918 : : !!aParent) {
1919 25 : UpdateFormOwner(true, nullptr);
1920 : }
1921 :
1922 : // Set parent fieldset which should be used for the disabled state.
1923 25 : UpdateFieldSet(false);
1924 :
1925 25 : return NS_OK;
1926 : }
1927 :
1928 : void
1929 2 : nsGenericHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
1930 : {
1931 : // Save state before doing anything
1932 2 : SaveState();
1933 :
1934 2 : if (mForm) {
1935 : // Might need to unset mForm
1936 0 : if (aNullParent) {
1937 : // No more parent means no more form
1938 0 : ClearForm(true, true);
1939 : } else {
1940 : // Recheck whether we should still have an mForm.
1941 0 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
1942 0 : !FindAncestorForm(mForm)) {
1943 0 : ClearForm(true, true);
1944 : } else {
1945 0 : UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
1946 : }
1947 : }
1948 :
1949 0 : if (!mForm) {
1950 : // Our novalidate state might have changed
1951 0 : UpdateState(false);
1952 : }
1953 : }
1954 :
1955 : // We have to remove the form id observer if there was one.
1956 : // We will re-add one later if needed (during bind to tree).
1957 2 : if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
1958 : nsGkAtoms::form)) {
1959 0 : RemoveFormIdObserver();
1960 : }
1961 :
1962 2 : nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
1963 :
1964 : // The element might not have a fieldset anymore.
1965 2 : UpdateFieldSet(false);
1966 2 : }
1967 :
1968 : nsresult
1969 37 : nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
1970 : const nsAttrValueOrString* aValue,
1971 : bool aNotify)
1972 : {
1973 37 : if (aNameSpaceID == kNameSpaceID_None) {
1974 58 : nsAutoString tmp;
1975 :
1976 : // remove the control from the hashtable as needed
1977 :
1978 29 : if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
1979 0 : GetAttr(kNameSpaceID_None, aName, tmp);
1980 :
1981 0 : if (!tmp.IsEmpty()) {
1982 0 : mForm->RemoveElementFromTable(this, tmp);
1983 : }
1984 : }
1985 :
1986 29 : if (mForm && aName == nsGkAtoms::type) {
1987 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
1988 :
1989 0 : if (!tmp.IsEmpty()) {
1990 0 : mForm->RemoveElementFromTable(this, tmp);
1991 : }
1992 :
1993 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
1994 :
1995 0 : if (!tmp.IsEmpty()) {
1996 0 : mForm->RemoveElementFromTable(this, tmp);
1997 : }
1998 :
1999 0 : mForm->RemoveElement(this, false);
2000 : }
2001 :
2002 29 : if (aName == nsGkAtoms::form) {
2003 : // If @form isn't set or set to the empty string, there were no observer
2004 : // so we don't have to remove it.
2005 0 : if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
2006 : nsGkAtoms::form)) {
2007 : // The current form id observer is no longer needed.
2008 : // A new one may be added in AfterSetAttr.
2009 0 : RemoveFormIdObserver();
2010 : }
2011 : }
2012 : }
2013 :
2014 37 : return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
2015 37 : aValue, aNotify);
2016 : }
2017 :
2018 : nsresult
2019 37 : nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
2020 : const nsAttrValue* aValue,
2021 : const nsAttrValue* aOldValue, bool aNotify)
2022 : {
2023 37 : if (aNameSpaceID == kNameSpaceID_None) {
2024 : // add the control to the hashtable as needed
2025 :
2026 58 : if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
2027 29 : aValue && !aValue->IsEmptyString()) {
2028 0 : MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom,
2029 : "Expected atom value for name/id");
2030 0 : mForm->AddElementToTable(this,
2031 0 : nsDependentAtomString(aValue->GetAtomValue()));
2032 : }
2033 :
2034 29 : if (mForm && aName == nsGkAtoms::type) {
2035 0 : nsAutoString tmp;
2036 :
2037 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
2038 :
2039 0 : if (!tmp.IsEmpty()) {
2040 0 : mForm->AddElementToTable(this, tmp);
2041 : }
2042 :
2043 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
2044 :
2045 0 : if (!tmp.IsEmpty()) {
2046 0 : mForm->AddElementToTable(this, tmp);
2047 : }
2048 :
2049 0 : mForm->AddElement(this, false, aNotify);
2050 : }
2051 :
2052 29 : if (aName == nsGkAtoms::form) {
2053 : // We need a new form id observer.
2054 : //XXXsmaug How should this work in Shadow DOM?
2055 0 : nsIDocument* doc = GetUncomposedDoc();
2056 0 : if (doc) {
2057 0 : Element* formIdElement = nullptr;
2058 0 : if (aValue && !aValue->IsEmptyString()) {
2059 0 : formIdElement = AddFormIdObserver();
2060 : }
2061 :
2062 : // Because we have a new @form value (or no more @form), we have to
2063 : // update our form owner.
2064 0 : UpdateFormOwner(false, formIdElement);
2065 : }
2066 : }
2067 : }
2068 :
2069 37 : return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
2070 37 : aValue, aOldValue, aNotify);
2071 : }
2072 :
2073 : nsresult
2074 4 : nsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
2075 : {
2076 8 : if (aVisitor.mEvent->IsTrusted() && (aVisitor.mEvent->mMessage == eFocus ||
2077 4 : aVisitor.mEvent->mMessage == eBlur)) {
2078 : // We have to handle focus/blur event to change focus states in
2079 : // PreHandleEvent to prevent it breaks event target chain creation.
2080 0 : aVisitor.mWantsPreHandleEvent = true;
2081 : }
2082 4 : return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
2083 : }
2084 :
2085 : nsresult
2086 0 : nsGenericHTMLFormElement::PreHandleEvent(EventChainVisitor& aVisitor)
2087 : {
2088 0 : if (aVisitor.mEvent->IsTrusted()) {
2089 0 : switch (aVisitor.mEvent->mMessage) {
2090 : case eFocus: {
2091 : // Check to see if focus has bubbled up from a form control's
2092 : // child textfield or button. If that's the case, don't focus
2093 : // this parent file control -- leave focus on the child.
2094 0 : nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
2095 0 : if (formControlFrame &&
2096 0 : aVisitor.mEvent->mOriginalTarget == static_cast<nsINode*>(this))
2097 0 : formControlFrame->SetFocus(true, true);
2098 0 : break;
2099 : }
2100 : case eBlur: {
2101 0 : nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
2102 0 : if (formControlFrame)
2103 0 : formControlFrame->SetFocus(false, false);
2104 0 : break;
2105 : }
2106 : default:
2107 0 : break;
2108 : }
2109 : }
2110 0 : return nsGenericHTMLElement::PreHandleEvent(aVisitor);
2111 : }
2112 :
2113 : /* virtual */
2114 : bool
2115 100 : nsGenericHTMLFormElement::IsDisabled() const
2116 : {
2117 200 : return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
2118 200 : (mFieldSet && mFieldSet->IsDisabled());
2119 : }
2120 :
2121 : void
2122 0 : nsGenericHTMLFormElement::ForgetFieldSet(nsIContent* aFieldset)
2123 : {
2124 0 : if (mFieldSet == aFieldset) {
2125 0 : mFieldSet = nullptr;
2126 : }
2127 0 : }
2128 :
2129 : bool
2130 69 : nsGenericHTMLFormElement::CanBeDisabled() const
2131 : {
2132 69 : int32_t type = ControlType();
2133 : // It's easier to test the types that _cannot_ be disabled
2134 : return
2135 69 : type != NS_FORM_OBJECT &&
2136 69 : type != NS_FORM_OUTPUT;
2137 : }
2138 :
2139 : bool
2140 0 : nsGenericHTMLFormElement::IsHTMLFocusable(bool aWithMouse,
2141 : bool* aIsFocusable,
2142 : int32_t* aTabIndex)
2143 : {
2144 0 : if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
2145 0 : return true;
2146 : }
2147 :
2148 : #ifdef XP_MACOSX
2149 : *aIsFocusable =
2150 : (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) && *aIsFocusable;
2151 : #endif
2152 0 : return false;
2153 : }
2154 :
2155 : EventStates
2156 69 : nsGenericHTMLFormElement::IntrinsicState() const
2157 : {
2158 : // If you add attribute-dependent states here, you need to add them them to
2159 : // AfterSetAttr too. And add them to AfterSetAttr for all subclasses that
2160 : // implement IntrinsicState() and are affected by that attribute.
2161 69 : EventStates state = nsGenericHTMLElement::IntrinsicState();
2162 :
2163 69 : if (CanBeDisabled()) {
2164 : // :enabled/:disabled
2165 69 : if (IsDisabled()) {
2166 0 : state |= NS_EVENT_STATE_DISABLED;
2167 0 : state &= ~NS_EVENT_STATE_ENABLED;
2168 : } else {
2169 69 : state &= ~NS_EVENT_STATE_DISABLED;
2170 69 : state |= NS_EVENT_STATE_ENABLED;
2171 : }
2172 : }
2173 :
2174 69 : if (mForm && mForm->IsDefaultSubmitElement(this)) {
2175 0 : NS_ASSERTION(IsSubmitControl(),
2176 : "Default submit element that isn't a submit control.");
2177 : // We are the default submit element (:default)
2178 0 : state |= NS_EVENT_STATE_DEFAULT;
2179 : }
2180 :
2181 : // Make the text controls read-write
2182 138 : if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
2183 69 : IsTextOrNumberControl(/*aExcludePassword*/ false)) {
2184 66 : bool roState = GetBoolAttr(nsGkAtoms::readonly);
2185 :
2186 66 : if (!roState) {
2187 66 : state |= NS_EVENT_STATE_MOZ_READWRITE;
2188 66 : state &= ~NS_EVENT_STATE_MOZ_READONLY;
2189 : }
2190 : }
2191 :
2192 69 : return state;
2193 : }
2194 :
2195 : nsGenericHTMLFormElement::FocusTristate
2196 0 : nsGenericHTMLFormElement::FocusState()
2197 : {
2198 : // We can't be focused if we aren't in a (composed) document
2199 0 : nsIDocument* doc = GetComposedDoc();
2200 0 : if (!doc)
2201 0 : return eUnfocusable;
2202 :
2203 : // first see if we are disabled or not. If disabled then do nothing.
2204 0 : if (IsDisabled()) {
2205 0 : return eUnfocusable;
2206 : }
2207 :
2208 : // If the window is not active, do not allow the focus to bring the
2209 : // window to the front. We update the focus controller, but do
2210 : // nothing else.
2211 0 : if (nsPIDOMWindowOuter* win = doc->GetWindow()) {
2212 0 : nsCOMPtr<nsPIDOMWindowOuter> rootWindow = win->GetPrivateRoot();
2213 :
2214 0 : nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
2215 0 : if (fm && rootWindow) {
2216 0 : nsCOMPtr<mozIDOMWindowProxy> activeWindow;
2217 0 : fm->GetActiveWindow(getter_AddRefs(activeWindow));
2218 0 : if (activeWindow == rootWindow) {
2219 0 : return eActiveWindow;
2220 : }
2221 : }
2222 : }
2223 :
2224 0 : return eInactiveWindow;
2225 : }
2226 :
2227 : Element*
2228 0 : nsGenericHTMLFormElement::AddFormIdObserver()
2229 : {
2230 0 : NS_ASSERTION(GetUncomposedDoc(), "When adding a form id observer, "
2231 : "we should be in a document!");
2232 :
2233 0 : nsAutoString formId;
2234 0 : nsIDocument* doc = OwnerDoc();
2235 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
2236 0 : NS_ASSERTION(!formId.IsEmpty(),
2237 : "@form value should not be the empty string!");
2238 0 : nsCOMPtr<nsIAtom> atom = NS_Atomize(formId);
2239 :
2240 0 : return doc->AddIDTargetObserver(atom, FormIdUpdated, this, false);
2241 : }
2242 :
2243 : void
2244 0 : nsGenericHTMLFormElement::RemoveFormIdObserver()
2245 : {
2246 : /**
2247 : * We are using OwnerDoc() because we don't really care about having the
2248 : * element actually being in the tree. If it is not and @form value changes,
2249 : * this method will be called for nothing but removing an observer which does
2250 : * not exist doesn't cost so much (no entry in the hash table) so having a
2251 : * boolean for GetUncomposedDoc()/GetOwnerDoc() would make everything look
2252 : * more complex for nothing.
2253 : */
2254 :
2255 0 : nsIDocument* doc = OwnerDoc();
2256 :
2257 : // At this point, we may not have a document anymore. In that case, we can't
2258 : // remove the observer. The document did that for us.
2259 0 : if (!doc) {
2260 0 : return;
2261 : }
2262 :
2263 0 : nsAutoString formId;
2264 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
2265 0 : NS_ASSERTION(!formId.IsEmpty(),
2266 : "@form value should not be the empty string!");
2267 0 : nsCOMPtr<nsIAtom> atom = NS_Atomize(formId);
2268 :
2269 0 : doc->RemoveIDTargetObserver(atom, FormIdUpdated, this, false);
2270 : }
2271 :
2272 :
2273 : /* static */
2274 : bool
2275 0 : nsGenericHTMLFormElement::FormIdUpdated(Element* aOldElement,
2276 : Element* aNewElement,
2277 : void* aData)
2278 : {
2279 : nsGenericHTMLFormElement* element =
2280 0 : static_cast<nsGenericHTMLFormElement*>(aData);
2281 :
2282 0 : NS_ASSERTION(element->IsHTMLElement(), "aData should be an HTML element");
2283 :
2284 0 : element->UpdateFormOwner(false, aNewElement);
2285 :
2286 0 : return true;
2287 : }
2288 :
2289 : bool
2290 4 : nsGenericHTMLFormElement::IsElementDisabledForEvents(EventMessage aMessage,
2291 : nsIFrame* aFrame)
2292 : {
2293 4 : switch (aMessage) {
2294 : case eMouseMove:
2295 : case eMouseOver:
2296 : case eMouseOut:
2297 : case eMouseEnter:
2298 : case eMouseLeave:
2299 : case ePointerMove:
2300 : case ePointerOver:
2301 : case ePointerOut:
2302 : case ePointerEnter:
2303 : case ePointerLeave:
2304 : case eWheel:
2305 : case eLegacyMouseLineOrPageScroll:
2306 : case eLegacyMousePixelScroll:
2307 0 : return false;
2308 : default:
2309 4 : break;
2310 : }
2311 :
2312 4 : bool disabled = IsDisabled();
2313 4 : if (!disabled && aFrame) {
2314 4 : const nsStyleUserInterface* uiStyle = aFrame->StyleUserInterface();
2315 8 : disabled = uiStyle->mUserInput == StyleUserInput::None ||
2316 4 : uiStyle->mUserInput == StyleUserInput::Disabled;
2317 :
2318 : }
2319 4 : return disabled;
2320 : }
2321 :
2322 : void
2323 25 : nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
2324 : Element* aFormIdElement)
2325 : {
2326 25 : NS_PRECONDITION(!aBindToTree || !aFormIdElement,
2327 : "aFormIdElement shouldn't be set if aBindToTree is true!");
2328 :
2329 25 : bool needStateUpdate = false;
2330 25 : if (!aBindToTree) {
2331 0 : needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
2332 0 : ClearForm(true, false);
2333 : }
2334 :
2335 25 : HTMLFormElement *oldForm = mForm;
2336 :
2337 25 : if (!mForm) {
2338 : // If @form is set, we have to use that to find the form.
2339 50 : nsAutoString formId;
2340 25 : if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) {
2341 0 : if (!formId.IsEmpty()) {
2342 0 : Element* element = nullptr;
2343 :
2344 0 : if (aBindToTree) {
2345 0 : element = AddFormIdObserver();
2346 : } else {
2347 0 : element = aFormIdElement;
2348 : }
2349 :
2350 0 : NS_ASSERTION(GetUncomposedDoc(), "The element should be in a document "
2351 : "when UpdateFormOwner is called!");
2352 0 : NS_ASSERTION(!GetUncomposedDoc() ||
2353 : element == GetUncomposedDoc()->GetElementById(formId),
2354 : "element should be equals to the current element "
2355 : "associated with the id in @form!");
2356 :
2357 0 : if (element && element->IsHTMLElement(nsGkAtoms::form)) {
2358 0 : SetForm(static_cast<HTMLFormElement*>(element), aBindToTree);
2359 : }
2360 : }
2361 : } else {
2362 : // We now have a parent, so we may have picked up an ancestor form. Search
2363 : // for it. Note that if mForm is already set we don't want to do this,
2364 : // because that means someone (probably the content sink) has already set
2365 : // it to the right value. Also note that even if being bound here didn't
2366 : // change our parent, we still need to search, since our parent chain
2367 : // probably changed _somewhere_.
2368 25 : SetForm(FindAncestorForm(), aBindToTree);
2369 : }
2370 : }
2371 :
2372 25 : if (mForm && !HasFlag(ADDED_TO_FORM)) {
2373 : // Now we need to add ourselves to the form
2374 0 : nsAutoString nameVal, idVal;
2375 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
2376 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
2377 :
2378 0 : SetFlags(ADDED_TO_FORM);
2379 :
2380 : // Notify only if we just found this mForm.
2381 0 : mForm->AddElement(this, true, oldForm == nullptr);
2382 :
2383 0 : if (!nameVal.IsEmpty()) {
2384 0 : mForm->AddElementToTable(this, nameVal);
2385 : }
2386 :
2387 0 : if (!idVal.IsEmpty()) {
2388 0 : mForm->AddElementToTable(this, idVal);
2389 : }
2390 : }
2391 :
2392 25 : if (mForm != oldForm || needStateUpdate) {
2393 0 : UpdateState(true);
2394 : }
2395 25 : }
2396 :
2397 : void
2398 27 : nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify)
2399 : {
2400 27 : nsIContent* parent = nullptr;
2401 27 : nsIContent* prev = nullptr;
2402 :
2403 113 : for (parent = GetParent(); parent;
2404 86 : prev = parent, parent = parent->GetParent()) {
2405 : HTMLFieldSetElement* fieldset =
2406 86 : HTMLFieldSetElement::FromContent(parent);
2407 86 : if (fieldset &&
2408 0 : (!prev || fieldset->GetFirstLegend() != prev)) {
2409 0 : if (mFieldSet == fieldset) {
2410 : // We already have the right fieldset;
2411 0 : return;
2412 : }
2413 :
2414 0 : if (mFieldSet) {
2415 0 : mFieldSet->RemoveElement(this);
2416 : }
2417 0 : mFieldSet = fieldset;
2418 0 : fieldset->AddElement(this);
2419 :
2420 : // The disabled state may have changed
2421 0 : FieldSetDisabledChanged(aNotify);
2422 0 : return;
2423 : }
2424 : }
2425 :
2426 : // No fieldset found.
2427 27 : if (mFieldSet) {
2428 0 : mFieldSet->RemoveElement(this);
2429 0 : mFieldSet = nullptr;
2430 : // The disabled state may have changed
2431 0 : FieldSetDisabledChanged(aNotify);
2432 : }
2433 : }
2434 :
2435 : void
2436 0 : nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
2437 : {
2438 0 : UpdateState(aNotify);
2439 0 : }
2440 :
2441 : bool
2442 0 : nsGenericHTMLFormElement::IsLabelable() const
2443 : {
2444 : // TODO: keygen should be in that list, see bug 101019.
2445 0 : uint32_t type = ControlType();
2446 0 : return (type & NS_FORM_INPUT_ELEMENT && type != NS_FORM_INPUT_HIDDEN) ||
2447 0 : type & NS_FORM_BUTTON_ELEMENT ||
2448 : // type == NS_FORM_KEYGEN ||
2449 0 : type == NS_FORM_OUTPUT ||
2450 0 : type == NS_FORM_SELECT ||
2451 0 : type == NS_FORM_TEXTAREA;
2452 : }
2453 :
2454 : //----------------------------------------------------------------------
2455 :
2456 : void
2457 0 : nsGenericHTMLElement::Click(CallerType aCallerType)
2458 : {
2459 0 : if (HandlingClick())
2460 0 : return;
2461 :
2462 : // Strong in case the event kills it
2463 0 : nsCOMPtr<nsIDocument> doc = GetComposedDoc();
2464 :
2465 0 : nsCOMPtr<nsIPresShell> shell;
2466 0 : RefPtr<nsPresContext> context;
2467 0 : if (doc) {
2468 0 : shell = doc->GetShell();
2469 0 : if (shell) {
2470 0 : context = shell->GetPresContext();
2471 : }
2472 : }
2473 :
2474 0 : SetHandlingClick();
2475 :
2476 : // Mark this event trusted if Click() is called from system code.
2477 : WidgetMouseEvent event(aCallerType == CallerType::System,
2478 0 : eMouseClick, nullptr, WidgetMouseEvent::eReal);
2479 0 : event.mFlags.mIsPositionless = true;
2480 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
2481 :
2482 0 : EventDispatcher::Dispatch(static_cast<nsIContent*>(this), context, &event);
2483 :
2484 0 : ClearHandlingClick();
2485 : }
2486 :
2487 : bool
2488 0 : nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse,
2489 : bool *aIsFocusable,
2490 : int32_t *aTabIndex)
2491 : {
2492 0 : nsIDocument* doc = GetComposedDoc();
2493 0 : if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
2494 : // In designMode documents we only allow focusing the document.
2495 0 : if (aTabIndex) {
2496 0 : *aTabIndex = -1;
2497 : }
2498 :
2499 0 : *aIsFocusable = false;
2500 :
2501 0 : return true;
2502 : }
2503 :
2504 0 : int32_t tabIndex = TabIndex();
2505 0 : bool disabled = false;
2506 0 : bool disallowOverridingFocusability = true;
2507 :
2508 0 : if (IsEditableRoot()) {
2509 : // Editable roots should always be focusable.
2510 0 : disallowOverridingFocusability = true;
2511 :
2512 : // Ignore the disabled attribute in editable contentEditable/designMode
2513 : // roots.
2514 0 : if (!HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
2515 : // The default value for tabindex should be 0 for editable
2516 : // contentEditable roots.
2517 0 : tabIndex = 0;
2518 : }
2519 : }
2520 : else {
2521 0 : disallowOverridingFocusability = false;
2522 :
2523 : // Just check for disabled attribute on form controls
2524 0 : disabled = IsDisabled();
2525 0 : if (disabled) {
2526 0 : tabIndex = -1;
2527 : }
2528 : }
2529 :
2530 0 : if (aTabIndex) {
2531 0 : *aTabIndex = tabIndex;
2532 : }
2533 :
2534 : // If a tabindex is specified at all, or the default tabindex is 0, we're focusable
2535 0 : *aIsFocusable =
2536 0 : (tabIndex >= 0 || (!disabled && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)));
2537 :
2538 0 : return disallowOverridingFocusability;
2539 : }
2540 :
2541 : void
2542 0 : nsGenericHTMLElement::RegUnRegAccessKey(bool aDoReg)
2543 : {
2544 : // first check to see if we have an access key
2545 0 : nsAutoString accessKey;
2546 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
2547 0 : if (accessKey.IsEmpty()) {
2548 0 : return;
2549 : }
2550 :
2551 : // We have an access key, so get the ESM from the pres context.
2552 0 : nsPresContext* presContext = GetPresContext(eForUncomposedDoc);
2553 :
2554 0 : if (presContext) {
2555 0 : EventStateManager* esm = presContext->EventStateManager();
2556 :
2557 : // Register or unregister as appropriate.
2558 0 : if (aDoReg) {
2559 0 : esm->RegisterAccessKey(this, (uint32_t)accessKey.First());
2560 : } else {
2561 0 : esm->UnregisterAccessKey(this, (uint32_t)accessKey.First());
2562 : }
2563 : }
2564 : }
2565 :
2566 : bool
2567 0 : nsGenericHTMLElement::PerformAccesskey(bool aKeyCausesActivation,
2568 : bool aIsTrustedEvent)
2569 : {
2570 0 : nsPresContext* presContext = GetPresContext(eForUncomposedDoc);
2571 0 : if (!presContext) {
2572 0 : return false;
2573 : }
2574 :
2575 : // It's hard to say what HTML4 wants us to do in all cases.
2576 0 : bool focused = true;
2577 0 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
2578 0 : if (fm) {
2579 0 : fm->SetFocus(this, nsIFocusManager::FLAG_BYKEY);
2580 :
2581 : // Return true if the element became the current focus within its window.
2582 0 : nsPIDOMWindowOuter* window = OwnerDoc()->GetWindow();
2583 0 : focused = (window && window->GetFocusedNode());
2584 : }
2585 :
2586 0 : if (aKeyCausesActivation) {
2587 : // Click on it if the users prefs indicate to do so.
2588 : nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
2589 0 : openAllowed : openAbused);
2590 0 : DispatchSimulatedClick(this, aIsTrustedEvent, presContext);
2591 : }
2592 :
2593 0 : return focused;
2594 : }
2595 :
2596 : nsresult
2597 0 : nsGenericHTMLElement::DispatchSimulatedClick(nsGenericHTMLElement* aElement,
2598 : bool aIsTrusted,
2599 : nsPresContext* aPresContext)
2600 : {
2601 : WidgetMouseEvent event(aIsTrusted, eMouseClick, nullptr,
2602 0 : WidgetMouseEvent::eReal);
2603 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
2604 0 : event.mFlags.mIsPositionless = true;
2605 0 : return EventDispatcher::Dispatch(ToSupports(aElement), aPresContext, &event);
2606 : }
2607 :
2608 : already_AddRefed<nsIEditor>
2609 0 : nsGenericHTMLElement::GetAssociatedEditor()
2610 : {
2611 : // If contenteditable is ever implemented, it might need to do something different here?
2612 :
2613 0 : RefPtr<TextEditor> textEditor = GetTextEditorInternal();
2614 0 : return textEditor.forget();
2615 : }
2616 :
2617 : bool
2618 0 : nsGenericHTMLElement::IsCurrentBodyElement()
2619 : {
2620 : // TODO Bug 698498: Should this handle the case where GetBody returns a
2621 : // frameset?
2622 0 : if (!IsHTMLElement(nsGkAtoms::body)) {
2623 0 : return false;
2624 : }
2625 :
2626 : nsCOMPtr<nsIDOMHTMLDocument> htmlDocument =
2627 0 : do_QueryInterface(GetUncomposedDoc());
2628 0 : if (!htmlDocument) {
2629 0 : return false;
2630 : }
2631 :
2632 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement;
2633 0 : htmlDocument->GetBody(getter_AddRefs(htmlElement));
2634 0 : return htmlElement == static_cast<HTMLBodyElement*>(this);
2635 : }
2636 :
2637 : // static
2638 : void
2639 0 : nsGenericHTMLElement::SyncEditorsOnSubtree(nsIContent* content)
2640 : {
2641 : /* Sync this node */
2642 0 : nsGenericHTMLElement* element = FromContent(content);
2643 0 : if (element) {
2644 0 : nsCOMPtr<nsIEditor> editor = element->GetAssociatedEditor();
2645 0 : if (editor) {
2646 0 : editor->SyncRealTimeSpell();
2647 : }
2648 : }
2649 :
2650 : /* Sync all children */
2651 0 : for (nsIContent* child = content->GetFirstChild();
2652 0 : child;
2653 0 : child = child->GetNextSibling()) {
2654 0 : SyncEditorsOnSubtree(child);
2655 : }
2656 0 : }
2657 :
2658 : void
2659 0 : nsGenericHTMLElement::RecompileScriptEventListeners()
2660 : {
2661 0 : int32_t i, count = mAttrsAndChildren.AttrCount();
2662 0 : for (i = 0; i < count; ++i) {
2663 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
2664 :
2665 : // Eventlistenener-attributes are always in the null namespace
2666 0 : if (!name->IsAtom()) {
2667 0 : continue;
2668 : }
2669 :
2670 0 : nsIAtom *attr = name->Atom();
2671 0 : if (!IsEventAttributeName(attr)) {
2672 0 : continue;
2673 : }
2674 :
2675 0 : nsAutoString value;
2676 0 : GetAttr(kNameSpaceID_None, attr, value);
2677 0 : SetEventHandler(attr, value, true);
2678 : }
2679 0 : }
2680 :
2681 : bool
2682 0 : nsGenericHTMLElement::IsEditableRoot() const
2683 : {
2684 0 : nsIDocument *document = GetComposedDoc();
2685 0 : if (!document) {
2686 0 : return false;
2687 : }
2688 :
2689 0 : if (document->HasFlag(NODE_IS_EDITABLE)) {
2690 0 : return false;
2691 : }
2692 :
2693 0 : if (GetContentEditableValue() != eTrue) {
2694 0 : return false;
2695 : }
2696 :
2697 0 : nsIContent *parent = GetParent();
2698 :
2699 0 : return !parent || !parent->HasFlag(NODE_IS_EDITABLE);
2700 : }
2701 :
2702 : static void
2703 0 : MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
2704 : {
2705 : // If aContent is not an element, we just need to update its
2706 : // internal editable state and don't need to notify anyone about
2707 : // that. For elements, we need to send a ContentStateChanged
2708 : // notification.
2709 0 : if (!aContent->IsElement()) {
2710 0 : aContent->UpdateEditableState(false);
2711 0 : return;
2712 : }
2713 :
2714 0 : Element *element = aContent->AsElement();
2715 :
2716 0 : element->UpdateEditableState(true);
2717 :
2718 0 : for (nsIContent *child = aContent->GetFirstChild();
2719 0 : child;
2720 0 : child = child->GetNextSibling()) {
2721 0 : if (!child->HasAttr(kNameSpaceID_None, nsGkAtoms::contenteditable)) {
2722 0 : MakeContentDescendantsEditable(child, aDocument);
2723 : }
2724 : }
2725 : }
2726 :
2727 : void
2728 0 : nsGenericHTMLElement::ChangeEditableState(int32_t aChange)
2729 : {
2730 : //XXXsmaug Fix this for Shadow DOM, bug 1066965.
2731 0 : nsIDocument* document = GetUncomposedDoc();
2732 0 : if (!document) {
2733 0 : return;
2734 : }
2735 :
2736 0 : if (aChange != 0) {
2737 : nsCOMPtr<nsIHTMLDocument> htmlDocument =
2738 0 : do_QueryInterface(document);
2739 0 : if (htmlDocument) {
2740 0 : htmlDocument->ChangeContentEditableCount(this, aChange);
2741 : }
2742 :
2743 0 : nsIContent* parent = GetParent();
2744 0 : while (parent) {
2745 0 : parent->ChangeEditableDescendantCount(aChange);
2746 0 : parent = parent->GetParent();
2747 : }
2748 : }
2749 :
2750 0 : if (document->HasFlag(NODE_IS_EDITABLE)) {
2751 0 : document = nullptr;
2752 : }
2753 :
2754 : // MakeContentDescendantsEditable is going to call ContentStateChanged for
2755 : // this element and all descendants if editable state has changed.
2756 : // We might as well wrap it all in one script blocker.
2757 0 : nsAutoScriptBlocker scriptBlocker;
2758 0 : MakeContentDescendantsEditable(this, document);
2759 : }
2760 :
2761 :
2762 : //----------------------------------------------------------------------
2763 :
2764 9 : nsGenericHTMLFormElementWithState::nsGenericHTMLFormElementWithState(
2765 : already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, uint8_t aType
2766 9 : )
2767 9 : : nsGenericHTMLFormElement(aNodeInfo, aType)
2768 : {
2769 9 : mStateKey.SetIsVoid(true);
2770 9 : }
2771 :
2772 : nsresult
2773 2 : nsGenericHTMLFormElementWithState::GenerateStateKey()
2774 : {
2775 : // Keep the key if already computed
2776 2 : if (!mStateKey.IsVoid()) {
2777 0 : return NS_OK;
2778 : }
2779 :
2780 2 : nsIDocument* doc = GetUncomposedDoc();
2781 2 : if (!doc) {
2782 2 : return NS_OK;
2783 : }
2784 :
2785 : // Generate the state key
2786 0 : nsresult rv = nsContentUtils::GenerateStateKey(this, doc, mStateKey);
2787 :
2788 0 : if (NS_FAILED(rv)) {
2789 0 : mStateKey.SetIsVoid(true);
2790 0 : return rv;
2791 : }
2792 :
2793 : // If the state key is blank, this is anonymous content or for whatever
2794 : // reason we are not supposed to save/restore state: keep it as such.
2795 0 : if (!mStateKey.IsEmpty()) {
2796 : // Add something unique to content so layout doesn't muck us up.
2797 0 : mStateKey += "-C";
2798 : }
2799 0 : return NS_OK;
2800 : }
2801 :
2802 : nsPresState*
2803 0 : nsGenericHTMLFormElementWithState::GetPrimaryPresState()
2804 : {
2805 0 : if (mStateKey.IsEmpty()) {
2806 0 : return nullptr;
2807 : }
2808 :
2809 0 : nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistory(false);
2810 :
2811 0 : if (!history) {
2812 0 : return nullptr;
2813 : }
2814 :
2815 : // Get the pres state for this key, if it doesn't exist, create one.
2816 0 : nsPresState* result = history->GetState(mStateKey);
2817 0 : if (!result) {
2818 0 : result = new nsPresState();
2819 0 : history->AddState(mStateKey, result);
2820 : }
2821 :
2822 0 : return result;
2823 : }
2824 :
2825 : already_AddRefed<nsILayoutHistoryState>
2826 0 : nsGenericHTMLFormElementWithState::GetLayoutHistory(bool aRead)
2827 : {
2828 0 : nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
2829 0 : if (!doc) {
2830 0 : return nullptr;
2831 : }
2832 :
2833 : //
2834 : // Get the history
2835 : //
2836 0 : nsCOMPtr<nsILayoutHistoryState> history = doc->GetLayoutHistoryState();
2837 0 : if (!history) {
2838 0 : return nullptr;
2839 : }
2840 :
2841 0 : if (aRead && !history->HasStates()) {
2842 0 : return nullptr;
2843 : }
2844 :
2845 0 : return history.forget();
2846 : }
2847 :
2848 : bool
2849 2 : nsGenericHTMLFormElementWithState::RestoreFormControlState()
2850 : {
2851 2 : if (mStateKey.IsEmpty()) {
2852 2 : return false;
2853 : }
2854 :
2855 : nsCOMPtr<nsILayoutHistoryState> history =
2856 0 : GetLayoutHistory(true);
2857 0 : if (!history) {
2858 0 : return false;
2859 : }
2860 :
2861 : nsPresState *state;
2862 : // Get the pres state for this key
2863 0 : state = history->GetState(mStateKey);
2864 0 : if (state) {
2865 0 : bool result = RestoreState(state);
2866 0 : history->RemoveState(mStateKey);
2867 0 : return result;
2868 : }
2869 :
2870 0 : return false;
2871 : }
2872 :
2873 : void
2874 0 : nsGenericHTMLFormElementWithState::NodeInfoChanged(nsIDocument* aOldDoc)
2875 : {
2876 0 : nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
2877 0 : mStateKey.SetIsVoid(true);
2878 0 : }
2879 :
2880 : nsSize
2881 0 : nsGenericHTMLElement::GetWidthHeightForImage(RefPtr<imgRequestProxy>& aImageRequest)
2882 : {
2883 0 : nsSize size(0,0);
2884 :
2885 0 : nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
2886 :
2887 0 : if (frame) {
2888 0 : size = frame->GetContentRect().Size();
2889 :
2890 0 : size.width = nsPresContext::AppUnitsToIntCSSPixels(size.width);
2891 0 : size.height = nsPresContext::AppUnitsToIntCSSPixels(size.height);
2892 : } else {
2893 : const nsAttrValue* value;
2894 0 : nsCOMPtr<imgIContainer> image;
2895 0 : if (aImageRequest) {
2896 0 : aImageRequest->GetImage(getter_AddRefs(image));
2897 : }
2898 :
2899 0 : if ((value = GetParsedAttr(nsGkAtoms::width)) &&
2900 0 : value->Type() == nsAttrValue::eInteger) {
2901 0 : size.width = value->GetIntegerValue();
2902 0 : } else if (image) {
2903 0 : image->GetWidth(&size.width);
2904 : }
2905 :
2906 0 : if ((value = GetParsedAttr(nsGkAtoms::height)) &&
2907 0 : value->Type() == nsAttrValue::eInteger) {
2908 0 : size.height = value->GetIntegerValue();
2909 0 : } else if (image) {
2910 0 : image->GetHeight(&size.height);
2911 : }
2912 : }
2913 :
2914 0 : NS_ASSERTION(size.width >= 0, "negative width");
2915 0 : NS_ASSERTION(size.height >= 0, "negative height");
2916 0 : return size;
2917 : }
2918 :
2919 : bool
2920 1 : nsGenericHTMLElement::IsEventAttributeNameInternal(nsIAtom *aName)
2921 : {
2922 1 : return nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML);
2923 : }
2924 :
2925 : /**
2926 : * Construct a URI from a string, as an element.src attribute
2927 : * would be set to. Helper for the media elements.
2928 : */
2929 : nsresult
2930 0 : nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
2931 : nsIURI** aURI)
2932 : {
2933 0 : NS_ENSURE_ARG_POINTER(aURI);
2934 :
2935 0 : *aURI = nullptr;
2936 :
2937 0 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
2938 :
2939 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
2940 0 : nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, aURISpec,
2941 0 : doc, baseURI);
2942 0 : NS_ENSURE_SUCCESS(rv, rv);
2943 :
2944 : bool equal;
2945 0 : if (aURISpec.IsEmpty() &&
2946 0 : doc->GetDocumentURI() &&
2947 0 : NS_SUCCEEDED(doc->GetDocumentURI()->Equals(*aURI, &equal)) &&
2948 : equal) {
2949 : // Assume an element can't point to a fragment of its embedding
2950 : // document. Fail here instead of returning the recursive URI
2951 : // and waiting for the subsequent load to fail.
2952 0 : NS_RELEASE(*aURI);
2953 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
2954 : }
2955 :
2956 0 : return NS_OK;
2957 : }
2958 :
2959 : static bool
2960 0 : IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
2961 : {
2962 0 : nsTArray<Element*> elementsToCheck;
2963 0 : for (Element* e = aElement; e; e = e->GetParentElement()) {
2964 0 : if (e->GetPrimaryFrame()) {
2965 : // e definitely isn't display:none and doesn't have a display:none
2966 : // ancestor.
2967 0 : break;
2968 : }
2969 0 : elementsToCheck.AppendElement(e);
2970 : }
2971 :
2972 0 : if (elementsToCheck.IsEmpty()) {
2973 0 : return false;
2974 : }
2975 :
2976 : // XXXbholley: This could be done more directly with Servo's style system.
2977 0 : StyleSetHandle styleSet = aPresShell->StyleSet();
2978 0 : RefPtr<nsStyleContext> sc;
2979 0 : for (int32_t i = elementsToCheck.Length() - 1; i >= 0; --i) {
2980 0 : if (sc) {
2981 0 : sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc, LazyComputeBehavior::Assert);
2982 : } else {
2983 0 : sc = nsComputedDOMStyle::GetStyleContextNoFlush(elementsToCheck[i],
2984 0 : nullptr, aPresShell);
2985 : }
2986 0 : if (sc->StyleDisplay()->mDisplay == StyleDisplay::None) {
2987 0 : return true;
2988 : }
2989 : }
2990 :
2991 0 : return false;
2992 : }
2993 :
2994 : void
2995 0 : nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
2996 : mozilla::ErrorResult& aError)
2997 : {
2998 0 : if (!GetPrimaryFrame(FlushType::Layout)) {
2999 0 : nsIPresShell* presShell = nsComputedDOMStyle::GetPresShellForContent(this);
3000 0 : if (!presShell || IsOrHasAncestorWithDisplayNone(this, presShell)) {
3001 0 : GetTextContentInternal(aValue, aError);
3002 0 : return;
3003 : }
3004 : }
3005 :
3006 0 : nsRange::GetInnerTextNoFlush(aValue, aError, this, 0, this, GetChildCount());
3007 : }
3008 :
3009 : void
3010 0 : nsGenericHTMLElement::SetInnerText(const nsAString& aValue)
3011 : {
3012 : // Batch possible DOMSubtreeModified events.
3013 0 : mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
3014 0 : FireNodeRemovedForChildren();
3015 :
3016 : // Might as well stick a batch around this since we're performing several
3017 : // mutations.
3018 : mozAutoDocUpdate updateBatch(GetComposedDoc(),
3019 0 : UPDATE_CONTENT_MODEL, true);
3020 0 : nsAutoMutationBatch mb;
3021 :
3022 0 : uint32_t childCount = GetChildCount();
3023 :
3024 0 : mb.Init(this, true, false);
3025 0 : for (uint32_t i = 0; i < childCount; ++i) {
3026 0 : RemoveChildAt(0, true);
3027 : }
3028 0 : mb.RemovalDone();
3029 :
3030 0 : nsString str;
3031 0 : const char16_t* s = aValue.BeginReading();
3032 0 : const char16_t* end = aValue.EndReading();
3033 : while (true) {
3034 0 : if (s != end && *s == '\r' && s + 1 != end && s[1] == '\n') {
3035 : // a \r\n pair should only generate one <br>, so just skip the \r
3036 0 : ++s;
3037 : }
3038 0 : if (s == end || *s == '\r' || *s == '\n') {
3039 0 : if (!str.IsEmpty()) {
3040 : RefPtr<nsTextNode> textContent =
3041 0 : new nsTextNode(NodeInfo()->NodeInfoManager());
3042 0 : textContent->SetText(str, true);
3043 0 : AppendChildTo(textContent, true);
3044 : }
3045 0 : if (s == end) {
3046 0 : break;
3047 : }
3048 0 : str.Truncate();
3049 : already_AddRefed<mozilla::dom::NodeInfo> ni =
3050 : NodeInfo()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::br,
3051 0 : nullptr, kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
3052 0 : RefPtr<HTMLBRElement> br = new HTMLBRElement(ni);
3053 0 : AppendChildTo(br, true);
3054 : } else {
3055 0 : str.Append(*s);
3056 : }
3057 0 : ++s;
3058 0 : }
3059 :
3060 0 : mb.NodesAdded();
3061 0 : }
|