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 "HTMLBodyElement.h"
8 #include "mozilla/dom/HTMLBodyElementBinding.h"
10 #include "mozilla/AttributeStyles.h"
11 #include "mozilla/EditorBase.h"
12 #include "mozilla/HTMLEditor.h"
13 #include "mozilla/MappedDeclarationsBuilder.h"
14 #include "mozilla/TextEditor.h"
15 #include "mozilla/dom/BindContext.h"
16 #include "mozilla/dom/Document.h"
17 #include "nsAttrValueInlines.h"
18 #include "nsGkAtoms.h"
19 #include "nsStyleConsts.h"
20 #include "nsPresContext.h"
21 #include "DocumentInlines.h"
22 #include "nsDocShell.h"
23 #include "nsIDocShell.h"
24 #include "nsGlobalWindowInner.h"
26 NS_IMPL_NS_NEW_HTML_ELEMENT(Body
)
28 namespace mozilla::dom
{
30 //----------------------------------------------------------------------
32 HTMLBodyElement::~HTMLBodyElement() = default;
34 JSObject
* HTMLBodyElement::WrapNode(JSContext
* aCx
,
35 JS::Handle
<JSObject
*> aGivenProto
) {
36 return HTMLBodyElement_Binding::Wrap(aCx
, this, aGivenProto
);
39 NS_IMPL_ELEMENT_CLONE(HTMLBodyElement
)
41 bool HTMLBodyElement::ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
42 const nsAString
& aValue
,
43 nsIPrincipal
* aMaybeScriptedPrincipal
,
44 nsAttrValue
& aResult
) {
45 if (aNamespaceID
== kNameSpaceID_None
) {
46 if (aAttribute
== nsGkAtoms::bgcolor
|| aAttribute
== nsGkAtoms::text
||
47 aAttribute
== nsGkAtoms::link
|| aAttribute
== nsGkAtoms::alink
||
48 aAttribute
== nsGkAtoms::vlink
) {
49 return aResult
.ParseColor(aValue
);
51 if (aAttribute
== nsGkAtoms::marginwidth
||
52 aAttribute
== nsGkAtoms::marginheight
||
53 aAttribute
== nsGkAtoms::topmargin
||
54 aAttribute
== nsGkAtoms::bottommargin
||
55 aAttribute
== nsGkAtoms::leftmargin
||
56 aAttribute
== nsGkAtoms::rightmargin
) {
57 return aResult
.ParseNonNegativeIntValue(aValue
);
61 return nsGenericHTMLElement::ParseBackgroundAttribute(
62 aNamespaceID
, aAttribute
, aValue
, aResult
) ||
63 nsGenericHTMLElement::ParseAttribute(aNamespaceID
, aAttribute
, aValue
,
64 aMaybeScriptedPrincipal
, aResult
);
67 void HTMLBodyElement::MapAttributesIntoRule(
68 MappedDeclarationsBuilder
& aBuilder
) {
69 // This is the one place where we try to set the same property
70 // multiple times in presentation attributes. Servo does not support
71 // querying if a property is set (because that is O(n) behavior
72 // in ServoSpecifiedValues). Instead, we use the below values to keep
73 // track of whether we have already set a property, and if so, what value
74 // we set it to (which is used when handling margin
75 // attributes from the containing frame element)
77 int32_t bodyMarginWidth
= -1;
78 int32_t bodyMarginHeight
= -1;
79 int32_t bodyTopMargin
= -1;
80 int32_t bodyBottomMargin
= -1;
81 int32_t bodyLeftMargin
= -1;
82 int32_t bodyRightMargin
= -1;
84 const nsAttrValue
* value
;
85 // if marginwidth/marginheight are set, reflect them as 'margin'
86 value
= aBuilder
.GetAttr(nsGkAtoms::marginwidth
);
87 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
88 bodyMarginWidth
= value
->GetIntegerValue();
89 if (bodyMarginWidth
< 0) {
92 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_left
,
93 (float)bodyMarginWidth
);
94 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_right
,
95 (float)bodyMarginWidth
);
98 value
= aBuilder
.GetAttr(nsGkAtoms::marginheight
);
99 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
100 bodyMarginHeight
= value
->GetIntegerValue();
101 if (bodyMarginHeight
< 0) {
102 bodyMarginHeight
= 0;
104 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_top
,
105 (float)bodyMarginHeight
);
106 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_bottom
,
107 (float)bodyMarginHeight
);
110 // topmargin (IE-attribute)
111 if (bodyMarginHeight
== -1) {
112 value
= aBuilder
.GetAttr(nsGkAtoms::topmargin
);
113 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
114 bodyTopMargin
= value
->GetIntegerValue();
115 if (bodyTopMargin
< 0) {
118 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_top
,
119 (float)bodyTopMargin
);
122 // bottommargin (IE-attribute)
124 if (bodyMarginHeight
== -1) {
125 value
= aBuilder
.GetAttr(nsGkAtoms::bottommargin
);
126 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
127 bodyBottomMargin
= value
->GetIntegerValue();
128 if (bodyBottomMargin
< 0) {
129 bodyBottomMargin
= 0;
131 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_bottom
,
132 (float)bodyBottomMargin
);
136 // leftmargin (IE-attribute)
137 if (bodyMarginWidth
== -1) {
138 value
= aBuilder
.GetAttr(nsGkAtoms::leftmargin
);
139 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
140 bodyLeftMargin
= value
->GetIntegerValue();
141 if (bodyLeftMargin
< 0) {
144 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_left
,
145 (float)bodyLeftMargin
);
148 // rightmargin (IE-attribute)
149 if (bodyMarginWidth
== -1) {
150 value
= aBuilder
.GetAttr(nsGkAtoms::rightmargin
);
151 if (value
&& value
->Type() == nsAttrValue::eInteger
) {
152 bodyRightMargin
= value
->GetIntegerValue();
153 if (bodyRightMargin
< 0) {
156 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_right
,
157 (float)bodyRightMargin
);
161 // if marginwidth or marginheight is set in the <frame> and not set in the
162 // <body> reflect them as margin in the <body>
163 if (bodyMarginWidth
== -1 || bodyMarginHeight
== -1) {
164 if (nsDocShell
* ds
= nsDocShell::Cast(aBuilder
.Document().GetDocShell())) {
165 CSSIntSize margins
= ds
->GetFrameMargins();
166 int32_t frameMarginWidth
= margins
.width
;
167 int32_t frameMarginHeight
= margins
.height
;
169 if (bodyMarginWidth
== -1 && frameMarginWidth
>= 0) {
170 if (bodyLeftMargin
== -1) {
171 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_left
,
172 (float)frameMarginWidth
);
174 if (bodyRightMargin
== -1) {
175 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_right
,
176 (float)frameMarginWidth
);
180 if (bodyMarginHeight
== -1 && frameMarginHeight
>= 0) {
181 if (bodyTopMargin
== -1) {
182 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_top
,
183 (float)frameMarginHeight
);
185 if (bodyBottomMargin
== -1) {
186 aBuilder
.SetPixelValueIfUnset(eCSSProperty_margin_bottom
,
187 (float)frameMarginHeight
);
193 // When display if first asked for, go ahead and get our colors set up.
194 if (AttributeStyles
* attrStyles
= aBuilder
.Document().GetAttributeStyles()) {
196 value
= aBuilder
.GetAttr(nsGkAtoms::link
);
197 if (value
&& value
->GetColorValue(color
)) {
198 attrStyles
->SetLinkColor(color
);
201 value
= aBuilder
.GetAttr(nsGkAtoms::alink
);
202 if (value
&& value
->GetColorValue(color
)) {
203 attrStyles
->SetActiveLinkColor(color
);
206 value
= aBuilder
.GetAttr(nsGkAtoms::vlink
);
207 if (value
&& value
->GetColorValue(color
)) {
208 attrStyles
->SetVisitedLinkColor(color
);
212 if (!aBuilder
.PropertyIsSet(eCSSProperty_color
)) {
215 value
= aBuilder
.GetAttr(nsGkAtoms::text
);
216 if (value
&& value
->GetColorValue(color
)) {
217 aBuilder
.SetColorValue(eCSSProperty_color
, color
);
221 nsGenericHTMLElement::MapBackgroundAttributesInto(aBuilder
);
222 nsGenericHTMLElement::MapCommonAttributesInto(aBuilder
);
225 nsMapRuleToAttributesFunc
HTMLBodyElement::GetAttributeMappingFunction() const {
226 return &MapAttributesIntoRule
;
230 HTMLBodyElement::IsAttributeMapped(const nsAtom
* aAttribute
) const {
231 static const MappedAttributeEntry attributes
[] = {
236 {nsGkAtoms::marginwidth
},
237 {nsGkAtoms::marginheight
},
238 {nsGkAtoms::topmargin
},
239 {nsGkAtoms::rightmargin
},
240 {nsGkAtoms::bottommargin
},
241 {nsGkAtoms::leftmargin
},
245 static const MappedAttributeEntry
* const map
[] = {
248 sBackgroundAttributeMap
,
251 return FindAttributeDependence(aAttribute
, map
);
254 already_AddRefed
<EditorBase
> HTMLBodyElement::GetAssociatedEditor() {
255 MOZ_ASSERT(!GetTextEditorInternal());
257 // Make sure this is the actual body of the document
258 if (this != OwnerDoc()->GetBodyElement()) {
262 // For designmode, try to get document's editor
263 nsPresContext
* presContext
= GetPresContext(eForComposedDoc
);
268 nsCOMPtr
<nsIDocShell
> docShell
= presContext
->GetDocShell();
273 RefPtr
<HTMLEditor
> htmlEditor
= docShell
->GetHTMLEditor();
274 return htmlEditor
.forget();
277 bool HTMLBodyElement::IsEventAttributeNameInternal(nsAtom
* aName
) {
278 return nsContentUtils::IsEventAttributeName(
279 aName
, EventNameType_HTML
| EventNameType_HTMLBodyOrFramesetOnly
);
282 nsresult
HTMLBodyElement::BindToTree(BindContext
& aContext
, nsINode
& aParent
) {
283 mAttrs
.MarkAsPendingPresAttributeEvaluation();
284 return nsGenericHTMLElement::BindToTree(aContext
, aParent
);
287 void HTMLBodyElement::FrameMarginsChanged() {
288 MOZ_ASSERT(IsInComposedDoc());
289 if (IsPendingMappedAttributeEvaluation()) {
292 if (mAttrs
.MarkAsPendingPresAttributeEvaluation()) {
293 OwnerDoc()->ScheduleForPresAttrEvaluation(this);
297 #define EVENT(name_, id_, type_, \
298 struct_) /* nothing; handled by the superclass */
299 // nsGenericHTMLElement::GetOnError returns
300 // already_AddRefed<EventHandlerNonNull> while other getters return
301 // EventHandlerNonNull*, so allow passing in the type to use here.
302 #define WINDOW_EVENT_HELPER(name_, type_) \
303 type_* HTMLBodyElement::GetOn##name_() { \
304 if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
305 nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win); \
306 return globalWin->GetOn##name_(); \
310 void HTMLBodyElement::SetOn##name_(type_* handler) { \
311 nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
316 nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win); \
317 return globalWin->SetOn##name_(handler); \
319 #define WINDOW_EVENT(name_, id_, type_, struct_) \
320 WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
321 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
322 WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
323 #include "mozilla/EventNameList.h" // IWYU pragma: keep
324 #undef BEFOREUNLOAD_EVENT
326 #undef WINDOW_EVENT_HELPER
329 } // namespace mozilla::dom