layout/style/CounterStyleManager.h
author Xianzhu Wang <wangxianzhu@chromium.org>
Tue, 05 Mar 2019 12:18:01 +0000
changeset 464575 4325ba7b38576495a78289c2a8f4dff391922e66
parent 456576 43a3aa2199c12427c9784a9cdbb89f76cf1296a5
child 474084 d81e4aa6bf0c5701bf5369b4f764caa09cf803ea
permissions -rw-r--r--
Bug 1529059 [wpt PR 15420] - [BlinkGenPropertyTrees] Initiailize double_sided of synthetic effect, a=testonly Automatic update from web-platform-tests [BlinkGenPropertyTrees] Initiailize double_sided of synthetic effect Previously synthetic effects always had double_sided==false, causing the layer disappear when the backface was facing forward. Bug: 928190 Change-Id: I35534b40346d5c5918bc99c00a4ca6b4e3b68796 Reviewed-on: https://chromium-review.googlesource.com/c/1475815 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org> Cr-Commit-Position: refs/heads/master@{#632764} -- wpt-commits: a89467050deaf1dcbd9140a2f0670b1b85e518ee wpt-pr: 15420

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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_CounterStyleManager_h_
#define mozilla_CounterStyleManager_h_

#include "nsAtom.h"
#include "nsGkAtoms.h"
#include "nsStringFwd.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"

#include "nsStyleConsts.h"

#include "mozilla/Attributes.h"

#include "nsCSSValue.h"

class nsPresContext;

namespace mozilla {

class WritingMode;

typedef int32_t CounterValue;

class CounterStyleManager;
class AnonymousCounterStyle;

struct NegativeType;
struct PadType;

class CounterStyle {
 protected:
  explicit constexpr CounterStyle(int32_t aStyle) : mStyle(aStyle) {}

 private:
  CounterStyle(const CounterStyle& aOther) = delete;
  void operator=(const CounterStyle& other) = delete;

 public:
  constexpr int32_t GetStyle() const { return mStyle; }
  bool IsNone() const { return mStyle == NS_STYLE_LIST_STYLE_NONE; }
  bool IsCustomStyle() const { return mStyle == NS_STYLE_LIST_STYLE_CUSTOM; }
  // A style is dependent if it depends on the counter style manager.
  // Custom styles are certainly dependent. In addition, some builtin
  // styles are dependent for fallback.
  bool IsDependentStyle() const;

  virtual void GetPrefix(nsAString& aResult) = 0;
  virtual void GetSuffix(nsAString& aResult) = 0;
  void GetCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
                      nsAString& aResult, bool& aIsRTL);
  virtual void GetSpokenCounterText(CounterValue aOrdinal,
                                    WritingMode aWritingMode,
                                    nsAString& aResult, bool& aIsBullet);

  // XXX This method could be removed once ::-moz-list-bullet and
  //     ::-moz-list-number are completely merged into ::marker.
  virtual bool IsBullet() = 0;

  virtual void GetNegative(NegativeType& aResult) = 0;
  /**
   * This method returns whether an ordinal is in the range of this
   * counter style. Note that, it is possible that an ordinal in range
   * is rejected by the generating algorithm.
   */
  virtual bool IsOrdinalInRange(CounterValue aOrdinal) = 0;
  /**
   * This method returns whether an ordinal is in the default range of
   * this counter style. This is the effective range when no 'range'
   * descriptor is specified.
   */
  virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) = 0;
  virtual void GetPad(PadType& aResult) = 0;
  virtual CounterStyle* GetFallback() = 0;
  virtual uint8_t GetSpeakAs() = 0;
  virtual bool UseNegativeSign() = 0;

  virtual void CallFallbackStyle(CounterValue aOrdinal,
                                 WritingMode aWritingMode, nsAString& aResult,
                                 bool& aIsRTL);
  virtual bool GetInitialCounterText(CounterValue aOrdinal,
                                     WritingMode aWritingMode,
                                     nsAString& aResult, bool& aIsRTL) = 0;

  virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; }

 protected:
  const int32_t mStyle;
};

class AnonymousCounterStyle final : public CounterStyle {
 public:
  explicit AnonymousCounterStyle(const nsAString& aContent);
  AnonymousCounterStyle(uint8_t aSystem, nsTArray<nsString> aSymbols);
  explicit AnonymousCounterStyle(const nsCSSValue::Array* aValue);

  virtual void GetPrefix(nsAString& aResult) override;
  virtual void GetSuffix(nsAString& aResult) override;
  virtual bool IsBullet() override;

  virtual void GetNegative(NegativeType& aResult) override;
  virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
  virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
  virtual void GetPad(PadType& aResult) override;
  virtual CounterStyle* GetFallback() override;
  virtual uint8_t GetSpeakAs() override;
  virtual bool UseNegativeSign() override;

  virtual bool GetInitialCounterText(CounterValue aOrdinal,
                                     WritingMode aWritingMode,
                                     nsAString& aResult, bool& aIsRTL) override;

  virtual AnonymousCounterStyle* AsAnonymous() override { return this; }

  bool IsSingleString() const { return mSingleString; }
  uint8_t GetSystem() const { return mSystem; }
  const nsTArray<nsString>& GetSymbols() const { return mSymbols; }

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)

 private:
  ~AnonymousCounterStyle() {}

  bool mSingleString;
  uint8_t mSystem;
  nsTArray<nsString> mSymbols;
};

// A smart pointer to CounterStyle. It either owns a reference to an
// anonymous counter style, or weakly refers to a named counter style
// managed by counter style manager.
class CounterStylePtr {
 public:
  CounterStylePtr() : mRaw(0) {}
  CounterStylePtr(const CounterStylePtr& aOther) : mRaw(aOther.mRaw) {
    if (!mRaw) {
      return;
    }
    switch (GetType()) {
      case eAnonymousCounterStyle:
        AsAnonymous()->AddRef();
        break;
      case eAtom:
        AsAtom()->AddRef();
        break;
      default:
        MOZ_ASSERT_UNREACHABLE("Unknown type");
        break;
    }
  }
  CounterStylePtr(CounterStylePtr&& aOther) : mRaw(aOther.mRaw) {
    aOther.mRaw = 0;
  }
  ~CounterStylePtr() { Reset(); }

  CounterStylePtr& operator=(const CounterStylePtr& aOther) {
    if (this != &aOther) {
      Reset();
      new (this) CounterStylePtr(aOther);
    }
    return *this;
  }
  CounterStylePtr& operator=(CounterStylePtr&& aOther) {
    if (this != &aOther) {
      Reset();
      mRaw = aOther.mRaw;
      aOther.mRaw = 0;
    }
    return *this;
  }
  CounterStylePtr& operator=(decltype(nullptr)) {
    Reset();
    return *this;
  }
  CounterStylePtr& operator=(nsStaticAtom* aStaticAtom) {
    Reset();
    mRaw = reinterpret_cast<uintptr_t>(aStaticAtom) | eAtom;
    return *this;
  }
  CounterStylePtr& operator=(already_AddRefed<nsAtom> aAtom) {
    Reset();
    mRaw = reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom;
    return *this;
  }
  CounterStylePtr& operator=(AnonymousCounterStyle* aCounterStyle) {
    Reset();
    if (aCounterStyle) {
      CounterStyle* raw = do_AddRef(aCounterStyle).take();
      mRaw = reinterpret_cast<uintptr_t>(raw) | eAnonymousCounterStyle;
    }
    return *this;
  }

  explicit operator bool() const { return !!mRaw; }
  bool operator!() const { return !mRaw; }
  bool operator==(const CounterStylePtr& aOther) const {
    // FIXME(emilio): For atoms this is all right, but for symbols doesn't this
    // cause us to compare as unequal all the time, even if the specified
    // symbols didn't change?
    return mRaw == aOther.mRaw;
  }
  bool operator!=(const CounterStylePtr& aOther) const {
    return mRaw != aOther.mRaw;
  }

  nsAtom* AsAtom() const {
    MOZ_ASSERT(IsAtom());
    return reinterpret_cast<nsAtom*>(mRaw & ~eMask);
  }
  AnonymousCounterStyle* AsAnonymous() const {
    MOZ_ASSERT(IsAnonymous());
    return static_cast<AnonymousCounterStyle*>(
        reinterpret_cast<CounterStyle*>(mRaw & ~eMask));
  }

  bool IsAtom() const { return GetType() == eAtom; }
  bool IsAnonymous() const { return GetType() == eAnonymousCounterStyle; }

  bool IsNone() const { return IsAtom() && AsAtom() == nsGkAtoms::none; }

 private:
  enum Type : uintptr_t {
    eAnonymousCounterStyle = 0,
    eAtom = 1,
    eMask = 1,
  };

  static_assert(alignof(CounterStyle) >= 1 << eMask,
                "We're gonna tag the pointer, so it better fit");
  static_assert(alignof(nsAtom) >= 1 << eMask,
                "We're gonna tag the pointer, so it better fit");

  Type GetType() const { return static_cast<Type>(mRaw & eMask); }

  void Reset() {
    if (!mRaw) {
      return;
    }
    switch (GetType()) {
      case eAnonymousCounterStyle:
        AsAnonymous()->Release();
        break;
      case eAtom:
        AsAtom()->Release();
        break;
      default:
        MOZ_ASSERT_UNREACHABLE("Unknown type");
        break;
    }
    mRaw = 0;
  }

  // mRaw contains the pointer, and its last bit is used to store the type of
  // the pointer.
  // If the type is eAtom, the pointer owns a reference to an nsAtom
  // (potentially null).
  // If the type is eAnonymousCounterStyle, it owns a reference to an
  // anonymous counter style (never null).
  uintptr_t mRaw;
};

class CounterStyleManager final {
 private:
  ~CounterStyleManager();

 public:
  explicit CounterStyleManager(nsPresContext* aPresContext);

  void Disconnect();

  bool IsInitial() const {
    // only 'none', 'decimal', and 'disc'
    return mStyles.Count() == 3;
  }

  // Returns the counter style object for the given name from the style
  // table if it is already built, and nullptr otherwise.
  CounterStyle* GetCounterStyle(nsAtom* aName) const {
    return mStyles.Get(aName);
  }
  // Same as GetCounterStyle but try to build the counter style object
  // rather than returning nullptr if that hasn't been built.
  CounterStyle* ResolveCounterStyle(nsAtom* aName);
  CounterStyle* ResolveCounterStyle(const CounterStylePtr& aPtr) {
    if (aPtr.IsAtom()) {
      return ResolveCounterStyle(aPtr.AsAtom());
    }
    return aPtr.AsAnonymous();
  }

  static CounterStyle* GetBuiltinStyle(int32_t aStyle);
  static CounterStyle* GetNoneStyle() {
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_NONE);
  }
  static CounterStyle* GetDecimalStyle() {
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DECIMAL);
  }
  static CounterStyle* GetDiscStyle() {
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DISC);
  }

  // This method will scan all existing counter styles generated by this
  // manager, and remove or mark data dirty accordingly. It returns true
  // if any counter style is changed, false elsewise. This method should
  // be called when any counter style may be affected.
  bool NotifyRuleChanged();
  // NotifyRuleChanged will evict no longer needed counter styles into
  // mRetiredStyles, and this function destroys all objects listed there.
  // It should be called only after no one may ever use those objects.
  void CleanRetiredStyles();

  nsPresContext* PresContext() const { return mPresContext; }

  NS_INLINE_DECL_REFCOUNTING(CounterStyleManager)

 private:
  void DestroyCounterStyle(CounterStyle* aCounterStyle);

  nsPresContext* mPresContext;
  nsDataHashtable<nsRefPtrHashKey<nsAtom>, CounterStyle*> mStyles;
  nsTArray<CounterStyle*> mRetiredStyles;
};

}  // namespace mozilla

#endif /* !defined(mozilla_CounterStyleManager_h_) */