Bug 115199 - CSS2 @page rule style support. r=dbaron

This commit is contained in:
Brendan Dahl 2012-08-31 14:21:28 -07:00
parent 416d875170
commit ec5ca0d279
15 changed files with 549 additions and 38 deletions

View File

@ -285,6 +285,7 @@
#include "nsIDOMCSSSupportsRule.h"
#include "nsIDOMMozCSSKeyframeRule.h"
#include "nsIDOMMozCSSKeyframesRule.h"
#include "nsIDOMCSSPageRule.h"
#include "nsIDOMCSSPrimitiveValue.h"
#include "nsIDOMCSSStyleRule.h"
#include "nsIDOMCSSStyleSheet.h"
@ -1616,6 +1617,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MediaQueryList, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MutationObserver, nsDOMMutationObserverSH,
@ -4325,6 +4329,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MediaQueryList, nsIDOMMediaQueryList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMediaQueryList)
DOM_CLASSINFO_MAP_END

View File

@ -478,6 +478,8 @@ DOMCI_CLASS(TouchEvent)
DOMCI_CLASS(MozCSSKeyframeRule)
DOMCI_CLASS(MozCSSKeyframesRule)
DOMCI_CLASS(CSSPageRule)
DOMCI_CLASS(MediaQueryList)
DOMCI_CLASS(MutationObserver)

View File

@ -5,10 +5,10 @@
#include "nsIDOMCSSRule.idl"
[scriptable, uuid(a6cf90bd-15b3-11d2-932e-00805f8add32)]
[scriptable, uuid(6126024d-d716-4ad8-bc53-24dd6d5846b1)]
interface nsIDOMCSSPageRule : nsIDOMCSSRule
{
attribute DOMString selectorText;
//attribute DOMString selectorText;
// raises(DOMException) on setting
readonly attribute nsIDOMCSSStyleDeclaration style;

View File

@ -400,12 +400,18 @@ protected:
eParseDeclaration_InBraces = 1 << 0,
eParseDeclaration_AllowImportant = 1 << 1
};
enum nsCSSContextType {
eCSSContext_General,
eCSSContext_Page
};
css::Declaration* ParseDeclarationBlock(uint32_t aFlags);
css::Declaration* ParseDeclarationBlock(uint32_t aFlags,
nsCSSContextType aContext = eCSSContext_General);
bool ParseDeclaration(css::Declaration* aDeclaration,
uint32_t aFlags,
bool aMustCallValueAppended,
bool* aChanged);
bool* aChanged,
nsCSSContextType aContext = eCSSContext_General);
bool ParseProperty(nsCSSProperty aPropID);
bool ParsePropertyByFunction(nsCSSProperty aPropID);
@ -2260,13 +2266,6 @@ CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule* aRule)
}
bool
CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData)
{
// XXX not yet implemented
return false;
}
bool
CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData)
{
@ -2303,6 +2302,26 @@ CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData)
return true;
}
bool
CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData)
{
// TODO: There can be page selectors after @page such as ":first", ":left".
uint32_t parseFlags = eParseDeclaration_InBraces |
eParseDeclaration_AllowImportant;
nsAutoPtr<css::Declaration> declaration(
ParseDeclarationBlock(parseFlags,
eCSSContext_Page));
if (!declaration) {
return false;
}
// Takes ownership of declaration.
nsRefPtr<nsCSSPageRule> rule = new nsCSSPageRule(declaration);
(*aAppendFunc)(rule, aData);
return true;
}
already_AddRefed<nsCSSKeyframeRule>
CSSParserImpl::ParseKeyframeRule()
{
@ -2316,7 +2335,6 @@ CSSParserImpl::ParseKeyframeRule()
uint32_t parseFlags = eParseDeclaration_InBraces;
nsAutoPtr<css::Declaration> declaration(ParseDeclarationBlock(parseFlags));
if (!declaration) {
REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored);
return nullptr;
}
@ -3892,7 +3910,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
}
css::Declaration*
CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags)
CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext)
{
bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0;
@ -3908,7 +3926,7 @@ CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags)
if (declaration) {
for (;;) {
bool changed;
if (!ParseDeclaration(declaration, aFlags, true, &changed)) {
if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) {
if (!SkipDeclaration(checkForBraces)) {
break;
}
@ -4299,8 +4317,12 @@ bool
CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
uint32_t aFlags,
bool aMustCallValueAppended,
bool* aChanged)
bool* aChanged,
nsCSSContextType aContext)
{
NS_PRECONDITION(aContext == eCSSContext_General ||
aContext == eCSSContext_Page,
"Must be page or general context");
bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0;
mTempData.AssertInitialState();
@ -4344,7 +4366,9 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
// Map property name to its ID and then parse the property
nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName,
nsCSSProps::eEnabled);
if (eCSSProperty_UNKNOWN == propID) { // unknown property
if (eCSSProperty_UNKNOWN == propID ||
(aContext == nsCSSContextType::eCSSContext_Page &&
!nsCSSProps::PropHasFlags(propID, CSS_PROPERTY_APPLIES_TO_PAGE_RULE))) { // unknown property
if (!NonMozillaVendorIdentifier(propertyName)) {
const PRUnichar *params[] = {
propertyName.get()

View File

@ -1919,7 +1919,8 @@ CSS_PROP_SHORTHAND(
margin,
Margin,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"")
CSS_PROP_MARGIN(
margin-bottom,
@ -1928,7 +1929,8 @@ CSS_PROP_MARGIN(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC,
nullptr,
@ -1938,7 +1940,8 @@ CSS_PROP_SHORTHAND(
-moz-margin-end,
margin_end,
CSS_PROP_DOMPROP_PREFIXED(MarginEnd),
CSS_PROPERTY_PARSE_FUNCTION,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"")
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_MARGIN(
@ -1947,7 +1950,8 @@ CSS_PROP_MARGIN(
MarginEndValue,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_STORES_CALC,
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC, // for internal use
nullptr,
@ -1959,7 +1963,8 @@ CSS_PROP_SHORTHAND(
margin_left,
MarginLeft,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"")
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_MARGIN(
@ -1969,7 +1974,8 @@ CSS_PROP_MARGIN(
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_REPORT_OTHER_NAME |
CSS_PROPERTY_STORES_CALC,
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC, // for internal use
nullptr,
@ -1981,7 +1987,8 @@ CSS_PROP_MARGIN(
MarginLeftLTRSource,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_DIRECTIONAL_SOURCE,
CSS_PROPERTY_DIRECTIONAL_SOURCE |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
0,
kBoxPropSourceKTable,
@ -1993,7 +2000,8 @@ CSS_PROP_MARGIN(
MarginLeftRTLSource,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_DIRECTIONAL_SOURCE,
CSS_PROPERTY_DIRECTIONAL_SOURCE |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
0,
kBoxPropSourceKTable,
@ -2005,7 +2013,8 @@ CSS_PROP_SHORTHAND(
margin_right,
MarginRight,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"")
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_MARGIN(
@ -2015,7 +2024,8 @@ CSS_PROP_MARGIN(
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_REPORT_OTHER_NAME |
CSS_PROPERTY_STORES_CALC,
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC, // for internal use
nullptr,
@ -2027,7 +2037,8 @@ CSS_PROP_MARGIN(
MarginRightLTRSource,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_DIRECTIONAL_SOURCE,
CSS_PROPERTY_DIRECTIONAL_SOURCE |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
0,
kBoxPropSourceKTable,
@ -2039,7 +2050,8 @@ CSS_PROP_MARGIN(
MarginRightRTLSource,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_DIRECTIONAL_SOURCE,
CSS_PROPERTY_DIRECTIONAL_SOURCE |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
0,
kBoxPropSourceKTable,
@ -2050,7 +2062,8 @@ CSS_PROP_SHORTHAND(
-moz-margin-start,
margin_start,
CSS_PROP_DOMPROP_PREFIXED(MarginStart),
CSS_PROPERTY_PARSE_FUNCTION,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"")
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_MARGIN(
@ -2059,7 +2072,8 @@ CSS_PROP_MARGIN(
MarginStartValue,
CSS_PROPERTY_PARSE_INACCESSIBLE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_STORES_CALC,
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC, // for internal use
nullptr,
@ -2073,7 +2087,8 @@ CSS_PROP_MARGIN(
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
CSS_PROPERTY_STORES_CALC |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_APPLIES_TO_PAGE_RULE,
"",
VARIANT_AHLP | VARIANT_CALC,
nullptr,

View File

@ -104,6 +104,9 @@ MOZ_STATIC_ASSERT((CSS_PROPERTY_PARSE_PROPERTY_MASK &
// Does the property apply to ::-moz-placeholder?
#define CSS_PROPERTY_APPLIES_TO_PLACEHOLDER (1<<18)
// This property is allowed in an @page rule.
#define CSS_PROPERTY_APPLIES_TO_PAGE_RULE (1<<19)
/**
* Types of animatable values.
*/

View File

@ -979,6 +979,7 @@ struct RuleCascadeData {
nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
nsTArray<nsCSSPageRule*> mPageRules;
// Looks up or creates the appropriate list in |mAttributeSelectors|.
// Returns null only on allocation failure.
@ -1029,6 +1030,7 @@ RuleCascadeData::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf);
n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf);
n += mPageRules.SizeOfExcludingThis(aMallocSizeOf);
return n;
}
@ -2681,6 +2683,24 @@ nsCSSRuleProcessor::AppendKeyframesRules(
return true;
}
// Append all the currently-active page rules to aArray. Return
// true for success and false for failure.
bool
nsCSSRuleProcessor::AppendPageRules(
nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray)
{
RuleCascadeData* cascade = GetRuleCascade(aPresContext);
if (cascade) {
if (!aArray.AppendElements(cascade->mPageRules)) {
return false;
}
}
return true;
}
nsresult
nsCSSRuleProcessor::ClearRuleCascades()
{
@ -2979,11 +2999,13 @@ struct CascadeEnumData {
CascadeEnumData(nsPresContext* aPresContext,
nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
nsTArray<nsCSSPageRule*>& aPageRules,
nsMediaQueryResultCacheKey& aKey,
uint8_t aSheetType)
: mPresContext(aPresContext),
mFontFaceRules(aFontFaceRules),
mKeyframesRules(aKeyframesRules),
mPageRules(aPageRules),
mCacheKey(aKey),
mSheetType(aSheetType)
{
@ -3006,6 +3028,7 @@ struct CascadeEnumData {
nsPresContext* mPresContext;
nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
nsTArray<nsCSSPageRule*>& mPageRules;
nsMediaQueryResultCacheKey& mCacheKey;
PLArenaPool mArena;
// Hooray, a manual PLDHashTable since nsClassHashtable doesn't
@ -3022,6 +3045,7 @@ struct CascadeEnumData {
* but kept in order per-weight, and
* (2) add any @font-face rules, in order, into data->mFontFaceRules.
* (3) add any @keyframes rules, in order, into data->mKeyframesRules.
* (4) add any @page rules, in order, into data->mPageRules.
*/
static bool
CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
@ -3074,7 +3098,12 @@ CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
return false;
}
}
else if (css::Rule::PAGE_RULE == type) {
nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule);
if (!data->mPageRules.AppendElement(pageRule)) {
return false;
}
}
return true;
}
@ -3175,6 +3204,7 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
if (newCascade) {
CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
newCascade->mKeyframesRules,
newCascade->mPageRules,
newCascade->mCacheKey,
mSheetType);
if (!data.mRulesByWeight.ops)

View File

@ -121,6 +121,9 @@ public:
bool AppendKeyframesRules(nsPresContext* aPresContext,
nsTArray<nsCSSKeyframesRule*>& aArray);
bool AppendPageRules(nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray);
#ifdef DEBUG
void AssertQuirksChangeOK() {
NS_ASSERTION(!mRuleCascades, "can't toggle quirks style sheet without "

View File

@ -36,6 +36,7 @@
#include "nsPrintfCString.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
#include "StyleRule.h"
namespace css = mozilla::css;
@ -2326,6 +2327,212 @@ nsCSSKeyframesRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
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)
css::Declaration*
nsCSSPageStyleDeclaration::GetCSSDeclaration(bool aAllocate)
{
if (mRule) {
return mRule->Declaration();
} else {
return nullptr;
}
}
void
nsCSSPageStyleDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
{
GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
}
NS_IMETHODIMP
nsCSSPageStyleDeclaration::GetParentRule(nsIDOMCSSRule** aParent)
{
NS_ENSURE_ARG_POINTER(aParent);
NS_IF_ADDREF(*aParent = mRule);
return NS_OK;
}
nsresult
nsCSSPageStyleDeclaration::SetCSSDeclaration(css::Declaration* aDecl)
{
NS_ABORT_IF_FALSE(aDecl, "must be non-null");
mRule->ChangeDeclaration(aDecl);
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
: Rule(aCopy)
, mDeclaration(new css::Declaration(*aCopy.mDeclaration))
{
}
nsCSSPageRule::~nsCSSPageRule()
{
if (mDOMDeclaration) {
mDOMDeclaration->DropReference();
}
}
/* virtual */ already_AddRefed<css::Rule>
nsCSSPageRule::Clone() const
{
nsRefPtr<css::Rule> clone = new nsCSSPageRule(*this);
return clone.forget();
}
NS_IMPL_ADDREF(nsCSSPageRule)
NS_IMPL_RELEASE(nsCSSPageRule)
DOMCI_DATA(CSSPageRule, nsCSSPageRule)
// QueryInterface implementation for nsCSSPageRule
NS_INTERFACE_MAP_BEGIN(nsCSSPageRule)
NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSPageRule)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSPageRule)
NS_INTERFACE_MAP_END
IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(nsCSSPageRule, Rule)
#ifdef DEBUG
void
nsCSSPageRule::List(FILE* out, int32_t aIndent) const
{
// FIXME: WRITE ME
}
#endif
/* virtual */ int32_t
nsCSSPageRule::GetType() const
{
return Rule::PAGE_RULE;
}
NS_IMETHODIMP
nsCSSPageRule::GetType(uint16_t* aType)
{
*aType = nsIDOMCSSRule::PAGE_RULE;
return NS_OK;
}
NS_IMETHODIMP
nsCSSPageRule::GetCssText(nsAString& aCssText)
{
aCssText.AppendLiteral("@page { ");
nsAutoString tmp;
mDeclaration->ToString(tmp);
aCssText.Append(tmp);
aCssText.AppendLiteral(" }");
return NS_OK;
}
NS_IMETHODIMP
nsCSSPageRule::SetCssText(const nsAString& aCssText)
{
// FIXME: implement???
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCSSPageRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
{
return Rule::GetParentStyleSheet(aSheet);
}
NS_IMETHODIMP
nsCSSPageRule::GetParentRule(nsIDOMCSSRule** aParentRule)
{
return Rule::GetParentRule(aParentRule);
}
css::ImportantRule*
nsCSSPageRule::GetImportantRule()
{
if (!mDeclaration->HasImportantData()) {
return nullptr;
}
if (!mImportantRule) {
mImportantRule = new css::ImportantRule(mDeclaration);
}
return mImportantRule;
}
/* virtual */ void
nsCSSPageRule::MapRuleInfoInto(nsRuleData* aRuleData)
{
mDeclaration->MapNormalRuleInfoInto(aRuleData);
}
NS_IMETHODIMP
nsCSSPageRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
{
if (!mDOMDeclaration) {
mDOMDeclaration = new nsCSSPageStyleDeclaration(this);
}
NS_ADDREF(*aStyle = mDOMDeclaration);
return NS_OK;
}
void
nsCSSPageRule::ChangeDeclaration(css::Declaration* aDeclaration)
{
mImportantRule = nullptr;
mDeclaration = aDeclaration;
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
}
}
/* virtual */ size_t
nsCSSPageRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
return aMallocSizeOf(this);
}
namespace mozilla {
CSSSupportsRule::CSSSupportsRule(bool aConditionMet,

View File

@ -28,12 +28,8 @@
#include "nsTArray.h"
#include "nsDOMCSSDeclaration.h"
#include "Declaration.h"
namespace mozilla {
namespace css {
class StyleRule;
}
}
#include "nsIDOMCSSPageRule.h"
#include "StyleRule.h"
class nsMediaList;
@ -433,6 +429,79 @@ private:
nsString mName;
};
class nsCSSPageRule;
class nsCSSPageStyleDeclaration MOZ_FINAL : public nsDOMCSSDeclaration
{
public:
nsCSSPageStyleDeclaration(nsCSSPageRule *aRule);
virtual ~nsCSSPageStyleDeclaration();
NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) MOZ_OVERRIDE;
void DropReference() { mRule = nullptr; }
virtual mozilla::css::Declaration* GetCSSDeclaration(bool aAllocate) MOZ_OVERRIDE;
virtual nsresult SetCSSDeclaration(mozilla::css::Declaration* aDecl) MOZ_OVERRIDE;
virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) MOZ_OVERRIDE;
virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsCSSPageStyleDeclaration,
nsICSSDeclaration)
virtual nsINode *GetParentObject();
protected:
// This reference is not reference-counted. The rule object tells us
// when it's about to go away.
nsCSSPageRule *mRule;
};
class nsCSSPageRule MOZ_FINAL : public mozilla::css::Rule,
public nsIDOMCSSPageRule
{
public:
// WARNING: Steals the contents of aDeclaration
nsCSSPageRule(nsAutoPtr<mozilla::css::Declaration> aDeclaration)
: mDeclaration(aDeclaration),
mImportantRule(nullptr)
{
}
private:
nsCSSPageRule(const nsCSSPageRule& aCopy);
~nsCSSPageRule();
public:
NS_DECL_ISUPPORTS
// nsIStyleRule methods
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const;
#endif
// Rule methods
DECL_STYLE_RULE_INHERIT
virtual int32_t GetType() const;
virtual already_AddRefed<mozilla::css::Rule> Clone() const;
// nsIDOMCSSRule interface
NS_DECL_NSIDOMCSSRULE
// nsIDOMCSSPageRule interface
NS_DECL_NSIDOMCSSPAGERULE
mozilla::css::Declaration* Declaration() { return mDeclaration; }
void ChangeDeclaration(mozilla::css::Declaration* aDeclaration);
mozilla::css::ImportantRule* GetImportantRule();
virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
private:
nsAutoPtr<mozilla::css::Declaration> mDeclaration;
// lazily created when needed:
nsRefPtr<nsCSSPageStyleDeclaration> mDOMDeclaration;
nsRefPtr<mozilla::css::ImportantRule> mImportantRule;
};
namespace mozilla {
class CSSSupportsRule : public css::GroupRule,

View File

@ -1165,6 +1165,24 @@ nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
&ruleWalker);
if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
// Add any @page rules that are specified.
nsTArray<nsCSSPageRule*> rules;
nsTArray<css::ImportantRule*> importantRules;
nsPresContext* presContext = PresContext();
presContext->StyleSet()->AppendPageRules(presContext, rules);
for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
ruleWalker.Forward(rules[i]);
css::ImportantRule* importantRule = rules[i]->GetImportantRule();
if (importantRule) {
importantRules.AppendElement(importantRule);
}
}
for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
ruleWalker.Forward(importantRules[i]);
}
}
return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
false, false,
aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox,
@ -1242,6 +1260,21 @@ nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext,
return true;
}
bool
nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray)
{
NS_ENSURE_FALSE(mInShutdown, false);
for (uint32_t i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
(mRuleProcessors[gCSSSheetTypes[i]].get());
if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
return false;
}
return true;
}
void
nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
{

View File

@ -29,6 +29,7 @@
class nsIURI;
class nsCSSFontFaceRule;
class nsCSSKeyframesRule;
class nsCSSPageRule;
class nsRuleWalker;
struct RuleProcessorData;
struct TreeMatchContext;
@ -152,6 +153,11 @@ class nsStyleSet
bool AppendKeyframesRules(nsPresContext* aPresContext,
nsTArray<nsCSSKeyframesRule*>& aArray);
// Append all the currently-active page rules to aArray. Return
// true for success and false for failure.
bool AppendPageRules(nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray);
// Begin ignoring style context destruction, to avoid lots of unnecessary
// work on document teardown.
void BeginShutdown(nsPresContext* aPresContext);

View File

@ -187,6 +187,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
visited_image_loading_frame_empty.html \
test_load_events_on_stylesheets.html \
test_bug721136.html \
test_page_parser.html \
test_bug732153.html \
test_bug732209.html \
bug732209-css.sjs \

View File

@ -0,0 +1,109 @@
<!DOCTYPE HTML>
<html>
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=115199 -->
<head>
<meta charset="UTF-8">
<title>Test of @page parser</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<p>@page parsing (<a
target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=115199"
>bug 115199</a>)</p>
<pre id="display"></pre>
<style type="text/css" id="testbox"></style>
<script class="testbody" type="text/javascript">
function _(b) { return "@page { " + b + " }"; };
var testset = [
// CSS 2.1 only allows margin properties in the page rule.
// Check a bad property.
{ rule: "position: absolute;" },
// Check good properties.
// NOTE: The margin-*-value and margin-*-source properties are not really
// expected and will need to be removed once bug 241234 is addressed.
{ rule: _("margin: 2in;"), expected: {
"margin-top": "2in",
"margin-right-value": "2in",
"margin-bottom": "2in",
"margin-left-value": "2in",
"margin-left-ltr-source": "physical",
"margin-left-rtl-source": "physical",
"margin-right-ltr-source": "physical",
"margin-right-rtl-source": "physical"
}},
{ rule: _("margin-top: 2in;"), expected: {"margin-top": "2in"}},
{ rule: _("margin-left: 2in;"), expected: {
"margin-left-value": "2in",
"margin-left-ltr-source": "physical",
"margin-left-rtl-source": "physical",
}},
{ rule: _("margin-bottom: 2in;"), expected: {"margin-bottom": "2in"}},
{ rule: _("margin-right: 2in;"), expected: {
"margin-right-value": "2in",
"margin-right-ltr-source": "physical",
"margin-right-rtl-source": "physical",
}}
];
var display = document.getElementById("display");
var sheet = document.styleSheets[1];
for (var curTest = 0; curTest < testset.length; curTest++) {
try {
while(sheet.cssRules.length > 0)
sheet.deleteRule(0);
sheet.insertRule(testset[curTest].rule, 0);
} catch (e) {
ok(e.name == "SyntaxError"
&& e instanceof DOMException
&& e.code == DOMException.SYNTAX_ERR
&& !('expected' in testset[curTest]),
testset[curTest].rule + " syntax error thrown", e);
}
try {
if (testset[curTest].expected) {
is(sheet.cssRules.length, 1,
testset[curTest].rule + " rule count");
is(sheet.cssRules[0].type, CSSRule.PAGE_RULE,
testset[curTest].rule + " rule type");
var expected = testset[curTest].expected;
var s = sheet.cssRules[0].style;
var n = 0;
// everything is set that should be
for (var name in expected) {
is(s.getPropertyValue(name), expected[name],
testset[curTest].rule + " (prop " + name + ")");
n++;
}
// nothing else is set
is(s.length, n, testset[curTest].rule + "prop count");
for (var i = 0; i < s.length; i++) {
ok(s[i] in expected, testset[curTest].rule,
"Unexpected item #" + i + ": " + s[i]);
}
} else {
if (sheet.cssRules.length == 0) {
is(sheet.cssRules.length, 0,
testset[curTest].rule + " rule count (0)");
} else {
is(sheet.cssRules.length, 1,
testset[curTest].rule + " rule count (1 non-page)");
isnot(sheet.cssRules[0].type, CSSRule.PAGE_RULE,
testset[curTest].rule + " rule type (1 non-page)");
}
}
} catch (e) {
ok(false, testset[curTest].rule, "During test: " + e);
}
}
</script>
</body>
</html>

View File

@ -193,6 +193,7 @@
*|*::-moz-pagecontent {
display: block !important;
margin: auto;
}
*|*::-moz-pagebreak {