Add mechanism for separate style data for visited style. (Bug 147777) r=bzbarsky
This commit is contained in:
@@ -7652,6 +7652,13 @@ nsCSSFrameConstructor::DoContentStateChanged(nsIContent* aContent,
|
||||
++mHoverGeneration;
|
||||
}
|
||||
|
||||
if (aStateMask & NS_EVENT_STATE_VISITED) {
|
||||
// Exposing information to the page about whether the link is
|
||||
// visited or not isn't really something we can worry about here.
|
||||
// FIXME: We could probably do this a bit better.
|
||||
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
||||
}
|
||||
|
||||
PostRestyleEvent(aContent, rshint, hint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,12 +463,118 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
|
||||
|
||||
#undef DO_STRUCT_DIFFERENCE
|
||||
|
||||
// Note that we do not check whether this->RelevantLinkVisited() !=
|
||||
// aOther->RelevantLinkVisited(); we don't need to since
|
||||
// nsCSSFrameConstructor::DoContentStateChanged always adds
|
||||
// nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
|
||||
// needs to, since HasStateDependentStyle probably doesn't work right
|
||||
// for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
|
||||
// expose whether links are visited to performance tests since all
|
||||
// link coloring happens asynchronously at a time when it's hard for
|
||||
// the page to measure.
|
||||
// However, we do need to compute the larger of the changes that can
|
||||
// happen depending on whether the link is visited or unvisited, since
|
||||
// doing only the one that's currently appropriate would expose which
|
||||
// links are in history to easy performance measurement. Therefore,
|
||||
// here, we add nsChangeHint_RepaintFrame hints (the maximum for
|
||||
// things that can depend on :visited) for the properties on which we
|
||||
// call GetVisitedDependentColor.
|
||||
nsStyleContext *thisVis = GetStyleIfVisited(),
|
||||
*otherVis = aOther->GetStyleIfVisited();
|
||||
if (!thisVis != !otherVis) {
|
||||
// One style context has a style-if-visited and the other doesn't.
|
||||
// Presume a difference.
|
||||
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
||||
} else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
|
||||
// Both style contexts have a style-if-visited.
|
||||
PRBool change = PR_FALSE;
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis|, since callers may look
|
||||
// at a struct on |this| without looking at the same struct on
|
||||
// |thisVis| (including this function if we skip one of these checks
|
||||
// due to change being true already or due to the old style context
|
||||
// not having a style-if-visited), but not the other way around.
|
||||
if (PeekStyleColor()) {
|
||||
if (thisVis->GetStyleColor()->mColor !=
|
||||
otherVis->GetStyleColor()->mColor) {
|
||||
change = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleBackground()) {
|
||||
if (thisVis->GetStyleBackground()->mBackgroundColor !=
|
||||
otherVis->GetStyleBackground()->mBackgroundColor) {
|
||||
change = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleBorder()) {
|
||||
const nsStyleBorder *thisVisBorder = thisVis->GetStyleBorder();
|
||||
const nsStyleBorder *otherVisBorder = otherVis->GetStyleBorder();
|
||||
NS_FOR_CSS_SIDES(side) {
|
||||
PRBool thisFG, otherFG;
|
||||
nscolor thisColor, otherColor;
|
||||
thisVisBorder->GetBorderColor(side, thisColor, thisFG);
|
||||
otherVisBorder->GetBorderColor(side, otherColor, otherFG);
|
||||
if (thisFG != otherFG || (!thisFG && thisColor != otherColor)) {
|
||||
change = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleOutline()) {
|
||||
const nsStyleOutline *thisVisOutline = thisVis->GetStyleOutline();
|
||||
const nsStyleOutline *otherVisOutline = otherVis->GetStyleOutline();
|
||||
PRBool haveColor;
|
||||
nscolor thisColor, otherColor;
|
||||
if (thisVisOutline->GetOutlineInitialColor() !=
|
||||
otherVisOutline->GetOutlineInitialColor() ||
|
||||
(haveColor = thisVisOutline->GetOutlineColor(thisColor)) !=
|
||||
otherVisOutline->GetOutlineColor(otherColor) ||
|
||||
(haveColor && thisColor != otherColor)) {
|
||||
change = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleColumn()) {
|
||||
const nsStyleColumn *thisVisColumn = thisVis->GetStyleColumn();
|
||||
const nsStyleColumn *otherVisColumn = otherVis->GetStyleColumn();
|
||||
if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor ||
|
||||
thisVisColumn->mColumnRuleColorIsForeground !=
|
||||
otherVisColumn->mColumnRuleColorIsForeground) {
|
||||
change = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Calling Peek on |this|, not |thisVis| (see above).
|
||||
if (!change && PeekStyleSVG()) {
|
||||
const nsStyleSVG *thisVisSVG = thisVis->GetStyleSVG();
|
||||
const nsStyleSVG *otherVisSVG = otherVis->GetStyleSVG();
|
||||
if (thisVisSVG->mFill != otherVisSVG->mFill ||
|
||||
thisVisSVG->mStroke != otherVisSVG->mStroke) {
|
||||
change = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (change) {
|
||||
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
||||
}
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleContext::Mark()
|
||||
{
|
||||
if (mStyleIfVisited)
|
||||
mStyleIfVisited->Mark();
|
||||
|
||||
// Mark our rule node.
|
||||
mRuleNode->Mark();
|
||||
|
||||
|
||||
@@ -130,6 +130,48 @@ public:
|
||||
PRBool HasPseudoElementData() const
|
||||
{ return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
|
||||
|
||||
// Is the only link whose visitedness is allowed to influence the
|
||||
// style of the node this style context is for (which is that element
|
||||
// or its nearest ancestor that is a link) visited?
|
||||
PRBool RelevantLinkVisited() const
|
||||
{ return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
|
||||
|
||||
// Return the style context whose style data should be used for the R,
|
||||
// G, and B components of color, background-color, and border-*-color
|
||||
// if RelevantLinkIsVisited().
|
||||
//
|
||||
// GetPseudo() and GetPseudoType() on this style context return the
|
||||
// same as on |this|, and its depth in the tree (number of GetParent()
|
||||
// calls until null is returned) is the same as |this|, since its
|
||||
// parent is either |this|'s parent or |this|'s parent's
|
||||
// style-if-visited.
|
||||
//
|
||||
// Structs on this context should never be examined without also
|
||||
// examining the corresponding struct on |this|. Doing so will likely
|
||||
// both (1) lead to a privacy leak and (2) lead to dynamic change bugs
|
||||
// related to the Peek code in nsStyleContext::CalcStyleDifference.
|
||||
nsStyleContext* GetStyleIfVisited()
|
||||
{ return mStyleIfVisited; }
|
||||
|
||||
// To be called only from nsStyleSet.
|
||||
void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
|
||||
{
|
||||
NS_ASSERTION(!mStyleIfVisited, "should only be set once");
|
||||
mStyleIfVisited = aStyleIfVisited;
|
||||
|
||||
NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
|
||||
"pseudo tag mismatch");
|
||||
if (GetParent() && GetParent()->GetStyleIfVisited()) {
|
||||
NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
|
||||
GetParent()->GetStyleIfVisited() ||
|
||||
GetStyleIfVisited()->GetParent() == GetParent(),
|
||||
"parent mismatch");
|
||||
} else {
|
||||
NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
|
||||
"parent mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
// Tell this style context to cache aStruct as the struct for aSID
|
||||
NS_HIDDEN_(void) SetStyle(nsStyleStructID aSID, void* aStruct);
|
||||
|
||||
@@ -243,7 +285,7 @@ protected:
|
||||
#undef STYLE_STRUCT_RESET
|
||||
#undef STYLE_STRUCT_INHERITED
|
||||
|
||||
nsStyleContext* const mParent;
|
||||
nsStyleContext* const mParent; // STRONG
|
||||
|
||||
// Children are kept in two circularly-linked lists. The list anchor
|
||||
// is not part of the list (null for empty), and we point to the first
|
||||
@@ -256,6 +298,11 @@ protected:
|
||||
nsStyleContext* mPrevSibling;
|
||||
nsStyleContext* mNextSibling;
|
||||
|
||||
// Style to be used instead for the R, G, and B components of color,
|
||||
// background-color, and border-*-color if the nearest ancestor link
|
||||
// element is visited (see RelevantLinkVisited()).
|
||||
nsRefPtr<nsStyleContext> mStyleIfVisited;
|
||||
|
||||
// If this style context is for a pseudo-element or anonymous box,
|
||||
// the relevant atom.
|
||||
nsCOMPtr<nsIAtom> mPseudoTag;
|
||||
|
||||
@@ -84,6 +84,8 @@ class imgIContainer;
|
||||
#define NS_STYLE_HAS_TEXT_DECORATIONS 0x01000000
|
||||
// See nsStyleContext::HasPseudoElementData.
|
||||
#define NS_STYLE_HAS_PSEUDO_ELEMENT_DATA 0x02000000
|
||||
// See nsStyleContext::RelevantLinkIsVisited
|
||||
#define NS_STYLE_RELEVANT_LINK_VISITED 0x04000000
|
||||
// See nsStyleContext::GetPseudoEnum
|
||||
#define NS_STYLE_CONTEXT_TYPE_MASK 0xf0000000
|
||||
#define NS_STYLE_CONTEXT_TYPE_SHIFT 28
|
||||
|
||||
Reference in New Issue
Block a user