michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * A unique per-element set of attributes that is used as an michael@0: * nsIStyleRule; used to implement presentational attributes. michael@0: */ michael@0: michael@0: #include "nsMappedAttributes.h" michael@0: #include "nsHTMLStyleSheet.h" michael@0: #include "nsRuleWalker.h" michael@0: #include "mozilla/HashFunctions.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet, michael@0: nsMapRuleToAttributesFunc aMapRuleFunc) michael@0: : mAttrCount(0), michael@0: mSheet(aSheet), michael@0: mRuleMapper(aMapRuleFunc) michael@0: { michael@0: } michael@0: michael@0: nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy) michael@0: : mAttrCount(aCopy.mAttrCount), michael@0: mSheet(aCopy.mSheet), michael@0: mRuleMapper(aCopy.mRuleMapper) michael@0: { michael@0: NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes"); michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]); michael@0: } michael@0: } michael@0: michael@0: nsMappedAttributes::~nsMappedAttributes() michael@0: { michael@0: if (mSheet) { michael@0: mSheet->DropMappedAttributes(this); michael@0: } michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: Attrs()[i].~InternalAttr(); michael@0: } michael@0: } michael@0: michael@0: michael@0: nsMappedAttributes* michael@0: nsMappedAttributes::Clone(bool aWillAddAttr) michael@0: { michael@0: uint32_t extra = aWillAddAttr ? 1 : 0; michael@0: michael@0: // This will call the overridden operator new michael@0: return new (mAttrCount + extra) nsMappedAttributes(*this); michael@0: } michael@0: michael@0: void* nsMappedAttributes::operator new(size_t aSize, uint32_t aAttrCount) CPP_THROW_NEW michael@0: { michael@0: NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested"); michael@0: michael@0: // aSize will include the mAttrs buffer so subtract that. michael@0: void* newAttrs = ::operator new(aSize - sizeof(void*[1]) + michael@0: aAttrCount * sizeof(InternalAttr)); michael@0: michael@0: #ifdef DEBUG michael@0: static_cast(newAttrs)->mBufferSize = aAttrCount; michael@0: #endif michael@0: michael@0: return newAttrs; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsMappedAttributes, michael@0: nsIStyleRule) michael@0: michael@0: void michael@0: nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue) michael@0: { michael@0: NS_PRECONDITION(aAttrName, "null name"); michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) { michael@0: if (Attrs()[i].mName.Equals(aAttrName)) { michael@0: Attrs()[i].mValue.Reset(); michael@0: Attrs()[i].mValue.SwapValueWith(aValue); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes"); michael@0: michael@0: if (mAttrCount != i) { michael@0: memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr)); michael@0: } michael@0: michael@0: new (&Attrs()[i].mName) nsAttrName(aAttrName); michael@0: new (&Attrs()[i].mValue) nsAttrValue(); michael@0: Attrs()[i].mValue.SwapValueWith(aValue); michael@0: ++mAttrCount; michael@0: } michael@0: michael@0: const nsAttrValue* michael@0: nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const michael@0: { michael@0: NS_PRECONDITION(aAttrName, "null name"); michael@0: michael@0: for (uint32_t i = 0; i < mAttrCount; ++i) { michael@0: if (Attrs()[i].mName.Equals(aAttrName)) { michael@0: return &Attrs()[i].mValue; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: const nsAttrValue* michael@0: nsMappedAttributes::GetAttr(const nsAString& aAttrName) const michael@0: { michael@0: for (uint32_t i = 0; i < mAttrCount; ++i) { michael@0: if (Attrs()[i].mName.Atom()->Equals(aAttrName)) { michael@0: return &Attrs()[i].mValue; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const michael@0: { michael@0: if (this == aOther) { michael@0: return true; michael@0: } michael@0: michael@0: if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) { michael@0: return false; michael@0: } michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: if (!Attrs()[i].mName.Equals(aOther->Attrs()[i].mName) || michael@0: !Attrs()[i].mValue.Equals(aOther->Attrs()[i].mValue)) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: uint32_t michael@0: nsMappedAttributes::HashValue() const michael@0: { michael@0: uint32_t hash = HashGeneric(mRuleMapper); michael@0: michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: hash = AddToHash(hash, michael@0: Attrs()[i].mName.HashValue(), michael@0: Attrs()[i].mValue.HashValue()); michael@0: } michael@0: michael@0: return hash; michael@0: } michael@0: michael@0: void michael@0: nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet) michael@0: { michael@0: if (mSheet) { michael@0: mSheet->DropMappedAttributes(this); michael@0: } michael@0: mSheet = aSheet; // not ref counted michael@0: } michael@0: michael@0: /* virtual */ void michael@0: nsMappedAttributes::MapRuleInfoInto(nsRuleData* aRuleData) michael@0: { michael@0: if (mRuleMapper) { michael@0: (*mRuleMapper)(this, aRuleData); michael@0: } michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: /* virtual */ void michael@0: nsMappedAttributes::List(FILE* out, int32_t aIndent) const michael@0: { michael@0: nsAutoString buffer; michael@0: uint32_t i; michael@0: michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: int32_t indent; michael@0: for (indent = aIndent; indent > 0; --indent) michael@0: fputs(" ", out); michael@0: michael@0: Attrs()[i].mName.GetQualifiedName(buffer); michael@0: fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); michael@0: michael@0: Attrs()[i].mValue.ToString(buffer); michael@0: fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); michael@0: fputs("\n", out); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: void michael@0: nsMappedAttributes::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue) michael@0: { michael@0: Attrs()[aPos].mValue.SwapValueWith(aValue); michael@0: Attrs()[aPos].~InternalAttr(); michael@0: memmove(&Attrs()[aPos], &Attrs()[aPos + 1], michael@0: (mAttrCount - aPos - 1) * sizeof(InternalAttr)); michael@0: mAttrCount--; michael@0: } michael@0: michael@0: const nsAttrName* michael@0: nsMappedAttributes::GetExistingAttrNameFromQName(const nsAString& aName) const michael@0: { michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: if (Attrs()[i].mName.IsAtom()) { michael@0: if (Attrs()[i].mName.Atom()->Equals(aName)) { michael@0: return &Attrs()[i].mName; michael@0: } michael@0: } michael@0: else { michael@0: if (Attrs()[i].mName.NodeInfo()->QualifiedNameEquals(aName)) { michael@0: return &Attrs()[i].mName; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: int32_t michael@0: nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName) const michael@0: { michael@0: uint32_t i; michael@0: for (i = 0; i < mAttrCount; ++i) { michael@0: if (Attrs()[i].mName.Equals(aLocalName)) { michael@0: return i; michael@0: } michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: size_t michael@0: nsMappedAttributes::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: NS_ASSERTION(mAttrCount == mBufferSize, michael@0: "mBufferSize and mAttrCount are expected to be the same."); michael@0: michael@0: size_t n = aMallocSizeOf(this); michael@0: for (uint16_t i = 0; i < mAttrCount; ++i) { michael@0: n += Attrs()[i].mValue.SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: return n; michael@0: } michael@0: