DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d38398e5144e)

VCS Links

NonOwningStyleContextSource

OwningStyleContextSource

Macros

Line Code
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