MiscContainer* nsAttrValue::ClearMiscContainer() { MiscContainer* cont = nullptr; if (BaseType() == eOtherBase) { cont = GetMiscContainer(); if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) { // This MiscContainer is shared, we need a new one. NS_RELEASE(cont); cont = new MiscContainer; SetPtrValueAndType(cont, eOtherBase); } else { switch (cont->mType) { case eCSSStyleRule: { MOZ_ASSERT(cont->mValue.mRefCount == 1); cont->Release(); cont->Evict(); NS_RELEASE(cont->mValue.mCSSStyleRule); break; } case eURL: { NS_RELEASE(cont->mValue.mURL); break; } case eImage: { NS_RELEASE(cont->mValue.mImage); break; } case eAtomArray: { delete cont->mValue.mAtomArray; break; } case eIntMarginValue: { delete cont->mValue.mIntMargin; break; } default: { break; } } } ResetMiscAtomOrString(); } else { ResetIfSet(); } return cont; }
size_t nsAttrValue::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = 0; switch (BaseType()) { case eStringBase: { nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0; break; } case eOtherBase: { MiscContainer* container = GetMiscContainer(); if (!container) { break; } if (container->IsRefCounted() && container->mValue.mRefCount > 1) { // We don't report this MiscContainer at all in order to avoid // twice-reporting it. // TODO DMD, bug 1027551 - figure out how to report this ref-counted // object just once. break; } n += aMallocSizeOf(container); void* otherPtr = MISC_STR_PTR(container); // We only count the size of the object pointed by otherPtr if it's a // string. When it's an atom, it's counted separatly. if (otherPtr && static_cast<ValueBaseType>(container->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) { nsStringBuffer* str = static_cast<nsStringBuffer*>(otherPtr); n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0; } if (Type() == eCSSDeclaration && container->mValue.mCSSDeclaration) { // TODO: mCSSDeclaration might be owned by another object which // would make us count them twice, bug 677493. // Bug 1281964: For ServoDeclarationBlock if we do measure we'll // need a way to call the Servo heap_size_of function. //n += container->mCSSDeclaration->SizeOfIncludingThis(aMallocSizeOf); } else if (Type() == eAtomArray && container->mValue.mAtomArray) { // Don't measure each nsIAtom, they are measured separatly. n += container->mValue.mAtomArray->ShallowSizeOfIncludingThis(aMallocSizeOf); } break; } case eAtomBase: // Atoms are counted separately. case eIntegerBase: // The value is in mBits, nothing to do. break; } return n; }
bool nsAttrValue::ParseStyleAttribute(const nsAString& aString, nsStyledElement* aElement) { nsIDocument* ownerDoc = aElement->OwnerDoc(); nsHTMLCSSStyleSheet* sheet = ownerDoc->GetInlineStyleSheet(); nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURI(); nsIURI* docURI = ownerDoc->GetDocumentURI(); NS_ASSERTION(aElement->NodePrincipal() == ownerDoc->NodePrincipal(), "This is unexpected"); // If the (immutable) document URI does not match the element's base URI // (the common case is that they do match) do not cache the rule. This is // because the results of the CSS parser are dependent on these URIs, and we // do not want to have to account for the URIs in the hash lookup. bool cachingAllowed = sheet && baseURI == docURI; if (cachingAllowed) { MiscContainer* cont = sheet->LookupStyleAttr(aString); if (cont) { // Set our MiscContainer to the cached one. NS_ADDREF(cont); SetPtrValueAndType(cont, eOtherBase); return true; } } RefPtr<DeclarationBlock> decl; if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) { decl = ServoDeclarationBlock::FromCssText(aString); } else { css::Loader* cssLoader = ownerDoc->CSSLoader(); nsCSSParser cssParser(cssLoader); decl = cssParser.ParseStyleAttribute(aString, docURI, baseURI, aElement->NodePrincipal()); } if (!decl) { return false; } decl->SetHTMLCSSStyleSheet(sheet); SetTo(decl.forget(), &aString); if (cachingAllowed) { MiscContainer* cont = GetMiscContainer(); cont->Cache(); } return true; }
void nsAttrValue::Reset() { switch(BaseType()) { case eStringBase: { nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); if (str) { str->Release(); } break; } case eOtherBase: { MiscContainer* cont = GetMiscContainer(); if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) { NS_RELEASE(cont); break; } delete ClearMiscContainer(); break; } case eAtomBase: { nsIAtom* atom = GetAtomValue(); NS_RELEASE(atom); break; } case eIntegerBase: { break; } } mBits = 0; }
void nsAttrValue::ToString(nsAString& aResult) const { MiscContainer* cont = nullptr; if (BaseType() == eOtherBase) { cont = GetMiscContainer(); if (cont->GetString(aResult)) { return; } } switch(Type()) { case eString: { nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); if (str) { str->ToString(str->StorageSize()/sizeof(char16_t) - 1, aResult); } else { aResult.Truncate(); } break; } case eAtom: { nsIAtom *atom = static_cast<nsIAtom*>(GetPtr()); atom->ToString(aResult); break; } case eInteger: { nsAutoString intStr; intStr.AppendInt(GetIntegerValue()); aResult = intStr; break; } #ifdef DEBUG case eColor: { NS_NOTREACHED("color attribute without string data"); aResult.Truncate(); break; } #endif case eEnum: { GetEnumString(aResult, false); break; } case ePercent: { nsAutoString intStr; intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal()); aResult = intStr + NS_LITERAL_STRING("%"); break; } case eCSSStyleRule: { aResult.Truncate(); MiscContainer *container = GetMiscContainer(); css::Declaration *decl = container->mValue.mCSSStyleRule->GetDeclaration(); if (decl) { decl->ToString(aResult); } const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult); break; } case eDoubleValue: { aResult.Truncate(); aResult.AppendFloat(GetDoubleValue()); break; } case eSVGAngle: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle, aResult); break; } case eSVGIntegerPair: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair, aResult); break; } case eSVGLength: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength, aResult); break; } case eSVGLengthList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLengthList, aResult); break; } case eSVGNumberList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberList, aResult); break; } case eSVGNumberPair: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberPair, aResult); break; } case eSVGPathData: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPathData, aResult); break; } case eSVGPointList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPointList, aResult); break; } case eSVGPreserveAspectRatio: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPreserveAspectRatio, aResult); break; } case eSVGStringList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGStringList, aResult); break; } case eSVGTransformList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGTransformList, aResult); break; } case eSVGViewBox: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGViewBox, aResult); break; } default: { aResult.Truncate(); break; } } }
void nsAttrValue::SetTo(const nsAttrValue& aOther) { if (this == &aOther) { return; } switch (aOther.BaseType()) { case eStringBase: { ResetIfSet(); nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr()); if (str) { str->AddRef(); SetPtrValueAndType(str, eStringBase); } return; } case eOtherBase: { break; } case eAtomBase: { ResetIfSet(); nsIAtom* atom = aOther.GetAtomValue(); NS_ADDREF(atom); SetPtrValueAndType(atom, eAtomBase); return; } case eIntegerBase: { ResetIfSet(); mBits = aOther.mBits; return; } } MiscContainer* otherCont = aOther.GetMiscContainer(); if (otherCont->IsRefCounted()) { delete ClearMiscContainer(); NS_ADDREF(otherCont); SetPtrValueAndType(otherCont, eOtherBase); return; } MiscContainer* cont = EnsureEmptyMiscContainer(); switch (otherCont->mType) { case eInteger: { cont->mValue.mInteger = otherCont->mValue.mInteger; break; } case eEnum: { cont->mValue.mEnumValue = otherCont->mValue.mEnumValue; break; } case ePercent: { cont->mValue.mPercent = otherCont->mValue.mPercent; break; } case eColor: { cont->mValue.mColor = otherCont->mValue.mColor; break; } case eCSSStyleRule: { MOZ_CRASH("These should be refcounted!"); } case eURL: { NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL); break; } case eImage: { NS_ADDREF(cont->mValue.mImage = otherCont->mValue.mImage); break; } case eAtomArray: { if (!EnsureEmptyAtomArray() || !GetAtomArrayValue()->AppendElements(*otherCont->mValue.mAtomArray)) { Reset(); return; } break; } case eDoubleValue: { cont->mDoubleValue = otherCont->mDoubleValue; break; } case eIntMarginValue: { if (otherCont->mValue.mIntMargin) cont->mValue.mIntMargin = new nsIntMargin(*otherCont->mValue.mIntMargin); break; } default: { if (IsSVGType(otherCont->mType)) { // All SVG types are just pointers to classes and will therefore have // the same size so it doesn't really matter which one we assign cont->mValue.mSVGAngle = otherCont->mValue.mSVGAngle; } else { NS_NOTREACHED("unknown type stored in MiscContainer"); } break; } } void* otherPtr = MISC_STR_PTR(otherCont); if (otherPtr) { if (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) { static_cast<nsStringBuffer*>(otherPtr)->AddRef(); } else { static_cast<nsIAtom*>(otherPtr)->AddRef(); } cont->mStringBits = otherCont->mStringBits; } // Note, set mType after switch-case, otherwise EnsureEmptyAtomArray doesn't // work correctly. cont->mType = otherCont->mType; }
void nsAttrValue::ToString(nsAString& aResult) const { MiscContainer* cont = nullptr; if (BaseType() == eOtherBase) { cont = GetMiscContainer(); if (cont->GetString(aResult)) { return; } } switch(Type()) { case eString: { nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); if (str) { str->ToString(str->StorageSize()/sizeof(char16_t) - 1, aResult); } else { aResult.Truncate(); } break; } case eAtom: { nsIAtom *atom = static_cast<nsIAtom*>(GetPtr()); atom->ToString(aResult); break; } case eInteger: { nsAutoString intStr; intStr.AppendInt(GetIntegerValue()); aResult = intStr; break; } #ifdef DEBUG case eColor: { NS_NOTREACHED("color attribute without string data"); aResult.Truncate(); break; } #endif case eEnum: { GetEnumString(aResult, false); break; } case ePercent: { nsAutoString intStr; intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal()); aResult = intStr + NS_LITERAL_STRING("%"); break; } case eCSSDeclaration: { aResult.Truncate(); MiscContainer *container = GetMiscContainer(); if (DeclarationBlock* decl = container->mValue.mCSSDeclaration) { decl->ToString(aResult); } // We can reach this during parallel style traversal. If that happens, // don't cache the string. The TLS overhead should't hurt us here, since // main thread consumers will subsequently use the cache, and // off-main-thread consumers only reach this in the rare case of selector // matching on the "style" attribute. if (!ServoStyleSet::IsInServoTraversal()) { const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult); } break; } case eDoubleValue: { aResult.Truncate(); aResult.AppendFloat(GetDoubleValue()); break; } case eSVGAngle: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle, aResult); break; } case eSVGIntegerPair: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair, aResult); break; } case eSVGLength: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength, aResult); break; } case eSVGLengthList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLengthList, aResult); break; } case eSVGNumberList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberList, aResult); break; } case eSVGNumberPair: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberPair, aResult); break; } case eSVGPathData: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPathData, aResult); break; } case eSVGPointList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPointList, aResult); break; } case eSVGPreserveAspectRatio: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPreserveAspectRatio, aResult); break; } case eSVGStringList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGStringList, aResult); break; } case eSVGTransformList: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGTransformList, aResult); break; } case eSVGViewBox: { SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGViewBox, aResult); break; } default: { aResult.Truncate(); break; } } }