summaryrefslogtreecommitdiffstats
path: root/layout/style/StyleContextSource.h
blob: 7c6a0073044915bc9407c3ebe79d85c2e6b36881 (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
/* -*- 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/. */

#ifndef mozilla_StyleContextSource_h
#define mozilla_StyleContextSource_h

#include "mozilla/ServoBindingTypes.h"
#include "nsRuleNode.h"

namespace mozilla {

// Tagged union between Gecko Rule Nodes and Servo Computed Values.
//
// The rule node is the node in the lexicographic tree of rule nodes
// (the "rule tree") that indicates which style rules are used to
// compute the style data, and in what cascading order.  The least
// specific rule matched is the one whose rule node is a child of the
// root of the rule tree, and the most specific rule matched is the
// |mRule| member of the rule node.
//
// In the Servo case, we hold an atomically-refcounted handle to a
// Servo ComputedValues struct, which is more or less the Servo equivalent
// of an nsStyleContext.

// Underlying pointer without any strong ownership semantics.
struct NonOwningStyleContextSource
{
  MOZ_IMPLICIT NonOwningStyleContextSource(nsRuleNode* aRuleNode)
    : mBits(reinterpret_cast<uintptr_t>(aRuleNode)) {}
  explicit NonOwningStyleContextSource(const ServoComputedValues* aComputedValues)
    : mBits(reinterpret_cast<uintptr_t>(aComputedValues) | 1) {}

  bool operator==(const NonOwningStyleContextSource& aOther) const {
    MOZ_ASSERT(IsServoComputedValues() == aOther.IsServoComputedValues(),
               "Comparing Servo to Gecko - probably a bug");
    return mBits == aOther.mBits;
  }
  bool operator!=(const NonOwningStyleContextSource& aOther) const {
    return !(*this == aOther);
  }

  // We intentionally avoid exposing IsGeckoRuleNode() here, because that would
  // encourage callers to do:
  //
  // if (source.IsGeckoRuleNode()) {
  //   // Code that we would run unconditionally if it weren't for Servo.
  // }
  //
  // We want these branches to compile away when MOZ_STYLO is disabled, but that
  // won't happen if there's an implicit null-check.
  bool IsNull() const { return !mBits; }
  bool IsGeckoRuleNodeOrNull() const { return !IsServoComputedValues(); }
  bool IsServoComputedValues() const {
#ifdef MOZ_STYLO
    return mBits & 1;
#else
    return false;
#endif
  }

  nsRuleNode* AsGeckoRuleNode() const {
    MOZ_ASSERT(IsGeckoRuleNodeOrNull() && !IsNull());
    return reinterpret_cast<nsRuleNode*>(mBits);
  }

  const ServoComputedValues* AsServoComputedValues() const {
    MOZ_ASSERT(IsServoComputedValues());
    return reinterpret_cast<ServoComputedValues*>(mBits & ~1);
  }

  bool MatchesNoRules() const {
    if (IsGeckoRuleNodeOrNull()) {
      return AsGeckoRuleNode()->IsRoot();
    }

    // Just assume a Servo-backed StyleContextSource always matches some rules.
    //
    // MatchesNoRules is used to ensure style contexts that match no rules
    // go into a separate mEmptyChild list on their parent.  This is only used
    // as an optimization so that calling FindChildWithRules for style context
    // sharing is faster for text nodes (which match no rules, and are common).
    // Since Servo will handle sharing for us, there's no need to split children
    // into two lists.
    return false;
  }

private:
  uintptr_t mBits;
};

// Higher-level struct that owns a strong reference to the source. The source
// is never null.
struct OwningStyleContextSource
{
  explicit OwningStyleContextSource(already_AddRefed<nsRuleNode> aRuleNode)
    : mRaw(aRuleNode.take())
  {
    MOZ_COUNT_CTOR(OwningStyleContextSource);
    MOZ_ASSERT(!mRaw.IsNull());
  };

  explicit OwningStyleContextSource(already_AddRefed<ServoComputedValues> aComputedValues)
    : mRaw(aComputedValues.take())
  {
    MOZ_COUNT_CTOR(OwningStyleContextSource);
    MOZ_ASSERT(!mRaw.IsNull());
  }

  OwningStyleContextSource(OwningStyleContextSource&& aOther)
    : mRaw(aOther.mRaw)
  {
    MOZ_COUNT_CTOR(OwningStyleContextSource);
    aOther.mRaw = nullptr;
  }

  OwningStyleContextSource& operator=(OwningStyleContextSource&) = delete;
  OwningStyleContextSource(OwningStyleContextSource&) = delete;

  ~OwningStyleContextSource() {
    MOZ_COUNT_DTOR(OwningStyleContextSource);
    if (mRaw.IsNull()) {
      // We must have invoked the move constructor.
    } else if (IsGeckoRuleNode()) {
      RefPtr<nsRuleNode> releaseme = dont_AddRef(AsGeckoRuleNode());
    } else {
      MOZ_ASSERT(IsServoComputedValues());
      RefPtr<ServoComputedValues> releaseme =
        dont_AddRef(AsServoComputedValues());
    }
  }

  bool operator==(const OwningStyleContextSource& aOther) const {
    return mRaw == aOther.mRaw;
  }
  bool operator!=(const OwningStyleContextSource& aOther) const {
    return !(*this == aOther);
  }
  bool IsNull() const { return mRaw.IsNull(); }
  bool IsGeckoRuleNode() const {
    MOZ_ASSERT(!mRaw.IsNull());
    return mRaw.IsGeckoRuleNodeOrNull();
  }
  bool IsServoComputedValues() const { return mRaw.IsServoComputedValues(); }

  NonOwningStyleContextSource AsRaw() const { return mRaw; }
  nsRuleNode* AsGeckoRuleNode() const { return mRaw.AsGeckoRuleNode(); }
  ServoComputedValues* AsServoComputedValues() const {
    return const_cast<ServoComputedValues*>(mRaw.AsServoComputedValues());
  }

  bool MatchesNoRules() const { return mRaw.MatchesNoRules(); }

private:
  NonOwningStyleContextSource mRaw;
};

} // namespace mozilla

#endif // mozilla_StyleContextSource_h