Bug 508482 - Window activation status should be a pseudoclass (:-moz-window-inactive) instead of an attribute. r=dbaron, r+sr=jst

This commit is contained in:
Markus Stange 2010-03-17 18:10:57 +01:00
Родитель 662abfef89
Коммит 51f979aa23
29 изменённых файлов: 374 добавлений и 66 удалений

Просмотреть файл

@ -1335,6 +1335,11 @@ void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2); nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
} }
void nsDocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
PRInt32 aStateMask)
{
}
void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument, void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument,
nsIContent* aContent, nsIContent* aContent,
CharacterDataChangeInfo* aInfo) CharacterDataChangeInfo* aInfo)

Просмотреть файл

@ -115,12 +115,19 @@ class Link;
} // namespace mozilla } // namespace mozilla
#define NS_IDOCUMENT_IID \ #define NS_IDOCUMENT_IID \
{ 0x36f0a42c, 0x089b, 0x4909, \ { 0x94fb5716, 0xff00, 0x4b97, \
{ 0xb3, 0xee, 0xc5, 0xa4, 0x00, 0x90, 0x30, 0x02 } } { 0x90, 0x01, 0x91, 0x65, 0x1a, 0x5f, 0xbe, 0x64 } }
// Flag for AddStyleSheet(). // Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0) #define NS_STYLESHEET_FROM_CATALOG (1 << 0)
// Document states
// RTL locale: specific to the XUL localedir attribute
#define NS_DOCUMENT_STATE_RTL_LOCALE (1 << 0)
// Window activation status
#define NS_DOCUMENT_STATE_WINDOW_INACTIVE (1 << 1)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Document interface. This is implemented by all document objects in // Document interface. This is implemented by all document objects in
@ -677,6 +684,11 @@ public:
nsIContent* aContent2, nsIContent* aContent2,
PRInt32 aStateMask) = 0; PRInt32 aStateMask) = 0;
// Notify that a document state has changed.
// This should only be called by callers whose state is also reflected in the
// implementation of nsDocument::GetDocumentState.
virtual void DocumentStatesChanged(PRInt32 aStateMask) = 0;
// Observation hooks for style data to propagate notifications // Observation hooks for style data to propagate notifications
// to document observers // to document observers
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet, virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet,
@ -1282,6 +1294,13 @@ public:
*/ */
virtual int GetDocumentLWTheme() { return Doc_Theme_None; } virtual int GetDocumentLWTheme() { return Doc_Theme_None; }
/**
* Returns the document state.
* Document state bits have the form NS_DOCUMENT_STATE_* and are declared in
* nsIDocument.h.
*/
virtual PRInt32 GetDocumentState() = 0;
/** /**
* Gets the document's cached pointer to the first <base> element in this * Gets the document's cached pointer to the first <base> element in this
* document which has an href attribute. If the document doesn't contain any * document which has an href attribute. If the document doesn't contain any

Просмотреть файл

@ -118,6 +118,15 @@ public:
nsIContent* aContent2, nsIContent* aContent2,
PRInt32 aStateMask) = 0; PRInt32 aStateMask) = 0;
/**
* Notification that the state of the document has changed.
*
* @param aDocument The document being observed
* @param aStateMask the state that changed
*/
virtual void DocumentStatesChanged(nsIDocument* aDocument,
PRInt32 aStateMask) = 0;
/** /**
* A StyleSheet has just been added to the document. This method is * A StyleSheet has just been added to the document. This method is
* called automatically when a StyleSheet gets added to the * called automatically when a StyleSheet gets added to the
@ -234,6 +243,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
nsIContent* aContent1, \ nsIContent* aContent1, \
nsIContent* aContent2, \ nsIContent* aContent2, \
PRInt32 aStateMask); \ PRInt32 aStateMask); \
virtual void DocumentStatesChanged(nsIDocument* aDocument, \
PRInt32 aStateMask); \
virtual void StyleSheetAdded(nsIDocument* aDocument, \ virtual void StyleSheetAdded(nsIDocument* aDocument, \
nsIStyleSheet* aStyleSheet, \ nsIStyleSheet* aStyleSheet, \
PRBool aDocumentSheet); \ PRBool aDocumentSheet); \
@ -284,6 +295,12 @@ _class::ContentStatesChanged(nsIDocument* aDocument, \
nsIContent* aContent2, \ nsIContent* aContent2, \
PRInt32 aStateMask) \ PRInt32 aStateMask) \
{ \ { \
} \
\
void \
_class::DocumentStatesChanged(nsIDocument* aDocument, \
PRInt32 aStateMask) \
{ \
} }
#define NS_IMPL_NSIDOCUMENTOBSERVER_CONTENT(_class) \ #define NS_IMPL_NSIDOCUMENTOBSERVER_CONTENT(_class) \

Просмотреть файл

@ -4055,6 +4055,16 @@ nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2,
(this, aContent1, aContent2, aStateMask)); (this, aContent1, aContent2, aStateMask));
} }
void
nsDocument::DocumentStatesChanged(PRInt32 aStateMask)
{
// Invalidate our cached state.
mGotDocumentState &= ~aStateMask;
mDocumentState &= ~aStateMask;
NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged, (this, aStateMask));
}
void void
nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet, nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet,
nsIStyleRule* aOldStyleRule, nsIStyleRule* aOldStyleRule,
@ -7615,6 +7625,26 @@ nsDocument::MaybePreLoadImage(nsIURI* uri)
} }
} }
PRInt32
nsDocument::GetDocumentState()
{
if (!(mGotDocumentState & NS_DOCUMENT_STATE_RTL_LOCALE)) {
if (IsDocumentRightToLeft()) {
mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
}
mGotDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
}
if (!(mGotDocumentState & NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
nsIPresShell* shell = GetPrimaryShell();
if (shell && shell->GetPresContext() &&
shell->GetPresContext()->IsTopLevelWindowInactive()) {
mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
}
mGotDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
}
return mDocumentState;
}
namespace { namespace {
/** /**

Просмотреть файл

@ -693,6 +693,7 @@ public:
virtual void ContentStatesChanged(nsIContent* aContent1, virtual void ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2, nsIContent* aContent2,
PRInt32 aStateMask); PRInt32 aStateMask);
virtual void DocumentStatesChanged(PRInt32 aStateMask);
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet, virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet,
nsIStyleRule* aOldStyleRule, nsIStyleRule* aOldStyleRule,
@ -939,6 +940,8 @@ public:
virtual nsISupports* GetCurrentContentSink(); virtual nsISupports* GetCurrentContentSink();
virtual PRInt32 GetDocumentState();
virtual void RegisterFileDataUri(nsACString& aUri); virtual void RegisterFileDataUri(nsACString& aUri);
protected: protected:
@ -1134,6 +1137,9 @@ protected:
nsCOMPtr<nsIContent> mFirstBaseNodeWithHref; nsCOMPtr<nsIContent> mFirstBaseNodeWithHref;
PRInt32 mDocumentState;
PRInt32 mGotDocumentState;
private: private:
friend class nsUnblockOnloadEvent; friend class nsUnblockOnloadEvent;

Просмотреть файл

@ -126,7 +126,6 @@
#include "nsXULPopupManager.h" #include "nsXULPopupManager.h"
#include "nsCCUncollectableMarker.h" #include "nsCCUncollectableMarker.h"
#include "nsURILoader.h" #include "nsURILoader.h"
#include "nsCSSFrameConstructor.h"
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// //
@ -4665,17 +4664,11 @@ nsXULDocument::IsDocumentRightToLeft()
int int
nsXULDocument::DirectionChanged(const char* aPrefName, void* aData) nsXULDocument::DirectionChanged(const char* aPrefName, void* aData)
{ {
// reset the direction and reflow the document. This will happen if // Reset the direction and restyle the document if necessary.
// the direction isn't actually being used, but that doesn't really
// matter too much
nsXULDocument* doc = (nsXULDocument *)aData; nsXULDocument* doc = (nsXULDocument *)aData;
if (doc) if (doc) {
doc->ResetDocumentDirection(); doc->ResetDocumentDirection();
doc->DocumentStatesChanged(NS_DOCUMENT_STATE_RTL_LOCALE);
nsIPresShell *shell = doc->GetPrimaryShell();
if (shell) {
shell->FrameConstructor()->
PostRestyleEvent(doc->GetRootContent(), eReStyle_Self, NS_STYLE_HINT_NONE);
} }
return 0; return 0;

Просмотреть файл

@ -6833,15 +6833,18 @@ nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
void void
nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate) nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
{ {
// Set / unset the "active" attribute on the documentElement // Set / unset mIsActive on the top level window, which is used for the
// of the top level window // :-moz-window-inactive pseudoclass.
nsCOMPtr<nsIWidget> mainWidget = GetMainWidget(); nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
if (mainWidget) { if (!mainWidget)
return;
// Get the top level widget (if the main widget is a sheet, this will // Get the top level widget (if the main widget is a sheet, this will
// be the sheet's top (non-sheet) parent). // be the sheet's top (non-sheet) parent).
nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent(); nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
if (!topLevelWidget) if (!topLevelWidget) {
topLevelWidget = mainWidget; topLevelWidget = mainWidget;
}
// Get the top level widget's nsGlobalWindow // Get the top level widget's nsGlobalWindow
nsCOMPtr<nsIDOMWindowInternal> topLevelWindow; nsCOMPtr<nsIDOMWindowInternal> topLevelWindow;
@ -6851,34 +6854,32 @@ nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
// This is a workaround for the following problem: // This is a workaround for the following problem:
// When a window with an open sheet loses focus, only the sheet window // When a window with an open sheet loses focus, only the sheet window
// receives the NS_DEACTIVATE event. However, it's not the sheet that // receives the NS_DEACTIVATE event. However, it's not the sheet that
// should lose the "active" attribute, but the containing top level window. // should lose the active styling, but the containing top level window.
void* clientData; void* clientData;
topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
nsISupports* data = static_cast<nsISupports*>(clientData); nsISupports* data = static_cast<nsISupports*>(clientData);
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data)); nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
topLevelWindow = do_GetInterface(req); topLevelWindow = do_GetInterface(req);
} }
if (topLevelWindow) { if (topLevelWindow) {
// Only set the attribute if the document is a XUL document and the nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
// window is a chrome window piWin->SetActive(aActivate);
nsCOMPtr<nsIDOMDocument> domDoc;
topLevelWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
nsCOMPtr<nsIDOMXULDocument> xulDoc(do_QueryInterface(doc));
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(topLevelWindow);
if (xulDoc && chromeWin) {
nsCOMPtr<nsIContent> rootElem = doc->GetRootContent();
if (rootElem) {
if (aActivate)
rootElem->SetAttr(kNameSpaceID_None, nsGkAtoms::active,
NS_LITERAL_STRING("true"), PR_TRUE);
else
rootElem->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, PR_TRUE);
}
} }
} }
static PRBool
NotifyDocumentTree(nsIDocument* aDocument, void* aData)
{
aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
return PR_TRUE;
} }
void
nsGlobalWindow::SetActive(PRBool aActive)
{
nsPIDOMWindow::SetActive(aActive);
NotifyDocumentTree(mDoc, nsnull);
} }
void void

Просмотреть файл

@ -288,6 +288,7 @@ public:
// nsPIDOMWindow // nsPIDOMWindow
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot(); virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
virtual NS_HIDDEN_(void) ActivateOrDeactivate(PRBool aActivate); virtual NS_HIDDEN_(void) ActivateOrDeactivate(PRBool aActivate);
virtual NS_HIDDEN_(void) SetActive(PRBool aActive);
virtual NS_HIDDEN_(void) SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler); virtual NS_HIDDEN_(void) SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler);
virtual NS_HIDDEN_(void) SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal); virtual NS_HIDDEN_(void) SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal);

Просмотреть файл

@ -78,8 +78,8 @@ class nsIArray;
class nsPIWindowRoot; class nsPIWindowRoot;
#define NS_PIDOMWINDOW_IID \ #define NS_PIDOMWINDOW_IID \
{ 0x81cdf500, 0x2183, 0x4af6, \ { 0xC5CB154D, 0x17C0, 0x49E9, \
{ 0xa4, 0x56, 0x35, 0x1f, 0x4a, 0x0d, 0x1a, 0x0b } } { 0x9C, 0x83, 0xFF, 0xC7, 0x2C, 0x93, 0xAF, 0x24 } }
class nsPIDOMWindow : public nsIDOMWindowInternal class nsPIDOMWindow : public nsIDOMWindowInternal
{ {
@ -93,6 +93,16 @@ public:
// this is called GetTopWindowRoot to avoid conflicts with nsIDOMWindow2::GetWindowRoot // this is called GetTopWindowRoot to avoid conflicts with nsIDOMWindow2::GetWindowRoot
virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0; virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0;
virtual void SetActive(PRBool aActive)
{
mIsActive = aActive;
}
PRBool IsActive()
{
return mIsActive;
}
nsPIDOMEventTarget* GetChromeEventHandler() const nsPIDOMEventTarget* GetChromeEventHandler() const
{ {
return mChromeEventHandler; return mChromeEventHandler;
@ -490,8 +500,8 @@ protected:
mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE), mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull), mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
mMayHavePaintEventListener(PR_FALSE), mMayHavePaintEventListener(PR_FALSE),
mIsModalContentWindow(PR_FALSE), mInnerWindow(nsnull), mIsModalContentWindow(PR_FALSE), mIsActive(PR_FALSE),
mOuterWindow(aOuterWindow) mInnerWindow(nsnull), mOuterWindow(aOuterWindow)
{ {
} }
@ -525,6 +535,9 @@ protected:
// should match). // should match).
PRPackedBool mIsModalContentWindow; PRPackedBool mIsModalContentWindow;
// Tracks activation state that's used for :-moz-window-inactive
PRPackedBool mIsActive;
// And these are the references between inner and outer windows. // And these are the references between inner and outer windows.
nsPIDOMWindow *mInnerWindow; nsPIDOMWindow *mInnerWindow;
nsPIDOMWindow *mOuterWindow; nsPIDOMWindow *mOuterWindow;

Просмотреть файл

@ -60,6 +60,8 @@ _TEST_FILES = \
window_focus.xul \ window_focus.xul \
test_focused_link_scroll.xul \ test_focused_link_scroll.xul \
test_geolocation.xul \ test_geolocation.xul \
test_activation.xul \
window_activation.xul \
$(NULL) $(NULL)
libs:: $(_TEST_FILES) libs:: $(_TEST_FILES)

Просмотреть файл

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<?xml-stylesheet href="data:text/css,
#box {
background: blue;
}
#box:-moz-window-inactive {
background: cyan;
}
" type="text/css"?>
<!--
Test for the :-moz-window-inactive pseudoclass
-->
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
sizemode="fullscreen">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<box id="box" height="100"/>
<script>
SimpleTest.waitForExplicitFinish();
newwindow = window.open("window_activation.xul", "_blank","chrome,width=300,height=200");
function complete()
{
newwindow.close();
SimpleTest.finish();
}
</script>
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
</window>

Просмотреть файл

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="data:text/css,
#box {
background: blue;
}
#box:-moz-window-inactive {
background: cyan;
}
" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<box id="box" height="100"/>
<script type="application/javascript"><![CDATA[
var ok = window.opener.wrappedJSObject.ok;
var complete = window.opener.wrappedJSObject.complete;
var openerDoc = window.opener.wrappedJSObject.document;
window.onfocus = function () {
ok(getComputedStyle(document.getElementById("box"), "").backgroundColor, "rgb(0, 0, 255)");
ok(getComputedStyle(openerDoc.getElementById("box"), "").backgroundColor, "rgb(0, 255, 255)");
window.opener.focus();
ok(getComputedStyle(document.getElementById("box"), "").backgroundColor, "rgb(0, 255, 255)");
ok(getComputedStyle(openerDoc.getElementById("box"), "").backgroundColor, "rgb(0, 0, 255)");
complete();
}
]]></script>
</window>

Просмотреть файл

@ -1435,6 +1435,20 @@ nsPresContext::GetBidi() const
} }
#endif //IBMBIDI #endif //IBMBIDI
PRBool
nsPresContext::IsTopLevelWindowInactive()
{
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryReferent(mContainer));
if (!treeItem)
return PR_FALSE;
nsCOMPtr<nsIDocShellTreeItem> rootItem;
treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
nsCOMPtr<nsPIDOMWindow> domWindow(do_GetInterface(rootItem));
return domWindow && !domWindow->IsActive();
}
nsITheme* nsITheme*
nsPresContext::GetTheme() nsPresContext::GetTheme()
{ {

Просмотреть файл

@ -757,6 +757,8 @@ public:
PRBool IsRenderingOnlySelection() const { return mIsRenderingOnlySelection; } PRBool IsRenderingOnlySelection() const { return mIsRenderingOnlySelection; }
NS_HIDDEN_(PRBool) IsTopLevelWindowInactive();
/* /*
* Obtain a native them for rendering our widgets (both form controls and html) * Obtain a native them for rendering our widgets (both form controls and html)
*/ */

Просмотреть файл

@ -856,6 +856,8 @@ public:
nsIContent* aContent1, nsIContent* aContent1,
nsIContent* aContent2, nsIContent* aContent2,
PRInt32 aStateMask); PRInt32 aStateMask);
virtual void DocumentStatesChanged(nsIDocument* aDocument,
PRInt32 aStateMask);
virtual void StyleSheetAdded(nsIDocument* aDocument, virtual void StyleSheetAdded(nsIDocument* aDocument,
nsIStyleSheet* aStyleSheet, nsIStyleSheet* aStyleSheet,
PRBool aDocumentSheet); PRBool aDocumentSheet);
@ -4911,6 +4913,23 @@ PresShell::ContentStatesChanged(nsIDocument* aDocument,
} }
} }
void
PresShell::DocumentStatesChanged(nsIDocument* aDocument,
PRInt32 aStateMask)
{
NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
if (mDidInitialReflow &&
mStyleSet->HasDocumentStateDependentStyle(mPresContext,
mDocument->GetRootContent(),
aStateMask)) {
mFrameConstructor->PostRestyleEvent(mDocument->GetRootContent(),
eReStyle_Self, NS_STYLE_HINT_NONE);
VERIFY_STYLE_TREE;
}
}
void void
PresShell::AttributeWillChange(nsIDocument* aDocument, PresShell::AttributeWillChange(nsIDocument* aDocument,
nsIContent* aContent, nsIContent* aContent,

Просмотреть файл

@ -141,6 +141,9 @@ CSS_PSEUDO_CLASS(mozLWThemeBrightText, ":-moz-lwtheme-brighttext")
// -moz-lwtheme-darktext matches a document that has a bright lightweight theme // -moz-lwtheme-darktext matches a document that has a bright lightweight theme
CSS_PSEUDO_CLASS(mozLWThemeDarkText, ":-moz-lwtheme-darktext") CSS_PSEUDO_CLASS(mozLWThemeDarkText, ":-moz-lwtheme-darktext")
// Matches anything when the containing window is inactive
CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive")
#ifdef MOZ_MATHML #ifdef MOZ_MATHML
CSS_STATE_PSEUDO_CLASS(mozMathIncrementScriptLevel, CSS_STATE_PSEUDO_CLASS(mozMathIncrementScriptLevel,
":-moz-math-increment-script-level", ":-moz-math-increment-script-level",

Просмотреть файл

@ -707,6 +707,7 @@ static const PLDHashTableOps AttributeSelectorOps = {
struct RuleCascadeData { struct RuleCascadeData {
RuleCascadeData(nsIAtom *aMedium, PRBool aQuirksMode) RuleCascadeData(nsIAtom *aMedium, PRBool aQuirksMode)
: mRuleHash(aQuirksMode), : mRuleHash(aQuirksMode),
mSelectorDocumentStates(0),
mStateSelectors(), mStateSelectors(),
mCacheKey(aMedium), mCacheKey(aMedium),
mNext(nsnull), mNext(nsnull),
@ -736,6 +737,7 @@ struct RuleCascadeData {
RuleHash* RuleHash*
mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount]; mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount];
nsTArray<nsCSSSelector*> mStateSelectors; nsTArray<nsCSSSelector*> mStateSelectors;
PRUint32 mSelectorDocumentStates;
nsTArray<nsCSSSelector*> mClassSelectors; nsTArray<nsCSSSelector*> mClassSelectors;
nsTArray<nsCSSSelector*> mIDSelectors; nsTArray<nsCSSSelector*> mIDSelectors;
PLDHashTable mAttributeSelectors; PLDHashTable mAttributeSelectors;
@ -1123,6 +1125,12 @@ RuleProcessorData::ContentState()
return mContentState; return mContentState;
} }
PRUint32
RuleProcessorData::DocumentState()
{
return mContent->GetOwnerDoc()->GetDocumentState();
}
PRBool PRBool
RuleProcessorData::IsLink() RuleProcessorData::IsLink()
{ {
@ -1704,13 +1712,8 @@ mozLocaleDirMatches(RuleProcessorData& data, PRBool setNodeFlags,
{ {
NS_PRECONDITION(pseudoClass->mAtom == nsCSSPseudoClasses::mozLocaleDir, NS_PRECONDITION(pseudoClass->mAtom == nsCSSPseudoClasses::mozLocaleDir,
"Unexpected atom"); "Unexpected atom");
nsIDocument* doc = data.mContent->GetDocument();
if (!doc) { PRBool docIsRTL = (data.DocumentState() & NS_DOCUMENT_STATE_RTL_LOCALE) != 0;
return PR_FALSE;
}
PRBool docIsRTL = doc && doc->IsDocumentRightToLeft();
nsDependentString dirString(pseudoClass->u.mString); nsDependentString dirString(pseudoClass->u.mString);
NS_ASSERTION(dirString.EqualsLiteral("ltr") || dirString.EqualsLiteral("rtl"), NS_ASSERTION(dirString.EqualsLiteral("ltr") || dirString.EqualsLiteral("rtl"),
@ -1751,6 +1754,16 @@ mozLWThemeDarkTextMatches(RuleProcessorData& data, PRBool setNodeFlags,
return doc && doc->GetDocumentLWTheme() == nsIDocument::Doc_Theme_Dark; return doc && doc->GetDocumentLWTheme() == nsIDocument::Doc_Theme_Dark;
} }
static PRBool NS_FASTCALL
mozWindowInactiveMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass)
{
NS_PRECONDITION(pseudoClass->mAtom ==
nsCSSPseudoClasses::mozWindowInactive,
"Unexpected atom");
return (data.DocumentState() & NS_DOCUMENT_STATE_WINDOW_INACTIVE) != 0;
}
static PRBool NS_FASTCALL static PRBool NS_FASTCALL
notPseudoMatches(RuleProcessorData& data, PRBool setNodeFlags, notPseudoMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass) nsPseudoClassList* pseudoClass)
@ -2292,6 +2305,14 @@ nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
return hint; return hint;
} }
PRBool
nsCSSRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
{
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
return cascade && (cascade->mSelectorDocumentStates & aData->mStateMask) != 0;
}
struct AttributeEnumData { struct AttributeEnumData {
AttributeEnumData(AttributeRuleProcessorData *aData) AttributeEnumData(AttributeRuleProcessorData *aData)
: data(aData), change(nsReStyleHint(0)) {} : data(aData), change(nsReStyleHint(0)) {}
@ -2456,6 +2477,20 @@ PRBool IsStateSelector(nsCSSSelector& aSelector)
return PR_FALSE; return PR_FALSE;
} }
inline
void AddSelectorDocumentStates(nsCSSSelector& aSelector, PRUint32* aStateMask)
{
for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList;
pseudoClass; pseudoClass = pseudoClass->mNext) {
if (pseudoClass->mAtom == nsCSSPseudoClasses::mozLocaleDir) {
*aStateMask |= NS_DOCUMENT_STATE_RTL_LOCALE;
}
else if (pseudoClass->mAtom == nsCSSPseudoClasses::mozWindowInactive) {
*aStateMask |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
}
}
}
static PRBool static PRBool
AddRule(RuleValue* aRuleInfo, RuleCascadeData* aCascade) AddRule(RuleValue* aRuleInfo, RuleCascadeData* aCascade)
{ {
@ -2533,6 +2568,9 @@ AddRule(RuleValue* aRuleInfo, RuleCascadeData* aCascade)
// in the future if :not() is extended. // in the future if :not() is extended.
for (nsCSSSelector* negation = selector; negation; for (nsCSSSelector* negation = selector; negation;
negation = negation->mNegations) { negation = negation->mNegations) {
// Track the selectors that depend on document states.
AddSelectorDocumentStates(*negation, &cascade->mSelectorDocumentStates);
// Build mStateSelectors. // Build mStateSelectors.
if (IsStateSelector(*negation)) if (IsStateSelector(*negation))
stateArray->AppendElement(selector); stateArray->AppendElement(selector);

Просмотреть файл

@ -104,6 +104,8 @@ public:
virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData); virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
virtual nsReStyleHint virtual nsReStyleHint
HasAttributeDependentStyle(AttributeRuleProcessorData* aData); HasAttributeDependentStyle(AttributeRuleProcessorData* aData);

Просмотреть файл

@ -148,6 +148,12 @@ nsHTMLCSSStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData)
return nsReStyleHint(0); return nsReStyleHint(0);
} }
PRBool
nsHTMLCSSStyleSheet::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
{
return PR_FALSE;
}
// Test if style is dependent on attribute // Test if style is dependent on attribute
nsReStyleHint nsReStyleHint
nsHTMLCSSStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData) nsHTMLCSSStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)

Просмотреть файл

@ -80,6 +80,7 @@ public:
NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData); NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
#endif #endif
virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData); virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
virtual nsReStyleHint virtual nsReStyleHint
HasAttributeDependentStyle(AttributeRuleProcessorData* aData); HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext, NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,

Просмотреть файл

@ -301,6 +301,12 @@ nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData)
return nsReStyleHint(0); return nsReStyleHint(0);
} }
PRBool
nsHTMLStyleSheet::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
{
return PR_FALSE;
}
nsReStyleHint nsReStyleHint
nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData) nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
{ {

Просмотреть файл

@ -85,6 +85,7 @@ public:
NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData); NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
#endif #endif
virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData); virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
virtual nsReStyleHint virtual nsReStyleHint
HasAttributeDependentStyle(AttributeRuleProcessorData* aData); HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext, NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,

Просмотреть файл

@ -109,6 +109,14 @@ public:
NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData) = 0; NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData) = 0;
#endif #endif
/**
* Return whether style can depend on a change of the given document state.
*
* Document states are defined in nsIDocument.h.
*/
virtual PRBool
HasDocumentStateDependentStyle(StateRuleProcessorData* aData) = 0;
/** /**
* Return how (as described by nsReStyleHint) style can depend on a * Return how (as described by nsReStyleHint) style can depend on a
* change of the given content state on the given content node. This * change of the given content state on the given content node. This

Просмотреть файл

@ -108,6 +108,7 @@ private:
public: public:
const nsString* GetLang(); const nsString* GetLang();
PRUint32 ContentState(); PRUint32 ContentState();
PRUint32 DocumentState();
PRBool IsLink(); PRBool IsLink();
// Returns a 1-based index of the child in its parent. If the child // Returns a 1-based index of the child in its parent. If the child

Просмотреть файл

@ -1072,6 +1072,31 @@ struct StatefulData : public StateRuleProcessorData {
nsReStyleHint mHint; nsReStyleHint mHint;
}; };
static PRBool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
void *aData)
{
StatefulData* data = (StatefulData*)aData;
if (aProcessor->HasDocumentStateDependentStyle(data)) {
data->mHint = eReStyle_Self;
return PR_FALSE; // don't continue
}
return PR_TRUE; // continue
}
// Test if style is dependent on a document state.
PRBool
nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
nsIContent* aContent,
PRInt32 aStateMask)
{
if (!aContent || !aContent->IsNodeOfType(nsINode::eELEMENT))
return PR_FALSE;
StatefulData data(aPresContext, aContent, aStateMask);
WalkRuleProcessors(SheetHasDocumentStateStyle, &data);
return data.mHint != 0;
}
static PRBool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor, static PRBool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
void *aData) void *aData)
{ {

Просмотреть файл

@ -177,6 +177,11 @@ class nsStyleSet
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsStyleContext* aNewParentContext); nsStyleContext* aNewParentContext);
// Test if style is dependent on a document state.
PRBool HasDocumentStateDependentStyle(nsPresContext* aPresContext,
nsIContent* aContent,
PRInt32 aStateMask);
// Test if style is dependent on content state // Test if style is dependent on content state
nsReStyleHint HasStateDependentStyle(nsPresContext* aPresContext, nsReStyleHint HasStateDependentStyle(nsPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,

Просмотреть файл

@ -892,6 +892,12 @@ nsTransitionManager::HasStateDependentStyle(StateRuleProcessorData* aData)
return nsReStyleHint(0); return nsReStyleHint(0);
} }
PRBool
nsTransitionManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
{
return PR_FALSE;
}
nsReStyleHint nsReStyleHint
nsTransitionManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData) nsTransitionManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
{ {

Просмотреть файл

@ -93,6 +93,7 @@ public:
NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData); NS_IMETHOD RulesMatching(XULTreeRuleProcessorData* aData);
#endif #endif
virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData); virtual nsReStyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
virtual nsReStyleHint virtual nsReStyleHint
HasAttributeDependentStyle(AttributeRuleProcessorData* aData); HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext, NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,

Просмотреть файл

@ -704,6 +704,9 @@ function run() {
test_balanced_unparseable(":-moz-tree-twisty(open())"); test_balanced_unparseable(":-moz-tree-twisty(open())");
test_balanced_unparseable("::-moz-tree-twisty(hover ())"); test_balanced_unparseable("::-moz-tree-twisty(hover ())");
test_parseable(":-moz-window-inactive");
test_parseable("div p:-moz-window-inactive:hover span");
// Plugin pseudoclasses // Plugin pseudoclasses
test_parseable(":-moz-type-unsupported"); test_parseable(":-moz-type-unsupported");
test_parseable(":-moz-handler-disabled"); test_parseable(":-moz-handler-disabled");