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/. */
8 * methods for dealing with CSS properties and tables of the keyword
12 #include "nsCSSProps.h"
14 #include "mozilla/ArrayUtils.h"
15 #include "mozilla/Casting.h"
17 #include "nsCSSKeywords.h"
18 #include "nsLayoutUtils.h"
19 #include "nsIWidget.h"
20 #include "nsStyleConsts.h" // For system widget appearance types
22 #include "mozilla/dom/Animation.h"
23 #include "mozilla/dom/AnimationEffectBinding.h" // for PlaybackDirection
24 #include "mozilla/LookAndFeel.h" // for system colors
27 #include "nsStaticNameTable.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/StaticPrefs_layout.h"
32 using namespace mozilla
;
34 typedef nsCSSProps::KTableEntry KTableEntry
;
36 static int32_t gPropertyTableRefCount
;
37 static nsStaticCaseInsensitiveNameTable
* gFontDescTable
;
38 static nsStaticCaseInsensitiveNameTable
* gCounterDescTable
;
39 static nsDataHashtable
<nsCStringHashKey
, nsCSSPropertyID
>*
40 gPropertyIDLNameTable
;
42 static const char* const kCSSRawFontDescs
[] = {
43 #define CSS_FONT_DESC(name_, method_) #name_,
44 #include "nsCSSFontDescList.h"
48 static const char* const kCSSRawCounterDescs
[] = {
49 #define CSS_COUNTER_DESC(name_, method_) #name_,
50 #include "nsCSSCounterDescList.h"
51 #undef CSS_COUNTER_DESC
54 static nsStaticCaseInsensitiveNameTable
* CreateStaticTable(
55 const char* const aRawTable
[], int32_t aLength
) {
56 auto table
= new nsStaticCaseInsensitiveNameTable(aRawTable
, aLength
);
58 // Partially verify the entries.
59 for (int32_t index
= 0; index
< aLength
; ++index
) {
60 nsAutoCString
temp(aRawTable
[index
]);
61 MOZ_ASSERT(-1 == temp
.FindChar('_'),
62 "underscore char in case insensitive name table");
68 void nsCSSProps::AddRefTable(void) {
69 if (0 == gPropertyTableRefCount
++) {
70 MOZ_ASSERT(!gFontDescTable
, "pre existing array!");
71 MOZ_ASSERT(!gCounterDescTable
, "pre existing array!");
72 MOZ_ASSERT(!gPropertyIDLNameTable
, "pre existing array!");
74 gFontDescTable
= CreateStaticTable(kCSSRawFontDescs
, eCSSFontDesc_COUNT
);
76 CreateStaticTable(kCSSRawCounterDescs
, eCSSCounterDesc_COUNT
);
78 gPropertyIDLNameTable
=
79 new nsDataHashtable
<nsCStringHashKey
, nsCSSPropertyID
>;
80 for (nsCSSPropertyID p
= nsCSSPropertyID(0);
81 size_t(p
) < ArrayLength(kIDLNameTable
); p
= nsCSSPropertyID(p
+ 1)) {
82 if (kIDLNameTable
[p
]) {
83 gPropertyIDLNameTable
->Put(nsDependentCString(kIDLNameTable
[p
]), p
);
87 static bool prefObserversInited
= false;
88 if (!prefObserversInited
) {
89 prefObserversInited
= true;
90 for (const PropertyPref
* pref
= kPropertyPrefTable
;
91 pref
->mPropID
!= eCSSProperty_UNKNOWN
; pref
++) {
93 prefName
.AssignLiteral(pref
->mPref
, strlen(pref
->mPref
));
94 bool* enabled
= &gPropertyEnabled
[pref
->mPropID
];
95 Preferences::AddBoolVarCache(enabled
, prefName
);
101 #undef DEBUG_SHORTHANDS_CONTAINING
103 void nsCSSProps::ReleaseTable(void) {
104 if (0 == --gPropertyTableRefCount
) {
105 delete gFontDescTable
;
106 gFontDescTable
= nullptr;
108 delete gCounterDescTable
;
109 gCounterDescTable
= nullptr;
111 delete gPropertyIDLNameTable
;
112 gPropertyIDLNameTable
= nullptr;
117 bool nsCSSProps::IsCustomPropertyName(const nsAString
& aProperty
) {
118 return aProperty
.Length() >= CSS_CUSTOM_NAME_PREFIX_LENGTH
&&
119 StringBeginsWith(aProperty
, NS_LITERAL_STRING("--"));
122 nsCSSPropertyID
nsCSSProps::LookupPropertyByIDLName(
123 const nsACString
& aPropertyIDLName
, EnabledState aEnabled
) {
125 if (!gPropertyIDLNameTable
->Get(aPropertyIDLName
, &res
)) {
126 return eCSSProperty_UNKNOWN
;
128 MOZ_ASSERT(res
< eCSSProperty_COUNT
);
129 if (!IsEnabled(res
, aEnabled
)) {
130 return eCSSProperty_UNKNOWN
;
135 nsCSSPropertyID
nsCSSProps::LookupPropertyByIDLName(
136 const nsAString
& aPropertyIDLName
, EnabledState aEnabled
) {
137 MOZ_ASSERT(gPropertyIDLNameTable
, "no lookup table, needs addref");
138 return LookupPropertyByIDLName(NS_ConvertUTF16toUTF8(aPropertyIDLName
),
142 nsCSSFontDesc
nsCSSProps::LookupFontDesc(const nsAString
& aFontDesc
) {
143 MOZ_ASSERT(gFontDescTable
, "no lookup table, needs addref");
144 nsCSSFontDesc which
= nsCSSFontDesc(gFontDescTable
->Lookup(aFontDesc
));
146 if (which
== eCSSFontDesc_Display
&&
147 !StaticPrefs::layout_css_font_display_enabled()) {
148 which
= eCSSFontDesc_UNKNOWN
;
153 const nsCString
& nsCSSProps::GetStringValue(nsCSSFontDesc aFontDescID
) {
154 MOZ_ASSERT(gFontDescTable
, "no lookup table, needs addref");
155 if (gFontDescTable
) {
156 return gFontDescTable
->GetStringValue(int32_t(aFontDescID
));
158 static nsDependentCString
sNullStr("");
163 const nsCString
& nsCSSProps::GetStringValue(nsCSSCounterDesc aCounterDesc
) {
164 MOZ_ASSERT(gCounterDescTable
, "no lookup table, needs addref");
165 if (gCounterDescTable
) {
166 return gCounterDescTable
->GetStringValue(int32_t(aCounterDesc
));
168 static nsDependentCString
sNullStr("");
173 /***************************************************************************/
175 const KTableEntry
nsCSSProps::kCursorKTable
[] = {
177 {eCSSKeyword_auto
, StyleCursorKind::Auto
},
178 {eCSSKeyword_crosshair
, StyleCursorKind::Crosshair
},
179 {eCSSKeyword_default
, StyleCursorKind::Default
},
180 {eCSSKeyword_pointer
, StyleCursorKind::Pointer
},
181 {eCSSKeyword_move
, StyleCursorKind::Move
},
182 {eCSSKeyword_e_resize
, StyleCursorKind::EResize
},
183 {eCSSKeyword_ne_resize
, StyleCursorKind::NeResize
},
184 {eCSSKeyword_nw_resize
, StyleCursorKind::NwResize
},
185 {eCSSKeyword_n_resize
, StyleCursorKind::NResize
},
186 {eCSSKeyword_se_resize
, StyleCursorKind::SeResize
},
187 {eCSSKeyword_sw_resize
, StyleCursorKind::SwResize
},
188 {eCSSKeyword_s_resize
, StyleCursorKind::SResize
},
189 {eCSSKeyword_w_resize
, StyleCursorKind::WResize
},
190 {eCSSKeyword_text
, StyleCursorKind::Text
},
191 {eCSSKeyword_wait
, StyleCursorKind::Wait
},
192 {eCSSKeyword_help
, StyleCursorKind::Help
},
194 {eCSSKeyword_progress
, StyleCursorKind::Progress
},
195 // CSS3 basic user interface module
196 {eCSSKeyword_copy
, StyleCursorKind::Copy
},
197 {eCSSKeyword_alias
, StyleCursorKind::Alias
},
198 {eCSSKeyword_context_menu
, StyleCursorKind::ContextMenu
},
199 {eCSSKeyword_cell
, StyleCursorKind::Cell
},
200 {eCSSKeyword_not_allowed
, StyleCursorKind::NotAllowed
},
201 {eCSSKeyword_col_resize
, StyleCursorKind::ColResize
},
202 {eCSSKeyword_row_resize
, StyleCursorKind::RowResize
},
203 {eCSSKeyword_no_drop
, StyleCursorKind::NoDrop
},
204 {eCSSKeyword_vertical_text
, StyleCursorKind::VerticalText
},
205 {eCSSKeyword_all_scroll
, StyleCursorKind::AllScroll
},
206 {eCSSKeyword_nesw_resize
, StyleCursorKind::NeswResize
},
207 {eCSSKeyword_nwse_resize
, StyleCursorKind::NwseResize
},
208 {eCSSKeyword_ns_resize
, StyleCursorKind::NsResize
},
209 {eCSSKeyword_ew_resize
, StyleCursorKind::EwResize
},
210 {eCSSKeyword_none
, StyleCursorKind::None
},
211 {eCSSKeyword_grab
, StyleCursorKind::Grab
},
212 {eCSSKeyword_grabbing
, StyleCursorKind::Grabbing
},
213 {eCSSKeyword_zoom_in
, StyleCursorKind::ZoomIn
},
214 {eCSSKeyword_zoom_out
, StyleCursorKind::ZoomOut
},
215 // -moz- prefixed vendor specific
216 {eCSSKeyword__moz_grab
, StyleCursorKind::Grab
},
217 {eCSSKeyword__moz_grabbing
, StyleCursorKind::Grabbing
},
218 {eCSSKeyword__moz_zoom_in
, StyleCursorKind::ZoomIn
},
219 {eCSSKeyword__moz_zoom_out
, StyleCursorKind::ZoomOut
},
220 {eCSSKeyword_UNKNOWN
, nsCSSKTableEntry::SENTINEL_VALUE
}};
222 const KTableEntry
nsCSSProps::kFontSmoothingKTable
[] = {
223 {eCSSKeyword_auto
, NS_FONT_SMOOTHING_AUTO
},
224 {eCSSKeyword_grayscale
, NS_FONT_SMOOTHING_GRAYSCALE
},
225 {eCSSKeyword_UNKNOWN
, nsCSSKTableEntry::SENTINEL_VALUE
}};
227 const KTableEntry
nsCSSProps::kTextAlignKTable
[] = {
228 {eCSSKeyword_left
, NS_STYLE_TEXT_ALIGN_LEFT
},
229 {eCSSKeyword_right
, NS_STYLE_TEXT_ALIGN_RIGHT
},
230 {eCSSKeyword_center
, NS_STYLE_TEXT_ALIGN_CENTER
},
231 {eCSSKeyword_justify
, NS_STYLE_TEXT_ALIGN_JUSTIFY
},
232 {eCSSKeyword__moz_center
, NS_STYLE_TEXT_ALIGN_MOZ_CENTER
},
233 {eCSSKeyword__moz_right
, NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
},
234 {eCSSKeyword__moz_left
, NS_STYLE_TEXT_ALIGN_MOZ_LEFT
},
235 {eCSSKeyword_start
, NS_STYLE_TEXT_ALIGN_START
},
236 {eCSSKeyword_end
, NS_STYLE_TEXT_ALIGN_END
},
237 {eCSSKeyword_UNKNOWN
, nsCSSKTableEntry::SENTINEL_VALUE
}};
239 const KTableEntry
nsCSSProps::kTextDecorationStyleKTable
[] = {
240 {eCSSKeyword__moz_none
, NS_STYLE_TEXT_DECORATION_STYLE_NONE
},
241 {eCSSKeyword_solid
, NS_STYLE_TEXT_DECORATION_STYLE_SOLID
},
242 {eCSSKeyword_double
, NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE
},
243 {eCSSKeyword_dotted
, NS_STYLE_TEXT_DECORATION_STYLE_DOTTED
},
244 {eCSSKeyword_dashed
, NS_STYLE_TEXT_DECORATION_STYLE_DASHED
},
245 {eCSSKeyword_wavy
, NS_STYLE_TEXT_DECORATION_STYLE_WAVY
},
246 {eCSSKeyword_UNKNOWN
, nsCSSKTableEntry::SENTINEL_VALUE
}};
248 int32_t nsCSSProps::FindIndexOfKeyword(nsCSSKeyword aKeyword
,
249 const KTableEntry aTable
[]) {
250 if (eCSSKeyword_UNKNOWN
== aKeyword
) {
251 // NOTE: we can have keyword tables where eCSSKeyword_UNKNOWN is used
252 // not only for the sentinel, but also in the middle of the table to
253 // knock out values that have been disabled by prefs, e.g. kDisplayKTable.
254 // So we deal with eCSSKeyword_UNKNOWN up front to avoid returning a valid
255 // index in the loop below.
258 for (int32_t i
= 0;; ++i
) {
259 const KTableEntry
& entry
= aTable
[i
];
260 if (entry
.IsSentinel()) {
263 if (aKeyword
== entry
.mKeyword
) {
270 bool nsCSSProps::FindKeyword(nsCSSKeyword aKeyword
, const KTableEntry aTable
[],
272 int32_t index
= FindIndexOfKeyword(aKeyword
, aTable
);
274 aResult
= aTable
[index
].mValue
;
280 nsCSSKeyword
nsCSSProps::ValueToKeywordEnum(int32_t aValue
,
281 const KTableEntry aTable
[]) {
283 typedef decltype(aTable
[0].mValue
) table_value_type
;
284 NS_ASSERTION(table_value_type(aValue
) == aValue
, "Value out of range");
286 for (int32_t i
= 0;; ++i
) {
287 const KTableEntry
& entry
= aTable
[i
];
288 if (entry
.IsSentinel()) {
291 if (aValue
== entry
.mValue
) {
292 return entry
.mKeyword
;
295 return eCSSKeyword_UNKNOWN
;
298 const nsCString
& nsCSSProps::ValueToKeyword(int32_t aValue
,
299 const KTableEntry aTable
[]) {
300 nsCSSKeyword keyword
= ValueToKeywordEnum(aValue
, aTable
);
301 if (keyword
== eCSSKeyword_UNKNOWN
) {
302 static nsDependentCString
sNullStr("");
305 return nsCSSKeywords::GetStringValue(keyword
);
309 const CSSPropFlags
nsCSSProps::kFlagsTable
[eCSSProperty_COUNT
] = {
310 #define CSS_PROP_LONGHAND(name_, id_, method_, flags_, ...) flags_,
311 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, ...) flags_,
312 #include "mozilla/ServoCSSPropList.h"
313 #undef CSS_PROP_SHORTHAND
314 #undef CSS_PROP_LONGHAND
318 bool nsCSSProps::gPropertyEnabled
[eCSSProperty_COUNT_with_aliases
] = {
319 // If the property has any "ENABLED_IN" flag set, it is disabled by
320 // default. Note that, if a property has pref, whatever its default
321 // value is, it will later be changed in nsCSSProps::AddRefTable().
322 // If the property has "ENABLED_IN" flags but doesn't have a pref,
323 // it is an internal property which is disabled elsewhere.
324 #define IS_ENABLED_BY_DEFAULT(flags_) \
325 (!((flags_) & (CSSPropFlags::EnabledMask | CSSPropFlags::Inaccessible)))
327 #define CSS_PROP_LONGHAND(name_, id_, method_, flags_, ...) \
328 IS_ENABLED_BY_DEFAULT(flags_),
329 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, ...) \
330 IS_ENABLED_BY_DEFAULT(flags_),
331 #define CSS_PROP_ALIAS(...) true,
332 #include "mozilla/ServoCSSPropList.h"
333 #undef CSS_PROP_ALIAS
334 #undef CSS_PROP_SHORTHAND
335 #undef CSS_PROP_LONGHAND
337 #undef IS_ENABLED_BY_DEFAULT
340 #include "nsCSSPropsGenerated.inc"