tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsCSSPropertyIDSet.h (9446B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /* bit vectors for sets of CSS properties */
      6 
      7 #ifndef nsCSSPropertyIDSet_h__
      8 #define nsCSSPropertyIDSet_h__
      9 
     10 #include <limits.h>  // for CHAR_BIT
     11 
     12 #include <initializer_list>
     13 #include <ostream>
     14 
     15 #include "mozilla/ArrayUtils.h"
     16 // For COMPOSITOR_ANIMATABLE_PROPERTY_LIST and
     17 // COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH
     18 #include "NonCustomCSSPropertyId.h"
     19 #include "mozilla/CSSPropertyId.h"
     20 #include "mozilla/CompositorAnimatableProperties.h"
     21 #include "nsCSSProps.h"  // For operator<< for NonCustomCSSPropertyId
     22 
     23 /**
     24 * nsCSSPropertyIDSet maintains a set of non-shorthand CSS properties.  In
     25 * other words, for each longhand CSS property we support, it has a bit
     26 * for whether that property is in the set.
     27 */
     28 class nsCSSPropertyIDSet {
     29 public:
     30  constexpr nsCSSPropertyIDSet() : mProperties{0} {}
     31  // auto-generated copy-constructor OK
     32 
     33  explicit constexpr nsCSSPropertyIDSet(
     34      std::initializer_list<NonCustomCSSPropertyId> aProperties)
     35      : mProperties{0} {
     36    for (auto property : aProperties) {
     37      size_t p = property;
     38      mProperties[p / kBitsInChunk] |= property_set_type(1)
     39                                       << (p % kBitsInChunk);
     40    }
     41  }
     42 
     43  void AssertInSetRange(NonCustomCSSPropertyId aProperty) const {
     44    MOZ_DIAGNOSTIC_ASSERT(aProperty != eCSSProperty_UNKNOWN &&
     45                              aProperty < eCSSProperty_COUNT_no_shorthands,
     46                          "out of bounds");
     47  }
     48 
     49  // Conversion of aProperty to |size_t| after AssertInSetRange
     50  // lets the compiler generate significantly tighter code.
     51 
     52  void AddProperty(NonCustomCSSPropertyId aProperty) {
     53    AssertInSetRange(aProperty);
     54    size_t p = aProperty;
     55    mProperties[p / kBitsInChunk] |= property_set_type(1) << (p % kBitsInChunk);
     56  }
     57 
     58  void RemoveProperty(NonCustomCSSPropertyId aProperty) {
     59    AssertInSetRange(aProperty);
     60    size_t p = aProperty;
     61    mProperties[p / kBitsInChunk] &=
     62        ~(property_set_type(1) << (p % kBitsInChunk));
     63  }
     64 
     65  bool HasProperty(const mozilla::CSSPropertyId& aProperty) const {
     66    return !aProperty.IsCustom() && HasProperty(aProperty.mId);
     67  }
     68 
     69  bool HasProperty(NonCustomCSSPropertyId aProperty) const {
     70    AssertInSetRange(aProperty);
     71    size_t p = aProperty;
     72    return (mProperties[p / kBitsInChunk] &
     73            (property_set_type(1) << (p % kBitsInChunk))) != 0;
     74  }
     75 
     76  // Returns an nsCSSPropertyIDSet including all properties that can be run
     77  // on the compositor.
     78  static constexpr nsCSSPropertyIDSet CompositorAnimatables() {
     79    return nsCSSPropertyIDSet(COMPOSITOR_ANIMATABLE_PROPERTY_LIST);
     80  }
     81 
     82  static constexpr size_t CompositorAnimatableCount() {
     83    return COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH;
     84  }
     85 
     86  static constexpr size_t CompositorAnimatableDisplayItemCount() {
     87    // We have 3 individual transforms and 5 motion path properties, and they
     88    // also use DisplayItemType::TYPE_TRANSFORM.
     89    return COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH - 8;
     90  }
     91 
     92  static constexpr nsCSSPropertyIDSet CSSTransformProperties() {
     93    return nsCSSPropertyIDSet{eCSSProperty_transform, eCSSProperty_translate,
     94                              eCSSProperty_rotate, eCSSProperty_scale};
     95  }
     96 
     97  static constexpr nsCSSPropertyIDSet MotionPathProperties() {
     98    return nsCSSPropertyIDSet{
     99        eCSSProperty_offset_path, eCSSProperty_offset_distance,
    100        eCSSProperty_offset_rotate, eCSSProperty_offset_anchor,
    101        eCSSProperty_offset_position};
    102  }
    103 
    104  static constexpr nsCSSPropertyIDSet TransformLikeProperties() {
    105    return nsCSSPropertyIDSet{
    106        eCSSProperty_transform,      eCSSProperty_translate,
    107        eCSSProperty_rotate,         eCSSProperty_scale,
    108        eCSSProperty_offset_path,    eCSSProperty_offset_distance,
    109        eCSSProperty_offset_rotate,  eCSSProperty_offset_anchor,
    110        eCSSProperty_offset_position};
    111  }
    112 
    113  static constexpr nsCSSPropertyIDSet OpacityProperties() {
    114    return nsCSSPropertyIDSet{eCSSProperty_opacity};
    115  }
    116 
    117  bool Intersects(const nsCSSPropertyIDSet& aOther) const {
    118    for (size_t i = 0; i < std::size(mProperties); ++i) {
    119      if (mProperties[i] & aOther.mProperties[i]) {
    120        return true;
    121      }
    122    }
    123    return false;
    124  }
    125 
    126  void Empty() { memset(mProperties, 0, sizeof(mProperties)); }
    127 
    128  void AssertIsEmpty(const char* aText) const {
    129    for (size_t i = 0; i < std::size(mProperties); ++i) {
    130      NS_ASSERTION(mProperties[i] == 0, aText);
    131    }
    132  }
    133 
    134  bool Equals(const nsCSSPropertyIDSet& aOther) const {
    135    return mozilla::ArrayEqual(mProperties, aOther.mProperties);
    136  }
    137 
    138  bool IsEmpty() const {
    139    for (size_t i = 0; i < std::size(mProperties); ++i) {
    140      if (mProperties[i] != 0) {
    141        return false;
    142      }
    143    }
    144    return true;
    145  }
    146 
    147  bool IsSubsetOf(const nsCSSPropertyIDSet& aOther) const {
    148    return this->Intersect(aOther).Equals(*this);
    149  }
    150 
    151  // Returns a new nsCSSPropertyIDSet with all properties that are both in
    152  // this set and |aOther|.
    153  nsCSSPropertyIDSet Intersect(const nsCSSPropertyIDSet& aOther) const {
    154    nsCSSPropertyIDSet result;
    155    for (size_t i = 0; i < std::size(mProperties); ++i) {
    156      result.mProperties[i] = mProperties[i] & aOther.mProperties[i];
    157    }
    158    return result;
    159  }
    160 
    161  // Returns a new nsCSSPropertyIDSet with all properties that are in either
    162  // this set or |aOther| but not both.
    163  nsCSSPropertyIDSet Xor(const nsCSSPropertyIDSet& aOther) const {
    164    nsCSSPropertyIDSet result;
    165    for (size_t i = 0; i < std::size(mProperties); ++i) {
    166      result.mProperties[i] = mProperties[i] ^ aOther.mProperties[i];
    167    }
    168    return result;
    169  }
    170 
    171  nsCSSPropertyIDSet& operator|=(const nsCSSPropertyIDSet& aOther) {
    172    for (size_t i = 0; i < std::size(mProperties); ++i) {
    173      mProperties[i] |= aOther.mProperties[i];
    174    }
    175    return *this;
    176  }
    177 
    178 private:
    179  typedef unsigned long property_set_type;
    180 
    181 public:
    182  // number of bits in |property_set_type|.
    183  static const size_t kBitsInChunk = sizeof(property_set_type) * CHAR_BIT;
    184  // number of |property_set_type|s in the set
    185  static const size_t kChunkCount =
    186      (eCSSProperty_COUNT_no_shorthands + kBitsInChunk - 1) / kBitsInChunk;
    187 
    188  /*
    189   * For fast enumeration of all the bits that are set, callers can
    190   * check each chunk against zero (since in normal cases few bits are
    191   * likely to be set).
    192   */
    193  bool HasPropertyInChunk(size_t aChunk) const {
    194    return mProperties[aChunk] != 0;
    195  }
    196  bool HasPropertyAt(size_t aChunk, size_t aBit) const {
    197    return (mProperties[aChunk] & (property_set_type(1) << aBit)) != 0;
    198  }
    199  static NonCustomCSSPropertyId CSSPropertyAt(size_t aChunk, size_t aBit) {
    200    return NonCustomCSSPropertyId(aChunk * kBitsInChunk + aBit);
    201  }
    202 
    203  // Iterator for use in range-based for loops
    204  class Iterator {
    205   public:
    206    Iterator(Iterator&& aOther)
    207        : mPropertySet(aOther.mPropertySet),
    208          mChunk(aOther.mChunk),
    209          mBit(aOther.mBit) {}
    210 
    211    static Iterator BeginIterator(const nsCSSPropertyIDSet& aPropertySet) {
    212      Iterator result(aPropertySet);
    213 
    214      // Search for the first property.
    215      // Unsigned integer overflow is defined so the following is safe.
    216      result.mBit = -1;
    217      ++result;
    218 
    219      return result;
    220    }
    221 
    222    static Iterator EndIterator(const nsCSSPropertyIDSet& aPropertySet) {
    223      Iterator result(aPropertySet);
    224      result.mChunk = kChunkCount;
    225      result.mBit = 0;
    226      return result;
    227    }
    228 
    229    bool operator!=(const Iterator& aOther) const {
    230      return mChunk != aOther.mChunk || mBit != aOther.mBit;
    231    }
    232 
    233    Iterator& operator++() {
    234      MOZ_ASSERT(mChunk < kChunkCount, "Should not iterate beyond end");
    235 
    236      do {
    237        mBit++;
    238      } while (mBit < kBitsInChunk &&
    239               !mPropertySet.HasPropertyAt(mChunk, mBit));
    240      if (mBit != kBitsInChunk) {
    241        return *this;
    242      }
    243 
    244      do {
    245        mChunk++;
    246      } while (mChunk < kChunkCount &&
    247               !mPropertySet.HasPropertyInChunk(mChunk));
    248      mBit = 0;
    249      if (mChunk != kChunkCount) {
    250        while (mBit < kBitsInChunk &&
    251               !mPropertySet.HasPropertyAt(mChunk, mBit)) {
    252          mBit++;
    253        }
    254      }
    255 
    256      return *this;
    257    }
    258 
    259    NonCustomCSSPropertyId operator*() {
    260      MOZ_ASSERT(mChunk < kChunkCount, "Should not dereference beyond end");
    261      return nsCSSPropertyIDSet::CSSPropertyAt(mChunk, mBit);
    262    }
    263 
    264   private:
    265    explicit Iterator(const nsCSSPropertyIDSet& aPropertySet)
    266        : mPropertySet(aPropertySet) {}
    267 
    268    Iterator() = delete;
    269    Iterator(const Iterator&) = delete;
    270    Iterator& operator=(const Iterator&) = delete;
    271    Iterator& operator=(const Iterator&&) = delete;
    272 
    273    const nsCSSPropertyIDSet& mPropertySet;
    274    size_t mChunk = 0;
    275    size_t mBit = 0;
    276  };
    277 
    278  Iterator begin() const { return Iterator::BeginIterator(*this); }
    279  Iterator end() const { return Iterator::EndIterator(*this); }
    280 
    281 private:
    282  property_set_type mProperties[kChunkCount];
    283 };
    284 
    285 // MOZ_DBG support
    286 
    287 inline std::ostream& operator<<(std::ostream& aOut,
    288                                const nsCSSPropertyIDSet& aPropertySet) {
    289  AutoTArray<NonCustomCSSPropertyId, 16> properties;
    290  for (NonCustomCSSPropertyId property : aPropertySet) {
    291    properties.AppendElement(property);
    292  }
    293  return aOut << properties;
    294 }
    295 
    296 #endif /* !defined(nsCSSPropertyIDSet_h__) */