Backed out changeset bca0b6ed92e4

This commit is contained in:
Shawn Wilsher 2010-02-18 10:02:49 -08:00
parent 40e546231a
commit 56b8597aca
5 changed files with 151 additions and 36 deletions

View File

@ -1676,6 +1676,7 @@ PresShell::Init(nsIDocument* aDocument,
nsCOMPtr<nsIObserverService> os =
do_GetService("@mozilla.org/observer-service;1", &result);
if (os) {
os->AddObserver(this, NS_LINK_VISITED_EVENT_TOPIC, PR_FALSE);
os->AddObserver(this, "agent-sheet-added", PR_FALSE);
os->AddObserver(this, "user-sheet-added", PR_FALSE);
os->AddObserver(this, "agent-sheet-removed", PR_FALSE);
@ -1743,6 +1744,7 @@ PresShell::Destroy()
nsCOMPtr<nsIObserverService> os =
do_GetService("@mozilla.org/observer-service;1");
if (os) {
os->RemoveObserver(this, NS_LINK_VISITED_EVENT_TOPIC);
os->RemoveObserver(this, "agent-sheet-added");
os->RemoveObserver(this, "user-sheet-added");
os->RemoveObserver(this, "agent-sheet-removed");
@ -7585,6 +7587,14 @@ PresShell::Observe(nsISupports* aSubject,
}
#endif
if (!nsCRT::strcmp(aTopic, NS_LINK_VISITED_EVENT_TOPIC)) {
nsCOMPtr<nsIURI> uri = do_QueryInterface(aSubject);
if (uri && mDocument) {
mDocument->NotifyURIVisitednessChanged(uri);
}
return NS_OK;
}
if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
AddAgentSheet(aSubject);
return NS_OK;

View File

@ -48,8 +48,7 @@
* order. The first argument to CSS_PSEUDO_CLASS is the C++
* identifier of the atom. The second argument is the string value of
* the atom. CSS_STATE_PSEUDO_CLASS also takes the name of the state
* bits that the class corresponds to. Only one of the bits needs to
* match for the pseudo-class to match. If CSS_STATE_PSEUDO_CLASS is
* bit that the class corresponds to. If CSS_STATE_PSEUDO_CLASS is
* not defined, it'll be automatically defined to CSS_PSEUDO_CLASS.
*/
@ -74,11 +73,9 @@ CSS_PSEUDO_CLASS(notPseudo, ":not")
CSS_PSEUDO_CLASS(mozBoundElement, ":-moz-bound-element")
CSS_PSEUDO_CLASS(root, ":root")
CSS_STATE_PSEUDO_CLASS(link, ":link", NS_EVENT_STATE_UNVISITED)
// what matches :link or :visited
CSS_STATE_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link",
NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)
CSS_STATE_PSEUDO_CLASS(visited, ":visited", NS_EVENT_STATE_VISITED)
CSS_PSEUDO_CLASS(link, ":link")
CSS_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link") // what matches :link or :visited
CSS_PSEUDO_CLASS(visited, ":visited")
CSS_STATE_PSEUDO_CLASS(active, ":active", NS_EVENT_STATE_ACTIVE)
CSS_STATE_PSEUDO_CLASS(checked, ":checked", NS_EVENT_STATE_CHECKED)

View File

@ -910,7 +910,8 @@ RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
mPreviousSiblingData(nsnull),
mParentData(nsnull),
mLanguage(nsnull),
mGotContentState(PR_FALSE)
mGotContentState(PR_FALSE),
mGotLinkInfo(PR_FALSE)
{
MOZ_COUNT_CTOR(RuleProcessorData);
@ -958,6 +959,9 @@ RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
mIsHTMLContent = (mNameSpaceID == kNameSpaceID_XHTML);
mIsHTML = mIsHTMLContent && aContent->IsInHTMLDocument();
// No need to initialize mIsLink or mLinkState; the IsLink() accessor will
// handle that.
// No need to initialize mContentState; the ContentState() accessor will handle
// that.
}
@ -1034,13 +1038,6 @@ RuleProcessorData::ContentState()
} else {
mContentState = mContent->IntrinsicState();
}
// If we are not supposed to mark visited links as such, be sure to flip the
// bits appropriately.
if (!gSupportVisitedPseudo && (mContentState & NS_EVENT_STATE_VISITED)) {
mContentState = (mContentState & ~PRUint32(NS_EVENT_STATE_VISITED)) |
NS_EVENT_STATE_UNVISITED;
}
}
return mContentState;
}
@ -1048,8 +1045,37 @@ RuleProcessorData::ContentState()
PRBool
RuleProcessorData::IsLink()
{
PRUint32 state = ContentState();
return (state & (NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) != 0;
if (!mGotLinkInfo) {
mGotLinkInfo = PR_TRUE;
mLinkState = eLinkState_Unknown;
mIsLink = PR_FALSE;
// if HTML content and it has some attributes, check for an HTML link
// NOTE: optimization: cannot be a link if no attributes (since it needs
// an href)
nsILinkHandler* linkHandler =
mPresContext ? mPresContext->GetLinkHandler() : nsnull;
if (mIsHTMLContent && mHasAttributes) {
// check if it is an HTML Link
if (nsStyleUtil::IsHTMLLink(mContent, linkHandler, &mLinkState)) {
mIsLink = PR_TRUE;
}
}
// if not an HTML link, check for a simple xlink (cannot be both HTML
// link and xlink) NOTE: optimization: cannot be an XLink if no
// attributes (since it needs an href)
if(!mIsLink &&
mHasAttributes &&
!(mIsHTMLContent || mContent->IsXUL()) &&
nsStyleUtil::IsLink(mContent, linkHandler, &mLinkState)) {
mIsLink = PR_TRUE;
}
if (mLinkState == eLinkState_Visited && !gSupportVisitedPseudo) {
mLinkState = eLinkState_Unvisited;
}
}
return mIsLink;
}
PRInt32
@ -1611,6 +1637,31 @@ langMatches(RuleProcessorData& data, PRBool setNodeFlags,
return PR_FALSE;
}
static PRBool NS_FASTCALL
mozAnyLinkMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass)
{
NS_PRECONDITION(pseudoClass->mAtom == nsCSSPseudoClasses::mozAnyLink,
"Unexpected atom");
return data.IsLink();
}
static PRBool NS_FASTCALL
linkMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass)
{
NS_NOTREACHED("Shouldn't be called");
return PR_FALSE;
}
static PRBool NS_FASTCALL
visitedMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass)
{
NS_NOTREACHED("Shouldn't be called");
return PR_FALSE;
}
static PRBool NS_FASTCALL
mozIsHTMLMatches(RuleProcessorData& data, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass)
@ -1684,13 +1735,13 @@ notPseudoMatches(RuleProcessorData& data, PRBool setNodeFlags,
typedef PRBool
(NS_FASTCALL * PseudoClassMatcher)(RuleProcessorData&, PRBool setNodeFlags,
nsPseudoClassList* pseudoClass);
// Only one of mFunc or mBits will be set; the other will be null or 0
// Only one of mFunc or mBit will be set; the other will be null or 0
// respectively. We could use a union, but then we'd still need to
// differentiate somehow, eiher with another member in the struct or
// with a boolean coming from _sowewhere_.
struct PseudoClassInfo {
PseudoClassMatcher mFunc;
PRInt32 mBits;
PRInt32 mBit;
};
static const PseudoClassInfo sPseudoClassInfo[] = {
@ -1814,15 +1865,33 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// test for pseudo class match
for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
pseudoClass; pseudoClass = pseudoClass->mNext) {
// XXXbz special-case for :link and :visited, which are neither
// fish nor fowl
if (pseudoClass->mAtom == nsCSSPseudoClasses::link ||
pseudoClass->mAtom == nsCSSPseudoClasses::visited) {
if (!data.IsLink()) {
return PR_FALSE;
}
if (aStateMask & NS_EVENT_STATE_VISITED) {
if (aDependence)
*aDependence = PR_TRUE;
} else if ((eLinkState_Visited == data.LinkState()) ==
(nsCSSPseudoClasses::link == pseudoClass->mAtom)) {
// Visited but :link or unvisited but :visited
return PR_FALSE;
}
continue;
}
const PseudoClassInfo& info = sPseudoClassInfo[pseudoClass->mType];
if (info.mFunc) {
if (!(*info.mFunc)(data, setNodeFlags, pseudoClass)) {
return PR_FALSE;
}
} else {
PRInt32 statesToCheck = info.mBits;
NS_ABORT_IF_FALSE(statesToCheck != 0, "How did that happen?");
if ((statesToCheck & (NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) &&
PRInt32 stateToCheck = info.mBit;
NS_ABORT_IF_FALSE(stateToCheck != 0, "How did that happen?");
if ((stateToCheck & (NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) &&
data.mCompatMode == eCompatibility_NavQuirks &&
// global selector (but don't check .class):
!aSelector->HasTagSelector() && !aSelector->mIDList &&
@ -1839,11 +1908,11 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// selectors ":hover" and ":active".
return PR_FALSE;
} else {
if (aStateMask & statesToCheck) {
if (aStateMask & stateToCheck) {
if (aDependence)
*aDependence = PR_TRUE;
} else {
if (!(data.ContentState() & statesToCheck)) {
if (!(data.ContentState() & stateToCheck)) {
return PR_FALSE;
}
}
@ -2255,6 +2324,28 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData
// Don't do our special handling of certain attributes if the attr
// hasn't changed yet.
if (aData->mAttrHasChanged) {
// Since we always have :-moz-any-link (and almost always have :link
// and :visited rules from prefs), rather than hacking AddRule below
// to add |href| to the hash, we'll just handle it here.
if (aData->mAttribute == nsGkAtoms::href &&
aData->mIsHTMLContent &&
(aData->mContentTag == nsGkAtoms::a ||
aData->mContentTag == nsGkAtoms::area ||
aData->mContentTag == nsGkAtoms::link)) {
data.change = nsReStyleHint(data.change | eReStyle_Self);
}
// XXX What about XLinks?
#ifdef MOZ_SVG
// XXX should really check the attribute namespace is XLink
if (aData->mAttribute == nsGkAtoms::href &&
aData->mNameSpaceID == kNameSpaceID_SVG &&
aData->mContentTag == nsGkAtoms::a) {
data.change = nsReStyleHint(data.change | eReStyle_Self);
}
#endif
// XXXbz now that :link and :visited are also states, do we need a
// similar optimization in HasStateDependentStyle?
// check for the localedir, lwtheme and lwthemetextcolor attribute on root XUL elements
if ((aData->mAttribute == nsGkAtoms::localedir ||
aData->mAttribute == nsGkAtoms::lwtheme ||
@ -2371,7 +2462,11 @@ PRBool IsStateSelector(nsCSSSelector& aSelector)
if (pseudoClass->mType >= nsCSSPseudoClasses::ePseudoClass_Count) {
continue;
}
if (sPseudoClassInfo[pseudoClass->mType].mBits) {
// XXXbz special-case for now for :link/:visited, since they're
// sorta-states-but-not-really right now.
if (sPseudoClassInfo[pseudoClass->mType].mBit ||
pseudoClass->mAtom == nsCSSPseudoClasses::link ||
pseudoClass->mAtom == nsCSSPseudoClasses::visited) {
return PR_TRUE;
}
}

View File

@ -238,18 +238,23 @@ nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData* aData)
// if we have anchor colors, check if this is an anchor with an href
if (tag == nsGkAtoms::a) {
if (mLinkRule || mVisitedRule || mActiveRule) {
PRUint32 state = aData->ContentState();
if (mLinkRule && (state & NS_EVENT_STATE_UNVISITED)) {
ruleWalker->Forward(mLinkRule);
}
else if (mVisitedRule && (state & NS_EVENT_STATE_VISITED)) {
ruleWalker->Forward(mVisitedRule);
}
if (aData->IsLink()) {
switch (aData->LinkState()) {
case eLinkState_Unvisited:
if (mLinkRule)
ruleWalker->Forward(mLinkRule);
break;
case eLinkState_Visited:
if (mVisitedRule)
ruleWalker->Forward(mVisitedRule);
break;
default:
break;
}
// No need to add to the active rule if it's not a link
if (mActiveRule && aData->IsLink() &&
(state & NS_EVENT_STATE_ACTIVE)) {
ruleWalker->Forward(mActiveRule);
// No need to add to the active rule if it's not a link
if (mActiveRule && (aData->ContentState() & NS_EVENT_STATE_ACTIVE))
ruleWalker->Forward(mActiveRule);
}
} // end link/visited/active rules
} // end A tag

View File

@ -109,6 +109,10 @@ public:
const nsString* GetLang();
PRUint32 ContentState();
PRBool IsLink();
nsLinkState LinkState() {
NS_ASSERTION(mGotLinkInfo && mIsLink, "Why am I being called?");
return mLinkState;
}
// Returns a 1-based index of the child in its parent. If the child
// is not in its parent's child list (i.e., it is anonymous content),
@ -153,7 +157,11 @@ private:
// mContentState, mLinkState, mIsLink are initialized lazily.
PRInt32 mContentState; // eventStateMgr->GetContentState() or
// mContent->IntrinsicState() if we have no ESM
nsLinkState mLinkState; // if a link, this is the state, otherwise unknown
PRPackedBool mIsLink; // nsStyleUtil::IsHTMLLink or nsStyleUtil::IsLink
PRPackedBool mGotContentState;
PRPackedBool mGotLinkInfo; // Whether we've gotten the right values
// for mLinkState and mIsLink.
};
struct ElementRuleProcessorData : public RuleProcessorData {