Bug 1224918 part 1 - Make SetDiscrete more type-safe and easy to use with enum classes. r=dbaron
authorXidorn Quan <quanxunzhen@gmail.com>
Tue, 24 Nov 2015 11:44:40 +1100
changeset 339313 4e6d4982db0ba1ecb9eca96aad9db606a9714f47
parent 339312 8e8ef068956be4badbd8c75488145eaadd0756f1
child 339314 1f8b79672ffe480a2414844e398ab3101336e0fa
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1224918
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1224918 part 1 - Make SetDiscrete more type-safe and easy to use with enum classes. r=dbaron MozReview-Commit-ID: 591zyIlPxKh
layout/style/nsRuleNode.cpp
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -12,16 +12,17 @@
 #include <algorithm>
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
 #include "mozilla/Likely.h"
 #include "mozilla/LookAndFeel.h"
+#include "mozilla/unused.h"
 
 #include "mozilla/css/Declaration.h"
 
 #include "nsAlgorithm.h" // for clamped()
 #include "nsRuleNode.h"
 #include "nscore.h"
 #include "nsIWidget.h"
 #include "nsIPresShell.h"
@@ -1275,120 +1276,187 @@ static void SetStyleImage(nsStyleContext
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unexpected Unit type.");
       break;
   }
 }
 
+struct SetEnumValueHelper
+{
+  template<typename FieldT>
+  static void SetIntegerValue(FieldT&, const nsCSSValue&)
+  {
+    // FIXME Is it possible to turn this assertion into a compilation error?
+    MOZ_ASSERT_UNREACHABLE("inappropriate unit");
+  }
+
+#define DEFINE_ENUM_CLASS_SETTER(type_, min_, max_) \
+  static void SetEnumeratedValue(type_& aField, const nsCSSValue& aValue) \
+  { \
+    auto value = aValue.GetIntValue(); \
+    MOZ_ASSERT(value >= static_cast<decltype(value)>(type_::min_) && \
+               value <= static_cast<decltype(value)>(type_::max_), \
+               "inappropriate value"); \
+    aField = static_cast<type_>(value); \
+  }
+
+  DEFINE_ENUM_CLASS_SETTER(StyleBoxSizing, Content, Border)
+
+#undef DEF_SET_ENUMERATED_VALUE
+};
+
+template<typename FieldT>
+struct SetIntegerValueHelper
+{
+  static void SetIntegerValue(FieldT& aField, const nsCSSValue& aValue)
+  {
+    aField = aValue.GetIntValue();
+  }
+  static void SetEnumeratedValue(FieldT& aField, const nsCSSValue& aValue)
+  {
+    aField = aValue.GetIntValue();
+  }
+};
+
+template<typename FieldT>
+struct SetValueHelper : Conditional<IsEnum<FieldT>::value,
+                                    SetEnumValueHelper,
+                                    SetIntegerValueHelper<FieldT>>::Type
+{
+  template<typename ValueT>
+  static void SetValue(FieldT& aField, const ValueT& aValue)
+  {
+    aField = aValue;
+  }
+  static void SetValue(FieldT&, unused_t)
+  {
+    // FIXME Is it possible to turn this assertion into a compilation error?
+    MOZ_ASSERT_UNREACHABLE("inappropriate unit");
+  }
+};
+
+
 // flags for SetValue - align values with SETCOORD_* constants
 // where possible
 
 #define SETVAL_NORMAL                 0x01   // N
 #define SETVAL_AUTO                   0x02   // A
 #define SETVAL_INTEGER                0x40   // I
 #define SETVAL_ENUMERATED             0x80   // E
 #define SETVAL_NONE                   0x100  // O
 #define SETVAL_SYSTEM_FONT            0x2000
 #define SETVAL_UNSET_INHERIT          0x00400000
 #define SETVAL_UNSET_INITIAL          0x00800000
 
 // no caller cares whether aField was changed or not
-template <typename FieldT,
-          typename T1, typename T2, typename T3, typename T4, typename T5>
+template<typename FieldT, typename InitialT,
+         typename AutoT, typename NoneT, typename NormalT, typename SysFontT>
 static void
-SetValue(const nsCSSValue& aValue, FieldT & aField,
+SetValue(const nsCSSValue& aValue, FieldT& aField,
          RuleNodeCacheConditions& aConditions, uint32_t aMask,
          FieldT aParentValue,
-         T1 aInitialValue,
-         T2 aAutoValue,
-         T3 aNoneValue,
-         T4 aNormalValue,
-         T5 aSystemFontValue)
-{
+         InitialT aInitialValue,
+         AutoT aAutoValue,
+         NoneT aNoneValue,
+         NormalT aNormalValue,
+         SysFontT aSystemFontValue)
+{
+  typedef SetValueHelper<FieldT> Helper;
+
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     return;
 
     // every caller of SetValue provides inherit and initial
     // alternatives, so we don't require them to say so in the mask
   case eCSSUnit_Inherit:
     aConditions.SetUncacheable();
     aField = aParentValue;
     return;
 
   case eCSSUnit_Initial:
-    aField = aInitialValue;
+    Helper::SetValue(aField, aInitialValue);
     return;
 
     // every caller provides one or other of these alternatives,
     // but they have to say which
   case eCSSUnit_Enumerated:
     if (aMask & SETVAL_ENUMERATED) {
-      aField = FieldT(aValue.GetIntValue());
+      Helper::SetEnumeratedValue(aField, aValue);
       return;
     }
     break;
 
   case eCSSUnit_Integer:
     if (aMask & SETVAL_INTEGER) {
-      aField = FieldT(aValue.GetIntValue());
+      Helper::SetIntegerValue(aField, aValue);
       return;
     }
     break;
 
     // remaining possibilities in descending order of frequency of use
   case eCSSUnit_Auto:
     if (aMask & SETVAL_AUTO) {
-      aField = aAutoValue;
+      Helper::SetValue(aField, aAutoValue);
       return;
     }
     break;
 
   case eCSSUnit_None:
     if (aMask & SETVAL_NONE) {
-      aField = aNoneValue;
+      Helper::SetValue(aField, aNoneValue);
       return;
     }
     break;
 
   case eCSSUnit_Normal:
     if (aMask & SETVAL_NORMAL) {
-      aField = aNormalValue;
+      Helper::SetValue(aField, aNormalValue);
       return;
     }
     break;
 
   case eCSSUnit_System_Font:
     if (aMask & SETVAL_SYSTEM_FONT) {
-      aField = aSystemFontValue;
+      Helper::SetValue(aField, aSystemFontValue);
       return;
     }
     break;
 
   case eCSSUnit_Unset:
     if (aMask & SETVAL_UNSET_INHERIT) {
       aConditions.SetUncacheable();
       aField = aParentValue;
       return;
     }
     if (aMask & SETVAL_UNSET_INITIAL) {
-      aField = aInitialValue;
+      Helper::SetValue(aField, aInitialValue);
       return;
     }
     break;
 
   default:
     break;
   }
 
   NS_NOTREACHED("SetValue: inappropriate unit");
 }
 
+template <typename FieldT, typename T1>
+static void
+SetValue(const nsCSSValue& aValue, FieldT& aField,
+         RuleNodeCacheConditions& aConditions, uint32_t aMask,
+         FieldT aParentValue, T1 aInitialValue)
+{
+  SetValue(aValue, aField, aConditions, aMask, aParentValue,
+           aInitialValue, Unused, Unused, Unused, Unused);
+}
+
 // flags for SetFactor
 #define SETFCT_POSITIVE 0x01        // assert value is >= 0.0f
 #define SETFCT_OPACITY  0x02        // clamp value to [0.0f .. 1.0f]
 #define SETFCT_NONE     0x04        // allow _None (uses aInitialValue).
 #define SETFCT_UNSET_INHERIT  0x00400000
 #define SETFCT_UNSET_INITIAL  0x00800000
 
 static void
@@ -8367,21 +8435,17 @@ nsRuleNode::ComputePositionData(void* aS
              SETCOORD_UNSET_INITIAL,
            aContext, mPresContext, conditions);
 
   // box-sizing: enum, inherit, initial
   SetValue(*aRuleData->ValueForBoxSizing(),
            pos->mBoxSizing, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentPos->mBoxSizing,
-           StyleBoxSizing::Content,
-           StyleBoxSizing::Content /* ignored */,
-           StyleBoxSizing::Content /* ignored */,
-           StyleBoxSizing::Content /* ignored */,
-           StyleBoxSizing::Content /* ignored */);
+           StyleBoxSizing::Content);
 
   // align-content: enum, inherit, initial
   SetValue(*aRuleData->ValueForAlignContent(),
            pos->mAlignContent, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentPos->mAlignContent,
            NS_STYLE_ALIGN_NORMAL, 0, 0, 0, 0);