Bug 1728955: part 3) Add logging to `nsBaseClipboard`. r=masayuki
[gecko.git] / dom / base / nsMappedAttributes.cpp
blob43322f4d9a2c0ccc767b93ad03e16a2841edeb46
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/. */
7 /*
8 * A unique per-element set of attributes that is used as an
9 * nsIStyleRule; used to implement presentational attributes.
12 #include "nsMappedAttributes.h"
13 #include "mozilla/Assertions.h"
14 #include "nsHTMLStyleSheet.h"
15 #include "mozilla/DeclarationBlock.h"
16 #include "mozilla/HashFunctions.h"
17 #include "mozilla/MappedDeclarations.h"
18 #include "mozilla/MemoryReporting.h"
20 using namespace mozilla;
22 bool nsMappedAttributes::sShuttingDown = false;
23 nsTArray<void*>* nsMappedAttributes::sCachedMappedAttributeAllocations =
24 nullptr;
26 void nsMappedAttributes::Shutdown() {
27 sShuttingDown = true;
28 if (sCachedMappedAttributeAllocations) {
29 for (uint32_t i = 0; i < sCachedMappedAttributeAllocations->Length(); ++i) {
30 void* cachedValue = (*sCachedMappedAttributeAllocations)[i];
31 ::operator delete(cachedValue);
35 delete sCachedMappedAttributeAllocations;
36 sCachedMappedAttributeAllocations = nullptr;
39 nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet,
40 nsMapRuleToAttributesFunc aMapRuleFunc)
41 : mAttrCount(0),
42 mSheet(aSheet),
43 mRuleMapper(aMapRuleFunc),
44 mServoStyle(nullptr) {
45 MOZ_ASSERT(mRefCnt == 0); // Ensure caching works as expected.
48 nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy)
49 : mAttrCount(aCopy.mAttrCount),
50 mSheet(aCopy.mSheet),
51 mRuleMapper(aCopy.mRuleMapper),
52 // This is only called by ::Clone, which is used to create independent
53 // nsMappedAttributes objects which should not share a DeclarationBlock
54 mServoStyle(nullptr) {
55 MOZ_ASSERT(mBufferSize >= aCopy.mAttrCount, "can't fit attributes");
56 MOZ_ASSERT(mRefCnt == 0); // Ensure caching works as expected.
58 uint32_t i = 0;
59 for (const InternalAttr& attr : aCopy.Attrs()) {
60 new (&mBuffer[i++]) InternalAttr(attr);
64 nsMappedAttributes::~nsMappedAttributes() {
65 if (mSheet) {
66 mSheet->DropMappedAttributes(this);
69 for (InternalAttr& attr : Attrs()) {
70 attr.~InternalAttr();
74 nsMappedAttributes* nsMappedAttributes::Clone(bool aWillAddAttr) {
75 uint32_t extra = aWillAddAttr ? 1 : 0;
77 // This will call the overridden operator new
78 return new (mAttrCount + extra) nsMappedAttributes(*this);
81 void* nsMappedAttributes::operator new(size_t aSize,
82 uint32_t aAttrCount) noexcept(true) {
83 size_t size = aSize + aAttrCount * sizeof(InternalAttr);
85 if (sCachedMappedAttributeAllocations) {
86 void* cached = sCachedMappedAttributeAllocations->SafeElementAt(aAttrCount);
87 if (cached) {
88 (*sCachedMappedAttributeAllocations)[aAttrCount] = nullptr;
89 return cached;
93 void* newAttrs = ::operator new(size);
95 #ifdef DEBUG
96 static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
97 #endif
98 return newAttrs;
101 void nsMappedAttributes::LastRelease() {
102 if (!sShuttingDown) {
103 if (!sCachedMappedAttributeAllocations) {
104 sCachedMappedAttributeAllocations = new nsTArray<void*>();
107 // Ensure the cache array is at least mAttrCount + 1 long and
108 // that each item is either null or pointing to a cached item.
109 // The size of the array is capped because mapped attributes are defined
110 // statically in element implementations.
111 sCachedMappedAttributeAllocations->SetCapacity(mAttrCount + 1);
112 for (uint32_t i = sCachedMappedAttributeAllocations->Length();
113 i < (uint32_t(mAttrCount) + 1); ++i) {
114 sCachedMappedAttributeAllocations->AppendElement(nullptr);
117 if (!(*sCachedMappedAttributeAllocations)[mAttrCount]) {
118 void* memoryToCache = this;
119 this->~nsMappedAttributes();
120 (*sCachedMappedAttributeAllocations)[mAttrCount] = memoryToCache;
121 return;
125 delete this;
128 void nsMappedAttributes::SetAndSwapAttr(nsAtom* aAttrName, nsAttrValue& aValue,
129 bool* aValueWasSet) {
130 MOZ_ASSERT(aAttrName, "null name");
131 *aValueWasSet = false;
132 uint32_t i;
133 for (i = 0; i < mAttrCount && !mBuffer[i].mName.IsSmaller(aAttrName); ++i) {
134 if (mBuffer[i].mName.Equals(aAttrName)) {
135 mBuffer[i].mValue.SwapValueWith(aValue);
136 *aValueWasSet = true;
137 return;
141 MOZ_ASSERT(mBufferSize >= mAttrCount + 1, "can't fit attributes");
143 if (mAttrCount != i) {
144 memmove(&mBuffer[i + 1], &mBuffer[i],
145 (mAttrCount - i) * sizeof(InternalAttr));
148 new (&mBuffer[i].mName) nsAttrName(aAttrName);
149 new (&mBuffer[i].mValue) nsAttrValue();
150 mBuffer[i].mValue.SwapValueWith(aValue);
151 ++mAttrCount;
154 const nsAttrValue* nsMappedAttributes::GetAttr(const nsAtom* aAttrName) const {
155 MOZ_ASSERT(aAttrName, "null name");
156 for (const InternalAttr& attr : Attrs()) {
157 if (attr.mName.Equals(aAttrName)) {
158 return &attr.mValue;
161 return nullptr;
164 const nsAttrValue* nsMappedAttributes::GetAttr(
165 const nsAString& aAttrName) const {
166 for (const InternalAttr& attr : Attrs()) {
167 if (attr.mName.Atom()->Equals(aAttrName)) {
168 return &attr.mValue;
171 return nullptr;
174 bool nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const {
175 if (this == aOther) {
176 return true;
179 if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) {
180 return false;
183 uint32_t i;
184 for (i = 0; i < mAttrCount; ++i) {
185 if (!mBuffer[i].mName.Equals(aOther->mBuffer[i].mName) ||
186 !mBuffer[i].mValue.Equals(aOther->mBuffer[i].mValue)) {
187 return false;
191 return true;
194 PLDHashNumber nsMappedAttributes::HashValue() const {
195 PLDHashNumber hash = HashGeneric(mRuleMapper);
196 for (const InternalAttr& attr : Attrs()) {
197 hash = AddToHash(hash, attr.mName.HashValue(), attr.mValue.HashValue());
199 return hash;
202 void nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet) {
203 MOZ_ASSERT(!mSheet,
204 "Should either drop the sheet reference manually, "
205 "or drop the mapped attributes");
206 mSheet = aSheet; // not ref counted
209 void nsMappedAttributes::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue) {
210 mBuffer[aPos].mValue.SwapValueWith(aValue);
211 mBuffer[aPos].~InternalAttr();
212 memmove(&mBuffer[aPos], &mBuffer[aPos + 1],
213 (mAttrCount - aPos - 1) * sizeof(InternalAttr));
214 mAttrCount--;
217 const nsAttrName* nsMappedAttributes::GetExistingAttrNameFromQName(
218 const nsAString& aName) const {
219 for (const InternalAttr& attr : Attrs()) {
220 if (attr.mName.IsAtom()) {
221 if (attr.mName.Atom()->Equals(aName)) {
222 return &attr.mName;
224 } else {
225 if (attr.mName.NodeInfo()->QualifiedNameEquals(aName)) {
226 return &attr.mName;
231 return nullptr;
234 int32_t nsMappedAttributes::IndexOfAttr(const nsAtom* aLocalName) const {
235 for (uint32_t i = 0; i < mAttrCount; ++i) {
236 if (mBuffer[i].mName.Equals(aLocalName)) {
237 return i;
240 return -1;
243 size_t nsMappedAttributes::SizeOfIncludingThis(
244 MallocSizeOf aMallocSizeOf) const {
245 MOZ_ASSERT(mBufferSize >= mAttrCount, "can't fit attributes");
247 size_t n = aMallocSizeOf(this);
248 for (const InternalAttr& attr : Attrs()) {
249 n += attr.mValue.SizeOfExcludingThis(aMallocSizeOf);
251 return n;
254 void nsMappedAttributes::LazilyResolveServoDeclaration(dom::Document* aDoc) {
255 MOZ_ASSERT(!mServoStyle,
256 "LazilyResolveServoDeclaration should not be called if "
257 "mServoStyle is already set");
258 if (mRuleMapper) {
259 MappedDeclarations declarations(
260 aDoc, Servo_DeclarationBlock_CreateEmpty().Consume());
261 (*mRuleMapper)(this, declarations);
262 mServoStyle = declarations.TakeDeclarationBlock();