forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			236 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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
 | ||
| 
 | ||
| using mozilla::dom::IsSpaceCharacter;
 | ||
| using mozilla::dom::WindowFeatures;
 | ||
| 
 | ||
| #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` doesn’t 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);
 | ||
|     }
 | ||
|   }
 | ||
| }
 | 
