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 #ifndef mozilla_dom_WindowFeatures_h
8 #define mozilla_dom_WindowFeatures_h
9 
10 #include "nsString.h"
11 #include "mozilla/Assertions.h"  // MOZ_ASSERT
12 #include "mozilla/HashTable.h"   // mozilla::HashMap
13 
14 #include "nsStringFwd.h"  // nsCString, nsACString, nsAutoCString, nsLiteralCString
15 #include "nsTStringHasher.h"  // mozilla::DefaultHasher<nsCString>
16 
17 namespace mozilla {
18 namespace dom {
19 
20 // Represents `tokenizedFeatures` in
21 // https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-tokenize
22 // with accessor methods for values.
23 class WindowFeatures {
24  public:
25   WindowFeatures() = default;
26 
27   WindowFeatures(const WindowFeatures& aOther) = delete;
28   WindowFeatures& operator=(const WindowFeatures& aOther) = delete;
29 
30   WindowFeatures(WindowFeatures&& aOther) = delete;
31   WindowFeatures& operator=(WindowFeatures&& aOther) = delete;
32 
33   // Tokenizes `aFeatures` and stores the result map in member field.
34   // This should be called at the begining, only once.
35   //
36   // Returns true if successfully tokenized, false otherwise.
37   bool Tokenize(const nsACString& aFeatures);
38 
39   // Returns true if the `aName` feature is specified.
40   template <size_t N>
Exists(const char (& aName)[N])41   bool Exists(const char (&aName)[N]) const {
42     MOZ_ASSERT(IsLowerCase(aName));
43     nsLiteralCString name(aName);
44     return tokenizedFeatures_.has(name);
45   }
46 
47   // Returns string value of `aName` feature.
48   // The feature must exist.
49   template <size_t N>
Get(const char (& aName)[N])50   const nsCString& Get(const char (&aName)[N]) const {
51     MOZ_ASSERT(IsLowerCase(aName));
52     nsLiteralCString name(aName);
53     auto p = tokenizedFeatures_.lookup(name);
54     MOZ_ASSERT(p.found());
55 
56     return p->value();
57   }
58 
59   // Returns integer value of `aName` feature.
60   // The feature must exist.
61   template <size_t N>
GetInt(const char (& aName)[N])62   int32_t GetInt(const char (&aName)[N]) const {
63     const nsCString& value = Get(aName);
64     return ParseIntegerWithFallback(value);
65   }
66 
67   // Returns bool value of `aName` feature.
68   // The feature must exist.
69   template <size_t N>
GetBool(const char (& aName)[N])70   bool GetBool(const char (&aName)[N]) const {
71     const nsCString& value = Get(aName);
72     return ParseBool(value);
73   }
74 
75   // Returns bool value of `aName` feature.
76   // If the feature doesn't exist, returns `aDefault`.
77   //
78   // If `aPresenceFlag` is provided and the feature exists, it's set to `true`.
79   // (note that the value isn't overwritten if the feature doesn't exist)
80   template <size_t N>
81   bool GetBoolWithDefault(const char (&aName)[N], bool aDefault,
82                           bool* aPresenceFlag = nullptr) const {
83     MOZ_ASSERT(IsLowerCase(aName));
84     nsLiteralCString name(aName);
85     auto p = tokenizedFeatures_.lookup(name);
86     if (p.found()) {
87       if (aPresenceFlag) {
88         *aPresenceFlag = true;
89       }
90       return ParseBool(p->value());
91     }
92     return aDefault;
93   }
94 
95   // Remove the feature from the map.
96   template <size_t N>
Remove(const char (& aName)[N])97   void Remove(const char (&aName)[N]) {
98     MOZ_ASSERT(IsLowerCase(aName));
99     nsLiteralCString name(aName);
100     tokenizedFeatures_.remove(name);
101   }
102 
103   // Returns true if there was no feature specified, or all features are
104   // removed by `Remove`.
105   //
106   // Note that this can be true even if `aFeatures` parameter of `Tokenize`
107   // is not empty, in case it contains no feature with non-empty name.
IsEmpty()108   bool IsEmpty() const { return tokenizedFeatures_.empty(); }
109 
110   // Stringify the map into `aOutput`.
111   // The result can be parsed again with `Tokenize`.
112   void Stringify(nsAutoCString& aOutput);
113 
114  private:
115 #ifdef DEBUG
116   // Returns true if `text` does not contain any character that gets modified by
117   // `ToLowerCase`.
118   static bool IsLowerCase(const char* text);
119 #endif
120 
121   static int32_t ParseIntegerWithFallback(const nsCString& aValue);
122   static bool ParseBool(const nsCString& aValue);
123 
124   // A map from feature name to feature value.
125   // If value is not provided, it's empty string.
126   mozilla::HashMap<nsCString, nsCString> tokenizedFeatures_;
127 };
128 
129 }  // namespace dom
130 }  // namespace mozilla
131 
132 #endif  // #ifndef mozilla_dom_WindowFeatures_h
133