Commit 04d4b7d8 authored by Nicolás Peña Moreno's avatar Nicolás Peña Moreno Committed by Commit Bot

[ElementTiming] Improve inline image behavior

This CL does the following changes for inline images (images with data
URIs):
* Trim the |name| to a max 100 chars.
* Do not apply the Timing-Allow-Origin check: assume it passes.

Bug: 879270
Change-Id: I58b67cb96bea11a78d0bb60af609db8459917df0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1555006Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Nicolás Peña Moreno <npm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#650482}
parent ac68afce
......@@ -25,6 +25,10 @@ namespace blink {
// TODO(npm): decide on a reasonable value for the threshold.
constexpr const float kImageTimingSizeThreshold = 0.15f;
// The maximum amount of characters included in Element Timing for inline
// images.
constexpr const unsigned kInlineImageMaxChars = 100u;
// static
const char ImageElementTiming::kSupplementName[] = "ImageElementTiming";
......@@ -81,9 +85,13 @@ void ImageElementTiming::NotifyImagePaintedInternal(
const AtomicString& id = element->GetIdAttribute();
const KURL& url = cached_image.Url();
DCHECK(GetSupplementable()->document() == &layout_object.GetDocument());
DCHECK(layout_object.GetDocument().GetSecurityOrigin());
if (!Performance::PassesTimingAllowCheck(
// It's ok to expose rendering timestamp for data URIs so exclude those from
// the Timing-Allow-Origin check.
if (!url.ProtocolIsData() &&
!Performance::PassesTimingAllowCheck(
cached_image.GetResponse(),
*layout_object.GetDocument().GetSecurityOrigin(),
&layout_object.GetDocument())) {
......@@ -94,15 +102,22 @@ void ImageElementTiming::NotifyImagePaintedInternal(
performance->ShouldBufferEntries())) {
// Create an entry with a |startTime| of 0.
performance->AddElementTiming(
AtomicString(cached_image.Url().GetString()), intersection_rect,
TimeTicks(), cached_image.LoadResponseEnd(), attr,
AtomicString(url.GetString()), intersection_rect, TimeTicks(),
cached_image.LoadResponseEnd(), attr,
cached_image.IntrinsicSize(kDoNotRespectImageOrientation), id);
}
return;
}
// If the image URL is a data URL ("data:image/..."), then the |name| of the
// PerformanceElementTiming entry should be the URL trimmed to 100 characters.
// If it is not, then pass in the full URL regardless of the length to be
// consistent with Resource Timing.
const String& image_name = url.ProtocolIsData()
? url.GetString().Left(kInlineImageMaxChars)
: url.GetString();
element_timings_.emplace_back(
AtomicString(cached_image.Url().GetString()), intersection_rect,
AtomicString(image_name), intersection_rect,
cached_image.LoadResponseEnd(), attr,
cached_image.IntrinsicSize(kDoNotRespectImageOrientation), id);
// Only queue a swap promise when |element_timings_| was empty. All of the
......
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Element Timing: observe element with inline background image</title>
<body>
<style>
body {
margin: 0;
}
#target {
width: 100px;
height: 50px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEX/AAD///9BHTQRAAAAAWJLR0QB/wIt3gAAAAtJREFUCNdjYMAHAAAeAAFuhUcyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTA0LTA1VDIwOjA4OjQxKzAyOjAwPa6EZwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wNC0wNVQyMDowODo0MSswMjowMEzzPNsAAAAASUVORK5CYII=);
}
</style>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/element-timing-helpers.js"></script>
<script>
let beforeRender = performance.now();
async_test(function (t) {
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
// Only the first characters of the data URI are included in the entry.
const uriPrefix = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAA';
checkElementWithoutResourceTiming(entry, uriPrefix, 'my_div', 'target',
beforeRender);
// The background image is a red square of length 10.
checkRect(entry, [0, 100, 0, 50]);
checkNaturalSize(entry, 10, 10);
})
);
observer.observe({entryTypes: ['element']});
}, 'Element with elementtiming attribute and inline background image is observable.');
</script>
<div id='target' elementtiming='my_div'></div>
</body>
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Element Timing: observe inline image</title>
<body>
<style>
body {
margin: 0;
}
#inline_wee {
display: block;
}
</style>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/element-timing-helpers.js"></script>
<script>
let beforeRender = performance.now();
async_test(function (t) {
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
// Only the first characters of the data URI are included in the entry.
const uriPrefix = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAA';
checkElementWithoutResourceTiming(entry, uriPrefix, 'my_img', 'inline_wee',
beforeRender);
// The image is a red square of length 10.
checkRect(entry, [0, 10, 0, 10]);
checkNaturalSize(entry, 10, 10);
})
);
observer.observe({entryTypes: ['element']});
}, 'Inline image is observable via Element Timing.');
</script>
<img elementtiming='my_img' id='inline_wee' src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEX/AAD///9BHTQRAAAAAWJLR0QB/wIt3gAAAAtJREFUCNdjYMAHAAAeAAFuhUcyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTA0LTA1VDIwOjA4OjQxKzAyOjAwPa6EZwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wNC0wNVQyMDowODo0MSswMjowMEzzPNsAAAAASUVORK5CYII="/>
</body>
......@@ -13,6 +13,19 @@ function checkElement(entry, expectedName, expectedIdentifier, expectedID, befor
assert_equals(rt_entries[0].responseEnd, entry.responseEnd);
}
function checkElementWithoutResourceTiming(entry, expectedName, expectedIdentifier,
expectedID, beforeRender) {
assert_equals(entry.entryType, 'element');
assert_equals(entry.name, expectedName);
assert_equals(entry.identifier, expectedIdentifier);
assert_equals(entry.duration, 0);
assert_equals(entry.id, expectedID);
assert_greater_than_equal(entry.startTime, beforeRender);
assert_greater_than_equal(performance.now(), entry.startTime);
// No associated resource from ResourceTiming, so the responseEnd should be 0.
assert_equals(entry.responseEnd, 0);
}
// Checks that the rect matches the desired values [left right top bottom].
function checkRect(entry, expected, description="") {
assert_equals(entry.intersectionRect.left, expected[0],
......
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