Closed Bug 1361274 Opened 7 years ago Closed 7 years ago

querySelectorAll should not call nsIDocument::FlushPendingLinkUpdates

Categories

(Core :: DOM: Core & HTML, defect)

36 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla55
Performance Impact ?
Tracking Status
firefox55 --- fixed

People

(Reporter: smaug, Assigned: bzbarsky)

References

Details

Attachments

(1 file, 2 obsolete files)

-nsINode::QuerySelectorAll(nsAString const&, mozilla::ErrorResult&)                       87.7%        1.8% 
 | +moz_xmalloc                                                                             1.8%        0.0%   
 | -nsCSSRuleProcessor::SelectorListMatches()                                              10.5%        0.0% 
 | |  SelectorMatches(                                                                      3.5%        3.5%   
 | | +SelectorMatchesTree()                                                                 7.0%        3.5%   
 | -nsIDocument::FlushPendingLinkUpdates()                                                 73.7%        0.0%   
 | | -mozilla::dom::Link::LinkState() const                                                71.9%        1.8%   
 | | | +PLDHashTable::Add(void const*)                                                      1.8%        0.0%   
 | | | -mozilla::dom::HTMLAnchorElement::GetHrefURI() const                                56.1%        0.0%   
 | | | |  nsCOMPtr_base::begin_assignment()                                                 1.8%        1.8%   
 | | | | -nsGenericHTMLElement::GetHrefURIForAnchors() const                               54.4%        0.0%   
 | | | | |  mozilla::net::nsStandardURL::Release()                                          1.8%        1.8%   
 | | | | | -nsGenericHTMLElement::GetURIAttr(nsIAtom*, nsIAtom*, nsIURI**) const           52.6%        1.8%   
 | | | | | | +NS_NewURI(nsIURI**, nsAString const&, char const*, nsIURI*, nsIIOService*)   33.3%        0.0%   
 | | | | | | +nsIContent::GetBaseURI(bool) const                                           14.0%        7.0%  
 | | | | | |  nsIDocument::GetBaseURI(bool) const                                           3.5%        3.5%  
 | | | +mozilla::places::History::RegisterVisitedCallback(nsIURI*, mozilla::dom::Link*)    12.3%        1.8%  
 | |  nsDocument::AddStyleRelevantLink(mozilla::dom::Link*)                                 1.7%        1.7%
Whiteboard: [qf]
Is the testcase basically inserting a bunch of links, then doing a querySelectoAll, then repeating that in a loop or something?

In any case, speeding up FlushPendingLinkUpdates is not trivial, because it has to do real work: get the attribute, parse the URI, etc, etc.

But why are we calling it from querySelectorAll at all?  The only point of FlushPendingLinkUpdates, I believe, is so we can tell apart :link and :visited.  But querySelectorAll treats all links as unvisited anyway.  It's possible the current setup was created before we stopped matching :visited in querySelectorAll.
Summary: nsIDocument::FlushPendingLinkUpdates is rather slow → querySelectorAll should not call nsIDocument::FlushPendingLinkUpdates
Assignee: nobody → bzbarsky
Status: NEW → ASSIGNED
Comment on attachment 8863983 [details] [diff] [review]
There's no need to update link :visited state when doing querySelectorAll, since querySelectorAll ignores that state anyway


>+  // TreeMatchContext constructor is to not call it all the time furing various

s/furing/during/
Comment on attachment 8863983 [details] [diff] [review]
There's no need to update link :visited state when doing querySelectorAll, since querySelectorAll ignores that state anyway

s/furing/during/

I guess change to nsComputedDOMStyle::UpdateCurrentStyleSources is ok, since
we don't flush link states anyhow before layout/style flushes.
And ElementRestyler::Restyle, nsCSSFrameConstructor::ResolveStyleContext etc. do link flushing.

But don't we need link flushing for :link to work?

I don't understand eNeverMatchVisited. That seems to be for the private browsing flag control.
Isn't eRelevantLinkUnvisited the key thing here? Am I confused here now?
Attachment #8863983 - Flags: review?(bugs)
> I guess change to nsComputedDOMStyle::UpdateCurrentStyleSources is ok

Right, because computed style never depends on :visited state: it always pretends the link only matched the :link rules.

> But don't we need link flushing for :link to work?

I don't believe we do.  Here's why, using HTMLAnchorElement as an example.

When it's first created, it calls the Link() constructor, which sets mLinkState to eLinkState_NotLink.  At his point neither NS_EVENT_STATE_VISITED nor NS_EVENT_STATE_UNVISITED is set, which means neither :link nor :visited is set, which is correct.

If the "href" attribute is now set (and in fact any time it's modified or removed), we will call Link::ResetLinkState (from HTMLAnchorElement::SetAttr/UnsetAttr).  ResetLinkState will always set mLinkState to defaultState, which is either eLinkState_Unvisited if we have an href attr or eLinkState_NotLink if we do not.  It will also make the relevant UpdateState/UpdateLinkState calls on the element to set NS_EVENT_STATE_UNVISITED on it.  So once the "href" attribute has been set, we'll be in NS_EVENT_STATE_UNVISITED and match :link.  The only thing we're waiting on FlishPendingLinkStates for at that point is maybe switching us to NS_EVENT_STATE_VISITED.

This didn't use to be the case back when <a href="something not parseable as URI"> was not considered to match :link, which is why the current setup is perhaps more complicated than it should be...

> I don't understand eNeverMatchVisited.

Ah, good catch.  This stuff could really use better documentation, which I will add.  But the summary is that eNeverMatchVisited is a promise that mVisitedHandling will _always_ be eRelevantLinkUnvisited for this TreeMatchContext.  And yes, eRelevantLinkUnvisited is the real key here.
Aha, didn't think (Un)SetAttr + ResetLinkState.
Attachment #8863983 - Attachment is obsolete: true
Attachment #8864130 - Attachment is obsolete: true
Comment on attachment 8864134 [details] [diff] [review]
With better comments and commit message

eNeverMatchVisited is still odd beast given how it just controls whether pb flag is checked.
Attachment #8864134 - Flags: review+
Pushed by bzbarsky@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/06d436f9330d
There's no need to update link :visited state when doing querySelectorAll, since querySelectorAll ignores that state anyway.  r=smaug
https://hg.mozilla.org/mozilla-central/rev/06d436f9330d
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
Performance Impact: --- → ?
Whiteboard: [qf]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: