summaryrefslogtreecommitdiffstats
path: root/dom/base/LinkStyle.h
blob: d62ab8f4e1fdf01e913d37f2a4c6532d6ab79ee7 (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
/* -*- 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/. */
#ifndef mozilla_dom_LinkStyle_h
#define mozilla_dom_LinkStyle_h

#include "nsINode.h"
#include "mozilla/Attributes.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/Result.h"
#include "mozilla/Unused.h"
#include "nsTArray.h"

class nsIContent;
class nsICSSLoaderObserver;
class nsIPrincipal;
class nsIURI;

namespace mozilla::dom {

class Document;
enum class FetchPriority : uint8_t;
class ShadowRoot;

// https://drafts.csswg.org/cssom/#the-linkstyle-interface
class LinkStyle {
 public:
  enum class ForceUpdate : uint8_t {
    No,
    Yes,
  };

  enum class Completed : uint8_t {
    No,
    Yes,
  };

  enum class HasAlternateRel : uint8_t {
    No,
    Yes,
  };

  enum class IsAlternate : uint8_t {
    No,
    Yes,
  };

  enum class IsInline : uint8_t {
    No,
    Yes,
  };

  enum class IsExplicitlyEnabled : uint8_t {
    No,
    Yes,
  };

  enum class MediaMatched : uint8_t {
    Yes,
    No,
  };

  struct Update {
   private:
    bool mWillNotify;
    bool mIsAlternate;
    bool mMediaMatched;

   public:
    Update() : mWillNotify(false), mIsAlternate(false), mMediaMatched(false) {}

    Update(Completed aCompleted, IsAlternate aIsAlternate,
           MediaMatched aMediaMatched)
        : mWillNotify(aCompleted == Completed::No),
          mIsAlternate(aIsAlternate == IsAlternate::Yes),
          mMediaMatched(aMediaMatched == MediaMatched::Yes) {}

    bool WillNotify() const { return mWillNotify; }

    bool ShouldBlock() const {
      if (!mWillNotify) {
        return false;
      }

      return !mIsAlternate && mMediaMatched;
    }
  };

  static LinkStyle* FromNode(nsINode& aNode) { return aNode.AsLinkStyle(); }
  static const LinkStyle* FromNode(const nsINode& aNode) {
    return aNode.AsLinkStyle();
  }

  static LinkStyle* FromNode(Element&);
  static const LinkStyle* FromNode(const Element& aElement) {
    return FromNode(const_cast<Element&>(aElement));
  }

  template <typename T>
  static LinkStyle* FromNodeOrNull(T* aNode) {
    return aNode ? FromNode(*aNode) : nullptr;
  }

  template <typename T>
  static const LinkStyle* FromNodeOrNull(const T* aNode) {
    return aNode ? FromNode(*aNode) : nullptr;
  }

  enum RelValue {
    ePREFETCH = 0x00000001,
    eDNS_PREFETCH = 0x00000002,
    eSTYLESHEET = 0x00000004,
    eNEXT = 0x00000008,
    eALTERNATE = 0x00000010,
    ePRECONNECT = 0x00000020,
    // NOTE: 0x40 is unused
    ePRELOAD = 0x00000080,
    eMODULE_PRELOAD = 0x00000100
  };

  // The return value is a bitwise or of 0 or more RelValues.
  static uint32_t ParseLinkTypes(const nsAString& aTypes);

  void UpdateStyleSheetInternal() {
    Unused << UpdateStyleSheetInternal(nullptr, nullptr);
  }

  struct MOZ_STACK_CLASS SheetInfo {
    nsIContent* mContent;
    // FIXME(emilio): do these really need to be strong refs?
    nsCOMPtr<nsIURI> mURI;

    // The principal of the scripted caller that initiated the load, if
    // available. Otherwise null.
    nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
    nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
    mozilla::CORSMode mCORSMode;
    nsString mTitle;
    nsString mMedia;
    nsString mIntegrity;
    nsString mNonce;
    const FetchPriority mFetchPriority;

    bool mHasAlternateRel;
    bool mIsInline;
    IsExplicitlyEnabled mIsExplicitlyEnabled;

    SheetInfo(const mozilla::dom::Document&, nsIContent*,
              already_AddRefed<nsIURI> aURI,
              already_AddRefed<nsIPrincipal> aTriggeringPrincipal,
              already_AddRefed<nsIReferrerInfo> aReferrerInfo,
              mozilla::CORSMode, const nsAString& aTitle,
              const nsAString& aMedia, const nsAString& aIntegrity,
              const nsAString& aNonce, HasAlternateRel, IsInline,
              IsExplicitlyEnabled, FetchPriority aFetchPriority);

    ~SheetInfo();
  };

  virtual nsIContent& AsContent() = 0;
  virtual Maybe<SheetInfo> GetStyleSheetInfo() = 0;

  /**
   * Used to make the association between a style sheet and
   * the element that linked it to the document.
   *
   * @param aStyleSheet the style sheet associated with this
   *                    element.
   */
  void SetStyleSheet(StyleSheet* aStyleSheet);

  /**
   * Tells this element whether to update the stylesheet when the element's
   * properties change. This is used by the parser until it has all content etc,
   * and to guarantee that the right observer is used.
   */
  void DisableUpdates() { mUpdatesEnabled = false; }
  Result<Update, nsresult> EnableUpdatesAndUpdateStyleSheet(
      nsICSSLoaderObserver* aObserver) {
    MOZ_ASSERT(!mUpdatesEnabled);
    mUpdatesEnabled = true;
    return DoUpdateStyleSheet(nullptr, nullptr, aObserver, ForceUpdate::No);
  }

  /**
   * Gets the charset that the element claims the style sheet is in.
   * Can return empty string to indicate that we have no charset
   * information.
   *
   * @param aCharset the charset
   */
  virtual void GetCharset(nsAString& aCharset);

  // This doesn't entirely belong here since they only make sense for
  // some types of linking elements, but it's a better place than
  // anywhere else.
  void SetLineNumber(uint32_t aLineNumber) { mLineNumber = aLineNumber; }

  /**
   * Get the line number, as previously set by SetLineNumber.
   *
   * @return the line number of this element; or 1 if no line number
   *         was set
   */
  uint32_t GetLineNumber() const { return mLineNumber; }

  // This doesn't entirely belong here since they only make sense for
  // some types of linking elements, but it's a better place than
  // anywhere else.
  void SetColumnNumber(uint32_t aColumnNumber) {
    mColumnNumber = aColumnNumber;
  }

  /**
   * Get the column number, as previously set by SetColumnNumber.
   *
   * @return the column number of this element; or 1 if no column number
   *         was set
   */
  uint32_t GetColumnNumber() const { return mColumnNumber; }

  StyleSheet* GetSheet() const { return mStyleSheet; }

  /** JS can only observe the sheet once fully loaded */
  StyleSheet* GetSheetForBindings() const;

 protected:
  LinkStyle();
  virtual ~LinkStyle();

  // Gets a suitable title and media for SheetInfo out of an element, which
  // needs to be `this`.
  //
  // NOTE(emilio): Needs nsString instead of nsAString because of
  // CompressWhitespace.
  static void GetTitleAndMediaForElement(const mozilla::dom::Element&,
                                         nsString& aTitle, nsString& aMedia);

  // Returns whether the type attribute specifies the text/css type for style
  // elements.
  static bool IsCSSMimeTypeAttributeForStyleElement(const Element&);

  // CC methods
  void Unlink();
  void Traverse(nsCycleCollectionTraversalCallback& cb);

  /**
   * @param aOldDocument   should be non-null only if we're updating because we
   *                       removed the node from the document.
   * @param aOldShadowRoot should be non-null only if we're updating because we
   *                       removed the node from a shadow tree.
   * @param aForceUpdate true will force the update even if the URI has not
   *                     changed.  This should be used in cases when something
   *                     about the content that affects the resulting sheet
   *                     changed but the URI may not have changed.
   *
   * TODO(emilio): Should probably pass a single DocumentOrShadowRoot.
   */
  Result<Update, nsresult> UpdateStyleSheetInternal(
      Document* aOldDocument, ShadowRoot* aOldShadowRoot,
      ForceUpdate = ForceUpdate::No);

  /**
   * @param aOldDocument should be non-null only if we're updating because we
   *                     removed the node from the document.
   * @param aOldShadowRoot The ShadowRoot that used to contain the style.
   *                     Passed as a parameter because on an update, the node
   *                     is removed from the tree before the sheet is removed
   *                     from the ShadowRoot.
   * @param aForceUpdate true will force the update even if the URI has not
   *                     changed.  This should be used in cases when something
   *                     about the content that affects the resulting sheet
   *                     changed but the URI may not have changed.
   */
  Result<Update, nsresult> DoUpdateStyleSheet(Document* aOldDocument,
                                              ShadowRoot* aOldShadowRoot,
                                              nsICSSLoaderObserver*,
                                              ForceUpdate);

  void BindToTree();

  RefPtr<mozilla::StyleSheet> mStyleSheet;
  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
  bool mUpdatesEnabled = true;
  uint32_t mLineNumber = 1;
  uint32_t mColumnNumber = 1;
};

}  // namespace mozilla::dom

#endif  // mozilla_dom_LinkStyle_h