diff options
Diffstat (limited to 'layout/style/StyleContextSource.h')
-rw-r--r-- | layout/style/StyleContextSource.h | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/layout/style/StyleContextSource.h b/layout/style/StyleContextSource.h new file mode 100644 index 000000000..7c6a00730 --- /dev/null +++ b/layout/style/StyleContextSource.h @@ -0,0 +1,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 |