no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / html / HTMLBodyElement.cpp
blob9fcf3e0eb6374c19e0bd90248f6df02769bef89b
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) {
90 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) {
116 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) {
142 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) {
154 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()) {
195 nscolor color;
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)) {
213 // color: color
214 nscolor 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;
229 NS_IMETHODIMP_(bool)
230 HTMLBodyElement::IsAttributeMapped(const nsAtom* aAttribute) const {
231 static const MappedAttributeEntry attributes[] = {
232 {nsGkAtoms::link},
233 {nsGkAtoms::vlink},
234 {nsGkAtoms::alink},
235 {nsGkAtoms::text},
236 {nsGkAtoms::marginwidth},
237 {nsGkAtoms::marginheight},
238 {nsGkAtoms::topmargin},
239 {nsGkAtoms::rightmargin},
240 {nsGkAtoms::bottommargin},
241 {nsGkAtoms::leftmargin},
242 {nullptr},
245 static const MappedAttributeEntry* const map[] = {
246 attributes,
247 sCommonAttributeMap,
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()) {
259 return nullptr;
262 // For designmode, try to get document's editor
263 nsPresContext* presContext = GetPresContext(eForComposedDoc);
264 if (!presContext) {
265 return nullptr;
268 nsCOMPtr<nsIDocShell> docShell = presContext->GetDocShell();
269 if (!docShell) {
270 return nullptr;
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()) {
290 return;
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_(); \
308 return nullptr; \
310 void HTMLBodyElement::SetOn##name_(type_* handler) { \
311 nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
312 if (!win) { \
313 return; \
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
325 #undef WINDOW_EVENT
326 #undef WINDOW_EVENT_HELPER
327 #undef EVENT
329 } // namespace mozilla::dom