mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 20:55:39 +00:00
5b55368eda
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
307 lines
7.6 KiB
C++
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);
|
|
}
|
|
}
|
|
}
|