HTMLHRElement.cpp (7168B)
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/HTMLHRElement.h" 8 9 #include "mozilla/MappedDeclarationsBuilder.h" 10 #include "mozilla/dom/HTMLHRElementBinding.h" 11 #include "nsCSSProps.h" 12 #include "nsStyleConsts.h" 13 14 NS_IMPL_NS_NEW_HTML_ELEMENT(HR) 15 16 namespace mozilla::dom { 17 18 HTMLHRElement::HTMLHRElement( 19 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 20 : nsGenericHTMLElement(std::move(aNodeInfo)) {} 21 22 HTMLHRElement::~HTMLHRElement() = default; 23 24 NS_IMPL_ELEMENT_CLONE(HTMLHRElement) 25 26 bool HTMLHRElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, 27 const nsAString& aValue, 28 nsIPrincipal* aMaybeScriptedPrincipal, 29 nsAttrValue& aResult) { 30 static const nsAttrValue::EnumTableEntry kAlignTable[] = { 31 {"left", StyleTextAlign::Left}, 32 {"right", StyleTextAlign::Right}, 33 {"center", StyleTextAlign::Center}, 34 }; 35 36 if (aNamespaceID == kNameSpaceID_None) { 37 if (aAttribute == nsGkAtoms::width) { 38 return aResult.ParseHTMLDimension(aValue); 39 } 40 if (aAttribute == nsGkAtoms::size) { 41 return aResult.ParseIntWithBounds(aValue, 1, 1000); 42 } 43 if (aAttribute == nsGkAtoms::align) { 44 return aResult.ParseEnumValue(aValue, kAlignTable, false); 45 } 46 if (aAttribute == nsGkAtoms::color) { 47 return aResult.ParseColor(aValue); 48 } 49 } 50 51 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, 52 aMaybeScriptedPrincipal, aResult); 53 } 54 55 void HTMLHRElement::MapAttributesIntoRule(MappedDeclarationsBuilder& aBuilder) { 56 bool noshade = false; 57 58 const nsAttrValue* colorValue = aBuilder.GetAttr(nsGkAtoms::color); 59 nscolor color; 60 bool colorIsSet = colorValue && colorValue->GetColorValue(color); 61 62 if (colorIsSet) { 63 noshade = true; 64 } else { 65 noshade = !!aBuilder.GetAttr(nsGkAtoms::noshade); 66 } 67 68 // align: enum 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); 76 break; 77 case StyleTextAlign::Right: 78 aBuilder.SetAutoValueIfUnset(eCSSProperty_margin_left); 79 aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_right, 0.0f); 80 break; 81 case StyleTextAlign::Center: 82 aBuilder.SetAutoValueIfUnset(eCSSProperty_margin_left); 83 aBuilder.SetAutoValueIfUnset(eCSSProperty_margin_right); 84 break; 85 default: 86 MOZ_ASSERT_UNREACHABLE("Unknown <hr align> value"); 87 break; 88 } 89 } 90 if (!aBuilder.PropertyIsSet(eCSSProperty_height)) { 91 // size: integer 92 if (noshade) { 93 // noshade case: size is set using the border 94 aBuilder.SetAutoValue(eCSSProperty_height); 95 } else { 96 // normal case 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 105 } 106 } 107 108 // if not noshade, border styles are dealt with by html.css 109 if (noshade) { 110 // size: integer 111 // if a size is set, use half of it per side, otherwise, use 1px per side 112 float sizePerSide; 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. 121 sizePerSide = 1.0f; 122 allSides = false; 123 } 124 } else { 125 sizePerSide = 1.0f; // default to a 2px high line 126 } 127 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_top_width, sizePerSide); 128 if (allSides) { 129 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_right_width, 130 sizePerSide); 131 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, 132 sizePerSide); 133 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_left_width, 134 sizePerSide); 135 } 136 137 if (!aBuilder.PropertyIsSet(eCSSProperty_border_top_style)) { 138 aBuilder.SetKeywordValue(eCSSProperty_border_top_style, 139 StyleBorderStyle::Solid); 140 } 141 if (allSides) { 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); 148 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 NonCustomCSSPropertyId* props = 154 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius); 155 *props != eCSSProperty_UNKNOWN; ++props) { 156 aBuilder.SetPixelValueIfUnset(*props, 10000.0f); 157 } 158 } 159 } 160 // color: a color 161 // (we got the color attribute earlier) 162 if (colorIsSet) { 163 aBuilder.SetColorValueIfUnset(eCSSProperty_color, color); 164 } 165 MapWidthAttributeInto(aBuilder); 166 MapCommonAttributesInto(aBuilder); 167 } 168 169 NS_IMETHODIMP_(bool) 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}, 174 }; 175 176 static const MappedAttributeEntry* const map[] = { 177 attributes, 178 sCommonAttributeMap, 179 }; 180 181 return FindAttributeDependence(aAttribute, map); 182 } 183 184 nsMapRuleToAttributesFunc HTMLHRElement::GetAttributeMappingFunction() const { 185 return &MapAttributesIntoRule; 186 } 187 188 JSObject* HTMLHRElement::WrapNode(JSContext* aCx, 189 JS::Handle<JSObject*> aGivenProto) { 190 return HTMLHRElement_Binding::Wrap(aCx, this, aGivenProto); 191 } 192 193 } // namespace mozilla::dom