1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/HTMLLegendElement.h"
8 #include "mozilla/dom/ElementBinding.h"
9 #include "mozilla/dom/HTMLLegendElementBinding.h"
10 #include "nsFocusManager.h"
11 #include "nsIFrame.h"
12 
13 NS_IMPL_NS_NEW_HTML_ELEMENT(Legend)
14 
15 namespace mozilla::dom {
16 
17 HTMLLegendElement::~HTMLLegendElement() = default;
18 
NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)19 NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)
20 
21 nsIContent* HTMLLegendElement::GetFieldSet() const {
22   nsIContent* parent = GetParent();
23 
24   if (parent && parent->IsHTMLElement(nsGkAtoms::fieldset)) {
25     return parent;
26   }
27 
28   return nullptr;
29 }
30 
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)31 bool HTMLLegendElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
32                                        const nsAString& aValue,
33                                        nsIPrincipal* aMaybeScriptedPrincipal,
34                                        nsAttrValue& aResult) {
35   // this contains center, because IE4 does
36   static const nsAttrValue::EnumTable kAlignTable[] = {
37       {"left", LegendAlignValue::Left},
38       {"right", LegendAlignValue::Right},
39       {"center", LegendAlignValue::Center},
40       {nullptr, 0}};
41 
42   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
43     return aResult.ParseEnumValue(aValue, kAlignTable, false);
44   }
45 
46   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
47                                               aMaybeScriptedPrincipal, aResult);
48 }
49 
GetAttributeChangeHint(const nsAtom * aAttribute,int32_t aModType) const50 nsChangeHint HTMLLegendElement::GetAttributeChangeHint(const nsAtom* aAttribute,
51                                                        int32_t aModType) const {
52   nsChangeHint retval =
53       nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
54   if (aAttribute == nsGkAtoms::align) {
55     retval |= NS_STYLE_HINT_REFLOW;
56   }
57   return retval;
58 }
59 
BindToTree(BindContext & aContext,nsINode & aParent)60 nsresult HTMLLegendElement::BindToTree(BindContext& aContext,
61                                        nsINode& aParent) {
62   return nsGenericHTMLElement::BindToTree(aContext, aParent);
63 }
64 
UnbindFromTree(bool aNullParent)65 void HTMLLegendElement::UnbindFromTree(bool aNullParent) {
66   nsGenericHTMLElement::UnbindFromTree(aNullParent);
67 }
68 
Focus(const FocusOptions & aOptions,const CallerType aCallerType,ErrorResult & aError)69 void HTMLLegendElement::Focus(const FocusOptions& aOptions,
70                               const CallerType aCallerType,
71                               ErrorResult& aError) {
72   nsIFrame* frame = GetPrimaryFrame();
73   if (!frame) {
74     return;
75   }
76 
77   if (frame->IsFocusable()) {
78     nsGenericHTMLElement::Focus(aOptions, aCallerType, aError);
79     return;
80   }
81 
82   // If the legend isn't focusable, focus whatever is focusable following
83   // the legend instead, bug 81481.
84   nsFocusManager* fm = nsFocusManager::GetFocusManager();
85   if (!fm) {
86     return;
87   }
88 
89   RefPtr<Element> result;
90   aError = fm->MoveFocus(nullptr, this, nsIFocusManager::MOVEFOCUS_FORWARD,
91                          nsIFocusManager::FLAG_NOPARENTFRAME |
92                              nsFocusManager::ProgrammaticFocusFlags(aOptions),
93                          getter_AddRefs(result));
94 }
95 
PerformAccesskey(bool aKeyCausesActivation,bool aIsTrustedEvent)96 Result<bool, nsresult> HTMLLegendElement::PerformAccesskey(
97     bool aKeyCausesActivation, bool aIsTrustedEvent) {
98   FocusOptions options;
99   ErrorResult rv;
100 
101   Focus(options, CallerType::System, rv);
102   if (rv.Failed()) {
103     return Err(rv.StealNSResult());
104   }
105 
106   // XXXedgar, do we need to check whether the focus is really changed?
107   return true;
108 }
109 
LogicalAlign(mozilla::WritingMode aCBWM) const110 HTMLLegendElement::LegendAlignValue HTMLLegendElement::LogicalAlign(
111     mozilla::WritingMode aCBWM) const {
112   const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::align);
113   if (!attr || attr->Type() != nsAttrValue::eEnum) {
114     return LegendAlignValue::InlineStart;
115   }
116 
117   auto value = static_cast<LegendAlignValue>(attr->GetEnumValue());
118   switch (value) {
119     case LegendAlignValue::Left:
120       return aCBWM.IsBidiLTR() ? LegendAlignValue::InlineStart
121                                : LegendAlignValue::InlineEnd;
122     case LegendAlignValue::Right:
123       return aCBWM.IsBidiLTR() ? LegendAlignValue::InlineEnd
124                                : LegendAlignValue::InlineStart;
125     default:
126       return value;
127   }
128 }
129 
GetForm() const130 HTMLFormElement* HTMLLegendElement::GetForm() const {
131   nsCOMPtr<nsIFormControl> fieldsetControl = do_QueryInterface(GetFieldSet());
132   return fieldsetControl ? fieldsetControl->GetForm() : nullptr;
133 }
134 
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)135 JSObject* HTMLLegendElement::WrapNode(JSContext* aCx,
136                                       JS::Handle<JSObject*> aGivenProto) {
137   return HTMLLegendElement_Binding::Wrap(aCx, this, aGivenProto);
138 }
139 
140 }  // namespace mozilla::dom
141