Bug 968923 - part 3d - record use counter information from the CSS parser; r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Wed, 03 Jun 2015 15:21:24 -0400
changeset 258245 d0d513d053427bd517e73f500cd5c5733efa4da8
parent 258244 a384a005caf834d0df80f44b985303bc47602fe1
child 258246 f58b8e4e584353ddcb733f9c163e88cf17947c4a
push id29249
push userryanvm@gmail.com
push dateWed, 19 Aug 2015 11:17:27 +0000
treeherdermozilla-central@706b23a03d1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs968923
milestone43.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 968923 - part 3d - record use counter information from the CSS parser; r=dbaron
dom/base/UseCounters.conf
dom/base/gen-usecounters.py
dom/base/usecounters.py
dom/svg/nsSVGElement.cpp
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDataBlock.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
--- a/dom/base/UseCounters.conf
+++ b/dom/base/UseCounters.conf
@@ -13,21 +13,27 @@
 //   (b) a comment, which is a line that begins with "//"
 //
 //   (c) an #if/ifdef/else/endif preprocessor directive
 //
 //   (d) one of three possible use counter declarations:
 //
 //         method <IDL interface name>.<IDL operation name>
 //         attribute <IDL interface name>.<IDL attribute name>
-//         property <CSS property name>
+//         property <CSS property method name>
+//
+// The |CSS property method name| should be identical to the |method|
+// argument to CSS_PROP and related macros.  The method name is
+// identical to the name of the property, except that all hyphens are
+// removed and CamelCase naming is used.  See nsCSSPropList.h for
+// further details.
 //
 // To actually cause use counters to be incremented, DOM methods
 // and attributes must have a [UseCounter] extended attribute in
-// the Web IDL file, and CSS properties must be declared with
-// the CSS_PROPERTY_HAS_USE_COUNTER flag in nsCSSPropList.h.
+// the Web IDL file.  CSS properties require no special treatment
+// beyond being listed below.
 //
 // You might reasonably ask why we have this file and we require
 // annotating things with [UseCounter] in the relevant WebIDL file as
 // well.  Generating things from bindings codegen and ensuring all the
 // dependencies were correct would have been rather difficult, and
 // annotating the WebIDL files does nothing for identifying CSS
 // property usage, which we would also like to track.
--- a/dom/base/gen-usecounters.py
+++ b/dom/base/gen-usecounters.py
@@ -40,39 +40,40 @@ def generate_list(f, counters):
 
     for counter in counters:
         if counter['type'] == 'method':
             print('USE_COUNTER_DOM_METHOD(%s, %s)' % (counter['interface_name'], counter['method_name']), file=f)
         elif counter['type'] == 'attribute':
             print('USE_COUNTER_DOM_ATTRIBUTE(%s, %s)' % (counter['interface_name'], counter['attribute_name']), file=f)
         elif counter['type'] == 'property':
             prop = counter['property_name']
-            print('USE_COUNTER_CSS_PROPERTY(%s, %s)' % (prop, prop.replace('-', '_')), file=f)
+            print('USE_COUNTER_CSS_PROPERTY(%s, %s)' % (prop, prop), file=f)
 
     print_optional_macro_undeclare('USE_COUNTER_DOM_METHOD')
     print_optional_macro_undeclare('USE_COUNTER_DOM_ATTRIBUTE')
     print_optional_macro_undeclare('USE_COUNTER_CSS_PROPERTY')
 
 def generate_property_map(f, counters):
     print(AUTOGENERATED_WARNING_COMMENT, file=f)
     print('''
 enum {
-  // XXX is this the right define?
+  #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
   #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,     \\
                    kwtable_, stylestruct_, stylestructoffset_, animtype_) \\
-    USE_COUNTER_FOR_CSS_PROPERTY_##id_ = eUseCounter_UNKNOWN,
+    USE_COUNTER_FOR_CSS_PROPERTY_##method_ = eUseCounter_UNKNOWN,
   #include "nsCSSPropList.h"
   #undef CSS_PROP
   #undef CSS_PROP_LIST_INCLUDE_LOGICAL
+  #undef CSS_PROP_PUBLIC_OR_PRIVATE
 };
 ''', file=f)
     for counter in counters:
         if counter['type'] == 'property':
-            prop = counter['property_name'].replace('-', '_')
+            prop = counter['property_name']
             print('#define USE_COUNTER_FOR_CSS_PROPERTY_%s eUseCounter_property_%s' % (prop, prop), file=f)
 
 def use_counter_list(output_header, conf_filename):
     counters = usecounters.read_conf(conf_filename)
     generate_list(output_header, counters)
 
 def property_map(output_map, conf_filename):
     counters = usecounters.read_conf(conf_filename)
--- a/dom/base/usecounters.py
+++ b/dom/base/usecounters.py
@@ -36,17 +36,17 @@ def read_conf(conf_filename):
                 continue
             m = re.match(r'attribute ([A-Za-z0-9]+)\.([A-Za-z0-9]+)$', line)
             if m:
                 interface_name, attribute_name = m.groups()
                 yield { 'type': 'attribute',
                         'interface_name': interface_name,
                         'attribute_name': attribute_name }
                 continue
-            m = re.match(r'property ([a-z0-9-]+)$', line)
+            m = re.match(r'property ([A-Za-z0-9]+)$', line)
             if m:
                 property_name = m.group(1)
                 yield { 'type': 'property',
                         'property_name': property_name }
                 continue
             raise ValueError('error parsing %s at line %d' % (conf_filename, line_num))
 
     return parse_counters(stream)
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1178,19 +1178,28 @@ MappedAttrParser::ParseMappedAttrValue(n
     mDecl->InitializeEmpty();
   }
 
   // Get the nsCSSProperty ID for our mapped attribute.
   nsCSSProperty propertyID =
     nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
                                nsCSSProps::eEnabledForAllContent);
   if (propertyID != eCSSProperty_UNKNOWN) {
-    bool changed; // outparam for ParseProperty. (ignored)
+    bool changed = false; // outparam for ParseProperty.
     mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
                           mElement->NodePrincipal(), mDecl, &changed, false, true);
+    if (changed) {
+      // The normal reporting of use counters by the nsCSSParser won't happen
+      // since it doesn't have a sheet.
+      MOZ_ASSERT(!nsCSSProps::IsShorthand(propertyID));
+      UseCounter useCounter = nsCSSProps::UseCounterFor(propertyID);
+      if (useCounter != eUseCounter_UNKNOWN) {
+        mElement->OwnerDoc()->SetDocumentAndPageUseCounter(useCounter);
+      }
+    }
     return;
   }
   MOZ_ASSERT(aMappedAttrName == nsGkAtoms::lang,
              "Only 'lang' should be unrecognized!");
   // nsCSSParser doesn't know about 'lang', so we need to handle it specially.
   if (aMappedAttrName == nsGkAtoms::lang) {
     propertyID = eCSSProperty__x_lang;
     nsCSSExpandedDataBlock block;
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -609,45 +609,49 @@ nsCSSExpandedDataBlock::ClearLonghandPro
 
 bool
 nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
                                           nsCSSProperty aPropID,
                                           nsCSSProps::EnabledState aEnabledState,
                                           bool aIsImportant,
                                           bool aOverrideImportant,
                                           bool aMustCallValueAppended,
-                                          css::Declaration* aDeclaration)
+                                          css::Declaration* aDeclaration,
+                                          nsIDocument* aSheetDocument)
 {
     if (!nsCSSProps::IsShorthand(aPropID)) {
         return DoTransferFromBlock(aFromBlock, aPropID,
                                    aIsImportant, aOverrideImportant,
-                                   aMustCallValueAppended, aDeclaration);
+                                   aMustCallValueAppended, aDeclaration,
+                                   aSheetDocument);
     }
 
     // We can pass eIgnoreEnabledState (here, and in ClearProperty above) rather
     // than a value corresponding to whether we're parsing a UA style sheet or
     // certified app because we assert in nsCSSProps::AddRefTable that shorthand
     // properties available in these contexts also have all of their
     // subproperties available in these contexts.
     bool changed = false;
     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID, aEnabledState) {
         changed |= DoTransferFromBlock(aFromBlock, *p,
                                        aIsImportant, aOverrideImportant,
-                                       aMustCallValueAppended, aDeclaration);
+                                       aMustCallValueAppended, aDeclaration,
+                                       aSheetDocument);
     }
     return changed;
 }
 
 bool
 nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
                                             nsCSSProperty aPropID,
                                             bool aIsImportant,
                                             bool aOverrideImportant,
                                             bool aMustCallValueAppended,
-                                            css::Declaration* aDeclaration)
+                                            css::Declaration* aDeclaration,
+                                            nsIDocument* aSheetDocument)
 {
   bool changed = false;
   MOZ_ASSERT(aFromBlock.HasPropertyBit(aPropID), "oops");
   if (aIsImportant) {
     if (!HasImportantBit(aPropID))
       changed = true;
     SetImportantBit(aPropID);
   } else {
@@ -665,16 +669,23 @@ nsCSSExpandedDataBlock::DoTransferFromBl
       ClearImportantBit(aPropID);
     }
   }
 
   if (aMustCallValueAppended || !HasPropertyBit(aPropID)) {
     aDeclaration->ValueAppended(aPropID);
   }
 
+  if (aSheetDocument) {
+    UseCounter useCounter = nsCSSProps::UseCounterFor(aPropID);
+    if (useCounter != eUseCounter_UNKNOWN) {
+      aSheetDocument->SetDocumentAndPageUseCounter(useCounter);
+    }
+  }
+
   SetPropertyBit(aPropID);
   aFromBlock.ClearPropertyBit(aPropID);
 
   /*
    * Save needless copying and allocation by calling the destructor in
    * the destination, copying memory directly, and then using placement
    * new.
    */
--- a/layout/style/nsCSSDataBlock.h
+++ b/layout/style/nsCSSDataBlock.h
@@ -14,16 +14,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "nsCSSProps.h"
 #include "nsCSSPropertySet.h"
 #include "nsCSSValue.h"
 #include "imgRequestProxy.h"
 
 struct nsRuleData;
 class nsCSSExpandedDataBlock;
+class nsIDocument;
 
 namespace mozilla {
 namespace css {
 class Declaration;
 } // namespace css
 } // namespace mozilla
 
 /**
@@ -244,24 +245,27 @@ public:
      * existing !important property regardless of its own importance
      * if |aOverrideImportant| is true.  |aEnabledState| is used to
      * determine which longhand components of |aPropID| (if it is a
      * shorthand) to transfer.
      *
      * Returns true if something changed, false otherwise.  Calls
      * |ValueAppended| on |aDeclaration| if the property was not
      * previously set, or in any case if |aMustCallValueAppended| is true.
+     * Calls |SetDocumentAndPageUseCounter| on |aSheetDocument| if it is
+     * non-null and |aPropID| has a use counter.
      */
     bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
                            nsCSSProperty aPropID,
                            nsCSSProps::EnabledState aEnabledState,
                            bool aIsImportant,
                            bool aOverrideImportant,
                            bool aMustCallValueAppended,
-                           mozilla::css::Declaration* aDeclaration);
+                           mozilla::css::Declaration* aDeclaration,
+                           nsIDocument* aSheetDocument);
 
     /**
      * Copies the values for aPropID into the specified aRuleData object.
      *
      * This is used for copying parsed-at-computed-value-time properties
      * that had variable references.  aPropID must be a longhand property.
      */
     void MapRuleInfoInto(nsCSSProperty aPropID, nsRuleData* aRuleData) const;
@@ -285,17 +289,18 @@ private:
     /**
      * Worker for TransferFromBlock; cannot be used with shorthands.
      */
     bool DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
                                nsCSSProperty aPropID,
                                bool aIsImportant,
                                bool aOverrideImportant,
                                bool aMustCallValueAppended,
-                               mozilla::css::Declaration* aDeclaration);
+                               mozilla::css::Declaration* aDeclaration,
+                               nsIDocument* aSheetDocument);
 
 #ifdef DEBUG
     void DoAssertInitialState();
 #endif
 
     /*
      * mPropertiesSet stores a bit for every property that is present,
      * to optimize compression of blocks with small numbers of
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -110,16 +110,18 @@ struct CSSParserInputState {
 // needed by nsCSSParser, far below.
 class CSSParserImpl {
 public:
   CSSParserImpl();
   ~CSSParserImpl();
 
   nsresult SetStyleSheet(CSSStyleSheet* aSheet);
 
+  nsIDocument* GetDocument();
+
   nsresult SetQuirkMode(bool aQuirkMode);
 
   nsresult SetChildLoader(mozilla::css::Loader* aChildLoader);
 
   // Clears everything set by the above Set*() functions.
   void Reset();
 
   nsresult ParseSheet(const nsAString& aInput,
@@ -1366,16 +1368,25 @@ CSSParserImpl::SetStyleSheet(CSSStyleShe
     }
   } else if (mSheet) {
     mNameSpaceMap = mSheet->GetNameSpaceMap();
   }
 
   return NS_OK;
 }
 
+nsIDocument*
+CSSParserImpl::GetDocument()
+{
+  if (!mSheet) {
+    return nullptr;
+  }
+  return mSheet->GetDocument();
+}
+
 nsresult
 CSSParserImpl::SetQuirkMode(bool aQuirkMode)
 {
   mNavQuirkMode = aQuirkMode;
   return NS_OK;
 }
 
 nsresult
@@ -1712,17 +1723,18 @@ CSSParserImpl::ParseProperty(const nsCSS
     // directly into the declaration without going through the whole
     // expand/compress thing.
     if (!aDeclaration->TryReplaceValue(aPropID, aIsImportant, mTempData,
                                        aChanged)) {
       // Do it the slow way
       aDeclaration->ExpandTo(&mData);
       *aChanged = mData.TransferFromBlock(mTempData, aPropID,
                                           PropertyEnabledState(), aIsImportant,
-                                          true, false, aDeclaration);
+                                          true, false, aDeclaration,
+                                          GetDocument());
       aDeclaration->CompressFrom(&mData);
     }
     CLEAR_ERROR();
   }
 
   mTempData.AssertInitialState();
 
   ReleaseScanner();
@@ -6972,17 +6984,17 @@ CSSParserImpl::ParseDeclaration(css::Dec
     nsDependentString varName(propertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
     aDeclaration->AddVariableDeclaration(varName, variableType, variableValue,
                                          status == ePriority_Important, false);
   } else {
     *aChanged |= mData.TransferFromBlock(mTempData, propID,
                                          PropertyEnabledState(),
                                          status == ePriority_Important,
                                          false, aMustCallValueAppended,
-                                         aDeclaration);
+                                         aDeclaration, GetDocument());
   }
 
   return true;
 }
 
 static const nsCSSProperty kBorderTopIDs[] = {
   eCSSProperty_border_top_width,
   eCSSProperty_border_top_style,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2931,16 +2931,31 @@ nsCSSProps::gPropertyEnabled[eCSSPropert
   #undef CSS_PROP_SHORTHAND
 
   #define CSS_PROP_ALIAS(aliasname_, propid_, aliasmethod_, pref_) \
     true,
   #include "nsCSSPropAliasList.h"
   #undef CSS_PROP_ALIAS
 };
 
+#include "../../dom/base/PropertyUseCounterMap.inc"
+
+/* static */ const UseCounter
+nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = {
+  #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
+  #define CSS_PROP_LIST_INCLUDE_LOGICAL
+  #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,     \
+                   kwtable_, stylestruct_, stylestructoffset_, animtype_) \
+    static_cast<UseCounter>(USE_COUNTER_FOR_CSS_PROPERTY_##method_),
+  #include "nsCSSPropList.h"
+  #undef CSS_PROP
+  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
+  #undef CSS_PROP_PUBLIC_OR_PRIVATE
+};
+
 // Check that all logical property flags are used appropriately.
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_,         \
                  kwtable_, stylestruct_, stylestructoffset_, animtype_)     \
   static_assert(!((flags_) & CSS_PROPERTY_LOGICAL),                         \
                 "only properties defined with CSS_PROP_LOGICAL can use "    \
                 "the CSS_PROPERTY_LOGICAL flag");                           \
   static_assert(!((flags_) & CSS_PROPERTY_LOGICAL_AXIS),                    \
                 "only properties defined with CSS_PROP_LOGICAL can use "    \
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -10,16 +10,17 @@
 
 #ifndef nsCSSProps_h___
 #define nsCSSProps_h___
 
 #include "nsString.h"
 #include "nsCSSProperty.h"
 #include "nsStyleStructFwd.h"
 #include "nsCSSKeywords.h"
+#include "mozilla/UseCounter.h"
 
 // Length of the "--" prefix on custom names (such as custom property names,
 // and, in the future, custom media query names).
 #define CSS_CUSTOM_NAME_PREFIX_LENGTH 2
 
 // Flags for ParseVariant method
 #define VARIANT_KEYWORD         0x000001  // K
 #define VARIANT_LENGTH          0x000002  // L
@@ -511,16 +512,30 @@ private:
 public:
 
   static bool IsEnabled(nsCSSProperty aProperty) {
     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
                "out of range");
     return gPropertyEnabled[aProperty];
   }
 
+private:
+  // A table for the use counter associated with each CSS property.  If a
+  // property does not have a use counter defined in UseCounters.conf, then
+  // its associated entry is |eUseCounter_UNKNOWN|.
+  static const mozilla::UseCounter gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands];
+
+public:
+
+  static mozilla::UseCounter UseCounterFor(nsCSSProperty aProperty) {
+    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
+               "out of range");
+    return gPropertyUseCounter[aProperty];
+  }
+
   static bool IsEnabled(nsCSSProperty aProperty, EnabledState aEnabled)
   {
     if (IsEnabled(aProperty)) {
       return true;
     }
     if (aEnabled == eIgnoreEnabledState) {
       return true;
     }