123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "HTMLFrameSetElement.h"
- #include "mozilla/dom/HTMLFrameSetElementBinding.h"
- #include "mozilla/dom/EventHandlerBinding.h"
- #include "nsContentUtils.h"
- #include "nsGlobalWindow.h"
- #include "mozilla/UniquePtrExtensions.h"
- #include "nsAttrValueOrString.h"
- NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
- namespace mozilla {
- namespace dom {
- HTMLFrameSetElement::~HTMLFrameSetElement()
- {
- }
- JSObject*
- HTMLFrameSetElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return HTMLFrameSetElementBinding::Wrap(aCx, this, aGivenProto);
- }
- NS_IMPL_ISUPPORTS_INHERITED(HTMLFrameSetElement, nsGenericHTMLElement,
- nsIDOMHTMLFrameSetElement)
- NS_IMPL_ELEMENT_CLONE(HTMLFrameSetElement)
- NS_IMETHODIMP
- HTMLFrameSetElement::SetCols(const nsAString& aCols)
- {
- ErrorResult rv;
- SetCols(aCols, rv);
- return rv.StealNSResult();
- }
- NS_IMETHODIMP
- HTMLFrameSetElement::GetCols(nsAString& aCols)
- {
- DOMString cols;
- GetCols(cols);
- cols.ToString(aCols);
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLFrameSetElement::SetRows(const nsAString& aRows)
- {
- ErrorResult rv;
- SetRows(aRows, rv);
- return rv.StealNSResult();
- }
- NS_IMETHODIMP
- HTMLFrameSetElement::GetRows(nsAString& aRows)
- {
- DOMString rows;
- GetRows(rows);
- rows.ToString(aRows);
- return NS_OK;
- }
- nsresult
- HTMLFrameSetElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValueOrString* aValue,
- bool aNotify)
- {
- /* The main goal here is to see whether the _number_ of rows or
- * columns has changed. If it has, we need to reframe; otherwise
- * we want to reflow.
- * Ideally, the style hint would be changed back to reflow after the reframe
- * has been performed. Unfortunately, however, the reframe will be performed
- * by the call to nsNodeUtils::AttributeChanged, which occurs *after*
- * AfterSetAttr is called, leaving us with no convenient way of changing the
- * value back to reflow afterwards. However, nsNodeUtils::AttributeChanged is
- * effectively the only consumer of this value, so as long as we always set
- * the value correctly here, we should be fine.
- */
- mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
- if (aNamespaceID == kNameSpaceID_None) {
- if (aName == nsGkAtoms::rows) {
- if (aValue) {
- int32_t oldRows = mNumRows;
- ParseRowCol(aValue->String(), mNumRows, &mRowSpecs);
- if (mNumRows != oldRows) {
- mCurrentRowColHint = nsChangeHint_ReconstructFrame;
- }
- }
- } else if (aName == nsGkAtoms::cols) {
- if (aValue) {
- int32_t oldCols = mNumCols;
- ParseRowCol(aValue->String(), mNumCols, &mColSpecs);
- if (mNumCols != oldCols) {
- mCurrentRowColHint = nsChangeHint_ReconstructFrame;
- }
- }
- }
- }
- return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
- }
- nsresult
- HTMLFrameSetElement::GetRowSpec(int32_t *aNumValues,
- const nsFramesetSpec** aSpecs)
- {
- NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
- NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
- *aNumValues = 0;
- *aSpecs = nullptr;
-
- if (!mRowSpecs) {
- const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows);
- if (value && value->Type() == nsAttrValue::eString) {
- nsresult rv = ParseRowCol(value->GetStringValue(), mNumRows,
- &mRowSpecs);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- if (!mRowSpecs) { // we may not have had an attr or had an empty attr
- mRowSpecs = MakeUnique<nsFramesetSpec[]>(1);
- mNumRows = 1;
- mRowSpecs[0].mUnit = eFramesetUnit_Relative;
- mRowSpecs[0].mValue = 1;
- }
- }
- *aSpecs = mRowSpecs.get();
- *aNumValues = mNumRows;
- return NS_OK;
- }
- nsresult
- HTMLFrameSetElement::GetColSpec(int32_t *aNumValues,
- const nsFramesetSpec** aSpecs)
- {
- NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
- NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
- *aNumValues = 0;
- *aSpecs = nullptr;
- if (!mColSpecs) {
- const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols);
- if (value && value->Type() == nsAttrValue::eString) {
- nsresult rv = ParseRowCol(value->GetStringValue(), mNumCols,
- &mColSpecs);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- if (!mColSpecs) { // we may not have had an attr or had an empty attr
- mColSpecs = MakeUnique<nsFramesetSpec[]>(1);
- mNumCols = 1;
- mColSpecs[0].mUnit = eFramesetUnit_Relative;
- mColSpecs[0].mValue = 1;
- }
- }
- *aSpecs = mColSpecs.get();
- *aNumValues = mNumCols;
- return NS_OK;
- }
- bool
- HTMLFrameSetElement::ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult)
- {
- if (aNamespaceID == kNameSpaceID_None) {
- if (aAttribute == nsGkAtoms::bordercolor) {
- return aResult.ParseColor(aValue);
- }
- if (aAttribute == nsGkAtoms::frameborder) {
- return nsGenericHTMLElement::ParseFrameborderValue(aValue, aResult);
- }
- if (aAttribute == nsGkAtoms::border) {
- return aResult.ParseIntWithBounds(aValue, 0, 100);
- }
- }
-
- return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
- aResult);
- }
- nsChangeHint
- HTMLFrameSetElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
- int32_t aModType) const
- {
- nsChangeHint retval =
- nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
- if (aAttribute == nsGkAtoms::rows ||
- aAttribute == nsGkAtoms::cols) {
- retval |= mCurrentRowColHint;
- }
- return retval;
- }
- /**
- * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
- */
- nsresult
- HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
- int32_t& aNumSpecs,
- UniquePtr<nsFramesetSpec[]>* aSpecs)
- {
- if (aValue.IsEmpty()) {
- aNumSpecs = 0;
- *aSpecs = nullptr;
- return NS_OK;
- }
- static const char16_t sAster('*');
- static const char16_t sPercent('%');
- static const char16_t sComma(',');
- nsAutoString spec(aValue);
- // remove whitespace (Bug 33699) and quotation marks (bug 224598)
- // also remove leading/trailing commas (bug 31482)
- spec.StripChars(" \n\r\t\"\'");
- spec.Trim(",");
-
- // Count the commas. Don't count more than X commas (bug 576447).
- static_assert(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30),
- "Too many frameset specs allowed to allocate");
- int32_t commaX = spec.FindChar(sComma);
- int32_t count = 1;
- while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
- count++;
- commaX = spec.FindChar(sComma, commaX + 1);
- }
- auto specs = MakeUniqueFallible<nsFramesetSpec[]>(count);
- if (!specs) {
- *aSpecs = nullptr;
- aNumSpecs = 0;
- return NS_ERROR_OUT_OF_MEMORY;
- }
- // Pre-grab the compat mode; we may need it later in the loop.
- bool isInQuirks = InNavQuirksMode(OwnerDoc());
-
- // Parse each comma separated token
- int32_t start = 0;
- int32_t specLen = spec.Length();
- for (int32_t i = 0; i < count; i++) {
- // Find our comma
- commaX = spec.FindChar(sComma, start);
- NS_ASSERTION(i == count - 1 || commaX != kNotFound,
- "Failed to find comma, somehow");
- int32_t end = (commaX == kNotFound) ? specLen : commaX;
- // Note: If end == start then it means that the token has no
- // data in it other than a terminating comma (or the end of the spec).
- // So default to a fixed width of 0.
- specs[i].mUnit = eFramesetUnit_Fixed;
- specs[i].mValue = 0;
- if (end > start) {
- int32_t numberEnd = end;
- char16_t ch = spec.CharAt(numberEnd - 1);
- if (sAster == ch) {
- specs[i].mUnit = eFramesetUnit_Relative;
- numberEnd--;
- } else if (sPercent == ch) {
- specs[i].mUnit = eFramesetUnit_Percent;
- numberEnd--;
- // check for "*%"
- if (numberEnd > start) {
- ch = spec.CharAt(numberEnd - 1);
- if (sAster == ch) {
- specs[i].mUnit = eFramesetUnit_Relative;
- numberEnd--;
- }
- }
- }
- // Translate value to an integer
- nsAutoString token;
- spec.Mid(token, start, numberEnd - start);
- // Treat * as 1*
- if ((eFramesetUnit_Relative == specs[i].mUnit) &&
- (0 == token.Length())) {
- specs[i].mValue = 1;
- }
- else {
- // Otherwise just convert to integer.
- nsresult err;
- specs[i].mValue = token.ToInteger(&err);
- if (NS_FAILED(err)) {
- specs[i].mValue = 0;
- }
- }
- // Treat 0* as 1* in quirks mode (bug 40383)
- if (isInQuirks) {
- if ((eFramesetUnit_Relative == specs[i].mUnit) &&
- (0 == specs[i].mValue)) {
- specs[i].mValue = 1;
- }
- }
-
- // Catch zero and negative frame sizes for Nav compatibility
- // Nav resized absolute and relative frames to "1" and
- // percent frames to an even percentage of the width
- //
- //if (isInQuirks && (specs[i].mValue <= 0)) {
- // if (eFramesetUnit_Percent == specs[i].mUnit) {
- // specs[i].mValue = 100 / count;
- // } else {
- // specs[i].mValue = 1;
- // }
- //} else {
- // In standards mode, just set negative sizes to zero
- if (specs[i].mValue < 0) {
- specs[i].mValue = 0;
- }
- start = end + 1;
- }
- }
- aNumSpecs = count;
- // Transfer ownership to caller here
- *aSpecs = Move(specs);
- return NS_OK;
- }
- bool
- HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
- {
- return nsContentUtils::IsEventAttributeName(aName,
- EventNameType_HTML |
- EventNameType_HTMLBodyOrFramesetOnly);
- }
- #define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
- // 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_* \
- HTMLFrameSetElement::GetOn##name_() \
- { \
- if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \
- nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \
- return globalWin->GetOn##name_(); \
- } \
- return nullptr; \
- } \
- void \
- HTMLFrameSetElement::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
|