Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/ComputedStyle.h
Line
Count
Source (jump to first uncovered line)
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
/* the interface (to internal code) for retrieving computed style data */
8
9
#ifndef _ComputedStyle_h_
10
#define _ComputedStyle_h_
11
12
#include "nsIMemoryReporter.h"
13
#include <algorithm>
14
#include "mozilla/ArenaObjectID.h"
15
#include "mozilla/Assertions.h"
16
#include "mozilla/CachedInheritingStyles.h"
17
#include "mozilla/Maybe.h"
18
#include "mozilla/ServoComputedData.h"
19
#include "mozilla/ServoTypes.h"
20
#include "mozilla/ServoUtils.h"
21
#include "mozilla/StyleComplexColor.h"
22
#include "nsCSSAnonBoxes.h"
23
#include "nsCSSPseudoElements.h"
24
25
#include "nsStyleStructFwd.h"
26
27
class nsAtom;
28
enum nsChangeHint : uint32_t;
29
class nsIPresShell;
30
class nsPresContext;
31
class nsWindowSizes;
32
33
#define STYLE_STRUCT(name_) struct nsStyle##name_;
34
#include "nsStyleStructList.h"
35
#undef STYLE_STRUCT
36
37
extern "C" {
38
  void Servo_ComputedStyle_AddRef(const mozilla::ComputedStyle* aStyle);
39
  void Servo_ComputedStyle_Release(const mozilla::ComputedStyle* aStyle);
40
  void Gecko_ComputedStyle_Destroy(mozilla::ComputedStyle*);
41
}
42
43
namespace mozilla {
44
45
enum class CSSPseudoElementType : uint8_t;
46
class ComputedStyle;
47
48
/**
49
 * A ComputedStyle represents the computed style data for an element.
50
 *
51
 * The computed style data are stored in a set of reference counted structs
52
 * (see nsStyleStruct.h) that are stored directly on the ComputedStyle.
53
 *
54
 * Style structs are immutable once they have been produced, so when any change
55
 * is made that needs a restyle, we create a new ComputedStyle.
56
 *
57
 * ComputedStyles are reference counted. References are generally held by:
58
 *
59
 *  1. nsIFrame::mComputedStyle, for every frame
60
 *  2. Element::mServoData, for every element not inside a display:none subtree
61
 *  3. nsComputedDOMStyle, when created for elements in display:none subtrees
62
 *  4. media_queries::Device, which holds the initial value of every property
63
 */
64
65
enum class ComputedStyleBit : uint8_t
66
{
67
  HasTextDecorationLines = 1 << 0,
68
  HasPseudoElementData = 1 << 1,
69
  SuppressLineBreak = 1 << 2,
70
  IsTextCombined = 1 << 3,
71
  RelevantLinkVisited = 1 << 4,
72
};
73
74
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ComputedStyleBit)
75
76
class ComputedStyle
77
{
78
  using Bit = ComputedStyleBit;
79
public:
80
  ComputedStyle(nsPresContext* aPresContext,
81
                nsAtom* aPseudoTag,
82
                CSSPseudoElementType aPseudoType,
83
                ServoComputedDataForgotten aComputedValues);
84
85
  // FIXME(emilio, bug 548397): This will need to go away. Don't add new callers
86
  // of this methed.
87
0
  nsPresContext* PresContextForFrame() const { return mPresContext; }
88
0
  const ServoComputedData* ComputedData() const { return &mSource; }
89
90
  // These two methods are for use by ArenaRefPtr.
91
  //
92
  // FIXME(emilio): Think this can go away.
93
  static mozilla::ArenaObjectID ArenaObjectID()
94
0
  {
95
0
    return mozilla::eArenaObjectID_GeckoComputedStyle;
96
0
  }
97
  nsIPresShell* Arena();
98
99
0
  void AddRef() { Servo_ComputedStyle_AddRef(this); }
100
0
  void Release() { Servo_ComputedStyle_Release(this); }
101
102
  // Return the ComputedStyle whose style data should be used for the R,
103
  // G, and B components of color, background-color, and border-*-color
104
  // if RelevantLinkIsVisited().
105
  //
106
  // GetPseudo() and GetPseudoType() on this ComputedStyle return the
107
  // same as on |this|, and its depth in the tree (number of GetParent()
108
  // calls until null is returned) is the same as |this|, since its
109
  // parent is either |this|'s parent or |this|'s parent's
110
  // style-if-visited.
111
  //
112
  // Structs on this context should never be examined without also
113
  // examining the corresponding struct on |this|.  Doing so will likely
114
  // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
115
  // related to the Peek code in ComputedStyle::CalcStyleDifference.
116
  ComputedStyle* GetStyleIfVisited() const
117
0
  {
118
0
    return ComputedData()->visited_style.mPtr;
119
0
  }
120
121
  bool IsLazilyCascadedPseudoElement() const
122
0
  {
123
0
    return IsPseudoElement() &&
124
0
           !nsCSSPseudoElements::IsEagerlyCascadedInServo(GetPseudoType());
125
0
  }
126
127
0
  nsAtom* GetPseudo() const { return mPseudoTag; }
128
  mozilla::CSSPseudoElementType GetPseudoType() const
129
0
  {
130
0
    return mPseudoType;
131
0
  }
132
133
0
  bool IsInheritingAnonBox() const {
134
0
    return GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox;
135
0
  }
136
137
0
  bool IsNonInheritingAnonBox() const {
138
0
    return GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
139
0
  }
140
141
  // This function is rather slow; you probably don't want to use it outside
142
  // asserts unless you have to.  We _could_ add a new CSSPseudoElementType for
143
  // wrapper anon boxes, but that adds a bunch of complexity everywhere we
144
  // resolve anonymous box styles...
145
0
  bool IsWrapperAnonBox() const {
146
0
    return nsCSSAnonBoxes::IsWrapperAnonBox(GetPseudo());
147
0
  }
148
149
0
  bool IsAnonBox() const {
150
0
    return IsInheritingAnonBox() || IsNonInheritingAnonBox();
151
0
  }
152
153
0
  bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }
154
155
  // Does this ComputedStyle or any of its ancestors have text
156
  // decoration lines?
157
  // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
158
  // only the data for a single context.
159
  bool HasTextDecorationLines() const
160
0
  {
161
0
    return bool(mBits & Bit::HasTextDecorationLines);
162
0
  }
163
164
  // Whether any line break inside should be suppressed? If this returns
165
  // true, the line should not be broken inside, which means inlines act
166
  // as if nowrap is set, <br> is suppressed, and blocks are inlinized.
167
  // This bit is propogated to all children of line partitipants. It is
168
  // currently used by ruby to make its content frames unbreakable.
169
  // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak()
170
  // instead of this method.
171
  bool ShouldSuppressLineBreak() const
172
0
  {
173
0
    return bool(mBits & Bit::SuppressLineBreak);
174
0
  }
175
176
  // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is
177
  // only set on ComputedStyles whose pseudo is nsCSSAnonBoxes::mozText().
178
  bool IsTextCombined() const
179
0
  {
180
0
    return bool(mBits & Bit::IsTextCombined);
181
0
  }
182
183
  // Does this ComputedStyle represent the style for a pseudo-element or
184
  // inherit data from such a ComputedStyle?  Whether this returns true
185
  // is equivalent to whether it or any of its ancestors returns
186
  // non-null for IsPseudoElement().
187
  bool HasPseudoElementData() const
188
0
  {
189
0
    return bool(mBits & Bit::HasPseudoElementData);
190
0
  }
191
192
  // Is the only link whose visitedness is allowed to influence the
193
  // style of the node this ComputedStyle is for (which is that element
194
  // or its nearest ancestor that is a link) visited?
195
  bool RelevantLinkVisited() const
196
0
  {
197
0
    return bool(mBits & Bit::RelevantLinkVisited);
198
0
  }
199
200
  ComputedStyle* GetCachedInheritingAnonBoxStyle(nsAtom* aAnonBox) const
201
0
  {
202
0
    MOZ_ASSERT(nsCSSAnonBoxes::IsInheritingAnonBox(aAnonBox));
203
0
    return mCachedInheritingStyles.Lookup(aAnonBox);
204
0
  }
205
206
  void SetCachedInheritedAnonBoxStyle(nsAtom* aAnonBox, ComputedStyle* aStyle)
207
0
  {
208
0
    MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox));
209
0
    mCachedInheritingStyles.Insert(aStyle);
210
0
  }
211
212
  ComputedStyle* GetCachedLazyPseudoStyle(CSSPseudoElementType aPseudo) const;
213
214
  void SetCachedLazyPseudoStyle(ComputedStyle* aStyle)
215
0
  {
216
0
    MOZ_ASSERT(aStyle->GetPseudo() && !aStyle->IsAnonBox());
217
0
    MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType()));
218
0
    MOZ_ASSERT(!IsLazilyCascadedPseudoElement(), "lazy pseudos can't inherit lazy pseudos");
219
0
    MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement());
220
0
221
0
    // Since we're caching lazy pseudo styles on the ComputedValues of the
222
0
    // originating element, we can assume that we either have the same
223
0
    // originating element, or that they were at least similar enough to share
224
0
    // the same ComputedValues, which means that they would match the same
225
0
    // pseudo rules. This allows us to avoid matching selectors and checking
226
0
    // the rule node before deciding to share.
227
0
    //
228
0
    // The one place this optimization breaks is with pseudo-elements that
229
0
    // support state (like :hover). So we just avoid sharing in those cases.
230
0
    if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(aStyle->GetPseudoType())) {
231
0
      return;
232
0
    }
233
0
234
0
    mCachedInheritingStyles.Insert(aStyle);
235
0
  }
236
237
  /**
238
   * Define typesafe getter functions for each style struct by
239
   * preprocessing the list of style structs.  These functions are the
240
   * preferred way to get style data.  The macro creates functions like:
241
   *   const nsStyleBorder* StyleBorder();
242
   *   const nsStyleColor* StyleColor();
243
   */
244
  #define STYLE_STRUCT(name_) \
245
    inline const nsStyle##name_ * Style##name_() MOZ_NONNULL_RETURN;
246
  #include "nsStyleStructList.h"
247
  #undef STYLE_STRUCT
248
249
  /**
250
   * Equivalent to StyleFoo(), except that we skip the cache write during the
251
   * servo traversal. This can cause incorrect behavior if used improperly,
252
   * since we won't record that layout potentially depends on the values in
253
   * this style struct. Use with care.
254
   */
255
256
  #define STYLE_STRUCT(name_) \
257
    inline const nsStyle##name_ * ThreadsafeStyle##name_();
258
  #include "nsStyleStructList.h"
259
  #undef STYLE_STRUCT
260
261
262
  /**
263
   * PeekStyle* is like Style* but doesn't trigger style
264
   * computation if the data is not cached on either the ComputedStyle
265
   * or the rule node.
266
   *
267
   * Perhaps this shouldn't be a public ComputedStyle API.
268
   */
269
  #define STYLE_STRUCT(name_)  \
270
    inline const nsStyle##name_ * PeekStyle##name_();
271
  #include "nsStyleStructList.h"
272
  #undef STYLE_STRUCT
273
274
  /**
275
   * Compute the style changes needed during restyling when this style
276
   * context is being replaced by aNewContext.  (This is nonsymmetric since
277
   * we optimize by skipping comparison for styles that have never been
278
   * requested.)
279
   *
280
   * This method returns a change hint (see nsChangeHint.h).  All change
281
   * hints apply to the frame and its later continuations or ib-split
282
   * siblings.  Most (all of those except the "NotHandledForDescendants"
283
   * hints) also apply to all descendants.
284
   *
285
   * aEqualStructs must not be null.  Into it will be stored a bitfield
286
   * representing which structs were compared to be non-equal.
287
   *
288
   * CSS Variables are not compared here. Instead, the caller is responsible for
289
   * that when needed (basically only for elements).
290
   */
291
  nsChangeHint CalcStyleDifference(ComputedStyle* aNewContext,
292
                                   uint32_t* aEqualStructs);
293
294
public:
295
  /**
296
   * Get a color that depends on link-visitedness using this and
297
   * this->GetStyleIfVisited().
298
   *
299
   * @param aField A pointer to a member variable in a style struct.
300
   *               The member variable and its style struct must have
301
   *               been listed in nsCSSVisitedDependentPropList.h.
302
   */
303
  template<typename T, typename S>
304
  nscolor GetVisitedDependentColor(T S::* aField);
305
306
  /**
307
   * aColors should be a two element array of nscolor in which the first
308
   * color is the unvisited color and the second is the visited color.
309
   *
310
   * Combine the R, G, and B components of whichever of aColors should
311
   * be used based on aLinkIsVisited with the A component of aColors[0].
312
   */
313
  static nscolor CombineVisitedColors(nscolor* aColors, bool aLinkIsVisited);
314
315
  /**
316
   * Start the background image loads for this ComputedStyle.
317
   */
318
  inline void StartBackgroundImageLoads();
319
320
#ifdef DEBUG
321
  void List(FILE* out, int32_t aIndent);
322
  static const char* StructName(StyleStructID aSID);
323
  static Maybe<StyleStructID> LookupStruct(const nsACString& aName);
324
#endif
325
326
  /**
327
   * Makes this context match |aOther| in terms of which style structs have
328
   * been resolved.
329
   */
330
  inline void ResolveSameStructsAs(const ComputedStyle* aOther);
331
332
  // The |aCVsSize| outparam on this function is where the actual CVs size
333
  // value is added. It's done that way because the callers know which value
334
  // the size should be added to.
335
  void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aCVsSize) const;
336
337
protected:
338
  bool HasRequestedStruct(StyleStructID aID) const
339
0
  {
340
0
    return mRequestedStructs & StyleStructConstants::BitFor(aID);
341
0
  }
342
343
  void SetRequestedStruct(StyleStructID aID)
344
0
  {
345
0
    mRequestedStructs |= StyleStructConstants::BitFor(aID);
346
0
  }
347
348
  // Needs to be friend so that it can call the destructor without making it
349
  // public.
350
  friend void ::Gecko_ComputedStyle_Destroy(ComputedStyle*);
351
352
0
  ~ComputedStyle() = default;
353
354
  nsPresContext* const mPresContext;
355
356
  ServoComputedData mSource;
357
358
  // A cache of anonymous box and lazy pseudo styles inheriting from this style.
359
  CachedInheritingStyles mCachedInheritingStyles;
360
361
  // Helper functions for GetStyle* and PeekStyle*
362
  #define STYLE_STRUCT_INHERITED(name_)         \
363
    template<bool aComputeData>                 \
364
    const nsStyle##name_ * DoGetStyle##name_();
365
  #define STYLE_STRUCT_RESET(name_)             \
366
    template<bool aComputeData>                 \
367
    const nsStyle##name_ * DoGetStyle##name_();
368
369
  #include "nsStyleStructList.h"
370
  #undef STYLE_STRUCT_RESET
371
  #undef STYLE_STRUCT_INHERITED
372
373
  // If this ComputedStyle is for a pseudo-element or anonymous box,
374
  // the relevant atom.
375
  const RefPtr<nsAtom> mPseudoTag;
376
377
  // A bitfield with the structs that have been requested so far.
378
  uint32_t mRequestedStructs = 0;
379
  const Bit mBits;
380
  const CSSPseudoElementType mPseudoType;
381
};
382
383
} // namespace mozilla
384
385
#endif