mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1202095 - re-use @imported style sheets from inIDOMUtils.parseStyleSheet. r=heycam
This commit is contained in:
parent
0c3b5fe361
commit
b383334103
@ -1259,7 +1259,7 @@ inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
|
||||
nsRefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
|
||||
NS_ENSURE_ARG_POINTER(sheet);
|
||||
|
||||
return sheet->ParseSheet(aInput);
|
||||
return sheet->ReparseSheet(aInput);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
7
layout/inspector/tests/bug1202095-2.css
Normal file
7
layout/inspector/tests/bug1202095-2.css
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Bug 1202095 - parseStyleSheet should not re-load @imports
|
||||
*/
|
||||
|
||||
body {
|
||||
color: chartreuse;
|
||||
}
|
7
layout/inspector/tests/bug1202095.css
Normal file
7
layout/inspector/tests/bug1202095.css
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Bug 1202095 - parseStyleSheet should not re-load @imports
|
||||
*/
|
||||
|
||||
body {
|
||||
background-color: purple;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
bug1202095.css
|
||||
bug1202095-2.css
|
||||
bug856317.css
|
||||
file_bug522601.html
|
||||
|
||||
@ -22,4 +24,5 @@ support-files =
|
||||
[test_is_valid_css_color.html]
|
||||
[test_isinheritableproperty.html]
|
||||
[test_parseStyleSheet.html]
|
||||
[test_parseStyleSheetImport.html]
|
||||
[test_selectormatcheselement.html]
|
||||
|
83
layout/inspector/tests/test_parseStyleSheetImport.html
Normal file
83
layout/inspector/tests/test_parseStyleSheetImport.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1202095
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1202095</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
@import url('bug1202095.css');
|
||||
@import url('bug1202095-2.css');
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
var domUtils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(SpecialPowers.Ci.inIDOMUtils);
|
||||
|
||||
function do_test() {
|
||||
var sheet = document.styleSheets[1];
|
||||
var importRule = sheet.cssRules[0];
|
||||
is(importRule.type, SpecialPowers.Ci.nsIDOMCSSRule.IMPORT_RULE,
|
||||
"initial sheet has @import rule");
|
||||
|
||||
var importedSheet = importRule.styleSheet;
|
||||
importedSheet.deleteRule(0);
|
||||
is(importedSheet.cssRules.length, 0, "imported sheet now has no rules");
|
||||
|
||||
// "suffixed" refers to the "-2".
|
||||
var suffixedSheet = sheet.cssRules[1].styleSheet;
|
||||
domUtils.parseStyleSheet(suffixedSheet, "");
|
||||
is(suffixedSheet.cssRules.length, 0, "second imported sheet now has no rules");
|
||||
|
||||
// Re-parse the style sheet, preserving the imports.
|
||||
domUtils.parseStyleSheet(sheet, "@import url('bug1202095.css');" +
|
||||
"@import url('bug1202095-2.css');");
|
||||
is(sheet.cssRules[0].type, SpecialPowers.Ci.nsIDOMCSSRule.IMPORT_RULE,
|
||||
"re-parsed sheet has @import rule");
|
||||
is(sheet.cssRules[0].styleSheet, importedSheet,
|
||||
"imported sheet has not changed");
|
||||
is(sheet.cssRules[1].styleSheet, suffixedSheet,
|
||||
"second imported sheet has not changed");
|
||||
|
||||
// Re-parse the style sheet, preserving both imports, but changing
|
||||
// the order.
|
||||
domUtils.parseStyleSheet(sheet, "@import url('bug1202095-2.css');" +
|
||||
"@import url('bug1202095.css');");
|
||||
is(sheet.cssRules[0].styleSheet, suffixedSheet,
|
||||
"reordering preserved suffixed style sheet");
|
||||
is(sheet.cssRules[1].styleSheet, importedSheet,
|
||||
"reordering preserved unsuffixed style sheet");
|
||||
|
||||
// Re-parse the style sheet, removing the imports.
|
||||
domUtils.parseStyleSheet(sheet, "");
|
||||
is(sheet.cssRules.length, 0, "style sheet now has no rules");
|
||||
|
||||
// Re-parse the style sheet, adding one import back. This should
|
||||
// not allow reuse.
|
||||
domUtils.parseStyleSheet(sheet, "@import url('bug1202095.css');");
|
||||
is(sheet.cssRules[0].type, SpecialPowers.Ci.nsIDOMCSSRule.IMPORT_RULE,
|
||||
"re-re-re-parsed sheet has @import rule");
|
||||
isnot(sheet.cssRules[0].styleSheet, importedSheet,
|
||||
"imported sheet has changed now");
|
||||
|
||||
// Re-parse the style sheet, importing the same URL twice.
|
||||
// The style sheet should be reused once, but not two times.
|
||||
importedSheet = sheet.cssRules[0].styleSheet;
|
||||
domUtils.parseStyleSheet(sheet, "@import url('bug1202095.css');" +
|
||||
"@import url('bug1202095.css');");
|
||||
is(sheet.cssRules[0].styleSheet, importedSheet,
|
||||
"first imported sheet is reused");
|
||||
isnot(sheet.cssRules[1].styleSheet, importedSheet,
|
||||
"second imported sheet is reused");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(do_test);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -2268,7 +2268,7 @@ CSSStyleSheet::StyleSheetLoaded(CSSStyleSheet* aSheet,
|
||||
}
|
||||
|
||||
nsresult
|
||||
CSSStyleSheet::ParseSheet(const nsAString& aInput)
|
||||
CSSStyleSheet::ReparseSheet(const nsAString& aInput)
|
||||
{
|
||||
// Not doing this if the sheet is not complete!
|
||||
if (!mInner->mComplete) {
|
||||
@ -2290,21 +2290,37 @@ CSSStyleSheet::ParseSheet(const nsAString& aInput)
|
||||
WillDirty();
|
||||
|
||||
// detach existing rules (including child sheets via import rules)
|
||||
css::LoaderReusableStyleSheets reusableSheets;
|
||||
int ruleCount;
|
||||
while ((ruleCount = mInner->mOrderedRules.Count()) != 0) {
|
||||
nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(ruleCount - 1);
|
||||
mInner->mOrderedRules.RemoveObjectAt(ruleCount - 1);
|
||||
rule->SetStyleSheet(nullptr);
|
||||
if (rule->GetType() == css::Rule::IMPORT_RULE) {
|
||||
nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(rule));
|
||||
NS_ASSERTION(importRule, "GetType lied");
|
||||
|
||||
nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
|
||||
importRule->GetStyleSheet(getter_AddRefs(childSheet));
|
||||
|
||||
nsRefPtr<CSSStyleSheet> cssSheet = do_QueryObject(childSheet);
|
||||
if (cssSheet && cssSheet->GetOriginalURI()) {
|
||||
reusableSheets.AddReusableSheet(cssSheet);
|
||||
}
|
||||
}
|
||||
if (mDocument) {
|
||||
mDocument->StyleRuleRemoved(this, rule);
|
||||
}
|
||||
}
|
||||
|
||||
// nuke child sheets list and current namespace map
|
||||
for (CSSStyleSheet* child = mInner->mFirstChild; child; child = child->mNext) {
|
||||
for (CSSStyleSheet* child = mInner->mFirstChild; child; ) {
|
||||
NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
|
||||
CSSStyleSheet* next = child->mNext;
|
||||
child->mParent = nullptr;
|
||||
child->mDocument = nullptr;
|
||||
child->mNext = nullptr;
|
||||
child = next;
|
||||
}
|
||||
mInner->mFirstChild = nullptr;
|
||||
mInner->mNameSpaceMap = nullptr;
|
||||
@ -2323,7 +2339,7 @@ CSSStyleSheet::ParseSheet(const nsAString& aInput)
|
||||
nsCSSParser parser(loader, this);
|
||||
nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
|
||||
mInner->mPrincipal, lineNumber,
|
||||
allowUnsafeRules);
|
||||
allowUnsafeRules, &reusableSheets);
|
||||
DidDirty(); // we are always 'dirty' here since we always remove rules first
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -242,7 +242,7 @@ public:
|
||||
bool UseForPresentation(nsPresContext* aPresContext,
|
||||
nsMediaQueryResultCacheKey& aKey) const;
|
||||
|
||||
nsresult ParseSheet(const nsAString& aInput);
|
||||
nsresult ReparseSheet(const nsAString& aInput);
|
||||
|
||||
void SetInRuleProcessorCache() { mInRuleProcessorCache = true; }
|
||||
|
||||
|
@ -507,6 +507,30 @@ SheetLoadData::ScheduleLoadEventIfNeeded(nsresult aStatus)
|
||||
}
|
||||
}
|
||||
|
||||
/*********************
|
||||
* Style sheet reuse *
|
||||
*********************/
|
||||
|
||||
bool
|
||||
LoaderReusableStyleSheets::FindReusableStyleSheet(nsIURI* aURL,
|
||||
nsRefPtr<CSSStyleSheet>& aResult)
|
||||
{
|
||||
MOZ_ASSERT(aURL);
|
||||
for (size_t i = mReusableSheets.Length(); i > 0; --i) {
|
||||
size_t index = i - 1;
|
||||
bool sameURI;
|
||||
MOZ_ASSERT(mReusableSheets[index]->GetOriginalURI());
|
||||
nsresult rv = aURL->Equals(mReusableSheets[index]->GetOriginalURI(),
|
||||
&sameURI);
|
||||
if (!NS_FAILED(rv) && sameURI) {
|
||||
aResult = mReusableSheets[index];
|
||||
mReusableSheets.RemoveElementAt(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Loader Implementation *
|
||||
*************************/
|
||||
@ -2151,7 +2175,8 @@ nsresult
|
||||
Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
|
||||
nsIURI* aURL,
|
||||
nsMediaList* aMedia,
|
||||
ImportRule* aParentRule)
|
||||
ImportRule* aParentRule,
|
||||
LoaderReusableStyleSheets* aReusableSheets)
|
||||
{
|
||||
LOG(("css::Loader::LoadChildSheet"));
|
||||
NS_PRECONDITION(aURL, "Must have a URI to load");
|
||||
@ -2220,18 +2245,23 @@ Loader::LoadChildSheet(CSSStyleSheet* aParentSheet,
|
||||
// Now that we know it's safe to load this (passes security check and not a
|
||||
// loop) do so.
|
||||
nsRefPtr<CSSStyleSheet> sheet;
|
||||
bool isAlternate;
|
||||
StyleSheetState state;
|
||||
const nsSubstring& empty = EmptyString();
|
||||
// For now, use CORS_NONE for child sheets
|
||||
rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
|
||||
aParentSheet->GetReferrerPolicy(),
|
||||
EmptyString(), // integrity is only checked on main sheet
|
||||
parentData ? parentData->mSyncLoad : false,
|
||||
false, empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
|
||||
aParentRule->SetSheet(sheet);
|
||||
state = eSheetComplete;
|
||||
} else {
|
||||
bool isAlternate;
|
||||
const nsSubstring& empty = EmptyString();
|
||||
// For now, use CORS_NONE for child sheets
|
||||
rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
|
||||
aParentSheet->GetReferrerPolicy(),
|
||||
EmptyString(), // integrity is only checked on main sheet
|
||||
parentData ? parentData->mSyncLoad : false,
|
||||
false, empty, state, &isAlternate, getter_AddRefs(sheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
|
||||
PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
|
||||
}
|
||||
|
||||
rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsURIHashKey.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/CSSStyleSheet.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
@ -30,7 +31,6 @@ class nsMediaList;
|
||||
class nsIStyleSheetLinkingElement;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
@ -131,6 +131,47 @@ namespace css {
|
||||
class SheetLoadData;
|
||||
class ImportRule;
|
||||
|
||||
/*********************
|
||||
* Style sheet reuse *
|
||||
*********************/
|
||||
|
||||
class MOZ_RAII LoaderReusableStyleSheets
|
||||
{
|
||||
public:
|
||||
LoaderReusableStyleSheets()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a reusable sheet (see AddReusableSheet) matching the
|
||||
* given URL. If found, set aResult, remove the reused sheet from
|
||||
* the internal list, and return true. If not found, return false;
|
||||
* in this case, aResult is not modified.
|
||||
*
|
||||
* @param aURL the url to match
|
||||
* @param aResult [out] the style sheet which can be reused
|
||||
*/
|
||||
bool FindReusableStyleSheet(nsIURI* aURL, nsRefPtr<CSSStyleSheet>& aResult);
|
||||
|
||||
/**
|
||||
* Indicate that a certain style sheet is available for reuse if its
|
||||
* URI matches the URI of an @import. Sheets should be added in the
|
||||
* opposite order in which they are intended to be reused.
|
||||
*
|
||||
* @param aSheet the sheet which can be reused
|
||||
*/
|
||||
void AddReusableSheet(CSSStyleSheet* aSheet) {
|
||||
mReusableSheets.AppendElement(aSheet);
|
||||
}
|
||||
|
||||
private:
|
||||
LoaderReusableStyleSheets(const LoaderReusableStyleSheets&) = delete;
|
||||
LoaderReusableStyleSheets& operator=(const LoaderReusableStyleSheets&) = delete;
|
||||
|
||||
// The sheets that can be reused.
|
||||
nsTArray<nsRefPtr<CSSStyleSheet>> mReusableSheets;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Enum that describes the state of the sheet returned by CreateSheet. *
|
||||
***********************************************************************/
|
||||
@ -242,11 +283,14 @@ public:
|
||||
* @param aMedia the already-parsed media list for the child sheet
|
||||
* @param aRule the @import rule importing this child. This is used to
|
||||
* properly order the child sheet list of aParentSheet.
|
||||
* @param aSavedSheets any saved style sheets which could be reused
|
||||
* for this load
|
||||
*/
|
||||
nsresult LoadChildSheet(CSSStyleSheet* aParentSheet,
|
||||
nsIURI* aURL,
|
||||
nsMediaList* aMedia,
|
||||
ImportRule* aRule);
|
||||
ImportRule* aRule,
|
||||
LoaderReusableStyleSheets* aSavedSheets);
|
||||
|
||||
/**
|
||||
* Synchronously load and return the stylesheet at aURL. Any child sheets
|
||||
|
@ -129,7 +129,8 @@ public:
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber,
|
||||
bool aAllowUnsafeRules);
|
||||
bool aAllowUnsafeRules,
|
||||
LoaderReusableStyleSheets* aReusableSheets);
|
||||
|
||||
nsresult ParseStyleAttribute(const nsAString& aAttributeValue,
|
||||
nsIURI* aDocURL,
|
||||
@ -1174,6 +1175,9 @@ protected:
|
||||
// Used for @import rules
|
||||
mozilla::css::Loader* mChildLoader; // not ref counted, it owns us
|
||||
|
||||
// Any sheets we may reuse when parsing an @import.
|
||||
LoaderReusableStyleSheets* mReusableSheets;
|
||||
|
||||
// Sheet section we're in. This is used to enforce correct ordering of the
|
||||
// various rule types (eg the fact that a @charset rule must come before
|
||||
// anything else). Note that there are checks of similar things in various
|
||||
@ -1319,6 +1323,7 @@ CSSParserImpl::CSSParserImpl()
|
||||
mScanner(nullptr),
|
||||
mReporter(nullptr),
|
||||
mChildLoader(nullptr),
|
||||
mReusableSheets(nullptr),
|
||||
mSection(eCSSSection_Charset),
|
||||
mNameSpaceMap(nullptr),
|
||||
mHavePushBack(false),
|
||||
@ -1431,7 +1436,8 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber,
|
||||
bool aAllowUnsafeRules)
|
||||
bool aAllowUnsafeRules,
|
||||
LoaderReusableStyleSheets* aReusableSheets)
|
||||
{
|
||||
NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
|
||||
NS_PRECONDITION(aBaseURI, "need base URI");
|
||||
@ -1477,6 +1483,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
|
||||
}
|
||||
|
||||
mUnsafeRulesEnabled = aAllowUnsafeRules;
|
||||
mReusableSheets = aReusableSheets;
|
||||
|
||||
nsCSSToken* tk = &mToken;
|
||||
for (;;) {
|
||||
@ -1500,6 +1507,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
|
||||
ReleaseScanner();
|
||||
|
||||
mUnsafeRulesEnabled = false;
|
||||
mReusableSheets = nullptr;
|
||||
|
||||
// XXX check for low level errors
|
||||
return NS_OK;
|
||||
@ -3440,7 +3448,7 @@ CSSParserImpl::ProcessImport(const nsString& aURLSpec,
|
||||
}
|
||||
|
||||
if (mChildLoader) {
|
||||
mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule);
|
||||
mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule, mReusableSheets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15785,11 +15793,12 @@ nsCSSParser::ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber,
|
||||
bool aAllowUnsafeRules)
|
||||
bool aAllowUnsafeRules,
|
||||
LoaderReusableStyleSheets* aReusableSheets)
|
||||
{
|
||||
return static_cast<CSSParserImpl*>(mImpl)->
|
||||
ParseSheet(aInput, aSheetURI, aBaseURI, aSheetPrincipal, aLineNumber,
|
||||
aAllowUnsafeRules);
|
||||
aAllowUnsafeRules, aReusableSheets);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -33,6 +33,7 @@ namespace css {
|
||||
class Rule;
|
||||
class Declaration;
|
||||
class Loader;
|
||||
class LoaderReusableStyleSheets;
|
||||
class StyleRule;
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
@ -79,13 +80,17 @@ public:
|
||||
* @param aLineNumber the line number of the first line of the sheet.
|
||||
* @param aAllowUnsafeRules see aEnableUnsafeRules in
|
||||
* mozilla::css::Loader::LoadSheetSync
|
||||
* @param aReusableSheets style sheets that can be reused by an @import.
|
||||
* This can be nullptr.
|
||||
*/
|
||||
nsresult ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aSheetURL,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber,
|
||||
bool aAllowUnsafeRules);
|
||||
bool aAllowUnsafeRules,
|
||||
mozilla::css::LoaderReusableStyleSheets* aReusableSheets =
|
||||
nullptr);
|
||||
|
||||
// Parse HTML style attribute or its equivalent in other markup
|
||||
// languages. aBaseURL is the base url to use for relative links in
|
||||
|
Loading…
Reference in New Issue
Block a user