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 /*
8  * methods for dealing with CSS properties and tables of the keyword
9  * values they accept
10  */
11 
12 #ifndef nsCSSProps_h___
13 #define nsCSSProps_h___
14 
15 #include <limits>
16 #include <ostream>
17 #include <type_traits>
18 
19 #include "nsString.h"
20 #include "nsCSSPropertyID.h"
21 #include "nsStyleStructFwd.h"
22 #include "mozilla/UseCounter.h"
23 #include "mozilla/CSSEnabledState.h"
24 #include "mozilla/CSSPropFlags.h"
25 #include "mozilla/EnumTypeTraits.h"
26 #include "mozilla/Preferences.h"
27 #include "mozilla/gfx/gfxVarReceiver.h"
28 #include "nsXULAppAPI.h"
29 
30 // Length of the "--" prefix on custom names (such as custom property names,
31 // and, in the future, custom media query names).
32 #define CSS_CUSTOM_NAME_PREFIX_LENGTH 2
33 
34 namespace mozilla {
35 class ComputedStyle;
36 }
37 
38 extern "C" {
39 nsCSSPropertyID Servo_ResolveLogicalProperty(nsCSSPropertyID,
40                                              const mozilla::ComputedStyle*);
41 nsCSSPropertyID Servo_Property_LookupEnabledForAllContent(const nsACString*);
42 const uint8_t* Servo_Property_GetName(nsCSSPropertyID, uint32_t* aLength);
43 }
44 
45 class nsCSSProps {
46  public:
47   typedef mozilla::CSSEnabledState EnabledState;
48   typedef mozilla::CSSPropFlags Flags;
49 
50   static void AddRefTable(void);
51   static void ReleaseTable(void);
52 
53   // Looks up the property with name aProperty and returns its corresponding
54   // nsCSSPropertyID value.  If aProperty is the name of a custom property,
55   // then eCSSPropertyExtra_variable will be returned.
56   //
57   // This only returns properties enabled for all content, and resolves aliases
58   // to return the aliased property.
LookupProperty(const nsACString & aProperty)59   static nsCSSPropertyID LookupProperty(const nsACString& aProperty) {
60     return Servo_Property_LookupEnabledForAllContent(&aProperty);
61   }
62 
63   // As above, but looked up using a property's IDL name.
64   // eCSSPropertyExtra_variable won't be returned from this method.
65   static nsCSSPropertyID LookupPropertyByIDLName(
66       const nsACString& aPropertyIDLName, EnabledState aEnabled);
67 
68   // Returns whether aProperty is a custom property name, i.e. begins with
69   // "--".  This assumes that the CSS Variables pref has been enabled.
70   static bool IsCustomPropertyName(const nsACString& aProperty);
71 
IsShorthand(nsCSSPropertyID aProperty)72   static bool IsShorthand(nsCSSPropertyID aProperty) {
73     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
74                "out of range");
75     return (aProperty >= eCSSProperty_COUNT_no_shorthands);
76   }
77 
78   // Same but for @font-face descriptors
79   static nsCSSFontDesc LookupFontDesc(const nsACString& aProperty);
80 
81   // The relevant invariants are asserted in Document.cpp
UseCounterFor(nsCSSPropertyID aProperty)82   static mozilla::UseCounter UseCounterFor(nsCSSPropertyID aProperty) {
83     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
84                "out of range");
85     return mozilla::UseCounter(size_t(mozilla::eUseCounter_FirstCSSProperty) +
86                                size_t(aProperty));
87   }
88 
89   // Given a property enum, get the string value
90   //
91   // This string is static.
GetStringValue(nsCSSPropertyID aProperty)92   static const nsDependentCSubstring GetStringValue(nsCSSPropertyID aProperty) {
93     uint32_t len;
94     const uint8_t* chars = Servo_Property_GetName(aProperty, &len);
95     return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
96   }
97 
98   static const nsCString& GetStringValue(nsCSSFontDesc aFontDesc);
99   static const nsCString& GetStringValue(nsCSSCounterDesc aCounterDesc);
100 
101  private:
102   static const Flags kFlagsTable[eCSSProperty_COUNT];
103 
104  public:
PropHasFlags(nsCSSPropertyID aProperty,Flags aFlags)105   static bool PropHasFlags(nsCSSPropertyID aProperty, Flags aFlags) {
106     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
107                "out of range");
108     return (nsCSSProps::kFlagsTable[aProperty] & aFlags) == aFlags;
109   }
110 
Physicalize(nsCSSPropertyID aProperty,const mozilla::ComputedStyle & aStyle)111   static nsCSSPropertyID Physicalize(nsCSSPropertyID aProperty,
112                                      const mozilla::ComputedStyle& aStyle) {
113     MOZ_ASSERT(!IsShorthand(aProperty));
114     if (PropHasFlags(aProperty, Flags::IsLogical)) {
115       return Servo_ResolveLogicalProperty(aProperty, &aStyle);
116     }
117     return aProperty;
118   }
119 
120  private:
121   // A table for shorthand properties.  The appropriate index is the
122   // property ID minus eCSSProperty_COUNT_no_shorthands.
123   static const nsCSSPropertyID* const
124       kSubpropertyTable[eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands];
125 
126  public:
127   /**
128    * Recoumputes the enabled state of a pref. If aPrefName is nullptr,
129    * recomputes the state of all prefs in gPropertyEnabled.
130    * aClosure is the pref callback closure data, which is not used.
131    */
132   static void RecomputeEnabledState(const char* aPrefName,
133                                     void* aClosure = nullptr);
134 
135   /**
136    * Retrieve a singleton receiver to register with gfxVars
137    */
138   static mozilla::gfx::gfxVarReceiver& GfxVarReceiver();
139 
SubpropertyEntryFor(nsCSSPropertyID aProperty)140   static const nsCSSPropertyID* SubpropertyEntryFor(nsCSSPropertyID aProperty) {
141     MOZ_ASSERT(eCSSProperty_COUNT_no_shorthands <= aProperty &&
142                    aProperty < eCSSProperty_COUNT,
143                "out of range");
144     return nsCSSProps::kSubpropertyTable[aProperty -
145                                          eCSSProperty_COUNT_no_shorthands];
146   }
147 
148  private:
149   static bool gPropertyEnabled[eCSSProperty_COUNT_with_aliases];
150 
151  private:
152   // Defined in the generated nsCSSPropsGenerated.inc.
153   static const char* const kIDLNameTable[eCSSProperty_COUNT];
154 
155  public:
156   /**
157    * Returns the IDL name of the specified property, which must be a
158    * longhand, logical or shorthand property.  The IDL name is the property
159    * name with any hyphen-lowercase character pairs replaced by an
160    * uppercase character:
161    * https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
162    *
163    * As a special case, the string "cssFloat" is returned for the float
164    * property.  nullptr is returned for internal properties.
165    */
PropertyIDLName(nsCSSPropertyID aProperty)166   static const char* PropertyIDLName(nsCSSPropertyID aProperty) {
167     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
168                "out of range");
169     return kIDLNameTable[aProperty];
170   }
171 
172  private:
173   static const int32_t kIDLNameSortPositionTable[eCSSProperty_COUNT];
174 
175  public:
176   /**
177    * Returns the position of the specified property in a list of all
178    * properties sorted by their IDL name.
179    */
PropertyIDLNameSortPosition(nsCSSPropertyID aProperty)180   static int32_t PropertyIDLNameSortPosition(nsCSSPropertyID aProperty) {
181     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
182                "out of range");
183     return kIDLNameSortPositionTable[aProperty];
184   }
185 
IsEnabled(nsCSSPropertyID aProperty)186   static bool IsEnabled(nsCSSPropertyID aProperty) {
187     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
188                "out of range");
189     // In the child process, assert that we're not trying to parse stylesheets
190     // before we've gotten all our prefs.
191     MOZ_ASSERT_IF(!XRE_IsParentProcess(),
192                   mozilla::Preferences::ArePrefsInitedInContentProcess());
193     return gPropertyEnabled[aProperty];
194   }
195 
196  public:
IsEnabled(nsCSSPropertyID aProperty,EnabledState aEnabled)197   static bool IsEnabled(nsCSSPropertyID aProperty, EnabledState aEnabled) {
198     if (IsEnabled(aProperty)) {
199       return true;
200     }
201     if (aEnabled == EnabledState::IgnoreEnabledState) {
202       return true;
203     }
204     if ((aEnabled & EnabledState::InUASheets) &&
205         PropHasFlags(aProperty, Flags::EnabledInUASheets)) {
206       return true;
207     }
208     if ((aEnabled & EnabledState::InChrome) &&
209         PropHasFlags(aProperty, Flags::EnabledInChrome)) {
210       return true;
211     }
212     return false;
213   }
214 
215  public:
216   struct PropertyPref {
217     nsCSSPropertyID mPropID;
218     const char* mPref;
219   };
220   static const PropertyPref kPropertyPrefTable[];
221 
222 // Storing the enabledstate_ value in an nsCSSPropertyID variable is a small
223 // hack to avoid needing a separate variable declaration for its real type
224 // (CSSEnabledState), which would then require using a block and
225 // therefore a pair of macros by consumers for the start and end of the loop.
226 #define CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(it_, prop_, enabledstate_)  \
227   for (const nsCSSPropertyID *                                           \
228            it_ = nsCSSProps::SubpropertyEntryFor(prop_),                 \
229           es_ = (nsCSSPropertyID)((enabledstate_) | CSSEnabledState(0)); \
230        *it_ != eCSSProperty_UNKNOWN; ++it_)                              \
231     if (nsCSSProps::IsEnabled(*it_, (mozilla::CSSEnabledState)es_))
232 };
233 
234 // MOZ_DBG support for nsCSSPropertyID
235 
236 inline std::ostream& operator<<(std::ostream& aOut, nsCSSPropertyID aProperty) {
237   return aOut << nsCSSProps::GetStringValue(aProperty);
238 }
239 
240 #endif /* nsCSSProps_h___ */
241