Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/HTMLFrameSetElement.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/dom/HTMLFrameSetElementBinding.h"
9
#include "mozilla/dom/EventHandlerBinding.h"
10
#include "nsGlobalWindow.h"
11
#include "mozilla/UniquePtrExtensions.h"
12
#include "nsAttrValueOrString.h"
13
14
NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
15
16
namespace mozilla {
17
namespace dom {
18
19
HTMLFrameSetElement::~HTMLFrameSetElement()
20
0
{
21
0
}
22
23
JSObject*
24
HTMLFrameSetElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
25
0
{
26
0
  return HTMLFrameSetElement_Binding::Wrap(aCx, this, aGivenProto);
27
0
}
28
29
NS_IMPL_ELEMENT_CLONE(HTMLFrameSetElement)
30
31
nsresult
32
HTMLFrameSetElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
33
                                   const nsAttrValueOrString* aValue,
34
                                   bool aNotify)
35
0
{
36
0
  /* The main goal here is to see whether the _number_ of rows or
37
0
   * columns has changed. If it has, we need to reframe; otherwise
38
0
   * we want to reflow.
39
0
   * Ideally, the style hint would be changed back to reflow after the reframe
40
0
   * has been performed. Unfortunately, however, the reframe will be performed
41
0
   * by the call to nsNodeUtils::AttributeChanged, which occurs *after*
42
0
   * AfterSetAttr is called, leaving us with no convenient way of changing the
43
0
   * value back to reflow afterwards. However, nsNodeUtils::AttributeChanged is
44
0
   * effectively the only consumer of this value, so as long as we always set
45
0
   * the value correctly here, we should be fine.
46
0
   */
47
0
  mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
48
0
  if (aNamespaceID == kNameSpaceID_None) {
49
0
    if (aName == nsGkAtoms::rows) {
50
0
      if (aValue) {
51
0
        int32_t oldRows = mNumRows;
52
0
        ParseRowCol(aValue->String(), mNumRows, &mRowSpecs);
53
0
54
0
        if (mNumRows != oldRows) {
55
0
          mCurrentRowColHint = nsChangeHint_ReconstructFrame;
56
0
        }
57
0
      }
58
0
    } else if (aName == nsGkAtoms::cols) {
59
0
      if (aValue) {
60
0
        int32_t oldCols = mNumCols;
61
0
        ParseRowCol(aValue->String(), mNumCols, &mColSpecs);
62
0
63
0
        if (mNumCols != oldCols) {
64
0
          mCurrentRowColHint = nsChangeHint_ReconstructFrame;
65
0
        }
66
0
      }
67
0
    }
68
0
  }
69
0
70
0
  return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
71
0
}
72
73
nsresult
74
HTMLFrameSetElement::GetRowSpec(int32_t *aNumValues,
75
                                const nsFramesetSpec** aSpecs)
76
0
{
77
0
  MOZ_ASSERT(aNumValues, "Must have a pointer to an integer here!");
78
0
  MOZ_ASSERT(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
79
0
  *aNumValues = 0;
80
0
  *aSpecs = nullptr;
81
0
82
0
  if (!mRowSpecs) {
83
0
    const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows);
84
0
    if (value && value->Type() == nsAttrValue::eString) {
85
0
      nsresult rv = ParseRowCol(value->GetStringValue(), mNumRows,
86
0
                                &mRowSpecs);
87
0
      NS_ENSURE_SUCCESS(rv, rv);
88
0
    }
89
0
90
0
    if (!mRowSpecs) {  // we may not have had an attr or had an empty attr
91
0
      mRowSpecs = MakeUnique<nsFramesetSpec[]>(1);
92
0
      mNumRows = 1;
93
0
      mRowSpecs[0].mUnit  = eFramesetUnit_Relative;
94
0
      mRowSpecs[0].mValue = 1;
95
0
    }
96
0
  }
97
0
98
0
  *aSpecs = mRowSpecs.get();
99
0
  *aNumValues = mNumRows;
100
0
  return NS_OK;
101
0
}
102
103
nsresult
104
HTMLFrameSetElement::GetColSpec(int32_t *aNumValues,
105
                                const nsFramesetSpec** aSpecs)
106
0
{
107
0
  MOZ_ASSERT(aNumValues, "Must have a pointer to an integer here!");
108
0
  MOZ_ASSERT(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
109
0
  *aNumValues = 0;
110
0
  *aSpecs = nullptr;
111
0
112
0
  if (!mColSpecs) {
113
0
    const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols);
114
0
    if (value && value->Type() == nsAttrValue::eString) {
115
0
      nsresult rv = ParseRowCol(value->GetStringValue(), mNumCols,
116
0
                                &mColSpecs);
117
0
      NS_ENSURE_SUCCESS(rv, rv);
118
0
    }
119
0
120
0
    if (!mColSpecs) {  // we may not have had an attr or had an empty attr
121
0
      mColSpecs = MakeUnique<nsFramesetSpec[]>(1);
122
0
      mNumCols = 1;
123
0
      mColSpecs[0].mUnit  = eFramesetUnit_Relative;
124
0
      mColSpecs[0].mValue = 1;
125
0
    }
126
0
  }
127
0
128
0
  *aSpecs = mColSpecs.get();
129
0
  *aNumValues = mNumCols;
130
0
  return NS_OK;
131
0
}
132
133
134
bool
135
HTMLFrameSetElement::ParseAttribute(int32_t aNamespaceID,
136
                                    nsAtom* aAttribute,
137
                                    const nsAString& aValue,
138
                                    nsIPrincipal* aMaybeScriptedPrincipal,
139
                                    nsAttrValue& aResult)
140
0
{
141
0
  if (aNamespaceID == kNameSpaceID_None) {
142
0
    if (aAttribute == nsGkAtoms::bordercolor) {
143
0
      return aResult.ParseColor(aValue);
144
0
    }
145
0
    if (aAttribute == nsGkAtoms::frameborder) {
146
0
      return nsGenericHTMLElement::ParseFrameborderValue(aValue, aResult);
147
0
    }
148
0
    if (aAttribute == nsGkAtoms::border) {
149
0
      return aResult.ParseIntWithBounds(aValue, 0, 100);
150
0
    }
151
0
  }
152
0
153
0
  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
154
0
                                              aMaybeScriptedPrincipal, aResult);
155
0
}
156
157
nsChangeHint
158
HTMLFrameSetElement::GetAttributeChangeHint(const nsAtom* aAttribute,
159
                                            int32_t aModType) const
160
0
{
161
0
  nsChangeHint retval =
162
0
    nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
163
0
  if (aAttribute == nsGkAtoms::rows ||
164
0
      aAttribute == nsGkAtoms::cols) {
165
0
    retval |= mCurrentRowColHint;
166
0
  }
167
0
  return retval;
168
0
}
169
170
/**
171
 * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
172
 */
173
nsresult
174
HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
175
                                 int32_t& aNumSpecs,
176
                                 UniquePtr<nsFramesetSpec[]>* aSpecs)
177
0
{
178
0
  if (aValue.IsEmpty()) {
179
0
    aNumSpecs = 0;
180
0
    *aSpecs = nullptr;
181
0
    return NS_OK;
182
0
  }
183
0
184
0
  static const char16_t sAster('*');
185
0
  static const char16_t sPercent('%');
186
0
  static const char16_t sComma(',');
187
0
188
0
  nsAutoString spec(aValue);
189
0
  // remove whitespace (Bug 33699) and quotation marks (bug 224598)
190
0
  // also remove leading/trailing commas (bug 31482)
191
0
  spec.StripChars(" \n\r\t\"\'");
192
0
  spec.Trim(",");
193
0
194
0
  // Count the commas. Don't count more than X commas (bug 576447).
195
0
  static_assert(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30),
196
0
                "Too many frameset specs allowed to allocate");
197
0
  int32_t commaX = spec.FindChar(sComma);
198
0
  int32_t count = 1;
199
0
  while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
200
0
    count++;
201
0
    commaX = spec.FindChar(sComma, commaX + 1);
202
0
  }
203
0
204
0
  auto specs = MakeUniqueFallible<nsFramesetSpec[]>(count);
205
0
  if (!specs) {
206
0
    *aSpecs = nullptr;
207
0
    aNumSpecs = 0;
208
0
    return NS_ERROR_OUT_OF_MEMORY;
209
0
  }
210
0
211
0
  // Pre-grab the compat mode; we may need it later in the loop.
212
0
  bool isInQuirks = InNavQuirksMode(OwnerDoc());
213
0
214
0
  // Parse each comma separated token
215
0
216
0
  int32_t start = 0;
217
0
  int32_t specLen = spec.Length();
218
0
219
0
  for (int32_t i = 0; i < count; i++) {
220
0
    // Find our comma
221
0
    commaX = spec.FindChar(sComma, start);
222
0
    NS_ASSERTION(i == count - 1 || commaX != kNotFound,
223
0
                 "Failed to find comma, somehow");
224
0
    int32_t end = (commaX == kNotFound) ? specLen : commaX;
225
0
226
0
    // Note: If end == start then it means that the token has no
227
0
    // data in it other than a terminating comma (or the end of the spec).
228
0
    // So default to a fixed width of 0.
229
0
    specs[i].mUnit = eFramesetUnit_Fixed;
230
0
    specs[i].mValue = 0;
231
0
    if (end > start) {
232
0
      int32_t numberEnd = end;
233
0
      char16_t ch = spec.CharAt(numberEnd - 1);
234
0
      if (sAster == ch) {
235
0
        specs[i].mUnit = eFramesetUnit_Relative;
236
0
        numberEnd--;
237
0
      } else if (sPercent == ch) {
238
0
        specs[i].mUnit = eFramesetUnit_Percent;
239
0
        numberEnd--;
240
0
        // check for "*%"
241
0
        if (numberEnd > start) {
242
0
          ch = spec.CharAt(numberEnd - 1);
243
0
          if (sAster == ch) {
244
0
            specs[i].mUnit = eFramesetUnit_Relative;
245
0
            numberEnd--;
246
0
          }
247
0
        }
248
0
      }
249
0
250
0
      // Translate value to an integer
251
0
      nsAutoString token;
252
0
      spec.Mid(token, start, numberEnd - start);
253
0
254
0
      // Treat * as 1*
255
0
      if ((eFramesetUnit_Relative == specs[i].mUnit) &&
256
0
        (0 == token.Length())) {
257
0
        specs[i].mValue = 1;
258
0
      }
259
0
      else {
260
0
        // Otherwise just convert to integer.
261
0
        nsresult err;
262
0
        specs[i].mValue = token.ToInteger(&err);
263
0
        if (NS_FAILED(err)) {
264
0
          specs[i].mValue = 0;
265
0
        }
266
0
      }
267
0
268
0
      // Treat 0* as 1* in quirks mode (bug 40383)
269
0
      if (isInQuirks) {
270
0
        if ((eFramesetUnit_Relative == specs[i].mUnit) &&
271
0
          (0 == specs[i].mValue)) {
272
0
          specs[i].mValue = 1;
273
0
        }
274
0
      }
275
0
276
0
      // Catch zero and negative frame sizes for Nav compatibility
277
0
      // Nav resized absolute and relative frames to "1" and
278
0
      // percent frames to an even percentage of the width
279
0
      //
280
0
      //if (isInQuirks && (specs[i].mValue <= 0)) {
281
0
      //  if (eFramesetUnit_Percent == specs[i].mUnit) {
282
0
      //    specs[i].mValue = 100 / count;
283
0
      //  } else {
284
0
      //    specs[i].mValue = 1;
285
0
      //  }
286
0
      //} else {
287
0
288
0
      // In standards mode, just set negative sizes to zero
289
0
      if (specs[i].mValue < 0) {
290
0
        specs[i].mValue = 0;
291
0
      }
292
0
      start = end + 1;
293
0
    }
294
0
  }
295
0
296
0
  aNumSpecs = count;
297
0
  // Transfer ownership to caller here
298
0
  *aSpecs = std::move(specs);
299
0
300
0
  return NS_OK;
301
0
}
302
303
bool
304
HTMLFrameSetElement::IsEventAttributeNameInternal(nsAtom *aName)
305
0
{
306
0
  return nsContentUtils::IsEventAttributeName(aName,
307
0
                                              EventNameType_HTML |
308
0
                                              EventNameType_HTMLBodyOrFramesetOnly);
309
0
}
310
311
312
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
313
// nsGenericHTMLElement::GetOnError returns
314
// already_AddRefed<EventHandlerNonNull> while other getters return
315
// EventHandlerNonNull*, so allow passing in the type to use here.
316
#define WINDOW_EVENT_HELPER(name_, type_)                                      \
317
  type_*                                                                       \
318
  HTMLFrameSetElement::GetOn##name_()                                          \
319
0
  {                                                                            \
320
0
    if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {              \
321
0
      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);         \
322
0
      return globalWin->GetOn##name_();                                        \
323
0
    }                                                                          \
324
0
    return nullptr;                                                            \
325
0
  }                                                                            \
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnafterprint()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnbeforeprint()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnbeforeunload()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnhashchange()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnlanguagechange()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnmessage()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnmessageerror()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnoffline()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnonline()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnpagehide()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnpageshow()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnpopstate()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnstorage()
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::GetOnunload()
326
  void                                                                         \
327
  HTMLFrameSetElement::SetOn##name_(type_* handler)                            \
328
0
  {                                                                            \
329
0
    nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();                    \
330
0
    if (!win) {                                                                \
331
0
      return;                                                                  \
332
0
    }                                                                          \
333
0
                                                                               \
334
0
    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);           \
335
0
    return globalWin->SetOn##name_(handler);                                   \
336
0
  }
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnafterprint(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnbeforeprint(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnbeforeunload(mozilla::dom::OnBeforeUnloadEventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnhashchange(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnlanguagechange(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnmessage(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnmessageerror(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnoffline(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnonline(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnpagehide(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnpageshow(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnpopstate(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnstorage(mozilla::dom::EventHandlerNonNull*)
Unexecuted instantiation: mozilla::dom::HTMLFrameSetElement::SetOnunload(mozilla::dom::EventHandlerNonNull*)
337
#define WINDOW_EVENT(name_, id_, type_, struct_)                               \
338
  WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
339
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                         \
340
  WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
341
#include "mozilla/EventNameList.h" // IWYU pragma: keep
342
#undef BEFOREUNLOAD_EVENT
343
#undef WINDOW_EVENT
344
#undef WINDOW_EVENT_HELPER
345
#undef EVENT
346
347
} // namespace dom
348
} // namespace mozilla