Bug 1273706 - Part 6: Add CSSProperty type for custom properties. r?heycam draft
authorJonathan Chan <jyc@eqv.io>
Mon, 15 Aug 2016 00:48:17 -0700
changeset 400594 6b4db8145ce8573168043360ed8454f9e19fdbfc
parent 400593 c6087ed10b3749457d64518489f7515289baea35
child 400595 b0ee16a654296ca4b0aefb162ec8682ab2a8cf1f
push id26211
push userjchan@mozilla.com
push dateMon, 15 Aug 2016 08:07:32 +0000
reviewersheycam
bugs1273706
milestone51.0a1
Bug 1273706 - Part 6: Add CSSProperty type for custom properties. r?heycam Add CSSProperty type to replace nsCSSPropertyID in places where we might want to represent custom properties. In particular, a later patch in this series will modify the animation code to use these where appropriate. A CSSProperty is a tagged union containing a nsCSSPropertyID or holding a reference to an nsIAtom corresponding to the custom property name, sans the leading --. MozReview-Commit-ID: 3bEXG3qCxHt
layout/style/CSSProperty.h
layout/style/moz.build
new file mode 100644
--- /dev/null
+++ b/layout/style/CSSProperty.h
@@ -0,0 +1,257 @@
+/* -*- 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/. */
+
+/* type for representing CSS properties (custom or 'fixed'/standard) */
+ 
+#ifndef mozilla_CSSProperty_h
+#define mozilla_CSSProperty_h
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Move.h"
+#include "mozilla/RefPtr.h"
+#include "nsCSSPropertyID.h"
+#include "nsCSSProps.h"
+#include "nsIAtom.h"
+#include "nsStyleStructFwd.h"
+
+namespace mozilla {
+
+/**
+ * A CSSProperty represents either a registered custom property or a standard
+ * CSS property. IsFixed() and AsFixed() check for and retrieve standard CSS
+ * properties, and IsCustom() and AsCustom() do the same for custom properties.
+ * Custom properties are encoded as atoms containing their names without the
+ * leading '--', while standard properties are represented by nsCSSProperty.
+ */
+class CSSProperty
+{
+private:
+  enum State : uint8_t {
+    Invalid,
+    Fixed,
+    Custom,
+  };
+
+public:
+  CSSProperty()
+    : mState(State::Invalid)
+  {
+  }
+
+  explicit CSSProperty(nsCSSPropertyID aProperty)
+    : mState(State::Fixed)
+    , mFixed(aProperty)
+  {
+  }
+
+  explicit CSSProperty(nsIAtom* aProperty)
+    : mState(State::Custom)
+    , mCustom(aProperty)
+  {
+    mCustom->AddRef();
+  }
+
+  explicit CSSProperty(already_AddRefed<nsIAtom> aProperty)
+    : mState(State::Custom)
+    , mCustom(aProperty.take())
+  {
+  }
+
+  CSSProperty(const CSSProperty& aOther)
+    : mState(aOther.mState)
+  {
+    if (mState == State::Custom) {
+      mCustom = aOther.mCustom;
+      mCustom->AddRef();
+    } else {
+      mFixed = aOther.mFixed;
+    }
+  }
+
+  CSSProperty(CSSProperty&& aOther)
+    : mState(State::Invalid)
+  {
+    *this = aOther;
+  }
+
+  CSSProperty& operator=(const CSSProperty& aOther)
+  {
+    CSSProperty copy(aOther);
+    *this = Move(copy);
+    return *this;
+  }
+
+  CSSProperty& operator=(CSSProperty&& aOther)
+  {
+    if (mState == State::Custom) {
+      mCustom->Release();
+    }
+    mState = aOther.mState;
+    if (mState == State::Custom) {
+      mCustom = aOther.mCustom;
+      // Don't want double-frees.
+      aOther.mCustom = nullptr;
+      aOther.mState = State::Invalid;
+    } else {
+      mFixed = aOther.mFixed;
+    }
+    return *this;
+  }
+
+  bool operator==(const CSSProperty& aOther) const
+  {
+    MOZ_ASSERT(mState != State::Invalid &&
+               aOther.mState != State::Invalid);
+    if (mState == State::Custom) {
+      return aOther.mState == State::Custom &&
+             mCustom == aOther.mCustom;
+    } else {
+      return mFixed == aOther.mFixed;
+    }
+  }
+
+  bool operator!=(const CSSProperty& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool operator==(const nsCSSPropertyID& aOther) const
+  {
+    MOZ_ASSERT(mState != State::Invalid);
+    return mState == State::Fixed &&
+           mFixed == aOther;
+  }
+
+  bool operator!=(const nsCSSPropertyID& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool operator==(nsIAtom* aOther) const
+  {
+    MOZ_ASSERT(mState != State::Invalid);
+    return mState == State::Custom &&
+           mCustom == aOther;
+  }
+
+  bool operator!=(nsIAtom* aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  ~CSSProperty()
+  {
+    if (mState == State::Custom) {
+      mCustom->Release();
+    }
+  }
+
+  bool IsFixed() const
+  {
+    MOZ_ASSERT(mState != State::Invalid);
+    return mState == State::Fixed;
+  }
+
+  bool IsCustom() const
+  {
+    MOZ_ASSERT(mState != State::Invalid);
+    return mState == State::Custom;
+  }
+
+  nsCSSPropertyID AsFixed() const
+  {
+    MOZ_ASSERT(mState == State::Fixed);
+    return mFixed;
+  }
+
+  nsIAtom* AsCustom() const
+  {
+    MOZ_ASSERT(mState == State::Custom);
+    return mCustom;
+  }
+
+  /**
+   * GetStyleStructID returns the nsStyleStructID corresponding to this
+   * property. Custom properties always have style struct ID
+   * eStyleStruct_Variables.
+   */
+  nsStyleStructID GetStyleStructID() const
+  {
+    switch (mState) {
+    case State::Invalid:
+      MOZ_ASSERT(false);
+      break;
+    case State::Fixed:
+      return nsCSSProps::kSIDTable[mFixed];
+    case State::Custom:
+      return eStyleStruct_Variables;
+    }
+    return nsStyleStructID_None;
+  }
+
+  /**
+   * ToString converts this property into its CSS property name.
+   * Custom properties have '--' prefixed.
+   */
+  void ToString(nsAString& aString) const
+  {
+    aString.Truncate(0);
+    switch (mState) {
+    case State::Invalid:
+      MOZ_ASSERT(false);
+      break;
+    case State::Fixed:
+      aString = NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(mFixed));
+      break;
+    case State::Custom:
+      nsAutoString name;
+      mCustom->ToString(name);
+      aString.AppendLiteral("--");
+      aString.Append(name);
+      break;
+    }
+  }
+
+  /**
+   * IsShorthand returns true iff this represents a fixed shorthand property.
+   * Custom properties are never shorthands.
+   */
+  bool IsShorthand() const
+  {
+    MOZ_ASSERT(mState != State::Invalid);
+    if (mState == State::Custom) {
+      return false;
+    }
+    return nsCSSProps::IsShorthand(mFixed);
+  }
+
+  /**
+   * IsCustomLessThan returns true iff this and aOther are custom properties
+   * and the custom property name for this property is less than (according to
+   * nsString::operator<) aOther's custom property name. It is an error to call
+   * IsCustomLessThan if this or aOther do not represent custom properties.
+   */
+  bool IsCustomLessThan(const CSSProperty& aOther) const
+  {
+    MOZ_ASSERT(mState == State::Custom &&
+               aOther.mState == State::Custom);
+    nsString left;
+    nsString right;
+    mCustom->ToString(left);
+    aOther.mCustom->ToString(right);
+    return left < right;
+  }
+
+private:
+  State mState;
+  union {
+    nsCSSPropertyID mFixed;
+    nsIAtom* mCustom;
+  };
+};
+
+} // namespace mozilla
+
+#endif // mozilla_CSSProperty_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -77,16 +77,17 @@ EXPORTS += [
     'nsStyleStructInlines.h',
     'nsStyleTransformMatrix.h',
     'nsStyleUtil.h',
 ]
 
 EXPORTS.mozilla += [
     'AnimationCollection.h',
     'CSSEnabledState.h',
+    'CSSProperty.h',
     'CSSStyleSheet.h',
     'CSSVariableDeclarations.h',
     'CSSVariableResolver.h',
     'CSSVariableValues.h',
     'HandleRefPtr.h',
     'IncrementalClearCOMRuleArray.h',
     'LayerAnimationInfo.h',
     'RuleNodeCacheConditions.h',