Backed out 3 changesets (bug 1624150, bug 1432749) for wpt failures at open-features-tokenization-top-left.html. CLOSED TREE

Backed out changeset ff061c8d9da9 (bug 1624150)
Backed out changeset 7e96d4acf317 (bug 1432749)
Backed out changeset a95f77732a1c (bug 1432749)
This commit is contained in:
Narcis Beleuzu 2020-04-13 22:51:48 +03:00
parent 4c093d6d9b
commit 1783003a34
18 changed files with 426 additions and 767 deletions

View File

@ -1,233 +0,0 @@
/* -*- 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 "WindowFeatures.h"
#include "nsINode.h" // IsSpaceCharacter
#include "nsContentUtils.h" // nsContentUtils
#include "nsDependentSubstring.h" // Substring
#include "nsReadableUtils.h" // ToLowerCase
#ifdef DEBUG
/* static */
bool WindowFeatures::IsLowerCase(const char* text) {
nsAutoCString before(text);
nsAutoCString after;
ToLowerCase(before, after);
return before == after;
}
#endif
static bool IsFeatureSeparator(char aChar) {
// https://html.spec.whatwg.org/multipage/window-object.html#feature-separator
// A code point is a feature separator if it is ASCII whitespace, U+003D (=),
// or U+002C (,).
return IsSpaceCharacter(aChar) || aChar == '=' || aChar == ',';
}
template <class IterT, class CondT>
void AdvanceWhile(IterT& aPosition, const IterT& aEnd, CondT aCondition) {
// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
//
// Step 2. While `position` doesnt point past the end of `input` and the
// code point at `position` within `input` meets the condition condition:
while (aCondition(*aPosition) && aPosition < aEnd) {
// Step 2.1. Append that code point to the end of `result`.
// (done by caller)
// Step 2.2. Advance `position` by 1.
++aPosition;
}
}
template <class IterT, class CondT>
nsTDependentSubstring<char> CollectSequence(IterT& aPosition, const IterT& aEnd,
CondT aCondition) {
// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
// To collect a sequence of code points meeting a condition `condition` from
// a string `input`, given a position variable `position` tracking the
// position of the calling algorithm within `input`:
// Step 1. Let `result` be the empty string.
auto start = aPosition;
// Step 2.
AdvanceWhile(aPosition, aEnd, aCondition);
// Step 3. Return `result`.
return Substring(start, aPosition);
}
static void NormalizeName(nsAutoCString& aName) {
// https://html.spec.whatwg.org/multipage/window-object.html#normalizing-the-feature-name
if (aName == "screenx") {
aName = "left";
} else if (aName == "screeny") {
aName = "top";
} else if (aName == "innerwidth") {
aName = "width";
} else if (aName == "innerheight") {
aName = "height";
}
}
/* static */
int32_t WindowFeatures::ParseIntegerWithFallback(const nsCString& aValue) {
// https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-parse-boolean
//
// Step 3. Let `parsed` be the result of parsing value as an integer.
nsContentUtils::ParseHTMLIntegerResultFlags parseResult;
int32_t parsed = nsContentUtils::ParseHTMLInteger(aValue, &parseResult);
// Step 4. If `parsed` is an error, then set it to 0.
//
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
//
// eParseHTMLInteger_NonStandard is not tested given:
// * Step 4 allows leading whitespaces
// * Step 6 allows a plus sign
// * Step 8 does not disallow leading zeros
// * Steps 6 and 9 allow `-0`
//
// eParseHTMLInteger_DidNotConsumeAllInput is not tested given:
// * Step 8 collects digits and ignores remaining part
//
if (parseResult & nsContentUtils::eParseHTMLInteger_Error) {
parsed = 0;
}
return parsed;
}
/* static */
bool WindowFeatures::ParseBool(const nsCString& aValue) {
// https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-parse-boolean
// To parse a boolean feature given a string `value`:
// Step 1. If `value` is the empty string, then return true.
if (aValue.IsEmpty()) {
return true;
}
// Step 2. If `value` is a case-sensitive match for "yes", then return true.
if (aValue == "yes") {
return true;
}
// Steps 3-4.
int32_t parsed = ParseIntegerWithFallback(aValue);
// Step 5. Return false if `parsed` is 0, and true otherwise.
return parsed != 0;
}
bool WindowFeatures::Tokenize(const nsACString& aFeatures) {
// https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-tokenize
// To tokenize the `features` argument:
// Step 1. Let `tokenizedFeatures` be a new ordered map.
// (implicit)
// Step 2. Let `position` point at the first code point of features.
auto position = aFeatures.BeginReading();
// Step 3. While `position` is not past the end of `features`:
auto end = aFeatures.EndReading();
while (position < end) {
// Step 3.1. Let `name` be the empty string.
// (implicit)
// Step 3.2. Let `value` be the empty string.
nsAutoCString value;
// Step 3.3. Collect a sequence of code points that are feature separators
// from `features` given `position`. This skips past leading separators
// before the name.
//
// NOTE: Do not collect given this value is unused.
AdvanceWhile(position, end, IsFeatureSeparator);
// Step 3.4. Collect a sequence of code points that are not feature
// separators from `features` given `position`. Set `name` to the collected
// characters, converted to ASCII lowercase.
nsAutoCString name(CollectSequence(
position, end, [](char c) { return !IsFeatureSeparator(c); }));
ToLowerCase(name);
// Step 3.5. Set `name` to the result of normalizing the feature name
// `name`.
NormalizeName(name);
// Step 3.6. While `position` is not past the end of `features` and the
// code point at `position` in features is not U+003D (=):
//
// Step 3.6.1. If the code point at `position` in features is U+002C (,),
// or if it is not a feature separator, then break.
//
// Step 3.6.2. Advance `position` by 1.
//
// NOTE: This skips to the first U+003D (=) but does not skip past a U+002C
// (,) or a non-separator.
//
// The above means skip all whitespaces.
AdvanceWhile(position, end, [](char c) { return IsSpaceCharacter(c); });
// Step 3.7. If the code point at `position` in `features` is a feature
// separator:
if (position < end && IsFeatureSeparator(*position)) {
// Step 3.7.1. While `position` is not past the end of `features` and the
// code point at `position` in `features` is a feature separator:
//
// Step 3.7.1.1. If the code point at `position` in `features` is
// U+002C (,), then break.
//
// Step 3.7.1.2. Advance `position` by 1.
//
// NOTE: This skips to the first non-separator but does not skip past a
// U+002C (,).
AdvanceWhile(position, end,
[](char c) { return IsFeatureSeparator(c) && c != ','; });
// Step 3.7.2. Collect a sequence of code points that are not feature
// separators code points from `features` given `position`. Set `value` to
// the collected code points, converted to ASCII lowercase.
value = CollectSequence(position, end,
[](char c) { return !IsFeatureSeparator(c); });
ToLowerCase(value);
}
// Step 3.8. If `name` is not the empty string, then set
// `tokenizedFeatures[name]` to `value`.
if (!name.IsEmpty()) {
if (!tokenizedFeatures_.put(name, value)) {
return false;
}
}
}
// Step 4. Return `tokenizedFeatures`.
return true;
}
void WindowFeatures::Stringify(nsAutoCString& aOutput) {
MOZ_ASSERT(aOutput.IsEmpty());
for (auto r = tokenizedFeatures_.all(); !r.empty(); r.popFront()) {
if (!aOutput.IsEmpty()) {
aOutput.Append(',');
}
const nsCString& name = r.front().key();
const nsCString& value = r.front().value();
aOutput.Append(name);
if (!value.IsEmpty()) {
aOutput.Append('=');
aOutput.Append(value);
}
}
}

View File

@ -1,131 +0,0 @@
/* -*- 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/. */
#ifndef mozilla_dom_WindowFeatures_h
#define mozilla_dom_WindowFeatures_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/HashTable.h" // mozilla::HashMap
#include "nsStringFwd.h" // nsCString, nsACString, nsAutoCString, nsLiteralCString
#include "nsTStringHasher.h" // mozilla::DefaultHasher<nsCString>
namespace mozilla {
namespace dom {
// Represents `tokenizedFeatures` in
// https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-tokenize
// with accessor methods for values.
class WindowFeatures {
public:
WindowFeatures() = default;
WindowFeatures(const WindowFeatures& aOther) = delete;
WindowFeatures& operator=(const WindowFeatures& aOther) = delete;
WindowFeatures(WindowFeatures&& aOther) = delete;
WindowFeatures& operator=(WindowFeatures&& aOther) = delete;
// Tokenizes `aFeatures` and stores the result map in member field.
// This should be called at the begining, only once.
//
// Returns true if successfully tokenized, false otherwise.
bool Tokenize(const nsACString& aFeatures);
// Returns true if the `aName` feature is specified.
template <size_t N>
bool Exists(const char (&aName)[N]) const {
MOZ_ASSERT(IsLowerCase(aName));
nsLiteralCString name(aName);
return tokenizedFeatures_.has(name);
}
// Returns string value of `aName` feature.
// The feature must exist.
template <size_t N>
const nsCString& Get(const char (&aName)[N]) const {
MOZ_ASSERT(IsLowerCase(aName));
nsLiteralCString name(aName);
auto p = tokenizedFeatures_.lookup(name);
MOZ_ASSERT(p.found());
return p->value();
}
// Returns integer value of `aName` feature.
// The feature must exist.
template <size_t N>
int32_t GetInt(const char (&aName)[N]) const {
const nsCString& value = Get(aName);
return ParseIntegerWithFallback(value);
}
// Returns bool value of `aName` feature.
// The feature must exist.
template <size_t N>
bool GetBool(const char (&aName)[N]) const {
const nsCString& value = Get(aName);
return ParseBool(value);
}
// Returns bool value of `aName` feature.
// If the feature doesn't exist, returns `aDefault`.
//
// If `aPresenceFlag` is provided and the feature exists, it's set to `true`.
// (note that the value isn't overwritten if the feature doesn't exist)
template <size_t N>
bool GetBoolWithDefault(const char (&aName)[N], bool aDefault,
bool* aPresenceFlag = nullptr) const {
MOZ_ASSERT(IsLowerCase(aName));
nsLiteralCString name(aName);
auto p = tokenizedFeatures_.lookup(name);
if (p.found()) {
if (aPresenceFlag) {
*aPresenceFlag = true;
}
return ParseBool(p->value());
}
return aDefault;
}
// Remove the feature from the map.
template <size_t N>
void Remove(const char (&aName)[N]) {
MOZ_ASSERT(IsLowerCase(aName));
nsLiteralCString name(aName);
tokenizedFeatures_.remove(name);
}
// Returns true if there was no feature specified, or all features are
// removed by `Remove`.
//
// Note that this can be true even if `aFeatures` parameter of `Tokenize`
// is not empty, in case it contains no feature with non-empty name.
bool IsEmpty() const { return tokenizedFeatures_.empty(); }
// Stringify the map into `aOutput`.
// The result can be parsed again with `Tokenize`.
void Stringify(nsAutoCString& aOutput);
private:
#ifdef DEBUG
// Returns true if `text` does not contain any character that gets modified by
// `ToLowerCase`.
static bool IsLowerCase(const char* text);
#endif
static int32_t ParseIntegerWithFallback(const nsCString& aValue);
static bool ParseBool(const nsCString& aValue);
// A map from feature name to feature value.
// If value is not provided, it's empty string.
mozilla::HashMap<nsCString, nsCString> tokenizedFeatures_;
};
} // namespace dom
} // namespace mozilla
#endif // #ifndef mozilla_dom_WindowFeatures_h

View File

@ -253,7 +253,6 @@ EXPORTS.mozilla.dom += [
'UserActivation.h',
'ViewportMetaData.h',
'VisualViewport.h',
'WindowFeatures.h',
'WindowOrientationObserver.h',
'WindowProxyHolder.h',
]
@ -426,7 +425,6 @@ UNIFIED_SOURCES += [
'ViewportMetaData.cpp',
'VisualViewport.cpp',
'WindowDestroyedEvent.cpp',
'WindowFeatures.cpp',
'WindowNamedPropertiesHandler.cpp',
'WindowOrientationObserver.cpp',
'XPathGenerator.cpp',

View File

@ -1181,14 +1181,11 @@ nsContentUtils::InternalSerializeAutocompleteAttribute(
}
// Parse an integer according to HTML spec
template <class StringT>
int32_t nsContentUtils::ParseHTMLIntegerImpl(
const StringT& aValue, ParseHTMLIntegerResultFlags* aResult) {
using CharT = typename StringT::char_type;
int32_t nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags* aResult) {
int result = eParseHTMLInteger_NoFlags;
typename StringT::const_iterator iter, end;
nsAString::const_iterator iter, end;
aValue.BeginReading(iter);
aValue.EndReading(end);
@ -1204,11 +1201,11 @@ int32_t nsContentUtils::ParseHTMLIntegerImpl(
}
int sign = 1;
if (*iter == CharT('-')) {
if (*iter == char16_t('-')) {
sign = -1;
result |= eParseHTMLInteger_Negative;
++iter;
} else if (*iter == CharT('+')) {
} else if (*iter == char16_t('+')) {
result |= eParseHTMLInteger_NonStandard;
++iter;
}
@ -1219,7 +1216,7 @@ int32_t nsContentUtils::ParseHTMLIntegerImpl(
// Check for leading zeros first.
uint64_t leadingZeros = 0;
while (iter != end) {
if (*iter != CharT('0')) {
if (*iter != char16_t('0')) {
break;
}
@ -1229,8 +1226,8 @@ int32_t nsContentUtils::ParseHTMLIntegerImpl(
}
while (iter != end) {
if (*iter >= CharT('0') && *iter <= CharT('9')) {
value = (value * 10) + (*iter - CharT('0')) * sign;
if (*iter >= char16_t('0') && *iter <= char16_t('9')) {
value = (value * 10) + (*iter - char16_t('0')) * sign;
++iter;
if (!value.isValid()) {
result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow;
@ -1260,17 +1257,6 @@ int32_t nsContentUtils::ParseHTMLIntegerImpl(
return value.isValid() ? value.value() : 0;
}
// Parse an integer according to HTML spec
int32_t nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags* aResult) {
return ParseHTMLIntegerImpl(aValue, aResult);
}
int32_t nsContentUtils::ParseHTMLInteger(const nsACString& aValue,
ParseHTMLIntegerResultFlags* aResult) {
return ParseHTMLIntegerImpl(aValue, aResult);
}
#define SKIP_WHITESPACE(iter, end_iter, end_res) \
while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
++(iter); \

View File

@ -614,12 +614,7 @@ class nsContentUtils {
enum ParseHTMLIntegerResultFlags {
eParseHTMLInteger_NoFlags = 0,
// eParseHTMLInteger_NonStandard is set if the string representation of the
// integer was not the canonical one, but matches at least one of the
// following:
// * had leading whitespaces
// * had '+' sign
// * had leading '0'
// * was '-0'
// integer was not the canonical one (e.g. had extra leading '+' or '0').
eParseHTMLInteger_NonStandard = 1 << 0,
eParseHTMLInteger_DidNotConsumeAllInput = 1 << 1,
// Set if one or more error flags were set.
@ -631,15 +626,7 @@ class nsContentUtils {
};
static int32_t ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags* aResult);
static int32_t ParseHTMLInteger(const nsACString& aValue,
ParseHTMLIntegerResultFlags* aResult);
private:
template <class StringT>
static int32_t ParseHTMLIntegerImpl(const StringT& aValue,
ParseHTMLIntegerResultFlags* aResult);
public:
/**
* Parse a margin string of format 'top, right, bottom, left' into
* an nsIntMargin.

View File

@ -41,7 +41,6 @@
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowFeatures.h" // WindowFeatures
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/IntegerPrintfMacros.h"
#if defined(MOZ_WIDGET_ANDROID)
@ -77,6 +76,7 @@
#include "jsfriendapi.h"
#include "js/PropertySpec.h"
#include "js/Wrapper.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsReadableUtils.h"
#include "nsJSEnvironment.h"
#include "mozilla/dom/ScriptSettings.h"
@ -7019,31 +7019,33 @@ nsresult nsGlobalWindowOuter::OpenInternal(
NS_ASSERTION(mDocShell, "Must have docshell here");
NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
WindowFeatures features;
if (!features.Tokenize(optionsUtf8)) {
return NS_ERROR_FAILURE;
}
nsAutoCString options;
bool forceNoOpener = aForceNoOpener;
if (features.Exists("noopener")) {
forceNoOpener = features.GetBool("noopener");
features.Remove("noopener");
}
bool forceNoReferrer = false;
if (features.Exists("noreferrer")) {
forceNoReferrer = features.GetBool("noreferrer");
if (forceNoReferrer) {
// Unlike other window flags, "noopener" comes from splitting on commas with
// HTML whitespace trimming...
nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
aOptions, ',');
while (tok.hasMoreTokens()) {
auto nextTok = tok.nextToken();
if (nextTok.EqualsLiteral("noopener")) {
forceNoOpener = true;
continue;
}
if (StaticPrefs::dom_window_open_noreferrer_enabled() &&
nextTok.LowerCaseEqualsLiteral("noreferrer")) {
forceNoReferrer = true;
// noreferrer implies noopener
forceNoOpener = true;
continue;
}
features.Remove("noreferrer");
// Want to create a copy of the options without 'noopener' because having
// 'noopener' in the options affects other window features.
if (!options.IsEmpty()) {
options.Append(',');
}
AppendUTF16toUTF8(nextTok, options);
}
nsAutoCString options;
features.Stringify(options);
// If current's top-level browsing context's active document's
// cross-origin-opener-policy is "same-origin" or "same-origin + COEP" then

View File

@ -11,7 +11,6 @@
#include "nsClassHashtable.h"
#include "nsComponentManagerUtils.h"
#include "nsTArray.h"
#include "nsTStringHasher.h" // mozilla::DefaultHasher<nsCString>
#include "nsZipArchive.h"
#include "nsITimer.h"
#include "nsIMemoryReporter.h"
@ -122,6 +121,19 @@ struct StartupCacheEntry {
};
};
struct nsCStringHasher {
using Key = nsCString;
using Lookup = nsCString;
static HashNumber hash(const Lookup& aLookup) {
return HashString(aLookup.get());
}
static bool match(const Key& aKey, const Lookup& aLookup) {
return aKey.Equals(aLookup);
}
};
// We don't want to refcount StartupCache, and ObserverService wants to
// refcount its listeners, so we'll let it refcount this instead.
class StartupCacheListener final : public nsIObserver {
@ -206,7 +218,7 @@ class StartupCache : public nsIMemoryReporter {
static void ThreadedWrite(void* aClosure);
static void ThreadedPrefetch(void* aClosure);
HashMap<nsCString, StartupCacheEntry> mTable;
HashMap<nsCString, StartupCacheEntry, nsCStringHasher> mTable;
// owns references to the contents of tables which have been invalidated.
// In theory grows forever if the cache is continually filled and then
// invalidated, but this should not happen in practice.

View File

@ -3,14 +3,10 @@
if webrender and not debug: bug 1425588
if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview)
["innerwidth==401" should set width of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
["innerheight==402" should set height of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
["INNERHEIGHT=402" should set height of opened window]
expected:

View File

@ -1,2 +1,20 @@
[open-features-tokenization-noopener.html]
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1364696
[tokenization should skip window features separators before `name`]
expected: FAIL
[feature `name` should be converted to ASCII lowercase]
expected: FAIL
[after `name`, tokenization should skip window features separators that are not "=" or ","]
expected: FAIL
[Tokenizing should ignore window feature separators except "," after initial "=" and before value]
expected: FAIL
[Tokenizing should read characters until first window feature separator as `value`]
expected: FAIL
["noopener" should be based on name (key), not value]
expected: FAIL

View File

@ -1,3 +1,22 @@
[open-features-tokenization-noreferrer.html]
expected:
if webrender and (os == "linux"): ["OK", "TIMEOUT", "CRASH"]
[Tokenizing "noreferrer" should ignore window feature separators except "," after initial "=" and before value]
expected: FAIL
[Tokenizing "noreferrer" should read characters until first window feature separator as `value`]
expected: FAIL
[After "noreferrer", tokenization should skip window features separators that are not "=" or ","]
expected: FAIL
[Integer values other than 0 should activate the feature]
expected: FAIL
[Tokenization of "noreferrer" should skip window features separators before feature]
expected: FAIL
[Feature "noreferrer" should be converted to ASCII lowercase]
expected: FAIL

View File

@ -2,5 +2,69 @@
disabled:
if webrender and not debug: bug 1425588
if verify and (os == "linux") and not debug: fails in verify mode
if os == "android": frequently hits timeout
["screenx==141" should set left position of opened window]
expected: FAIL
["screeny==142" should set top position of opened window]
expected: FAIL
["screenx=141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["screeny=142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["\\nscreenx= 141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
[" screeny = 142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["screenX=141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
[",screenx=141,," should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
[",screeny=142,," should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["screenY=142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
[" screenx = 141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["SCREENX=141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["SCREENY=142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
["\\nscreeny= 142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL

View File

@ -3,19 +3,13 @@
if webrender and not debug: bug 1425588
if verify and (os == "linux") and not debug: fails in verify mode
["left==141" should set left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
["top==142" should set top position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
["top=152==left=152" should set top and left position of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
[",left=141,," should set left position of opened window]
expected:

View File

@ -3,27 +3,16 @@
if webrender and not debug: bug 1425588
if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview)
["width==401" should set width of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
expected: FAIL
["height==402" should set height of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
if devedition and os == "win" and bits == 32: FAIL # bug 1540551
expected: FAIL
["height==402 width = 401" should set height and width of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
if devedition and os == "win" and bits == 32: FAIL # bug 1540551
expected: FAIL
[",height=402,,width==401" should set height and width of opened window]
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: FAIL
if devedition and os == "win" and bits == 32: FAIL # bug 1540551
expected: FAIL
["\\nheight= 402" should set height of opened window]
expected:

View File

@ -14949,16 +14949,6 @@
"bug_numbers": [1597956, 1614905],
"description": "milliseconds to complete a TLS session resumption with external cache"
},
"WINDOW_OPEN_OUTER_SIZE": {
"record_in_processes": ["main", "content"],
"products": ["firefox"],
"alert_emails": ["tfujisawa.birchill@mozilla.com"],
"expires_in_version": "80",
"kind": "boolean",
"bug_numbers": [1624150],
"releaseChannelCollection": "opt-out",
"description": "Flag indicating consumer of non-standard outerWidth/outerHeight features in window.open"
},
"WINDOW_REMOTE_SUBFRAMES_ENABLED_STATUS": {
"record_in_processes": ["main"],
"products": ["firefox"],

View File

@ -63,7 +63,6 @@
#include "mozilla/ResultExtensions.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_full_screen_api.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/ScriptSettings.h"
@ -318,7 +317,9 @@ struct SizeSpec {
mOuterHeightSpecified(false),
mInnerWidthSpecified(false),
mInnerHeightSpecified(false),
mLockAspectRatio(false) {}
mLockAspectRatio(false),
mUseDefaultWidth(false),
mUseDefaultHeight(false) {}
int32_t mLeft;
int32_t mTop;
@ -335,6 +336,11 @@ struct SizeSpec {
bool mInnerHeightSpecified;
bool mLockAspectRatio;
// If these booleans are true, don't look at the corresponding width values
// even if they're specified -- they'll be bogus
bool mUseDefaultWidth;
bool mUseDefaultHeight;
bool PositionSpecified() const { return mLeftSpecified || mTopSpecified; }
bool SizeSpecified() const { return WidthSpecified() || HeightSpecified(); }
@ -405,7 +411,8 @@ static bool CheckUserContextCompatibility(nsIDocShell* aDocShell) {
return subjectPrincipal->GetUserContextId() == userContextId;
}
nsresult nsWindowWatcher::CreateChromeWindow(nsIWebBrowserChrome* aParentChrome,
nsresult nsWindowWatcher::CreateChromeWindow(const nsACString& aFeatures,
nsIWebBrowserChrome* aParentChrome,
uint32_t aChromeFlags,
nsIOpenWindowInfo* aOpenWindowInfo,
nsIWebBrowserChrome** aResult) {
@ -437,18 +444,21 @@ nsresult nsWindowWatcher::CreateChromeWindow(nsIWebBrowserChrome* aParentChrome,
* the size.
*
* @param aFeatures
* The features that was used to open the window.
* The features string that was used to open the window.
* @param aTreeOwner
* The nsIDocShellTreeOwner of the newly opened window. If null,
* this function is a no-op.
*/
void nsWindowWatcher::MaybeDisablePersistence(
const SizeSpec& sizeSpec, nsIDocShellTreeOwner* aTreeOwner) {
const nsACString& aFeatures, nsIDocShellTreeOwner* aTreeOwner) {
if (!aTreeOwner) {
return;
}
if (sizeSpec.SizeSpecified()) {
// At the moment, the strings "height=" or "width=" never happen
// outside a size specification, so we can do this the Q&D way.
if (PL_strcasestr(aFeatures.BeginReading(), "width=") ||
PL_strcasestr(aFeatures.BeginReading(), "height=")) {
aTreeOwner->SetPersistence(false, false, false);
}
}
@ -513,13 +523,10 @@ nsWindowWatcher::OpenWindowWithRemoteTab(nsIRemoteTab* aRemoteTab,
return NS_ERROR_UNEXPECTED;
}
WindowFeatures features;
features.Tokenize(aFeatures);
SizeSpec sizeSpec;
CalcSizeSpec(features, sizeSpec);
CalcSizeSpec(aFeatures, sizeSpec);
uint32_t chromeFlags = CalculateChromeFlagsForChild(features, sizeSpec);
uint32_t chromeFlags = CalculateChromeFlagsForChild(aFeatures, sizeSpec);
if (isPrivateBrowsingWindow) {
chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
@ -536,7 +543,7 @@ nsWindowWatcher::OpenWindowWithRemoteTab(nsIRemoteTab* aRemoteTab,
nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
CreateChromeWindow(parentChrome, chromeFlags, aOpenWindowInfo,
CreateChromeWindow(aFeatures, parentChrome, chromeFlags, aOpenWindowInfo,
getter_AddRefs(newWindowChrome));
if (NS_WARN_IF(!newWindowChrome)) {
@ -567,7 +574,7 @@ nsWindowWatcher::OpenWindowWithRemoteTab(nsIRemoteTab* aRemoteTab,
// that will also run with out-of-process tabs.
MOZ_ASSERT(chromeContext->UseRemoteTabs());
MaybeDisablePersistence(sizeSpec, chromeTreeOwner);
MaybeDisablePersistence(aFeatures, chromeTreeOwner);
SizeOpenedWindow(chromeTreeOwner, parentWindowOuter, false, sizeSpec,
Some(aOpenerFullZoom));
@ -599,6 +606,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
uint32_t chromeFlags;
nsAutoString name; // string version of aName
nsAutoCString features; // string version of aFeatures
nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
nsCOMPtr<nsIDocShellTreeOwner>
parentTreeOwner; // from the parent window, if any
@ -636,13 +644,11 @@ nsresult nsWindowWatcher::OpenWindowInternal(
name.SetIsVoid(true);
}
WindowFeatures features;
nsAutoCString featuresStr;
if (aFeatures) {
featuresStr.Assign(aFeatures);
features.Tokenize(featuresStr);
features.Assign(aFeatures);
features.StripWhitespace();
} else {
featuresStr.SetIsVoid(true);
features.SetIsVoid(true);
}
RefPtr<BrowsingContext> parentBC(
@ -685,13 +691,6 @@ nsresult nsWindowWatcher::OpenWindowInternal(
bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
if (!hasChromeParent) {
bool outerSizeUsed =
features.Exists("outerwidth") || features.Exists("outerheight");
mozilla::Telemetry::Accumulate(mozilla::Telemetry::WINDOW_OPEN_OUTER_SIZE,
outerSizeUsed);
}
SizeSpec sizeSpec;
CalcSizeSpec(features, sizeSpec);
@ -840,8 +839,8 @@ nsresult nsWindowWatcher::OpenWindowInternal(
if (provider) {
rv = provider->ProvideWindow(openWindowInfo, chromeFlags, aCalledFromJS,
sizeSpec.WidthSpecified(), uriToLoad, name,
featuresStr, aForceNoOpener,
aForceNoReferrer, aLoadState, &windowIsNew,
features, aForceNoOpener, aForceNoReferrer,
aLoadState, &windowIsNew,
getter_AddRefs(newBC));
if (NS_SUCCEEDED(rv) && newBC) {
@ -937,8 +936,9 @@ nsresult nsWindowWatcher::OpenWindowInternal(
completely honest: we clear that indicator if the opener is chrome, so
that the downstream consumer can treat the indicator to mean simply
that the new window is subject to popup control. */
rv = CreateChromeWindow(parentChrome, chromeFlags, openWindowInfo,
getter_AddRefs(newChrome));
rv = CreateChromeWindow(features, parentChrome, chromeFlags,
openWindowInfo, getter_AddRefs(newChrome));
if (parentTopInnerWindow) {
parentTopInnerWindow->Resume();
}
@ -1031,7 +1031,7 @@ nsresult nsWindowWatcher::OpenWindowInternal(
if (isNewToplevelWindow) {
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
newDocShell->GetTreeOwner(getter_AddRefs(newTreeOwner));
MaybeDisablePersistence(sizeSpec, newTreeOwner);
MaybeDisablePersistence(features, newTreeOwner);
}
if (aDialog && aArgv) {
@ -1649,43 +1649,41 @@ nsresult nsWindowWatcher::URIfromURL(const char* aURL,
return NS_NewURI(aURI, aURL, baseURI);
}
#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag) \
chromeFlags |= \
WinHasOption(aFeatures, (feature), 0, &presenceFlag) ? (flag) : 0;
// static
uint32_t nsWindowWatcher::CalculateChromeFlagsHelper(
uint32_t aInitialFlags, const WindowFeatures& aFeatures,
const SizeSpec& aSizeSpec, bool* presenceFlag, bool aHasChromeParent) {
uint32_t aInitialFlags, const nsACString& aFeatures,
const SizeSpec& aSizeSpec, bool& presenceFlag, bool aHasChromeParent) {
uint32_t chromeFlags = aInitialFlags;
if (aFeatures.GetBoolWithDefault("titlebar", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
}
if (aFeatures.GetBoolWithDefault("close", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
}
if (aFeatures.GetBoolWithDefault("toolbar", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_TOOLBAR;
}
if (aFeatures.GetBoolWithDefault("location", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_LOCATIONBAR;
}
if (aFeatures.GetBoolWithDefault("personalbar", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR;
}
if (aFeatures.GetBoolWithDefault("status", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_STATUSBAR;
}
if (aFeatures.GetBoolWithDefault("menubar", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_MENUBAR;
}
if (aFeatures.GetBoolWithDefault("resizable", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RESIZE;
}
if (aFeatures.GetBoolWithDefault("minimizable", false, presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_MIN;
}
// NS_CALCULATE_CHROME_FLAG_FOR requires aFeatures, presenceFlag, and
// chromeFlags to be in scope.
if (aFeatures.GetBoolWithDefault("scrollbars", true, presenceFlag)) {
NS_CALCULATE_CHROME_FLAG_FOR("titlebar",
nsIWebBrowserChrome::CHROME_TITLEBAR);
NS_CALCULATE_CHROME_FLAG_FOR("close",
nsIWebBrowserChrome::CHROME_WINDOW_CLOSE);
NS_CALCULATE_CHROME_FLAG_FOR("toolbar", nsIWebBrowserChrome::CHROME_TOOLBAR);
NS_CALCULATE_CHROME_FLAG_FOR("location",
nsIWebBrowserChrome::CHROME_LOCATIONBAR);
NS_CALCULATE_CHROME_FLAG_FOR("personalbar",
nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
NS_CALCULATE_CHROME_FLAG_FOR("status", nsIWebBrowserChrome::CHROME_STATUSBAR);
NS_CALCULATE_CHROME_FLAG_FOR("menubar", nsIWebBrowserChrome::CHROME_MENUBAR);
NS_CALCULATE_CHROME_FLAG_FOR("resizable",
nsIWebBrowserChrome::CHROME_WINDOW_RESIZE);
NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
nsIWebBrowserChrome::CHROME_WINDOW_MIN);
// default scrollbar to "on," unless explicitly turned off
bool scrollbarsPresent = false;
if (WinHasOption(aFeatures, "scrollbars", 1, &scrollbarsPresent) ||
!scrollbarsPresent) {
chromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
}
presenceFlag = presenceFlag || scrollbarsPresent;
if (aHasChromeParent) {
return chromeFlags;
@ -1741,32 +1739,37 @@ uint32_t nsWindowWatcher::EnsureFlagsSafeForContent(uint32_t aChromeFlags,
}
// static
bool nsWindowWatcher::ShouldOpenPopup(const WindowFeatures& aFeatures,
bool nsWindowWatcher::ShouldOpenPopup(const nsACString& aFeatures,
const SizeSpec& aSizeSpec) {
if (aFeatures.IsEmpty()) {
if (aFeatures.IsVoid()) {
return false;
}
// Follow Google Chrome's behavior that opens a popup depending on
// the following features.
if (!aFeatures.GetBoolWithDefault("location", false) &&
!aFeatures.GetBoolWithDefault("toolbar", false)) {
bool unused;
if (!WinHasOption(aFeatures, "location", 0, &unused) &&
!WinHasOption(aFeatures, "toolbar", 0, &unused)) {
return true;
}
if (!aFeatures.GetBoolWithDefault("menubar", false)) {
if (!WinHasOption(aFeatures, "menubar", 0, &unused)) {
return true;
}
if (!aFeatures.GetBoolWithDefault("resizable", true)) {
// `resizable` defaults to true.
// Should open popup only when explicitly specified to 0.
bool resizablePresent = false;
if (!WinHasOption(aFeatures, "resizable", 0, &resizablePresent) &&
resizablePresent) {
return true;
}
if (!aFeatures.GetBoolWithDefault("scrollbars", false)) {
if (!WinHasOption(aFeatures, "scrollbars", 0, &unused)) {
return true;
}
if (!aFeatures.GetBoolWithDefault("status", false)) {
if (!WinHasOption(aFeatures, "status", 0, &unused)) {
return true;
}
@ -1788,13 +1791,15 @@ bool nsWindowWatcher::ShouldOpenPopup(const WindowFeatures& aFeatures,
*/
// static
uint32_t nsWindowWatcher::CalculateChromeFlagsForChild(
const WindowFeatures& aFeatures, const SizeSpec& aSizeSpec) {
if (aFeatures.IsEmpty()) {
const nsACString& aFeatures, const SizeSpec& aSizeSpec) {
if (aFeatures.IsVoid()) {
return nsIWebBrowserChrome::CHROME_ALL;
}
uint32_t chromeFlags = CalculateChromeFlagsHelper(
nsIWebBrowserChrome::CHROME_WINDOW_BORDERS, aFeatures, aSizeSpec);
bool presenceFlag = false;
uint32_t chromeFlags =
CalculateChromeFlagsHelper(nsIWebBrowserChrome::CHROME_WINDOW_BORDERS,
aFeatures, aSizeSpec, presenceFlag);
return EnsureFlagsSafeForContent(chromeFlags);
}
@ -1812,7 +1817,7 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForChild(
*/
// static
uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
mozIDOMWindowProxy* aParent, const WindowFeatures& aFeatures,
mozIDOMWindowProxy* aParent, const nsACString& aFeatures,
const SizeSpec& aSizeSpec, bool aDialog, bool aChromeURL,
bool aHasChromeParent, bool aCalledFromJS) {
MOZ_ASSERT(XRE_IsParentProcess());
@ -1822,7 +1827,7 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
// The features string is made void by OpenWindowInternal
// if nullptr was originally passed as the features string.
if (aFeatures.IsEmpty()) {
if (aFeatures.IsVoid()) {
chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
if (aDialog) {
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
@ -1841,29 +1846,29 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
in the standards-compliant window.(normal)open. */
bool presenceFlag = false;
if (aDialog && aFeatures.GetBoolWithDefault("all", false, &presenceFlag)) {
if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) {
chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
}
/* Next, allow explicitly named options to override the initial settings */
chromeFlags = CalculateChromeFlagsHelper(chromeFlags, aFeatures, aSizeSpec,
&presenceFlag, aHasChromeParent);
presenceFlag, aHasChromeParent);
// Determine whether the window is a private browsing window
if (aFeatures.GetBoolWithDefault("private", false, &presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
}
if (aFeatures.GetBoolWithDefault("non-private", false, &presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW;
}
chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag)
? nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
: 0;
chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag)
? nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW
: 0;
// Determine whether the window should have remote tabs.
bool remote = BrowserTabsRemoteAutostart();
if (remote) {
remote = !aFeatures.GetBoolWithDefault("non-remote", false, &presenceFlag);
remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
} else {
remote = aFeatures.GetBoolWithDefault("remote", false, &presenceFlag);
remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
}
if (remote) {
@ -1874,19 +1879,18 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
bool fission = StaticPrefs::fission_autostart();
if (fission) {
fission =
!aFeatures.GetBoolWithDefault("non-fission", false, &presenceFlag);
fission = !WinHasOption(aFeatures, "non-fission", 0, &presenceFlag);
} else {
fission = aFeatures.GetBoolWithDefault("fission", false, &presenceFlag);
fission = WinHasOption(aFeatures, "fission", 0, &presenceFlag);
}
if (fission) {
chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
}
if (aFeatures.GetBoolWithDefault("popup", false, &presenceFlag)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
}
chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag)
? nsIWebBrowserChrome::CHROME_WINDOW_POPUP
: 0;
/* OK.
Normal browser windows, in spite of a stated pattern of turning off
@ -1897,15 +1901,15 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
// default titlebar and closebox to "on," if not mentioned at all
if (!(chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)) {
if (!aFeatures.Exists("titlebar")) {
if (!PL_strcasestr(aFeatures.BeginReading(), "titlebar")) {
chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
}
if (!aFeatures.Exists("close")) {
if (!PL_strcasestr(aFeatures.BeginReading(), "close")) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
}
}
if (aDialog && !aFeatures.IsEmpty() && !presenceFlag) {
if (aDialog && !aFeatures.IsVoid() && !presenceFlag) {
chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
}
@ -1913,35 +1917,35 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
with the features that are more operating hints than appearance
instructions. (Note modality implies dependence.) */
if (aFeatures.GetBoolWithDefault("alwayslowered", false) ||
aFeatures.GetBoolWithDefault("z-lock", false)) {
if (WinHasOption(aFeatures, "alwaysLowered", 0, nullptr) ||
WinHasOption(aFeatures, "z-lock", 0, nullptr)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
} else if (aFeatures.GetBoolWithDefault("alwaysraised", false)) {
} else if (WinHasOption(aFeatures, "alwaysRaised", 0, nullptr)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
}
if (aFeatures.GetBoolWithDefault("suppressanimation", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION;
}
if (aFeatures.GetBoolWithDefault("alwaysontop", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP;
}
if (aFeatures.GetBoolWithDefault("chrome", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
}
if (aFeatures.GetBoolWithDefault("extrachrome", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_EXTRA;
}
if (aFeatures.GetBoolWithDefault("centerscreen", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
}
if (aFeatures.GetBoolWithDefault("dependent", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_DEPENDENT;
}
if (aFeatures.GetBoolWithDefault("modal", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_DEPENDENT;
}
chromeFlags |= WinHasOption(aFeatures, "suppressanimation", 0, nullptr)
? nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION
: 0;
chromeFlags |= WinHasOption(aFeatures, "alwaysontop", 0, nullptr)
? nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP
: 0;
chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nullptr)
? nsIWebBrowserChrome::CHROME_OPENAS_CHROME
: 0;
chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nullptr)
? nsIWebBrowserChrome::CHROME_EXTRA
: 0;
chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nullptr)
? nsIWebBrowserChrome::CHROME_CENTER_SCREEN
: 0;
chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nullptr)
? nsIWebBrowserChrome::CHROME_DEPENDENT
: 0;
chromeFlags |= WinHasOption(aFeatures, "modal", 0, nullptr)
? (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_DEPENDENT)
: 0;
/* On mobile we want to ignore the dialog window feature, since the mobile UI
does not provide any affordance for dialog windows. This does not interfere
@ -1953,18 +1957,18 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
&disableDialogFeature);
if (!disableDialogFeature) {
if (aFeatures.GetBoolWithDefault("dialog", false)) {
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
}
chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nullptr)
? nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
: 0;
}
/* and dialogs need to have the last word. assume dialogs are dialogs,
and opened as chrome, unless explicitly told otherwise. */
if (aDialog) {
if (!aFeatures.Exists("dialog")) {
if (!PL_strcasestr(aFeatures.BeginReading(), "dialog")) {
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
}
if (!aFeatures.Exists("chrome")) {
if (!PL_strcasestr(aFeatures.BeginReading(), "chrome")) {
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
}
}
@ -1988,6 +1992,63 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForParent(
return chromeFlags;
}
// static
int32_t nsWindowWatcher::WinHasOption(const nsACString& aOptions,
const char* aName, int32_t aDefault,
bool* aPresenceFlag) {
if (aOptions.IsEmpty()) {
return 0;
}
const char* options = aOptions.BeginReading();
char* comma;
char* equal;
int32_t found = 0;
#ifdef DEBUG
NS_ASSERTION(nsAutoCString(aOptions).FindCharInSet(" \n\r\t") == kNotFound,
"There should be no whitespace in this string!");
#endif
while (true) {
comma = PL_strchr(options, ',');
if (comma) {
*comma = '\0';
}
equal = PL_strchr(options, '=');
if (equal) {
*equal = '\0';
}
if (nsCRT::strcasecmp(options, aName) == 0) {
if (aPresenceFlag) {
*aPresenceFlag = true;
}
if (equal)
if (*(equal + 1) == '*') {
found = aDefault;
} else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) {
found = 1;
} else {
found = atoi(equal + 1);
}
else {
found = 1;
}
}
if (equal) {
*equal = '=';
}
if (comma) {
*comma = ',';
}
if (found || !comma) {
break;
}
options = comma + 1;
}
return found;
}
already_AddRefed<BrowsingContext> nsWindowWatcher::GetBrowsingContextByName(
const nsAString& aName, bool aForceNoOpener,
BrowsingContext* aCurrentContext) {
@ -2019,148 +2080,70 @@ already_AddRefed<BrowsingContext> nsWindowWatcher::GetBrowsingContextByName(
}
// static
void nsWindowWatcher::CalcSizeSpec(const WindowFeatures& aFeatures,
void nsWindowWatcher::CalcSizeSpec(const nsACString& aFeatures,
SizeSpec& aResult) {
// https://drafts.csswg.org/cssom-view/#set-up-browsing-context-features
// To set up browsing context features for a browsing context `target` given
// a map `tokenizedFeatures`:
// Parse position spec, if any, from aFeatures
bool present;
int32_t temp;
// Step 1. Let `x` be null.
// (implicit)
// Step 2. Let `y` be null.
// (implicit)
// Step 3. Let `width` be null.
// (implicit)
// Step 4. Let `height` be null.
// (implicit)
// Step 5. If `tokenizedFeatures["left"]` exists:
if (aFeatures.Exists("left")) {
// Step 5.1. Set `x` to the result of invoking the rules for parsing
// integers on `tokenizedFeatures["left"]`.
//
// Step 5.2. If `x` is an error, set `x` to 0.
int32_t x = aFeatures.GetInt("left");
// Step 5.3. Optionally, clamp `x` in a user-agent-defined manner so that
// the window does not move outside the Web-exposed available screen area.
// (done later)
// Step 5.4. Optionally, move `target`s window such that the windows
// left edge is at the horizontal coordinate `x` relative to the left edge
// of the Web-exposed screen area, measured in CSS pixels of target.
// The positive axis is rightward.
aResult.mLeft = x;
aResult.mLeftSpecified = true;
present = false;
if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) {
aResult.mLeft = temp;
} else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) ||
present) {
aResult.mLeft = temp;
}
aResult.mLeftSpecified = present;
// Step 6. If `tokenizedFeatures["top"]` exists:
if (aFeatures.Exists("top")) {
// Step 6.1. Set `y` to the result of invoking the rules for parsing
// integers on `tokenizedFeatures["top"]`.
//
// Step 6.2. If `y` is an error, set `y` to 0.
int32_t y = aFeatures.GetInt("top");
// Step 6.3. Optionally, clamp `y` in a user-agent-defined manner so that
// the window does not move outside the Web-exposed available screen area.
// (done later)
// Step 6.4. Optionally, move `target`s window such that the windows top
// edge is at the vertical coordinate `y` relative to the top edge of the
// Web-exposed screen area, measured in CSS pixels of target. The positive
// axis is downward.
aResult.mTop = y;
aResult.mTopSpecified = true;
present = false;
if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present) {
aResult.mTop = temp;
} else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) ||
present) {
aResult.mTop = temp;
}
aResult.mTopSpecified = present;
// Non-standard extension.
// See bug 1623826
if (aFeatures.Exists("outerwidth")) {
int32_t width = aFeatures.GetInt("outerwidth");
if (width) {
aResult.mOuterWidth = width;
// Parse size spec, if any. Chrome size overrides content size.
if ((temp = WinHasOption(aFeatures, "outerWidth", INT32_MIN, nullptr))) {
if (temp == INT32_MIN) {
aResult.mUseDefaultWidth = true;
} else {
aResult.mOuterWidth = temp;
}
aResult.mOuterWidthSpecified = true;
} else if ((temp = WinHasOption(aFeatures, "width", INT32_MIN, nullptr)) ||
(temp =
WinHasOption(aFeatures, "innerWidth", INT32_MIN, nullptr))) {
if (temp == INT32_MIN) {
aResult.mUseDefaultWidth = true;
} else {
aResult.mInnerWidth = temp;
}
}
if (!aResult.mOuterWidthSpecified) {
// Step 7. If `tokenizedFeatures["width"]` exists:
if (aFeatures.Exists("width")) {
// Step 7.1. Set `width` to the result of invoking the rules for parsing
// integers on `tokenizedFeatures["width"]`.
//
// Step 7.2. If `width` is an error, set `width` to 0.
int32_t width = aFeatures.GetInt("width");
// Step 7.3. If `width` is not 0:
if (width) {
// Step 7.3.1. Optionally, clamp `width` in a user-agent-defined manner
// so that the window does not get too small or bigger than the
// Web-exposed available screen area.
// (done later)
// Step 7.3.2. Optionally, size `target`s window by moving its right
// edge such that the distance between the left and right edges of the
// viewport are `width` CSS pixels of target.
aResult.mInnerWidth = width;
aResult.mInnerWidthSpecified = true;
// Step 7.3.3. Optionally, move targets window in a user-agent-defined
// manner so that it does not grow outside the Web-exposed available
// screen area.
// (done later)
}
}
}
// Non-standard extension.
// See bug 1623826
if (aFeatures.Exists("outerheight")) {
int32_t height = aFeatures.GetInt("outerheight");
if (height) {
aResult.mOuterHeight = height;
if ((temp = WinHasOption(aFeatures, "outerHeight", INT32_MIN, nullptr))) {
if (temp == INT32_MIN) {
aResult.mUseDefaultHeight = true;
} else {
aResult.mOuterHeight = temp;
}
aResult.mOuterHeightSpecified = true;
} else if ((temp = WinHasOption(aFeatures, "height", INT32_MIN, nullptr)) ||
(temp =
WinHasOption(aFeatures, "innerHeight", INT32_MIN, nullptr))) {
if (temp == INT32_MIN) {
aResult.mUseDefaultHeight = true;
} else {
aResult.mInnerHeight = temp;
}
}
if (!aResult.mOuterHeightSpecified) {
// Step 8. If `tokenizedFeatures["height"]` exists:
if (aFeatures.Exists("height")) {
// Step 8.1. Set `height` to the result of invoking the rules for parsing
// integers on `tokenizedFeatures["height"]`.
//
// Step 8.2. If `height` is an error, set `height` to 0.
int32_t height = aFeatures.GetInt("height");
// Step 8.3. If `height` is not 0:
if (height) {
// Step 8.3.1. Optionally, clamp `height` in a user-agent-defined manner
// so that the window does not get too small or bigger than the
// Web-exposed available screen area.
// (done later)
// Step 8.3.2. Optionally, size `target`s window by moving its bottom
// edge such that the distance between the top and bottom edges of the
// viewport are `height` CSS pixels of target.
aResult.mInnerHeight = height;
aResult.mInnerHeightSpecified = true;
// Step 8.3.3. Optionally, move targets window in a user-agent-defined
// manner so that it does not grow outside the Web-exposed available
// screen area.
// (done later)
}
}
}
// NOTE: The value is handled only on chrome-priv code.
// See nsWindowWatcher::SizeOpenedWindow.
aResult.mLockAspectRatio =
aFeatures.GetBoolWithDefault("lockaspectratio", false);
if (WinHasOption(aFeatures, "lockaspectratio", 0, nullptr)) {
aResult.mLockAspectRatio = true;
}
}
/* Size and position a new window according to aSizeSpec. This method
@ -2250,19 +2233,31 @@ void nsWindowWatcher::SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
// Set up width
if (aSizeSpec.mOuterWidthSpecified) {
if (!aSizeSpec.mUseDefaultWidth) {
width = NSToIntRound(aSizeSpec.mOuterWidth * openerZoom);
} // Else specified to default; just use our existing width
} else if (aSizeSpec.mInnerWidthSpecified) {
sizeChromeWidth = false;
if (aSizeSpec.mUseDefaultWidth) {
width = width - chromeWidth;
} else {
width = NSToIntRound(aSizeSpec.mInnerWidth * openerZoom);
}
}
// Set up height
if (aSizeSpec.mOuterHeightSpecified) {
if (!aSizeSpec.mUseDefaultHeight) {
height = NSToIntRound(aSizeSpec.mOuterHeight * openerZoom);
} // Else specified to default; just use our existing height
} else if (aSizeSpec.mInnerHeightSpecified) {
sizeChromeHeight = false;
if (aSizeSpec.mUseDefaultHeight) {
height = height - chromeHeight;
} else {
height = NSToIntRound(aSizeSpec.mInnerHeight * openerZoom);
}
}
bool positionSpecified = aSizeSpec.PositionSpecified();

View File

@ -25,7 +25,6 @@
#include "nsIRemoteTab.h"
#include "nsPIWindowWatcher.h"
#include "nsTArray.h"
#include "mozilla/dom/WindowFeatures.h" // mozilla::dom::WindowFeatures
class nsIURI;
class nsIDocShellTreeItem;
@ -87,20 +86,23 @@ class nsWindowWatcher : public nsIWindowWatcher,
static nsresult URIfromURL(const char* aURL, mozIDOMWindowProxy* aParent,
nsIURI** aURI);
static bool ShouldOpenPopup(const mozilla::dom::WindowFeatures& aFeatures,
static bool ShouldOpenPopup(const nsACString& aFeatures,
const SizeSpec& aSizeSpec);
static uint32_t CalculateChromeFlagsForChild(
const mozilla::dom::WindowFeatures& aFeatures, const SizeSpec& aSizeSpec);
static uint32_t CalculateChromeFlagsForChild(const nsACString& aFeaturesStr,
const SizeSpec& aSizeSpec);
static uint32_t CalculateChromeFlagsForParent(
mozIDOMWindowProxy* aParent,
const mozilla::dom::WindowFeatures& aFeatures, const SizeSpec& aSizeSpec,
bool aDialog, bool aChromeURL, bool aHasChromeParent, bool aCalledFromJS);
static uint32_t CalculateChromeFlagsForParent(mozIDOMWindowProxy* aParent,
const nsACString& aFeaturesStr,
const SizeSpec& aSizeSpec,
bool aDialog, bool aChromeURL,
bool aHasChromeParent,
bool aCalledFromJS);
static int32_t WinHasOption(const nsACString& aOptions, const char* aName,
int32_t aDefault, bool* aPresenceFlag);
/* Compute the right SizeSpec based on aFeatures */
static void CalcSizeSpec(const mozilla::dom::WindowFeatures& aFeatures,
SizeSpec& aResult);
static void CalcSizeSpec(const nsACString& aFeatures, SizeSpec& aResult);
static void SizeOpenedWindow(
nsIDocShellTreeOwner* aTreeOwner, mozIDOMWindowProxy* aParent,
bool aIsCallerChrome, const SizeSpec& aSizeSpec,
@ -111,17 +113,19 @@ class nsWindowWatcher : public nsIWindowWatcher,
nsIDocShellTreeOwner** aResult);
private:
nsresult CreateChromeWindow(nsIWebBrowserChrome* aParentChrome,
nsresult CreateChromeWindow(const nsACString& aFeatures,
nsIWebBrowserChrome* aParentChrome,
uint32_t aChromeFlags,
nsIOpenWindowInfo* aOpenWindowInfo,
nsIWebBrowserChrome** aResult);
void MaybeDisablePersistence(const SizeSpec& sizeSpec,
void MaybeDisablePersistence(const nsACString& aFeatures,
nsIDocShellTreeOwner* aTreeOwner);
static uint32_t CalculateChromeFlagsHelper(
uint32_t aInitialFlags, const mozilla::dom::WindowFeatures& aFeatures,
const SizeSpec& aSizeSpec, bool* presenceFlag = nullptr,
static uint32_t CalculateChromeFlagsHelper(uint32_t aInitialFlags,
const nsACString& aFeatures,
const SizeSpec& aSizeSpec,
bool& presenceFlag,
bool aHasChromeParent = false);
static uint32_t EnsureFlagsSafeForContent(uint32_t aChromeFlags,
bool aChromeURL = false);

View File

@ -28,7 +28,6 @@ EXPORTS += [
'nsTLiteralString.h',
'nsTPromiseFlatString.h',
'nsTString.h',
'nsTStringHasher.h',
'nsTStringRepr.h',
'nsTSubstring.h',
'nsTSubstringTuple.h',

View File

@ -1,30 +0,0 @@
/* -*- 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/. */
#ifndef nsTStringHasher_h___
#define nsTStringHasher_h___
#include "mozilla/HashTable.h" // mozilla::{DefaultHasher, HashNumber, HashString}
namespace mozilla {
template <typename T>
struct DefaultHasher<nsTString<T>> {
using Key = nsTString<T>;
using Lookup = nsTString<T>;
static mozilla::HashNumber hash(const Lookup& aLookup) {
return mozilla::HashString(aLookup.get());
}
static bool match(const Key& aKey, const Lookup& aLookup) {
return aKey.Equals(aLookup);
}
};
} // namespace mozilla
#endif // !defined(nsTStringHasher_h___)