Commit 20d9207c authored by sunjian's avatar sunjian Committed by Commit bot

first-paint and first-contentful paint

BUG=657825
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2

Review-Url: https://codereview.chromium.org/2528513003
Cr-Commit-Position: refs/heads/master@{#443142}
parent e850e3f2
...@@ -79,6 +79,8 @@ Bug(none) webaudio/ [ Skip ] ...@@ -79,6 +79,8 @@ Bug(none) webaudio/ [ Skip ]
Bug(none) webexposed/ [ Skip ] Bug(none) webexposed/ [ Skip ]
Bug(none) webmidi/ [ Skip ] Bug(none) webmidi/ [ Skip ]
Bug(none) xmlviewer/ [ Skip ] Bug(none) xmlviewer/ [ Skip ]
crbug.com/657825 fast/performance/performance-first-paint-timing-observable.html [ Skip ]
crbug.com/657825 fast/performance/performance-paint-timing-observable.html [ Skip ]
Bug(none) broadcastchannel/blobs.html [ Pass Failure ] Bug(none) broadcastchannel/blobs.html [ Pass Failure ]
Bug(none) compositing/3d-cube.html [ Failure ] Bug(none) compositing/3d-cube.html [ Failure ]
......
<!DOCTYPE html>
<head>
<title>Performance Paint Timing Test</title>
</head>
<body>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
var observer = new PerformanceObserver(
t.step_func(function (entryList) {
var entries = entryList.getEntries();
// Nothing contentful to be painted yet.
assert_equals(entries.length, 1,
"There should be only first paint timing instance.");
assert_equals(entries[0].entryType, "paint",
"Expected entryType to be: paint.");
assert_equals(entries[0].name, "first-paint",
"Expected name to be: first-paint.");
assert_equals(entries[0].duration, 0,
"Expected duration to be: 0.");
observer.disconnect();
t.done();
})
);
observer.observe({entryTypes: ["paint"]});
}, "Performance first paint timing entry is observable.");
</script>
<div style="background-color:black;color:white;padding:20px;"></div>
</body>
</html>
<!DOCTYPE html>
<head>
<title>Performance Paint Timing Test</title>
</head>
<body>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
var observer = new PerformanceObserver(
t.step_func(function (entryList) {
var entries = entryList.getEntries();
assert_equals(entries.length, 2,
"There should be two paint timing instances.");
assert_equals(entries[0].entryType, "paint",
"Expected entryType to be: paint.");
assert_equals(entries[0].duration, 0,
"Expected duration to be: 0.");
assert_equals(entries[1].entryType, "paint",
"Expected entryType to be: paint.");
assert_equals(entries[1].duration, 0,
"Expected duration to be: 0.");
observer.disconnect();
t.done();
})
);
observer.observe({entryTypes: ["paint"]});
}, "Both first-paint-timing and first-contentful-paint timing entry are observable.");
</script>
<div style="background-color:black;color:white;padding:20px;">...test...</div>
</body>
</html>
\ No newline at end of file
...@@ -10,7 +10,7 @@ FAIL [[GetOwnProperty]] - Property descriptors for cross-origin properties shoul ...@@ -10,7 +10,7 @@ FAIL [[GetOwnProperty]] - Property descriptors for cross-origin properties shoul
FAIL [[Delete]] Should throw on cross-origin objects assert_throws: Can't delete cross-origin indexed property function "function () { delete C[0]; }" did not throw FAIL [[Delete]] Should throw on cross-origin objects assert_throws: Can't delete cross-origin indexed property function "function () { delete C[0]; }" did not throw
FAIL [[DefineOwnProperty]] Should throw for cross-origin objects assert_throws: Can't define cross-origin value property length function "function () { Object.defineProperty(obj, prop, valueDesc); }" did not throw FAIL [[DefineOwnProperty]] Should throw for cross-origin objects assert_throws: Can't define cross-origin value property length function "function () { Object.defineProperty(obj, prop, valueDesc); }" did not throw
FAIL [[Enumerate]] should return an empty iterator assert_unreached: Shouldn't have been able to enumerate stop on cross-origin Window Reached unreachable code FAIL [[Enumerate]] should return an empty iterator assert_unreached: Shouldn't have been able to enumerate stop on cross-origin Window Reached unreachable code
FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Window lengths differ, expected 874 got 13 FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Window lengths differ, expected 875 got 13
PASS A and B jointly observe the same identity for cross-origin Window and Location PASS A and B jointly observe the same identity for cross-origin Window and Location
PASS Cross-origin functions get local Function.prototype PASS Cross-origin functions get local Function.prototype
FAIL Cross-origin Window accessors get local Function.prototype Cannot read property 'name' of undefined FAIL Cross-origin Window accessors get local Function.prototype Cannot read property 'name' of undefined
......
...@@ -4616,6 +4616,9 @@ interface PerformanceObserverEntryList ...@@ -4616,6 +4616,9 @@ interface PerformanceObserverEntryList
method getEntries method getEntries
method getEntriesByName method getEntriesByName
method getEntriesByType method getEntriesByType
interface PerformancePaintTiming : PerformanceEntry
attribute @@toStringTag
method constructor
interface PerformanceResourceTiming : PerformanceEntry interface PerformanceResourceTiming : PerformanceEntry
attribute @@toStringTag attribute @@toStringTag
getter connectEnd getter connectEnd
......
...@@ -400,6 +400,7 @@ core_idl_files = get_path_info([ ...@@ -400,6 +400,7 @@ core_idl_files = get_path_info([
"timing/PerformanceNavigationTiming.idl", "timing/PerformanceNavigationTiming.idl",
"timing/PerformanceObserver.idl", "timing/PerformanceObserver.idl",
"timing/PerformanceObserverEntryList.idl", "timing/PerformanceObserverEntryList.idl",
"timing/PerformancePaintTiming.idl",
"timing/PerformanceResourceTiming.idl", "timing/PerformanceResourceTiming.idl",
"timing/PerformanceTiming.idl", "timing/PerformanceTiming.idl",
"timing/TaskAttributionTiming.idl", "timing/TaskAttributionTiming.idl",
......
...@@ -6,13 +6,28 @@ ...@@ -6,13 +6,28 @@
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/frame/FrameView.h" #include "core/frame/FrameView.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "core/loader/DocumentLoader.h" #include "core/loader/DocumentLoader.h"
#include "core/timing/DOMWindowPerformance.h"
#include "core/timing/Performance.h"
#include "platform/WebFrameScheduler.h" #include "platform/WebFrameScheduler.h"
#include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/instrumentation/tracing/TraceEvent.h"
namespace blink { namespace blink {
namespace {
Performance* getPerformanceInstance(LocalFrame* frame) {
Performance* performance = nullptr;
if (frame && frame->domWindow()) {
performance = DOMWindowPerformance::performance(*frame->domWindow());
}
return performance;
}
} // namespace
static const char kSupplementName[] = "PaintTiming"; static const char kSupplementName[] = "PaintTiming";
PaintTiming& PaintTiming::from(Document& document) { PaintTiming& PaintTiming::from(Document& document) {
...@@ -120,6 +135,10 @@ void PaintTiming::setFirstPaint(double stamp) { ...@@ -120,6 +135,10 @@ void PaintTiming::setFirstPaint(double stamp) {
if (m_firstPaint != 0.0) if (m_firstPaint != 0.0)
return; return;
m_firstPaint = stamp; m_firstPaint = stamp;
Performance* performance = getPerformanceInstance(frame());
if (performance)
performance->addFirstPaintTiming(m_firstPaint);
TRACE_EVENT_INSTANT1("blink.user_timing,rail", "firstPaint", TRACE_EVENT_INSTANT1("blink.user_timing,rail", "firstPaint",
TRACE_EVENT_SCOPE_PROCESS, "frame", frame()); TRACE_EVENT_SCOPE_PROCESS, "frame", frame());
} }
...@@ -129,6 +148,9 @@ void PaintTiming::setFirstContentfulPaint(double stamp) { ...@@ -129,6 +148,9 @@ void PaintTiming::setFirstContentfulPaint(double stamp) {
return; return;
setFirstPaint(stamp); setFirstPaint(stamp);
m_firstContentfulPaint = stamp; m_firstContentfulPaint = stamp;
Performance* performance = getPerformanceInstance(frame());
if (performance)
performance->addFirstContentfulPaintTiming(m_firstContentfulPaint);
TRACE_EVENT_INSTANT1("blink.user_timing,rail", "firstContentfulPaint", TRACE_EVENT_INSTANT1("blink.user_timing,rail", "firstContentfulPaint",
TRACE_EVENT_SCOPE_PROCESS, "frame", frame()); TRACE_EVENT_SCOPE_PROCESS, "frame", frame());
} }
......
...@@ -27,6 +27,8 @@ blink_core_sources("timing") { ...@@ -27,6 +27,8 @@ blink_core_sources("timing") {
"PerformanceObserver.h", "PerformanceObserver.h",
"PerformanceObserverEntryList.cpp", "PerformanceObserverEntryList.cpp",
"PerformanceObserverEntryList.h", "PerformanceObserverEntryList.h",
"PerformancePaintTiming.cpp",
"PerformancePaintTiming.h",
"PerformanceResourceTiming.cpp", "PerformanceResourceTiming.cpp",
"PerformanceResourceTiming.h", "PerformanceResourceTiming.h",
"PerformanceTiming.cpp", "PerformanceTiming.cpp",
......
...@@ -157,9 +157,11 @@ PerformanceEntryVector PerformanceBase::getEntriesByType( ...@@ -157,9 +157,11 @@ PerformanceEntryVector PerformanceBase::getEntriesByType(
if (m_userTiming) if (m_userTiming)
entries.appendVector(m_userTiming->getMeasures()); entries.appendVector(m_userTiming->getMeasures());
break; break;
// Unsupported for LongTask, TaskAttribution. // Unsupported for Paint, LongTask, TaskAttribution.
// Per the spec, these entries can only be accessed via // Per the spec, these entries can only be accessed via
// Performance Observer. No separate buffer is maintained. // Performance Observer. No separate buffer is maintained.
case PerformanceEntry::Paint:
break;
case PerformanceEntry::LongTask: case PerformanceEntry::LongTask:
break; break;
case PerformanceEntry::TaskAttribution: case PerformanceEntry::TaskAttribution:
...@@ -400,6 +402,24 @@ void PerformanceBase::addNavigationTiming(LocalFrame* frame) { ...@@ -400,6 +402,24 @@ void PerformanceBase::addNavigationTiming(LocalFrame* frame) {
notifyObserversOfEntry(*m_navigationTiming); notifyObserversOfEntry(*m_navigationTiming);
} }
void PerformanceBase::addFirstPaintTiming(double startTime) {
addPaintTiming(PerformancePaintTiming::PaintType::FirstPaint, startTime);
}
void PerformanceBase::addFirstContentfulPaintTiming(double startTime) {
addPaintTiming(PerformancePaintTiming::PaintType::FirstContentfulPaint,
startTime);
}
void PerformanceBase::addPaintTiming(PerformancePaintTiming::PaintType type,
double startTime) {
if (!RuntimeEnabledFeatures::performancePaintTimingEnabled())
return;
PerformanceEntry* entry = new PerformancePaintTiming(
type, monotonicTimeToDOMHighResTimeStamp(startTime));
notifyObserversOfEntry(*entry);
}
void PerformanceBase::addResourceTimingBuffer(PerformanceEntry& entry) { void PerformanceBase::addResourceTimingBuffer(PerformanceEntry& entry) {
m_resourceTimingBuffer.push_back(&entry); m_resourceTimingBuffer.push_back(&entry);
...@@ -557,7 +577,8 @@ DOMHighResTimeStamp PerformanceBase::monotonicTimeToDOMHighResTimeStamp( ...@@ -557,7 +577,8 @@ DOMHighResTimeStamp PerformanceBase::monotonicTimeToDOMHighResTimeStamp(
return 0.0; return 0.0;
double timeInSeconds = monotonicTime - timeOrigin; double timeInSeconds = monotonicTime - timeOrigin;
DCHECK_GE(timeInSeconds, 0); if (timeInSeconds < 0)
return 0.0;
return convertSecondsToDOMHighResTimeStamp( return convertSecondsToDOMHighResTimeStamp(
clampTimeResolution(timeInSeconds)); clampTimeResolution(timeInSeconds));
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "core/loader/FrameLoaderTypes.h" #include "core/loader/FrameLoaderTypes.h"
#include "core/timing/PerformanceEntry.h" #include "core/timing/PerformanceEntry.h"
#include "core/timing/PerformanceNavigationTiming.h" #include "core/timing/PerformanceNavigationTiming.h"
#include "core/timing/PerformancePaintTiming.h"
#include "platform/Timer.h" #include "platform/Timer.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "wtf/Forward.h" #include "wtf/Forward.h"
...@@ -113,6 +114,10 @@ class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData { ...@@ -113,6 +114,10 @@ class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData {
void addNavigationTiming(LocalFrame*); void addNavigationTiming(LocalFrame*);
void addFirstPaintTiming(double startTime);
void addFirstContentfulPaintTiming(double startTime);
void mark(const String& markName, ExceptionState&); void mark(const String& markName, ExceptionState&);
void clearMarks(const String& markName); void clearMarks(const String& markName);
...@@ -145,6 +150,8 @@ class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData { ...@@ -145,6 +150,8 @@ class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData {
const AtomicString&, const AtomicString&,
ExecutionContext*); ExecutionContext*);
void addPaintTiming(PerformancePaintTiming::PaintType, double startTime);
protected: protected:
explicit PerformanceBase(double timeOrigin); explicit PerformanceBase(double timeOrigin);
......
...@@ -81,6 +81,8 @@ PerformanceEntry::EntryType PerformanceEntry::toEntryTypeEnum( ...@@ -81,6 +81,8 @@ PerformanceEntry::EntryType PerformanceEntry::toEntryTypeEnum(
return Navigation; return Navigation;
if (entryType == "taskattribution") if (entryType == "taskattribution")
return TaskAttribution; return TaskAttribution;
if (entryType == "paint")
return Paint;
return Invalid; return Invalid;
} }
......
...@@ -44,8 +44,8 @@ class ScriptState; ...@@ -44,8 +44,8 @@ class ScriptState;
class ScriptValue; class ScriptValue;
class V8ObjectBuilder; class V8ObjectBuilder;
using PerformanceEntryType = unsigned char; using PerformanceEntryType = unsigned;
using PerformanceEntryTypeMask = unsigned char; using PerformanceEntryTypeMask = unsigned;
class CORE_EXPORT PerformanceEntry class CORE_EXPORT PerformanceEntry
: public GarbageCollectedFinalized<PerformanceEntry>, : public GarbageCollectedFinalized<PerformanceEntry>,
...@@ -55,7 +55,7 @@ class CORE_EXPORT PerformanceEntry ...@@ -55,7 +55,7 @@ class CORE_EXPORT PerformanceEntry
public: public:
virtual ~PerformanceEntry(); virtual ~PerformanceEntry();
enum EntryType { enum EntryType : PerformanceEntryType {
Invalid = 0, Invalid = 0,
Navigation = 1 << 0, Navigation = 1 << 0,
Composite = 1 << 1, Composite = 1 << 1,
...@@ -65,6 +65,7 @@ class CORE_EXPORT PerformanceEntry ...@@ -65,6 +65,7 @@ class CORE_EXPORT PerformanceEntry
Resource = 1 << 5, Resource = 1 << 5,
LongTask = 1 << 6, LongTask = 1 << 6,
TaskAttribution = 1 << 7, TaskAttribution = 1 << 7,
Paint = 1 << 8
}; };
String name() const; String name() const;
...@@ -87,7 +88,7 @@ class CORE_EXPORT PerformanceEntry ...@@ -87,7 +88,7 @@ class CORE_EXPORT PerformanceEntry
return a->startTime() < b->startTime(); return a->startTime() < b->startTime();
} }
static EntryType toEntryTypeEnum(const String& entryType); static PerformanceEntry::EntryType toEntryTypeEnum(const String& entryType);
DEFINE_INLINE_VIRTUAL_TRACE() {} DEFINE_INLINE_VIRTUAL_TRACE() {}
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/timing/PerformancePaintTiming.h"
#include "bindings/core/v8/V8ObjectBuilder.h"
namespace blink {
PerformancePaintTiming::PerformancePaintTiming(PaintType type, double startTime)
: PerformanceEntry(fromPaintTypeToString(type),
"paint",
startTime,
startTime) {}
PerformancePaintTiming::~PerformancePaintTiming() {}
String PerformancePaintTiming::fromPaintTypeToString(PaintType type) {
switch (type) {
case PaintType::FirstPaint:
return "first-paint";
case PaintType::FirstContentfulPaint:
return "first-contentful-paint";
}
NOTREACHED();
return "";
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PerformancePaintTiming_h
#define PerformancePaintTiming_h
#include "core/CoreExport.h"
#include "core/timing/PerformanceEntry.h"
namespace blink {
class CORE_EXPORT PerformancePaintTiming final : public PerformanceEntry {
DEFINE_WRAPPERTYPEINFO();
public:
enum class PaintType { FirstPaint, FirstContentfulPaint };
PerformancePaintTiming(PaintType, double startTime);
~PerformancePaintTiming() override;
static String fromPaintTypeToString(PaintType);
};
} // namespace blink
#endif // PerformancePaintTiming_h
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://github.com/WICG/paint-timing
[
RuntimeEnabled=PerformancePaintTiming,
] interface PerformancePaintTiming : PerformanceEntry {
};
...@@ -283,3 +283,4 @@ ParseHTMLOnMainThread status=test ...@@ -283,3 +283,4 @@ ParseHTMLOnMainThread status=test
SendBeaconThrowForBlobWithNonSimpleType status=experimental SendBeaconThrowForBlobWithNonSimpleType status=experimental
PerformanceNavigationTiming2 status=experimental PerformanceNavigationTiming2 status=experimental
BackgroundVideoTrackOptimization status=stable BackgroundVideoTrackOptimization status=stable
PerformancePaintTiming status=test
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