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/. */
7 #include "WindowFeatures.h"
9 #include "nsINode.h" // IsSpaceCharacter
10 #include "nsContentUtils.h" // nsContentUtils
11 #include "nsDependentSubstring.h" // Substring
12 #include "nsReadableUtils.h" // ToLowerCase
14 using mozilla::dom::IsSpaceCharacter
;
15 using mozilla::dom::WindowFeatures
;
19 bool WindowFeatures::IsLowerCase(const char* text
) {
20 nsAutoCString
before(text
);
22 ToLowerCase(before
, after
);
23 return before
== after
;
27 static bool IsFeatureSeparator(char aChar
) {
28 // https://html.spec.whatwg.org/multipage/window-object.html#feature-separator
29 // A code point is a feature separator if it is ASCII whitespace, U+003D (=),
31 return IsSpaceCharacter(aChar
) || aChar
== '=' || aChar
== ',';
34 template <class IterT
, class CondT
>
35 void AdvanceWhile(IterT
& aPosition
, const IterT
& aEnd
, CondT aCondition
) {
36 // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
38 // Step 2. While `position` doesn’t point past the end of `input` and the
39 // code point at `position` within `input` meets the condition condition:
40 while (aCondition(*aPosition
) && aPosition
< aEnd
) {
41 // Step 2.1. Append that code point to the end of `result`.
44 // Step 2.2. Advance `position` by 1.
49 template <class IterT
, class CondT
>
50 nsTDependentSubstring
<char> CollectSequence(IterT
& aPosition
, const IterT
& aEnd
,
52 // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
53 // To collect a sequence of code points meeting a condition `condition` from
54 // a string `input`, given a position variable `position` tracking the
55 // position of the calling algorithm within `input`:
57 // Step 1. Let `result` be the empty string.
58 auto start
= aPosition
;
61 AdvanceWhile(aPosition
, aEnd
, aCondition
);
63 // Step 3. Return `result`.
64 return Substring(start
, aPosition
);
67 static void NormalizeName(nsAutoCString
& aName
) {
68 // https://html.spec.whatwg.org/multipage/window-object.html#normalizing-the-feature-name
69 if (aName
== "screenx") {
71 } else if (aName
== "screeny") {
73 } else if (aName
== "innerwidth") {
75 } else if (aName
== "innerheight") {
81 int32_t WindowFeatures::ParseIntegerWithFallback(const nsCString
& aValue
) {
82 // https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-parse-boolean
84 // Step 3. Let `parsed` be the result of parsing value as an integer.
85 nsContentUtils::ParseHTMLIntegerResultFlags parseResult
;
86 int32_t parsed
= nsContentUtils::ParseHTMLInteger(aValue
, &parseResult
);
88 // Step 4. If `parsed` is an error, then set it to 0.
90 // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
92 // eParseHTMLInteger_NonStandard is not tested given:
93 // * Step 4 allows leading whitespaces
94 // * Step 6 allows a plus sign
95 // * Step 8 does not disallow leading zeros
96 // * Steps 6 and 9 allow `-0`
98 // eParseHTMLInteger_DidNotConsumeAllInput is not tested given:
99 // * Step 8 collects digits and ignores remaining part
101 if (parseResult
& nsContentUtils::eParseHTMLInteger_Error
) {
109 bool WindowFeatures::ParseBool(const nsCString
& aValue
) {
110 // https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-parse-boolean
111 // To parse a boolean feature given a string `value`:
113 // Step 1. If `value` is the empty string, then return true.
114 if (aValue
.IsEmpty()) {
118 // Step 2. If `value` is "yes", then return true.
119 if (aValue
== "yes") {
123 // Step 3. If `value` is "true", then return
124 if (aValue
== "true") {
129 int32_t parsed
= ParseIntegerWithFallback(aValue
);
131 // Step 6. Return false if `parsed` is 0, and true otherwise.
135 bool WindowFeatures::Tokenize(const nsACString
& aFeatures
) {
136 // https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-tokenize
137 // To tokenize the `features` argument:
139 // Step 1. Let `tokenizedFeatures` be a new ordered map.
142 // Step 2. Let `position` point at the first code point of features.
143 auto position
= aFeatures
.BeginReading();
145 // Step 3. While `position` is not past the end of `features`:
146 auto end
= aFeatures
.EndReading();
147 while (position
< end
) {
148 // Step 3.1. Let `name` be the empty string.
151 // Step 3.2. Let `value` be the empty string.
154 // Step 3.3. Collect a sequence of code points that are feature separators
155 // from `features` given `position`. This skips past leading separators
158 // NOTE: Do not collect given this value is unused.
159 AdvanceWhile(position
, end
, IsFeatureSeparator
);
161 // Step 3.4. Collect a sequence of code points that are not feature
162 // separators from `features` given `position`. Set `name` to the collected
163 // characters, converted to ASCII lowercase.
164 nsAutoCString
name(CollectSequence(
165 position
, end
, [](char c
) { return !IsFeatureSeparator(c
); }));
168 // Step 3.5. Set `name` to the result of normalizing the feature name
172 // Step 3.6. While `position` is not past the end of `features` and the
173 // code point at `position` in features is not U+003D (=):
175 // Step 3.6.1. If the code point at `position` in features is U+002C (,),
176 // or if it is not a feature separator, then break.
178 // Step 3.6.2. Advance `position` by 1.
180 // NOTE: This skips to the first U+003D (=) but does not skip past a U+002C
181 // (,) or a non-separator.
183 // The above means skip all whitespaces.
184 AdvanceWhile(position
, end
, [](char c
) { return IsSpaceCharacter(c
); });
186 // Step 3.7. If the code point at `position` in `features` is a feature
188 if (position
< end
&& IsFeatureSeparator(*position
)) {
189 // Step 3.7.1. While `position` is not past the end of `features` and the
190 // code point at `position` in `features` is a feature separator:
192 // Step 3.7.1.1. If the code point at `position` in `features` is
193 // U+002C (,), then break.
195 // Step 3.7.1.2. Advance `position` by 1.
197 // NOTE: This skips to the first non-separator but does not skip past a
199 AdvanceWhile(position
, end
,
200 [](char c
) { return IsFeatureSeparator(c
) && c
!= ','; });
202 // Step 3.7.2. Collect a sequence of code points that are not feature
203 // separators code points from `features` given `position`. Set `value` to
204 // the collected code points, converted to ASCII lowercase.
205 value
= CollectSequence(position
, end
,
206 [](char c
) { return !IsFeatureSeparator(c
); });
210 // Step 3.8. If `name` is not the empty string, then set
211 // `tokenizedFeatures[name]` to `value`.
212 if (!name
.IsEmpty()) {
213 if (!tokenizedFeatures_
.put(name
, value
)) {
219 // Step 4. Return `tokenizedFeatures`.
223 void WindowFeatures::Stringify(nsAutoCString
& aOutput
) {
224 MOZ_ASSERT(aOutput
.IsEmpty());
226 for (auto r
= tokenizedFeatures_
.all(); !r
.empty(); r
.popFront()) {
227 if (!aOutput
.IsEmpty()) {
231 const nsCString
& name
= r
.front().key();
232 const nsCString
& value
= r
.front().value();
234 aOutput
.Append(name
);
236 if (!value
.IsEmpty()) {
238 aOutput
.Append(value
);