diff options
Diffstat (limited to 'dom/html/HTMLBodyElement.cpp')
-rw-r--r-- | dom/html/HTMLBodyElement.cpp | 530 |
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 |