LCOV - code coverage report
Current view: top level - layout/style - nsCSSDataBlock.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 283 338 83.7 %
Date: 2017-07-14 16:53:18 Functions: 28 33 84.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * compact representation of the property-value pairs within a CSS
       9             :  * declaration, and the code for expanding and compacting it
      10             :  */
      11             : 
      12             : #include "nsCSSDataBlock.h"
      13             : 
      14             : #include "CSSVariableImageTable.h"
      15             : #include "mozilla/css/Declaration.h"
      16             : #include "mozilla/css/ImageLoader.h"
      17             : #include "mozilla/MemoryReporting.h"
      18             : #include "mozilla/WritingModes.h"
      19             : #include "nsAutoPtr.h"
      20             : #include "nsIDocument.h"
      21             : #include "nsRuleData.h"
      22             : #include "nsStyleContext.h"
      23             : #include "nsStyleSet.h"
      24             : 
      25             : using namespace mozilla;
      26             : using namespace mozilla::css;
      27             : 
      28             : /**
      29             :  * Does a fast move of aSource to aDest.  The previous value in
      30             :  * aDest is cleanly destroyed, and aSource is cleared.  Returns
      31             :  * true if, before the copy, the value at aSource compared unequal
      32             :  * to the value at aDest; false otherwise.
      33             :  */
      34             : static bool
      35       12996 : MoveValue(nsCSSValue* aSource, nsCSSValue* aDest)
      36             : {
      37       12996 :   bool changed = (*aSource != *aDest);
      38       12996 :   aDest->~nsCSSValue();
      39       12996 :   memcpy(aDest, aSource, sizeof(nsCSSValue));
      40       12996 :   new (aSource) nsCSSValue();
      41       12996 :   return changed;
      42             : }
      43             : 
      44             : static bool
      45         815 : ShouldIgnoreColors(nsRuleData *aRuleData)
      46             : {
      47        1450 :   return aRuleData->mLevel != SheetType::Agent &&
      48        1450 :          aRuleData->mLevel != SheetType::User &&
      49        1450 :          !aRuleData->mPresContext->UseDocumentColors();
      50             : }
      51             : 
      52             : /**
      53             :  * Tries to call |nsCSSValue::StartImageLoad()| on an image source.
      54             :  * Image sources are specified by |url()| or |-moz-image-rect()| function.
      55             :  */
      56             : static void
      57         254 : TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
      58             :                            nsStyleContext* aContext, nsCSSPropertyID aProperty,
      59             :                            bool aForTokenStream)
      60             : {
      61         254 :   MOZ_ASSERT(aDocument);
      62             : 
      63         254 :   if (aValue.GetUnit() == eCSSUnit_URL) {
      64             : #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
      65             :     // The 'mask-image' property accepts local reference URIs.
      66             :     // For example,
      67             :     //   mask-image: url(#mask_id); // refer to a SVG mask element, whose id is
      68             :     //                              // "mask_id", in the current document.
      69             :     // For such 'mask-image' values (pointing to an in-document element),
      70             :     // there is no need to trigger image download.
      71          41 :     if (aProperty == eCSSProperty_mask_image) {
      72             :       // Filter out all fragment URLs.
      73             :       // Since nsCSSValue::GetURLStructValue runs much faster than
      74             :       // nsIURI::EqualsExceptRef bellow, we get performance gain by this
      75             :       // early return.
      76           1 :       URLValue* urlValue = aValue.GetURLStructValue();
      77           1 :       if (urlValue->IsLocalRef()) {
      78           1 :         return;
      79             :       }
      80             : 
      81             :       // Even though urlValue is not a fragment URL, it might still refer to
      82             :       // an internal resource.
      83             :       // For example, aDocument base URL is "http://foo/index.html" and
      84             :       // intentionally references a mask-image at
      85             :       // url(http://foo/index.html#mask) which still refers to a resource in
      86             :       // aDocument.
      87           0 :       nsIURI* imageURI = aValue.GetURLValue();
      88           0 :       if (imageURI) {
      89           0 :         nsIURI* docURI = aDocument->GetDocumentURI();
      90           0 :         bool isEqualExceptRef = false;
      91           0 :         nsresult  rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
      92           0 :         if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
      93           0 :           return;
      94             :         }
      95             :       }
      96             :     }
      97             : #endif
      98          40 :     aValue.StartImageLoad(aDocument);
      99          40 :     if (aForTokenStream && aContext) {
     100           0 :       CSSVariableImageTable::Add(aContext, aProperty,
     101           0 :                                  aValue.GetImageStructValue());
     102             :     }
     103             :   }
     104         213 :   else if (aValue.GetUnit() == eCSSUnit_Image) {
     105             :     // If we already have a request, see if this document needs to clone it.
     106         101 :     imgIRequest* request = aValue.GetImageValue(nullptr);
     107             : 
     108         101 :     if (request) {
     109         101 :       ImageValue* imageValue = aValue.GetImageStructValue();
     110         101 :       aDocument->StyleImageLoader()->MaybeRegisterCSSImage(imageValue);
     111         101 :       if (aForTokenStream && aContext) {
     112           0 :         CSSVariableImageTable::Add(aContext, aProperty, imageValue);
     113             :       }
     114             :     }
     115             :   }
     116         112 :   else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
     117           2 :     nsCSSValue::Array* arguments = aValue.GetArrayValue();
     118           2 :     MOZ_ASSERT(arguments->Count() == 6, "unexpected num of arguments");
     119             : 
     120           2 :     const nsCSSValue& image = arguments->Item(1);
     121           2 :     TryToStartImageLoadOnValue(image, aDocument, aContext, aProperty,
     122           2 :                                aForTokenStream);
     123             :   }
     124             : }
     125             : 
     126             : static void
     127         749 : TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument,
     128             :                     nsStyleContext* aContext, nsCSSPropertyID aProperty,
     129             :                     bool aForTokenStream)
     130             : {
     131         749 :   if (aValue.GetUnit() == eCSSUnit_List) {
     132         552 :     for (const nsCSSValueList* l = aValue.GetListValue(); l; l = l->mNext) {
     133         283 :       TryToStartImageLoad(l->mValue, aDocument, aContext, aProperty,
     134         283 :                           aForTokenStream);
     135             :     }
     136         480 :   } else if (nsCSSProps::PropHasFlags(aProperty,
     137             :                                       CSS_PROPERTY_IMAGE_IS_IN_ARRAY_0)) {
     138         228 :     if (aValue.GetUnit() == eCSSUnit_Array) {
     139           0 :       TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument,
     140           0 :                                  aContext, aProperty, aForTokenStream);
     141             :     }
     142             :   } else {
     143         252 :     TryToStartImageLoadOnValue(aValue, aDocument, aContext, aProperty,
     144         252 :                                aForTokenStream);
     145             :   }
     146         749 : }
     147             : 
     148             : static inline bool
     149        9948 : ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSPropertyID aProperty)
     150             : {
     151             :   // Don't initiate image loads for if-visited styles.  This is
     152             :   // important because:
     153             :   //  (1) it's a waste of CPU and bandwidth
     154             :   //  (2) in some cases we'd start the image load on a style change
     155             :   //      where we wouldn't have started the load initially, which makes
     156             :   //      which links are visited detectable to Web pages (see bug
     157             :   //      557287)
     158       19896 :   return !aRuleData->mStyleContext->IsStyleIfVisited() &&
     159       19896 :          nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_START_IMAGE_LOADS);
     160             : }
     161             : 
     162             : static void
     163        9948 : MapSinglePropertyInto(nsCSSPropertyID aTargetProp,
     164             :                       const nsCSSValue* aSrcValue,
     165             :                       nsCSSValue* aTargetValue,
     166             :                       nsRuleData* aRuleData)
     167             : {
     168        9948 :   MOZ_ASSERT(!nsCSSProps::PropHasFlags(aTargetProp, CSS_PROPERTY_LOGICAL),
     169             :              "Can't map into a logical property");
     170        9948 :   MOZ_ASSERT(aSrcValue->GetUnit() != eCSSUnit_Null, "oops");
     171             : 
     172             :   // Although aTargetValue is the nsCSSValue we are going to write into,
     173             :   // we also look at its value before writing into it.  This is done
     174             :   // when aTargetValue is a token stream value, which is the case when we
     175             :   // have just re-parsed a property that had a variable reference (in
     176             :   // nsCSSParser::ParsePropertyWithVariableReferences).  TryToStartImageLoad
     177             :   // then records any resulting ImageValue objects in the
     178             :   // CSSVariableImageTable, to give them the appropriate lifetime.
     179        9948 :   MOZ_ASSERT(aTargetValue->GetUnit() == eCSSUnit_TokenStream ||
     180             :              aTargetValue->GetUnit() == eCSSUnit_Null,
     181             :              "aTargetValue must only be a token stream (when re-parsing "
     182             :              "properties with variable references) or null");
     183             : 
     184        9948 :   if (ShouldStartImageLoads(aRuleData, aTargetProp)) {
     185         466 :     nsIDocument* doc = aRuleData->mPresContext->Document();
     186         466 :     TryToStartImageLoad(*aSrcValue, doc, aRuleData->mStyleContext,
     187             :                         aTargetProp,
     188         932 :                         aTargetValue->GetUnit() == eCSSUnit_TokenStream);
     189             :   }
     190        9948 :   *aTargetValue = *aSrcValue;
     191       19896 :   if (nsCSSProps::PropHasFlags(aTargetProp,
     192       10763 :         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) &&
     193         815 :       ShouldIgnoreColors(aRuleData))
     194             :   {
     195           0 :     if (aTargetProp == eCSSProperty_background_color) {
     196             :       // Force non-'transparent' background
     197             :       // colors to the user's default.
     198           0 :       if (aTargetValue->IsNonTransparentColor()) {
     199           0 :         aTargetValue->SetColorValue(aRuleData->mPresContext->
     200           0 :                                     DefaultBackgroundColor());
     201             :       }
     202             :     } else {
     203             :       // Ignore 'color', 'border-*-color', etc.
     204           0 :       *aTargetValue = nsCSSValue();
     205             :     }
     206             :   }
     207        9948 : }
     208             : 
     209             : /**
     210             :  * If aProperty is a logical property, converts it to the equivalent physical
     211             :  * property based on writing mode information obtained from aRuleData's
     212             :  * style context.
     213             :  */
     214             : static inline void
     215         202 : EnsurePhysicalProperty(nsCSSPropertyID& aProperty, nsRuleData* aRuleData)
     216             : {
     217             :   bool isAxisProperty =
     218         202 :     nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_AXIS);
     219             :   bool isBlock =
     220         202 :     nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_BLOCK_AXIS);
     221             : 
     222             :   int index;
     223             : 
     224         202 :   if (isAxisProperty) {
     225           0 :     LogicalAxis logicalAxis = isBlock ? eLogicalAxisBlock : eLogicalAxisInline;
     226           0 :     uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
     227             :     PhysicalAxis axis =
     228           0 :       WritingMode::PhysicalAxisForLogicalAxis(wm, logicalAxis);
     229             : 
     230             :     // We rely on physical axis constants values matching the order of the
     231             :     // physical properties in the logical group array.
     232             :     static_assert(eAxisVertical == 0 && eAxisHorizontal == 1,
     233             :                   "unexpected axis constant values");
     234           0 :     index = axis;
     235             :   } else {
     236             :     bool isEnd =
     237         202 :       nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_END_EDGE);
     238             : 
     239         202 :     LogicalEdge edge = isEnd ? eLogicalEdgeEnd : eLogicalEdgeStart;
     240             : 
     241             :     // We handle block axis logical properties separately to save a bit of
     242             :     // work that the WritingMode constructor does that is unnecessary
     243             :     // unless we have an inline axis property.
     244             :     mozilla::Side side;
     245         202 :     if (isBlock) {
     246           0 :       uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode;
     247           0 :       side = WritingMode::PhysicalSideForBlockAxis(wm, edge);
     248             :     } else {
     249         202 :       WritingMode wm(aRuleData->mStyleContext);
     250         202 :       side = wm.PhysicalSideForInlineAxis(edge);
     251             :     }
     252             : 
     253             :     // We rely on the physical side constant values matching the order of
     254             :     // the physical properties in the logical group array.
     255             :     static_assert(eSideTop == 0 && eSideRight == 1 &&
     256             :                   eSideBottom == 2 && eSideLeft == 3,
     257             :                   "unexpected side constant values");
     258         202 :     index = side;
     259             :   }
     260             : 
     261         202 :   const nsCSSPropertyID* props = nsCSSProps::LogicalGroup(aProperty);
     262         202 :   size_t len = isAxisProperty ? 2 : 4;
     263             : #ifdef DEBUG
     264        1010 :     for (size_t i = 0; i < len; i++) {
     265         808 :     MOZ_ASSERT(props[i] != eCSSProperty_UNKNOWN,
     266             :                "unexpected logical group length");
     267             :   }
     268         202 :   MOZ_ASSERT(props[len] == eCSSProperty_UNKNOWN,
     269             :              "unexpected logical group length");
     270             : #endif
     271             : 
     272         247 :   for (size_t i = 0; i < len; i++) {
     273         239 :     if (aRuleData->ValueFor(props[i])->GetUnit() == eCSSUnit_Null) {
     274             :       // A declaration of one of the logical properties in this logical
     275             :       // group (but maybe not aProperty) would be the winning
     276             :       // declaration in the cascade.  This means that it's reasonably
     277             :       // likely that this logical property could be the winning
     278             :       // declaration in the cascade for some values of writing-mode,
     279             :       // direction, and text-orientation.  (It doesn't mean that for
     280             :       // sure, though.  For example, if this is a block-start logical
     281             :       // property, and all but the bottom physical property were set.
     282             :       // But the common case we want to hit here is logical declarations
     283             :       // that are completely overridden by a shorthand.)
     284             :       //
     285             :       // If this logical property could be the winning declaration in
     286             :       // the cascade for some values of writing-mode, direction, and
     287             :       // text-orientation, then we have to fault the resulting style
     288             :       // struct out of the rule tree.  We can't cache anything on the
     289             :       // rule tree if it depends on data from the style context, since
     290             :       // data cached in the rule tree could be used with a style context
     291             :       // with a different value of the depended-upon data.
     292         194 :       uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits();
     293         194 :       aRuleData->mConditions.SetWritingModeDependency(wm);
     294         194 :       break;
     295             :     }
     296             :   }
     297             : 
     298         202 :   aProperty = props[index];
     299         202 : }
     300             : 
     301             : void
     302       31904 : nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
     303             : {
     304             :   // If we have no data for these structs, then return immediately.
     305             :   // This optimization should make us return most of the time, so we
     306             :   // have to worry much less (although still some) about the speed of
     307             :   // the rest of the function.
     308       31904 :   if (!(aRuleData->mSIDs & mStyleBits))
     309       26610 :     return;
     310             : 
     311             :   // We process these in reverse order so that we end up mapping the
     312             :   // right property when one can be expressed using both logical and
     313             :   // physical property names.
     314       40709 :   for (uint32_t i = mNumProps; i-- > 0; ) {
     315       35415 :     nsCSSPropertyID iProp = PropertyAtIndex(i);
     316       70830 :     if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
     317       35415 :         aRuleData->mSIDs) {
     318       10161 :       if (nsCSSProps::PropHasFlags(iProp, CSS_PROPERTY_LOGICAL)) {
     319         153 :         EnsurePhysicalProperty(iProp, aRuleData);
     320             :       }
     321       10161 :       nsCSSValue* target = aRuleData->ValueFor(iProp);
     322       10161 :       if (target->GetUnit() == eCSSUnit_Null) {
     323        9065 :         const nsCSSValue *val = ValueAtIndex(i);
     324             :         // In order for variable resolution to have the right information
     325             :         // about the stylesheet level of a value, that level needs to be
     326             :         // stored on the token stream. We can't do that at creation time
     327             :         // because the CSS parser (which creates the object) has no idea
     328             :         // about the stylesheet level, so we do it here instead, where
     329             :         // the rule walking will have just updated aRuleData.
     330        9065 :         if (val->GetUnit() == eCSSUnit_TokenStream) {
     331         883 :           val->GetTokenStreamValue()->mLevel = aRuleData->mLevel;
     332             :         }
     333        9065 :         MapSinglePropertyInto(iProp, val, target, aRuleData);
     334             :       }
     335             :     }
     336             :   }
     337             : }
     338             : 
     339             : const nsCSSValue*
     340         102 : nsCSSCompressedDataBlock::ValueFor(nsCSSPropertyID aProperty) const
     341             : {
     342         102 :   MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
     343             :              "Don't call for shorthands");
     344             : 
     345             :   // If we have no data for this struct, then return immediately.
     346             :   // This optimization should make us return most of the time, so we
     347             :   // have to worry much less (although still some) about the speed of
     348             :   // the rest of the function.
     349         204 :   if (!(nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]) &
     350         102 :         mStyleBits))
     351          69 :     return nullptr;
     352             : 
     353          63 :   for (uint32_t i = 0; i < mNumProps; i++) {
     354          34 :     if (PropertyAtIndex(i) == aProperty) {
     355           4 :       return ValueAtIndex(i);
     356             :     }
     357             :   }
     358             : 
     359          29 :   return nullptr;
     360             : }
     361             : 
     362             : bool
     363         102 : nsCSSCompressedDataBlock::TryReplaceValue(nsCSSPropertyID aProperty,
     364             :                                           nsCSSExpandedDataBlock& aFromBlock,
     365             :                                           bool *aChanged)
     366             : {
     367         102 :   nsCSSValue* newValue = aFromBlock.PropertyAt(aProperty);
     368         102 :   MOZ_ASSERT(newValue && newValue->GetUnit() != eCSSUnit_Null,
     369             :              "cannot replace with empty value");
     370             : 
     371         102 :   const nsCSSValue* oldValue = ValueFor(aProperty);
     372         102 :   if (!oldValue) {
     373          98 :     *aChanged = false;
     374          98 :     return false;
     375             :   }
     376             : 
     377           4 :   *aChanged = MoveValue(newValue, const_cast<nsCSSValue*>(oldValue));
     378           4 :   aFromBlock.ClearPropertyBit(aProperty);
     379           4 :   return true;
     380             : }
     381             : 
     382             : nsCSSCompressedDataBlock*
     383          15 : nsCSSCompressedDataBlock::Clone() const
     384             : {
     385             :   nsAutoPtr<nsCSSCompressedDataBlock>
     386          30 :     result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps));
     387             : 
     388          15 :   result->mStyleBits = mStyleBits;
     389             : 
     390          63 :   for (uint32_t i = 0; i < mNumProps; i++) {
     391          48 :     result->SetPropertyAtIndex(i, PropertyAtIndex(i));
     392          48 :     result->CopyValueToIndex(i, ValueAtIndex(i));
     393             :   }
     394             : 
     395          30 :   return result.forget();
     396             : }
     397             : 
     398         282 : nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock()
     399             : {
     400         167 :   for (uint32_t i = 0; i < mNumProps; i++) {
     401             : #ifdef DEBUG
     402          26 :     (void)PropertyAtIndex(i);   // this checks the property is in range
     403             : #endif
     404          26 :     const nsCSSValue* val = ValueAtIndex(i);
     405          26 :     MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null, "oops");
     406          26 :     val->~nsCSSValue();
     407             :   }
     408         141 : }
     409             : 
     410             : /* static */ nsCSSCompressedDataBlock*
     411          84 : nsCSSCompressedDataBlock::CreateEmptyBlock()
     412             : {
     413          84 :   nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0);
     414          84 :   return result;
     415             : }
     416             : 
     417             : size_t
     418          14 : nsCSSCompressedDataBlock::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     419             : {
     420          14 :   size_t n = aMallocSizeOf(this);
     421          41 :   for (uint32_t i = 0; i < mNumProps; i++) {
     422          27 :     n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf);
     423             :   }
     424          14 :   return n;
     425             : }
     426             : 
     427             : bool
     428           0 : nsCSSCompressedDataBlock::HasDefaultBorderImageSlice() const
     429             : {
     430             :   const nsCSSValueList *slice =
     431           0 :     ValueFor(eCSSProperty_border_image_slice)->GetListValue();
     432           0 :   return !slice->mNext &&
     433           0 :          slice->mValue.GetRectValue().AllSidesEqualTo(
     434           0 :            nsCSSValue(1.0f, eCSSUnit_Percent));
     435             : }
     436             : 
     437             : bool
     438           0 : nsCSSCompressedDataBlock::HasDefaultBorderImageWidth() const
     439             : {
     440             :   const nsCSSRect &width =
     441           0 :     ValueFor(eCSSProperty_border_image_width)->GetRectValue();
     442           0 :   return width.AllSidesEqualTo(nsCSSValue(1.0f, eCSSUnit_Number));
     443             : }
     444             : 
     445             : bool
     446           0 : nsCSSCompressedDataBlock::HasDefaultBorderImageOutset() const
     447             : {
     448             :   const nsCSSRect &outset =
     449           0 :     ValueFor(eCSSProperty_border_image_outset)->GetRectValue();
     450           0 :   return outset.AllSidesEqualTo(nsCSSValue(0.0f, eCSSUnit_Number));
     451             : }
     452             : 
     453             : bool
     454           0 : nsCSSCompressedDataBlock::HasDefaultBorderImageRepeat() const
     455             : {
     456             :   const nsCSSValuePair &repeat =
     457           0 :     ValueFor(eCSSProperty_border_image_repeat)->GetPairValue();
     458             :   return repeat.BothValuesEqualTo(
     459           0 :     nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, eCSSUnit_Enumerated));
     460             : }
     461             : 
     462             : /*****************************************************************************/
     463             : 
     464          25 : nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
     465             : {
     466          25 :   AssertInitialState();
     467          25 : }
     468             : 
     469          34 : nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock()
     470             : {
     471          17 :   AssertInitialState();
     472          17 : }
     473             : 
     474             : void
     475         116 : nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
     476             :                                  bool aImportant)
     477             : {
     478             :   /*
     479             :    * Save needless copying and allocation by copying the memory
     480             :    * corresponding to the stored data in the compressed block.
     481             :    */
     482         150 :   for (uint32_t i = 0; i < aBlock->mNumProps; i++) {
     483          34 :     nsCSSPropertyID iProp = aBlock->PropertyAtIndex(i);
     484          34 :     MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
     485          34 :     MOZ_ASSERT(!HasPropertyBit(iProp),
     486             :                "compressed block has property multiple times");
     487          34 :     SetPropertyBit(iProp);
     488          34 :     if (aImportant)
     489           0 :       SetImportantBit(iProp);
     490             : 
     491          34 :     const nsCSSValue* val = aBlock->ValueAtIndex(i);
     492          34 :     nsCSSValue* dest = PropertyAt(iProp);
     493          34 :     MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null, "oops");
     494          34 :     MOZ_ASSERT(dest->GetUnit() == eCSSUnit_Null,
     495             :                "expanding into non-empty block");
     496             : #ifdef NS_BUILD_REFCNT_LOGGING
     497          34 :     dest->~nsCSSValue();
     498             : #endif
     499          34 :     memcpy(dest, val, sizeof(nsCSSValue));
     500             :   }
     501             : 
     502             :   // Set the number of properties to zero so that we don't destroy the
     503             :   // remnants of what we just copied.
     504         116 :   aBlock->SetNumPropsToZero();
     505         116 :   delete aBlock;
     506         116 : }
     507             : 
     508             : void
     509         116 : nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock,
     510             :                                nsCSSCompressedDataBlock *aImportantBlock)
     511             : {
     512         116 :   MOZ_ASSERT(aNormalBlock, "unexpected null block");
     513         116 :   AssertInitialState();
     514             : 
     515         116 :   DoExpand(aNormalBlock, false);
     516         116 :   if (aImportantBlock) {
     517           0 :     DoExpand(aImportantBlock, true);
     518             :   }
     519         116 : }
     520             : 
     521             : void
     522        3118 : nsCSSExpandedDataBlock::ComputeNumProps(uint32_t* aNumPropsNormal,
     523             :                                         uint32_t* aNumPropsImportant)
     524             : {
     525        3118 :   *aNumPropsNormal = *aNumPropsImportant = 0;
     526       21826 :   for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; ++iHigh) {
     527       18708 :     if (!mPropertiesSet.HasPropertyInChunk(iHigh))
     528       14045 :       continue;
     529      303095 :     for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; ++iLow) {
     530      298432 :       if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
     531      285498 :         continue;
     532             : #ifdef DEBUG
     533       12934 :       nsCSSPropertyID iProp = nsCSSPropertyIDSet::CSSPropertyAt(iHigh, iLow);
     534             : #endif
     535       12934 :       MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
     536       12934 :       MOZ_ASSERT(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null,
     537             :                  "null value while computing size");
     538       12934 :       if (mPropertiesImportant.HasPropertyAt(iHigh, iLow))
     539        1031 :         (*aNumPropsImportant)++;
     540             :       else
     541       11903 :         (*aNumPropsNormal)++;
     542             :     }
     543             :   }
     544        3118 : }
     545             : 
     546             : void
     547        3118 : nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
     548             :                                  nsCSSCompressedDataBlock **aImportantBlock,
     549             :                                  const nsTArray<uint32_t>& aOrder)
     550             : {
     551        6236 :   nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important;
     552        3118 :   uint32_t i_normal = 0, i_important = 0;
     553             : 
     554             :   uint32_t numPropsNormal, numPropsImportant;
     555        3118 :   ComputeNumProps(&numPropsNormal, &numPropsImportant);
     556             : 
     557             :   result_normal =
     558        3118 :     new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal);
     559             : 
     560        3118 :   if (numPropsImportant != 0) {
     561             :     result_important =
     562         303 :       new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant);
     563             :   } else {
     564        2815 :     result_important = nullptr;
     565             :   }
     566             : 
     567             :   /*
     568             :    * Save needless copying and allocation by copying the memory
     569             :    * corresponding to the stored data in the expanded block, and then
     570             :    * clearing the data in the expanded block.
     571             :    */
     572       16126 :   for (size_t i = 0; i < aOrder.Length(); i++) {
     573       13008 :     nsCSSPropertyID iProp = static_cast<nsCSSPropertyID>(aOrder[i]);
     574       13008 :     if (iProp >= eCSSProperty_COUNT) {
     575             :       // a custom property
     576          74 :       continue;
     577             :     }
     578       12934 :     MOZ_ASSERT(mPropertiesSet.HasProperty(iProp),
     579             :                "aOrder identifies a property not in the expanded "
     580             :                "data block");
     581       12934 :     MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range");
     582       12934 :     bool important = mPropertiesImportant.HasProperty(iProp);
     583             :     nsCSSCompressedDataBlock *result =
     584       12934 :       important ? result_important : result_normal;
     585       12934 :     uint32_t* ip = important ? &i_important : &i_normal;
     586       12934 :     nsCSSValue* val = PropertyAt(iProp);
     587       12934 :     MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null,
     588             :                "Null value while compressing");
     589       12934 :     result->SetPropertyAtIndex(*ip, iProp);
     590       12934 :     result->RawCopyValueToIndex(*ip, val);
     591       12934 :     new (val) nsCSSValue();
     592       12934 :     (*ip)++;
     593       12934 :     result->mStyleBits |=
     594       12934 :       nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
     595             :   }
     596             : 
     597        3118 :   MOZ_ASSERT(numPropsNormal == i_normal, "bad numProps");
     598             : 
     599        3118 :   if (result_important) {
     600         303 :     MOZ_ASSERT(numPropsImportant == i_important, "bad numProps");
     601             :   }
     602             : 
     603             : #ifdef DEBUG
     604             :   {
     605             :     // assert that we didn't have any other properties on this expanded data
     606             :     // block that we didn't find in aOrder
     607        3118 :     uint32_t numPropsInSet = 0;
     608       21826 :     for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; iHigh++) {
     609       18708 :       if (!mPropertiesSet.HasPropertyInChunk(iHigh)) {
     610       14045 :         continue;
     611             :       }
     612      303095 :       for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; iLow++) {
     613      298432 :         if (mPropertiesSet.HasPropertyAt(iHigh, iLow)) {
     614       12934 :           numPropsInSet++;
     615             :         }
     616             :       }
     617             :     }
     618        3118 :     MOZ_ASSERT(numPropsNormal + numPropsImportant == numPropsInSet,
     619             :                "aOrder missing properties from the expanded data block");
     620             :   }
     621             : #endif
     622             : 
     623        3118 :   ClearSets();
     624        3118 :   AssertInitialState();
     625        3118 :   *aNormalBlock = result_normal.forget();
     626        3118 :   *aImportantBlock = result_important.forget();
     627        3118 : }
     628             : 
     629             : void
     630       17626 : nsCSSExpandedDataBlock::AddLonghandProperty(nsCSSPropertyID aProperty,
     631             :                                             const nsCSSValue& aValue)
     632             : {
     633       17626 :   MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
     634             :              "property out of range");
     635       17626 :   nsCSSValue& storage = *static_cast<nsCSSValue*>(PropertyAt(aProperty));
     636       17626 :   storage = aValue;
     637       17626 :   SetPropertyBit(aProperty);
     638       17626 : }
     639             : 
     640             : void
     641           0 : nsCSSExpandedDataBlock::Clear()
     642             : {
     643           0 :   for (size_t iHigh = 0; iHigh < nsCSSPropertyIDSet::kChunkCount; ++iHigh) {
     644           0 :     if (!mPropertiesSet.HasPropertyInChunk(iHigh))
     645           0 :       continue;
     646           0 :     for (size_t iLow = 0; iLow < nsCSSPropertyIDSet::kBitsInChunk; ++iLow) {
     647           0 :       if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
     648           0 :         continue;
     649           0 :       nsCSSPropertyID iProp = nsCSSPropertyIDSet::CSSPropertyAt(iHigh, iLow);
     650           0 :       ClearLonghandProperty(iProp);
     651             :     }
     652             :   }
     653             : 
     654           0 :   AssertInitialState();
     655           0 : }
     656             : 
     657             : void
     658         883 : nsCSSExpandedDataBlock::ClearProperty(nsCSSPropertyID aPropID)
     659             : {
     660         883 :   if (nsCSSProps::IsShorthand(aPropID)) {
     661       22991 :     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
     662             :         p, aPropID, CSSEnabledState::eIgnoreEnabledState) {
     663        4222 :       ClearLonghandProperty(*p);
     664             :     }
     665             :   } else {
     666         177 :     ClearLonghandProperty(aPropID);
     667             :   }
     668         883 : }
     669             : 
     670             : void
     671        4400 : nsCSSExpandedDataBlock::ClearLonghandProperty(nsCSSPropertyID aPropID)
     672             : {
     673        4400 :   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID), "out of range");
     674             : 
     675        4400 :   ClearPropertyBit(aPropID);
     676        4400 :   ClearImportantBit(aPropID);
     677        4400 :   PropertyAt(aPropID)->Reset();
     678        4400 : }
     679             : 
     680             : bool
     681        6571 : nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
     682             :                                           nsCSSPropertyID aPropID,
     683             :                                           CSSEnabledState aEnabledState,
     684             :                                           bool aIsImportant,
     685             :                                           bool aOverrideImportant,
     686             :                                           bool aMustCallValueAppended,
     687             :                                           css::Declaration* aDeclaration,
     688             :                                           nsIDocument* aSheetDocument)
     689             : {
     690        6571 :   if (!nsCSSProps::IsShorthand(aPropID)) {
     691        5446 :     return DoTransferFromBlock(aFromBlock, aPropID,
     692             :                                aIsImportant, aOverrideImportant,
     693             :                                aMustCallValueAppended, aDeclaration,
     694        5446 :                                aSheetDocument);
     695             :   }
     696             : 
     697             :   // We can pass CSSEnabledState::eIgnore (here, and in ClearProperty
     698             :   // above) rather than a value corresponding to whether we're parsing
     699             :   // a UA style sheet or certified app because we assert in nsCSSProps::
     700             :   // AddRefTable that shorthand properties available in these contexts
     701             :   // also have all of their subproperties available in these contexts.
     702        1125 :   bool changed = false;
     703        8671 :   CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID, aEnabledState) {
     704        7546 :     changed |= DoTransferFromBlock(aFromBlock, *p,
     705             :                                    aIsImportant, aOverrideImportant,
     706             :                                    aMustCallValueAppended, aDeclaration,
     707             :                                    aSheetDocument);
     708             :   }
     709        1125 :   return changed;
     710             : }
     711             : 
     712             : bool
     713       12992 : nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
     714             :                                             nsCSSPropertyID aPropID,
     715             :                                             bool aIsImportant,
     716             :                                             bool aOverrideImportant,
     717             :                                             bool aMustCallValueAppended,
     718             :                                             css::Declaration* aDeclaration,
     719             :                                             nsIDocument* aSheetDocument)
     720             : {
     721       12992 :   bool changed = false;
     722       12992 :   MOZ_ASSERT(aFromBlock.HasPropertyBit(aPropID), "oops");
     723       12992 :   if (aIsImportant) {
     724        1031 :     if (!HasImportantBit(aPropID))
     725        1031 :       changed = true;
     726        1031 :     SetImportantBit(aPropID);
     727             :   } else {
     728       11961 :     if (HasImportantBit(aPropID)) {
     729             :       // When parsing a declaration block, an !important declaration
     730             :       // is not overwritten by an ordinary declaration of the same
     731             :       // property later in the block.  However, CSSOM manipulations
     732             :       // come through here too, and in that case we do want to
     733             :       // overwrite the property.
     734           0 :       if (!aOverrideImportant) {
     735           0 :         aFromBlock.ClearLonghandProperty(aPropID);
     736           0 :         return false;
     737             :       }
     738           0 :       changed = true;
     739           0 :       ClearImportantBit(aPropID);
     740             :     }
     741             :   }
     742             : 
     743       12992 :   if (aMustCallValueAppended || !HasPropertyBit(aPropID)) {
     744       12992 :     aDeclaration->ValueAppended(aPropID);
     745             :   }
     746             : 
     747       12992 :   if (aSheetDocument) {
     748        6202 :     UseCounter useCounter = nsCSSProps::UseCounterFor(aPropID);
     749        6202 :     if (useCounter != eUseCounter_UNKNOWN) {
     750          71 :       aSheetDocument->SetDocumentAndPageUseCounter(useCounter);
     751             :     }
     752             :   }
     753             : 
     754       12992 :   SetPropertyBit(aPropID);
     755       12992 :   aFromBlock.ClearPropertyBit(aPropID);
     756             : 
     757             :   /*
     758             :    * Save needless copying and allocation by calling the destructor in
     759             :    * the destination, copying memory directly, and then using placement
     760             :    * new.
     761             :    */
     762       12992 :   changed |= MoveValue(aFromBlock.PropertyAt(aPropID), PropertyAt(aPropID));
     763       12992 :   return changed;
     764             : }
     765             : 
     766             : void
     767         883 : nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSPropertyID aPropID,
     768             :                                         nsRuleData* aRuleData) const
     769             : {
     770         883 :   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID));
     771             : 
     772         883 :   const nsCSSValue* src = PropertyAt(aPropID);
     773         883 :   MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null);
     774             : 
     775         883 :   nsCSSPropertyID physicalProp = aPropID;
     776         883 :   if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_LOGICAL)) {
     777          49 :     EnsurePhysicalProperty(physicalProp, aRuleData);
     778             :   }
     779             : 
     780         883 :   nsCSSValue* dest = aRuleData->ValueFor(physicalProp);
     781         883 :   MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream &&
     782             :              dest->GetTokenStreamValue()->mPropertyID == aPropID);
     783             : 
     784        1766 :   CSSVariableImageTable::ReplaceAll(aRuleData->mStyleContext, aPropID, [=] {
     785         883 :     MapSinglePropertyInto(physicalProp, src, dest, aRuleData);
     786        2649 :   });
     787         883 : }
     788             : 
     789             : #ifdef DEBUG
     790             : void
     791       21135 : nsCSSExpandedDataBlock::DoAssertInitialState()
     792             : {
     793       21135 :   mPropertiesSet.AssertIsEmpty("not initial state");
     794       21135 :   mPropertiesImportant.AssertIsEmpty("not initial state");
     795             : 
     796     6826605 :   for (uint32_t i = 0; i < eCSSProperty_COUNT_no_shorthands; ++i) {
     797     6805470 :     nsCSSPropertyID prop = nsCSSPropertyID(i);
     798     6805470 :     MOZ_ASSERT(PropertyAt(prop)->GetUnit() == eCSSUnit_Null,
     799             :                "not initial state");
     800             :   }
     801       21135 : }
     802             : #endif

Generated by: LCOV version 1.13