tor-browser

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

HTMLFrameSetElement.cpp (10191B)


      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 "HTMLFrameSetElement.h"
      8 
      9 #include "mozilla/dom/Document.h"
     10 #include "mozilla/dom/EventHandlerBinding.h"
     11 #include "mozilla/dom/HTMLFrameSetElementBinding.h"
     12 #include "nsAttrValueOrString.h"
     13 #include "nsGlobalWindowInner.h"
     14 
     15 NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
     16 
     17 namespace mozilla::dom {
     18 
     19 HTMLFrameSetElement::~HTMLFrameSetElement() = default;
     20 
     21 JSObject* HTMLFrameSetElement::WrapNode(JSContext* aCx,
     22                                        JS::Handle<JSObject*> aGivenProto) {
     23  return HTMLFrameSetElement_Binding::Wrap(aCx, this, aGivenProto);
     24 }
     25 
     26 NS_IMPL_ELEMENT_CLONE(HTMLFrameSetElement)
     27 
     28 void HTMLFrameSetElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
     29                                        const nsAttrValue* aValue,
     30                                        bool aNotify) {
     31  /* The main goal here is to see whether the _number_ of rows or
     32   * columns has changed. If it has, we need to reframe; otherwise
     33   * we want to reflow.
     34   * Ideally, the style hint would be changed back to reflow after the reframe
     35   * has been performed. Unfortunately, however, the reframe will be performed
     36   * by the call to MutationObservers::AttributeChanged, which occurs *after*
     37   * AfterSetAttr is called, leaving us with no convenient way of changing the
     38   * value back to reflow afterwards. However,
     39   * MutationObservers::AttributeChanged is effectively the only consumer of
     40   * this value, so as long as we always set the value correctly here, we should
     41   * be fine.
     42   */
     43  mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
     44  if (aNamespaceID == kNameSpaceID_None) {
     45    if (aName == nsGkAtoms::rows) {
     46      if (aValue) {
     47        size_t oldNumRows = mRowSpecs.Length();
     48        ParseRowCol(*aValue, mRowSpecs);
     49        if (mRowSpecs.Length() != oldNumRows) {
     50          mCurrentRowColHint = nsChangeHint_ReconstructFrame;
     51        }
     52      }
     53    } else if (aName == nsGkAtoms::cols) {
     54      if (aValue) {
     55        size_t oldNumCols = mColSpecs.Length();
     56        ParseRowCol(*aValue, mColSpecs);
     57        if (mColSpecs.Length() != oldNumCols) {
     58          mCurrentRowColHint = nsChangeHint_ReconstructFrame;
     59        }
     60      }
     61    }
     62  }
     63 
     64  return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue,
     65                                             aNotify);
     66 }
     67 
     68 Span<const nsFramesetSpec> HTMLFrameSetElement::GetRowSpec() {
     69  if (mRowSpecs.IsEmpty()) {
     70    if (const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows)) {
     71      if (NS_FAILED(ParseRowCol(*value, mRowSpecs))) {
     72        return {};
     73      }
     74    }
     75 
     76    if (mRowSpecs.IsEmpty()) {
     77      // We may not have had an attr or had an empty attr.
     78      mRowSpecs.SetLength(1);
     79      mRowSpecs[0].mUnit = eFramesetUnit_Relative;
     80      mRowSpecs[0].mValue = 1;
     81    }
     82  }
     83 
     84  return Span(mRowSpecs);
     85 }
     86 
     87 Span<const nsFramesetSpec> HTMLFrameSetElement::GetColSpec() {
     88  if (mColSpecs.IsEmpty()) {
     89    if (const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols)) {
     90      if (NS_FAILED(ParseRowCol(*value, mColSpecs))) {
     91        return {};
     92      }
     93    }
     94 
     95    if (mColSpecs.IsEmpty()) {
     96      // We may not have had an attr or had an empty attr.
     97      mColSpecs.SetLength(1);
     98      mColSpecs[0].mUnit = eFramesetUnit_Relative;
     99      mColSpecs[0].mValue = 1;
    100    }
    101  }
    102 
    103  return Span(mColSpecs);
    104 }
    105 
    106 bool HTMLFrameSetElement::ParseAttribute(int32_t aNamespaceID,
    107                                         nsAtom* aAttribute,
    108                                         const nsAString& aValue,
    109                                         nsIPrincipal* aMaybeScriptedPrincipal,
    110                                         nsAttrValue& aResult) {
    111  if (aNamespaceID == kNameSpaceID_None) {
    112    if (aAttribute == nsGkAtoms::bordercolor) {
    113      return aResult.ParseColor(aValue);
    114    }
    115    if (aAttribute == nsGkAtoms::frameborder) {
    116      return nsGenericHTMLElement::ParseFrameborderValue(aValue, aResult);
    117    }
    118    if (aAttribute == nsGkAtoms::border) {
    119      return aResult.ParseIntWithBounds(aValue, 0, 100);
    120    }
    121  }
    122 
    123  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
    124                                              aMaybeScriptedPrincipal, aResult);
    125 }
    126 
    127 nsChangeHint HTMLFrameSetElement::GetAttributeChangeHint(
    128    const nsAtom* aAttribute, AttrModType aModType) const {
    129  nsChangeHint retval =
    130      nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
    131  if (aAttribute == nsGkAtoms::rows || aAttribute == nsGkAtoms::cols) {
    132    retval |= mCurrentRowColHint;
    133  }
    134  return retval;
    135 }
    136 
    137 /**
    138 * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
    139 */
    140 nsresult HTMLFrameSetElement::ParseRowCol(const nsAttrValue& aValue,
    141                                          nsTArray<nsFramesetSpec>& aSpecs) {
    142  if (aValue.IsEmptyString()) {
    143    aSpecs.Clear();
    144    return NS_OK;
    145  }
    146 
    147  static const char16_t sAster('*');
    148  static const char16_t sPercent('%');
    149  static const char16_t sComma(',');
    150 
    151  nsAutoString spec(nsAttrValueOrString(&aValue).String());
    152  // remove whitespace (Bug 33699) and quotation marks (bug 224598)
    153  // also remove leading/trailing commas (bug 31482)
    154  spec.StripChars(u" \n\r\t\"\'");
    155  spec.Trim(",");
    156 
    157  // Count the commas. Don't count more than X commas (bug 576447).
    158  static_assert(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30),
    159                "Too many frameset specs allowed to allocate");
    160  int32_t commaX = spec.FindChar(sComma);
    161  size_t count = 1;
    162  while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
    163    count++;
    164    commaX = spec.FindChar(sComma, commaX + 1);
    165  }
    166 
    167  nsTArray<nsFramesetSpec> specs;
    168  if (!specs.SetLength(count, fallible)) {
    169    aSpecs.Clear();
    170    return NS_ERROR_OUT_OF_MEMORY;
    171  }
    172 
    173  // Pre-grab the compat mode; we may need it later in the loop.
    174  bool isInQuirks = InNavQuirksMode(OwnerDoc());
    175 
    176  // Parse each comma separated token
    177 
    178  size_t start = 0;
    179  size_t specLen = spec.Length();
    180 
    181  for (size_t i = 0; i < count; i++) {
    182    // Find our comma
    183    commaX = spec.FindChar(sComma, start);
    184    MOZ_ASSERT(i == count - 1 || commaX != kNotFound,
    185               "Failed to find comma, somehow");
    186    size_t end = (commaX == kNotFound) ? specLen : commaX;
    187 
    188    // Note: If end == start then it means that the token has no
    189    // data in it other than a terminating comma (or the end of the spec).
    190    // So default to a fixed width of 0.
    191    specs[i].mUnit = eFramesetUnit_Fixed;
    192    specs[i].mValue = 0;
    193    if (end > start) {
    194      size_t numberEnd = end;
    195      char16_t ch = spec.CharAt(numberEnd - 1);
    196      if (sAster == ch) {
    197        specs[i].mUnit = eFramesetUnit_Relative;
    198        numberEnd--;
    199      } else if (sPercent == ch) {
    200        specs[i].mUnit = eFramesetUnit_Percent;
    201        numberEnd--;
    202        // check for "*%"
    203        if (numberEnd > start) {
    204          ch = spec.CharAt(numberEnd - 1);
    205          if (sAster == ch) {
    206            specs[i].mUnit = eFramesetUnit_Relative;
    207            numberEnd--;
    208          }
    209        }
    210      }
    211 
    212      // Translate value to an integer
    213      nsAutoString token;
    214      spec.Mid(token, start, numberEnd - start);
    215 
    216      // Treat * as 1*
    217      if ((eFramesetUnit_Relative == specs[i].mUnit) && (0 == token.Length())) {
    218        specs[i].mValue = 1;
    219      } else {
    220        // Otherwise just convert to integer.
    221        nsresult err;
    222        specs[i].mValue = token.ToInteger(&err);
    223        if (NS_FAILED(err)) {
    224          specs[i].mValue = 0;
    225        }
    226      }
    227 
    228      // Treat 0* as 1* in quirks mode (bug 40383)
    229      if (isInQuirks) {
    230        if ((eFramesetUnit_Relative == specs[i].mUnit) &&
    231            (0 == specs[i].mValue)) {
    232          specs[i].mValue = 1;
    233        }
    234      }
    235 
    236      // In standards mode, just set negative sizes to zero
    237      if (specs[i].mValue < 0) {
    238        specs[i].mValue = 0;
    239      }
    240      start = end + 1;
    241    }
    242  }
    243 
    244  aSpecs = std::move(specs);
    245 
    246  return NS_OK;
    247 }
    248 
    249 bool HTMLFrameSetElement::IsEventAttributeNameInternal(nsAtom* aName) {
    250  return nsContentUtils::IsEventAttributeName(
    251      aName, EventNameType_HTML | EventNameType_HTMLBodyOrFramesetOnly);
    252 }
    253 
    254 #define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
    255 // nsGenericHTMLElement::GetOnError returns
    256 // already_AddRefed<EventHandlerNonNull> while other getters return
    257 // EventHandlerNonNull*, so allow passing in the type to use here.
    258 #define WINDOW_EVENT_HELPER(name_, type_)                              \
    259  type_* HTMLFrameSetElement::GetOn##name_() {                         \
    260    if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {      \
    261      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win); \
    262      return globalWin->GetOn##name_();                                \
    263    }                                                                  \
    264    return nullptr;                                                    \
    265  }                                                                    \
    266  void HTMLFrameSetElement::SetOn##name_(type_* handler) {             \
    267    nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();            \
    268    if (!win) {                                                        \
    269      return;                                                          \
    270    }                                                                  \
    271                                                                       \
    272    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);   \
    273    return globalWin->SetOn##name_(handler);                           \
    274  }
    275 #define WINDOW_EVENT(name_, id_, type_, struct_) \
    276  WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
    277 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
    278  WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
    279 #include "mozilla/EventNameList.h"  // IWYU pragma: keep
    280 #undef BEFOREUNLOAD_EVENT
    281 #undef WINDOW_EVENT
    282 #undef WINDOW_EVENT_HELPER
    283 #undef EVENT
    284 
    285 }  // namespace mozilla::dom