layout/style/nsCSSDataBlock.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * compact representation of the property-value pairs within a CSS
     8  * declaration, and the code for expanding and compacting it
     9  */
    11 #include "nsCSSDataBlock.h"
    12 #include "mozilla/MemoryReporting.h"
    13 #include "mozilla/css/Declaration.h"
    14 #include "mozilla/css/ImageLoader.h"
    15 #include "nsRuleData.h"
    16 #include "nsStyleSet.h"
    17 #include "nsStyleContext.h"
    18 #include "nsIDocument.h"
    20 using namespace mozilla;
    22 /**
    23  * Does a fast move of aSource to aDest.  The previous value in
    24  * aDest is cleanly destroyed, and aSource is cleared.  Returns
    25  * true if, before the copy, the value at aSource compared unequal
    26  * to the value at aDest; false otherwise.
    27  */
    28 static bool
    29 MoveValue(nsCSSValue* aSource, nsCSSValue* aDest)
    30 {
    31     bool changed = (*aSource != *aDest);
    32     aDest->~nsCSSValue();
    33     memcpy(aDest, aSource, sizeof(nsCSSValue));
    34     new (aSource) nsCSSValue();
    35     return changed;
    36 }
    38 static bool
    39 ShouldIgnoreColors(nsRuleData *aRuleData)
    40 {
    41     return aRuleData->mLevel != nsStyleSet::eAgentSheet &&
    42            aRuleData->mLevel != nsStyleSet::eUserSheet &&
    43            !aRuleData->mPresContext->UseDocumentColors();
    44 }
    46 /**
    47  * Tries to call |nsCSSValue::StartImageLoad()| on an image source.
    48  * Image sources are specified by |url()| or |-moz-image-rect()| function.
    49  */
    50 static void
    51 TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
    52                            nsCSSValueTokenStream* aTokenStream)
    53 {
    54   MOZ_ASSERT(aDocument);
    56   if (aValue.GetUnit() == eCSSUnit_URL) {
    57     aValue.StartImageLoad(aDocument);
    58     if (aTokenStream) {
    59       aTokenStream->mImageValues.PutEntry(aValue.GetImageStructValue());
    60     }
    61   }
    62   else if (aValue.GetUnit() == eCSSUnit_Image) {
    63     // If we already have a request, see if this document needs to clone it.
    64     imgIRequest* request = aValue.GetImageValue(nullptr);
    66     if (request) {
    67       mozilla::css::ImageValue* imageValue = aValue.GetImageStructValue();
    68       aDocument->StyleImageLoader()->MaybeRegisterCSSImage(imageValue);
    69       if (aTokenStream) {
    70         aTokenStream->mImageValues.PutEntry(imageValue);
    71       }
    72     }
    73   }
    74   else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
    75     nsCSSValue::Array* arguments = aValue.GetArrayValue();
    76     NS_ABORT_IF_FALSE(arguments->Count() == 6, "unexpected num of arguments");
    78     const nsCSSValue& image = arguments->Item(1);
    79     TryToStartImageLoadOnValue(image, aDocument, aTokenStream);
    80   }
    81 }
    83 static void
    84 TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument,
    85                     nsCSSProperty aProperty,
    86                     nsCSSValueTokenStream* aTokenStream)
    87 {
    88   if (aValue.GetUnit() == eCSSUnit_List) {
    89     for (const nsCSSValueList* l = aValue.GetListValue(); l; l = l->mNext) {
    90       TryToStartImageLoad(l->mValue, aDocument, aProperty, aTokenStream);
    91     }
    92   } else if (nsCSSProps::PropHasFlags(aProperty,
    93                                       CSS_PROPERTY_IMAGE_IS_IN_ARRAY_0)) {
    94     if (aValue.GetUnit() == eCSSUnit_Array) {
    95       TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument,
    96                                  aTokenStream);
    97     }
    98   } else {
    99     TryToStartImageLoadOnValue(aValue, aDocument, aTokenStream);
   100   }
   101 }
   103 static inline bool
   104 ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSProperty aProperty)
   105 {
   106   // Don't initiate image loads for if-visited styles.  This is
   107   // important because:
   108   //  (1) it's a waste of CPU and bandwidth
   109   //  (2) in some cases we'd start the image load on a style change
   110   //      where we wouldn't have started the load initially, which makes
   111   //      which links are visited detectable to Web pages (see bug
   112   //      557287)
   113   return !aRuleData->mStyleContext->IsStyleIfVisited() &&
   114          nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_START_IMAGE_LOADS);
   115 }
   117 static void
   118 MapSinglePropertyInto(nsCSSProperty aProp,
   119                       const nsCSSValue* aValue,
   120                       nsCSSValue* aTarget,
   121                       nsRuleData* aRuleData)
   122 {
   123     NS_ABORT_IF_FALSE(aValue->GetUnit() != eCSSUnit_Null, "oops");
   125     // Although aTarget is the nsCSSValue we are going to write into,
   126     // we also look at its value before writing into it.  This is done
   127     // when aTarget is a token stream value, which is the case when we
   128     // have just re-parsed a property that had a variable reference (in
   129     // nsCSSParser::ParsePropertyWithVariableReferences).  TryToStartImageLoad
   130     // then records any resulting ImageValue objects on the
   131     // nsCSSValueTokenStream object we found on aTarget.  See the comment
   132     // above nsCSSValueTokenStream::mImageValues for why.
   133     NS_ABORT_IF_FALSE(aTarget->GetUnit() == eCSSUnit_TokenStream ||
   134                       aTarget->GetUnit() == eCSSUnit_Null,
   135                       "aTarget must only be a token stream (when re-parsing "
   136                       "properties with variable references) or null");
   138     nsCSSValueTokenStream* tokenStream =
   139         aTarget->GetUnit() == eCSSUnit_TokenStream ?
   140             aTarget->GetTokenStreamValue() :
   141             nullptr;
   143     if (ShouldStartImageLoads(aRuleData, aProp)) {
   144         nsIDocument* doc = aRuleData->mPresContext->Document();
   145         TryToStartImageLoad(*aValue, doc, aProp, tokenStream);
   146     }
   147     *aTarget = *aValue;
   148     if (nsCSSProps::PropHasFlags(aProp,
   149             CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) &&
   150         ShouldIgnoreColors(aRuleData))
   151     {
   152         if (aProp == eCSSProperty_background_color) {
   153             // Force non-'transparent' background
   154             // colors to the user's default.
   155             if (aTarget->IsNonTransparentColor()) {
   156                 aTarget->SetColorValue(aRuleData->mPresContext->
   157                                        DefaultBackgroundColor());
   158             }
   159         } else {
   160             // Ignore 'color', 'border-*-color', etc.
   161             *aTarget = nsCSSValue();
   162         }
   163     }
   164 }
   166 void
   167 nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
   168 {
   169     // If we have no data for these structs, then return immediately.
   170     // This optimization should make us return most of the time, so we
   171     // have to worry much less (although still some) about the speed of
   172     // the rest of the function.
   173     if (!(aRuleData->mSIDs & mStyleBits))
   174         return;
   176     for (uint32_t i = 0; i < mNumProps; i++) {
   177         nsCSSProperty iProp = PropertyAtIndex(i);
   178         if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
   179             aRuleData->mSIDs) {
   180             nsCSSValue* target = aRuleData->ValueFor(iProp);
   181             if (target->GetUnit() == eCSSUnit_Null) {
   182                 const nsCSSValue *val = ValueAtIndex(i);
   183                 MapSinglePropertyInto(iProp, val, target, aRuleData);
   184             }
   185         }
   186     }
   187 }
   189 const nsCSSValue*
   190 nsCSSCompressedDataBlock::ValueFor(nsCSSProperty aProperty) const
   191 {
   192     NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty),
   193                       "Don't call for shorthands");
   195     // If we have no data for this struct, then return immediately.
   196     // This optimization should make us return most of the time, so we
   197     // have to worry much less (although still some) about the speed of
   198     // the rest of the function.
   199     if (!(nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]) &
   200           mStyleBits))
   201         return nullptr;
   203     for (uint32_t i = 0; i < mNumProps; i++) {
   204         if (PropertyAtIndex(i) == aProperty) {
   205             return ValueAtIndex(i);
   206         }
   207     }
   209     return nullptr;
   210 }
   212 bool
   213 nsCSSCompressedDataBlock::TryReplaceValue(nsCSSProperty aProperty,
   214                                           nsCSSExpandedDataBlock& aFromBlock,
   215                                           bool *aChanged)
   216 {
   217     nsCSSValue* newValue = aFromBlock.PropertyAt(aProperty);
   218     NS_ABORT_IF_FALSE(newValue && newValue->GetUnit() != eCSSUnit_Null,
   219                       "cannot replace with empty value");
   221     const nsCSSValue* oldValue = ValueFor(aProperty);
   222     if (!oldValue) {
   223         *aChanged = false;
   224         return false;
   225     }
   227     *aChanged = MoveValue(newValue, const_cast<nsCSSValue*>(oldValue));
   228     aFromBlock.ClearPropertyBit(aProperty);
   229     return true;
   230 }
   232 nsCSSCompressedDataBlock*
   233 nsCSSCompressedDataBlock::Clone() const
   234 {
   235     nsAutoPtr<nsCSSCompressedDataBlock>
   236         result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps));
   238     result->mStyleBits = mStyleBits;
   240     for (uint32_t i = 0; i < mNumProps; i++) {
   241         result->SetPropertyAtIndex(i, PropertyAtIndex(i));
   242         result->CopyValueToIndex(i, ValueAtIndex(i));
   243     }
   245     return result.forget();
   246 }
   248 nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock()
   249 {
   250     for (uint32_t i = 0; i < mNumProps; i++) {
   251 #ifdef DEBUG
   252         (void)PropertyAtIndex(i);   // this checks the property is in range
   253 #endif
   254         const nsCSSValue* val = ValueAtIndex(i);
   255         NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops");
   256         val->~nsCSSValue();
   257     }
   258 }
   260 /* static */ nsCSSCompressedDataBlock*
   261 nsCSSCompressedDataBlock::CreateEmptyBlock()
   262 {
   263     nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0);
   264     return result;
   265 }
   267 size_t
   268 nsCSSCompressedDataBlock::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   269 {
   270     size_t n = aMallocSizeOf(this);
   271     for (uint32_t i = 0; i < mNumProps; i++) {
   272         n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf);
   273     }
   274     return n;
   275 }
   277 bool
   278 nsCSSCompressedDataBlock::HasDefaultBorderImageSlice() const
   279 {
   280   const nsCSSValueList *slice =
   281     ValueFor(eCSSProperty_border_image_slice)->GetListValue();
   282   return !slice->mNext &&
   283          slice->mValue.GetRectValue().AllSidesEqualTo(
   284            nsCSSValue(1.0f, eCSSUnit_Percent));
   285 }
   287 bool
   288 nsCSSCompressedDataBlock::HasDefaultBorderImageWidth() const
   289 {
   290   const nsCSSRect &width =
   291     ValueFor(eCSSProperty_border_image_width)->GetRectValue();
   292   return width.AllSidesEqualTo(nsCSSValue(1.0f, eCSSUnit_Number));
   293 }
   295 bool
   296 nsCSSCompressedDataBlock::HasDefaultBorderImageOutset() const
   297 {
   298   const nsCSSRect &outset =
   299     ValueFor(eCSSProperty_border_image_outset)->GetRectValue();
   300   return outset.AllSidesEqualTo(nsCSSValue(0.0f, eCSSUnit_Number));
   301 }
   303 bool
   304 nsCSSCompressedDataBlock::HasDefaultBorderImageRepeat() const
   305 {
   306   const nsCSSValuePair &repeat =
   307     ValueFor(eCSSProperty_border_image_repeat)->GetPairValue();
   308   return repeat.BothValuesEqualTo(
   309     nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, eCSSUnit_Enumerated));
   310 }
   312 /*****************************************************************************/
   314 nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
   315 {
   316     AssertInitialState();
   317 }
   319 nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock()
   320 {
   321     AssertInitialState();
   322 }
   324 void
   325 nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
   326                                  bool aImportant)
   327 {
   328     /*
   329      * Save needless copying and allocation by copying the memory
   330      * corresponding to the stored data in the compressed block.
   331      */
   332     for (uint32_t i = 0; i < aBlock->mNumProps; i++) {
   333         nsCSSProperty iProp = aBlock->PropertyAtIndex(i);
   334         NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
   335         NS_ABORT_IF_FALSE(!HasPropertyBit(iProp),
   336                           "compressed block has property multiple times");
   337         SetPropertyBit(iProp);
   338         if (aImportant)
   339             SetImportantBit(iProp);
   341         const nsCSSValue* val = aBlock->ValueAtIndex(i);
   342         nsCSSValue* dest = PropertyAt(iProp);
   343         NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops");
   344         NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null,
   345                           "expanding into non-empty block");
   346 #ifdef NS_BUILD_REFCNT_LOGGING
   347         dest->~nsCSSValue();
   348 #endif
   349         memcpy(dest, val, sizeof(nsCSSValue));
   350     }
   352     // Set the number of properties to zero so that we don't destroy the
   353     // remnants of what we just copied.
   354     aBlock->SetNumPropsToZero();
   355     delete aBlock;
   356 }
   358 void
   359 nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock,
   360                                nsCSSCompressedDataBlock *aImportantBlock)
   361 {
   362     NS_ABORT_IF_FALSE(aNormalBlock, "unexpected null block");
   363     AssertInitialState();
   365     DoExpand(aNormalBlock, false);
   366     if (aImportantBlock) {
   367         DoExpand(aImportantBlock, true);
   368     }
   369 }
   371 void
   372 nsCSSExpandedDataBlock::ComputeNumProps(uint32_t* aNumPropsNormal,
   373                                         uint32_t* aNumPropsImportant)
   374 {
   375     *aNumPropsNormal = *aNumPropsImportant = 0;
   376     for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) {
   377         if (!mPropertiesSet.HasPropertyInChunk(iHigh))
   378             continue;
   379         for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) {
   380             if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
   381                 continue;
   382 #ifdef DEBUG
   383             nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow);
   384 #endif
   385             NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
   386             NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null,
   387                               "null value while computing size");
   388             if (mPropertiesImportant.HasPropertyAt(iHigh, iLow))
   389                 (*aNumPropsImportant)++;
   390             else
   391                 (*aNumPropsNormal)++;
   392         }
   393     }
   394 }
   396 void
   397 nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
   398                                  nsCSSCompressedDataBlock **aImportantBlock)
   399 {
   400     nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important;
   401     uint32_t i_normal = 0, i_important = 0;
   403     uint32_t numPropsNormal, numPropsImportant;
   404     ComputeNumProps(&numPropsNormal, &numPropsImportant);
   406     result_normal =
   407         new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal);
   409     if (numPropsImportant != 0) {
   410         result_important =
   411             new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant);
   412     } else {
   413         result_important = nullptr;
   414     }
   416     /*
   417      * Save needless copying and allocation by copying the memory
   418      * corresponding to the stored data in the expanded block, and then
   419      * clearing the data in the expanded block.
   420      */
   421     for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) {
   422         if (!mPropertiesSet.HasPropertyInChunk(iHigh))
   423             continue;
   424         for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) {
   425             if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
   426                 continue;
   427             nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow);
   428             NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
   429             bool important =
   430                 mPropertiesImportant.HasPropertyAt(iHigh, iLow);
   431             nsCSSCompressedDataBlock *result =
   432                 important ? result_important : result_normal;
   433             uint32_t* ip = important ? &i_important : &i_normal;
   434             nsCSSValue* val = PropertyAt(iProp);
   435             NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null,
   436                               "Null value while compressing");
   437             result->SetPropertyAtIndex(*ip, iProp);
   438             result->RawCopyValueToIndex(*ip, val);
   439             new (val) nsCSSValue();
   440             (*ip)++;
   441             result->mStyleBits |=
   442                 nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
   443         }
   444     }
   446     NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps");
   448     if (result_important) {
   449         NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps");
   450     }
   452     ClearSets();
   453     AssertInitialState();
   454     *aNormalBlock = result_normal.forget();
   455     *aImportantBlock = result_important.forget();
   456 }
   458 void
   459 nsCSSExpandedDataBlock::AddLonghandProperty(nsCSSProperty aProperty,
   460                                             const nsCSSValue& aValue)
   461 {
   462     NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty),
   463                       "property out of range");
   464     nsCSSValue& storage = *static_cast<nsCSSValue*>(PropertyAt(aProperty));
   465     storage = aValue;
   466     SetPropertyBit(aProperty);
   467 }
   469 void
   470 nsCSSExpandedDataBlock::Clear()
   471 {
   472     for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) {
   473         if (!mPropertiesSet.HasPropertyInChunk(iHigh))
   474             continue;
   475         for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) {
   476             if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
   477                 continue;
   478             nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow);
   479             ClearLonghandProperty(iProp);
   480         }
   481     }
   483     AssertInitialState();
   484 }
   486 void
   487 nsCSSExpandedDataBlock::ClearProperty(nsCSSProperty aPropID)
   488 {
   489   if (nsCSSProps::IsShorthand(aPropID)) {
   490     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) {
   491       ClearLonghandProperty(*p);
   492     }
   493   } else {
   494     ClearLonghandProperty(aPropID);
   495   }
   496 }
   498 void
   499 nsCSSExpandedDataBlock::ClearLonghandProperty(nsCSSProperty aPropID)
   500 {
   501     NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID), "out of range");
   503     ClearPropertyBit(aPropID);
   504     ClearImportantBit(aPropID);
   505     PropertyAt(aPropID)->Reset();
   506 }
   508 bool
   509 nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
   510                                           nsCSSProperty aPropID,
   511                                           bool aIsImportant,
   512                                           bool aOverrideImportant,
   513                                           bool aMustCallValueAppended,
   514                                           css::Declaration* aDeclaration)
   515 {
   516     if (!nsCSSProps::IsShorthand(aPropID)) {
   517         return DoTransferFromBlock(aFromBlock, aPropID,
   518                                    aIsImportant, aOverrideImportant,
   519                                    aMustCallValueAppended, aDeclaration);
   520     }
   522     bool changed = false;
   523     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) {
   524         changed |= DoTransferFromBlock(aFromBlock, *p,
   525                                        aIsImportant, aOverrideImportant,
   526                                        aMustCallValueAppended, aDeclaration);
   527     }
   528     return changed;
   529 }
   531 bool
   532 nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
   533                                             nsCSSProperty aPropID,
   534                                             bool aIsImportant,
   535                                             bool aOverrideImportant,
   536                                             bool aMustCallValueAppended,
   537                                             css::Declaration* aDeclaration)
   538 {
   539   bool changed = false;
   540   NS_ABORT_IF_FALSE(aFromBlock.HasPropertyBit(aPropID), "oops");
   541   if (aIsImportant) {
   542     if (!HasImportantBit(aPropID))
   543       changed = true;
   544     SetImportantBit(aPropID);
   545   } else {
   546     if (HasImportantBit(aPropID)) {
   547       // When parsing a declaration block, an !important declaration
   548       // is not overwritten by an ordinary declaration of the same
   549       // property later in the block.  However, CSSOM manipulations
   550       // come through here too, and in that case we do want to
   551       // overwrite the property.
   552       if (!aOverrideImportant) {
   553         aFromBlock.ClearLonghandProperty(aPropID);
   554         return false;
   555       }
   556       changed = true;
   557       ClearImportantBit(aPropID);
   558     }
   559   }
   561   if (aMustCallValueAppended || !HasPropertyBit(aPropID)) {
   562     aDeclaration->ValueAppended(aPropID);
   563   }
   565   SetPropertyBit(aPropID);
   566   aFromBlock.ClearPropertyBit(aPropID);
   568   /*
   569    * Save needless copying and allocation by calling the destructor in
   570    * the destination, copying memory directly, and then using placement
   571    * new.
   572    */
   573   changed |= MoveValue(aFromBlock.PropertyAt(aPropID), PropertyAt(aPropID));
   574   return changed;
   575 }
   577 void
   578 nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSProperty aPropID,
   579                                         nsRuleData* aRuleData) const
   580 {
   581   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID));
   583   const nsCSSValue* src = PropertyAt(aPropID);
   584   MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null);
   586   nsCSSValue* dest = aRuleData->ValueFor(aPropID);
   587   MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream &&
   588              dest->GetTokenStreamValue()->mPropertyID == aPropID);
   590   MapSinglePropertyInto(aPropID, src, dest, aRuleData);
   591 }
   593 #ifdef DEBUG
   594 void
   595 nsCSSExpandedDataBlock::DoAssertInitialState()
   596 {
   597     mPropertiesSet.AssertIsEmpty("not initial state");
   598     mPropertiesImportant.AssertIsEmpty("not initial state");
   600     for (uint32_t i = 0; i < eCSSProperty_COUNT_no_shorthands; ++i) {
   601         nsCSSProperty prop = nsCSSProperty(i);
   602         NS_ABORT_IF_FALSE(PropertyAt(prop)->GetUnit() == eCSSUnit_Null,
   603                           "not initial state");
   604     }
   605 }
   606 #endif

mercurial