mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1240357 - Support crossOrigin attribute on image and feImage elements r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D174737
This commit is contained in:
parent
cfb6408c17
commit
12236086e3
@ -101,6 +101,19 @@ void SVGFEImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
|
||||
//----------------------------------------------------------------------
|
||||
// nsIContent methods:
|
||||
|
||||
bool SVGFEImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) {
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
return SVGFEImageElementBase::ParseAttribute(
|
||||
aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
|
||||
}
|
||||
|
||||
nsresult SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
@ -115,6 +128,12 @@ nsresult SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
} else {
|
||||
CancelImageRequests(aNotify);
|
||||
}
|
||||
} else if (aNamespaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::crossorigin) {
|
||||
if (aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue) &&
|
||||
ShouldLoadImage()) {
|
||||
ForceReload(aNotify, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
return SVGFEImageElementBase::AfterSetAttr(
|
||||
@ -177,6 +196,13 @@ already_AddRefed<DOMSVGAnimatedString> SVGFEImageElement::Href() {
|
||||
: mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsImageLoadingContent methods:
|
||||
|
||||
CORSMode SVGFEImageElement::GetCORSMode() {
|
||||
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGFEImageElement methods
|
||||
|
||||
|
@ -52,12 +52,20 @@ class SVGFEImageElement final : public SVGFEImageElementBase,
|
||||
SVGAnimatedString& GetResultImageName() override {
|
||||
return mStringAttributes[RESULT];
|
||||
}
|
||||
|
||||
// nsImageLoadingContent
|
||||
CORSMode GetCORSMode() override;
|
||||
|
||||
bool OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
|
||||
nsIPrincipal* aReferencePrincipal) override;
|
||||
|
||||
// nsIContent
|
||||
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) override;
|
||||
nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
|
||||
nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
|
||||
@ -76,6 +84,15 @@ class SVGFEImageElement final : public SVGFEImageElementBase,
|
||||
// WebIDL
|
||||
already_AddRefed<DOMSVGAnimatedString> Href();
|
||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||
void GetCrossOrigin(nsAString& aCrossOrigin) {
|
||||
// Null for both missing and invalid defaults is ok, since we
|
||||
// always parse to an enum value, so we don't need an invalid
|
||||
// default, and we _want_ the missing default to be null.
|
||||
GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aCrossOrigin);
|
||||
}
|
||||
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError) {
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult LoadSVGImage(bool aForce, bool aNotify);
|
||||
|
@ -174,6 +174,13 @@ void SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
|
||||
nsImageLoadingContent::AsyncEventRunning(aEvent);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsImageLoadingContent methods:
|
||||
|
||||
CORSMode SVGImageElement::GetCORSMode() {
|
||||
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIContent methods:
|
||||
|
||||
@ -182,6 +189,10 @@ bool SVGImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) {
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::crossorigin) {
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::decoding) {
|
||||
return aResult.ParseEnumValue(aValue, kDecodingTable, false,
|
||||
kDecodingTableDefault);
|
||||
@ -206,13 +217,20 @@ nsresult SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
} else {
|
||||
CancelImageRequests(aNotify);
|
||||
}
|
||||
} else if (aName == nsGkAtoms::decoding &&
|
||||
aNamespaceID == kNameSpaceID_None) {
|
||||
// Request sync or async image decoding.
|
||||
SetSyncDecodingHint(
|
||||
aValue && static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
|
||||
ImageDecodingType::Sync);
|
||||
} else if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::decoding) {
|
||||
// Request sync or async image decoding.
|
||||
SetSyncDecodingHint(
|
||||
aValue && static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
|
||||
ImageDecodingType::Sync);
|
||||
} else if (aName == nsGkAtoms::crossorigin) {
|
||||
if (aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue) &&
|
||||
ShouldLoadImage()) {
|
||||
ForceReload(aNotify, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SVGImageElementBase::AfterSetAttr(
|
||||
aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ class SVGImageElement final : public SVGImageElementBase,
|
||||
// EventTarget
|
||||
void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
// nsImageLoadingContent interface
|
||||
CORSMode GetCORSMode() override;
|
||||
|
||||
// nsIContent interface
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
@ -92,6 +95,15 @@ class SVGImageElement final : public SVGImageElementBase,
|
||||
already_AddRefed<DOMSVGAnimatedLength> Height();
|
||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||
already_AddRefed<DOMSVGAnimatedString> Href();
|
||||
void GetCrossOrigin(nsAString& aCrossOrigin) {
|
||||
// Null for both missing and invalid defaults is ok, since we
|
||||
// always parse to an enum value, so we don't need an invalid
|
||||
// default, and we _want_ the missing default to be null.
|
||||
GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aCrossOrigin);
|
||||
}
|
||||
void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError) {
|
||||
SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
|
||||
}
|
||||
|
||||
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
|
||||
SetAttr(nsGkAtoms::decoding, aDecoding, aError);
|
||||
|
@ -14,6 +14,8 @@
|
||||
interface SVGFEImageElement : SVGElement {
|
||||
[Constant]
|
||||
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
|
||||
[SetterThrows]
|
||||
attribute DOMString? crossOrigin;
|
||||
};
|
||||
|
||||
SVGFEImageElement includes SVGFilterPrimitiveStandardAttributes;
|
||||
|
@ -22,6 +22,8 @@ interface SVGImageElement : SVGGraphicsElement {
|
||||
readonly attribute SVGAnimatedLength height;
|
||||
[Constant]
|
||||
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
|
||||
[SetterThrows]
|
||||
attribute DOMString? crossOrigin;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString decoding;
|
||||
[NewObject]
|
||||
|
@ -1,14 +1,6 @@
|
||||
[svg-image.https.sub.html]
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[sec-fetch-mode attributes: crossorigin]
|
||||
expected: FAIL
|
||||
|
||||
[sec-fetch-mode attributes: crossorigin=anonymous]
|
||||
expected: FAIL
|
||||
|
||||
[sec-fetch-mode attributes: crossorigin=use-credentials]
|
||||
expected: FAIL
|
||||
|
||||
[sec-fetch-dest no attributes]
|
||||
expected: FAIL
|
||||
|
@ -230,12 +230,6 @@
|
||||
[SVGElement interface: objects.textPath must inherit property "correspondingUseElement" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[SVGImageElement interface: attribute crossOrigin]
|
||||
expected: FAIL
|
||||
|
||||
[SVGImageElement interface: objects.image must inherit property "crossOrigin" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[SVGElement interface: objects.image must inherit property "correspondingElement" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<title>Test Crossorigin</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/SVG/embedded.html#ImageElementCrossoriginAttribute">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function draw_and_read_image(image, should_throw) {
|
||||
let c = document.createElement('canvas');
|
||||
document.body.appendChild(c);
|
||||
let ctx = c.getContext('2d');
|
||||
ctx.drawImage(image, 0, 0);
|
||||
|
||||
function get_image_data() {
|
||||
ctx.getImageData(0, 0, 4, 4);
|
||||
}
|
||||
|
||||
if (should_throw) {
|
||||
assert_throws_dom('SecurityError', get_image_data);
|
||||
} else {
|
||||
get_image_data();
|
||||
}
|
||||
|
||||
document.body.removeChild(c);
|
||||
}
|
||||
|
||||
async_test(t => {
|
||||
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
||||
image.setAttribute("href", "/images/green.png");
|
||||
image.crossOrigin = "anonymous";
|
||||
image.onload = t.step_func_done(() => {
|
||||
draw_and_read_image(image, false);
|
||||
});
|
||||
image.onerror = t.unreached_func();
|
||||
}, "Can get pixels of canvas with same origin image drawn");
|
||||
|
||||
async_test(t => {
|
||||
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
||||
image.setAttribute("href", "http://{{hosts[][www]}}:{{ports[http][0]}}/images/green.png?pipe=header(Access-Control-Allow-Origin,*)");
|
||||
image.crossOrigin = "anonymous";
|
||||
image.onload = t.step_func_done(() => {
|
||||
draw_and_read_image(image, false);
|
||||
});
|
||||
image.onerror = t.unreached_func();
|
||||
}, "Can get pixels of canvas with CORS enabled cross origin image drawn");
|
||||
|
||||
async_test(t => {
|
||||
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
||||
image.setAttribute("href", "http://{{hosts[][www]}}:{{ports[http][0]}}/images/green.png?pipe=header(Access-Control-Allow-Origin,*)");
|
||||
image.onload = t.step_func_done(() => {
|
||||
draw_and_read_image(image, true);
|
||||
});
|
||||
image.onerror = t.unreached_func();
|
||||
}, "Can't get pixels of canvas with CORS enabled cross origin image drawn from non-CORS element");
|
||||
|
||||
async_test(t => {
|
||||
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
||||
image.setAttribute("href", "http://{{hosts[][www]}}:{{ports[http][0]}}/images/green.png");
|
||||
|
||||
image.onload = t.step_func_done(() => {
|
||||
draw_and_read_image(image, true);
|
||||
});
|
||||
image.onerror = t.unreached_func();
|
||||
}, "Can't get pixels of canvas with non-CORS enabled cross origin image drawn");
|
||||
|
||||
</script>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user