mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-25 08:37:30 +09:00
Issue #2736 - Part 5: Re-work img <srcset> attribute.
Use subject principal as triggering principal in <img> "srcset" attribute.
This commit is contained in:
parent
c8db9efb3c
commit
2bdb9f3d85
5 changed files with 69 additions and 16 deletions
|
|
@ -115,7 +115,8 @@ ResponsiveImageSelector::~ResponsiveImageSelector()
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#processing-the-image-candidates
|
// http://www.whatwg.org/specs/web-apps/current-work/#processing-the-image-candidates
|
||||||
bool
|
bool
|
||||||
ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet)
|
ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet,
|
||||||
|
nsIPrincipal* aTriggeringPrincipal)
|
||||||
{
|
{
|
||||||
ClearSelectedCandidate();
|
ClearSelectedCandidate();
|
||||||
|
|
||||||
|
|
@ -167,6 +168,8 @@ ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet)
|
||||||
ResponsiveImageCandidate candidate;
|
ResponsiveImageCandidate candidate;
|
||||||
if (candidate.ConsumeDescriptors(iter, end)) {
|
if (candidate.ConsumeDescriptors(iter, end)) {
|
||||||
candidate.SetURLSpec(urlStr);
|
candidate.SetURLSpec(urlStr);
|
||||||
|
candidate.SetTriggeringPrincipal(nsContentUtils::GetAttrTriggeringPrincipal(
|
||||||
|
Content(), urlStr, aTriggeringPrincipal));
|
||||||
AppendCandidateIfUnique(candidate);
|
AppendCandidateIfUnique(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +210,8 @@ ResponsiveImageSelector::Document()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString)
|
ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString,
|
||||||
|
nsIPrincipal* aPrincipal)
|
||||||
{
|
{
|
||||||
ClearSelectedCandidate();
|
ClearSelectedCandidate();
|
||||||
|
|
||||||
|
|
@ -219,6 +223,7 @@ ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString)
|
||||||
}
|
}
|
||||||
|
|
||||||
mDefaultSourceURL = aURLString;
|
mDefaultSourceURL = aURLString;
|
||||||
|
mDefaultSourceTriggeringPrincipal = aPrincipal;
|
||||||
|
|
||||||
// Add new default to end of list
|
// Add new default to end of list
|
||||||
MaybeAppendDefaultCandidate();
|
MaybeAppendDefaultCandidate();
|
||||||
|
|
@ -291,8 +296,9 @@ ResponsiveImageSelector::MaybeAppendDefaultCandidate()
|
||||||
ResponsiveImageCandidate defaultCandidate;
|
ResponsiveImageCandidate defaultCandidate;
|
||||||
defaultCandidate.SetParameterDefault();
|
defaultCandidate.SetParameterDefault();
|
||||||
defaultCandidate.SetURLSpec(mDefaultSourceURL);
|
defaultCandidate.SetURLSpec(mDefaultSourceURL);
|
||||||
|
defaultCandidate.SetTriggeringPrincipal(mDefaultSourceTriggeringPrincipal);
|
||||||
// We don't use MaybeAppend since we want to keep this even if it can never
|
// We don't use MaybeAppend since we want to keep this even if it can never
|
||||||
// match, as it may if the source set changes.
|
// match, because as it may match if the source set changes dynamically.
|
||||||
mCandidates.AppendElement(defaultCandidate);
|
mCandidates.AppendElement(defaultCandidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,6 +335,17 @@ ResponsiveImageSelector::GetSelectedImageDensity()
|
||||||
return mCandidates[bestIndex].Density(this);
|
return mCandidates[bestIndex].Density(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIPrincipal*
|
||||||
|
ResponsiveImageSelector::GetSelectedImageTriggeringPrincipal()
|
||||||
|
{
|
||||||
|
int bestIndex = GetSelectedCandidateIndex();
|
||||||
|
if (bestIndex < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCandidates[bestIndex].TriggeringPrincipal();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ResponsiveImageSelector::SelectImage(bool aReselect)
|
ResponsiveImageSelector::SelectImage(bool aReselect)
|
||||||
{
|
{
|
||||||
|
|
@ -457,8 +474,10 @@ ResponsiveImageCandidate::ResponsiveImageCandidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsiveImageCandidate::ResponsiveImageCandidate(const nsAString& aURLString,
|
ResponsiveImageCandidate::ResponsiveImageCandidate(const nsAString& aURLString,
|
||||||
double aDensity)
|
double aDensity,
|
||||||
|
nsIPrincipal* aTriggeringPrincipal)
|
||||||
: mURLString(aURLString)
|
: mURLString(aURLString)
|
||||||
|
, mTriggeringPrincipal(aTriggeringPrincipal)
|
||||||
{
|
{
|
||||||
mType = eCandidateType_Density;
|
mType = eCandidateType_Density;
|
||||||
mValue.mDensity = aDensity;
|
mValue.mDensity = aDensity;
|
||||||
|
|
@ -471,6 +490,12 @@ ResponsiveImageCandidate::SetURLSpec(const nsAString& aURLString)
|
||||||
mURLString = aURLString;
|
mURLString = aURLString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ResponsiveImageCandidate::SetTriggeringPrincipal(nsIPrincipal* aPrincipal)
|
||||||
|
{
|
||||||
|
mTriggeringPrincipal = aPrincipal;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ResponsiveImageCandidate::SetParameterAsComputedWidth(int32_t aWidth)
|
ResponsiveImageCandidate::SetParameterAsComputedWidth(int32_t aWidth)
|
||||||
{
|
{
|
||||||
|
|
@ -717,6 +742,12 @@ ResponsiveImageCandidate::URLString() const
|
||||||
return mURLString;
|
return mURLString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIPrincipal*
|
||||||
|
ResponsiveImageCandidate::TriggeringPrincipal() const
|
||||||
|
{
|
||||||
|
return mTriggeringPrincipal;
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
ResponsiveImageCandidate::Density(ResponsiveImageSelector *aSelector) const
|
ResponsiveImageCandidate::Density(ResponsiveImageSelector *aSelector) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,16 @@ public:
|
||||||
|
|
||||||
// Given a srcset string, parse and replace current candidates (does not
|
// Given a srcset string, parse and replace current candidates (does not
|
||||||
// replace default source)
|
// replace default source)
|
||||||
bool SetCandidatesFromSourceSet(const nsAString & aSrcSet);
|
bool SetCandidatesFromSourceSet(const nsAString & aSrcSet,
|
||||||
|
nsIPrincipal* aTriggeringPrincipal = nullptr);
|
||||||
|
|
||||||
// Fill the source sizes from a valid sizes descriptor. Returns false if
|
// Fill the source sizes from a valid sizes descriptor. Returns false if
|
||||||
// descriptor is invalid.
|
// descriptor is invalid.
|
||||||
bool SetSizesFromDescriptor(const nsAString & aSizesDescriptor);
|
bool SetSizesFromDescriptor(const nsAString & aSizesDescriptor);
|
||||||
|
|
||||||
// Set the default source, treated as the least-precedence 1.0 density source.
|
// Set the default source, treated as the least-precedence 1.0 density source.
|
||||||
void SetDefaultSource(const nsAString& aURLString);
|
void SetDefaultSource(const nsAString& aURLString,
|
||||||
|
nsIPrincipal* aPrincipal = nullptr);
|
||||||
|
|
||||||
uint32_t NumCandidates(bool aIncludeDefault = true);
|
uint32_t NumCandidates(bool aIncludeDefault = true);
|
||||||
|
|
||||||
|
|
@ -69,6 +71,7 @@ public:
|
||||||
// Returns false if there is no selected image
|
// Returns false if there is no selected image
|
||||||
bool GetSelectedImageURLSpec(nsAString& aResult);
|
bool GetSelectedImageURLSpec(nsAString& aResult);
|
||||||
double GetSelectedImageDensity();
|
double GetSelectedImageDensity();
|
||||||
|
nsIPrincipal* GetSelectedImageTriggeringPrincipal();
|
||||||
|
|
||||||
// Runs image selection now if necessary. If an image has already
|
// Runs image selection now if necessary. If an image has already
|
||||||
// been choosen, takes no action unless aReselect is true.
|
// been choosen, takes no action unless aReselect is true.
|
||||||
|
|
@ -107,6 +110,7 @@ private:
|
||||||
nsCOMPtr<nsINode> mOwnerNode;
|
nsCOMPtr<nsINode> mOwnerNode;
|
||||||
// The cached URL for default candidate.
|
// The cached URL for default candidate.
|
||||||
nsString mDefaultSourceURL;
|
nsString mDefaultSourceURL;
|
||||||
|
nsCOMPtr<nsIPrincipal> mDefaultSourceTriggeringPrincipal;
|
||||||
// If this array contains an eCandidateType_Default, it should be the last
|
// If this array contains an eCandidateType_Default, it should be the last
|
||||||
// element, such that the Setters can preserve/replace it respectively.
|
// element, such that the Setters can preserve/replace it respectively.
|
||||||
nsTArray<ResponsiveImageCandidate> mCandidates;
|
nsTArray<ResponsiveImageCandidate> mCandidates;
|
||||||
|
|
@ -122,9 +126,11 @@ private:
|
||||||
class ResponsiveImageCandidate {
|
class ResponsiveImageCandidate {
|
||||||
public:
|
public:
|
||||||
ResponsiveImageCandidate();
|
ResponsiveImageCandidate();
|
||||||
ResponsiveImageCandidate(const nsAString& aURLString, double aDensity);
|
ResponsiveImageCandidate(const nsAString& aURLString, double aDensity,
|
||||||
|
nsIPrincipal* aTriggeringPrincipal = nullptr);
|
||||||
|
|
||||||
void SetURLSpec(const nsAString& aURLString);
|
void SetURLSpec(const nsAString& aURLString);
|
||||||
|
void SetTriggeringPrincipal(nsIPrincipal* aPrincipal);
|
||||||
// Set this as a default-candidate. This behaves the same as density 1.0, but
|
// Set this as a default-candidate. This behaves the same as density 1.0, but
|
||||||
// has a differing type such that it can be replaced by subsequent
|
// has a differing type such that it can be replaced by subsequent
|
||||||
// SetDefaultSource calls.
|
// SetDefaultSource calls.
|
||||||
|
|
@ -147,6 +153,7 @@ public:
|
||||||
bool HasSameParameter(const ResponsiveImageCandidate & aOther) const;
|
bool HasSameParameter(const ResponsiveImageCandidate & aOther) const;
|
||||||
|
|
||||||
const nsAString& URLString() const;
|
const nsAString& URLString() const;
|
||||||
|
nsIPrincipal* TriggeringPrincipal() const;
|
||||||
|
|
||||||
// Compute and return the density relative to a selector.
|
// Compute and return the density relative to a selector.
|
||||||
double Density(ResponsiveImageSelector *aSelector) const;
|
double Density(ResponsiveImageSelector *aSelector) const;
|
||||||
|
|
@ -171,6 +178,7 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
nsString mURLString;
|
nsString mURLString;
|
||||||
|
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||||
eCandidateType mType;
|
eCandidateType mType;
|
||||||
union {
|
union {
|
||||||
double mDensity;
|
double mDensity;
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||||
}
|
}
|
||||||
} else if (aName == nsGkAtoms::srcset &&
|
} else if (aName == nsGkAtoms::srcset &&
|
||||||
aNameSpaceID == kNameSpaceID_None) {
|
aNameSpaceID == kNameSpaceID_None) {
|
||||||
|
mSrcsetTriggeringPrincipal = aMaybeScriptedPrincipal;
|
||||||
PictureSourceSrcsetChanged(this, attrVal.String(), aNotify);
|
PictureSourceSrcsetChanged(this, attrVal.String(), aNotify);
|
||||||
} else if (aName == nsGkAtoms::sizes &&
|
} else if (aName == nsGkAtoms::sizes &&
|
||||||
aNameSpaceID == kNameSpaceID_None) {
|
aNameSpaceID == kNameSpaceID_None) {
|
||||||
|
|
@ -481,7 +482,7 @@ HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||||
if (InResponsiveMode()) {
|
if (InResponsiveMode()) {
|
||||||
if (mResponsiveSelector &&
|
if (mResponsiveSelector &&
|
||||||
mResponsiveSelector->Content() == this) {
|
mResponsiveSelector->Content() == this) {
|
||||||
mResponsiveSelector->SetDefaultSource(aValue.String());
|
mResponsiveSelector->SetDefaultSource(aValue.String(), mSrcTriggeringPrincipal);
|
||||||
}
|
}
|
||||||
QueueImageLoadTask(true);
|
QueueImageLoadTask(true);
|
||||||
} else if (aNotify && OwnerDoc()->IsCurrentActiveDocument()) {
|
} else if (aNotify && OwnerDoc()->IsCurrentActiveDocument()) {
|
||||||
|
|
@ -1000,13 +1001,14 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
|
||||||
double currentDensity = 1.0; // default to 1.0 for the src attribute case
|
double currentDensity = 1.0; // default to 1.0 for the src attribute case
|
||||||
if (mResponsiveSelector) {
|
if (mResponsiveSelector) {
|
||||||
nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL();
|
nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL();
|
||||||
|
nsCOMPtr<nsIPrincipal> triggeringPrincipal = mResponsiveSelector->GetSelectedImageTriggeringPrincipal();
|
||||||
selectedSource = url;
|
selectedSource = url;
|
||||||
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
|
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
|
||||||
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) {
|
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
if (url) {
|
if (url) {
|
||||||
rv = LoadImage(url, aForce, aNotify, eImageLoadType_Imageset);
|
rv = LoadImage(url, aForce, aNotify, eImageLoadType_Imageset, triggeringPrincipal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nsAutoString src;
|
nsAutoString src;
|
||||||
|
|
@ -1055,7 +1057,11 @@ HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode,
|
||||||
if (aSourceNode == currentSrc) {
|
if (aSourceNode == currentSrc) {
|
||||||
// We're currently using this node as our responsive selector
|
// We're currently using this node as our responsive selector
|
||||||
// source.
|
// source.
|
||||||
mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue);
|
nsCOMPtr<nsIPrincipal> principal;
|
||||||
|
if (aSourceNode == this) {
|
||||||
|
principal = mSrcsetTriggeringPrincipal;
|
||||||
|
}
|
||||||
|
mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue, principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mInDocResponsiveContent && IsInComposedDoc()) {
|
if (!mInDocResponsiveContent && IsInComposedDoc()) {
|
||||||
|
|
@ -1240,6 +1246,8 @@ HTMLImageElement::SourceElementMatches(nsIContent* aSourceNode)
|
||||||
bool
|
bool
|
||||||
HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode)
|
HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode)
|
||||||
{
|
{
|
||||||
|
nsCOMPtr<nsIPrincipal> principal;
|
||||||
|
|
||||||
// Skip if this is not a <source> with matching media query
|
// Skip if this is not a <source> with matching media query
|
||||||
bool isSourceTag = aSourceNode->IsHTMLElement(nsGkAtoms::source);
|
bool isSourceTag = aSourceNode->IsHTMLElement(nsGkAtoms::source);
|
||||||
if (isSourceTag) {
|
if (isSourceTag) {
|
||||||
|
|
@ -1249,6 +1257,7 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode)
|
||||||
} else if (aSourceNode->IsHTMLElement(nsGkAtoms::img)) {
|
} else if (aSourceNode->IsHTMLElement(nsGkAtoms::img)) {
|
||||||
// Otherwise this is the <img> tag itself
|
// Otherwise this is the <img> tag itself
|
||||||
MOZ_ASSERT(aSourceNode == this);
|
MOZ_ASSERT(aSourceNode == this);
|
||||||
|
principal = mSrcsetTriggeringPrincipal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if has no srcset or an empty srcset
|
// Skip if has no srcset or an empty srcset
|
||||||
|
|
@ -1264,8 +1273,8 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode)
|
||||||
|
|
||||||
// Try to parse
|
// Try to parse
|
||||||
RefPtr<ResponsiveImageSelector> sel = new ResponsiveImageSelector(aSourceNode);
|
RefPtr<ResponsiveImageSelector> sel = new ResponsiveImageSelector(aSourceNode);
|
||||||
if (!sel->SetCandidatesFromSourceSet(srcset)) {
|
if (!sel->SetCandidatesFromSourceSet(srcset, principal)) {
|
||||||
// No possible candidates, don't need to bother parsing sizes
|
// No possible candidates; no need to bother parsing sizes
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1278,7 +1287,7 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode)
|
||||||
MOZ_ASSERT(aSourceNode == this);
|
MOZ_ASSERT(aSourceNode == this);
|
||||||
nsAutoString src;
|
nsAutoString src;
|
||||||
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) && !src.IsEmpty()) {
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) && !src.IsEmpty()) {
|
||||||
sel->SetDefaultSource(src);
|
sel->SetDefaultSource(src, mSrcTriggeringPrincipal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,13 @@ public:
|
||||||
{
|
{
|
||||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
|
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
|
||||||
}
|
}
|
||||||
void SetSrcset(const nsAString& aSrcset, ErrorResult& aError)
|
void GetSrcset(nsAString& aSrcset, nsIPrincipal&)
|
||||||
{
|
{
|
||||||
SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aError);
|
GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
|
||||||
|
}
|
||||||
|
void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||||
|
{
|
||||||
|
SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError);
|
||||||
}
|
}
|
||||||
void GetCrossOrigin(nsAString& aResult)
|
void GetCrossOrigin(nsAString& aResult)
|
||||||
{
|
{
|
||||||
|
|
@ -387,6 +391,7 @@ private:
|
||||||
bool mInDocResponsiveContent;
|
bool mInDocResponsiveContent;
|
||||||
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
||||||
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
|
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
|
||||||
|
nsCOMPtr<nsIPrincipal> mSrcsetTriggeringPrincipal;
|
||||||
|
|
||||||
// Last URL that was attempted to load by this element.
|
// Last URL that was attempted to load by this element.
|
||||||
nsCOMPtr<nsIURI> mLastSelectedSource;
|
nsCOMPtr<nsIURI> mLastSelectedSource;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ interface HTMLImageElement : HTMLElement {
|
||||||
attribute DOMString alt;
|
attribute DOMString alt;
|
||||||
[CEReactions, NeedsSubjectPrincipal, SetterThrows]
|
[CEReactions, NeedsSubjectPrincipal, SetterThrows]
|
||||||
attribute DOMString src;
|
attribute DOMString src;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, NeedsSubjectPrincipal, SetterThrows]
|
||||||
attribute DOMString srcset;
|
attribute DOMString srcset;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString? crossOrigin;
|
attribute DOMString? crossOrigin;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue