Commit 03b4fcd9 authored by Ehsan Karamad's avatar Ehsan Karamad Committed by Commit Bot

Apply 'lazyload' feature policy for images

In CL 1171374 'lazyload' feature policy was introduced as a new
policy-controlled feature which would modify (restrict) the usage of the
lazyload attribute. The implementation only applied the feature to frame
owner elements. This CL extends the policy's coverage to images as well.

Bug: 869492
Change-Id: I9a2bd309ac366b75308b657d3ea129a7717ad23f
Reviewed-on: https://chromium-review.googlesource.com/c/1251024
Commit-Queue: Ehsan Karamad <ekaramad@chromium.org>
Reviewed-by: default avatarFredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarrajendrant <rajendrant@chromium.org>
Cr-Commit-Position: refs/heads/master@{#599204}
parent 0edf161e
......@@ -1919,6 +1919,18 @@ http/tests/cachestorage/large-put.html [ WontFix ]
crbug.com/846170 http/tests/lazyload/lazy.html [ WontFix ]
crbug.com/846170 http/tests/lazyload/attribute.html [ WontFix ]
crbug.com/846170 http/tests/lazyload/fixed-dimension.html [ WontFix ]
crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-image-tentative.html [ WontFix ]
crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html [ WontFix ]
crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazyload-image-attribute-on-sanity-check-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-image-tentative.html [ WontFix ]
crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/lazyload-image-attribute-on-sanity-check-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-image-tentative.html [ WontFix ]
crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-image-attribute-on-sanity-check-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-image-tentative.html [ WontFix ]
crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html [ WontFix ]
crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-image-attribute-on-sanity-check-tentative.sub.html [ WontFix ]
# Tests that are not supported if outofblink-cors feature is enabled.
# These functionarities should be verified on browser_tests for outofblink-cors.
......
......@@ -768,7 +768,7 @@
{
"prefix" : "lazyload-policy",
"base": "external/wpt/feature-policy/experimental-features/lazyload",
"args": ["--enable-blink-features=LazyFrameLoading"]
"args": ["--enable-blink-features=LazyFrameLoading,LazyImageLoading"]
},
{
"prefix": "display-lock",
......
<!doctype html>
<meta charset=utf-8>
<title>Verify behavior of 'lazyload' attribute state 'OFF' when the feature policy 'lazyload' is
disabled.
</title>
<link rel="stylesheet" href="/feature-policy/experimental-features/resources/lazyload-image.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/experimental-features/resources/common.js"></script>
<style>
body {
width: 100%;
height: 100%;
}
img {
width: 200px;
height: 200px;
border: solid 1px black;
}
#image-container {
position: absolute;
top: 400%;
}
</style>
<body>
<p>Image inserted further below.</p>
<div id="image-container">
<img id="off" lazyload="off" src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"></img>
<img id="auto" lazyload="auto" src="http://{{hosts[alt][www2]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"></img>
</div>
<script>
var img_off = document.getElementById("off");
var img_auto = document.getElementById("auto");
[window, img_off, img_auto].forEach((target) => {
target.load_complete = wait_for_load(target).then(() => target.did_load = true );
});
function images_loaded() {
return img_off.did_load && img_auto.did_load;
}
function same_load_state() {
return img_off.did_load === img_auto.did_load;
}
// Verifies that "off" and "auto" behave the same for out-of-view images.
promise_test(async(t) => {
await window.load_complete;
assert_true(same_load_state(), "Expected same loading state for both images.");
}, "When the 'lazyload' feature is disabled, lazyload=OFF and lazyload=AUTO behave the same.");
// Verifies that images with attributes "off" and "auto" load after the images get into view.
promise_test(async(t) => {
document.getElementById("image-container").scrollIntoView();
await img_off.load_complete;
await img_auto.load_complete;
}, "Sanity-check: Verify that all images load after they are scrolled into view.");
</script>
</body>
\ No newline at end of file
<!doctype html>
<meta charset=utf-8>
<title>Verify behavior of 'lazyload' attribute state 'OFF' when the feature policy 'lazyload' is
enabled.
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/experimental-features/resources/common.js"></script>
<style>
body {
width: 100%;
height: 100%;
}
img {
width: 200px;
height: 200px;
border: solid 1px black;
}
#image-container {
position: absolute;
top: 400%;
}
</style>
<body>
<p>Image inserted further below.</p>
<div id="image-container">
<img id="off" lazyload="off" src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"></img>
</div>
<script>
var img = document.querySelector("img");
[img, window].forEach((target) => {
target.load_complete = wait_for_load(target).then(() => target.did_load = true );
});
// Sanity-check: Verify that when feature-policy 'lazyload' is enabled, the lazyload attribute
// value 'OFF' works as expected (images load immediately).
promise_test( async(t) => {
await window.load_complete;
assert_true(img.did_load, "Image should have loaded.");
}, "When feature is enabled, lazyload=OFF works as expected.");
</script>
</body>
\ No newline at end of file
<!doctype html>
<meta charset=utf-8>
<title>Verify behavior of 'lazyload' attribute state 'ON' (sanity-check for lazyload policy tests).
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/experimental-features/resources/common.js"></script>
<style>
body {
width: 100%;
height: 100%;
}
img {
width: 200px;
height: 200px;
border: solid 1px black;
}
#image-container {
position: absolute;
top: 400%;
}
</style>
<body>
<p>Image inserted further below.</p>
<div id="image-container">
<img lazyload="on" src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"/>
</div>
<script>
var img = document.querySelector("img");
[img, window].forEach((target) => {
target.did_load = false;
target.load_complete = wait_for_load(target).then(() => target.did_load = true );
});
// Sanity-check: Verify that when feature-policy 'lazyload' is enabled, the lazyload attribute
// value 'OFF' works as expected (images load immediately).
promise_test( async(t) => {
await window.load_complete;
assert_false(img.did_load, "Out-of-viewport image should not have loaded.");
img.scrollIntoView();
await img.load_complete;
}, "Verify 'lazyload' attribute state 'on' works as expected: image loads only when in " +
"viewport.");
</script>
</body>
\ No newline at end of file
......@@ -58,3 +58,10 @@ function createIframe(container, attributes) {
container.appendChild(new_iframe);
return new_iframe;
}
// Returns a promise which is resolved when |load| event is dispatched for |e|.
function wait_for_load(e) {
return new Promise((resolve) => {
e.addEventListener("load", resolve);
});
}
\ No newline at end of file
......@@ -313,7 +313,8 @@ void HTMLImageElement::ParseAttribute(
GetLayoutObject()->IsLayoutImage())
ToLayoutImage(GetLayoutObject())->IntrinsicSizeChanged();
} else if (name == lazyloadAttr &&
EqualIgnoringASCIICase(params.new_value, "off")) {
EqualIgnoringASCIICase(params.new_value, "off") &&
!GetDocument().IsLazyLoadPolicyEnforced()) {
GetImageLoader().LoadDeferredImage(referrer_policy_);
} else {
HTMLElement::ParseAttribute(params);
......
......@@ -220,7 +220,7 @@ class TokenPreloadScanner::StartTagScanner {
const SegmentedString& source,
const ClientHintsPreferences& client_hints_preferences,
const PictureData& picture_data,
const ReferrerPolicy document_referrer_policy) {
const CachedDocumentParameters& document_parameters) {
PreloadRequest::RequestType request_type =
PreloadRequest::kRequestTypePreload;
base::Optional<ResourceType> type;
......@@ -266,8 +266,9 @@ class TokenPreloadScanner::StartTagScanner {
// The element's 'referrerpolicy' attribute (if present) takes precedence
// over the document's referrer policy.
ReferrerPolicy referrer_policy =
(referrer_policy_ != kReferrerPolicyDefault) ? referrer_policy_
: document_referrer_policy;
(referrer_policy_ != kReferrerPolicyDefault)
? referrer_policy_
: document_parameters.referrer_policy;
auto request = PreloadRequest::CreateIfNeeded(
InitiatorFor(tag_impl_), position, url_to_load_, predicted_base_url,
type.value(), referrer_policy, PreloadRequest::kDocumentIsReferrer,
......@@ -286,7 +287,10 @@ class TokenPreloadScanner::StartTagScanner {
request->SetCharset(Charset());
request->SetDefer(defer_);
if (lazyload_attr_set_to_off_ ||
// If the 'lazyload' feature policy is enforced, the attribute value "off"
// for the 'lazyload' attribute is considered as 'auto'.
if ((lazyload_attr_set_to_off_ &&
!document_parameters.lazyload_policy_enforced) ||
(width_attr_small_absolute_ && height_attr_small_absolute_)) {
request->SetIsLazyloadImageDisabled(true);
}
......@@ -901,7 +905,7 @@ void TokenPreloadScanner::ScanCommon(const Token& token,
scanner.HandlePictureSourceURL(picture_data_);
std::unique_ptr<PreloadRequest> request = scanner.CreatePreloadRequest(
predicted_base_element_url_, source, client_hints_preferences_,
picture_data_, document_parameters_->referrer_policy);
picture_data_, *document_parameters_);
if (request)
requests.push_back(std::move(request));
return;
......@@ -988,6 +992,7 @@ CachedDocumentParameters::CachedDocumentParameters(Document* document) {
document->GetSettings()->GetViewportMetaEnabled();
referrer_policy = document->GetReferrerPolicy();
integrity_features = SubresourceIntegrityHelper::GetFeatures(document);
lazyload_policy_enforced = document->IsLazyLoadPolicyEnforced();
}
} // namespace blink
......@@ -74,6 +74,7 @@ struct CORE_EXPORT CachedDocumentParameters {
bool viewport_meta_enabled;
ReferrerPolicy referrer_policy;
SubresourceIntegrity::IntegrityFeatures integrity_features;
bool lazyload_policy_enforced;
private:
explicit CachedDocumentParameters(Document*);
......
......@@ -85,9 +85,10 @@ bool IsLazyLoadingImageAllowed(const LocalFrame* frame,
return false;
if (EqualIgnoringASCIICase(
html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off"))
html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off") &&
!frame->GetDocument()->IsLazyLoadPolicyEnforced()) {
return false;
}
// Avoid lazyloading if width and height attributes are small. This
// heuristic helps avoid double fetching tracking pixels.
double width, height;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment