Bug 800983. Expose a getter for default computed style. r=dbaron

An alternative implementation strategy is to add "default-only"
versions of ResolveStyleFor and ResolvePseudoElementStyle and then
modify FileRules to support those, or use a cut-down custom version of
FileRules for them.  That would be faster, but more complicated on the
style set side.  We can always make that switch if we need to, I guess.
This commit is contained in:
Boris Zbarsky 2012-10-17 17:01:56 -04:00
parent 194968b6cb
commit 611fe536d0
10 changed files with 168 additions and 31 deletions

View File

@ -2604,8 +2604,6 @@ CanvasRenderingContext2D::SetFont(const nsAString& font,
}
nsIDocument* document = presShell->GetDocument();
nsCOMArray<nsIStyleRule> rules;
nsRefPtr<css::StyleRule> rule;
error = CreateFontStyleRule(font, document, getter_AddRefs(rule));
@ -2629,7 +2627,8 @@ CanvasRenderingContext2D::SetFont(const nsAString& font,
return;
}
rules.AppendObject(rule);
nsTArray< nsCOMPtr<nsIStyleRule> > rules;
rules.AppendElement(rule);
nsStyleSet* styleSet = presShell->StyleSet();
@ -2654,8 +2653,8 @@ CanvasRenderingContext2D::SetFont(const nsAString& font,
return;
}
nsCOMArray<nsIStyleRule> parentRules;
parentRules.AppendObject(parentRule);
nsTArray< nsCOMPtr<nsIStyleRule> > parentRules;
parentRules.AppendElement(parentRule);
parentContext = styleSet->ResolveStyleForRules(nullptr, parentRules);
}

View File

@ -8267,7 +8267,25 @@ nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
const nsAString& aPseudoElt,
nsIDOMCSSStyleDeclaration** aReturn)
{
FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
return GetComputedStyleHelper(aElt, aPseudoElt, false, aReturn);
}
NS_IMETHODIMP
nsGlobalWindow::GetDefaultComputedStyle(nsIDOMElement* aElt,
const nsAString& aPseudoElt,
nsIDOMCSSStyleDeclaration** aReturn)
{
return GetComputedStyleHelper(aElt, aPseudoElt, true, aReturn);
}
nsresult
nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
const nsAString& aPseudoElt,
bool aDefaultStylesOnly,
nsIDOMCSSStyleDeclaration** aReturn)
{
FORWARD_TO_OUTER(GetComputedStyleHelper, (aElt, aPseudoElt,
aDefaultStylesOnly, aReturn),
NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_ARG_POINTER(aReturn);
@ -8310,7 +8328,9 @@ nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
nsRefPtr<nsComputedDOMStyle> compStyle =
NS_NewComputedDOMStyle(element, aPseudoElt, presShell);
NS_NewComputedDOMStyle(element, aPseudoElt, presShell,
aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
nsComputedDOMStyle::eAll);
*aReturn = compStyle.forget().get();

View File

@ -932,6 +932,12 @@ protected:
// Outer windows only.
nsDOMWindowList* GetWindowList();
// Helper for getComputedStyle and getDefaultComputedStyle
nsresult GetComputedStyleHelper(nsIDOMElement* aElt,
const nsAString& aPseudoElt,
bool aDefaultStylesOnly,
nsIDOMCSSStyleDeclaration** aReturn);
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those

View File

@ -32,7 +32,7 @@ interface nsIDOMMozURLProperty : nsISupports
* @see <http://www.whatwg.org/html/#window>
*/
[scriptable, uuid(25404a1b-6c73-4850-af95-69aa095c8ad0)]
[scriptable, uuid(43933989-912e-4b6a-b889-3c9fc9dd9ed4)]
interface nsIDOMWindow : nsISupports
{
// the current browsing context
@ -316,6 +316,8 @@ interface nsIDOMWindow : nsISupports
*/
nsIDOMCSSStyleDeclaration getComputedStyle(in nsIDOMElement elt,
[optional] in DOMString pseudoElt);
nsIDOMCSSStyleDeclaration getDefaultComputedStyle(in nsIDOMElement elt,
[optional] in DOMString pseudoElt);
// Mozilla extensions

View File

@ -64,7 +64,8 @@ static nsComputedDOMStyle *sCachedComputedDOMStyle;
already_AddRefed<nsComputedDOMStyle>
NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
nsIPresShell* aPresShell)
nsIPresShell* aPresShell,
nsComputedDOMStyle::StyleType aStyleType)
{
nsRefPtr<nsComputedDOMStyle> computedStyle;
if (sCachedComputedDOMStyle) {
@ -73,13 +74,14 @@ NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
// Oh yeah baby, placement new!
computedStyle = new (sCachedComputedDOMStyle)
nsComputedDOMStyle(aElement, aPseudoElt, aPresShell);
nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, aStyleType);
sCachedComputedDOMStyle = nullptr;
} else {
// No nsComputedDOMStyle cached, create a new one.
computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell);
computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell,
aStyleType);
}
return computedStyle.forget();
@ -95,9 +97,11 @@ GetContainingBlockFor(nsIFrame* aFrame) {
nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell)
nsIPresShell* aPresShell,
StyleType aStyleType)
: mDocumentWeak(nullptr), mOuterFrame(nullptr),
mInnerFrame(nullptr), mPresShell(nullptr),
mStyleType(aStyleType),
mExposeVisitedStyle(false)
{
MOZ_ASSERT(aElement && aPresShell);
@ -268,7 +272,8 @@ nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
already_AddRefed<nsStyleContext>
nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell)
nsIPresShell* aPresShell,
StyleType aStyleType)
{
// If the content has a pres shell, we must use it. Otherwise we'd
// potentially mix rule trees by using the wrong pres shell's style
@ -284,14 +289,16 @@ nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
presShell->FlushPendingNotifications(Flush_Style);
return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell);
return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
aStyleType);
}
/* static */
already_AddRefed<nsStyleContext>
nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell)
nsIPresShell* aPresShell,
StyleType aStyleType)
{
NS_ABORT_IF_FALSE(aElement, "NULL element");
// If the content has a pres shell, we must use it. Otherwise we'd
@ -306,7 +313,7 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
return nullptr;
}
if (!aPseudo) {
if (!aPseudo && aStyleType == eAll) {
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
nsStyleContext* result =
@ -322,14 +329,15 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
}
}
// No frame has been created or we have a pseudo, so resolve the
// style ourselves
// No frame has been created, or we have a pseudo, or we're looking
// for the default style, so resolve the style ourselves.
nsRefPtr<nsStyleContext> parentContext;
nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
// Don't resolve parent context for document fragments.
if (parent && parent->IsElement())
parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
nullptr, presShell);
nullptr, presShell,
aStyleType);
nsPresContext *presContext = presShell->GetPresContext();
if (!presContext)
@ -337,15 +345,42 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
nsStyleSet *styleSet = presShell->StyleSet();
nsRefPtr<nsStyleContext> sc;
if (aPseudo) {
nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
return nullptr;
}
return styleSet->ResolvePseudoElementStyle(aElement, type, parentContext);
sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext);
} else {
sc = styleSet->ResolveStyleFor(aElement, parentContext);
}
return styleSet->ResolveStyleFor(aElement, parentContext);
if (aStyleType == eDefaultOnly) {
// We really only want the user and UA rules. Filter out the other ones.
nsTArray< nsCOMPtr<nsIStyleRule> > rules;
for (nsRuleNode* ruleNode = sc->GetRuleNode();
!ruleNode->IsRoot();
ruleNode = ruleNode->GetParent()) {
if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet ||
ruleNode->GetLevel() == nsStyleSet::eUserSheet) {
rules.AppendElement(ruleNode->GetRule());
}
}
// We want to build a list of user/ua rules that is in order from least to
// most important, so we have to reverse the list.
// Integer division to get "stop" is purposeful here: if length is odd, we
// don't have to do anything with the middle element of the array.
for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
i < stop; ++i) {
rules[i].swap(rules[length - i - 1]);
}
sc = styleSet->ResolveStyleForRules(parentContext, rules);
}
return sc.forget();
}
/* static */
@ -454,7 +489,7 @@ nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName,
NS_ENSURE_TRUE(mPresShell && mPresShell->GetPresContext(),
NS_ERROR_NOT_AVAILABLE);
if (!mPseudo) {
if (!mPseudo && mStyleType == eAll) {
mOuterFrame = mContent->GetPrimaryFrame();
mInnerFrame = mOuterFrame;
if (mOuterFrame) {
@ -495,7 +530,8 @@ nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName,
mStyleContextHolder =
nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(),
mPseudo,
mPresShell);
mPresShell,
mStyleType);
NS_ENSURE_TRUE(mStyleContextHolder, NS_ERROR_OUT_OF_MEMORY);
NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(),
"should not have pseudo-element data");

View File

@ -38,9 +38,15 @@ public:
NS_DECL_NSIDOMCSSSTYLEDECLARATION
virtual void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName);
enum StyleType {
eDefaultOnly, // Only includes UA and user sheets
eAll // Includes all stylesheets
};
nsComputedDOMStyle(mozilla::dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell);
nsIPresShell* aPresShell,
StyleType aStyleType);
virtual ~nsComputedDOMStyle();
static void Shutdown();
@ -52,12 +58,14 @@ public:
static already_AddRefed<nsStyleContext>
GetStyleContextForElement(mozilla::dom::Element* aElement, nsIAtom* aPseudo,
nsIPresShell* aPresShell);
nsIPresShell* aPresShell,
StyleType aStyleType = eAll);
static already_AddRefed<nsStyleContext>
GetStyleContextForElementNoFlush(mozilla::dom::Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell);
nsIPresShell* aPresShell,
StyleType aStyleType = eAll);
static nsIPresShell*
GetPresShellForContent(nsIContent* aContent);
@ -505,6 +513,11 @@ private:
*/
nsIPresShell* mPresShell;
/*
* The kind of styles we should be returning.
*/
StyleType mStyleType;
bool mExposeVisitedStyle;
#ifdef DEBUG
@ -515,7 +528,9 @@ private:
already_AddRefed<nsComputedDOMStyle>
NS_NewComputedDOMStyle(mozilla::dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell);
nsIPresShell* aPresShell,
nsComputedDOMStyle::StyleType aStyleType =
nsComputedDOMStyle::eAll);
#endif /* nsComputedDOMStyle_h__ */

View File

@ -969,7 +969,7 @@ nsStyleSet::ResolveStyleFor(Element* aElement,
already_AddRefed<nsStyleContext>
nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
const nsCOMArray<nsIStyleRule> &aRules)
const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
{
NS_ENSURE_FALSE(mInShutdown, nullptr);
@ -977,8 +977,8 @@ nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
// FIXME: Perhaps this should be passed in, but it probably doesn't
// matter.
ruleWalker.SetLevel(eDocSheet, false, false);
for (int32_t i = 0; i < aRules.Count(); i++) {
ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
for (uint32_t i = 0; i < aRules.Length(); i++) {
ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
}
return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,

View File

@ -90,7 +90,7 @@ class nsStyleSet
// sequence of style rules in the |aRules| array.
already_AddRefed<nsStyleContext>
ResolveStyleForRules(nsStyleContext* aParentContext,
const nsCOMArray<nsIStyleRule> &aRules);
const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules);
// Get a style context that represents aBaseContext, but as though
// it additionally matched the rules in the aRules array (in that

View File

@ -92,6 +92,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
test_compute_data_with_start_struct.html \
test_computed_style.html \
test_computed_style_no_pseudo.html \
test_default_computed_style.html \
test_css_cross_domain.html \
test_css_eof_handling.html \
test_default_bidi_css.html \

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=800983
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 800983</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
#display::before { content: "Visible"; display: block }
#display {
display: inline;
margin-top: 0;
background: yellow;
color: blue;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=800983">Mozilla Bug 800983</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 800983 **/
var cs = getComputedStyle($("display"));
var cs_pseudo = getComputedStyle($("display"), "::before")
var cs_default = getDefaultComputedStyle($("display"));
var cs_default_pseudo = getDefaultComputedStyle($("display"), "::before");
// Sanity checks for normal computed style
is(cs.display, "inline", "We have inline display");
is(cs.marginTop, "0px", "We have 0 margin");
is(cs.backgroundColor, "rgb(255, 255, 0)", "We have yellow background");
is(cs.color, "rgb(0, 0, 255)", "We have blue text");
is(cs_pseudo.content, '"Visible"', "We have some content");
is(cs_pseudo.display, "block", "Our ::before is block");
// And now our actual tests
is(cs_default.display, "block", "We have block display by default");
is(cs_default.marginTop, "16px", "We have 16px margin by default");
is(cs_default.backgroundColor, "transparent",
"We have transparent background by default");
is(cs_default.color, "rgb(0, 0, 0)", "We have black text by default");
is(cs_default_pseudo.content, "none", "We have no content by default");
is(cs_default_pseudo.display, "inline", "Our ::before is inline by default");
</script>
</pre>
</body>
</html>