2015-05-03 19:32:37 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 11:12:37 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2006-03-30 08:03:04 +00:00
|
|
|
/*
|
|
|
|
* Storage of the children and attributes of a DOM node; storage for
|
|
|
|
* the two is unified to minimize footprint.
|
|
|
|
*/
|
|
|
|
|
2018-08-07 19:07:26 +00:00
|
|
|
#include "AttrArray.h"
|
2013-06-30 16:26:39 +00:00
|
|
|
|
2015-09-01 13:42:26 +00:00
|
|
|
#include "mozilla/CheckedInt.h"
|
2013-11-13 00:22:38 +00:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2013-06-30 16:26:39 +00:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
|
|
|
|
2008-01-09 09:38:28 +00:00
|
|
|
#include "nsMappedAttributeElement.h"
|
2004-01-15 17:07:27 +00:00
|
|
|
#include "nsString.h"
|
2004-04-12 21:56:09 +00:00
|
|
|
#include "nsHTMLStyleSheet.h"
|
2004-01-26 19:22:05 +00:00
|
|
|
#include "nsMappedAttributes.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
2011-08-11 13:29:50 +00:00
|
|
|
#include "nsContentUtils.h" // nsAutoScriptBlocker
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2015-09-01 13:42:26 +00:00
|
|
|
using mozilla::CheckedUint32;
|
|
|
|
|
2004-01-16 21:04:12 +00:00
|
|
|
/**
|
2016-07-22 03:10:23 +00:00
|
|
|
* Due to a compiler bug in VisualAge C++ for AIX, we need to return the
|
|
|
|
* address of the first index into mBuffer here, instead of simply returning
|
2004-01-16 21:04:12 +00:00
|
|
|
* mBuffer itself.
|
|
|
|
*
|
|
|
|
* See Bug 231104 for more information.
|
|
|
|
*/
|
2004-01-15 17:07:27 +00:00
|
|
|
#define ATTRS(_impl) \
|
2007-07-08 07:08:04 +00:00
|
|
|
reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0]))
|
2016-07-22 03:10:23 +00:00
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
|
|
|
|
#define NS_IMPL_EXTRA_SIZE \
|
|
|
|
((sizeof(Impl) - sizeof(mImpl->mBuffer)) / sizeof(void*))
|
|
|
|
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AttrArray()
|
2012-07-30 14:20:58 +00:00
|
|
|
: mImpl(nullptr)
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::~AttrArray()
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2008-02-02 23:41:24 +00:00
|
|
|
if (!mImpl) {
|
|
|
|
return;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2008-02-02 23:41:24 +00:00
|
|
|
Clear();
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2015-02-19 04:51:06 +00:00
|
|
|
free(mImpl);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AttrCount() const
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2004-01-26 19:22:05 +00:00
|
|
|
return NonMappedAttrCount() + MappedAttrCount();
|
|
|
|
}
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2004-01-26 19:22:05 +00:00
|
|
|
const nsAttrValue*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2004-01-26 19:22:05 +00:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
// This should be the common case so lets make an optimized loop
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-26 19:22:05 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
|
|
|
return &ATTRS(mImpl)[i].mValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
|
|
|
return mImpl->mMappedAttrs->GetAttr(aLocalName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-26 19:22:05 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
|
|
|
|
return &ATTRS(mImpl)[i].mValue;
|
|
|
|
}
|
|
|
|
}
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 22:57:58 +00:00
|
|
|
const nsAttrValue*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetAttr(const nsAString& aLocalName) const
|
2013-05-10 22:57:58 +00:00
|
|
|
{
|
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
|
|
|
return &ATTRS(mImpl)[i].mValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
|
|
|
return mImpl->mMappedAttrs->GetAttr(aLocalName);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-07-13 23:29:14 +00:00
|
|
|
const nsAttrValue*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetAttr(const nsAString& aName,
|
|
|
|
nsCaseTreatment aCaseSensitive) const
|
2012-07-13 23:29:14 +00:00
|
|
|
{
|
|
|
|
// Check whether someone is being silly and passing non-lowercase
|
|
|
|
// attr names.
|
|
|
|
if (aCaseSensitive == eIgnoreCase &&
|
|
|
|
nsContentUtils::StringContainsASCIIUpper(aName)) {
|
|
|
|
// Try again with a lowercased name, but make sure we can't reenter this
|
|
|
|
// block by passing eCaseSensitive for aCaseSensitive.
|
|
|
|
nsAutoString lowercase;
|
|
|
|
nsContentUtils::ASCIIToLower(aName, lowercase);
|
|
|
|
return GetAttr(lowercase, eCaseMatters);
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2012-07-13 23:29:14 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
|
|
|
if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
|
|
|
|
return &ATTRS(mImpl)[i].mValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
|
|
|
const nsAttrValue* val =
|
|
|
|
mImpl->mMappedAttrs->GetAttr(aName);
|
|
|
|
if (val) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2012-07-13 23:29:14 +00:00
|
|
|
}
|
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
const nsAttrValue*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AttrAt(uint32_t aPos) const
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2004-01-26 19:22:05 +00:00
|
|
|
NS_ASSERTION(aPos < AttrCount(),
|
2018-08-07 19:07:26 +00:00
|
|
|
"out-of-bounds access in AttrArray");
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
uint32_t nonmapped = NonMappedAttrCount();
|
|
|
|
if (aPos < nonmapped) {
|
|
|
|
return &ATTRS(mImpl)[aPos].mValue;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return mImpl->mMappedAttrs->AttrAt(aPos - nonmapped);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::SetAndSwapAttr(nsAtom* aLocalName, nsAttrValue& aValue,
|
|
|
|
bool* aHadValue)
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2017-05-18 21:09:01 +00:00
|
|
|
*aHadValue = false;
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-15 17:07:27 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
2004-01-26 19:22:05 +00:00
|
|
|
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
2017-05-18 21:09:01 +00:00
|
|
|
*aHadValue = true;
|
2004-01-15 17:07:27 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == slotCount && !AddAttrSlot()) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
|
2004-01-26 19:22:05 +00:00
|
|
|
new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
|
|
|
|
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
2004-01-15 17:07:27 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
|
|
|
|
nsAttrValue& aValue, bool* aHadValue)
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t namespaceID = aName->NamespaceID();
|
2017-10-02 22:05:19 +00:00
|
|
|
nsAtom* localName = aName->NameAtom();
|
2004-01-15 17:07:27 +00:00
|
|
|
if (namespaceID == kNameSpaceID_None) {
|
2017-05-18 21:09:01 +00:00
|
|
|
return SetAndSwapAttr(localName, aValue, aHadValue);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 21:09:01 +00:00
|
|
|
*aHadValue = false;
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-15 17:07:27 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
|
|
|
|
ATTRS(mImpl)[i].mName.SetTo(aName);
|
2004-01-26 19:22:05 +00:00
|
|
|
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
2017-05-18 21:09:01 +00:00
|
|
|
*aHadValue = true;
|
2004-01-15 17:07:27 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == slotCount && !AddAttrSlot()) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
new (&ATTRS(mImpl)[i].mName) nsAttrName(aName);
|
2004-01-26 19:22:05 +00:00
|
|
|
new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
|
|
|
|
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
2004-01-15 17:07:27 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-26 19:22:05 +00:00
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue)
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aPos < AttrCount(), "out-of-bounds");
|
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
uint32_t nonmapped = NonMappedAttrCount();
|
|
|
|
if (aPos < nonmapped) {
|
|
|
|
ATTRS(mImpl)[aPos].mValue.SwapValueWith(aValue);
|
|
|
|
ATTRS(mImpl)[aPos].~InternalAttr();
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
uint32_t slotCount = AttrSlotCount();
|
|
|
|
memmove(&ATTRS(mImpl)[aPos],
|
|
|
|
&ATTRS(mImpl)[aPos + 1],
|
|
|
|
(slotCount - aPos - 1) * sizeof(InternalAttr));
|
|
|
|
memset(&ATTRS(mImpl)[slotCount - 1], 0, sizeof(InternalAttr));
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
if (MappedAttrCount() == 1) {
|
|
|
|
// We're removing the last mapped attribute. Can't swap in this
|
|
|
|
// case; have to copy.
|
|
|
|
aValue.SetTo(*mImpl->mMappedAttrs->AttrAt(0));
|
|
|
|
NS_RELEASE(mImpl->mMappedAttrs);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return NS_OK;
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
RefPtr<nsMappedAttributes> mapped =
|
|
|
|
GetModifiableMapped(nullptr, nullptr, false);
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
mapped->RemoveAttrAt(aPos - nonmapped, aValue);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return MakeMappedUnique(mapped);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2016-10-04 12:20:00 +00:00
|
|
|
mozilla::dom::BorrowedAttrInfo
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AttrInfoAt(uint32_t aPos) const
|
2016-07-22 03:10:23 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aPos < AttrCount(),
|
2018-08-07 19:07:26 +00:00
|
|
|
"out-of-bounds access in AttrArray");
|
2016-07-22 03:10:23 +00:00
|
|
|
|
|
|
|
uint32_t nonmapped = NonMappedAttrCount();
|
|
|
|
if (aPos < nonmapped) {
|
2016-07-22 21:11:41 +00:00
|
|
|
return BorrowedAttrInfo(&ATTRS(mImpl)[aPos].mName, &ATTRS(mImpl)[aPos].mValue);
|
2016-07-22 03:10:23 +00:00
|
|
|
}
|
|
|
|
|
2016-07-22 21:11:41 +00:00
|
|
|
return BorrowedAttrInfo(mImpl->mMappedAttrs->NameAt(aPos - nonmapped),
|
2016-07-22 03:10:23 +00:00
|
|
|
mImpl->mMappedAttrs->AttrAt(aPos - nonmapped));
|
|
|
|
}
|
|
|
|
|
2005-12-30 20:12:35 +00:00
|
|
|
const nsAttrName*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AttrNameAt(uint32_t aPos) const
|
2005-12-30 20:12:35 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aPos < AttrCount(),
|
2018-08-07 19:07:26 +00:00
|
|
|
"out-of-bounds access in AttrArray");
|
2005-12-30 20:12:35 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
uint32_t nonmapped = NonMappedAttrCount();
|
|
|
|
if (aPos < nonmapped) {
|
|
|
|
return &ATTRS(mImpl)[aPos].mName;
|
2005-12-30 20:12:35 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
|
2005-12-30 20:12:35 +00:00
|
|
|
}
|
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
const nsAttrName*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetSafeAttrNameAt(uint32_t aPos) const
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2016-05-01 12:15:26 +00:00
|
|
|
uint32_t nonmapped = NonMappedAttrCount();
|
|
|
|
if (aPos < nonmapped) {
|
|
|
|
void** pos = mImpl->mBuffer + aPos * ATTRSIZE;
|
|
|
|
if (!*pos) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return &reinterpret_cast<InternalAttr*>(pos)->mName;
|
2005-12-28 21:52:39 +00:00
|
|
|
}
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
if (aPos >= AttrCount()) {
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2005-12-28 21:52:39 +00:00
|
|
|
}
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2016-05-01 12:15:26 +00:00
|
|
|
return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsAttrName*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetExistingAttrNameFromQName(const nsAString& aName) const
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-02-10 09:08:06 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
|
2004-01-15 17:07:27 +00:00
|
|
|
return &ATTRS(mImpl)[i].mName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-26 19:22:05 +00:00
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
2004-02-10 09:08:06 +00:00
|
|
|
return mImpl->mMappedAttrs->GetExistingAttrNameFromQName(aName);
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::IndexOfAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t idx;
|
2012-07-13 23:29:14 +00:00
|
|
|
if (mImpl && mImpl->mMappedAttrs && aNamespaceID == kNameSpaceID_None) {
|
|
|
|
idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName);
|
2004-02-19 22:16:16 +00:00
|
|
|
if (idx >= 0) {
|
2016-05-01 12:15:26 +00:00
|
|
|
return NonMappedAttrCount() + idx;
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i;
|
|
|
|
uint32_t slotCount = AttrSlotCount();
|
2004-01-15 17:07:27 +00:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
// This should be the common case so lets make an optimized loop
|
2017-06-18 02:39:15 +00:00
|
|
|
// Note that here we don't check for AttrSlotIsTaken() in the loop
|
|
|
|
// condition for the sake of performance because comparing aLocalName
|
|
|
|
// against null would fail in the loop body (since Equals() just compares
|
|
|
|
// the raw pointer value of aLocalName to what AttrSlotIsTaken() would be
|
|
|
|
// checking.
|
|
|
|
for (i = 0; i < slotCount; ++i) {
|
2004-01-15 17:07:27 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
2017-06-18 02:39:15 +00:00
|
|
|
MOZ_ASSERT(AttrSlotIsTaken(i), "sanity check");
|
2016-05-01 12:15:26 +00:00
|
|
|
return i;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-15 17:07:27 +00:00
|
|
|
if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
|
2016-05-01 12:15:26 +00:00
|
|
|
return i;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-01-26 19:22:05 +00:00
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::SetAndSwapMappedAttr(nsAtom* aLocalName,
|
|
|
|
nsAttrValue& aValue,
|
|
|
|
nsMappedAttributeElement* aContent,
|
|
|
|
nsHTMLStyleSheet* aSheet,
|
|
|
|
bool* aHadValue)
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
bool willAdd = true;
|
2011-08-24 17:27:52 +00:00
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
2012-08-04 07:44:01 +00:00
|
|
|
willAdd = !mImpl->mMappedAttrs->GetAttr(aLocalName);
|
2011-08-24 17:27:52 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsMappedAttributes> mapped =
|
2012-08-04 07:44:01 +00:00
|
|
|
GetModifiableMapped(aContent, aSheet, willAdd);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2017-05-18 21:09:01 +00:00
|
|
|
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
|
|
|
return MakeMappedUnique(mapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet)
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
2018-04-28 19:50:58 +00:00
|
|
|
MOZ_ASSERT(mImpl && mImpl->mMappedAttrs,
|
2012-03-22 04:10:51 +00:00
|
|
|
"Should have mapped attrs here!");
|
|
|
|
if (aSheet == mImpl->mMappedAttrs->GetStyleSheet()) {
|
2004-01-26 19:22:05 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsMappedAttributes> mapped =
|
2012-08-04 07:44:01 +00:00
|
|
|
GetModifiableMapped(nullptr, nullptr, false);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
|
|
|
mapped->SetStyleSheet(aSheet);
|
|
|
|
|
|
|
|
return MakeMappedUnique(mapped);
|
|
|
|
}
|
|
|
|
|
2018-07-06 18:43:14 +00:00
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement)
|
2018-07-06 18:43:14 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mImpl && mImpl->mMappedAttrs, "Should have mapped attrs here!");
|
|
|
|
|
|
|
|
// First two args don't matter if the assert holds.
|
|
|
|
RefPtr<nsMappedAttributes> mapped =
|
|
|
|
GetModifiableMapped(nullptr, nullptr, false);
|
|
|
|
|
|
|
|
mapped->SetRuleMapper(aElement.GetAttributeMappingFunction());
|
|
|
|
|
|
|
|
return MakeMappedUnique(mapped);
|
|
|
|
}
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2008-02-02 23:41:24 +00:00
|
|
|
void
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::Compact()
|
2008-02-02 23:41:24 +00:00
|
|
|
{
|
|
|
|
if (!mImpl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First compress away empty attrslots
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t slotCount = AttrSlotCount();
|
|
|
|
uint32_t attrCount = NonMappedAttrCount();
|
2008-02-02 23:41:24 +00:00
|
|
|
|
|
|
|
if (attrCount < slotCount) {
|
|
|
|
SetAttrSlotCount(attrCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then resize or free buffer
|
2018-08-06 19:29:37 +00:00
|
|
|
uint32_t newSize = attrCount * ATTRSIZE;
|
2008-02-02 23:41:24 +00:00
|
|
|
if (!newSize && !mImpl->mMappedAttrs) {
|
2015-02-19 04:51:06 +00:00
|
|
|
free(mImpl);
|
2012-07-30 14:20:58 +00:00
|
|
|
mImpl = nullptr;
|
2008-02-02 23:41:24 +00:00
|
|
|
}
|
|
|
|
else if (newSize < mImpl->mBufferSize) {
|
2015-02-19 04:51:06 +00:00
|
|
|
mImpl = static_cast<Impl*>(realloc(mImpl, (newSize + NS_IMPL_EXTRA_SIZE) * sizeof(nsIContent*)));
|
2008-02-02 23:41:24 +00:00
|
|
|
NS_ASSERTION(mImpl, "failed to reallocate to smaller buffer");
|
|
|
|
|
|
|
|
mImpl->mBufferSize = newSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
void
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::Clear()
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
|
|
|
if (!mImpl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-01-26 19:22:05 +00:00
|
|
|
if (mImpl->mMappedAttrs) {
|
|
|
|
NS_RELEASE(mImpl->mMappedAttrs);
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t i, slotCount = AttrSlotCount();
|
2010-12-14 17:16:24 +00:00
|
|
|
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2004-01-15 17:07:27 +00:00
|
|
|
ATTRS(mImpl)[i].~InternalAttr();
|
|
|
|
}
|
|
|
|
|
2018-08-07 19:11:11 +00:00
|
|
|
SetAttrSlotCount(0);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::NonMappedAttrCount() const
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
|
|
|
if (!mImpl) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t count = AttrSlotCount();
|
2004-01-26 19:22:05 +00:00
|
|
|
while (count > 0 && !mImpl->mBuffer[(count - 1) * ATTRSIZE]) {
|
|
|
|
--count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::MappedAttrCount() const
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 19:10:00 +00:00
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
|
2017-03-29 19:10:00 +00:00
|
|
|
{
|
|
|
|
nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
|
|
|
|
RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
|
|
|
|
return MakeMappedUnique(mapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::ClearMappedServoStyle()
|
|
|
|
{
|
2017-03-29 19:10:00 +00:00
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
|
|
|
mImpl->mMappedAttrs->ClearServoStyle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-04 07:44:01 +00:00
|
|
|
nsMappedAttributes*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
|
|
|
|
nsHTMLStyleSheet* aSheet,
|
|
|
|
bool aWillAddAttr,
|
|
|
|
int32_t aAttrCount)
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
|
|
|
if (mImpl && mImpl->mMappedAttrs) {
|
2012-08-04 07:44:01 +00:00
|
|
|
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
|
2012-08-04 07:44:01 +00:00
|
|
|
MOZ_ASSERT(aContent, "Trying to create modifiable without content");
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2005-01-12 19:45:38 +00:00
|
|
|
nsMapRuleToAttributesFunc mapRuleFunc =
|
|
|
|
aContent->GetAttributeMappingFunction();
|
2017-03-29 19:10:00 +00:00
|
|
|
return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::MakeMappedUnique(nsMappedAttributes* aAttributes)
|
2004-01-26 19:22:05 +00:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aAttributes, "missing attributes");
|
|
|
|
|
|
|
|
if (!mImpl && !GrowBy(1)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aAttributes->GetStyleSheet()) {
|
|
|
|
// This doesn't currently happen, but it could if we do loading right
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsMappedAttributes> mapped(aAttributes);
|
2004-01-26 19:22:05 +00:00
|
|
|
mapped.swap(mImpl->mMappedAttrs);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsMappedAttributes> mapped =
|
2004-04-12 21:56:09 +00:00
|
|
|
aAttributes->GetStyleSheet()->UniqueMappedAttributes(aAttributes);
|
|
|
|
NS_ENSURE_TRUE(mapped, NS_ERROR_OUT_OF_MEMORY);
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2004-01-30 22:08:23 +00:00
|
|
|
if (mapped != aAttributes) {
|
|
|
|
// Reset the stylesheet of aAttributes so that it doesn't spend time
|
|
|
|
// trying to remove itself from the hash. There is no risk that aAttributes
|
|
|
|
// is in the hash since it will always have come from GetModifiableMapped,
|
|
|
|
// which never returns maps that are in the hash (such hashes are by
|
|
|
|
// nature not modifiable).
|
|
|
|
aAttributes->DropStyleSheetReference();
|
2004-01-26 19:22:05 +00:00
|
|
|
}
|
|
|
|
mapped.swap(mImpl->mMappedAttrs);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-01-19 23:56:53 +00:00
|
|
|
const nsMappedAttributes*
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GetMapped() const
|
2017-01-19 23:56:53 +00:00
|
|
|
{
|
|
|
|
return mImpl ? mImpl->mMappedAttrs : nullptr;
|
|
|
|
}
|
2004-01-26 19:22:05 +00:00
|
|
|
|
2018-08-07 19:07:26 +00:00
|
|
|
nsresult
|
2018-08-08 23:58:44 +00:00
|
|
|
AttrArray::EnsureCapacityToClone(const AttrArray& aOther)
|
2017-04-20 19:57:48 +00:00
|
|
|
{
|
2018-08-07 19:07:26 +00:00
|
|
|
MOZ_ASSERT(!mImpl, "AttrArray::EnsureCapacityToClone requires the array be empty when called");
|
2017-04-20 19:57:48 +00:00
|
|
|
|
|
|
|
uint32_t attrCount = aOther.NonMappedAttrCount();
|
|
|
|
|
2018-08-06 19:29:37 +00:00
|
|
|
if (attrCount == 0) {
|
2017-04-20 19:57:48 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No need to use a CheckedUint32 because we are cloning. We know that we
|
2018-08-07 19:07:26 +00:00
|
|
|
// have already allocated an AttrArray of this size.
|
2017-04-20 19:57:48 +00:00
|
|
|
uint32_t size = attrCount;
|
|
|
|
size *= ATTRSIZE;
|
|
|
|
uint32_t totalSize = size;
|
|
|
|
totalSize += NS_IMPL_EXTRA_SIZE;
|
|
|
|
|
|
|
|
mImpl = static_cast<Impl*>(malloc(totalSize * sizeof(void*)));
|
|
|
|
NS_ENSURE_TRUE(mImpl, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
mImpl->mMappedAttrs = nullptr;
|
|
|
|
mImpl->mBufferSize = size;
|
|
|
|
|
|
|
|
// The array is now the right size, but we should reserve the correct
|
|
|
|
// number of slots for attributes so that children don't get written into
|
|
|
|
// that part of the array (which will then need to be moved later).
|
|
|
|
memset(static_cast<void*>(mImpl->mBuffer), 0, sizeof(InternalAttr) * attrCount);
|
2018-08-07 19:11:11 +00:00
|
|
|
SetAttrSlotCount(attrCount);
|
2017-04-20 19:57:48 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::GrowBy(uint32_t aGrowSize)
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2015-07-09 23:18:30 +00:00
|
|
|
CheckedUint32 size = 0;
|
|
|
|
if (mImpl) {
|
|
|
|
size += mImpl->mBufferSize;
|
|
|
|
size += NS_IMPL_EXTRA_SIZE;
|
|
|
|
if (!size.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2015-07-09 23:18:30 +00:00
|
|
|
CheckedUint32 minSize = size.value();
|
|
|
|
minSize += aGrowSize;
|
|
|
|
if (!minSize.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (minSize.value() <= ATTRCHILD_ARRAY_LINEAR_THRESHOLD) {
|
2004-01-15 17:07:27 +00:00
|
|
|
do {
|
|
|
|
size += ATTRCHILD_ARRAY_GROWSIZE;
|
2015-07-09 23:18:30 +00:00
|
|
|
if (!size.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} while (size.value() < minSize.value());
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-08-16 06:04:59 +00:00
|
|
|
uint32_t shift = mozilla::CeilingLog2(minSize.value());
|
|
|
|
if (shift >= 32) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = 1u << shift;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool needToInitialize = !mImpl;
|
2015-07-09 23:18:30 +00:00
|
|
|
CheckedUint32 neededSize = size;
|
|
|
|
neededSize *= sizeof(void*);
|
|
|
|
if (!neededSize.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Impl* newImpl = static_cast<Impl*>(realloc(mImpl, neededSize.value()));
|
2011-10-17 14:59:28 +00:00
|
|
|
NS_ENSURE_TRUE(newImpl, false);
|
2008-02-02 23:41:24 +00:00
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
mImpl = newImpl;
|
2008-02-02 23:41:24 +00:00
|
|
|
|
|
|
|
// Set initial counts if we didn't have a buffer before
|
2009-07-22 22:31:01 +00:00
|
|
|
if (needToInitialize) {
|
2012-07-30 14:20:58 +00:00
|
|
|
mImpl->mMappedAttrs = nullptr;
|
2018-08-07 19:11:11 +00:00
|
|
|
SetAttrSlotCount(0);
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 23:18:30 +00:00
|
|
|
mImpl->mBufferSize = size.value() - NS_IMPL_EXTRA_SIZE;
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::AddAttrSlot()
|
2004-01-15 17:07:27 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t slotCount = AttrSlotCount();
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2015-07-09 23:18:30 +00:00
|
|
|
CheckedUint32 size = slotCount;
|
|
|
|
size += 1;
|
|
|
|
size *= ATTRSIZE;
|
|
|
|
if (!size.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
// Grow buffer if needed
|
2015-07-09 23:18:30 +00:00
|
|
|
if (!(mImpl && mImpl->mBufferSize >= size.value()) &&
|
2004-01-15 17:07:27 +00:00
|
|
|
!GrowBy(ATTRSIZE)) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
2015-07-09 23:18:30 +00:00
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
void** offset = mImpl->mBuffer + slotCount * ATTRSIZE;
|
2004-02-09 22:48:53 +00:00
|
|
|
|
2004-01-15 17:07:27 +00:00
|
|
|
SetAttrSlotCount(slotCount + 1);
|
2017-04-19 18:34:02 +00:00
|
|
|
memset(static_cast<void*>(offset), 0, sizeof(InternalAttr));
|
2004-01-15 17:07:27 +00:00
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2004-01-15 17:07:27 +00:00
|
|
|
}
|
2010-05-11 01:12:33 +00:00
|
|
|
|
2012-02-01 21:58:01 +00:00
|
|
|
size_t
|
2018-08-07 19:07:26 +00:00
|
|
|
AttrArray::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
2011-07-12 14:56:01 +00:00
|
|
|
{
|
2012-02-01 21:58:01 +00:00
|
|
|
size_t n = 0;
|
2011-07-12 14:56:01 +00:00
|
|
|
if (mImpl) {
|
|
|
|
// Don't add the size taken by *mMappedAttrs because it's shared.
|
|
|
|
|
2012-02-01 21:58:01 +00:00
|
|
|
n += aMallocSizeOf(mImpl);
|
2011-08-10 22:54:19 +00:00
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t slotCount = AttrSlotCount();
|
|
|
|
for (uint32_t i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
2011-08-10 22:54:19 +00:00
|
|
|
nsAttrValue* value = &ATTRS(mImpl)[i].mValue;
|
2012-02-01 21:58:01 +00:00
|
|
|
n += value->SizeOfExcludingThis(aMallocSizeOf);
|
2011-08-10 22:54:19 +00:00
|
|
|
}
|
2011-07-12 14:56:01 +00:00
|
|
|
}
|
|
|
|
|
2012-02-01 21:58:01 +00:00
|
|
|
return n;
|
2011-07-12 14:56:01 +00:00
|
|
|
}
|