summaryrefslogtreecommitdiffstats
path: root/layout/style/StyleRule.h
blob: 907e55448a03d24a94063a0e533a39f0a9815889 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */

/*
 * representation of CSS style rules (selectors+declaration) and CSS
 * selectors
 */

#ifndef mozilla_css_StyleRule_h__
#define mozilla_css_StyleRule_h__

#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/Rule.h"

#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsCSSPseudoElements.h"
#include "nsIStyleRule.h"

class nsIAtom;
struct nsCSSSelectorList;

namespace mozilla {
enum class CSSPseudoClassType : uint8_t;
class CSSStyleSheet;
} // namespace mozilla

struct nsAtomList {
public:
  explicit nsAtomList(nsIAtom* aAtom);
  explicit nsAtomList(const nsString& aAtomValue);
  ~nsAtomList(void);

  /** Do a deep clone.  Should be used only on the first in the linked list. */
  nsAtomList* Clone() const { return Clone(true); }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

  nsCOMPtr<nsIAtom> mAtom;
  nsAtomList*       mNext;
private:
  nsAtomList* Clone(bool aDeep) const;

  nsAtomList(const nsAtomList& aCopy) = delete;
  nsAtomList& operator=(const nsAtomList& aCopy) = delete;
};

struct nsPseudoClassList {
public:
  typedef mozilla::CSSPseudoClassType CSSPseudoClassType;

  explicit nsPseudoClassList(CSSPseudoClassType aType);
  nsPseudoClassList(CSSPseudoClassType aType, const char16_t *aString);
  nsPseudoClassList(CSSPseudoClassType aType, const int32_t *aIntPair);
  nsPseudoClassList(CSSPseudoClassType aType,
                    nsCSSSelectorList *aSelectorList /* takes ownership */);
  ~nsPseudoClassList(void);

  /** Do a deep clone.  Should be used only on the first in the linked list. */
  nsPseudoClassList* Clone() const { return Clone(true); }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

  union {
    // For a given value of mType, we have either:
    //   a. no value, which means mMemory is always null
    //      (if none of the conditions for (b), (c), or (d) is true)
    //   b. a string value, which means mString/mMemory is non-null
    //      (if nsCSSPseudoClasses::HasStringArg(mType))
    //   c. an integer pair value, which means mNumbers/mMemory is non-null
    //      (if nsCSSPseudoClasses::HasNthPairArg(mType))
    //   d. a selector list, which means mSelectors is non-null
    //      (if nsCSSPseudoClasses::HasSelectorListArg(mType))
    void*           mMemory; // mString and mNumbers use moz_xmalloc/free
    char16_t*       mString;
    int32_t*        mNumbers;
    nsCSSSelectorList* mSelectors;
  } u;
  CSSPseudoClassType mType;
  nsPseudoClassList* mNext;
private:
  nsPseudoClassList* Clone(bool aDeep) const;

  nsPseudoClassList(const nsPseudoClassList& aCopy) = delete;
  nsPseudoClassList& operator=(const nsPseudoClassList& aCopy) = delete;
};

#define NS_ATTR_FUNC_SET        0     // [attr]
#define NS_ATTR_FUNC_EQUALS     1     // [attr=value]
#define NS_ATTR_FUNC_INCLUDES   2     // [attr~=value] (space separated)
#define NS_ATTR_FUNC_DASHMATCH  3     // [attr|=value] ('-' truncated)
#define NS_ATTR_FUNC_BEGINSMATCH  4   // [attr^=value] (begins with)
#define NS_ATTR_FUNC_ENDSMATCH  5     // [attr$=value] (ends with)
#define NS_ATTR_FUNC_CONTAINSMATCH 6  // [attr*=value] (contains substring)

struct nsAttrSelector {
public:
  enum class ValueCaseSensitivity : uint8_t {
    CaseSensitive,
    CaseInsensitive,
    CaseInsensitiveInHTML
  };

  nsAttrSelector(int32_t aNameSpace, const nsString& aAttr);
  nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction, 
                 const nsString& aValue,
                 ValueCaseSensitivity aValueCaseSensitivity);
  nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr, 
                 nsIAtom* aCasedAttr, uint8_t aFunction, 
                 const nsString& aValue,
                 ValueCaseSensitivity aValueCaseSensitivity);
  ~nsAttrSelector(void);

  /** Do a deep clone.  Should be used only on the first in the linked list. */
  nsAttrSelector* Clone() const { return Clone(true); }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

  bool IsValueCaseSensitive(bool aInHTML) const {
    return mValueCaseSensitivity == ValueCaseSensitivity::CaseSensitive ||
      (!aInHTML &&
       mValueCaseSensitivity == ValueCaseSensitivity::CaseInsensitiveInHTML);
  }

  nsString        mValue;
  nsAttrSelector* mNext;
  nsCOMPtr<nsIAtom> mLowercaseAttr;
  nsCOMPtr<nsIAtom> mCasedAttr;
  int32_t         mNameSpace;
  uint8_t         mFunction;
  ValueCaseSensitivity mValueCaseSensitivity;

private:
  nsAttrSelector* Clone(bool aDeep) const;

  nsAttrSelector(const nsAttrSelector& aCopy) = delete;
  nsAttrSelector& operator=(const nsAttrSelector& aCopy) = delete;
};

struct nsCSSSelector {
public:
  typedef mozilla::CSSPseudoClassType CSSPseudoClassType;

  nsCSSSelector(void);
  ~nsCSSSelector(void);

  /** Do a deep clone.  Should be used only on the first in the linked list. */
  nsCSSSelector* Clone() const { return Clone(true, true); }

  void Reset(void);
  void SetNameSpace(int32_t aNameSpace);
  void SetTag(const nsString& aTag);
  void AddID(const nsString& aID);
  void AddClass(const nsString& aClass);
  void AddPseudoClass(CSSPseudoClassType aType);
  void AddPseudoClass(CSSPseudoClassType aType, const char16_t* aString);
  void AddPseudoClass(CSSPseudoClassType aType, const int32_t* aIntPair);
  // takes ownership of aSelectorList
  void AddPseudoClass(CSSPseudoClassType aType,
                      nsCSSSelectorList* aSelectorList);
  void AddAttribute(int32_t aNameSpace, const nsString& aAttr);
  void AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
                    const nsString& aValue,
                    nsAttrSelector::ValueCaseSensitivity aValueCaseSensitivity);
  void SetOperator(char16_t aOperator);

  inline bool HasTagSelector() const {
    return !!mCasedTag;
  }

  inline bool IsPseudoElement() const {
    return mLowercaseTag && !mCasedTag;
  }

  // Calculate the specificity of this selector (not including its mNext!).
  int32_t CalcWeight() const;

  void ToString(nsAString& aString, mozilla::CSSStyleSheet* aSheet,
                bool aAppend = false) const;

  bool IsRestrictedSelector() const {
    return PseudoType() == mozilla::CSSPseudoElementType::NotPseudo;
  }

#ifdef DEBUG
  nsCString RestrictedSelectorToString() const;
#endif

private:
  void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass);
  nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const;

  void AppendToStringWithoutCombinators(
      nsAString& aString,
      mozilla::CSSStyleSheet* aSheet,
      bool aUseStandardNamespacePrefixes) const;
  void AppendToStringWithoutCombinatorsOrNegations(
      nsAString& aString,
      mozilla::CSSStyleSheet* aSheet,
      bool aIsNegated,
      bool aUseStandardNamespacePrefixes) const;
  // Returns true if this selector can have a namespace specified (which
  // happens if and only if the default namespace would apply to this
  // selector).
  bool CanBeNamespaced(bool aIsNegated) const;
  // Calculate the specificity of this selector (not including its mNext
  // or its mNegations).
  int32_t CalcWeightWithoutNegations() const;

public:
  // Get and set the selector's pseudo type
  mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; }
  void SetPseudoType(mozilla::CSSPseudoElementType aType) {
    mPseudoType = aType;
  }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

  // For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
  // but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
  // Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
  // contains their name.
  nsCOMPtr<nsIAtom> mLowercaseTag;
  nsCOMPtr<nsIAtom> mCasedTag;
  nsAtomList*     mIDList;
  nsAtomList*     mClassList;
  nsPseudoClassList* mPseudoClassList; // atom for the pseudo, string for
                                       // the argument to functional pseudos
  nsAttrSelector* mAttrList;
  nsCSSSelector*  mNegations;
  nsCSSSelector*  mNext;
  int32_t         mNameSpace;
  char16_t       mOperator;
private:
  // The underlying type of CSSPseudoElementType is uint8_t and
  // it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
  mozilla::CSSPseudoElementType mPseudoType;

  nsCSSSelector(const nsCSSSelector& aCopy) = delete;
  nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete;
};

/**
 * A selector list is the unit of selectors that each style rule has.
 * For example, "P B, H1 B { ... }" would be a selector list with two
 * items (where each |nsCSSSelectorList| object's |mSelectors| has
 * an |mNext| for the P or H1).  We represent them as linked lists.
 */
class inDOMUtils;

struct nsCSSSelectorList {
  nsCSSSelectorList(void);
  ~nsCSSSelectorList(void);

  /**
   * Create a new selector and push it onto the beginning of |mSelectors|,
   * setting its |mNext| to the current value of |mSelectors|.  If there is an
   * earlier selector, set its |mOperator| to |aOperator|; else |aOperator|
   * must be char16_t(0).
   * Returns the new selector.
   * The list owns the new selector.
   * The caller is responsible for updating |mWeight|.
   */
  nsCSSSelector* AddSelector(char16_t aOperator);

  /**
   * Point |mSelectors| to its |mNext|, and delete the first node in the old
   * |mSelectors|.
   * Should only be used on a list with more than one selector in it.
   */
  void RemoveRightmostSelector();

  /**
   * Should be used only on the first in the list
   */
  void ToString(nsAString& aResult, mozilla::CSSStyleSheet* aSheet);

  /**
   * Do a deep clone.  Should be used only on the first in the list.
   */
  nsCSSSelectorList* Clone() const { return Clone(true); }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

  nsCSSSelector*     mSelectors;
  int32_t            mWeight;
  nsCSSSelectorList* mNext;
protected:
  friend class inDOMUtils;
  nsCSSSelectorList* Clone(bool aDeep) const;

private:
  nsCSSSelectorList(const nsCSSSelectorList& aCopy) = delete;
  nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) = delete;
};

// 464bab7a-2fce-4f30-ab44-b7a5f3aae57d
#define NS_CSS_STYLE_RULE_IMPL_CID \
{ 0x464bab7a, 0x2fce, 0x4f30, \
  { 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } }

namespace mozilla {
namespace css {

class Declaration;
class DOMCSSStyleRule;

class StyleRule final : public Rule
{
 public:
  StyleRule(nsCSSSelectorList* aSelector,
            Declaration *aDeclaration,
            uint32_t aLineNumber, uint32_t aColumnNumber);
private:
  // for |Clone|
  StyleRule(const StyleRule& aCopy);
public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID)

  NS_DECL_ISUPPORTS

  // null for style attribute
  nsCSSSelectorList* Selector() { return mSelector; }

  Declaration* GetDeclaration() const { return mDeclaration; }

  void SetDeclaration(Declaration* aDecl);

  // hooks for DOM rule
  void GetCssText(nsAString& aCssText);
  void SetCssText(const nsAString& aCssText);
  void GetSelectorText(nsAString& aSelectorText);
  void SetSelectorText(const nsAString& aSelectorText);

  virtual int32_t GetType() const override;

  virtual already_AddRefed<Rule> Clone() const override;

  virtual nsIDOMCSSRule* GetDOMRule() override;

  virtual nsIDOMCSSRule* GetExistingDOMRule() override;

#ifdef DEBUG
  virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif

  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;

private:
  ~StyleRule();

private:
  nsCSSSelectorList*      mSelector; // null for style attribute
  RefPtr<Declaration>     mDeclaration;
  RefPtr<DOMCSSStyleRule> mDOMRule;

private:
  StyleRule& operator=(const StyleRule& aCopy) = delete;
};

NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID)

} // namespace css
} // namespace mozilla

#endif /* mozilla_css_StyleRule_h__ */