Backed out 9 changesets (bug 1479173) for build failures in src/dom/animation/EffectCompositor.cpp CLOSED TREE
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Tue, 06 Nov 2018 12:13:31 +0200
changeset 444606 944be4a5056f5a54e606d9cda71064c087157304
parent 444605 981aa569f6de7c3b367acd92a8b2cfd64adda6fa
child 444607 48bcca6536ed31b0277c38e2d1de7a9b9de9c6ac
push id34998
push userapavel@mozilla.com
push dateTue, 06 Nov 2018 17:04:36 +0000
treeherdermozilla-central@f9affb18c3e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1479173
milestone65.0a1
backs out439ac5cfbcedb23c1587c703af3e66cda06ed5cf
73aba16a223faf3c6f7e3ad3b6da27995fd31db0
89dbc6f7f959765d2b2338c5d010bb8ee84a8cb6
ed1c344ccf0d83b20a699ec7d17f45c29153e9a3
c330e7e1eb1da557ae12eb7ad4f2b5853abf7ec6
efcbbb9daa3951052dee296675d7d75a00cc5be8
43c6a786353678dd483996bd0c72b327ebc59cc2
94f0ae94a02c3761ad176abd59bc425f4005b4df
7cf0ad1af067db997a49677e0051cc15faa37912
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
Backed out 9 changesets (bug 1479173) for build failures in src/dom/animation/EffectCompositor.cpp CLOSED TREE Backed out changeset 439ac5cfbced (bug 1479173) Backed out changeset 73aba16a223f (bug 1479173) Backed out changeset 89dbc6f7f959 (bug 1479173) Backed out changeset ed1c344ccf0d (bug 1479173) Backed out changeset c330e7e1eb1d (bug 1479173) Backed out changeset efcbbb9daa39 (bug 1479173) Backed out changeset 43c6a7863536 (bug 1479173) Backed out changeset 94f0ae94a02c (bug 1479173) Backed out changeset 7cf0ad1af067 (bug 1479173)
dom/animation/EffectCompositor.cpp
dom/animation/KeyframeEffect.cpp
layout/base/RestyleManager.cpp
layout/style/GenerateCompositorAnimatableProperties.py
layout/style/LayerAnimationInfo.cpp
layout/style/LayerAnimationInfo.h
layout/style/moz.build
layout/style/nsCSSPropertyIDSet.h
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/dom/KeyframeEffect.h"
 #include "mozilla/AnimationComparator.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
+#include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TypeTraits.h" // For std::forward<>
 #include "nsContentUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSPropertyIDSet.h"
@@ -603,33 +604,31 @@ EffectCompositor::GetOverriddenPropertie
 
   nsCSSPropertyIDSet result;
 
   Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
   if (!elementToRestyle) {
     return result;
   }
 
-  static constexpr size_t compositorAnimatableCount =
-    nsCSSPropertyIDSet::CompositorAnimatableCount();
-  AutoTArray<nsCSSPropertyID, compositorAnimatableCount> propertiesToTrack;
+  AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
   {
     nsCSSPropertyIDSet propertiesToTrackAsSet;
     for (KeyframeEffect* effect : aEffectSet) {
       for (const AnimationProperty& property : effect->Properties()) {
         if (nsCSSProps::PropHasFlags(property.mProperty,
                                      CSSPropFlags::CanAnimateOnCompositor) &&
             !propertiesToTrackAsSet.HasProperty(property.mProperty)) {
           propertiesToTrackAsSet.AddProperty(property.mProperty);
           propertiesToTrack.AppendElement(property.mProperty);
         }
       }
       // Skip iterating over the rest of the effects if we've already
       // found all the compositor-animatable properties.
-      if (propertiesToTrack.Length() == compositorAnimatableCount) {
+      if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
         break;
       }
     }
   }
 
   if (propertiesToTrack.IsEmpty()) {
     return result;
   }
@@ -662,27 +661,41 @@ EffectCompositor::UpdateCascadeResults(E
   // Get properties that override the *animations* level of the cascade.
   //
   // We only do this for properties that we can animate on the compositor
   // since we will apply other properties on the main thread where the usual
   // cascade applies.
   nsCSSPropertyIDSet overriddenProperties =
     GetOverriddenProperties(aEffectSet, aElement, aPseudoType);
 
+  // Returns a bitset the represents which properties from
+  // LayerAnimationInfo::sRecords are present in |aPropertySet|.
+  auto compositorPropertiesInSet =
+    [](nsCSSPropertyIDSet& aPropertySet) ->
+      std::bitset<LayerAnimationInfo::kRecords> {
+        std::bitset<LayerAnimationInfo::kRecords> result;
+        for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
+          if (aPropertySet.HasProperty(
+                LayerAnimationInfo::sRecords[i].mProperty)) {
+            result.set(i);
+          }
+        }
+      return result;
+    };
+
   nsCSSPropertyIDSet& propertiesWithImportantRules =
     aEffectSet.PropertiesWithImportantRules();
   nsCSSPropertyIDSet& propertiesForAnimationsLevel =
     aEffectSet.PropertiesForAnimationsLevel();
 
-  static constexpr nsCSSPropertyIDSet compositorAnimatables =
-    nsCSSPropertyIDSet::CompositorAnimatables();
   // Record which compositor-animatable properties were originally set so we can
   // compare for changes later.
-  nsCSSPropertyIDSet prevCompositorPropertiesWithImportantRules =
-    propertiesWithImportantRules.Intersect(compositorAnimatables);
+  std::bitset<LayerAnimationInfo::kRecords>
+    prevCompositorPropertiesWithImportantRules =
+      compositorPropertiesInSet(propertiesWithImportantRules);
 
   nsCSSPropertyIDSet prevPropertiesForAnimationsLevel =
     propertiesForAnimationsLevel;
 
   propertiesWithImportantRules.Empty();
   propertiesForAnimationsLevel.Empty();
 
   nsCSSPropertyIDSet propertiesForTransitionsLevel;
@@ -714,35 +727,35 @@ EffectCompositor::UpdateCascadeResults(E
   if (!presContext) {
     return;
   }
 
   // If properties for compositor are newly overridden by !important rules, or
   // released from being overridden by !important rules, we need to update
   // layers for animations level because it's a trigger to send animations to
   // the compositor or pull animations back from the compositor.
-  if (!prevCompositorPropertiesWithImportantRules.Equals(
-        propertiesWithImportantRules.Intersect(compositorAnimatables))) {
+  if (prevCompositorPropertiesWithImportantRules !=
+        compositorPropertiesInSet(propertiesWithImportantRules)) {
     presContext->EffectCompositor()->
       RequestRestyle(aElement, aPseudoType,
                      EffectCompositor::RestyleType::Layer,
                      EffectCompositor::CascadeLevel::Animations);
   }
 
   // If we have transition properties and if the same propery for animations
   // level is newly added or removed, we need to update the transition level
   // rule since the it will be added/removed from the rule tree.
   nsCSSPropertyIDSet changedPropertiesForAnimationLevel =
     prevPropertiesForAnimationsLevel.Xor(propertiesForAnimationsLevel);
   nsCSSPropertyIDSet commonProperties =
     propertiesForTransitionsLevel.Intersect(
       changedPropertiesForAnimationLevel);
   if (!commonProperties.IsEmpty()) {
     EffectCompositor::RestyleType restyleType =
-      changedPropertiesForAnimationLevel.Intersects(compositorAnimatables)
+      compositorPropertiesInSet(changedPropertiesForAnimationLevel).none()
       ? EffectCompositor::RestyleType::Standard
       : EffectCompositor::RestyleType::Layer;
     presContext->EffectCompositor()->
       RequestRestyle(aElement, aPseudoType,
                      restyleType,
                      EffectCompositor::CascadeLevel::Transitions);
   }
 }
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1237,56 +1237,58 @@ KeyframeEffect::CanThrottle() const
     // need to update on the main thread.
     return true;
   }
 
   if (CanThrottleIfNotVisible(*frame)) {
     return true;
   }
 
-  EffectSet* effectSet = nullptr;
-  for (const AnimationProperty& property : mProperties) {
-    if (!property.mIsRunningOnCompositor) {
-      return false;
+  // First we need to check layer generation and transform overflow
+  // prior to the property.mIsRunningOnCompositor check because we should
+  // occasionally unthrottle these animations even if the animations are
+  // already running on compositor.
+  for (const LayerAnimationInfo::Record& record :
+        LayerAnimationInfo::sRecords) {
+    // Skip properties that are overridden by !important rules.
+    // (GetEffectiveAnimationOfProperty, as called by
+    // HasEffectiveAnimationOfProperty, only returns a property which is
+    // neither overridden by !important rules nor overridden by other
+    // animation.)
+    if (!HasEffectiveAnimationOfProperty(record.mProperty)) {
+      continue;
     }
 
-    MOZ_ASSERT(nsCSSPropertyIDSet::CompositorAnimatables()
-                 .HasProperty(property.mProperty),
-               "The property should be able to run on the compositor");
-    MOZ_ASSERT(HasEffectiveAnimationOfProperty(property.mProperty),
-               "There should be an effective animation of the property while "
-               "it is marked as being run on the compositor");
-
-    if (!effectSet) {
-      effectSet = EffectSet::GetEffectSet(mTarget->mElement,
-                                          mTarget->mPseudoType);
-      MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
-                            "associated with a target element");
-    }
-
-    DisplayItemType displayItemType =
-      LayerAnimationInfo::GetDisplayItemTypeForProperty(property.mProperty);
-
+    EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
+                                                   mTarget->mPseudoType);
+    MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
+                          "associated with a target element");
     // Note that AnimationInfo::GetGenarationFromFrame() is supposed to work
     // with the primary frame instead of the style frame.
     Maybe<uint64_t> generation = layers::AnimationInfo::GetGenerationFromFrame(
-        GetPrimaryFrame(), displayItemType);
+        GetPrimaryFrame(), record.mLayerType);
     // Unthrottle if the animation needs to be brought up to date
     if (!generation || effectSet->GetAnimationGeneration() != *generation) {
       return false;
     }
 
     // If this is a transform animation that affects the overflow region,
     // we should unthrottle the animation periodically.
     if (HasPropertiesThatMightAffectOverflow() &&
         !CanThrottleOverflowChangesInScrollable(*frame)) {
       return false;
     }
   }
 
+  for (const AnimationProperty& property : mProperties) {
+    if (!property.mIsRunningOnCompositor) {
+      return false;
+    }
+  }
+
   return true;
 }
 
 bool
 KeyframeEffect::CanThrottleOverflowChanges(const nsIFrame& aFrame) const
 {
   TimeStamp now = aFrame.PresContext()->RefreshDriver()->MostRecentRefresh();
 
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1795,17 +1795,17 @@ RestyleManager::AddLayerChangesForAnimat
   uint64_t frameGeneration =
     RestyleManager::GetAnimationGenerationForFrame(aFrame);
 
   nsChangeHint hint = nsChangeHint(0);
   for (const LayerAnimationInfo::Record& layerInfo :
          LayerAnimationInfo::sRecords) {
     Maybe<uint64_t> generation =
       layers::AnimationInfo::GetGenerationFromFrame(aFrame,
-                                                    layerInfo.mDisplayItemType);
+                                                    layerInfo.mLayerType);
     if (generation && frameGeneration != *generation) {
       // If we have a transform layer bug don't have any transform style, we
       // probably just removed the transform but haven't destroyed the layer
       // yet. In this case we will typically add the appropriate change hint
       // (nsChangeHint_UpdateContainingBlock) when we compare styles so in
       // theory we could skip adding any change hint here.
       //
       // However, sometimes when we compare styles we'll get no change. For
@@ -1816,17 +1816,17 @@ RestyleManager::AddLayerChangesForAnimat
       // on the compositor. To handle this case we simply set all the change
       // hints relevant to removing transform style (since we don't know exactly
       // what changes happened while the animation was running on the
       // compositor).
       //
       // Note that we *don't* add nsChangeHint_UpdateTransformLayer since if we
       // did, ApplyRenderingChangeToTree would complain that we're updating a
       // transform layer without a transform.
-      if (layerInfo.mDisplayItemType == DisplayItemType::TYPE_TRANSFORM &&
+      if (layerInfo.mLayerType == DisplayItemType::TYPE_TRANSFORM &&
           !aFrame->StyleDisplay()->HasTransformStyle()) {
         // Add all the hints for a removing a transform if they are not already
         // set for this frame.
         if (!(NS_IsHintSubset(
                 nsChangeHint_ComprehensiveAddOrRemoveTransform,
                 aHintForThisFrame))) {
           hint |= nsChangeHint_ComprehensiveAddOrRemoveTransform;
         }
deleted file mode 100644
--- a/layout/style/GenerateCompositorAnimatableProperties.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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/.
-
-import runpy
-
-def generate(output, dataFile):
-    output.write("""/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */
-#ifndef COMPOSITOR_ANIMATABLE_PROPERTY_LIST
-#define COMPOSITOR_ANIMATABLE_PROPERTY_LIST { \\
-""")
-
-    def can_animate_on_compositor(p):
-        return "CanAnimateOnCompositor" in p.flags
-
-    properties = runpy.run_path(dataFile)["data"]
-    properties = filter(can_animate_on_compositor, properties)
-
-    for p in properties:
-        output.write("  eCSSProperty_{}, \\\n".format(p.id))
-
-    output.write("}\n")
-    output.write("#endif /* COMPOSITOR_ANIMATABLE_PROPERTY_LIST */\n")
--- a/layout/style/LayerAnimationInfo.cpp
+++ b/layout/style/LayerAnimationInfo.cpp
@@ -2,75 +2,53 @@
 /* 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/. */
 
 #include "LayerAnimationInfo.h"
 
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
-#include "nsCSSPropertyIDSet.h" // For nsCSSPropertyIDSet::CompositorAnimatable
 
 namespace mozilla {
 
 /* static */ const LayerAnimationInfo::Record LayerAnimationInfo::sRecords[] =
   { { eCSSProperty_transform,
       DisplayItemType::TYPE_TRANSFORM,
       nsChangeHint_UpdateTransformLayer },
     { eCSSProperty_opacity,
       DisplayItemType::TYPE_OPACITY,
       nsChangeHint_UpdateOpacityLayer } };
 
-/* static */ DisplayItemType
-LayerAnimationInfo::GetDisplayItemTypeForProperty(nsCSSPropertyID aProperty)
-{
-  switch (aProperty) {
-    case eCSSProperty_opacity:
-      return DisplayItemType::TYPE_OPACITY;
-    case eCSSProperty_transform:
-      return DisplayItemType::TYPE_TRANSFORM;
-    default:
-      break;
-  }
-  return DisplayItemType::TYPE_ZERO;
-}
-
 #ifdef DEBUG
 /* static */ void
 LayerAnimationInfo::Initialize()
 {
   for (const Record& record : sRecords) {
     MOZ_ASSERT(nsCSSProps::PropHasFlags(record.mProperty,
                                         CSSPropFlags::CanAnimateOnCompositor),
                "CSS property with entry in LayerAnimation::sRecords does not "
                "have the CSSPropFlags::CanAnimateOnCompositor flag");
   }
 
-  nsCSSPropertyIDSet properties;
   // Check that every property with the flag for animating on the
   // compositor has an entry in LayerAnimationInfo::sRecords.
   for (nsCSSPropertyID prop = nsCSSPropertyID(0);
        prop < eCSSProperty_COUNT;
        prop = nsCSSPropertyID(prop + 1)) {
     if (nsCSSProps::PropHasFlags(prop,
                                  CSSPropFlags::CanAnimateOnCompositor)) {
       bool found = false;
       for (const Record& record : sRecords) {
         if (record.mProperty == prop) {
           found = true;
-          properties.AddProperty(record.mProperty);
           break;
         }
       }
       MOZ_ASSERT(found,
                  "CSS property with the CSSPropFlags::CanAnimateOnCompositor "
                  "flag does not have an entry in LayerAnimationInfo::sRecords");
-      MOZ_ASSERT(GetDisplayItemTypeForProperty(prop) !=
-                   DisplayItemType::TYPE_ZERO,
-                 "GetDisplayItemTypeForProperty should return a valid display "
-                 "item type");
     }
   }
-  MOZ_ASSERT(properties.Equals(nsCSSPropertyIDSet::CompositorAnimatables()));
 }
 #endif
 
 } // namespace mozilla
--- a/layout/style/LayerAnimationInfo.h
+++ b/layout/style/LayerAnimationInfo.h
@@ -4,40 +4,31 @@
  * 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_LayerAnimationInfo_h
 #define mozilla_LayerAnimationInfo_h
 
 #include "nsChangeHint.h"
 #include "nsCSSPropertyID.h"
-#include "nsCSSPropertyIDSet.h"
 #include "nsDisplayList.h" // For nsDisplayItem::Type
 
 namespace mozilla {
 
 struct LayerAnimationInfo {
 #ifdef DEBUG
   static void Initialize();
 #endif
   // For CSS properties that may be animated on a separate layer, represents
   // a record of the corresponding layer type and change hint.
   struct Record {
     nsCSSPropertyID mProperty;
-    DisplayItemType mDisplayItemType;
+    DisplayItemType mLayerType;
     nsChangeHint mChangeHint;
   };
 
-  // Returns the corresponding display item type for |aProperty| when it is
-  // animated on the compositor.
-  // Returns DisplayItemType::TYPE_ZERO if |aProperty| cannot be animated on the
-  // compositor.
-  static DisplayItemType
-  GetDisplayItemTypeForProperty(nsCSSPropertyID aProperty);
-
-  static const size_t kRecords =
-    nsCSSPropertyIDSet::CompositorAnimatableCount();
+  static const size_t kRecords = 2;
   static const Record sRecords[kRecords];
 };
 
 } // namespace mozilla
 
 #endif /* !defined(mozilla_LayerAnimationInfo_h) */
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -286,33 +286,25 @@ servo_props.inputs = [
 servo_props = GENERATED_FILES['ServoCSSPropList.py']
 servo_props.script = 'GenerateServoCSSPropList.py:generate_data'
 servo_props.inputs = [
     'ServoCSSPropList.mako.py',
 ]
 
 if CONFIG['COMPILE_ENVIRONMENT']:
     GENERATED_FILES += [
-        'CompositorAnimatableProperties.h',
         'nsComputedDOMStyleGenerated.cpp',
         'nsCSSPropsGenerated.inc',
         'ServoStyleConsts.h',
     ]
 
     EXPORTS.mozilla += [
-        '!CompositorAnimatableProperties.h',
         '!ServoStyleConsts.h',
     ]
 
-    compositor = GENERATED_FILES['CompositorAnimatableProperties.h']
-    compositor.script = 'GenerateCompositorAnimatableProperties.py:generate'
-    compositor.inputs = [
-        '!ServoCSSPropList.py',
-    ]
-
     computed = GENERATED_FILES['nsComputedDOMStyleGenerated.cpp']
     computed.script = 'GenerateComputedDOMStyleGenerated.py:generate'
     computed.inputs = [
         '!ServoCSSPropList.py',
     ]
 
     css_props = GENERATED_FILES['nsCSSPropsGenerated.inc']
     css_props.script = 'GenerateCSSPropsGenerated.py:generate'
--- a/layout/style/nsCSSPropertyIDSet.h
+++ b/layout/style/nsCSSPropertyIDSet.h
@@ -6,42 +6,27 @@
 
 #ifndef nsCSSPropertyIDSet_h__
 #define nsCSSPropertyIDSet_h__
 
 #include "mozilla/ArrayUtils.h"
 
 #include "nsCSSPropertyID.h"
 #include <limits.h> // for CHAR_BIT
-#include <initializer_list>
-
-// For COMPOSITOR_ANIMATABLE_PROPERTY_LIST
-#include "mozilla/CompositorAnimatableProperties.h"
 
 /**
  * nsCSSPropertyIDSet maintains a set of non-shorthand CSS properties.  In
  * other words, for each longhand CSS property we support, it has a bit
  * for whether that property is in the set.
  */
 class nsCSSPropertyIDSet {
 public:
     nsCSSPropertyIDSet() { Empty(); }
     // auto-generated copy-constructor OK
 
-    explicit constexpr nsCSSPropertyIDSet(
-        std::initializer_list<nsCSSPropertyID> aProperties)
-      : mProperties{0}
-    {
-      for (auto property : aProperties) {
-        size_t p = property;
-        mProperties[p / kBitsInChunk] |=
-          property_set_type(1) << (p % kBitsInChunk);
-      }
-    }
-
     void AssertInSetRange(nsCSSPropertyID aProperty) const {
         NS_ASSERTION(0 <= aProperty &&
                      aProperty < eCSSProperty_COUNT_no_shorthands,
                      "out of bounds");
     }
 
     // Conversion of aProperty to |size_t| after AssertInSetRange
     // lets the compiler generate significantly tighter code.
@@ -62,39 +47,16 @@ public:
 
     bool HasProperty(nsCSSPropertyID aProperty) const {
         AssertInSetRange(aProperty);
         size_t p = aProperty;
         return (mProperties[p / kBitsInChunk] &
                 (property_set_type(1) << (p % kBitsInChunk))) != 0;
     }
 
-    // Returns an nsCSSPropertyIDSet including all properties that can be run
-    // on the compositor.
-    static constexpr nsCSSPropertyIDSet CompositorAnimatables()
-    {
-      return nsCSSPropertyIDSet(COMPOSITOR_ANIMATABLE_PROPERTY_LIST);
-    }
-
-    static constexpr size_t CompositorAnimatableCount()
-    {
-      auto list = COMPOSITOR_ANIMATABLE_PROPERTY_LIST;
-      return list.size();
-    }
-
-    bool Intersects(const nsCSSPropertyIDSet& aOther) const
-    {
-      for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
-        if (mProperties[i] & aOther.mProperties[i]) {
-          return true;
-        }
-      }
-      return false;
-    }
-
     void Empty() {
         memset(mProperties, 0, sizeof(mProperties));
     }
 
     void AssertIsEmpty(const char* aText) const {
         for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
             NS_ASSERTION(mProperties[i] == 0, aText);
         }