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/. */
7 #include "mozilla/dom/HTMLHRElement.h"
8 #include "mozilla/dom/HTMLHRElementBinding.h"
10 #include "nsCSSProps.h"
11 #include "nsStyleConsts.h"
12 #include "mozilla/MappedDeclarationsBuilder.h"
14 NS_IMPL_NS_NEW_HTML_ELEMENT(HR
)
16 namespace mozilla::dom
{
18 HTMLHRElement::HTMLHRElement(
19 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
20 : nsGenericHTMLElement(std::move(aNodeInfo
)) {}
22 HTMLHRElement::~HTMLHRElement() = default;
24 NS_IMPL_ELEMENT_CLONE(HTMLHRElement
)
26 bool HTMLHRElement::ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
27 const nsAString
& aValue
,
28 nsIPrincipal
* aMaybeScriptedPrincipal
,
29 nsAttrValue
& aResult
) {
30 static const nsAttrValue::EnumTable kAlignTable
[] = {
31 {"left", StyleTextAlign::Left
},
32 {"right", StyleTextAlign::Right
},
33 {"center", StyleTextAlign::Center
},
36 if (aNamespaceID
== kNameSpaceID_None
) {
37 if (aAttribute
== nsGkAtoms::width
) {
38 return aResult
.ParseHTMLDimension(aValue
);
40 if (aAttribute
== nsGkAtoms::size
) {
41 return aResult
.ParseIntWithBounds(aValue
, 1, 1000);
43 if (aAttribute
== nsGkAtoms::align
) {
44 return aResult
.ParseEnumValue(aValue
, kAlignTable
, false);
46 if (aAttribute
== nsGkAtoms::color
) {
47 return aResult
.ParseColor(aValue
);
51 return nsGenericHTMLElement::ParseAttribute(aNamespaceID
, aAttribute
, aValue
,
52 aMaybeScriptedPrincipal
, aResult
);
55 void HTMLHRElement::MapAttributesIntoRule(MappedDeclarationsBuilder
& aBuilder
) {
58 const nsAttrValue
* colorValue
= aBuilder
.GetAttr(nsGkAtoms::color
);
60 bool colorIsSet
= colorValue
&& colorValue
->GetColorValue(color
);
65 noshade
= !!aBuilder
.GetAttr(nsGkAtoms::noshade
);
69 const nsAttrValue
* value
= aBuilder
.GetAttr(nsGkAtoms::align
);
70 if (value
&& value
->Type() == nsAttrValue::eEnum
) {
71 // Map align attribute into auto side margins
72 switch (StyleTextAlign(value
->GetEnumValue())) {
73 case StyleTextAlign::Left
:
74 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_left
, 0.0f
);
75 aBuilder
.SetAutoValueIfUnset(eCSSProperty_margin_right
);
77 case StyleTextAlign::Right
:
78 aBuilder
.SetAutoValueIfUnset(eCSSProperty_margin_left
);
79 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_right
, 0.0f
);
81 case StyleTextAlign::Center
:
82 aBuilder
.SetAutoValueIfUnset(eCSSProperty_margin_left
);
83 aBuilder
.SetAutoValueIfUnset(eCSSProperty_margin_right
);
86 MOZ_ASSERT_UNREACHABLE("Unknown <hr align> value");
90 if (!aBuilder
.PropertyIsSet(eCSSProperty_height
)) {
93 // noshade case: size is set using the border
94 aBuilder
.SetAutoValue(eCSSProperty_height
);
97 // the height includes the top and bottom borders that are initially 1px.
98 // for size=1, html.css has a special case rule that makes this work by
99 // removing all but the top border.
100 const nsAttrValue
* value
= aBuilder
.GetAttr(nsGkAtoms::size
);
101 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
102 aBuilder
.SetPixelValue(eCSSProperty_height
,
103 (float)value
->GetIntegerValue());
104 } // else use default value from html.css
108 // if not noshade, border styles are dealt with by html.css
111 // if a size is set, use half of it per side, otherwise, use 1px per side
113 bool allSides
= true;
114 value
= aBuilder
.GetAttr(nsGkAtoms::size
);
115 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
116 sizePerSide
= (float)value
->GetIntegerValue() / 2.0f
;
117 if (sizePerSide
< 1.0f
) {
118 // XXX When the pixel bug is fixed, all the special casing for
119 // subpixel borders should be removed.
120 // In the meantime, this makes http://www.microsoft.com/ look right.
125 sizePerSide
= 1.0f
; // default to a 2px high line
127 aBuilder
.SetPixelValueIfUnset(eCSSProperty_border_top_width
, sizePerSide
);
129 aBuilder
.SetPixelValueIfUnset(eCSSProperty_border_right_width
,
131 aBuilder
.SetPixelValueIfUnset(eCSSProperty_border_bottom_width
,
133 aBuilder
.SetPixelValueIfUnset(eCSSProperty_border_left_width
,
137 if (!aBuilder
.PropertyIsSet(eCSSProperty_border_top_style
)) {
138 aBuilder
.SetKeywordValue(eCSSProperty_border_top_style
,
139 StyleBorderStyle::Solid
);
142 aBuilder
.SetKeywordValueIfUnset(eCSSProperty_border_right_style
,
143 StyleBorderStyle::Solid
);
144 aBuilder
.SetKeywordValueIfUnset(eCSSProperty_border_bottom_style
,
145 StyleBorderStyle::Solid
);
146 aBuilder
.SetKeywordValueIfUnset(eCSSProperty_border_left_style
,
147 StyleBorderStyle::Solid
);
149 // If it would be noticeable, set the border radius to
150 // 10000px on all corners; this triggers the clamping to make
151 // circular ends. This assumes the <hr> isn't larger than
152 // that in *both* dimensions.
153 for (const nsCSSPropertyID
* props
=
154 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius
);
155 *props
!= eCSSProperty_UNKNOWN
; ++props
) {
156 aBuilder
.SetPixelValueIfUnset(*props
, 10000.0f
);
161 // (we got the color attribute earlier)
163 aBuilder
.SetColorValueIfUnset(eCSSProperty_color
, color
);
165 MapWidthAttributeInto(aBuilder
);
166 MapCommonAttributesInto(aBuilder
);
170 HTMLHRElement::IsAttributeMapped(const nsAtom
* aAttribute
) const {
171 static const MappedAttributeEntry attributes
[] = {
172 {nsGkAtoms::align
}, {nsGkAtoms::width
}, {nsGkAtoms::size
},
173 {nsGkAtoms::color
}, {nsGkAtoms::noshade
}, {nullptr},
176 static const MappedAttributeEntry
* const map
[] = {
181 return FindAttributeDependence(aAttribute
, map
);
184 nsMapRuleToAttributesFunc
HTMLHRElement::GetAttributeMappingFunction() const {
185 return &MapAttributesIntoRule
;
188 JSObject
* HTMLHRElement::WrapNode(JSContext
* aCx
,
189 JS::Handle
<JSObject
*> aGivenProto
) {
190 return HTMLHRElement_Binding::Wrap(aCx
, this, aGivenProto
);
193 } // namespace mozilla::dom