summaryrefslogtreecommitdiffstats
path: root/dom/html/HTMLBodyElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/HTMLBodyElement.cpp')
-rw-r--r--dom/html/HTMLBodyElement.cpp530
1 files changed, 530 insertions, 0 deletions
diff --git a/dom/html/HTMLBodyElement.cpp b/dom/html/HTMLBodyElement.cpp
new file mode 100644
index 000000000..6230cb6ca
--- /dev/null
+++ b/dom/html/HTMLBodyElement.cpp
@@ -0,0 +1,530 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HTMLBodyElement.h"
+#include "mozilla/dom/HTMLBodyElementBinding.h"
+#include "nsAttrValueInlines.h"
+#include "nsGkAtoms.h"
+#include "nsStyleConsts.h"
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsIDocument.h"
+#include "nsHTMLStyleSheet.h"
+#include "nsIEditor.h"
+#include "nsMappedAttributes.h"
+#include "nsRuleData.h"
+#include "nsIDocShell.h"
+#include "nsRuleWalker.h"
+#include "nsGlobalWindow.h"
+
+NS_IMPL_NS_NEW_HTML_ELEMENT(Body)
+
+namespace mozilla {
+namespace dom {
+
+//----------------------------------------------------------------------
+
+BodyRule::BodyRule(HTMLBodyElement* aPart)
+ : mPart(aPart)
+{
+}
+
+BodyRule::~BodyRule()
+{
+}
+
+NS_IMPL_ISUPPORTS(BodyRule, nsIStyleRule)
+
+/* virtual */ void
+BodyRule::MapRuleInfoInto(nsRuleData* aData)
+{
+ if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) || !mPart)
+ return; // We only care about margins.
+
+ int32_t bodyMarginWidth = -1;
+ int32_t bodyMarginHeight = -1;
+ int32_t bodyTopMargin = -1;
+ int32_t bodyBottomMargin = -1;
+ int32_t bodyLeftMargin = -1;
+ int32_t bodyRightMargin = -1;
+
+ // check the mode (fortunately, the ruleData has a presContext for us to use!)
+ NS_ASSERTION(aData->mPresContext, "null presContext in ruleNode was unexpected");
+ nsCompatibility mode = aData->mPresContext->CompatibilityMode();
+
+
+ const nsAttrValue* value;
+ if (mPart->GetAttrCount() > 0) {
+ // if marginwidth/marginheight are set, reflect them as 'margin'
+ value = mPart->GetParsedAttr(nsGkAtoms::marginwidth);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyMarginWidth = value->GetIntegerValue();
+ if (bodyMarginWidth < 0) bodyMarginWidth = 0;
+ nsCSSValue* marginLeft = aData->ValueForMarginLeft();
+ if (marginLeft->GetUnit() == eCSSUnit_Null)
+ marginLeft->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
+ nsCSSValue* marginRight = aData->ValueForMarginRight();
+ if (marginRight->GetUnit() == eCSSUnit_Null)
+ marginRight->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
+ }
+
+ value = mPart->GetParsedAttr(nsGkAtoms::marginheight);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyMarginHeight = value->GetIntegerValue();
+ if (bodyMarginHeight < 0) bodyMarginHeight = 0;
+ nsCSSValue* marginTop = aData->ValueForMarginTop();
+ if (marginTop->GetUnit() == eCSSUnit_Null)
+ marginTop->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
+ nsCSSValue* marginBottom = aData->ValueForMarginBottom();
+ if (marginBottom->GetUnit() == eCSSUnit_Null)
+ marginBottom->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
+ }
+
+ // topmargin (IE-attribute)
+ value = mPart->GetParsedAttr(nsGkAtoms::topmargin);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyTopMargin = value->GetIntegerValue();
+ if (bodyTopMargin < 0) bodyTopMargin = 0;
+ nsCSSValue* marginTop = aData->ValueForMarginTop();
+ if (marginTop->GetUnit() == eCSSUnit_Null)
+ marginTop->SetFloatValue((float)bodyTopMargin, eCSSUnit_Pixel);
+ }
+
+ // bottommargin (IE-attribute)
+ value = mPart->GetParsedAttr(nsGkAtoms::bottommargin);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyBottomMargin = value->GetIntegerValue();
+ if (bodyBottomMargin < 0) bodyBottomMargin = 0;
+ nsCSSValue* marginBottom = aData->ValueForMarginBottom();
+ if (marginBottom->GetUnit() == eCSSUnit_Null)
+ marginBottom->SetFloatValue((float)bodyBottomMargin, eCSSUnit_Pixel);
+ }
+
+ // leftmargin (IE-attribute)
+ value = mPart->GetParsedAttr(nsGkAtoms::leftmargin);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyLeftMargin = value->GetIntegerValue();
+ if (bodyLeftMargin < 0) bodyLeftMargin = 0;
+ nsCSSValue* marginLeft = aData->ValueForMarginLeft();
+ if (marginLeft->GetUnit() == eCSSUnit_Null)
+ marginLeft->SetFloatValue((float)bodyLeftMargin, eCSSUnit_Pixel);
+ }
+
+ // rightmargin (IE-attribute)
+ value = mPart->GetParsedAttr(nsGkAtoms::rightmargin);
+ if (value && value->Type() == nsAttrValue::eInteger) {
+ bodyRightMargin = value->GetIntegerValue();
+ if (bodyRightMargin < 0) bodyRightMargin = 0;
+ nsCSSValue* marginRight = aData->ValueForMarginRight();
+ if (marginRight->GetUnit() == eCSSUnit_Null)
+ marginRight->SetFloatValue((float)bodyRightMargin, eCSSUnit_Pixel);
+ }
+
+ }
+
+ // if marginwidth or marginheight is set in the <frame> and not set in the <body>
+ // reflect them as margin in the <body>
+ if (bodyMarginWidth == -1 || bodyMarginHeight == -1) {
+ nsCOMPtr<nsIDocShell> docShell(aData->mPresContext->GetDocShell());
+ if (docShell) {
+ nscoord frameMarginWidth=-1; // default value
+ nscoord frameMarginHeight=-1; // default value
+ docShell->GetMarginWidth(&frameMarginWidth); // -1 indicates not set
+ docShell->GetMarginHeight(&frameMarginHeight);
+ if ((frameMarginWidth >= 0) && (bodyMarginWidth == -1)) { // set in <frame> & not in <body>
+ if (eCompatibility_NavQuirks == mode) {
+ if ((bodyMarginHeight == -1) && (0 > frameMarginHeight)) // nav quirk
+ frameMarginHeight = 0;
+ }
+ }
+ if ((frameMarginHeight >= 0) && (bodyMarginHeight == -1)) { // set in <frame> & not in <body>
+ if (eCompatibility_NavQuirks == mode) {
+ if ((bodyMarginWidth == -1) && (0 > frameMarginWidth)) // nav quirk
+ frameMarginWidth = 0;
+ }
+ }
+
+ if ((bodyMarginWidth == -1) && (frameMarginWidth >= 0)) {
+ nsCSSValue* marginLeft = aData->ValueForMarginLeft();
+ if (marginLeft->GetUnit() == eCSSUnit_Null)
+ marginLeft->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
+ nsCSSValue* marginRight = aData->ValueForMarginRight();
+ if (marginRight->GetUnit() == eCSSUnit_Null)
+ marginRight->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
+ }
+
+ if ((bodyMarginHeight == -1) && (frameMarginHeight >= 0)) {
+ nsCSSValue* marginTop = aData->ValueForMarginTop();
+ if (marginTop->GetUnit() == eCSSUnit_Null)
+ marginTop->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
+ nsCSSValue* marginBottom = aData->ValueForMarginBottom();
+ if (marginBottom->GetUnit() == eCSSUnit_Null)
+ marginBottom->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
+ }
+ }
+ }
+}
+
+/* virtual */ bool
+BodyRule::MightMapInheritedStyleData()
+{
+ return false;
+}
+
+/* virtual */ bool
+BodyRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
+ nsCSSValue* aValue)
+{
+ MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
+ return false;
+}
+
+#ifdef DEBUG
+/* virtual */ void
+BodyRule::List(FILE* out, int32_t aIndent) const
+{
+ nsAutoCString indent;
+ for (int32_t index = aIndent; --index >= 0; ) {
+ indent.AppendLiteral(" ");
+ }
+ fprintf_stderr(out, "%s[body rule] {}\n", indent.get());
+}
+#endif
+
+//----------------------------------------------------------------------
+
+HTMLBodyElement::~HTMLBodyElement()
+{
+ if (mContentStyleRule) {
+ mContentStyleRule->mPart = nullptr;
+ }
+}
+
+JSObject*
+HTMLBodyElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return HTMLBodyElementBinding::Wrap(aCx, this, aGivenProto);
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(HTMLBodyElement, nsGenericHTMLElement,
+ nsIDOMHTMLBodyElement)
+
+NS_IMPL_ELEMENT_CLONE(HTMLBodyElement)
+
+NS_IMETHODIMP
+HTMLBodyElement::SetBackground(const nsAString& aBackground)
+{
+ ErrorResult rv;
+ SetBackground(aBackground, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetBackground(nsAString& aBackground)
+{
+ DOMString background;
+ GetBackground(background);
+ background.ToString(aBackground);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::SetVLink(const nsAString& aVLink)
+{
+ ErrorResult rv;
+ SetVLink(aVLink, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetVLink(nsAString& aVLink)
+{
+ DOMString vLink;
+ GetVLink(vLink);
+ vLink.ToString(aVLink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::SetALink(const nsAString& aALink)
+{
+ ErrorResult rv;
+ SetALink(aALink, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetALink(nsAString& aALink)
+{
+ DOMString aLink;
+ GetALink(aLink);
+ aLink.ToString(aALink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::SetLink(const nsAString& aLink)
+{
+ ErrorResult rv;
+ SetLink(aLink, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetLink(nsAString& aLink)
+{
+ DOMString link;
+ GetLink(link);
+ link.ToString(aLink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::SetText(const nsAString& aText)
+{
+ ErrorResult rv;
+ SetText(aText, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetText(nsAString& aText)
+{
+ DOMString text;
+ GetText(text);
+ text.ToString(aText);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::SetBgColor(const nsAString& aBgColor)
+{
+ ErrorResult rv;
+ SetBgColor(aBgColor, rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::GetBgColor(nsAString& aBgColor)
+{
+ DOMString bgColor;
+ GetBgColor(bgColor);
+ bgColor.ToString(aBgColor);
+ return NS_OK;
+}
+
+bool
+HTMLBodyElement::ParseAttribute(int32_t aNamespaceID,
+ nsIAtom* aAttribute,
+ const nsAString& aValue,
+ nsAttrValue& aResult)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aAttribute == nsGkAtoms::bgcolor ||
+ aAttribute == nsGkAtoms::text ||
+ aAttribute == nsGkAtoms::link ||
+ aAttribute == nsGkAtoms::alink ||
+ aAttribute == nsGkAtoms::vlink) {
+ return aResult.ParseColor(aValue);
+ }
+ if (aAttribute == nsGkAtoms::marginwidth ||
+ aAttribute == nsGkAtoms::marginheight ||
+ aAttribute == nsGkAtoms::topmargin ||
+ aAttribute == nsGkAtoms::bottommargin ||
+ aAttribute == nsGkAtoms::leftmargin ||
+ aAttribute == nsGkAtoms::rightmargin) {
+ return aResult.ParseIntWithBounds(aValue, 0);
+ }
+ }
+
+ return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
+ aAttribute, aValue,
+ aResult) ||
+ nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
+ aResult);
+}
+
+void
+HTMLBodyElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+ if (mContentStyleRule) {
+ mContentStyleRule->mPart = nullptr;
+ mContentStyleRule = nullptr;
+ }
+
+ nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+void
+HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+ nsRuleData* aData)
+{
+ if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
+ // When display if first asked for, go ahead and get our colors set up.
+ nsIPresShell *presShell = aData->mPresContext->GetPresShell();
+ if (presShell) {
+ nsIDocument *doc = presShell->GetDocument();
+ if (doc) {
+ nsHTMLStyleSheet* styleSheet = doc->GetAttributeStyleSheet();
+ if (styleSheet) {
+ const nsAttrValue* value;
+ nscolor color;
+ value = aAttributes->GetAttr(nsGkAtoms::link);
+ if (value && value->GetColorValue(color)) {
+ styleSheet->SetLinkColor(color);
+ }
+
+ value = aAttributes->GetAttr(nsGkAtoms::alink);
+ if (value && value->GetColorValue(color)) {
+ styleSheet->SetActiveLinkColor(color);
+ }
+
+ value = aAttributes->GetAttr(nsGkAtoms::vlink);
+ if (value && value->GetColorValue(color)) {
+ styleSheet->SetVisitedLinkColor(color);
+ }
+ }
+ }
+ }
+ }
+
+ if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
+ nsCSSValue *colorValue = aData->ValueForColor();
+ if (colorValue->GetUnit() == eCSSUnit_Null &&
+ aData->mPresContext->UseDocumentColors()) {
+ // color: color
+ nscolor color;
+ const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::text);
+ if (value && value->GetColorValue(color))
+ colorValue->SetColorValue(color);
+ }
+ }
+
+ nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
+ nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+}
+
+nsMapRuleToAttributesFunc
+HTMLBodyElement::GetAttributeMappingFunction() const
+{
+ return &MapAttributesIntoRule;
+}
+
+NS_IMETHODIMP
+HTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
+{
+ nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
+
+ if (!mContentStyleRule && IsInUncomposedDoc()) {
+ // XXXbz should this use OwnerDoc() or GetComposedDoc()?
+ // sXBL/XBL2 issue!
+ mContentStyleRule = new BodyRule(this);
+ }
+ if (aRuleWalker && mContentStyleRule) {
+ aRuleWalker->Forward(mContentStyleRule);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(bool)
+HTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const
+{
+ static const MappedAttributeEntry attributes[] = {
+ { &nsGkAtoms::link },
+ { &nsGkAtoms::vlink },
+ { &nsGkAtoms::alink },
+ { &nsGkAtoms::text },
+ // These aren't mapped through attribute mapping, but they are
+ // mapped through a style rule, so it is attribute dependent style.
+ // XXXldb But we don't actually replace the body rule when we have
+ // dynamic changes...
+ { &nsGkAtoms::marginwidth },
+ { &nsGkAtoms::marginheight },
+ { nullptr },
+ };
+
+ static const MappedAttributeEntry* const map[] = {
+ attributes,
+ sCommonAttributeMap,
+ sBackgroundAttributeMap,
+ };
+
+ return FindAttributeDependence(aAttribute, map);
+}
+
+already_AddRefed<nsIEditor>
+HTMLBodyElement::GetAssociatedEditor()
+{
+ nsCOMPtr<nsIEditor> editor = GetEditorInternal();
+ if (editor) {
+ return editor.forget();
+ }
+
+ // Make sure this is the actual body of the document
+ if (!IsCurrentBodyElement()) {
+ return nullptr;
+ }
+
+ // For designmode, try to get document's editor
+ nsPresContext* presContext = GetPresContext(eForComposedDoc);
+ if (!presContext) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIDocShell> docShell = presContext->GetDocShell();
+ if (!docShell) {
+ return nullptr;
+ }
+
+ docShell->GetEditor(getter_AddRefs(editor));
+ return editor.forget();
+}
+
+bool
+HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
+{
+ return nsContentUtils::IsEventAttributeName(aName,
+ EventNameType_HTML |
+ EventNameType_HTMLBodyOrFramesetOnly);
+}
+
+#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
+// nsGenericHTMLElement::GetOnError returns
+// already_AddRefed<EventHandlerNonNull> while other getters return
+// EventHandlerNonNull*, so allow passing in the type to use here.
+#define WINDOW_EVENT_HELPER(name_, type_) \
+ type_* \
+ HTMLBodyElement::GetOn##name_() \
+ { \
+ if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
+ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
+ return globalWin->GetOn##name_(); \
+ } \
+ return nullptr; \
+ } \
+ void \
+ HTMLBodyElement::SetOn##name_(type_* handler) \
+ { \
+ nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \
+ if (!win) { \
+ return; \
+ } \
+ \
+ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
+ return globalWin->SetOn##name_(handler); \
+ }
+#define WINDOW_EVENT(name_, id_, type_, struct_) \
+ WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
+#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
+ WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
+#include "mozilla/EventNameList.h" // IWYU pragma: keep
+#undef BEFOREUNLOAD_EVENT
+#undef WINDOW_EVENT
+#undef WINDOW_EVENT_HELPER
+#undef EVENT
+
+} // namespace dom
+} // namespace mozilla