layout/style/Declaration.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/Declaration.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,361 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * representation of a declaration block (or style attribute) in a CSS
    1.11 + * stylesheet
    1.12 + */
    1.13 +
    1.14 +#ifndef mozilla_css_Declaration_h
    1.15 +#define mozilla_css_Declaration_h
    1.16 +
    1.17 +// This header is in EXPORTS because it's used in several places in content/,
    1.18 +// but it's not really a public interface.
    1.19 +#ifndef MOZILLA_INTERNAL_API
    1.20 +#error "This file should only be included within libxul"
    1.21 +#endif
    1.22 +
    1.23 +#include "mozilla/Attributes.h"
    1.24 +#include "mozilla/MemoryReporting.h"
    1.25 +#include "CSSVariableDeclarations.h"
    1.26 +#include "nsCSSDataBlock.h"
    1.27 +#include "nsCSSProperty.h"
    1.28 +#include "nsCSSProps.h"
    1.29 +#include "nsStringFwd.h"
    1.30 +#include "nsTArray.h"
    1.31 +#include <stdio.h>
    1.32 +
    1.33 +namespace mozilla {
    1.34 +namespace css {
    1.35 +
    1.36 +// Declaration objects have unusual lifetime rules.  Every declaration
    1.37 +// begins life in an invalid state which ends when InitializeEmpty or
    1.38 +// CompressFrom is called upon it.  After that, it can be attached to
    1.39 +// exactly one style rule, and will be destroyed when that style rule
    1.40 +// is destroyed.  A declaration becomes immutable when its style rule's
    1.41 +// |RuleMatched| method is called; after that, it must be copied before
    1.42 +// it can be modified, which is taken care of by |EnsureMutable|.
    1.43 +
    1.44 +class Declaration {
    1.45 +public:
    1.46 +  /**
    1.47 +   * Construct an |Declaration| that is in an invalid state (null
    1.48 +   * |mData|) and cannot be used until its |CompressFrom| method or
    1.49 +   * |InitializeEmpty| method is called.
    1.50 +   */
    1.51 +  Declaration();
    1.52 +
    1.53 +  Declaration(const Declaration& aCopy);
    1.54 +
    1.55 +  ~Declaration();
    1.56 +
    1.57 +  /**
    1.58 +   * |ValueAppended| must be called to maintain this declaration's
    1.59 +   * |mOrder| whenever a property is parsed into an expanded data block
    1.60 +   * for this declaration.  aProperty must not be a shorthand.
    1.61 +   */
    1.62 +  void ValueAppended(nsCSSProperty aProperty);
    1.63 +
    1.64 +  void RemoveProperty(nsCSSProperty aProperty);
    1.65 +
    1.66 +  bool HasProperty(nsCSSProperty aProperty) const;
    1.67 +
    1.68 +  void GetValue(nsCSSProperty aProperty, nsAString& aValue) const;
    1.69 +  void GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const;
    1.70 +
    1.71 +  bool HasImportantData() const {
    1.72 +    return mImportantData || mImportantVariables;
    1.73 +  }
    1.74 +  bool GetValueIsImportant(nsCSSProperty aProperty) const;
    1.75 +  bool GetValueIsImportant(const nsAString& aProperty) const;
    1.76 +
    1.77 +  /**
    1.78 +   * Adds a custom property declaration to this object.
    1.79 +   *
    1.80 +   * @param aName The variable name (i.e., without the "--" prefix).
    1.81 +   * @param aType The type of value the variable has.
    1.82 +   * @param aValue The value of the variable, if aType is
    1.83 +   *   CSSVariableDeclarations::eTokenStream.
    1.84 +   * @param aIsImportant Whether the declaration is !important.
    1.85 +   * @param aOverrideImportant When aIsImportant is false, whether an
    1.86 +   *   existing !important declaration will be overridden.
    1.87 +   */
    1.88 +  void AddVariableDeclaration(const nsAString& aName,
    1.89 +                              CSSVariableDeclarations::Type aType,
    1.90 +                              const nsString& aValue,
    1.91 +                              bool aIsImportant,
    1.92 +                              bool aOverrideImportant);
    1.93 +
    1.94 +  /**
    1.95 +   * Removes a custom property declaration from this object.
    1.96 +   *
    1.97 +   * @param aName The variable name (i.e., without the "--" prefix).
    1.98 +   */
    1.99 +  void RemoveVariableDeclaration(const nsAString& aName);
   1.100 +
   1.101 +  /**
   1.102 +   * Returns whether a custom property declaration for a variable with
   1.103 +   * a given name exists on this object.
   1.104 +   *
   1.105 +   * @param aName The variable name (i.e., without the "--" prefix).
   1.106 +   */
   1.107 +  bool HasVariableDeclaration(const nsAString& aName) const;
   1.108 +
   1.109 +  /**
   1.110 +   * Gets the string value for a custom property declaration of a variable
   1.111 +   * with a given name.
   1.112 +   *
   1.113 +   * @param aName The variable name (i.e., without the "--" prefix).
   1.114 +   * @param aValue Out parameter into which the variable's value will be
   1.115 +   *   stored.  If the value is 'initial' or 'inherit', that exact string
   1.116 +   *   will be stored in aValue.
   1.117 +   */
   1.118 +  void GetVariableDeclaration(const nsAString& aName, nsAString& aValue) const;
   1.119 +
   1.120 +  /**
   1.121 +   * Returns whether the custom property declaration for a variable with
   1.122 +   * the given name was !important.
   1.123 +   */
   1.124 +  bool GetVariableValueIsImportant(const nsAString& aName) const;
   1.125 +
   1.126 +  uint32_t Count() const {
   1.127 +    return mOrder.Length();
   1.128 +  }
   1.129 +
   1.130 +  // Returns whether we actually had a property at aIndex
   1.131 +  bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
   1.132 +
   1.133 +  void ToString(nsAString& aString) const;
   1.134 +
   1.135 +  nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
   1.136 +  nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
   1.137 +
   1.138 +  /**
   1.139 +   * Initialize this declaration as holding no data.  Cannot fail.
   1.140 +   */
   1.141 +  void InitializeEmpty();
   1.142 +
   1.143 +  /**
   1.144 +   * Transfer all of the state from |aExpandedData| into this declaration.
   1.145 +   * After calling, |aExpandedData| should be in its initial state.
   1.146 +   * Callers must make sure mOrder is updated as necessary.
   1.147 +   */
   1.148 +  void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
   1.149 +    NS_ABORT_IF_FALSE(!mData, "oops");
   1.150 +    NS_ABORT_IF_FALSE(!mImportantData, "oops");
   1.151 +    aExpandedData->Compress(getter_Transfers(mData),
   1.152 +                            getter_Transfers(mImportantData));
   1.153 +    aExpandedData->AssertInitialState();
   1.154 +  }
   1.155 +
   1.156 +  /**
   1.157 +   * Transfer all of the state from this declaration into
   1.158 +   * |aExpandedData| and put this declaration temporarily into an
   1.159 +   * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
   1.160 +   * should last only during parsing.  During this time only
   1.161 +   * |ValueAppended| should be called.
   1.162 +   */
   1.163 +  void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) {
   1.164 +    AssertMutable();
   1.165 +    aExpandedData->AssertInitialState();
   1.166 +
   1.167 +    NS_ABORT_IF_FALSE(mData, "oops");
   1.168 +    aExpandedData->Expand(mData.forget(), mImportantData.forget());
   1.169 +  }
   1.170 +
   1.171 +  /**
   1.172 +   * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
   1.173 +   * rule using this declaration for storage.
   1.174 +   */
   1.175 +  void MapNormalRuleInfoInto(nsRuleData *aRuleData) const {
   1.176 +    NS_ABORT_IF_FALSE(mData, "called while expanded");
   1.177 +    mData->MapRuleInfoInto(aRuleData);
   1.178 +    if (mVariables) {
   1.179 +      mVariables->MapRuleInfoInto(aRuleData);
   1.180 +    }
   1.181 +  }
   1.182 +  void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
   1.183 +    NS_ABORT_IF_FALSE(mData, "called while expanded");
   1.184 +    NS_ABORT_IF_FALSE(mImportantData || mImportantVariables,
   1.185 +                      "must have important data or variables");
   1.186 +    if (mImportantData) {
   1.187 +      mImportantData->MapRuleInfoInto(aRuleData);
   1.188 +    }
   1.189 +    if (mImportantVariables) {
   1.190 +      mImportantVariables->MapRuleInfoInto(aRuleData);
   1.191 +    }
   1.192 +  }
   1.193 +
   1.194 +  /**
   1.195 +   * Attempt to replace the value for |aProperty| stored in this
   1.196 +   * declaration with the matching value from |aFromBlock|.
   1.197 +   * This method may only be called on a mutable declaration.
   1.198 +   * It will fail (returning false) if |aProperty| is shorthand,
   1.199 +   * is not already in this declaration, or does not have the indicated
   1.200 +   * importance level.  If it returns true, it erases the value in
   1.201 +   * |aFromBlock|.  |aChanged| is set to true if the declaration
   1.202 +   * changed as a result of the call, and to false otherwise.
   1.203 +   */
   1.204 +  bool TryReplaceValue(nsCSSProperty aProperty, bool aIsImportant,
   1.205 +                         nsCSSExpandedDataBlock& aFromBlock,
   1.206 +                         bool* aChanged)
   1.207 +  {
   1.208 +    AssertMutable();
   1.209 +    NS_ABORT_IF_FALSE(mData, "called while expanded");
   1.210 +
   1.211 +    if (nsCSSProps::IsShorthand(aProperty)) {
   1.212 +      *aChanged = false;
   1.213 +      return false;
   1.214 +    }
   1.215 +    nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
   1.216 +    // mImportantData might be null
   1.217 +    if (!block) {
   1.218 +      *aChanged = false;
   1.219 +      return false;
   1.220 +    }
   1.221 +
   1.222 +#ifdef DEBUG
   1.223 +    {
   1.224 +      nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData;
   1.225 +      NS_ABORT_IF_FALSE(!other || !other->ValueFor(aProperty) ||
   1.226 +                        !block->ValueFor(aProperty),
   1.227 +                        "Property both important and not?");
   1.228 +    }
   1.229 +#endif
   1.230 +    return block->TryReplaceValue(aProperty, aFromBlock, aChanged);
   1.231 +  }
   1.232 +
   1.233 +  bool HasNonImportantValueFor(nsCSSProperty aProperty) const {
   1.234 +    NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
   1.235 +    return !!mData->ValueFor(aProperty);
   1.236 +  }
   1.237 +
   1.238 +  /**
   1.239 +   * Return whether |this| may be modified.
   1.240 +   */
   1.241 +  bool IsMutable() const {
   1.242 +    return !mImmutable;
   1.243 +  }
   1.244 +
   1.245 +  /**
   1.246 +   * Copy |this|, if necessary to ensure that it can be modified.
   1.247 +   */
   1.248 +  Declaration* EnsureMutable();
   1.249 +
   1.250 +  /**
   1.251 +   * Crash if |this| cannot be modified.
   1.252 +   */
   1.253 +  void AssertMutable() const {
   1.254 +    NS_ABORT_IF_FALSE(IsMutable(), "someone forgot to call EnsureMutable");
   1.255 +  }
   1.256 +
   1.257 +  /**
   1.258 +   * Mark this declaration as unmodifiable.  It's 'const' so it can
   1.259 +   * be called from ToString.
   1.260 +   */
   1.261 +  void SetImmutable() const { mImmutable = true; }
   1.262 +
   1.263 +  /**
   1.264 +   * Clear the data, in preparation for its replacement with entirely
   1.265 +   * new data by a call to |CompressFrom|.
   1.266 +   */
   1.267 +  void ClearData() {
   1.268 +    AssertMutable();
   1.269 +    mData = nullptr;
   1.270 +    mImportantData = nullptr;
   1.271 +    mVariables = nullptr;
   1.272 +    mImportantVariables = nullptr;
   1.273 +    mOrder.Clear();
   1.274 +    mVariableOrder.Clear();
   1.275 +  }
   1.276 +
   1.277 +#ifdef DEBUG
   1.278 +  void List(FILE* out = stdout, int32_t aIndent = 0) const;
   1.279 +#endif
   1.280 +
   1.281 +private:
   1.282 +  Declaration& operator=(const Declaration& aCopy) MOZ_DELETE;
   1.283 +  bool operator==(const Declaration& aCopy) const MOZ_DELETE;
   1.284 +
   1.285 +  void GetValue(nsCSSProperty aProperty, nsAString& aValue,
   1.286 +                nsCSSValue::Serialization aValueSerialization) const;
   1.287 +
   1.288 +  static void AppendImportanceToString(bool aIsImportant, nsAString& aString);
   1.289 +  // return whether there was a value in |aValue| (i.e., it had a non-null unit)
   1.290 +  bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const;
   1.291 +  bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult,
   1.292 +                           nsCSSValue::Serialization aValueSerialization) const;
   1.293 +  // Helper for ToString with strange semantics regarding aValue.
   1.294 +  void AppendPropertyAndValueToString(nsCSSProperty aProperty,
   1.295 +                                      nsAutoString& aValue,
   1.296 +                                      nsAString& aResult) const;
   1.297 +  // helper for ToString that serializes a custom property declaration for
   1.298 +  // a variable with the specified name
   1.299 +  void AppendVariableAndValueToString(const nsAString& aName,
   1.300 +                                      nsAString& aResult) const;
   1.301 +
   1.302 +public:
   1.303 +  /**
   1.304 +   * Returns the property at the given index in the ordered list of
   1.305 +   * declarations.  For custom properties, eCSSPropertyExtra_variable
   1.306 +   * is returned.
   1.307 +   */
   1.308 +  nsCSSProperty GetPropertyAt(uint32_t aIndex) const {
   1.309 +    uint32_t value = mOrder[aIndex];
   1.310 +    if (value >= eCSSProperty_COUNT) {
   1.311 +      return eCSSPropertyExtra_variable;
   1.312 +    }
   1.313 +    return nsCSSProperty(value);
   1.314 +  }
   1.315 +
   1.316 +  /**
   1.317 +   * Gets the name of the custom property at the given index in the ordered
   1.318 +   * list of declarations.
   1.319 +   */
   1.320 +  void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const {
   1.321 +    MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT);
   1.322 +    uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT;
   1.323 +    aResult.Truncate();
   1.324 +    aResult.AppendLiteral("--");
   1.325 +    aResult.Append(mVariableOrder[variableIndex]);
   1.326 +  }
   1.327 +
   1.328 +  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   1.329 +
   1.330 +private:
   1.331 +  // The order of properties in this declaration.  Longhand properties are
   1.332 +  // represented by their nsCSSProperty value, and each custom property (--*)
   1.333 +  // is represented by a value that begins at eCSSProperty_COUNT.
   1.334 +  //
   1.335 +  // Subtracting eCSSProperty_COUNT from those values that represent custom
   1.336 +  // properties results in an index into mVariableOrder, which identifies the
   1.337 +  // specific variable the custom property declaration is for.
   1.338 +  nsAutoTArray<uint32_t, 8> mOrder;
   1.339 +
   1.340 +  // variable names of custom properties found in mOrder
   1.341 +  nsTArray<nsString> mVariableOrder;
   1.342 +
   1.343 +  // never null, except while expanded, or before the first call to
   1.344 +  // InitializeEmpty or CompressFrom.
   1.345 +  nsAutoPtr<nsCSSCompressedDataBlock> mData;
   1.346 +
   1.347 +  // may be null
   1.348 +  nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
   1.349 +
   1.350 +  // may be null
   1.351 +  nsAutoPtr<CSSVariableDeclarations> mVariables;
   1.352 +
   1.353 +  // may be null
   1.354 +  nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
   1.355 +
   1.356 +  // set by style rules when |RuleMatched| is called;
   1.357 +  // also by ToString (hence the 'mutable').
   1.358 +  mutable bool mImmutable;
   1.359 +};
   1.360 +
   1.361 +} // namespace css
   1.362 +} // namespace mozilla
   1.363 +
   1.364 +#endif /* mozilla_css_Declaration_h */

mercurial