tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLBodyElement.cpp (12090B)


      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 "HTMLBodyElement.h"
      8 
      9 #include "DocumentInlines.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 "mozilla/dom/HTMLBodyElementBinding.h"
     18 #include "nsAttrValueInlines.h"
     19 #include "nsDocShell.h"
     20 #include "nsGkAtoms.h"
     21 #include "nsGlobalWindowInner.h"
     22 #include "nsIDocShell.h"
     23 #include "nsPresContext.h"
     24 #include "nsStyleConsts.h"
     25 
     26 NS_IMPL_NS_NEW_HTML_ELEMENT(Body)
     27 
     28 namespace mozilla::dom {
     29 
     30 //----------------------------------------------------------------------
     31 
     32 HTMLBodyElement::~HTMLBodyElement() = default;
     33 
     34 JSObject* HTMLBodyElement::WrapNode(JSContext* aCx,
     35                                    JS::Handle<JSObject*> aGivenProto) {
     36  return HTMLBodyElement_Binding::Wrap(aCx, this, aGivenProto);
     37 }
     38 
     39 NS_IMPL_ELEMENT_CLONE(HTMLBodyElement)
     40 
     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);
     50    }
     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);
     58    }
     59  }
     60 
     61  return nsGenericHTMLElement::ParseBackgroundAttribute(
     62             aNamespaceID, aAttribute, aValue, aResult) ||
     63         nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
     64                                              aMaybeScriptedPrincipal, aResult);
     65 }
     66 
     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)
     76 
     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;
     83 
     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;
     91    }
     92    aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_left,
     93                                  (float)bodyMarginWidth);
     94    aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_right,
     95                                  (float)bodyMarginWidth);
     96  }
     97 
     98  value = aBuilder.GetAttr(nsGkAtoms::marginheight);
     99  if (value && value->Type() == nsAttrValue::eInteger) {
    100    bodyMarginHeight = value->GetIntegerValue();
    101    if (bodyMarginHeight < 0) {
    102      bodyMarginHeight = 0;
    103    }
    104    aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_top,
    105                                  (float)bodyMarginHeight);
    106    aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_bottom,
    107                                  (float)bodyMarginHeight);
    108  }
    109 
    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;
    117      }
    118      aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_top,
    119                                    (float)bodyTopMargin);
    120    }
    121  }
    122  // bottommargin (IE-attribute)
    123 
    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;
    130      }
    131      aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_bottom,
    132                                    (float)bodyBottomMargin);
    133    }
    134  }
    135 
    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;
    143      }
    144      aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_left,
    145                                    (float)bodyLeftMargin);
    146    }
    147  }
    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;
    155      }
    156      aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_right,
    157                                    (float)bodyRightMargin);
    158    }
    159  }
    160 
    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;
    168 
    169      if (bodyMarginWidth == -1 && frameMarginWidth >= 0) {
    170        if (bodyLeftMargin == -1) {
    171          aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_left,
    172                                        (float)frameMarginWidth);
    173        }
    174        if (bodyRightMargin == -1) {
    175          aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_right,
    176                                        (float)frameMarginWidth);
    177        }
    178      }
    179 
    180      if (bodyMarginHeight == -1 && frameMarginHeight >= 0) {
    181        if (bodyTopMargin == -1) {
    182          aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_top,
    183                                        (float)frameMarginHeight);
    184        }
    185        if (bodyBottomMargin == -1) {
    186          aBuilder.SetPixelValueIfUnset(eCSSProperty_margin_bottom,
    187                                        (float)frameMarginHeight);
    188        }
    189      }
    190    }
    191  }
    192 
    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);
    199    }
    200 
    201    value = aBuilder.GetAttr(nsGkAtoms::alink);
    202    if (value && value->GetColorValue(color)) {
    203      attrStyles->SetActiveLinkColor(color);
    204    }
    205 
    206    value = aBuilder.GetAttr(nsGkAtoms::vlink);
    207    if (value && value->GetColorValue(color)) {
    208      attrStyles->SetVisitedLinkColor(color);
    209    }
    210  }
    211 
    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);
    218    }
    219  }
    220 
    221  nsGenericHTMLElement::MapBackgroundAttributesInto(aBuilder);
    222  nsGenericHTMLElement::MapCommonAttributesInto(aBuilder);
    223 }
    224 
    225 nsMapRuleToAttributesFunc HTMLBodyElement::GetAttributeMappingFunction() const {
    226  return &MapAttributesIntoRule;
    227 }
    228 
    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},
    243  };
    244 
    245  static const MappedAttributeEntry* const map[] = {
    246      attributes,
    247      sCommonAttributeMap,
    248      sBackgroundAttributeMap,
    249  };
    250 
    251  return FindAttributeDependence(aAttribute, map);
    252 }
    253 
    254 already_AddRefed<EditorBase> HTMLBodyElement::GetAssociatedEditor() {
    255  MOZ_ASSERT(!GetTextEditorInternal());
    256 
    257  // Make sure this is the actual body of the document
    258  if (this != OwnerDoc()->GetBodyElement()) {
    259    return nullptr;
    260  }
    261 
    262  // For designmode, try to get document's editor
    263  nsPresContext* presContext = GetPresContext(eForComposedDoc);
    264  if (!presContext) {
    265    return nullptr;
    266  }
    267 
    268  nsCOMPtr<nsIDocShell> docShell = presContext->GetDocShell();
    269  if (!docShell) {
    270    return nullptr;
    271  }
    272 
    273  RefPtr<HTMLEditor> htmlEditor = docShell->GetHTMLEditor();
    274  return htmlEditor.forget();
    275 }
    276 
    277 bool HTMLBodyElement::IsEventAttributeNameInternal(nsAtom* aName) {
    278  return nsContentUtils::IsEventAttributeName(
    279      aName, EventNameType_HTML | EventNameType_HTMLBodyOrFramesetOnly);
    280 }
    281 
    282 nsresult HTMLBodyElement::BindToTree(BindContext& aContext, nsINode& aParent) {
    283  mAttrs.MarkAsPendingPresAttributeEvaluation();
    284  return nsGenericHTMLElement::BindToTree(aContext, aParent);
    285 }
    286 
    287 void HTMLBodyElement::FrameMarginsChanged() {
    288  MOZ_ASSERT(IsInComposedDoc());
    289  if (IsPendingMappedAttributeEvaluation()) {
    290    return;
    291  }
    292  if (mAttrs.MarkAsPendingPresAttributeEvaluation()) {
    293    OwnerDoc()->ScheduleForPresAttrEvaluation(this);
    294  }
    295 }
    296 
    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_();                                \
    307    }                                                                  \
    308    return nullptr;                                                    \
    309  }                                                                    \
    310  void HTMLBodyElement::SetOn##name_(type_* handler) {                 \
    311    nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();            \
    312    if (!win) {                                                        \
    313      return;                                                          \
    314    }                                                                  \
    315                                                                       \
    316    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);   \
    317    return globalWin->SetOn##name_(handler);                           \
    318  }
    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
    328 
    329 }  // namespace mozilla::dom