1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsCSSDataBlock.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,606 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 + * compact representation of the property-value pairs within a CSS 1.11 + * declaration, and the code for expanding and compacting it 1.12 + */ 1.13 + 1.14 +#include "nsCSSDataBlock.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/css/Declaration.h" 1.17 +#include "mozilla/css/ImageLoader.h" 1.18 +#include "nsRuleData.h" 1.19 +#include "nsStyleSet.h" 1.20 +#include "nsStyleContext.h" 1.21 +#include "nsIDocument.h" 1.22 + 1.23 +using namespace mozilla; 1.24 + 1.25 +/** 1.26 + * Does a fast move of aSource to aDest. The previous value in 1.27 + * aDest is cleanly destroyed, and aSource is cleared. Returns 1.28 + * true if, before the copy, the value at aSource compared unequal 1.29 + * to the value at aDest; false otherwise. 1.30 + */ 1.31 +static bool 1.32 +MoveValue(nsCSSValue* aSource, nsCSSValue* aDest) 1.33 +{ 1.34 + bool changed = (*aSource != *aDest); 1.35 + aDest->~nsCSSValue(); 1.36 + memcpy(aDest, aSource, sizeof(nsCSSValue)); 1.37 + new (aSource) nsCSSValue(); 1.38 + return changed; 1.39 +} 1.40 + 1.41 +static bool 1.42 +ShouldIgnoreColors(nsRuleData *aRuleData) 1.43 +{ 1.44 + return aRuleData->mLevel != nsStyleSet::eAgentSheet && 1.45 + aRuleData->mLevel != nsStyleSet::eUserSheet && 1.46 + !aRuleData->mPresContext->UseDocumentColors(); 1.47 +} 1.48 + 1.49 +/** 1.50 + * Tries to call |nsCSSValue::StartImageLoad()| on an image source. 1.51 + * Image sources are specified by |url()| or |-moz-image-rect()| function. 1.52 + */ 1.53 +static void 1.54 +TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument, 1.55 + nsCSSValueTokenStream* aTokenStream) 1.56 +{ 1.57 + MOZ_ASSERT(aDocument); 1.58 + 1.59 + if (aValue.GetUnit() == eCSSUnit_URL) { 1.60 + aValue.StartImageLoad(aDocument); 1.61 + if (aTokenStream) { 1.62 + aTokenStream->mImageValues.PutEntry(aValue.GetImageStructValue()); 1.63 + } 1.64 + } 1.65 + else if (aValue.GetUnit() == eCSSUnit_Image) { 1.66 + // If we already have a request, see if this document needs to clone it. 1.67 + imgIRequest* request = aValue.GetImageValue(nullptr); 1.68 + 1.69 + if (request) { 1.70 + mozilla::css::ImageValue* imageValue = aValue.GetImageStructValue(); 1.71 + aDocument->StyleImageLoader()->MaybeRegisterCSSImage(imageValue); 1.72 + if (aTokenStream) { 1.73 + aTokenStream->mImageValues.PutEntry(imageValue); 1.74 + } 1.75 + } 1.76 + } 1.77 + else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) { 1.78 + nsCSSValue::Array* arguments = aValue.GetArrayValue(); 1.79 + NS_ABORT_IF_FALSE(arguments->Count() == 6, "unexpected num of arguments"); 1.80 + 1.81 + const nsCSSValue& image = arguments->Item(1); 1.82 + TryToStartImageLoadOnValue(image, aDocument, aTokenStream); 1.83 + } 1.84 +} 1.85 + 1.86 +static void 1.87 +TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument, 1.88 + nsCSSProperty aProperty, 1.89 + nsCSSValueTokenStream* aTokenStream) 1.90 +{ 1.91 + if (aValue.GetUnit() == eCSSUnit_List) { 1.92 + for (const nsCSSValueList* l = aValue.GetListValue(); l; l = l->mNext) { 1.93 + TryToStartImageLoad(l->mValue, aDocument, aProperty, aTokenStream); 1.94 + } 1.95 + } else if (nsCSSProps::PropHasFlags(aProperty, 1.96 + CSS_PROPERTY_IMAGE_IS_IN_ARRAY_0)) { 1.97 + if (aValue.GetUnit() == eCSSUnit_Array) { 1.98 + TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument, 1.99 + aTokenStream); 1.100 + } 1.101 + } else { 1.102 + TryToStartImageLoadOnValue(aValue, aDocument, aTokenStream); 1.103 + } 1.104 +} 1.105 + 1.106 +static inline bool 1.107 +ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSProperty aProperty) 1.108 +{ 1.109 + // Don't initiate image loads for if-visited styles. This is 1.110 + // important because: 1.111 + // (1) it's a waste of CPU and bandwidth 1.112 + // (2) in some cases we'd start the image load on a style change 1.113 + // where we wouldn't have started the load initially, which makes 1.114 + // which links are visited detectable to Web pages (see bug 1.115 + // 557287) 1.116 + return !aRuleData->mStyleContext->IsStyleIfVisited() && 1.117 + nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_START_IMAGE_LOADS); 1.118 +} 1.119 + 1.120 +static void 1.121 +MapSinglePropertyInto(nsCSSProperty aProp, 1.122 + const nsCSSValue* aValue, 1.123 + nsCSSValue* aTarget, 1.124 + nsRuleData* aRuleData) 1.125 +{ 1.126 + NS_ABORT_IF_FALSE(aValue->GetUnit() != eCSSUnit_Null, "oops"); 1.127 + 1.128 + // Although aTarget is the nsCSSValue we are going to write into, 1.129 + // we also look at its value before writing into it. This is done 1.130 + // when aTarget is a token stream value, which is the case when we 1.131 + // have just re-parsed a property that had a variable reference (in 1.132 + // nsCSSParser::ParsePropertyWithVariableReferences). TryToStartImageLoad 1.133 + // then records any resulting ImageValue objects on the 1.134 + // nsCSSValueTokenStream object we found on aTarget. See the comment 1.135 + // above nsCSSValueTokenStream::mImageValues for why. 1.136 + NS_ABORT_IF_FALSE(aTarget->GetUnit() == eCSSUnit_TokenStream || 1.137 + aTarget->GetUnit() == eCSSUnit_Null, 1.138 + "aTarget must only be a token stream (when re-parsing " 1.139 + "properties with variable references) or null"); 1.140 + 1.141 + nsCSSValueTokenStream* tokenStream = 1.142 + aTarget->GetUnit() == eCSSUnit_TokenStream ? 1.143 + aTarget->GetTokenStreamValue() : 1.144 + nullptr; 1.145 + 1.146 + if (ShouldStartImageLoads(aRuleData, aProp)) { 1.147 + nsIDocument* doc = aRuleData->mPresContext->Document(); 1.148 + TryToStartImageLoad(*aValue, doc, aProp, tokenStream); 1.149 + } 1.150 + *aTarget = *aValue; 1.151 + if (nsCSSProps::PropHasFlags(aProp, 1.152 + CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) && 1.153 + ShouldIgnoreColors(aRuleData)) 1.154 + { 1.155 + if (aProp == eCSSProperty_background_color) { 1.156 + // Force non-'transparent' background 1.157 + // colors to the user's default. 1.158 + if (aTarget->IsNonTransparentColor()) { 1.159 + aTarget->SetColorValue(aRuleData->mPresContext-> 1.160 + DefaultBackgroundColor()); 1.161 + } 1.162 + } else { 1.163 + // Ignore 'color', 'border-*-color', etc. 1.164 + *aTarget = nsCSSValue(); 1.165 + } 1.166 + } 1.167 +} 1.168 + 1.169 +void 1.170 +nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const 1.171 +{ 1.172 + // If we have no data for these structs, then return immediately. 1.173 + // This optimization should make us return most of the time, so we 1.174 + // have to worry much less (although still some) about the speed of 1.175 + // the rest of the function. 1.176 + if (!(aRuleData->mSIDs & mStyleBits)) 1.177 + return; 1.178 + 1.179 + for (uint32_t i = 0; i < mNumProps; i++) { 1.180 + nsCSSProperty iProp = PropertyAtIndex(i); 1.181 + if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & 1.182 + aRuleData->mSIDs) { 1.183 + nsCSSValue* target = aRuleData->ValueFor(iProp); 1.184 + if (target->GetUnit() == eCSSUnit_Null) { 1.185 + const nsCSSValue *val = ValueAtIndex(i); 1.186 + MapSinglePropertyInto(iProp, val, target, aRuleData); 1.187 + } 1.188 + } 1.189 + } 1.190 +} 1.191 + 1.192 +const nsCSSValue* 1.193 +nsCSSCompressedDataBlock::ValueFor(nsCSSProperty aProperty) const 1.194 +{ 1.195 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), 1.196 + "Don't call for shorthands"); 1.197 + 1.198 + // If we have no data for this struct, then return immediately. 1.199 + // This optimization should make us return most of the time, so we 1.200 + // have to worry much less (although still some) about the speed of 1.201 + // the rest of the function. 1.202 + if (!(nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]) & 1.203 + mStyleBits)) 1.204 + return nullptr; 1.205 + 1.206 + for (uint32_t i = 0; i < mNumProps; i++) { 1.207 + if (PropertyAtIndex(i) == aProperty) { 1.208 + return ValueAtIndex(i); 1.209 + } 1.210 + } 1.211 + 1.212 + return nullptr; 1.213 +} 1.214 + 1.215 +bool 1.216 +nsCSSCompressedDataBlock::TryReplaceValue(nsCSSProperty aProperty, 1.217 + nsCSSExpandedDataBlock& aFromBlock, 1.218 + bool *aChanged) 1.219 +{ 1.220 + nsCSSValue* newValue = aFromBlock.PropertyAt(aProperty); 1.221 + NS_ABORT_IF_FALSE(newValue && newValue->GetUnit() != eCSSUnit_Null, 1.222 + "cannot replace with empty value"); 1.223 + 1.224 + const nsCSSValue* oldValue = ValueFor(aProperty); 1.225 + if (!oldValue) { 1.226 + *aChanged = false; 1.227 + return false; 1.228 + } 1.229 + 1.230 + *aChanged = MoveValue(newValue, const_cast<nsCSSValue*>(oldValue)); 1.231 + aFromBlock.ClearPropertyBit(aProperty); 1.232 + return true; 1.233 +} 1.234 + 1.235 +nsCSSCompressedDataBlock* 1.236 +nsCSSCompressedDataBlock::Clone() const 1.237 +{ 1.238 + nsAutoPtr<nsCSSCompressedDataBlock> 1.239 + result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps)); 1.240 + 1.241 + result->mStyleBits = mStyleBits; 1.242 + 1.243 + for (uint32_t i = 0; i < mNumProps; i++) { 1.244 + result->SetPropertyAtIndex(i, PropertyAtIndex(i)); 1.245 + result->CopyValueToIndex(i, ValueAtIndex(i)); 1.246 + } 1.247 + 1.248 + return result.forget(); 1.249 +} 1.250 + 1.251 +nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock() 1.252 +{ 1.253 + for (uint32_t i = 0; i < mNumProps; i++) { 1.254 +#ifdef DEBUG 1.255 + (void)PropertyAtIndex(i); // this checks the property is in range 1.256 +#endif 1.257 + const nsCSSValue* val = ValueAtIndex(i); 1.258 + NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); 1.259 + val->~nsCSSValue(); 1.260 + } 1.261 +} 1.262 + 1.263 +/* static */ nsCSSCompressedDataBlock* 1.264 +nsCSSCompressedDataBlock::CreateEmptyBlock() 1.265 +{ 1.266 + nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0); 1.267 + return result; 1.268 +} 1.269 + 1.270 +size_t 1.271 +nsCSSCompressedDataBlock::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.272 +{ 1.273 + size_t n = aMallocSizeOf(this); 1.274 + for (uint32_t i = 0; i < mNumProps; i++) { 1.275 + n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf); 1.276 + } 1.277 + return n; 1.278 +} 1.279 + 1.280 +bool 1.281 +nsCSSCompressedDataBlock::HasDefaultBorderImageSlice() const 1.282 +{ 1.283 + const nsCSSValueList *slice = 1.284 + ValueFor(eCSSProperty_border_image_slice)->GetListValue(); 1.285 + return !slice->mNext && 1.286 + slice->mValue.GetRectValue().AllSidesEqualTo( 1.287 + nsCSSValue(1.0f, eCSSUnit_Percent)); 1.288 +} 1.289 + 1.290 +bool 1.291 +nsCSSCompressedDataBlock::HasDefaultBorderImageWidth() const 1.292 +{ 1.293 + const nsCSSRect &width = 1.294 + ValueFor(eCSSProperty_border_image_width)->GetRectValue(); 1.295 + return width.AllSidesEqualTo(nsCSSValue(1.0f, eCSSUnit_Number)); 1.296 +} 1.297 + 1.298 +bool 1.299 +nsCSSCompressedDataBlock::HasDefaultBorderImageOutset() const 1.300 +{ 1.301 + const nsCSSRect &outset = 1.302 + ValueFor(eCSSProperty_border_image_outset)->GetRectValue(); 1.303 + return outset.AllSidesEqualTo(nsCSSValue(0.0f, eCSSUnit_Number)); 1.304 +} 1.305 + 1.306 +bool 1.307 +nsCSSCompressedDataBlock::HasDefaultBorderImageRepeat() const 1.308 +{ 1.309 + const nsCSSValuePair &repeat = 1.310 + ValueFor(eCSSProperty_border_image_repeat)->GetPairValue(); 1.311 + return repeat.BothValuesEqualTo( 1.312 + nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, eCSSUnit_Enumerated)); 1.313 +} 1.314 + 1.315 +/*****************************************************************************/ 1.316 + 1.317 +nsCSSExpandedDataBlock::nsCSSExpandedDataBlock() 1.318 +{ 1.319 + AssertInitialState(); 1.320 +} 1.321 + 1.322 +nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock() 1.323 +{ 1.324 + AssertInitialState(); 1.325 +} 1.326 + 1.327 +void 1.328 +nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock, 1.329 + bool aImportant) 1.330 +{ 1.331 + /* 1.332 + * Save needless copying and allocation by copying the memory 1.333 + * corresponding to the stored data in the compressed block. 1.334 + */ 1.335 + for (uint32_t i = 0; i < aBlock->mNumProps; i++) { 1.336 + nsCSSProperty iProp = aBlock->PropertyAtIndex(i); 1.337 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); 1.338 + NS_ABORT_IF_FALSE(!HasPropertyBit(iProp), 1.339 + "compressed block has property multiple times"); 1.340 + SetPropertyBit(iProp); 1.341 + if (aImportant) 1.342 + SetImportantBit(iProp); 1.343 + 1.344 + const nsCSSValue* val = aBlock->ValueAtIndex(i); 1.345 + nsCSSValue* dest = PropertyAt(iProp); 1.346 + NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops"); 1.347 + NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null, 1.348 + "expanding into non-empty block"); 1.349 +#ifdef NS_BUILD_REFCNT_LOGGING 1.350 + dest->~nsCSSValue(); 1.351 +#endif 1.352 + memcpy(dest, val, sizeof(nsCSSValue)); 1.353 + } 1.354 + 1.355 + // Set the number of properties to zero so that we don't destroy the 1.356 + // remnants of what we just copied. 1.357 + aBlock->SetNumPropsToZero(); 1.358 + delete aBlock; 1.359 +} 1.360 + 1.361 +void 1.362 +nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock, 1.363 + nsCSSCompressedDataBlock *aImportantBlock) 1.364 +{ 1.365 + NS_ABORT_IF_FALSE(aNormalBlock, "unexpected null block"); 1.366 + AssertInitialState(); 1.367 + 1.368 + DoExpand(aNormalBlock, false); 1.369 + if (aImportantBlock) { 1.370 + DoExpand(aImportantBlock, true); 1.371 + } 1.372 +} 1.373 + 1.374 +void 1.375 +nsCSSExpandedDataBlock::ComputeNumProps(uint32_t* aNumPropsNormal, 1.376 + uint32_t* aNumPropsImportant) 1.377 +{ 1.378 + *aNumPropsNormal = *aNumPropsImportant = 0; 1.379 + for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { 1.380 + if (!mPropertiesSet.HasPropertyInChunk(iHigh)) 1.381 + continue; 1.382 + for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) { 1.383 + if (!mPropertiesSet.HasPropertyAt(iHigh, iLow)) 1.384 + continue; 1.385 +#ifdef DEBUG 1.386 + nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow); 1.387 +#endif 1.388 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); 1.389 + NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null, 1.390 + "null value while computing size"); 1.391 + if (mPropertiesImportant.HasPropertyAt(iHigh, iLow)) 1.392 + (*aNumPropsImportant)++; 1.393 + else 1.394 + (*aNumPropsNormal)++; 1.395 + } 1.396 + } 1.397 +} 1.398 + 1.399 +void 1.400 +nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, 1.401 + nsCSSCompressedDataBlock **aImportantBlock) 1.402 +{ 1.403 + nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; 1.404 + uint32_t i_normal = 0, i_important = 0; 1.405 + 1.406 + uint32_t numPropsNormal, numPropsImportant; 1.407 + ComputeNumProps(&numPropsNormal, &numPropsImportant); 1.408 + 1.409 + result_normal = 1.410 + new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal); 1.411 + 1.412 + if (numPropsImportant != 0) { 1.413 + result_important = 1.414 + new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant); 1.415 + } else { 1.416 + result_important = nullptr; 1.417 + } 1.418 + 1.419 + /* 1.420 + * Save needless copying and allocation by copying the memory 1.421 + * corresponding to the stored data in the expanded block, and then 1.422 + * clearing the data in the expanded block. 1.423 + */ 1.424 + for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { 1.425 + if (!mPropertiesSet.HasPropertyInChunk(iHigh)) 1.426 + continue; 1.427 + for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) { 1.428 + if (!mPropertiesSet.HasPropertyAt(iHigh, iLow)) 1.429 + continue; 1.430 + nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow); 1.431 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range"); 1.432 + bool important = 1.433 + mPropertiesImportant.HasPropertyAt(iHigh, iLow); 1.434 + nsCSSCompressedDataBlock *result = 1.435 + important ? result_important : result_normal; 1.436 + uint32_t* ip = important ? &i_important : &i_normal; 1.437 + nsCSSValue* val = PropertyAt(iProp); 1.438 + NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, 1.439 + "Null value while compressing"); 1.440 + result->SetPropertyAtIndex(*ip, iProp); 1.441 + result->RawCopyValueToIndex(*ip, val); 1.442 + new (val) nsCSSValue(); 1.443 + (*ip)++; 1.444 + result->mStyleBits |= 1.445 + nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); 1.446 + } 1.447 + } 1.448 + 1.449 + NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps"); 1.450 + 1.451 + if (result_important) { 1.452 + NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps"); 1.453 + } 1.454 + 1.455 + ClearSets(); 1.456 + AssertInitialState(); 1.457 + *aNormalBlock = result_normal.forget(); 1.458 + *aImportantBlock = result_important.forget(); 1.459 +} 1.460 + 1.461 +void 1.462 +nsCSSExpandedDataBlock::AddLonghandProperty(nsCSSProperty aProperty, 1.463 + const nsCSSValue& aValue) 1.464 +{ 1.465 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), 1.466 + "property out of range"); 1.467 + nsCSSValue& storage = *static_cast<nsCSSValue*>(PropertyAt(aProperty)); 1.468 + storage = aValue; 1.469 + SetPropertyBit(aProperty); 1.470 +} 1.471 + 1.472 +void 1.473 +nsCSSExpandedDataBlock::Clear() 1.474 +{ 1.475 + for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) { 1.476 + if (!mPropertiesSet.HasPropertyInChunk(iHigh)) 1.477 + continue; 1.478 + for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) { 1.479 + if (!mPropertiesSet.HasPropertyAt(iHigh, iLow)) 1.480 + continue; 1.481 + nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow); 1.482 + ClearLonghandProperty(iProp); 1.483 + } 1.484 + } 1.485 + 1.486 + AssertInitialState(); 1.487 +} 1.488 + 1.489 +void 1.490 +nsCSSExpandedDataBlock::ClearProperty(nsCSSProperty aPropID) 1.491 +{ 1.492 + if (nsCSSProps::IsShorthand(aPropID)) { 1.493 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) { 1.494 + ClearLonghandProperty(*p); 1.495 + } 1.496 + } else { 1.497 + ClearLonghandProperty(aPropID); 1.498 + } 1.499 +} 1.500 + 1.501 +void 1.502 +nsCSSExpandedDataBlock::ClearLonghandProperty(nsCSSProperty aPropID) 1.503 +{ 1.504 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID), "out of range"); 1.505 + 1.506 + ClearPropertyBit(aPropID); 1.507 + ClearImportantBit(aPropID); 1.508 + PropertyAt(aPropID)->Reset(); 1.509 +} 1.510 + 1.511 +bool 1.512 +nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock, 1.513 + nsCSSProperty aPropID, 1.514 + bool aIsImportant, 1.515 + bool aOverrideImportant, 1.516 + bool aMustCallValueAppended, 1.517 + css::Declaration* aDeclaration) 1.518 +{ 1.519 + if (!nsCSSProps::IsShorthand(aPropID)) { 1.520 + return DoTransferFromBlock(aFromBlock, aPropID, 1.521 + aIsImportant, aOverrideImportant, 1.522 + aMustCallValueAppended, aDeclaration); 1.523 + } 1.524 + 1.525 + bool changed = false; 1.526 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) { 1.527 + changed |= DoTransferFromBlock(aFromBlock, *p, 1.528 + aIsImportant, aOverrideImportant, 1.529 + aMustCallValueAppended, aDeclaration); 1.530 + } 1.531 + return changed; 1.532 +} 1.533 + 1.534 +bool 1.535 +nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock, 1.536 + nsCSSProperty aPropID, 1.537 + bool aIsImportant, 1.538 + bool aOverrideImportant, 1.539 + bool aMustCallValueAppended, 1.540 + css::Declaration* aDeclaration) 1.541 +{ 1.542 + bool changed = false; 1.543 + NS_ABORT_IF_FALSE(aFromBlock.HasPropertyBit(aPropID), "oops"); 1.544 + if (aIsImportant) { 1.545 + if (!HasImportantBit(aPropID)) 1.546 + changed = true; 1.547 + SetImportantBit(aPropID); 1.548 + } else { 1.549 + if (HasImportantBit(aPropID)) { 1.550 + // When parsing a declaration block, an !important declaration 1.551 + // is not overwritten by an ordinary declaration of the same 1.552 + // property later in the block. However, CSSOM manipulations 1.553 + // come through here too, and in that case we do want to 1.554 + // overwrite the property. 1.555 + if (!aOverrideImportant) { 1.556 + aFromBlock.ClearLonghandProperty(aPropID); 1.557 + return false; 1.558 + } 1.559 + changed = true; 1.560 + ClearImportantBit(aPropID); 1.561 + } 1.562 + } 1.563 + 1.564 + if (aMustCallValueAppended || !HasPropertyBit(aPropID)) { 1.565 + aDeclaration->ValueAppended(aPropID); 1.566 + } 1.567 + 1.568 + SetPropertyBit(aPropID); 1.569 + aFromBlock.ClearPropertyBit(aPropID); 1.570 + 1.571 + /* 1.572 + * Save needless copying and allocation by calling the destructor in 1.573 + * the destination, copying memory directly, and then using placement 1.574 + * new. 1.575 + */ 1.576 + changed |= MoveValue(aFromBlock.PropertyAt(aPropID), PropertyAt(aPropID)); 1.577 + return changed; 1.578 +} 1.579 + 1.580 +void 1.581 +nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSProperty aPropID, 1.582 + nsRuleData* aRuleData) const 1.583 +{ 1.584 + MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID)); 1.585 + 1.586 + const nsCSSValue* src = PropertyAt(aPropID); 1.587 + MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null); 1.588 + 1.589 + nsCSSValue* dest = aRuleData->ValueFor(aPropID); 1.590 + MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream && 1.591 + dest->GetTokenStreamValue()->mPropertyID == aPropID); 1.592 + 1.593 + MapSinglePropertyInto(aPropID, src, dest, aRuleData); 1.594 +} 1.595 + 1.596 +#ifdef DEBUG 1.597 +void 1.598 +nsCSSExpandedDataBlock::DoAssertInitialState() 1.599 +{ 1.600 + mPropertiesSet.AssertIsEmpty("not initial state"); 1.601 + mPropertiesImportant.AssertIsEmpty("not initial state"); 1.602 + 1.603 + for (uint32_t i = 0; i < eCSSProperty_COUNT_no_shorthands; ++i) { 1.604 + nsCSSProperty prop = nsCSSProperty(i); 1.605 + NS_ABORT_IF_FALSE(PropertyAt(prop)->GetUnit() == eCSSUnit_Null, 1.606 + "not initial state"); 1.607 + } 1.608 +} 1.609 +#endif