Bug 1134648, handle dynamic changes to rel=dns-prefetch, r=bz

--HG--
extra : rebase_source : 817f331da1cfadb0833a14a3a18c5d4769752b79
This commit is contained in:
Olli Pettay 2015-12-01 19:22:20 +02:00
Родитель ff55707b83
Коммит cc8c87cbc0
7 изменённых файлов: 136 добавлений и 29 удалений

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

@ -14,6 +14,7 @@
#include "nsEscape.h"
#include "nsGkAtoms.h"
#include "nsHTMLDNSPrefetch.h"
#include "nsString.h"
#include "mozAutoDocUpdate.h"
@ -46,6 +47,31 @@ Link::ElementHasHref() const
mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)));
}
void
Link::TryDNSPrefetch()
{
MOZ_ASSERT(mElement->IsInComposedDoc());
if (ElementHasHref() && nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
nsHTMLDNSPrefetch::PrefetchLow(this);
}
}
void
Link::CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
nsWrapperCache::FlagsType aRequestedFlag)
{
// If prefetch was deferred, clear flag and move on
if (mElement->HasFlag(aDeferredFlag)) {
mElement->UnsetFlags(aDeferredFlag);
// Else if prefetch was requested, clear flag and send cancellation
} else if (mElement->HasFlag(aRequestedFlag)) {
mElement->UnsetFlags(aRequestedFlag);
// Possible that hostname could have changed since binding, but since this
// covers common cases, most DNS prefetch requests will be canceled
nsHTMLDNSPrefetch::CancelPrefetchLow(this, NS_ERROR_ABORT);
}
}
void
Link::SetLinkState(nsLinkState aState)
{

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

@ -111,6 +111,11 @@ public:
bool ElementHasHref() const;
void TryDNSPrefetch();
void CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
nsWrapperCache::FlagsType aRequestedFlag);
protected:
virtual ~Link();

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

@ -158,9 +158,7 @@ HTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIDocument* doc = GetComposedDoc();
if (doc) {
doc->RegisterPendingLinkUpdate(this);
if (nsHTMLDNSPrefetch::IsAllowed(OwnerDoc())) {
nsHTMLDNSPrefetch::PrefetchLow(this);
}
TryDNSPrefetch();
}
return rv;
@ -172,18 +170,9 @@ HTMLAnchorElement::UnbindFromTree(bool aDeep, bool aNullParent)
// Cancel any DNS prefetches
// Note: Must come before ResetLinkState. If called after, it will recreate
// mCachedURI based on data that is invalid - due to a call to GetHostname.
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
// If prefetch was deferred, clear flag and move on
if (HasFlag(HTML_ANCHOR_DNS_PREFETCH_DEFERRED))
UnsetFlags(HTML_ANCHOR_DNS_PREFETCH_DEFERRED);
// Else if prefetch was requested, clear flag and send cancellation
else if (HasFlag(HTML_ANCHOR_DNS_PREFETCH_REQUESTED)) {
UnsetFlags(HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
// Possible that hostname could have changed since binding, but since this
// covers common cases, most DNS prefetch requests will be canceled
nsHTMLDNSPrefetch::CancelPrefetchLow(this, NS_ERROR_ABORT);
}
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false, Link::ElementHasHref());
@ -406,6 +395,10 @@ HTMLAnchorElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
reset = true;
}
}
if (reset) {
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
}
}
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
@ -418,6 +411,9 @@ HTMLAnchorElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// to get updated information about the visitedness from Link.
if (reset) {
Link::ResetLinkState(!!aNotify, true);
if (IsInComposedDoc()) {
TryDNSPrefetch();
}
}
return rv;
@ -427,6 +423,14 @@ nsresult
HTMLAnchorElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
bool href =
(aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID);
if (href) {
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
}
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
aNotify);
@ -435,7 +439,7 @@ HTMLAnchorElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
// we will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
if (href) {
Link::ResetLinkState(!!aNotify, false);
}

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

@ -28,6 +28,22 @@
#include "nsStyleConsts.h"
#include "nsUnicharUtils.h"
#define LINK_ELEMENT_FLAG_BIT(n_) \
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
// Link element specific bits
enum {
// Indicates that a DNS Prefetch has been requested from this Link element.
HTML_LINK_DNS_PREFETCH_REQUESTED = LINK_ELEMENT_FLAG_BIT(0),
// Indicates that a DNS Prefetch was added to the deferral queue
HTML_LINK_DNS_PREFETCH_DEFERRED = LINK_ELEMENT_FLAG_BIT(1)
};
#undef LINK_ELEMENT_FLAG_BIT
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
NS_IMPL_NS_NEW_HTML_ELEMENT(Link)
namespace mozilla {
@ -126,6 +142,26 @@ HTMLLinkElement::SetItemValueText(const nsAString& aValue)
SetHref(aValue);
}
void
HTMLLinkElement::OnDNSPrefetchRequested()
{
UnsetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
SetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
}
void
HTMLLinkElement::OnDNSPrefetchDeferred()
{
UnsetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
SetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
}
bool
HTMLLinkElement::HasDeferredDNSPrefetchRequest()
{
return HasFlag(HTML_LINK_DNS_PREFETCH_DEFERRED);
}
nsresult
HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@ -145,6 +181,9 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
if (IsInComposedDoc()) {
UpdatePreconnect();
if (HasDNSPrefetchRel()) {
TryDNSPrefetch();
}
}
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
@ -173,6 +212,12 @@ HTMLLinkElement::LinkRemoved()
void
HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
// Cancel any DNS prefetches
// Note: Must come before ResetLinkState. If called after, it will recreate
// mCachedURI based on data that is invalid - due to a call to GetHostname.
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
HTML_LINK_DNS_PREFETCH_REQUESTED);
// If this link is ever reinserted into a document, it might
// be under a different xml:base, so forget the cached state now.
Link::ResetLinkState(false, Link::ElementHasHref());
@ -322,6 +367,32 @@ HTMLLinkElement::UpdatePreconnect()
}
}
bool
HTMLLinkElement::HasDNSPrefetchRel()
{
nsAutoString rel;
if (GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
return !!(ParseLinkTypes(rel, NodePrincipal()) &
nsStyleLinkElement::eDNS_PREFETCH);
}
return false;
}
nsresult
HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsAttrValueOrString* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href || aName == nsGkAtoms::rel)) {
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
HTML_LINK_DNS_PREFETCH_REQUESTED);
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
@ -368,6 +439,11 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
if ((aName == nsGkAtoms::rel || aName == nsGkAtoms::href) &&
HasDNSPrefetchRel() && IsInComposedDoc()) {
TryDNSPrefetch();
}
UpdateStyleSheetInternal(nullptr, nullptr,
dropSheet ||
(aName == nsGkAtoms::title ||

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

@ -61,6 +61,9 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
bool aNotify) override;
@ -77,6 +80,10 @@ public:
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
virtual void OnDNSPrefetchDeferred() override;
virtual void OnDNSPrefetchRequested() override;
virtual bool HasDeferredDNSPrefetchRequest() override;
// WebIDL
bool Disabled();
void SetDisabled(bool aDisabled);
@ -166,6 +173,9 @@ protected:
// nsGenericHTMLElement
virtual void GetItemValueText(DOMString& text) override;
virtual void SetItemValueText(const nsAString& text) override;
bool HasDNSPrefetchRel();
RefPtr<nsDOMTokenList > mRelList;
private:
RefPtr<ImportLoader> mImportLoader;

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

@ -611,13 +611,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
PrefetchHref(hrefVal, aContent, hasPrefetch);
}
}
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
}
}
}
}
}

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

@ -96,13 +96,6 @@ nsHtml5DocumentBuilder::UpdateStyleSheet(nsIContent* aElement)
PrefetchHref(hrefVal, aElement, hasPrefetch);
}
}
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
nsAutoString hrefVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
}
}
}
}