Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/ServoElementSnapshot.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
#ifndef mozilla_ServoElementSnapshot_h
8
#define mozilla_ServoElementSnapshot_h
9
10
#include "mozilla/EventStates.h"
11
#include "mozilla/TypedEnumBits.h"
12
#include "mozilla/dom/BorrowedAttrInfo.h"
13
#include "mozilla/dom/Element.h"
14
#include "nsAttrName.h"
15
#include "nsAttrValue.h"
16
#include "nsChangeHint.h"
17
#include "nsGkAtoms.h"
18
#include "nsAtom.h"
19
20
namespace mozilla {
21
22
/**
23
 * A bitflags enum class used to determine what data does a ServoElementSnapshot
24
 * contains.
25
 */
26
enum class ServoElementSnapshotFlags : uint8_t
27
{
28
  State = 1 << 0,
29
  Attributes = 1 << 1,
30
  Id = 1 << 2,
31
  MaybeClass = 1 << 3,
32
  OtherPseudoClassState = 1 << 4,
33
};
34
35
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoElementSnapshotFlags)
36
37
/**
38
 * This class holds all non-tree-structural state of an element that might be
39
 * used for selector matching eventually.
40
 *
41
 * This means the attributes, and the element state, such as :hover, :active,
42
 * etc...
43
 */
44
class ServoElementSnapshot
45
{
46
  typedef dom::BorrowedAttrInfo BorrowedAttrInfo;
47
  typedef dom::Element Element;
48
  typedef EventStates::ServoType ServoStateType;
49
50
public:
51
  typedef ServoElementSnapshotFlags Flags;
52
53
  explicit ServoElementSnapshot(const Element&);
54
55
  ~ServoElementSnapshot()
56
0
  {
57
0
    MOZ_ASSERT(NS_IsMainThread());
58
0
    MOZ_COUNT_DTOR(ServoElementSnapshot);
59
0
  }
60
61
0
  bool HasAttrs() const { return HasAny(Flags::Attributes); }
62
63
0
  bool HasState() const { return HasAny(Flags::State); }
64
65
  bool HasOtherPseudoClassState() const
66
0
  {
67
0
    return HasAny(Flags::OtherPseudoClassState);
68
0
  }
69
70
  /**
71
   * Captures the given state (if not previously captured).
72
   */
73
  void AddState(EventStates aState)
74
0
  {
75
0
    if (!HasAny(Flags::State)) {
76
0
      mState = aState.ServoValue();
77
0
      mContains |= Flags::State;
78
0
    }
79
0
  }
80
81
  /**
82
   * Captures the given element attributes (if not previously captured).
83
   *
84
   * The attribute name and namespace are used to note which kind of attribute
85
   * has changed.
86
   */
87
  inline void AddAttrs(const Element&, int32_t aNameSpaceID, nsAtom* aAttribute);
88
89
  /**
90
   * Captures some other pseudo-class matching state not included in
91
   * EventStates.
92
   */
93
  void AddOtherPseudoClassState(const Element&);
94
95
  /**
96
   * Needed methods for attribute matching.
97
   */
98
  BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const
99
0
  {
100
0
    MOZ_ASSERT(HasAttrs());
101
0
    if (aIndex >= mAttrs.Length()) {
102
0
      return BorrowedAttrInfo(nullptr, nullptr);
103
0
    }
104
0
    return BorrowedAttrInfo(&mAttrs[aIndex].mName, &mAttrs[aIndex].mValue);
105
0
  }
106
107
  const nsAttrValue* GetParsedAttr(nsAtom* aLocalName) const
108
0
  {
109
0
    return GetParsedAttr(aLocalName, kNameSpaceID_None);
110
0
  }
111
112
  const nsAttrValue* GetParsedAttr(nsAtom* aLocalName,
113
                                   int32_t aNamespaceID) const
114
0
  {
115
0
    MOZ_ASSERT(HasAttrs());
116
0
    uint32_t i, len = mAttrs.Length();
117
0
    if (aNamespaceID == kNameSpaceID_None) {
118
0
      // This should be the common case so lets make an optimized loop
119
0
      for (i = 0; i < len; ++i) {
120
0
        if (mAttrs[i].mName.Equals(aLocalName)) {
121
0
          return &mAttrs[i].mValue;
122
0
        }
123
0
      }
124
0
125
0
      return nullptr;
126
0
    }
127
0
128
0
    for (i = 0; i < len; ++i) {
129
0
      if (mAttrs[i].mName.Equals(aLocalName, aNamespaceID)) {
130
0
        return &mAttrs[i].mValue;
131
0
      }
132
0
    }
133
0
134
0
    return nullptr;
135
0
  }
136
137
0
  bool IsInChromeDocument() const { return mIsInChromeDocument; }
138
0
  bool SupportsLangAttr() const { return mSupportsLangAttr; }
139
140
0
  bool HasAny(Flags aFlags) const { return bool(mContains & aFlags); }
141
142
  bool IsTableBorderNonzero() const
143
0
  {
144
0
    MOZ_ASSERT(HasOtherPseudoClassState());
145
0
    return mIsTableBorderNonzero;
146
0
  }
147
148
  bool IsMozBrowserFrame() const
149
0
  {
150
0
    MOZ_ASSERT(HasOtherPseudoClassState());
151
0
    return mIsMozBrowserFrame;
152
0
  }
153
154
private:
155
  // TODO: Profile, a 1 or 2 element AutoTArray could be worth it, given we know
156
  // we're dealing with attribute changes when we take snapshots of attributes,
157
  // though it can be wasted space if we deal with a lot of state-only
158
  // snapshots.
159
  nsTArray<AttrArray::InternalAttr> mAttrs;
160
  nsAttrValue mClass;
161
  ServoStateType mState;
162
  Flags mContains;
163
  bool mIsHTMLElementInHTMLDocument : 1;
164
  bool mIsInChromeDocument : 1;
165
  bool mSupportsLangAttr : 1;
166
  bool mIsTableBorderNonzero : 1;
167
  bool mIsMozBrowserFrame : 1;
168
  bool mClassAttributeChanged : 1;
169
  bool mIdAttributeChanged : 1;
170
  bool mOtherAttributeChanged : 1;
171
};
172
173
174
inline void
175
ServoElementSnapshot::AddAttrs(const Element& aElement,
176
                               int32_t aNameSpaceID,
177
                               nsAtom* aAttribute)
178
0
{
179
0
  if (aNameSpaceID == kNameSpaceID_None) {
180
0
    if (aAttribute == nsGkAtoms::_class) {
181
0
      mClassAttributeChanged = true;
182
0
    } else if (aAttribute == nsGkAtoms::id) {
183
0
      mIdAttributeChanged = true;
184
0
    } else {
185
0
      mOtherAttributeChanged = true;
186
0
    }
187
0
  } else {
188
0
    mOtherAttributeChanged = true;
189
0
  }
190
0
191
0
  if (HasAttrs()) {
192
0
    return;
193
0
  }
194
0
195
0
  uint32_t attrCount = aElement.GetAttrCount();
196
0
  mAttrs.SetCapacity(attrCount);
197
0
  for (uint32_t i = 0; i < attrCount; ++i) {
198
0
    const BorrowedAttrInfo info = aElement.GetAttrInfoAt(i);
199
0
    MOZ_ASSERT(info);
200
0
    mAttrs.AppendElement(AttrArray::InternalAttr { *info.mName, *info.mValue });
201
0
  }
202
0
203
0
  mContains |= Flags::Attributes;
204
0
  if (aElement.HasID()) {
205
0
    mContains |= Flags::Id;
206
0
  }
207
0
208
0
  if (const nsAttrValue* classValue = aElement.GetClasses()) {
209
0
    // FIXME(emilio): It's pretty unfortunate that this is only relevant for
210
0
    // SVG, yet it's a somewhat expensive copy. We should be able to do
211
0
    // better!
212
0
    mClass = *classValue;
213
0
    mContains |= Flags::MaybeClass;
214
0
  }
215
0
}
216
217
} // namespace mozilla
218
219
#endif