author | Brendan Dahl <bdahl@mozilla.com> |
Fri, 31 Aug 2012 14:21:28 -0700 | |
changeset 113332 | 2ea5d36b35a15f440c86bf825b1c3737234f4e59 |
parent 113331 | 31312fa1abdee6f8089c549f426602800ac73329 |
child 113333 | 3d61038df8830adbcb892d8a9de3ab35f4637f84 |
push id | 23869 |
push user | emorley@mozilla.com |
push date | Thu, 15 Nov 2012 16:18:16 +0000 |
treeherder | mozilla-central@a37525d304d9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dbaron |
bugs | 115199 |
milestone | 19.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -279,16 +279,17 @@ #include "nsIDOMCSSCharsetRule.h" #include "nsIDOMCSSImportRule.h" #include "nsIDOMCSSMediaRule.h" #include "nsIDOMCSSFontFaceRule.h" #include "nsIDOMCSSMozDocumentRule.h" #include "nsIDOMCSSSupportsRule.h" #include "nsIDOMMozCSSKeyframeRule.h" #include "nsIDOMMozCSSKeyframesRule.h" +#include "nsIDOMCSSPageRule.h" #include "nsIDOMCSSPrimitiveValue.h" #include "nsIDOMCSSStyleRule.h" #include "nsIDOMCSSStyleSheet.h" #include "nsDOMCSSValueList.h" #define MOZ_GENERATED_EVENTS_INCLUDES #include "GeneratedEvents.h" #undef MOZ_GENERATED_EVENTS_INCLUDES #include "nsIDOMDeviceMotionEvent.h" @@ -1610,16 +1611,19 @@ static nsDOMClassInfoData sClassInfoData NS_DEFINE_CLASSINFO_DATA(TouchEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) 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, DOM_DEFAULT_SCRIPTABLE_FLAGS | nsIXPCScriptable::WANT_ADDPROPERTY) NS_DEFINE_CLASSINFO_DATA(MutationRecord, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -4319,16 +4323,20 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule) 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 DOM_CLASSINFO_MAP_BEGIN(MutationObserver, nsIDOMMutationObserver) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMutationObserver) DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -473,16 +473,18 @@ DOMCI_CLASS(IDBOpenDBRequest) DOMCI_CLASS(Touch) DOMCI_CLASS(TouchList) DOMCI_CLASS(TouchEvent) DOMCI_CLASS(MozCSSKeyframeRule) DOMCI_CLASS(MozCSSKeyframesRule) +DOMCI_CLASS(CSSPageRule) + DOMCI_CLASS(MediaQueryList) DOMCI_CLASS(MutationObserver) DOMCI_CLASS(MutationRecord) #ifdef MOZ_B2G_RIL DOMCI_CLASS(Telephony) DOMCI_CLASS(TelephonyCall)
--- a/dom/interfaces/css/nsIDOMCSSPageRule.idl +++ b/dom/interfaces/css/nsIDOMCSSPageRule.idl @@ -1,15 +1,15 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ #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; };
--- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -395,22 +395,28 @@ protected: PRUnichar aStopChar); bool ParseSelectorGroup(nsCSSSelectorList*& aListHead); bool ParseSelector(nsCSSSelectorList* aList, PRUnichar aPrevCombinator); enum { eParseDeclaration_InBraces = 1 << 0, eParseDeclaration_AllowImportant = 1 << 1 }; - - css::Declaration* ParseDeclarationBlock(uint32_t aFlags); + enum nsCSSContextType { + eCSSContext_General, + eCSSContext_Page + }; + + 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); bool ParseSingleValueProperty(nsCSSValue& aValue, nsCSSProperty aPropID); enum PriorityParsingStatus { ePriority_None, @@ -2256,23 +2262,16 @@ CSSParserImpl::ParseFontDescriptor(nsCSS return false; aRule->SetDesc(descID, value); return true; } bool -CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData) -{ - // XXX not yet implemented - return false; -} - -bool CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData) { if (!GetToken(true)) { REPORT_UNEXPECTED_EOF(PEKeyframeNameEOF); return false; } if (mToken.mType != eCSSToken_Ident) { @@ -2298,30 +2297,49 @@ CSSParserImpl::ParseKeyframesRule(RuleAp SkipRuleSet(true); } } (*aAppendFunc)(rule, 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() { InfallibleTArray<float> selectorList; if (!ParseKeyframeSelectorList(selectorList)) { REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored); return nullptr; } // Ignore !important in keyframe rules uint32_t parseFlags = eParseDeclaration_InBraces; nsAutoPtr<css::Declaration> declaration(ParseDeclarationBlock(parseFlags)); if (!declaration) { - REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored); return nullptr; } // Takes ownership of declaration, and steals contents of selectorList. nsRefPtr<nsCSSKeyframeRule> rule = new nsCSSKeyframeRule(selectorList, declaration); return rule.forget(); @@ -3887,33 +3905,33 @@ CSSParserImpl::ParseSelector(nsCSSSelect selector->mClassList = pseudoElementArgs.forget(); selector->SetPseudoType(pseudoElementType); } return true; } css::Declaration* -CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags) +CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext) { bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0; if (checkForBraces) { if (!ExpectSymbol('{', true)) { REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart); OUTPUT_ERROR(); return nullptr; } } css::Declaration* declaration = new css::Declaration(); mData.AssertInitialState(); if (declaration) { for (;;) { bool changed; - if (!ParseDeclaration(declaration, aFlags, true, &changed)) { + if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) { if (!SkipDeclaration(checkForBraces)) { break; } if (checkForBraces) { if (ExpectSymbol('}', true)) { break; } } @@ -4294,18 +4312,22 @@ CSSParserImpl::ParseTreePseudoElement(ns #endif //---------------------------------------------------------------------- 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(); // Get property name nsCSSToken* tk = &mToken; nsAutoString propertyName; for (;;) { @@ -4339,17 +4361,19 @@ CSSParserImpl::ParseDeclaration(css::Dec // Not a declaration... UngetToken(); return false; } // 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() }; REPORT_UNEXPECTED_P(PEUnknownProperty, params); REPORT_UNEXPECTED(PEDeclDropped); OUTPUT_ERROR(); }
--- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1914,171 +1914,186 @@ CSS_PROP_LIST( kListStyleKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_SHORTHAND( margin, 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, margin_bottom, MarginBottom, 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, offsetof(nsStyleMargin, mMargin), eStyleAnimType_Sides_Bottom) 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( margin-end-value, margin_end_value, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) #endif CSS_PROP_SHORTHAND( margin-left, 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( margin-left-value, margin_left_value, MarginLeftValue, 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, offsetof(nsStyleMargin, mMargin), eStyleAnimType_Sides_Left) CSS_PROP_MARGIN( margin-left-ltr-source, margin_left_ltr_source, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_MARGIN( margin-left-rtl-source, margin_left_rtl_source, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) #endif CSS_PROP_SHORTHAND( margin-right, 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( margin-right-value, margin_right_value, MarginRightValue, 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, offsetof(nsStyleMargin, mMargin), eStyleAnimType_Sides_Right) CSS_PROP_MARGIN( margin-right-ltr-source, margin_right_ltr_source, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) CSS_PROP_MARGIN( margin-right-rtl-source, margin_right_rtl_source, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) #endif 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( margin-start-value, margin_start_value, 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, CSS_PROP_NO_OFFSET, eStyleAnimType_None) #endif CSS_PROP_MARGIN( margin-top, margin_top, MarginTop, 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, offsetof(nsStyleMargin, mMargin), eStyleAnimType_Sides_Top) CSS_PROP_CONTENT( marker-offset, marker_offset,
--- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -99,16 +99,19 @@ MOZ_STATIC_ASSERT((CSS_PROPERTY_PARSE_PR #define CSS_PROPERTY_UNITLESS_LENGTH_QUIRK (1<<16) // Is this property (which must be a shorthand) really an alias? #define CSS_PROPERTY_IS_ALIAS (1<<17) // 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. */ enum nsStyleAnimType { // requires a custom implementation in // nsStyleAnimation::ExtractComputedValue eStyleAnimType_Custom,
--- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -973,16 +973,17 @@ struct RuleCascadeData { PLDHashTable mAttributeSelectors; PLDHashTable mAnonBoxRules; #ifdef MOZ_XUL PLDHashTable mXULTreeRules; #endif nsTArray<nsFontFaceRuleContainer> mFontFaceRules; nsTArray<nsCSSKeyframesRule*> mKeyframesRules; + nsTArray<nsCSSPageRule*> mPageRules; // Looks up or creates the appropriate list in |mAttributeSelectors|. // Returns null only on allocation failure. nsTArray<nsCSSSelector*>* AttributeListFor(nsIAtom* aAttribute); nsMediaQueryResultCacheKey mCacheKey; RuleCascadeData* mNext; // for a different medium @@ -1023,16 +1024,17 @@ RuleCascadeData::SizeOfIncludingThis(nsM SizeOfRuleHashTableEntry, aMallocSizeOf); #ifdef MOZ_XUL n += PL_DHashTableSizeOfExcludingThis(&mXULTreeRules, SizeOfRuleHashTableEntry, aMallocSizeOf); #endif n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf); n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf); + n += mPageRules.SizeOfExcludingThis(aMallocSizeOf); return n; } nsTArray<nsCSSSelector*>* RuleCascadeData::AttributeListFor(nsIAtom* aAttribute) { AtomSelectorEntry *entry = @@ -2674,16 +2676,34 @@ nsCSSRuleProcessor::AppendKeyframesRules if (cascade) { if (!aArray.AppendElements(cascade->mKeyframesRules)) return false; } 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() { // We rely on our caller (perhaps indirectly) to do something that // will rebuild style data and the user font set (either // nsIPresShell::ReconstructStyleData or // nsPresContext::RebuildAllStyleData). RuleCascadeData *data = mRuleCascades; @@ -2972,21 +2992,23 @@ static PLDHashTableOps gRulesByWeightOps PL_DHashFinalizeStub, InitWeightEntry }; 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) { if (!PL_DHashTableInit(&mRulesByWeight, &gRulesByWeightOps, nullptr, sizeof(RuleByWeightEntry), 64)) mRulesByWeight.ops = nullptr; // Initialize our arena @@ -2999,32 +3021,34 @@ struct CascadeEnumData { if (mRulesByWeight.ops) PL_DHashTableFinish(&mRulesByWeight); PL_FinishArenaPool(&mArena); } nsPresContext* mPresContext; nsTArray<nsFontFaceRuleContainer>& mFontFaceRules; nsTArray<nsCSSKeyframesRule*>& mKeyframesRules; + nsTArray<nsCSSPageRule*>& mPageRules; nsMediaQueryResultCacheKey& mCacheKey; PLArenaPool mArena; // Hooray, a manual PLDHashTable since nsClassHashtable doesn't // provide a getter that gives me a *reference* to the value. PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists uint8_t mSheetType; }; /* * This enumerates style rules in a sheet (and recursively into any * grouping rules) in order to: * (1) add any style rules, in order, into data->mRulesByWeight (for * the primary CSS cascade), where they are separated by weight * 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) { CascadeEnumData* data = (CascadeEnumData*)aData; int32_t type = aRule->GetType(); if (css::Rule::STYLE_RULE == type) { @@ -3067,17 +3091,22 @@ CascadeRuleEnumFunc(css::Rule* aRule, vo } else if (css::Rule::KEYFRAMES_RULE == type) { nsCSSKeyframesRule *keyframesRule = static_cast<nsCSSKeyframesRule*>(aRule); if (!data->mKeyframesRules.AppendElement(keyframesRule)) { return false; } } - + else if (css::Rule::PAGE_RULE == type) { + nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule); + if (!data->mPageRules.AppendElement(pageRule)) { + return false; + } + } return true; } /* static */ bool nsCSSRuleProcessor::CascadeSheet(nsCSSStyleSheet* aSheet, CascadeEnumData* aData) { if (aSheet->IsApplicable() && aSheet->UseForPresentation(aData->mPresContext, aData->mCacheKey) && @@ -3168,16 +3197,17 @@ nsCSSRuleProcessor::RefreshRuleCascade(n if (mSheets.Length() != 0) { nsAutoPtr<RuleCascadeData> newCascade( new RuleCascadeData(aPresContext->Medium(), eCompatibility_NavQuirks == aPresContext->CompatibilityMode())); if (newCascade) { CascadeEnumData data(aPresContext, newCascade->mFontFaceRules, newCascade->mKeyframesRules, + newCascade->mPageRules, newCascade->mCacheKey, mSheetType); if (!data.mRulesByWeight.ops) return; /* out of memory */ for (uint32_t i = 0; i < mSheets.Length(); ++i) { if (!CascadeSheet(mSheets.ElementAt(i), &data)) return; /* out of memory */
--- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -116,16 +116,19 @@ public: // Append all the currently-active font face rules to aArray. Return // true for success and false for failure. bool AppendFontFaceRules(nsPresContext* aPresContext, nsTArray<nsFontFaceRuleContainer>& aArray); 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 " "clearing rule cascades"); } #endif #ifdef XP_WIN
--- a/layout/style/nsCSSRules.cpp +++ b/layout/style/nsCSSRules.cpp @@ -31,16 +31,17 @@ #include "nsStyleConsts.h" #include "nsError.h" #include "nsStyleUtil.h" #include "mozilla/css/Declaration.h" #include "nsCSSParser.h" #include "nsPrintfCString.h" #include "nsDOMClassInfoID.h" #include "mozilla/dom/CSSStyleDeclarationBinding.h" +#include "StyleRule.h" namespace css = mozilla::css; #define IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(class_, super_) \ /* virtual */ nsIDOMCSSRule* class_::GetDOMRule() \ { return this; } \ /* virtual */ nsIDOMCSSRule* class_::GetExistingDOMRule() \ { return this; } @@ -2321,16 +2322,222 @@ nsCSSKeyframesRule::SizeOfIncludingThis( // 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) + +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, const nsString& aCondition) : mUseGroup(aConditionMet), mCondition(aCondition) { }
--- a/layout/style/nsCSSRules.h +++ b/layout/style/nsCSSRules.h @@ -23,22 +23,18 @@ #include "nsICSSRuleList.h" #include "nsAutoPtr.h" #include "nsCSSProperty.h" #include "nsCSSValue.h" #include "nsIDOMCSSCharsetRule.h" #include "nsTArray.h" #include "nsDOMCSSDeclaration.h" #include "Declaration.h" - -namespace mozilla { -namespace css { -class StyleRule; -} -} +#include "nsIDOMCSSPageRule.h" +#include "StyleRule.h" class nsMediaList; namespace mozilla { namespace css { class MediaRule MOZ_FINAL : public GroupRule, public nsIDOMCSSMediaRule @@ -428,16 +424,89 @@ public: virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE; private: uint32_t FindRuleIndexForKey(const nsAString& aKey); 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, public nsIDOMCSSSupportsRule { public: CSSSupportsRule(bool aConditionMet, const nsString& aCondition); CSSSupportsRule(const CSSSupportsRule& aCopy);
--- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -1160,16 +1160,34 @@ nsStyleSet::ResolveAnonymousBoxStyle(nsI NS_PRECONDITION(isAnonBox, "Unexpected pseudo"); #endif nsRuleWalker ruleWalker(mRuleTree); AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker); 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, false, nullptr); } #ifdef MOZ_XUL already_AddRefed<nsStyleContext> @@ -1237,16 +1255,31 @@ nsStyleSet::AppendKeyframesRules(nsPresC nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*> (mRuleProcessors[gCSSSheetTypes[i]].get()); if (ruleProc && !ruleProc->AppendKeyframesRules(aPresContext, aArray)) return false; } 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) { mInShutdown = 1; mRoots.Clear(); // no longer valid, since we won't keep it up to date } void
--- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -24,16 +24,17 @@ #include "nsIStyleRule.h" #include "nsCSSPseudoElements.h" #include "nsCSSAnonBoxes.h" #include "mozilla/Attributes.h" class nsIURI; class nsCSSFontFaceRule; class nsCSSKeyframesRule; +class nsCSSPageRule; class nsRuleWalker; struct ElementDependentRuleProcessorData; struct TreeMatchContext; class nsEmptyStyleRule MOZ_FINAL : public nsIStyleRule { NS_DECL_ISUPPORTS virtual void MapRuleInfoInto(nsRuleData* aRuleData); @@ -147,16 +148,21 @@ class nsStyleSet bool AppendFontFaceRules(nsPresContext* aPresContext, nsTArray<nsFontFaceRuleContainer>& aArray); // Append all the currently-active keyframes rules to aArray. Return // true for success and false for failure. 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); // Free all of the data associated with this style set. void Shutdown(nsPresContext* aPresContext); // Notification that a style context is being destroyed.
--- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -182,16 +182,17 @@ MOCHITEST_FILES = test_acid3_test46.html ccd.sjs \ visited-pref-iframe.html \ visited-lying-inner.html \ visited_image_loading.sjs \ visited_image_loading_frame.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 \ test_bug795520.html \ viewport_units_iframe.html \ $(NULL) ifdef MOZ_FLEXBOX
new file mode 100644 --- /dev/null +++ b/layout/style/test/test_page_parser.html @@ -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>
--- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -188,16 +188,17 @@ display: block !important; background: white; box-shadow: 5px 5px 8px #202020; margin: 0.125in 0.25in; } *|*::-moz-pagecontent { display: block !important; + margin: auto; } *|*::-moz-pagebreak { display: block !important; } *|*::-moz-anonymous-positioned-block { display: block !important;