gecko-dev/dom/base/nsMappedAttributes.cpp
Manish Goregaokar 5b55368eda Bug 1330041 - Basic handling framework for presentation attributes in Stylo, with handling for font-size and color; r=bz,emilio
This introduces a basic framework for servo's style system to be able
to query the style of presentation attributes which it can then insert
into the cascade. It uses that framework to implement the size and
color attributes on <font>.

There are a number of improvements that can be done on top of this:

 - Implement all other properties
 - Abstractify the ruledata parameter of the mappers using templates or virtual dispatch so that it can be a Servo decl block instead
 - Implement aforementiond abstraction over Servo decl blocks (this obsoletes the code in the first item above, so it might just be better to skip that and directly do this)
 - Replace uses of nsHTMLStyleSheet with an abstract base class containing common elements between Servo and Gecko

I'd prefer for these to be done in separate steps.

MozReview-Commit-ID: GO60qfeZOfl

--HG--
extra : rebase_source : 516d369a8627e413983361aaf85ccb7132b0a06c
2017-01-19 15:56:53 -08:00

307 lines
7.6 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/*
* A unique per-element set of attributes that is used as an
* nsIStyleRule; used to implement presentational attributes.
*/
#include "nsMappedAttributes.h"
#include "nsHTMLStyleSheet.h"
#include "nsRuleWalker.h"
#include "nsRuleData.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoDeclarationBlock.h"
using namespace mozilla;
nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet,
nsMapRuleToAttributesFunc aMapRuleFunc)
: mAttrCount(0),
mSheet(aSheet),
mRuleMapper(aMapRuleFunc),
mServoStyle(nullptr)
{
}
nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy)
: mAttrCount(aCopy.mAttrCount),
mSheet(aCopy.mSheet),
mRuleMapper(aCopy.mRuleMapper),
// This is only called by ::Clone, which is used to create independent
// nsMappedAttributes objects which should not share a ServoDeclarationBlock
mServoStyle(nullptr)
{
NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes");
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]);
}
}
nsMappedAttributes::~nsMappedAttributes()
{
if (mSheet) {
mSheet->DropMappedAttributes(this);
}
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
Attrs()[i].~InternalAttr();
}
}
nsMappedAttributes*
nsMappedAttributes::Clone(bool aWillAddAttr)
{
uint32_t extra = aWillAddAttr ? 1 : 0;
// This will call the overridden operator new
return new (mAttrCount + extra) nsMappedAttributes(*this);
}
void* nsMappedAttributes::operator new(size_t aSize, uint32_t aAttrCount) CPP_THROW_NEW
{
NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested");
// aSize will include the mAttrs buffer so subtract that.
void* newAttrs = ::operator new(aSize - sizeof(void*[1]) +
aAttrCount * sizeof(InternalAttr));
#ifdef DEBUG
static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
#endif
return newAttrs;
}
NS_IMPL_ISUPPORTS(nsMappedAttributes,
nsIStyleRule)
void
nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
{
NS_PRECONDITION(aAttrName, "null name");
uint32_t i;
for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
if (Attrs()[i].mName.Equals(aAttrName)) {
Attrs()[i].mValue.Reset();
Attrs()[i].mValue.SwapValueWith(aValue);
return;
}
}
NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes");
if (mAttrCount != i) {
memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr));
}
new (&Attrs()[i].mName) nsAttrName(aAttrName);
new (&Attrs()[i].mValue) nsAttrValue();
Attrs()[i].mValue.SwapValueWith(aValue);
++mAttrCount;
}
const nsAttrValue*
nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const
{
NS_PRECONDITION(aAttrName, "null name");
for (uint32_t i = 0; i < mAttrCount; ++i) {
if (Attrs()[i].mName.Equals(aAttrName)) {
return &Attrs()[i].mValue;
}
}
return nullptr;
}
const nsAttrValue*
nsMappedAttributes::GetAttr(const nsAString& aAttrName) const
{
for (uint32_t i = 0; i < mAttrCount; ++i) {
if (Attrs()[i].mName.Atom()->Equals(aAttrName)) {
return &Attrs()[i].mValue;
}
}
return nullptr;
}
bool
nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const
{
if (this == aOther) {
return true;
}
if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) {
return false;
}
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
if (!Attrs()[i].mName.Equals(aOther->Attrs()[i].mName) ||
!Attrs()[i].mValue.Equals(aOther->Attrs()[i].mValue)) {
return false;
}
}
return true;
}
uint32_t
nsMappedAttributes::HashValue() const
{
uint32_t hash = HashGeneric(mRuleMapper);
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
hash = AddToHash(hash,
Attrs()[i].mName.HashValue(),
Attrs()[i].mValue.HashValue());
}
return hash;
}
void
nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet)
{
if (mSheet) {
mSheet->DropMappedAttributes(this);
}
mSheet = aSheet; // not ref counted
}
/* virtual */ void
nsMappedAttributes::MapRuleInfoInto(nsRuleData* aRuleData)
{
if (mRuleMapper) {
(*mRuleMapper)(this, aRuleData);
}
}
/* virtual */ bool
nsMappedAttributes::MightMapInheritedStyleData()
{
// Just assume that we do, rather than adding checks to all of the different
// kinds of attribute mapping functions we have.
return true;
}
/* virtual */ bool
nsMappedAttributes::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
nsCSSValue* aValue)
{
MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
return false;
}
#ifdef DEBUG
/* virtual */ void
nsMappedAttributes::List(FILE* out, int32_t aIndent) const
{
nsAutoCString str;
nsAutoString tmp;
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
int32_t indent;
for (indent = aIndent; indent > 0; --indent) {
str.AppendLiteral(" ");
}
Attrs()[i].mName.GetQualifiedName(tmp);
LossyAppendUTF16toASCII(tmp, str);
Attrs()[i].mValue.ToString(tmp);
LossyAppendUTF16toASCII(tmp, str);
str.Append('\n');
fprintf_stderr(out, "%s", str.get());
}
}
#endif
void
nsMappedAttributes::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue)
{
Attrs()[aPos].mValue.SwapValueWith(aValue);
Attrs()[aPos].~InternalAttr();
memmove(&Attrs()[aPos], &Attrs()[aPos + 1],
(mAttrCount - aPos - 1) * sizeof(InternalAttr));
mAttrCount--;
}
const nsAttrName*
nsMappedAttributes::GetExistingAttrNameFromQName(const nsAString& aName) const
{
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
if (Attrs()[i].mName.IsAtom()) {
if (Attrs()[i].mName.Atom()->Equals(aName)) {
return &Attrs()[i].mName;
}
}
else {
if (Attrs()[i].mName.NodeInfo()->QualifiedNameEquals(aName)) {
return &Attrs()[i].mName;
}
}
}
return nullptr;
}
int32_t
nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName) const
{
uint32_t i;
for (i = 0; i < mAttrCount; ++i) {
if (Attrs()[i].mName.Equals(aLocalName)) {
return i;
}
}
return -1;
}
size_t
nsMappedAttributes::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
NS_ASSERTION(mAttrCount == mBufferSize,
"mBufferSize and mAttrCount are expected to be the same.");
size_t n = aMallocSizeOf(this);
for (uint16_t i = 0; i < mAttrCount; ++i) {
n += Attrs()[i].mValue.SizeOfExcludingThis(aMallocSizeOf);
}
return n;
}
void
nsMappedAttributes::LazilyResolveServoDeclaration(nsRuleData* aRuleData,
nsCSSPropertyID* aIndexToIdMapping,
size_t aRuleDataSize)
{
MapRuleInfoInto(aRuleData);
MOZ_ASSERT(!mServoStyle,
"LazilyResolveServoDeclaration should not be called if mServoStyle is already set");
mServoStyle = Servo_DeclarationBlock_CreateEmpty().Consume();
for (size_t i = 0; i < aRuleDataSize; i++) {
nsCSSValue& val = aRuleData->mValueStorage[i];
if (val.GetUnit() != eCSSUnit_Null) {
Servo_DeclarationBlock_AddPresValue(mServoStyle.get(), aIndexToIdMapping[i], &val);
}
}
}