зеркало из https://github.com/mozilla/gecko-dev.git
1656 строки
40 KiB
C++
1656 строки
40 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/. */
|
|
|
|
/* rules in a CSS stylesheet other than style rules (e.g., @import rules) */
|
|
|
|
#include "nsCSSRules.h"
|
|
#include "nsCSSFontFaceRule.h"
|
|
|
|
#include "mozilla/Attributes.h"
|
|
|
|
#include "nsCSSValue.h"
|
|
#include "mozilla/StyleSheetInlines.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/css/ImportRule.h"
|
|
#include "mozilla/css/NameSpaceRule.h"
|
|
|
|
#include "nsString.h"
|
|
#include "nsAtom.h"
|
|
|
|
#include "nsCSSProps.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIDOMCSSStyleSheet.h"
|
|
#include "nsMediaList.h"
|
|
#include "mozilla/dom/CSSRuleList.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
#include "nsError.h"
|
|
#include "nsStyleUtil.h"
|
|
#include "mozilla/DeclarationBlockInlines.h"
|
|
#include "nsCSSParser.h"
|
|
#include "nsDOMClassInfoID.h"
|
|
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
|
|
#include "mozilla/dom/CSSFontFeatureValuesRuleBinding.h"
|
|
#include "StyleRule.h"
|
|
#include "nsFont.h"
|
|
#include "nsIURI.h"
|
|
#include "nsCCUncollectableMarker.h"
|
|
#include "nsWrapperCacheInlines.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
// base class for all rule types in a CSS style sheet
|
|
|
|
namespace mozilla {
|
|
namespace css {
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(Rule)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(Rule)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Rule)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Rule)
|
|
|
|
bool
|
|
Rule::IsCCLeaf() const
|
|
{
|
|
return !PreservingWrapper();
|
|
}
|
|
|
|
bool
|
|
Rule::IsKnownLive() const
|
|
{
|
|
if (HasKnownLiveWrapper()) {
|
|
return true;
|
|
}
|
|
|
|
StyleSheet* sheet = GetStyleSheet();
|
|
if (!sheet) {
|
|
return false;
|
|
}
|
|
|
|
if (!sheet->IsOwnedByDocument()) {
|
|
return false;
|
|
}
|
|
|
|
return nsCCUncollectableMarker::InGeneration(
|
|
sheet->GetAssociatedDocument()->GetMarkedCCGeneration());
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Rule)
|
|
return tmp->IsCCLeaf() || tmp->IsKnownLive();
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Rule)
|
|
// Please see documentation for nsCycleCollectionParticipant::CanSkip* for why
|
|
// we need to check HasNothingToTrace here but not in the other two CanSkip
|
|
// methods.
|
|
return tmp->IsCCLeaf() ||
|
|
(tmp->IsKnownLive() && tmp->HasNothingToTrace(tmp));
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Rule)
|
|
return tmp->IsCCLeaf() || tmp->IsKnownLive();
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
|
|
|
/* virtual */ void
|
|
Rule::SetStyleSheet(StyleSheet* aSheet)
|
|
{
|
|
// We don't reference count this up reference. The style sheet
|
|
// will tell us when it's going away or when we're detached from
|
|
// it.
|
|
mSheet = aSheet;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Rule::GetParentRule(nsIDOMCSSRule** aParentRule)
|
|
{
|
|
NS_IF_ADDREF(*aParentRule = mParentRule);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Rule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aSheet);
|
|
|
|
NS_IF_ADDREF(*aSheet = GetStyleSheet());
|
|
return NS_OK;
|
|
}
|
|
|
|
/* virtual */ css::Rule*
|
|
Rule::GetCSSRule()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Rule::GetType(uint16_t* aType)
|
|
{
|
|
*aType = Type();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Rule::SetCssText(const nsAString& aCssText)
|
|
{
|
|
// We used to throw for some rule types, but not all. Specifically, we did
|
|
// not throw for StyleRule. Let's just always not throw.
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Rule::GetCssText(nsAString& aCssText)
|
|
{
|
|
GetCssTextImpl(aCssText);
|
|
return NS_OK;
|
|
}
|
|
|
|
Rule*
|
|
Rule::GetParentRule() const
|
|
{
|
|
return mParentRule;
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// ImportRule
|
|
//
|
|
|
|
ImportRule::ImportRule(nsMediaList* aMedia, const nsString& aURLSpec,
|
|
uint32_t aLineNumber, uint32_t aColumnNumber)
|
|
: CSSImportRule(aLineNumber, aColumnNumber)
|
|
, mURLSpec(aURLSpec)
|
|
, mMedia(aMedia)
|
|
{
|
|
MOZ_ASSERT(aMedia);
|
|
// XXXbz This is really silly.... the mMedia here will be replaced
|
|
// with itself if we manage to load a sheet. Which should really
|
|
// never fail nowadays, in sane cases.
|
|
}
|
|
|
|
ImportRule::ImportRule(const ImportRule& aCopy)
|
|
: CSSImportRule(aCopy),
|
|
mURLSpec(aCopy.mURLSpec)
|
|
{
|
|
// Whether or not an @import rule has a null sheet is a permanent
|
|
// property of that @import rule, since it is null only if the target
|
|
// sheet failed security checks.
|
|
if (aCopy.mChildSheet) {
|
|
RefPtr<StyleSheet> sheet =
|
|
aCopy.mChildSheet->Clone(nullptr, this, nullptr, nullptr);
|
|
SetSheet(static_cast<CSSStyleSheet*>(sheet.get()));
|
|
// SetSheet sets mMedia appropriately
|
|
} else {
|
|
// We better just copy mMedia from aCopy, since we have nowhere else to get
|
|
// one.
|
|
mMedia = aCopy.mMedia;
|
|
}
|
|
}
|
|
|
|
ImportRule::~ImportRule()
|
|
{
|
|
if (mChildSheet) {
|
|
mChildSheet->SetOwnerRule(nullptr);
|
|
}
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(ImportRule, CSSImportRule)
|
|
NS_IMPL_RELEASE_INHERITED(ImportRule, CSSImportRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(ImportRule, CSSImportRule, mMedia, mChildSheet)
|
|
|
|
// QueryInterface implementation for ImportRule
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImportRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(CSSImportRule)
|
|
|
|
#ifdef DEBUG
|
|
/* virtual */ void
|
|
ImportRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString str;
|
|
// Indent
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
str.AppendLiteral(" ");
|
|
}
|
|
|
|
str.AppendLiteral("@import \"");
|
|
AppendUTF16toUTF8(mURLSpec, str);
|
|
str.AppendLiteral("\" ");
|
|
|
|
nsAutoString mediaText;
|
|
mMedia->GetText(mediaText);
|
|
AppendUTF16toUTF8(mediaText, str);
|
|
str.AppendLiteral("\n");
|
|
fprintf_stderr(out, "%s", str.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ already_AddRefed<Rule>
|
|
ImportRule::Clone() const
|
|
{
|
|
RefPtr<Rule> clone = new ImportRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
void
|
|
ImportRule::SetSheet(CSSStyleSheet* aSheet)
|
|
{
|
|
NS_PRECONDITION(aSheet, "null arg");
|
|
|
|
// set the new sheet
|
|
mChildSheet = aSheet;
|
|
aSheet->SetOwnerRule(this);
|
|
|
|
// set our medialist to be the same as the sheet's medialist
|
|
mMedia = static_cast<nsMediaList*>(mChildSheet->Media());
|
|
}
|
|
|
|
void
|
|
ImportRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@import url(");
|
|
nsStyleUtil::AppendEscapedCSSString(mURLSpec, aCssText);
|
|
aCssText.Append(')');
|
|
if (mMedia) {
|
|
nsAutoString mediaText;
|
|
mMedia->GetText(mediaText);
|
|
if (!mediaText.IsEmpty()) {
|
|
aCssText.Append(' ');
|
|
aCssText.Append(mediaText);
|
|
}
|
|
}
|
|
aCssText.Append(';');
|
|
}
|
|
|
|
MediaList*
|
|
ImportRule::GetMedia() const
|
|
{
|
|
return mMedia;
|
|
}
|
|
|
|
StyleSheet*
|
|
ImportRule::GetStyleSheet() const
|
|
{
|
|
return mChildSheet;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ImportRule::GetHref(nsAString & aHref)
|
|
{
|
|
aHref = mURLSpec;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
ImportRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mURLSpec
|
|
//
|
|
// The following members are not measured:
|
|
// - mMedia, because it is measured via CSSStyleSheet::mMedia
|
|
// - mChildSheet, because it is measured via CSSStyleSheetInner::mSheets
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsICSSMediaRule
|
|
//
|
|
MediaRule::MediaRule(uint32_t aLineNumber, uint32_t aColumnNumber)
|
|
: CSSMediaRule(aLineNumber, aColumnNumber)
|
|
{
|
|
}
|
|
|
|
MediaRule::MediaRule(const MediaRule& aCopy)
|
|
: CSSMediaRule(aCopy)
|
|
{
|
|
if (aCopy.mMedia) {
|
|
mMedia = aCopy.mMedia->Clone().downcast<nsMediaList>();
|
|
// XXXldb This doesn't really make sense.
|
|
mMedia->SetStyleSheet(aCopy.GetStyleSheet());
|
|
}
|
|
}
|
|
|
|
MediaRule::~MediaRule()
|
|
{
|
|
if (mMedia) {
|
|
mMedia->SetStyleSheet(nullptr);
|
|
}
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(MediaRule, CSSMediaRule)
|
|
NS_IMPL_RELEASE_INHERITED(MediaRule, CSSMediaRule)
|
|
|
|
// QueryInterface implementation for MediaRule
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(CSSMediaRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaRule, CSSMediaRule,
|
|
mMedia)
|
|
|
|
/* virtual */ void
|
|
MediaRule::SetStyleSheet(StyleSheet* aSheet)
|
|
{
|
|
if (mMedia) {
|
|
// Set to null so it knows it's leaving one sheet and joining another.
|
|
mMedia->SetStyleSheet(nullptr);
|
|
if (aSheet) {
|
|
mMedia->SetStyleSheet(aSheet->AsGecko());
|
|
}
|
|
}
|
|
|
|
GroupRule::SetStyleSheet(aSheet);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* virtual */ void
|
|
MediaRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString indentStr;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
indentStr.AppendLiteral(" ");
|
|
}
|
|
|
|
nsAutoCString str(indentStr);
|
|
str.AppendLiteral("@media ");
|
|
|
|
if (mMedia) {
|
|
nsAutoString mediaText;
|
|
mMedia->GetText(mediaText);
|
|
AppendUTF16toUTF8(mediaText, str);
|
|
}
|
|
|
|
str.AppendLiteral(" {\n");
|
|
fprintf_stderr(out, "%s", str.get());
|
|
|
|
GroupRule::List(out, aIndent);
|
|
|
|
fprintf_stderr(out, "%s}\n", indentStr.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ already_AddRefed<Rule>
|
|
MediaRule::Clone() const
|
|
{
|
|
RefPtr<Rule> clone = new MediaRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
nsresult
|
|
MediaRule::SetMedia(nsMediaList* aMedia)
|
|
{
|
|
mMedia = aMedia;
|
|
if (aMedia)
|
|
mMedia->SetStyleSheet(GetStyleSheet());
|
|
return NS_OK;
|
|
}
|
|
|
|
MediaList*
|
|
MediaRule::Media()
|
|
{
|
|
// In practice, if we end up being parsed at all, we have non-null mMedia. So
|
|
// it's OK to claim we don't return null here.
|
|
return mMedia;
|
|
}
|
|
|
|
void
|
|
MediaRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@media ");
|
|
AppendConditionText(aCssText);
|
|
GroupRule::AppendRulesToCssText(aCssText);
|
|
}
|
|
|
|
// nsIDOMCSSConditionRule methods
|
|
NS_IMETHODIMP
|
|
MediaRule::GetConditionText(nsAString& aConditionText)
|
|
{
|
|
aConditionText.Truncate(0);
|
|
AppendConditionText(aConditionText);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MediaRule::SetConditionText(const nsAString& aConditionText)
|
|
{
|
|
if (!mMedia) {
|
|
RefPtr<nsMediaList> media = new nsMediaList();
|
|
media->SetStyleSheet(GetStyleSheet());
|
|
nsresult rv = media->SetMediaText(aConditionText);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
mMedia = media;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
return mMedia->SetMediaText(aConditionText);
|
|
}
|
|
|
|
// GroupRule interface
|
|
/* virtual */ bool
|
|
MediaRule::UseForPresentation(nsPresContext* aPresContext,
|
|
nsMediaQueryResultCacheKey& aKey)
|
|
{
|
|
if (mMedia) {
|
|
MOZ_ASSERT(aPresContext);
|
|
return mMedia->Matches(aPresContext, &aKey);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
MediaRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mMedia
|
|
|
|
return n;
|
|
}
|
|
|
|
void
|
|
MediaRule::AppendConditionText(nsAString& aOutput) const
|
|
{
|
|
if (mMedia) {
|
|
nsAutoString mediaText;
|
|
mMedia->GetText(mediaText);
|
|
aOutput.Append(mediaText);
|
|
}
|
|
}
|
|
|
|
DocumentRule::DocumentRule(uint32_t aLineNumber, uint32_t aColumnNumber)
|
|
: dom::CSSMozDocumentRule(aLineNumber, aColumnNumber)
|
|
{
|
|
}
|
|
|
|
DocumentRule::DocumentRule(const DocumentRule& aCopy)
|
|
: dom::CSSMozDocumentRule(aCopy)
|
|
, mURLs(new URL(*aCopy.mURLs))
|
|
{
|
|
}
|
|
|
|
DocumentRule::~DocumentRule()
|
|
{
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(DocumentRule, ConditionRule)
|
|
NS_IMPL_RELEASE_INHERITED(DocumentRule, ConditionRule)
|
|
|
|
// QueryInterface implementation for DocumentRule
|
|
NS_INTERFACE_MAP_BEGIN(DocumentRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSMozDocumentRule)
|
|
|
|
#ifdef DEBUG
|
|
/* virtual */ void
|
|
DocumentRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString indentStr;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
indentStr.AppendLiteral(" ");
|
|
}
|
|
|
|
nsAutoCString str;
|
|
str.AppendLiteral("@-moz-document ");
|
|
for (URL *url = mURLs; url; url = url->next) {
|
|
switch (url->func) {
|
|
case URLMatchingFunction::eURL:
|
|
str.AppendLiteral("url(\"");
|
|
break;
|
|
case URLMatchingFunction::eURLPrefix:
|
|
str.AppendLiteral("url-prefix(\"");
|
|
break;
|
|
case URLMatchingFunction::eDomain:
|
|
str.AppendLiteral("domain(\"");
|
|
break;
|
|
case URLMatchingFunction::eRegExp:
|
|
str.AppendLiteral("regexp(\"");
|
|
break;
|
|
}
|
|
nsAutoCString escapedURL(url->url);
|
|
escapedURL.ReplaceSubstring("\"", "\\\""); // escape quotes
|
|
str.Append(escapedURL);
|
|
str.AppendLiteral("\"), ");
|
|
}
|
|
str.Cut(str.Length() - 2, 1); // remove last ,
|
|
fprintf_stderr(out, "%s%s {\n", indentStr.get(), str.get());
|
|
|
|
GroupRule::List(out, aIndent);
|
|
|
|
fprintf_stderr(out, "%s}\n", indentStr.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ already_AddRefed<Rule>
|
|
DocumentRule::Clone() const
|
|
{
|
|
RefPtr<Rule> clone = new DocumentRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
void
|
|
DocumentRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@-moz-document ");
|
|
AppendConditionText(aCssText);
|
|
GroupRule::AppendRulesToCssText(aCssText);
|
|
}
|
|
|
|
// nsIDOMCSSConditionRule methods
|
|
NS_IMETHODIMP
|
|
DocumentRule::GetConditionText(nsAString& aConditionText)
|
|
{
|
|
aConditionText.Truncate(0);
|
|
AppendConditionText(aConditionText);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
DocumentRule::SetConditionText(const nsAString& aConditionText)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
// GroupRule interface
|
|
/* virtual */ bool
|
|
DocumentRule::UseForPresentation(nsPresContext* aPresContext,
|
|
nsMediaQueryResultCacheKey& aKey)
|
|
{
|
|
return UseForPresentation(aPresContext);
|
|
}
|
|
|
|
bool
|
|
DocumentRule::UseForPresentation(nsPresContext* aPresContext)
|
|
{
|
|
nsIDocument *doc = aPresContext->Document();
|
|
nsIURI *docURI = doc->GetDocumentURI();
|
|
nsAutoCString docURISpec;
|
|
if (docURI) {
|
|
// If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
|
|
nsresult rv = docURI->GetSpec(docURISpec);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
}
|
|
|
|
for (URL *url = mURLs; url; url = url->next) {
|
|
if (Match(doc, docURI, docURISpec, url->url, url->func)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
DocumentRule::URL::~URL()
|
|
{
|
|
NS_CSS_DELETE_LIST_MEMBER(DocumentRule::URL, this, next);
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
DocumentRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mURLs
|
|
|
|
return n;
|
|
}
|
|
|
|
void
|
|
DocumentRule::AppendConditionText(nsAString& aCssText) const
|
|
{
|
|
for (URL *url = mURLs; url; url = url->next) {
|
|
switch (url->func) {
|
|
case URLMatchingFunction::eURL:
|
|
aCssText.AppendLiteral("url(");
|
|
break;
|
|
case URLMatchingFunction::eURLPrefix:
|
|
aCssText.AppendLiteral("url-prefix(");
|
|
break;
|
|
case URLMatchingFunction::eDomain:
|
|
aCssText.AppendLiteral("domain(");
|
|
break;
|
|
case URLMatchingFunction::eRegExp:
|
|
aCssText.AppendLiteral("regexp(");
|
|
break;
|
|
}
|
|
nsStyleUtil::AppendEscapedCSSString(NS_ConvertUTF8toUTF16(url->url),
|
|
aCssText);
|
|
aCssText.AppendLiteral("), ");
|
|
}
|
|
aCssText.Truncate(aCssText.Length() - 2); // remove last ", "
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// NameSpaceRule
|
|
//
|
|
|
|
NameSpaceRule::NameSpaceRule(nsAtom* aPrefix, const nsString& aURLSpec,
|
|
uint32_t aLineNumber, uint32_t aColumnNumber)
|
|
: CSSNamespaceRule(aLineNumber, aColumnNumber),
|
|
mPrefix(aPrefix),
|
|
mURLSpec(aURLSpec)
|
|
{
|
|
}
|
|
|
|
NameSpaceRule::NameSpaceRule(const NameSpaceRule& aCopy)
|
|
: CSSNamespaceRule(aCopy),
|
|
mPrefix(aCopy.mPrefix),
|
|
mURLSpec(aCopy.mURLSpec)
|
|
{
|
|
}
|
|
|
|
NameSpaceRule::~NameSpaceRule()
|
|
{
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(NameSpaceRule, CSSNamespaceRule)
|
|
NS_IMPL_RELEASE_INHERITED(NameSpaceRule, CSSNamespaceRule)
|
|
|
|
// QueryInterface implementation for NameSpaceRule
|
|
// If this ever gets its own cycle-collection bits, reevaluate our IsCCLeaf
|
|
// implementation.
|
|
NS_INTERFACE_MAP_BEGIN(NameSpaceRule)
|
|
if (aIID.Equals(NS_GET_IID(css::NameSpaceRule))) {
|
|
*aInstancePtr = this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
else
|
|
NS_INTERFACE_MAP_END_INHERITING(CSSNamespaceRule)
|
|
|
|
#ifdef DEBUG
|
|
/* virtual */ void
|
|
NameSpaceRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString str;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
str.AppendLiteral(" ");
|
|
}
|
|
|
|
nsAutoString buffer;
|
|
|
|
str.AppendLiteral("@namespace ");
|
|
|
|
if (mPrefix) {
|
|
mPrefix->ToString(buffer);
|
|
AppendUTF16toUTF8(buffer, str);
|
|
str.Append(' ');
|
|
}
|
|
|
|
str.AppendLiteral("url(\"");
|
|
AppendUTF16toUTF8(mURLSpec, str);
|
|
str.AppendLiteral("\")\n");
|
|
fprintf_stderr(out, "%s", str.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ already_AddRefed<Rule>
|
|
NameSpaceRule::Clone() const
|
|
{
|
|
RefPtr<Rule> clone = new NameSpaceRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
void
|
|
NameSpaceRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@namespace ");
|
|
if (mPrefix) {
|
|
aCssText.Append(nsDependentAtomString(mPrefix) + NS_LITERAL_STRING(" "));
|
|
}
|
|
aCssText.AppendLiteral("url(");
|
|
nsStyleUtil::AppendEscapedCSSString(mURLSpec, aCssText);
|
|
aCssText.AppendLiteral(");");
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
NameSpaceRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mPrefix
|
|
// - mURLSpec
|
|
}
|
|
|
|
} // namespace css
|
|
} // namespace mozilla
|
|
|
|
// -----------------------------------
|
|
// nsCSSFontFeatureValuesRule
|
|
//
|
|
|
|
/* virtual */ already_AddRefed<css::Rule>
|
|
nsCSSFontFeatureValuesRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new nsCSSFontFeatureValuesRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsCSSFontFeatureValuesRule, dom::CSSFontFeatureValuesRule)
|
|
NS_IMPL_RELEASE_INHERITED(nsCSSFontFeatureValuesRule, dom::CSSFontFeatureValuesRule)
|
|
|
|
// QueryInterface implementation for nsCSSFontFeatureValuesRule
|
|
// If this ever gets its own cycle-collection bits, reevaluate our IsCCLeaf
|
|
// implementation.
|
|
NS_INTERFACE_MAP_BEGIN(nsCSSFontFeatureValuesRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSFontFeatureValuesRule)
|
|
|
|
static void
|
|
FeatureValuesToString(
|
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aFeatureValues,
|
|
nsAString& aOutStr)
|
|
{
|
|
uint32_t i, n;
|
|
|
|
// append values
|
|
n = aFeatureValues.Length();
|
|
for (i = 0; i < n; i++) {
|
|
const gfxFontFeatureValueSet::FeatureValues& fv = aFeatureValues[i];
|
|
|
|
// @alternate
|
|
aOutStr.AppendLiteral(" @");
|
|
nsAutoString functAlt;
|
|
nsStyleUtil::GetFunctionalAlternatesName(fv.alternate, functAlt);
|
|
aOutStr.Append(functAlt);
|
|
aOutStr.AppendLiteral(" {");
|
|
|
|
// for each ident-values tuple
|
|
uint32_t j, numValues = fv.valuelist.Length();
|
|
for (j = 0; j < numValues; j++) {
|
|
aOutStr.Append(' ');
|
|
const gfxFontFeatureValueSet::ValueList& vlist = fv.valuelist[j];
|
|
nsStyleUtil::AppendEscapedCSSIdent(vlist.name, aOutStr);
|
|
aOutStr.Append(':');
|
|
|
|
uint32_t k, numSelectors = vlist.featureSelectors.Length();
|
|
for (k = 0; k < numSelectors; k++) {
|
|
aOutStr.Append(' ');
|
|
aOutStr.AppendInt(vlist.featureSelectors[k]);
|
|
}
|
|
|
|
aOutStr.Append(';');
|
|
}
|
|
aOutStr.AppendLiteral(" }\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
FontFeatureValuesRuleToString(
|
|
mozilla::SharedFontList* aFamilyList,
|
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aFeatureValues,
|
|
nsAString& aOutStr)
|
|
{
|
|
aOutStr.AssignLiteral("@font-feature-values ");
|
|
nsAutoString familyListStr, valueTextStr;
|
|
nsStyleUtil::AppendEscapedCSSFontFamilyList(aFamilyList, familyListStr);
|
|
aOutStr.Append(familyListStr);
|
|
aOutStr.AppendLiteral(" {\n");
|
|
FeatureValuesToString(aFeatureValues, valueTextStr);
|
|
aOutStr.Append(valueTextStr);
|
|
aOutStr.Append('}');
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsCSSFontFeatureValuesRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoString text;
|
|
FontFeatureValuesRuleToString(mFamilyList, mFeatureValues, text);
|
|
NS_ConvertUTF16toUTF8 utf8(text);
|
|
|
|
// replace newlines with newlines plus indent spaces
|
|
char* indent = new char[(aIndent + 1) * 2];
|
|
int32_t i;
|
|
for (i = 1; i < (aIndent + 1) * 2 - 1; i++) {
|
|
indent[i] = 0x20;
|
|
}
|
|
indent[0] = 0xa;
|
|
indent[aIndent * 2 + 1] = 0;
|
|
utf8.ReplaceSubstring("\n", indent);
|
|
delete [] indent;
|
|
|
|
nsAutoCString indentStr;
|
|
for (i = aIndent; --i >= 0; ) {
|
|
indentStr.AppendLiteral(" ");
|
|
}
|
|
fprintf_stderr(out, "%s%s\n", indentStr.get(), utf8.get());
|
|
}
|
|
#endif
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSFontFeatureValuesRule::GetFontFamily(nsAString& aFamilyListStr)
|
|
{
|
|
nsStyleUtil::AppendEscapedCSSFontFamilyList(mFamilyList, aFamilyListStr);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSFontFeatureValuesRule::GetValueText(nsAString& aValueText)
|
|
{
|
|
FeatureValuesToString(mFeatureValues, aValueText);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSFontFeatureValuesRule::SetFontFamily(const nsAString& aFontFamily)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSFontFeatureValuesRule::SetValueText(const nsAString& aValueText)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
void
|
|
nsCSSFontFeatureValuesRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
FontFeatureValuesRuleToString(mFamilyList, mFeatureValues, aCssText);
|
|
}
|
|
|
|
struct MakeFamilyArray {
|
|
explicit MakeFamilyArray(nsTArray<nsString>& aFamilyArray)
|
|
: familyArray(aFamilyArray), hasGeneric(false)
|
|
{}
|
|
|
|
static bool
|
|
AddFamily(const nsString& aFamily, bool aGeneric, void* aData)
|
|
{
|
|
MakeFamilyArray *familyArr = reinterpret_cast<MakeFamilyArray*> (aData);
|
|
if (!aGeneric && !aFamily.IsEmpty()) {
|
|
familyArr->familyArray.AppendElement(aFamily);
|
|
}
|
|
if (aGeneric) {
|
|
familyArr->hasGeneric = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
nsTArray<nsString>& familyArray;
|
|
bool hasGeneric;
|
|
};
|
|
|
|
void
|
|
nsCSSFontFeatureValuesRule::AddValueList(int32_t aVariantAlternate,
|
|
nsTArray<gfxFontFeatureValueSet::ValueList>& aValueList)
|
|
{
|
|
uint32_t i, len = mFeatureValues.Length();
|
|
bool foundAlternate = false;
|
|
|
|
// add to an existing list for a given property value
|
|
for (i = 0; i < len; i++) {
|
|
gfxFontFeatureValueSet::FeatureValues& f = mFeatureValues.ElementAt(i);
|
|
|
|
if (f.alternate == uint32_t(aVariantAlternate)) {
|
|
f.valuelist.AppendElements(aValueList);
|
|
foundAlternate = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// create a new list for a given property value
|
|
if (!foundAlternate) {
|
|
gfxFontFeatureValueSet::FeatureValues &f = *mFeatureValues.AppendElement();
|
|
f.alternate = aVariantAlternate;
|
|
f.valuelist.AppendElements(aValueList);
|
|
}
|
|
}
|
|
|
|
size_t
|
|
nsCSSFontFeatureValuesRule::SizeOfIncludingThis(
|
|
MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsCSSKeyframeStyleDeclaration
|
|
//
|
|
|
|
nsCSSKeyframeStyleDeclaration::nsCSSKeyframeStyleDeclaration(nsCSSKeyframeRule *aRule)
|
|
: mRule(aRule)
|
|
{
|
|
}
|
|
|
|
nsCSSKeyframeStyleDeclaration::~nsCSSKeyframeStyleDeclaration()
|
|
{
|
|
NS_ASSERTION(!mRule, "DropReference not called.");
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSKeyframeStyleDeclaration)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSKeyframeStyleDeclaration)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsCSSKeyframeStyleDeclaration)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSKeyframeStyleDeclaration)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
|
|
|
|
DeclarationBlock*
|
|
nsCSSKeyframeStyleDeclaration::GetCSSDeclaration(Operation aOperation)
|
|
{
|
|
if (mRule) {
|
|
return mRule->Declaration();
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSKeyframeStyleDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv,
|
|
nsIPrincipal* aSubjectPrincipal)
|
|
{
|
|
GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
|
|
}
|
|
|
|
nsDOMCSSDeclaration::ServoCSSParsingEnvironment
|
|
nsCSSKeyframeStyleDeclaration::GetServoCSSParsingEnvironment(
|
|
nsIPrincipal* aSubjectPrincipal) const
|
|
{
|
|
MOZ_CRASH("GetURLData shouldn't be calling on a Gecko rule");
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframeStyleDeclaration::GetParentRule(nsIDOMCSSRule **aParent)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aParent);
|
|
|
|
NS_IF_ADDREF(*aParent = mRule);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsCSSKeyframeStyleDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
|
|
{
|
|
MOZ_ASSERT(aDecl, "must be non-null");
|
|
mRule->ChangeDeclaration(aDecl->AsGecko());
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDocument*
|
|
nsCSSKeyframeStyleDeclaration::DocToUpdate()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
nsINode*
|
|
nsCSSKeyframeStyleDeclaration::GetParentObject()
|
|
{
|
|
return mRule ? mRule->GetDocument() : nullptr;
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsCSSKeyframeRule
|
|
//
|
|
|
|
nsCSSKeyframeRule::nsCSSKeyframeRule(const nsCSSKeyframeRule& aCopy)
|
|
// copy everything except our reference count and mDOMDeclaration
|
|
: dom::CSSKeyframeRule(aCopy)
|
|
, mKeys(aCopy.mKeys)
|
|
, mDeclaration(new css::Declaration(*aCopy.mDeclaration))
|
|
{
|
|
mDeclaration->SetOwningRule(this);
|
|
}
|
|
|
|
nsCSSKeyframeRule::~nsCSSKeyframeRule()
|
|
{
|
|
mDeclaration->SetOwningRule(nullptr);
|
|
if (mDOMDeclaration) {
|
|
mDOMDeclaration->DropReference();
|
|
}
|
|
}
|
|
|
|
/* virtual */ already_AddRefed<css::Rule>
|
|
nsCSSKeyframeRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new nsCSSKeyframeRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsCSSKeyframeRule, dom::CSSKeyframeRule)
|
|
NS_IMPL_RELEASE_INHERITED(nsCSSKeyframeRule, dom::CSSKeyframeRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSKeyframeRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCSSKeyframeRule,
|
|
dom::CSSKeyframeRule)
|
|
if (tmp->mDOMDeclaration) {
|
|
tmp->mDOMDeclaration->DropReference();
|
|
tmp->mDOMDeclaration = nullptr;
|
|
}
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCSSKeyframeRule,
|
|
dom::CSSKeyframeRule)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMDeclaration)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
bool
|
|
nsCSSKeyframeRule::IsCCLeaf() const
|
|
{
|
|
// Let's not worry about figuring out whether we're a leaf or not.
|
|
return false;
|
|
}
|
|
|
|
// QueryInterface implementation for nsCSSKeyframeRule
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSKeyframeRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSKeyframeRule)
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsCSSKeyframeRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString str;
|
|
for (int32_t index = aIndent; --index >= 0; ) {
|
|
str.AppendLiteral(" ");
|
|
}
|
|
|
|
nsAutoString tmp;
|
|
DoGetKeyText(tmp);
|
|
AppendUTF16toUTF8(tmp, str);
|
|
str.AppendLiteral(" { ");
|
|
mDeclaration->ToString(tmp);
|
|
AppendUTF16toUTF8(tmp, str);
|
|
str.AppendLiteral("}\n");
|
|
fprintf_stderr(out, "%s", str.get());
|
|
}
|
|
#endif
|
|
|
|
void
|
|
nsCSSKeyframeRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
DoGetKeyText(aCssText);
|
|
aCssText.AppendLiteral(" { ");
|
|
nsAutoString tmp;
|
|
mDeclaration->ToString(tmp);
|
|
aCssText.Append(tmp);
|
|
aCssText.AppendLiteral(" }");
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframeRule::GetKeyText(nsAString& aKeyText)
|
|
{
|
|
DoGetKeyText(aKeyText);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsCSSKeyframeRule::DoGetKeyText(nsAString& aKeyText) const
|
|
{
|
|
aKeyText.Truncate();
|
|
uint32_t i = 0, i_end = mKeys.Length();
|
|
MOZ_ASSERT(i_end != 0, "must have some keys");
|
|
for (;;) {
|
|
aKeyText.AppendFloat(mKeys[i] * 100.0f);
|
|
aKeyText.Append(char16_t('%'));
|
|
if (++i == i_end) {
|
|
break;
|
|
}
|
|
aKeyText.AppendLiteral(", ");
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframeRule::SetKeyText(const nsAString& aKeyText)
|
|
{
|
|
nsCSSParser parser;
|
|
|
|
InfallibleTArray<float> newSelectors;
|
|
// FIXME: pass filename and line number
|
|
if (!parser.ParseKeyframeSelectorString(aKeyText, nullptr, 0, newSelectors)) {
|
|
// for now, we don't do anything if the parse fails
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
newSelectors.SwapElements(mKeys);
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
if (doc) {
|
|
doc->StyleRuleChanged(sheet, this);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsICSSDeclaration*
|
|
nsCSSKeyframeRule::Style()
|
|
{
|
|
if (!mDOMDeclaration) {
|
|
mDOMDeclaration = new nsCSSKeyframeStyleDeclaration(this);
|
|
}
|
|
return mDOMDeclaration;
|
|
}
|
|
|
|
void
|
|
nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
|
|
{
|
|
// Our caller already did a BeginUpdate/EndUpdate, but with
|
|
// UPDATE_CONTENT, and we need UPDATE_STYLE to trigger work in
|
|
// PresShell::EndUpdate.
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
if (aDeclaration != mDeclaration) {
|
|
mDeclaration->SetOwningRule(nullptr);
|
|
mDeclaration = aDeclaration;
|
|
mDeclaration->SetOwningRule(this);
|
|
}
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
if (doc) {
|
|
doc->StyleRuleChanged(sheet, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
nsCSSKeyframeRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mKeys
|
|
// - mDeclaration
|
|
// - mDOMDeclaration
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsCSSKeyframesRule
|
|
//
|
|
|
|
nsCSSKeyframesRule::nsCSSKeyframesRule(const nsCSSKeyframesRule& aCopy)
|
|
// copy everything except our reference count. GroupRule's copy
|
|
// constructor also doesn't copy the lazily-constructed
|
|
// mRuleCollection.
|
|
: dom::CSSKeyframesRule(aCopy),
|
|
mName(aCopy.mName)
|
|
{
|
|
}
|
|
|
|
nsCSSKeyframesRule::~nsCSSKeyframesRule()
|
|
{
|
|
}
|
|
|
|
/* virtual */ already_AddRefed<css::Rule>
|
|
nsCSSKeyframesRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new nsCSSKeyframesRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsCSSKeyframesRule, dom::CSSKeyframesRule)
|
|
NS_IMPL_RELEASE_INHERITED(nsCSSKeyframesRule, dom::CSSKeyframesRule)
|
|
|
|
// QueryInterface implementation for nsCSSKeyframesRule
|
|
NS_INTERFACE_MAP_BEGIN(nsCSSKeyframesRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSKeyframesRule)
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsCSSKeyframesRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString indentStr;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
indentStr.AppendLiteral(" ");
|
|
}
|
|
|
|
fprintf_stderr(out, "%s@keyframes %s {\n",
|
|
indentStr.get(), nsAtomCString(mName).get());
|
|
|
|
GroupRule::List(out, aIndent);
|
|
|
|
fprintf_stderr(out, "%s}\n", indentStr.get());
|
|
}
|
|
#endif
|
|
|
|
void
|
|
nsCSSKeyframesRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@keyframes ");
|
|
aCssText.Append(nsDependentAtomString(mName));
|
|
aCssText.AppendLiteral(" {\n");
|
|
nsAutoString tmp;
|
|
for (const Rule* rule : GeckoRules()) {
|
|
static_cast<const nsCSSKeyframeRule*>(rule)->GetCssText(tmp);
|
|
aCssText.Append(tmp);
|
|
aCssText.Append('\n');
|
|
}
|
|
aCssText.Append('}');
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframesRule::GetName(nsAString& aName)
|
|
{
|
|
mName->ToString(aName);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframesRule::SetName(const nsAString& aName)
|
|
{
|
|
if (mName->Equals(aName)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
mName = NS_Atomize(aName);
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
if (doc) {
|
|
doc->StyleRuleChanged(sheet, this);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframesRule::AppendRule(const nsAString& aRule)
|
|
{
|
|
// The spec is confusing, and I think we should just append the rule,
|
|
// which also turns out to match WebKit:
|
|
// http://lists.w3.org/Archives/Public/www-style/2011Apr/0034.html
|
|
nsCSSParser parser;
|
|
|
|
// FIXME: pass filename and line number
|
|
RefPtr<nsCSSKeyframeRule> rule =
|
|
parser.ParseKeyframeRule(aRule, nullptr, 0);
|
|
if (rule) {
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
AppendStyleRule(rule);
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
if (doc) {
|
|
doc->StyleRuleChanged(sheet, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static const uint32_t RULE_NOT_FOUND = uint32_t(-1);
|
|
|
|
uint32_t
|
|
nsCSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey)
|
|
{
|
|
nsCSSParser parser;
|
|
|
|
InfallibleTArray<float> keys;
|
|
// FIXME: pass filename and line number
|
|
if (parser.ParseKeyframeSelectorString(aKey, nullptr, 0, keys)) {
|
|
IncrementalClearCOMRuleArray& rules = GeckoRules();
|
|
// The spec isn't clear, but we'll match on the key list, which
|
|
// mostly matches what WebKit does, except we'll do last-match
|
|
// instead of first-match, and handling parsing differences better.
|
|
// http://lists.w3.org/Archives/Public/www-style/2011Apr/0036.html
|
|
// http://lists.w3.org/Archives/Public/www-style/2011Apr/0037.html
|
|
for (uint32_t i = rules.Count(); i-- != 0; ) {
|
|
if (static_cast<nsCSSKeyframeRule*>(rules[i])->GetKeys() == keys) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return RULE_NOT_FOUND;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSKeyframesRule::DeleteRule(const nsAString& aKey)
|
|
{
|
|
uint32_t index = FindRuleIndexForKey(aKey);
|
|
if (index != RULE_NOT_FOUND) {
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
DeleteStyleRuleAt(index);
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
|
|
if (doc) {
|
|
doc->StyleRuleChanged(sheet, this);
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCSSKeyframeRule*
|
|
nsCSSKeyframesRule::FindRule(const nsAString& aKey)
|
|
{
|
|
uint32_t index = FindRuleIndexForKey(aKey);
|
|
if (index == RULE_NOT_FOUND) {
|
|
return nullptr;
|
|
}
|
|
return static_cast<nsCSSKeyframeRule*>(GeckoRules()[index]);
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
nsCSSKeyframesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
// worthwhile:
|
|
// - mName
|
|
|
|
return n;
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsCSSPageStyleDeclaration
|
|
//
|
|
|
|
nsCSSPageStyleDeclaration::nsCSSPageStyleDeclaration(nsCSSPageRule* aRule)
|
|
: mRule(aRule)
|
|
{
|
|
}
|
|
|
|
nsCSSPageStyleDeclaration::~nsCSSPageStyleDeclaration()
|
|
{
|
|
NS_ASSERTION(!mRule, "DropReference not called.");
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSPageStyleDeclaration)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSPageStyleDeclaration)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsCSSPageStyleDeclaration)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSPageStyleDeclaration)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
|
|
|
|
DeclarationBlock*
|
|
nsCSSPageStyleDeclaration::GetCSSDeclaration(Operation aOperation)
|
|
{
|
|
if (mRule) {
|
|
return mRule->Declaration();
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSPageStyleDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv,
|
|
nsIPrincipal* aSubjectPrincipal)
|
|
{
|
|
GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
|
|
}
|
|
|
|
nsDOMCSSDeclaration::ServoCSSParsingEnvironment
|
|
nsCSSPageStyleDeclaration::GetServoCSSParsingEnvironment(
|
|
nsIPrincipal* aSubjectPrincipal) const
|
|
{
|
|
MOZ_CRASH("GetURLData shouldn't be calling on a Gecko rule");
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSPageStyleDeclaration::GetParentRule(nsIDOMCSSRule** aParent)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aParent);
|
|
|
|
NS_IF_ADDREF(*aParent = mRule);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsCSSPageStyleDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
|
|
{
|
|
MOZ_ASSERT(aDecl, "must be non-null");
|
|
mRule->ChangeDeclaration(aDecl->AsGecko());
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDocument*
|
|
nsCSSPageStyleDeclaration::DocToUpdate()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
nsINode*
|
|
nsCSSPageStyleDeclaration::GetParentObject()
|
|
{
|
|
return mRule ? mRule->GetDocument() : nullptr;
|
|
}
|
|
|
|
// -------------------------------------------
|
|
// nsCSSPageRule
|
|
//
|
|
|
|
nsCSSPageRule::nsCSSPageRule(const nsCSSPageRule& aCopy)
|
|
// copy everything except our reference count and mDOMDeclaration
|
|
: dom::CSSPageRule(aCopy)
|
|
, mDeclaration(new css::Declaration(*aCopy.mDeclaration))
|
|
{
|
|
mDeclaration->SetOwningRule(this);
|
|
}
|
|
|
|
nsCSSPageRule::~nsCSSPageRule()
|
|
{
|
|
mDeclaration->SetOwningRule(nullptr);
|
|
if (mDOMDeclaration) {
|
|
mDOMDeclaration->DropReference();
|
|
}
|
|
}
|
|
|
|
/* virtual */ already_AddRefed<css::Rule>
|
|
nsCSSPageRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new nsCSSPageRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsCSSPageRule, dom::CSSPageRule)
|
|
NS_IMPL_RELEASE_INHERITED(nsCSSPageRule, dom::CSSPageRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSPageRule)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCSSPageRule,
|
|
dom::CSSPageRule)
|
|
if (tmp->mDOMDeclaration) {
|
|
tmp->mDOMDeclaration->DropReference();
|
|
tmp->mDOMDeclaration = nullptr;
|
|
}
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCSSPageRule,
|
|
dom::CSSPageRule)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMDeclaration)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
bool
|
|
nsCSSPageRule::IsCCLeaf() const
|
|
{
|
|
// Let's not worry about figuring out whether we're a leaf or not.
|
|
return false;
|
|
}
|
|
|
|
// QueryInterface implementation for nsCSSPageRule
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSPageRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSPageRule)
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsCSSPageRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString str;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
str.AppendLiteral(" ");
|
|
}
|
|
|
|
str.AppendLiteral("@page { ");
|
|
nsAutoString tmp;
|
|
mDeclaration->ToString(tmp);
|
|
AppendUTF16toUTF8(tmp, str);
|
|
str.AppendLiteral("}\n");
|
|
fprintf_stderr(out, "%s", str.get());
|
|
}
|
|
#endif
|
|
|
|
void
|
|
nsCSSPageRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AppendLiteral("@page { ");
|
|
nsAutoString tmp;
|
|
mDeclaration->ToString(tmp);
|
|
aCssText.Append(tmp);
|
|
aCssText.AppendLiteral(" }");
|
|
}
|
|
|
|
nsICSSDeclaration*
|
|
nsCSSPageRule::Style()
|
|
{
|
|
if (!mDOMDeclaration) {
|
|
mDOMDeclaration = new nsCSSPageStyleDeclaration(this);
|
|
}
|
|
return mDOMDeclaration;
|
|
}
|
|
|
|
void
|
|
nsCSSPageRule::ChangeDeclaration(css::Declaration* aDeclaration)
|
|
{
|
|
if (aDeclaration != mDeclaration) {
|
|
mDeclaration->SetOwningRule(nullptr);
|
|
mDeclaration = aDeclaration;
|
|
mDeclaration->SetOwningRule(this);
|
|
}
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->AsGecko()->SetModifiedByChildRule();
|
|
}
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
nsCSSPageRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
}
|
|
|
|
namespace mozilla {
|
|
|
|
CSSSupportsRule::CSSSupportsRule(bool aConditionMet,
|
|
const nsString& aCondition,
|
|
uint32_t aLineNumber, uint32_t aColumnNumber)
|
|
: dom::CSSSupportsRule(aLineNumber, aColumnNumber)
|
|
, mUseGroup(aConditionMet)
|
|
, mCondition(aCondition)
|
|
{
|
|
}
|
|
|
|
CSSSupportsRule::~CSSSupportsRule()
|
|
{
|
|
}
|
|
|
|
CSSSupportsRule::CSSSupportsRule(const CSSSupportsRule& aCopy)
|
|
: dom::CSSSupportsRule(aCopy),
|
|
mUseGroup(aCopy.mUseGroup),
|
|
mCondition(aCopy.mCondition)
|
|
{
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* virtual */ void
|
|
CSSSupportsRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsAutoCString indentStr;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
indentStr.AppendLiteral(" ");
|
|
}
|
|
|
|
fprintf_stderr(out, "%s@supports %s {\n",
|
|
indentStr.get(), NS_ConvertUTF16toUTF8(mCondition).get());
|
|
|
|
css::GroupRule::List(out, aIndent);
|
|
|
|
fprintf_stderr(out, "%s}\n", indentStr.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ already_AddRefed<mozilla::css::Rule>
|
|
CSSSupportsRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new CSSSupportsRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
/* virtual */ bool
|
|
CSSSupportsRule::UseForPresentation(nsPresContext* aPresContext,
|
|
nsMediaQueryResultCacheKey& aKey)
|
|
{
|
|
return mUseGroup;
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(mozilla::CSSSupportsRule, dom::CSSSupportsRule)
|
|
NS_IMPL_RELEASE_INHERITED(mozilla::CSSSupportsRule, dom::CSSSupportsRule)
|
|
|
|
// QueryInterface implementation for CSSSupportsRule
|
|
NS_INTERFACE_MAP_BEGIN(CSSSupportsRule)
|
|
NS_INTERFACE_MAP_END_INHERITING(dom::CSSSupportsRule)
|
|
|
|
void
|
|
CSSSupportsRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral("@supports ");
|
|
aCssText.Append(mCondition);
|
|
css::GroupRule::AppendRulesToCssText(aCssText);
|
|
}
|
|
|
|
// nsIDOMCSSConditionRule methods
|
|
NS_IMETHODIMP
|
|
CSSSupportsRule::GetConditionText(nsAString& aConditionText)
|
|
{
|
|
aConditionText.Assign(mCondition);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CSSSupportsRule::SetConditionText(const nsAString& aConditionText)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* virtual */ size_t
|
|
CSSSupportsRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += css::GroupRule::SizeOfExcludingThis(aMallocSizeOf);
|
|
n += mCondition.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
return n;
|
|
}
|
|
|
|
} // namespace mozilla
|