Title: [235897] trunk
Revision
235897
Author
[email protected]
Date
2018-09-11 10:14:07 -0700 (Tue, 11 Sep 2018)

Log Message

Add Web API Statistics Collection
https://bugs.webkit.org/show_bug.cgi?id=187773
<rdar://problem/44155162>

Patch by Woodrow Wang <[email protected]> on 2018-09-11
Reviewed by Brent Fulgham.

Source/WebCore:

Added data collection for web API statistics, specifically regarding the canvas, font loads,
screen functions, and navigator functions. The data collection code is placed under a runtime
enabled feature flag. The statistics are stored in a ResourceLoadStatistics object and written
to a plist on disk. Added a new file CanvasActivityRecord.h and CanvasActivityRecord.cpp which
includes a struct to keep track of HTML5 canvas element read and writes.

Tests: http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html
       http/tests/webAPIStatistics/font-load-data-collection.html
       http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html
       http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSFontFaceSource.cpp:
(WebCore::CSSFontFaceSource::load):
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::fontRangesForFamily):
(WebCore::CSSFontSelector::fallbackFontAt):

The following are the functions where we'd like to record a canvas read.

* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::toDataURL):
(WebCore::HTMLCanvasElement::toBlob):
(WebCore::HTMLCanvasElement::getImageData):
(WebCore::HTMLCanvasElement::toMediaSample):
(WebCore::HTMLCanvasElement::captureStream):

The following are the functions where we'd like to record a canvas write.

* html/canvas/CanvasRenderingContext2D.cpp:
(WebCore::CanvasRenderingContext2D::measureText):
(WebCore::CanvasRenderingContext2D::drawTextInternal):

The following files and functions handle the CanvasActivityRecord struct and
its respective functions.

* loader/CanvasActivityRecord.cpp: Added.
(WebCore::CanvasActivityRecord::recordWrittenOrMeasuredText):
(WebCore::CanvasActivityRecord::mergeWith):
* loader/CanvasActivityRecord.h: Added.
(WebCore::CanvasActivityRecord::encode const):
(WebCore::CanvasActivityRecord::decode):

* loader/DocumentThreadableLoader.cpp:
* loader/FrameLoader.cpp:
* loader/ResourceLoadObserver.cpp:
(WebCore::ResourceLoadObserver::logFontLoad):
(WebCore::ResourceLoadObserver::logCanvasRead):
(WebCore::ResourceLoadObserver::logCanvasWriteOrMeasure):
(WebCore::ResourceLoadObserver::logNavigatorAPIAccessed):
(WebCore::ResourceLoadObserver::logScreenAPIAccessed):

Before, entries in the ResourceLoadStatistics involving HashSets used "origin" as the key.
Now the encodeHashSet function has been generalized to take any key to encode the entries
in the HashSet. Also added functionality to encode an OptionSet by converting it to its
raw bitmask state.

* loader/ResourceLoadObserver.h:
* loader/ResourceLoadStatistics.cpp:
(WebCore::encodeHashSet):
(WebCore::encodeOriginHashSet):
(WebCore::encodeOptionSet):
(WebCore::encodeFontHashSet):
(WebCore::encodeCanvasActivityRecord):
(WebCore::ResourceLoadStatistics::encode const):
(WebCore::decodeHashSet):
(WebCore::decodeOriginHashSet):
(WebCore::decodeOptionSet):
(WebCore::decodeFontHashSet):
(WebCore::decodeCanvasActivityRecord):
(WebCore::ResourceLoadStatistics::decode):
(WebCore::navigatorAPIEnumToString):
(WebCore::screenAPIEnumToString):
(WebCore::appendNavigatorAPIOptionSet):
(WebCore::appendScreenAPIOptionSet):
(WebCore::ResourceLoadStatistics::toString const):
(WebCore::ResourceLoadStatistics::merge):
* loader/ResourceLoadStatistics.h:
* loader/ResourceTiming.cpp:

The following are the navigator functions recorded for the web API statistics.

* page/Navigator.cpp:
(WebCore::Navigator::appVersion const):
(WebCore::Navigator::userAgent const):
(WebCore::Navigator::plugins):
(WebCore::Navigator::mimeTypes):
(WebCore::Navigator::cookieEnabled const):
(WebCore::Navigator::javaEnabled const):

The following are the screen functions recorded for the web API statistics.

* page/Screen.cpp:
(WebCore::Screen::height const):
(WebCore::Screen::width const):
(WebCore::Screen::colorDepth const):
(WebCore::Screen::pixelDepth const):
(WebCore::Screen::availLeft const):
(WebCore::Screen::availTop const):
(WebCore::Screen::availHeight const):
(WebCore::Screen::availWidth const):

Source/WebKit:

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<ResourceLoadStatistics>::encode):
(IPC::ArgumentCoder<ResourceLoadStatistics>::decode):
* UIProcess/ResourceLoadStatisticsMemoryStore.cpp:

LayoutTests:

Added new tests and expectations for the web API statistics data collection.

* TestExpectations:
* http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt: Added.
* http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html: Added.
* http/tests/webAPIStatistics/font-load-data-collection-expected.txt: Added.
* http/tests/webAPIStatistics/font-load-data-collection.html: Added.
* http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt: Added.
* http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html: Added.
* http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt: Added.
* http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html: Added.
* platform/ios-wk2/TestExpectations:
* platform/mac-wk2/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (235896 => 235897)


--- trunk/LayoutTests/ChangeLog	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/LayoutTests/ChangeLog	2018-09-11 17:14:07 UTC (rev 235897)
@@ -1,3 +1,25 @@
+2018-09-11  Woodrow Wang  <[email protected]>
+
+        Add Web API Statistics Collection
+        https://bugs.webkit.org/show_bug.cgi?id=187773
+        <rdar://problem/44155162>
+
+        Reviewed by Brent Fulgham.
+
+        Added new tests and expectations for the web API statistics data collection.
+
+        * TestExpectations:
+        * http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt: Added.
+        * http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html: Added.
+        * http/tests/webAPIStatistics/font-load-data-collection-expected.txt: Added.
+        * http/tests/webAPIStatistics/font-load-data-collection.html: Added.
+        * http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt: Added.
+        * http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html: Added.
+        * http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt: Added.
+        * http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html: Added.
+        * platform/ios-wk2/TestExpectations:
+        * platform/mac-wk2/TestExpectations:
+
 2018-09-11  Frederic Wang  <[email protected]>
 
         Modify more tests to use document.scrollingElement to access viewport scroll properties

Modified: trunk/LayoutTests/TestExpectations (235896 => 235897)


--- trunk/LayoutTests/TestExpectations	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/LayoutTests/TestExpectations	2018-09-11 17:14:07 UTC (rev 235897)
@@ -2245,3 +2245,5 @@
 fast/gradients/conic-center-outside-box.html [ Skip ]
 fast/gradients/conic-extended-stops.html [ Skip ]
 fast/gradients/conic-from-angle.html [ Skip ]
+
+webkit.org/b/187773 http/tests/webAPIStatistics [ Skip ]

Added: trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,30 @@
+Tests for canvas read and write data collection in ResourceLoadStatistics plist by rendering and reading text on the canvas and dumping the entire resource load statistics map.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+Resource load statistics:
+
+High level domain: 127.0.0.1
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    isPrevalentResource: No
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 0
+    isMarkedForCookieBlocking: No
+    fontsSuccessfullyLoaded:
+        Helvetica
+        Times
+        Courier
+    topFrameRegistrableDomainsWhichAccessedWebAPIs:
+        127.0.0.1: 8
+    canvasTextWritten:
+        suspicious invisible text
+    canvasReadData: Yes
+

Added: trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<head>
+    <meta charset="UTF-8">
+    <title>Test for canvas read and write data collection in resource load statistics</title>
+    <script src=""
+</head>
+<body>
+<script>
+    description("Tests for canvas read and write data collection in ResourceLoadStatistics plist by rendering and reading text on the canvas and dumping the entire resource load statistics map.");
+    const hostUnderTest = "127.0.0.1:8000";
+    const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+    function completeTest() {
+        testRunner.dumpResourceLoadStatistics();
+            
+        testRunner.statisticsResetToConsistentState(function() {
+            testRunner.notifyDone();
+        });
+    }
+
+    function runTestRunnerTest() {
+        testRunner.setStatisticsNotifyPagesWhenDataRecordsWereScanned(true);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(completeTest);
+    
+        var canvas = document.createElement('canvas');
+        var context = canvas.getContext('2d');
+        context.fillText('suspicious invisible text', 2, 15);
+        canvas.toDataURL();
+    }
+
+    if (document.location.host === hostUnderTest && window.testRunner && window.internals) {
+        testRunner.waitUntilDone();
+        internals.setResourceLoadStatisticsEnabled(true);
+        testRunner.setWebAPIStatisticsEnabled(true);
+        runTestRunnerTest();
+    }
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,31 @@
+Tests for font loading data collection in ResourceLoadStatistics plist by loading fonts and dumping the entire resource load statistics map. The test tries to load various fonts through a comma separated font-family list to draw a string with many m's since they differ in width more prominently among fonts.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+mmmmmmmmmmlli
+Resource load statistics:
+
+High level domain: 127.0.0.1
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    isPrevalentResource: No
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 0
+    isMarkedForCookieBlocking: No
+    fontsFailedToLoad:
+        Fransiscan
+        Andale
+        notARealFont
+    fontsSuccessfullyLoaded:
+        Times
+        Courier
+    topFrameRegistrableDomainsWhichAccessedWebAPIs:
+        127.0.0.1: 9
+    canvasReadData: No
+

Added: trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<head>
+    <meta charset="UTF-8">
+    <title>Test for font loading data collection in resource load statistics</title>
+    <script src=""
+</head>
+<body>
+<script>
+    description("Tests for font loading data collection in ResourceLoadStatistics plist by loading fonts and dumping the entire resource load statistics map. The test tries to load various fonts through a comma separated font-family list to draw a string with many m's since they differ in width more prominently among fonts.");
+    const hostUnderTest = "127.0.0.1:8000";
+    const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+    function completeTest() {
+        testRunner.dumpResourceLoadStatistics();
+            
+        testRunner.statisticsResetToConsistentState(function() {
+            testRunner.notifyDone();
+        });
+    }
+
+    function runTestRunnerTest() {
+        testRunner.setStatisticsNotifyPagesWhenDataRecordsWereScanned(true);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(completeTest);
+
+        var body = document.getElementsByTagName('body')[0]
+    
+        var span = document.createElement('span');
+        var testFontString = 'mmmmmmmmmmlli';
+        
+        span.innerHTML = testFontString;
+        span.style.fontFamily = 'Andale, Fransiscan, notARealFont, serif';
+        body.appendChild(span);
+    }
+
+    if (document.location.host === hostUnderTest && window.testRunner && window.internals) {
+        testRunner.waitUntilDone();
+        internals.setResourceLoadStatisticsEnabled(true);
+        testRunner.setWebAPIStatisticsEnabled(true);
+        runTestRunnerTest();
+    }
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,34 @@
+Tests for navigator functions accessed data collection in ResourceLoadStatistics plist by querying for all the navigator properties and dumping the entire resource load statistics map.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+Resource load statistics:
+
+High level domain: 127.0.0.1
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    isPrevalentResource: No
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 0
+    isMarkedForCookieBlocking: No
+    fontsSuccessfullyLoaded:
+        Times
+        Courier
+    topFrameRegistrableDomainsWhichAccessedWebAPIs:
+        127.0.0.1: 12
+    navigatorFunctionsAccessed:
+        appVersion
+        userAgent
+        plugins
+        mimeTypes
+        cookieEnabled
+        javaEnabled
+    canvasReadData: No
+

Added: trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<head>
+    <meta charset="UTF-8">
+    <title>Test for navigator functions accessed data collection in resource load statistics</title>
+    <script src=""
+</head>
+<body>
+<script>
+    description("Tests for navigator functions accessed data collection in ResourceLoadStatistics plist by querying for all the navigator properties and dumping the entire resource load statistics map.");
+    const hostUnderTest = "127.0.0.1:8000";
+    const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+    function completeTest() {
+        testRunner.dumpResourceLoadStatistics();
+            
+        testRunner.statisticsResetToConsistentState(function() {
+            testRunner.notifyDone();
+        });
+    }
+
+    function runTestRunnerTest() {
+        testRunner.setStatisticsNotifyPagesWhenDataRecordsWereScanned(true);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(completeTest);
+    
+        var useragent = navigator.userAgent;
+        var javaenabled = navigator.javaEnabled();
+        var cookieEnabled = navigator.cookieEnabled;
+        var mimetypes = navigator.mimeTypes;
+        var plugins = navigator.plugins;
+        var appversion = navigator.appVersion;
+    }
+
+    if (document.location.host === hostUnderTest && window.testRunner && window.internals) {
+        testRunner.waitUntilDone();
+        internals.setResourceLoadStatisticsEnabled(true);
+        testRunner.setWebAPIStatisticsEnabled(true);
+        runTestRunnerTest();
+    }
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,36 @@
+Tests for screen functions accessed data collection in ResourceLoadStatistics plist by querying for all the screen properties and dumping the entire resource load statistics map.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+Resource load statistics:
+
+High level domain: 127.0.0.1
+    lastSeen: 0
+    hadUserInteraction: No
+    mostRecentUserInteraction: -1
+    grandfathered: No
+    isPrevalentResource: No
+    isVeryPrevalentResource: No
+    dataRecordsRemoved: 0
+    isMarkedForCookieBlocking: No
+    fontsSuccessfullyLoaded:
+        Times
+        Courier
+    topFrameRegistrableDomainsWhichAccessedWebAPIs:
+        127.0.0.1: 13
+    screenFunctionsAccessed:
+        height
+        width
+        colorDepth
+        pixelDepth
+        availLeft
+        availTop
+        availHeight
+        availWidth
+    canvasReadData: No
+

Added: trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html (0 => 235897)


--- trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<head>
+    <meta charset="UTF-8">
+    <title>Test for screen functions accessed data collection in resource load statistics</title>
+    <script src=""
+</head>
+<body>
+<script>
+    description("Tests for screen functions accessed data collection in ResourceLoadStatistics plist by querying for all the screen properties and dumping the entire resource load statistics map.");
+    const hostUnderTest = "127.0.0.1:8000";
+    const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+    function completeTest() {
+        testRunner.dumpResourceLoadStatistics();
+            
+        testRunner.statisticsResetToConsistentState(function() {
+            testRunner.notifyDone();
+        });
+    }
+
+    function runTestRunnerTest() {
+        testRunner.setStatisticsNotifyPagesWhenDataRecordsWereScanned(true);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(completeTest);
+    
+        var availTop = screen.availTop;
+        var colorDepth = screen.colorDepth;
+        var pixelDepth = screen.pixelDepth;
+        var height = screen.height;
+        var width = screen.width;
+        var availLeft = screen.availLeft;
+        var availHeight = screen.availHeight;
+        var availWidth = screen.availWidth;
+    }
+
+    if (document.location.host === hostUnderTest && window.testRunner && window.internals) {
+        testRunner.waitUntilDone();
+        internals.setResourceLoadStatisticsEnabled(true);
+        testRunner.setWebAPIStatisticsEnabled(true);
+        runTestRunnerTest();
+    }
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/ios-wk2/TestExpectations (235896 => 235897)


--- trunk/LayoutTests/platform/ios-wk2/TestExpectations	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/LayoutTests/platform/ios-wk2/TestExpectations	2018-09-11 17:14:07 UTC (rev 235897)
@@ -50,6 +50,8 @@
 http/tests/security/contentSecurityPolicy/manifest-src-blocked.html [ Pass ]
 applicationmanifest/ [ Pass ]
 
+webkit.org/b/187773 http/tests/webAPIStatistics [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (235896 => 235897)


--- trunk/LayoutTests/platform/mac-wk2/TestExpectations	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations	2018-09-11 17:14:07 UTC (rev 235897)
@@ -57,6 +57,8 @@
 
 fast/misc/valid-primary-screen-displayID.html [ Pass ]
 
+webkit.org/b/187773 http/tests/webAPIStatistics [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/Source/WebCore/ChangeLog (235896 => 235897)


--- trunk/Source/WebCore/ChangeLog	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/ChangeLog	2018-09-11 17:14:07 UTC (rev 235897)
@@ -1,3 +1,114 @@
+2018-09-11  Woodrow Wang  <[email protected]>
+
+        Add Web API Statistics Collection
+        https://bugs.webkit.org/show_bug.cgi?id=187773
+        <rdar://problem/44155162>
+
+        Reviewed by Brent Fulgham.
+
+        Added data collection for web API statistics, specifically regarding the canvas, font loads, 
+        screen functions, and navigator functions. The data collection code is placed under a runtime 
+        enabled feature flag. The statistics are stored in a ResourceLoadStatistics object and written 
+        to a plist on disk. Added a new file CanvasActivityRecord.h and CanvasActivityRecord.cpp which
+        includes a struct to keep track of HTML5 canvas element read and writes. 
+
+        Tests: http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html
+               http/tests/webAPIStatistics/font-load-data-collection.html
+               http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html
+               http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSFontFaceSource.cpp:
+        (WebCore::CSSFontFaceSource::load):
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::fontRangesForFamily):
+        (WebCore::CSSFontSelector::fallbackFontAt):
+
+        The following are the functions where we'd like to record a canvas read.
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::toDataURL):
+        (WebCore::HTMLCanvasElement::toBlob):
+        (WebCore::HTMLCanvasElement::getImageData):
+        (WebCore::HTMLCanvasElement::toMediaSample):
+        (WebCore::HTMLCanvasElement::captureStream):
+
+        The following are the functions where we'd like to record a canvas write.
+
+        * html/canvas/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::measureText):
+        (WebCore::CanvasRenderingContext2D::drawTextInternal):
+
+        The following files and functions handle the CanvasActivityRecord struct and
+        its respective functions.
+
+        * loader/CanvasActivityRecord.cpp: Added.
+        (WebCore::CanvasActivityRecord::recordWrittenOrMeasuredText):
+        (WebCore::CanvasActivityRecord::mergeWith):
+        * loader/CanvasActivityRecord.h: Added.
+        (WebCore::CanvasActivityRecord::encode const):
+        (WebCore::CanvasActivityRecord::decode):
+
+        * loader/DocumentThreadableLoader.cpp:
+        * loader/FrameLoader.cpp:
+        * loader/ResourceLoadObserver.cpp:
+        (WebCore::ResourceLoadObserver::logFontLoad):
+        (WebCore::ResourceLoadObserver::logCanvasRead):
+        (WebCore::ResourceLoadObserver::logCanvasWriteOrMeasure):
+        (WebCore::ResourceLoadObserver::logNavigatorAPIAccessed):
+        (WebCore::ResourceLoadObserver::logScreenAPIAccessed):
+
+        Before, entries in the ResourceLoadStatistics involving HashSets used "origin" as the key. 
+        Now the encodeHashSet function has been generalized to take any key to encode the entries 
+        in the HashSet. Also added functionality to encode an OptionSet by converting it to its 
+        raw bitmask state. 
+
+        * loader/ResourceLoadObserver.h:
+        * loader/ResourceLoadStatistics.cpp:
+        (WebCore::encodeHashSet):
+        (WebCore::encodeOriginHashSet):
+        (WebCore::encodeOptionSet):
+        (WebCore::encodeFontHashSet):
+        (WebCore::encodeCanvasActivityRecord):
+        (WebCore::ResourceLoadStatistics::encode const):
+        (WebCore::decodeHashSet):
+        (WebCore::decodeOriginHashSet):
+        (WebCore::decodeOptionSet):
+        (WebCore::decodeFontHashSet):
+        (WebCore::decodeCanvasActivityRecord):
+        (WebCore::ResourceLoadStatistics::decode):
+        (WebCore::navigatorAPIEnumToString):
+        (WebCore::screenAPIEnumToString):
+        (WebCore::appendNavigatorAPIOptionSet):
+        (WebCore::appendScreenAPIOptionSet):
+        (WebCore::ResourceLoadStatistics::toString const):
+        (WebCore::ResourceLoadStatistics::merge):
+        * loader/ResourceLoadStatistics.h:
+        * loader/ResourceTiming.cpp:
+
+        The following are the navigator functions recorded for the web API statistics.
+
+        * page/Navigator.cpp:
+        (WebCore::Navigator::appVersion const):
+        (WebCore::Navigator::userAgent const):
+        (WebCore::Navigator::plugins):
+        (WebCore::Navigator::mimeTypes):
+        (WebCore::Navigator::cookieEnabled const):
+        (WebCore::Navigator::javaEnabled const):
+
+        The following are the screen functions recorded for the web API statistics.
+
+        * page/Screen.cpp:
+        (WebCore::Screen::height const):
+        (WebCore::Screen::width const):
+        (WebCore::Screen::colorDepth const):
+        (WebCore::Screen::pixelDepth const):
+        (WebCore::Screen::availLeft const):
+        (WebCore::Screen::availTop const):
+        (WebCore::Screen::availHeight const):
+        (WebCore::Screen::availWidth const):
+
 2018-09-11  Pablo Saavedra  <[email protected]>
 
         playbackControlsManagerUpdateTimerFired and

Modified: trunk/Source/WebCore/Sources.txt (235896 => 235897)


--- trunk/Source/WebCore/Sources.txt	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/Sources.txt	2018-09-11 17:14:07 UTC (rev 235897)
@@ -1247,6 +1247,7 @@
 layout/layouttree/LayoutReplaced.cpp
 layout/layouttree/LayoutTreeBuilder.cpp
 
+loader/CanvasActivityRecord.cpp
 loader/ContentFilter.cpp
 loader/CookieJar.cpp
 loader/CrossOriginAccessControl.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (235896 => 235897)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-09-11 17:14:07 UTC (rev 235897)
@@ -4816,6 +4816,7 @@
 		ED2BA83C09A24B91006C0AC4 /* DocumentMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = ED2BA83B09A24B91006C0AC4 /* DocumentMarker.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EDE3A5000C7A430600956A37 /* ColorMac.h in Headers */ = {isa = PBXBuildFile; fileRef = EDE3A4FF0C7A430600956A37 /* ColorMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		EDEC98030AED7E170059137F /* WebCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEC98020AED7E170059137F /* WebCorePrefix.h */; };
+		EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F12171F516A8CED2000053CA /* WebVTTElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F12171F316A8BC63000053CA /* WebVTTElement.cpp */; };
 		F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; };
 		F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -14503,6 +14504,8 @@
 		ED501DC50B249F2900AE18D9 /* EditorMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorMac.mm; sourceTree = "<group>"; };
 		EDE3A4FF0C7A430600956A37 /* ColorMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorMac.h; sourceTree = "<group>"; };
 		EDEC98020AED7E170059137F /* WebCorePrefix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebCorePrefix.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
+		EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasActivityRecord.cpp; sourceTree = "<group>"; };
+		EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = "<group>"; };
 		F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = "<group>"; };
 		F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = "<group>"; };
 		F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorFrontendClient.h; sourceTree = "<group>"; };
@@ -24235,6 +24238,8 @@
 				93A1EAA20A5634D8006960A0 /* mac */,
 				63152D181F9531EE007A5E4B /* ApplicationManifestLoader.cpp */,
 				63152D171F9531EE007A5E4B /* ApplicationManifestLoader.h */,
+				EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */,
+				EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */,
 				A149786C1ABAF33800CEF7E4 /* ContentFilter.cpp */,
 				A149786D1ABAF33800CEF7E4 /* ContentFilter.h */,
 				E1424C91164B52C800F32D40 /* CookieJar.cpp */,
@@ -27318,6 +27323,7 @@
 				7C1E8D011ED0C2DA00B1D983 /* CallbackResult.h in Headers */,
 				952076051F2675FE007D2AAB /* CallTracer.h in Headers */,
 				952076061F2675FE007D2AAB /* CallTracerTypes.h in Headers */,
+				EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */,
 				313171561FB079E5008D91FC /* CanvasBase.h in Headers */,
 				415CDAF51E6B8F8B004F11EE /* CanvasCaptureMediaStreamTrack.h in Headers */,
 				7C193BBB1F5E0EED0088F3E6 /* CanvasDirection.h in Headers */,

Modified: trunk/Source/WebCore/css/CSSFontFaceSource.cpp (235896 => 235897)


--- trunk/Source/WebCore/css/CSSFontFaceSource.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/css/CSSFontFaceSource.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -34,6 +34,8 @@
 #include "FontCache.h"
 #include "FontCustomPlatformData.h"
 #include "FontDescription.h"
+#include "ResourceLoadObserver.h"
+#include "RuntimeEnabledFeatures.h"
 #include "SVGToOTFFontConversion.h"
 #include "SharedBuffer.h"
 
@@ -181,6 +183,10 @@
             fontDescription.setComputedSize(1);
             fontDescription.setShouldAllowUserInstalledFonts(m_face.allowUserInstalledFonts());
             success = FontCache::singleton().fontForFamily(fontDescription, m_familyNameOrURI, nullptr, nullptr, FontSelectionSpecifiedCapabilities(), true);
+            if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+                if (auto* document = fontSelector->document())
+                    ResourceLoadObserver::shared().logFontLoad(*document, m_familyNameOrURI.string(), success);
+            }
         }
         setStatus(success ? Status::Success : Status::Failure);
     }

Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (235896 => 235897)


--- trunk/Source/WebCore/css/CSSFontSelector.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -46,6 +46,8 @@
 #include "Frame.h"
 #include "FrameLoader.h"
 #include "Logging.h"
+#include "ResourceLoadObserver.h"
+#include "RuntimeEnabledFeatures.h"
 #include "Settings.h"
 #include "StyleProperties.h"
 #include "StyleResolver.h"
@@ -308,13 +310,21 @@
 
     AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName;
     auto* face = m_cssFontFaceSet->fontFace(fontDescription.fontSelectionRequest(), familyForLookup);
-    if (!face) {
-        if (!resolveGenericFamilyFirst)
-            familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName);
-        return FontRanges(FontCache::singleton().fontForFamily(fontDescription, familyForLookup));
+    if (face) {
+        if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+            if (m_document)
+                ResourceLoadObserver::shared().logFontLoad(*m_document, familyForLookup.string(), true);
+        }
+        return face->fontRanges(fontDescription);
     }
-
-    return face->fontRanges(fontDescription);
+    if (!resolveGenericFamilyFirst)
+        familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName);
+    auto font = FontCache::singleton().fontForFamily(fontDescription, familyForLookup);
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+        if (m_document)
+            ResourceLoadObserver::shared().logFontLoad(*m_document, familyForLookup.string(), !!font);
+    }
+    return FontRanges { WTFMove(font) };
 }
 
 void CSSFontSelector::clearDocument()
@@ -394,8 +404,12 @@
 
     if (!m_document->settings().fontFallbackPrefersPictographs())
         return nullptr;
-
-    return FontCache::singleton().fontForFamily(fontDescription, m_document->settings().pictographFontFamily());
+    auto& pictographFontFamily = m_document->settings().pictographFontFamily();
+    auto font = FontCache::singleton().fontForFamily(fontDescription, pictographFontFamily);
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logFontLoad(*m_document, pictographFontFamily.string(), !!font);
+    
+    return font;
 }
 
 }

Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (235896 => 235897)


--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -48,6 +48,7 @@
 #include "MIMETypeRegistry.h"
 #include "RenderElement.h"
 #include "RenderHTMLCanvas.h"
+#include "ResourceLoadObserver.h"
 #include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
 #include "Settings.h"
@@ -698,6 +699,8 @@
 
     if (m_size.isEmpty() || !buffer())
         return UncachedString { "data:,"_s };
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logCanvasRead(document());
 
     auto encodingMIMEType = toEncodingMimeType(mimeType);
     auto quality = qualityFromJSValue(qualityValue);
@@ -727,6 +730,8 @@
         callback->scheduleCallback(context, nullptr);
         return { };
     }
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logCanvasRead(document());
 
     auto encodingMIMEType = toEncodingMimeType(mimeType);
     auto quality = qualityFromJSValue(qualityValue);
@@ -755,8 +760,11 @@
 RefPtr<ImageData> HTMLCanvasElement::getImageData()
 {
 #if ENABLE(WEBGL)
-    if (is<WebGLRenderingContextBase>(m_context.get()))
+    if (is<WebGLRenderingContextBase>(m_context.get())) {
+        if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+            ResourceLoadObserver::shared().logCanvasRead(document());
         return downcast<WebGLRenderingContextBase>(*m_context).paintRenderingResultsToImageData();
+    }
 #endif
     return nullptr;
 }
@@ -768,6 +776,8 @@
     auto* imageBuffer = buffer();
     if (!imageBuffer)
         return nullptr;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logCanvasRead(document());
 
 #if PLATFORM(COCOA)
     makeRenderingResultsAvailable();
@@ -781,6 +791,8 @@
 {
     if (!originClean())
         return Exception(SecurityError, "Canvas is tainted"_s);
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logCanvasRead(document());
 
     if (frameRequestRate && frameRequestRate.value() < 0)
         return Exception(NotSupportedError, "frameRequestRate is negative"_s);

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (235896 => 235897)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -41,6 +41,8 @@
 #include "InspectorInstrumentation.h"
 #include "Path2D.h"
 #include "RenderTheme.h"
+#include "ResourceLoadObserver.h"
+#include "RuntimeEnabledFeatures.h"
 #include "StyleProperties.h"
 #include "StyleResolver.h"
 #include "TextMetrics.h"
@@ -363,6 +365,12 @@
 
 Ref<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
 {
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+        auto& canvas = this->canvas();
+        ResourceLoadObserver::shared().logCanvasWriteOrMeasure(canvas.document(), text);
+        ResourceLoadObserver::shared().logCanvasRead(canvas.document());
+    }
+    
     Ref<TextMetrics> metrics = TextMetrics::create();
 
     String normalizedText = text;
@@ -451,6 +459,9 @@
 
 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth)
 {
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logCanvasWriteOrMeasure(this->canvas().document(), text);
+    
     auto& fontProxy = this->fontProxy();
     const auto& fontMetrics = fontProxy.fontMetrics();
 

Added: trunk/Source/WebCore/loader/CanvasActivityRecord.cpp (0 => 235897)


--- trunk/Source/WebCore/loader/CanvasActivityRecord.cpp	                        (rev 0)
+++ trunk/Source/WebCore/loader/CanvasActivityRecord.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CanvasActivityRecord.h"
+
+const unsigned maximumNumberOfStringsToRecord = 10;
+namespace WebCore {
+bool CanvasActivityRecord::recordWrittenOrMeasuredText(const String& text)
+{
+    // We limit the size of the textWritten HashSet to save memory and prevent bloating
+    // the plist with the resourceLoadStatistics entries. A few strings is often enough
+    // to provide sufficient information about the state of canvas activity.
+    if (textWritten.size() >= maximumNumberOfStringsToRecord)
+        return false;
+    return textWritten.add(text).isNewEntry;
+}
+
+void CanvasActivityRecord::mergeWith(const CanvasActivityRecord& otherCanvasActivityRecord)
+{
+    textWritten.add(otherCanvasActivityRecord.textWritten.begin(), otherCanvasActivityRecord.textWritten.end());
+    wasDataRead |= otherCanvasActivityRecord.wasDataRead;
+}
+} // namespace WebCore

Added: trunk/Source/WebCore/loader/CanvasActivityRecord.h (0 => 235897)


--- trunk/Source/WebCore/loader/CanvasActivityRecord.h	                        (rev 0)
+++ trunk/Source/WebCore/loader/CanvasActivityRecord.h	2018-09-11 17:14:07 UTC (rev 235897)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+struct CanvasActivityRecord {
+    HashSet<String> textWritten;
+    bool wasDataRead { false };
+    
+    bool recordWrittenOrMeasuredText(const String&);
+    void mergeWith(const CanvasActivityRecord&);
+    
+    template <class Encoder> void encode(Encoder&) const;
+    template <class Decoder> static bool decode(Decoder&, CanvasActivityRecord&);
+};
+    
+template <class Encoder>
+void CanvasActivityRecord::encode(Encoder& encoder) const
+{
+    encoder << textWritten;
+    encoder << wasDataRead;
+}
+
+template <class Decoder>
+bool CanvasActivityRecord::decode(Decoder& decoder, CanvasActivityRecord& canvasActivityRecord)
+{
+    if (!decoder.decode(canvasActivityRecord.textWritten))
+        return false;
+    if (!decoder.decode(canvasActivityRecord.wasDataRead))
+        return false;
+    return true;
+}
+} // namespace WebCore

Modified: trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp (235896 => 235897)


--- trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -46,6 +46,7 @@
 #include "LoadTiming.h"
 #include "LoaderStrategy.h"
 #include "Performance.h"
+#include "PlatformStrategies.h"
 #include "ProgressTracker.h"
 #include "ResourceError.h"
 #include "ResourceRequest.h"

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (235896 => 235897)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -122,6 +122,7 @@
 #include "UserGestureIndicator.h"
 #include "WindowFeatures.h"
 #include "XMLDocumentParser.h"
+#include <dom/ScriptDisallowedScope.h>
 #include <wtf/CompletionHandler.h>
 #include <wtf/Ref.h>
 #include <wtf/SetForScope.h>

Modified: trunk/Source/WebCore/loader/ResourceLoadObserver.cpp (235896 => 235897)


--- trunk/Source/WebCore/loader/ResourceLoadObserver.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/ResourceLoadObserver.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -36,6 +36,7 @@
 #include "ResourceLoadStatistics.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScriptExecutionContext.h"
 #include "SecurityOrigin.h"
 #include "Settings.h"
@@ -242,6 +243,91 @@
 }
 #endif
 
+void ResourceLoadObserver::logFontLoad(const Document& document, const String& familyName, bool loadStatus)
+{
+    if (!shouldLog(document.sessionID().isEphemeral()))
+        return;
+    auto registrableDomain = primaryDomain(document.url());
+    auto& statistics = ensureResourceStatisticsForPrimaryDomain(registrableDomain);
+    bool shouldCallNotificationCallback = false;
+    if (!loadStatus) {
+        if (statistics.fontsFailedToLoad.add(familyName).isNewEntry)
+            shouldCallNotificationCallback = true;
+    } else {
+        if (statistics.fontsSuccessfullyLoaded.add(familyName).isNewEntry)
+            shouldCallNotificationCallback = true;
+    }
+    auto mainFrameRegistrableDomain = primaryDomain(document.topDocument().url());
+    if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain).isNewEntry)
+        shouldCallNotificationCallback = true;
+    if (shouldCallNotificationCallback)
+        scheduleNotificationIfNeeded();
+}
+    
+void ResourceLoadObserver::logCanvasRead(const Document& document)
+{
+    if (!shouldLog(document.sessionID().isEphemeral()))
+        return;
+    auto registrableDomain = primaryDomain(document.url());
+    auto& statistics = ensureResourceStatisticsForPrimaryDomain(registrableDomain);
+    auto mainFrameRegistrableDomain = primaryDomain(document.topDocument().url());
+    statistics.canvasActivityRecord.wasDataRead = true;
+    if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain).isNewEntry)
+        scheduleNotificationIfNeeded();
+}
+
+void ResourceLoadObserver::logCanvasWriteOrMeasure(const Document& document, const String& textWritten)
+{
+    if (!shouldLog(document.sessionID().isEphemeral()))
+        return;
+    auto registrableDomain = primaryDomain(document.url());
+    auto& statistics = ensureResourceStatisticsForPrimaryDomain(registrableDomain);
+    bool shouldCallNotificationCallback = false;
+    auto mainFrameRegistrableDomain = primaryDomain(document.topDocument().url());
+    if (statistics.canvasActivityRecord.recordWrittenOrMeasuredText(textWritten))
+        shouldCallNotificationCallback = true;
+    if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain).isNewEntry)
+        shouldCallNotificationCallback = true;
+    if (shouldCallNotificationCallback)
+        scheduleNotificationIfNeeded();
+}
+    
+void ResourceLoadObserver::logNavigatorAPIAccessed(const Document& document, const ResourceLoadStatistics::NavigatorAPI functionName)
+{
+    if (!shouldLog(document.sessionID().isEphemeral()))
+        return;
+    auto registrableDomain = primaryDomain(document.url());
+    auto& statistics = ensureResourceStatisticsForPrimaryDomain(registrableDomain);
+    bool shouldCallNotificationCallback = false;
+    if (!statistics.navigatorFunctionsAccessed.contains(functionName)) {
+        statistics.navigatorFunctionsAccessed.add(functionName);
+        shouldCallNotificationCallback = true;
+    }
+    auto mainFrameRegistrableDomain = primaryDomain(document.topDocument().url());
+    if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain).isNewEntry)
+        shouldCallNotificationCallback = true;
+    if (shouldCallNotificationCallback)
+        scheduleNotificationIfNeeded();
+}
+    
+void ResourceLoadObserver::logScreenAPIAccessed(const Document& document, const ResourceLoadStatistics::ScreenAPI functionName)
+{
+    if (!shouldLog(document.sessionID().isEphemeral()))
+        return;
+    auto registrableDomain = primaryDomain(document.url());
+    auto& statistics = ensureResourceStatisticsForPrimaryDomain(registrableDomain);
+    bool shouldCallNotificationCallback = false;
+    if (!statistics.screenFunctionsAccessed.contains(functionName)) {
+        statistics.screenFunctionsAccessed.add(functionName);
+        shouldCallNotificationCallback = true;
+    }
+    auto mainFrameRegistrableDomain = primaryDomain(document.topDocument().url());
+    if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain).isNewEntry)
+        shouldCallNotificationCallback = true;
+    if (shouldCallNotificationCallback)
+        scheduleNotificationIfNeeded();
+}
+    
 ResourceLoadStatistics& ResourceLoadObserver::ensureResourceStatisticsForPrimaryDomain(const String& primaryDomain)
 {
     auto addResult = m_resourceStatisticsMap.ensure(primaryDomain, [&primaryDomain] {

Modified: trunk/Source/WebCore/loader/ResourceLoadObserver.h (235896 => 235897)


--- trunk/Source/WebCore/loader/ResourceLoadObserver.h	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/ResourceLoadObserver.h	2018-09-11 17:14:07 UTC (rev 235897)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include "CanvasActivityRecord.h"
+#include "ResourceLoadStatistics.h"
 #include "Timer.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -58,6 +60,12 @@
     void logWebSocketLoading(const URL& targetURL, const URL& mainFrameURL, bool usesEphemeralSession);
     void logUserInteractionWithReducedTimeResolution(const Document&);
     void logWindowCreation(const URL& popupUrl, uint64_t openerPageID, Document& openerDocument);
+    
+    void logFontLoad(const Document&, const String& familyName, bool loadStatus);
+    void logCanvasRead(const Document&);
+    void logCanvasWriteOrMeasure(const Document&, const String& textWritten);
+    void logNavigatorAPIAccessed(const Document&, const ResourceLoadStatistics::NavigatorAPI);
+    void logScreenAPIAccessed(const Document&, const ResourceLoadStatistics::ScreenAPI);
 
     WEBCORE_EXPORT String statisticsForOrigin(const String&);
 

Modified: trunk/Source/WebCore/loader/ResourceLoadStatistics.cpp (235896 => 235897)


--- trunk/Source/WebCore/loader/ResourceLoadStatistics.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/ResourceLoadStatistics.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -29,6 +29,7 @@
 #include "KeyedCoding.h"
 #include "PublicSuffix.h"
 #include <wtf/MainThread.h>
+#include <wtf/text/ASCIILiteral.h>
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringHash.h>
 
@@ -49,16 +50,46 @@
     });
 }
 
-static void encodeHashSet(KeyedEncoder& encoder, const String& label, const HashSet<String>& hashSet)
+static void encodeHashSet(KeyedEncoder& encoder, const String& label,  const String& key, const HashSet<String>& hashSet)
 {
     if (hashSet.isEmpty())
         return;
     
-    encoder.encodeObjects(label, hashSet.begin(), hashSet.end(), [](KeyedEncoder& encoderInner, const String& origin) {
-        encoderInner.encodeString("origin", origin);
+    encoder.encodeObjects(label, hashSet.begin(), hashSet.end(), [&key](KeyedEncoder& encoderInner, const String& origin) {
+        encoderInner.encodeString(key, origin);
     });
 }
 
+static void encodeOriginHashSet(KeyedEncoder& encoder, const String& label, const HashSet<String>& hashSet)
+{
+    encodeHashSet(encoder, label, "origin", hashSet);
+}
+
+template<typename T>
+static void encodeOptionSet(KeyedEncoder& encoder, const String& label, const OptionSet<T>& optionSet)
+{
+    if (optionSet.isEmpty())
+        return;
+    
+    uint64_t optionSetBitMask = optionSet.toRaw();
+    encoder.encodeUInt64(label, optionSetBitMask);
+}
+    
+static void encodeFontHashSet(KeyedEncoder& encoder, const String& label, const HashSet<String>& hashSet)
+{
+    encodeHashSet(encoder, label, "font", hashSet);
+}
+    
+static void encodeCanvasActivityRecord(KeyedEncoder& encoder, const String& label, const CanvasActivityRecord& canvasActivityRecord)
+{
+    encoder.encodeObject(label, canvasActivityRecord, [] (KeyedEncoder& encoderInner, const CanvasActivityRecord& canvasActivityRecord) {
+        encoderInner.encodeBool("wasDataRead", canvasActivityRecord.wasDataRead);
+        encoderInner.encodeObjects("textWritten", canvasActivityRecord.textWritten.begin(), canvasActivityRecord.textWritten.end(), [] (KeyedEncoder& encoderInner2, const String& text) {
+            encoderInner2.encodeString("text", text);
+        });
+    });
+}
+
 void ResourceLoadStatistics::encode(KeyedEncoder& encoder) const
 {
     encoder.encodeString("PrevalentResourceOrigin", highLevelDomain);
@@ -71,7 +102,7 @@
     encoder.encodeBool("grandfathered", grandfathered);
 
     // Storage access
-    encodeHashSet(encoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins);
+    encodeOriginHashSet(encoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins);
 
     // Top frame stats
     encodeHashCountedSet(encoder, "topFrameUniqueRedirectsTo", topFrameUniqueRedirectsTo);
@@ -92,6 +123,13 @@
 
     encoder.encodeUInt32("timesAccessedAsFirstPartyDueToUserInteraction", timesAccessedAsFirstPartyDueToUserInteraction);
     encoder.encodeUInt32("timesAccessedAsFirstPartyDueToStorageAccessAPI", timesAccessedAsFirstPartyDueToStorageAccessAPI);
+    
+    encodeFontHashSet(encoder, "fontsFailedToLoad", fontsFailedToLoad);
+    encodeFontHashSet(encoder, "fontsSuccessfullyLoaded", fontsSuccessfullyLoaded);
+    encodeHashCountedSet(encoder, "topFrameRegistrableDomainsWhichAccessedWebAPIs", topFrameRegistrableDomainsWhichAccessedWebAPIs);
+    encodeCanvasActivityRecord(encoder, "canvasActivityRecord", canvasActivityRecord);
+    encodeOptionSet(encoder, "navigatorFunctionsAccessedBitMask", navigatorFunctionsAccessed);
+    encodeOptionSet(encoder, "screenFunctionsAccessedBitMask", screenFunctionsAccessed);
 }
 
 static void decodeHashCountedSet(KeyedDecoder& decoder, const String& label, HashCountedSet<String>& hashCountedSet)
@@ -110,11 +148,11 @@
     });
 }
 
-static void decodeHashSet(KeyedDecoder& decoder, const String& label, HashSet<String>& hashSet)
+static void decodeHashSet(KeyedDecoder& decoder, const String& label, const String& key, HashSet<String>& hashSet)
 {
     Vector<String> ignore;
-    decoder.decodeObjects(label, ignore, [&hashSet](KeyedDecoder& decoderInner, String& origin) {
-        if (!decoderInner.decodeString("origin", origin))
+    decoder.decodeObjects(label, ignore, [&hashSet, &key](KeyedDecoder& decoderInner, String& origin) {
+        if (!decoderInner.decodeString(key, origin))
             return false;
         
         hashSet.add(origin);
@@ -122,6 +160,40 @@
     });
 }
 
+static void decodeOriginHashSet(KeyedDecoder& decoder, const String& label, HashSet<String>& hashSet)
+{
+    decodeHashSet(decoder, label, "origin", hashSet);
+}
+
+template<typename T>
+static void decodeOptionSet(KeyedDecoder& decoder, const String& label, OptionSet<T>& optionSet)
+{
+    uint64_t optionSetBitMask = 0;
+    decoder.decodeUInt64(label, optionSetBitMask);
+    optionSet = OptionSet<T>::fromRaw(optionSetBitMask);
+}
+    
+static void decodeFontHashSet(KeyedDecoder& decoder, const String& label, HashSet<String>& hashSet)
+{
+    decodeHashSet(decoder, label, "font", hashSet);
+}
+    
+static void decodeCanvasActivityRecord(KeyedDecoder& decoder, const String& label, CanvasActivityRecord& canvasActivityRecord)
+{
+    decoder.decodeObject(label, canvasActivityRecord, [] (KeyedDecoder& decoderInner, CanvasActivityRecord& canvasActivityRecord) {
+        if (!decoderInner.decodeBool("wasDataRead", canvasActivityRecord.wasDataRead))
+            return false;
+        Vector<String> ignore;
+        decoderInner.decodeObjects("textWritten", ignore, [&canvasActivityRecord] (KeyedDecoder& decoderInner2, String& text) {
+            if (!decoderInner2.decodeString("text", text))
+                return false;
+            canvasActivityRecord.textWritten.add(text);
+            return true;
+        });
+        return true;
+    });
+}
+
 bool ResourceLoadStatistics::decode(KeyedDecoder& decoder, unsigned modelVersion)
 {
     if (!decoder.decodeString("PrevalentResourceOrigin", highLevelDomain))
@@ -132,7 +204,7 @@
         return false;
 
     // Storage access
-    decodeHashSet(decoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins);
+    decodeOriginHashSet(decoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins);
 
     // Top frame stats
     if (modelVersion >= 11) {
@@ -180,6 +252,16 @@
         if (!decoder.decodeUInt32("timesAccessedAsFirstPartyDueToStorageAccessAPI", timesAccessedAsFirstPartyDueToStorageAccessAPI))
             timesAccessedAsFirstPartyDueToStorageAccessAPI = 0;
     }
+    
+    if (modelVersion >= 13) {
+        decodeFontHashSet(decoder, "fontsFailedToLoad", fontsFailedToLoad);
+        decodeFontHashSet(decoder, "fontsSuccessfullyLoaded", fontsSuccessfullyLoaded);
+        decodeHashCountedSet(decoder, "topFrameRegistrableDomainsWhichAccessedWebAPIs", topFrameRegistrableDomainsWhichAccessedWebAPIs);
+        decodeCanvasActivityRecord(decoder, "canvasActivityRecord", canvasActivityRecord);
+        decodeOptionSet(decoder, "navigatorFunctionsAccessedBitMask", navigatorFunctionsAccessed);
+        decodeOptionSet(decoder, "screenFunctionsAccessedBitMask", screenFunctionsAccessed);
+    }
+    
     return true;
 }
 
@@ -225,11 +307,81 @@
     }
 }
 
+static ASCIILiteral navigatorAPIEnumToString(ResourceLoadStatistics::NavigatorAPI navigatorEnum)
+{
+    switch (navigatorEnum) {
+    case ResourceLoadStatistics::NavigatorAPI::JavaEnabled:
+        return "javaEnabled"_s;
+    case ResourceLoadStatistics::NavigatorAPI::MimeTypes:
+        return "mimeTypes"_s;
+    case ResourceLoadStatistics::NavigatorAPI::CookieEnabled:
+        return "cookieEnabled"_s;
+    case ResourceLoadStatistics::NavigatorAPI::Plugins:
+        return "plugins"_s;
+    case ResourceLoadStatistics::NavigatorAPI::UserAgent:
+        return "userAgent"_s;
+    case ResourceLoadStatistics::NavigatorAPI::AppVersion:
+        return "appVersion"_s;
+    }
+    ASSERT_NOT_REACHED();
+    return "Invalid navigator API"_s;
+}
+
+static ASCIILiteral screenAPIEnumToString(ResourceLoadStatistics::ScreenAPI screenEnum)
+{
+    switch (screenEnum) {
+    case ResourceLoadStatistics::ScreenAPI::Height:
+        return "height"_s;
+    case ResourceLoadStatistics::ScreenAPI::Width:
+        return "width"_s;
+    case ResourceLoadStatistics::ScreenAPI::ColorDepth:
+        return "colorDepth"_s;
+    case ResourceLoadStatistics::ScreenAPI::PixelDepth:
+        return "pixelDepth"_s;
+    case ResourceLoadStatistics::ScreenAPI::AvailLeft:
+        return "availLeft"_s;
+    case ResourceLoadStatistics::ScreenAPI::AvailTop:
+        return "availTop"_s;
+    case ResourceLoadStatistics::ScreenAPI::AvailHeight:
+        return "availHeight"_s;
+    case ResourceLoadStatistics::ScreenAPI::AvailWidth:
+        return "availWidth"_s;
+    }
+    ASSERT_NOT_REACHED();
+    return "Invalid screen API"_s;
+}
+    
+static void appendNavigatorAPIOptionSet(StringBuilder& builder, const OptionSet<ResourceLoadStatistics::NavigatorAPI>& optionSet)
+{
+    if (optionSet.isEmpty())
+        return;
+    builder.appendLiteral("    navigatorFunctionsAccessed:\n");
+    for (auto navigatorAPI : optionSet) {
+        builder.appendLiteral("        ");
+        builder.append(navigatorAPIEnumToString(navigatorAPI).characters());
+        builder.append('\n');
+    }
+}
+    
+static void appendScreenAPIOptionSet(StringBuilder& builder, const OptionSet<ResourceLoadStatistics::ScreenAPI>& optionSet)
+{
+    if (optionSet.isEmpty())
+        return;
+    builder.appendLiteral("    screenFunctionsAccessed:\n");
+    for (auto screenAPI : optionSet) {
+        builder.appendLiteral("        ");
+        builder.append(screenAPIEnumToString(screenAPI).characters());
+        builder.append('\n');
+    }
+}
+
 String ResourceLoadStatistics::toString() const
 {
     StringBuilder builder;
-    
-    builder.appendLiteral("lastSeen");
+    builder.appendLiteral("High level domain: ");
+    builder.append(highLevelDomain);
+    builder.append('\n');
+    builder.appendLiteral("    lastSeen: ");
     builder.appendNumber(lastSeen.secondsSinceEpoch().value());
     builder.append('\n');
     
@@ -239,7 +391,7 @@
     builder.appendLiteral("    mostRecentUserInteraction: ");
     builder.appendNumber(mostRecentUserInteractionTime.secondsSinceEpoch().value());
     builder.append('\n');
-    appendBoolean(builder, "    grandfathered", grandfathered);
+    appendBoolean(builder, "grandfathered", grandfathered);
     builder.append('\n');
 
     // Storage access
@@ -259,7 +411,9 @@
 
     // Prevalent Resource
     appendBoolean(builder, "isPrevalentResource", isPrevalentResource);
-    appendBoolean(builder, "    isVeryPrevalentResource", isVeryPrevalentResource);
+    builder.append('\n');
+    appendBoolean(builder, "isVeryPrevalentResource", isVeryPrevalentResource);
+    builder.append('\n');
     builder.appendLiteral("    dataRecordsRemoved: ");
     builder.appendNumber(dataRecordsRemoved);
     builder.append('\n');
@@ -268,7 +422,15 @@
     appendBoolean(builder, "isMarkedForCookieBlocking", isMarkedForCookieBlocking);
     builder.append('\n');
 
+    appendHashSet(builder, "fontsFailedToLoad", fontsFailedToLoad);
+    appendHashSet(builder, "fontsSuccessfullyLoaded", fontsSuccessfullyLoaded);
+    appendHashCountedSet(builder, "topFrameRegistrableDomainsWhichAccessedWebAPIs", topFrameRegistrableDomainsWhichAccessedWebAPIs);
+    appendNavigatorAPIOptionSet(builder, navigatorFunctionsAccessed);
+    appendScreenAPIOptionSet(builder, screenFunctionsAccessed);
+    appendHashSet(builder, "canvasTextWritten", canvasActivityRecord.textWritten);
+    appendBoolean(builder, "canvasReadData", canvasActivityRecord.wasDataRead);
     builder.append('\n');
+    builder.append('\n');
 
     return builder.toString();
 }
@@ -330,6 +492,13 @@
     
     // In-memory only
     isMarkedForCookieBlocking |= other.isMarkedForCookieBlocking;
+
+    mergeHashSet(fontsFailedToLoad, other.fontsFailedToLoad);
+    mergeHashSet(fontsSuccessfullyLoaded, other.fontsSuccessfullyLoaded);
+    mergeHashCountedSet(topFrameRegistrableDomainsWhichAccessedWebAPIs, other.topFrameRegistrableDomainsWhichAccessedWebAPIs);
+    canvasActivityRecord.mergeWith(other.canvasActivityRecord);
+    navigatorFunctionsAccessed.add(other.navigatorFunctionsAccessed);
+    screenFunctionsAccessed.add(other.screenFunctionsAccessed);
 }
 
 String ResourceLoadStatistics::primaryDomain(const URL& url)

Modified: trunk/Source/WebCore/loader/ResourceLoadStatistics.h (235896 => 235897)


--- trunk/Source/WebCore/loader/ResourceLoadStatistics.h	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/ResourceLoadStatistics.h	2018-09-11 17:14:07 UTC (rev 235897)
@@ -25,9 +25,11 @@
 
 #pragma once
 
+#include "CanvasActivityRecord.h"
 #include "URL.h"
 #include <wtf/HashCountedSet.h>
 #include <wtf/HashSet.h>
+#include <wtf/OptionSet.h>
 #include <wtf/WallTime.h>
 #include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>
@@ -96,6 +98,33 @@
 
     // In-memory only
     bool isMarkedForCookieBlocking { false };
+    
+    // This set represents the registrable domain of the top frame where web API
+    // were used in the top frame or one of its subframes.
+    HashCountedSet<String> topFrameRegistrableDomainsWhichAccessedWebAPIs;
+    HashSet<String> fontsFailedToLoad;
+    HashSet<String> fontsSuccessfullyLoaded;
+    CanvasActivityRecord canvasActivityRecord;
+    enum class NavigatorAPI : uint64_t {
+        AppVersion = 1 << 0,
+        UserAgent = 1 << 1,
+        Plugins = 1 << 2,
+        MimeTypes = 1 << 3,
+        CookieEnabled = 1 << 4,
+        JavaEnabled = 1 << 5,
+    };
+    enum class ScreenAPI : uint64_t {
+        Height = 1 << 0,
+        Width = 1 << 1,
+        ColorDepth = 1 << 2,
+        PixelDepth = 1 << 3,
+        AvailLeft = 1 << 4,
+        AvailTop = 1 << 5,
+        AvailHeight = 1 << 6,
+        AvailWidth = 1 << 7,
+    };
+    OptionSet<NavigatorAPI> navigatorFunctionsAccessed;
+    OptionSet<ScreenAPI> screenFunctionsAccessed;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/ResourceTiming.cpp (235896 => 235897)


--- trunk/Source/WebCore/loader/ResourceTiming.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/loader/ResourceTiming.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -28,8 +28,10 @@
 
 #include "CachedResource.h"
 #include "PerformanceServerTiming.h"
+#include "RuntimeEnabledFeatures.h"
 #include "SecurityOrigin.h"
 #include "ServerTimingParser.h"
+#include <wtf/CrossThreadCopier.h>
 
 namespace WebCore {
 

Modified: trunk/Source/WebCore/page/Navigator.cpp (235896 => 235897)


--- trunk/Source/WebCore/page/Navigator.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/page/Navigator.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -37,6 +37,8 @@
 #include "Page.h"
 #include "PlatformStrategies.h"
 #include "PluginData.h"
+#include "ResourceLoadObserver.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
 #include "SecurityOrigin.h"
 #include "Settings.h"
@@ -44,7 +46,6 @@
 #include <wtf/StdLibExtras.h>
 #include <wtf/WeakPtr.h>
 
-
 namespace WebCore {
 using namespace WTF;
 
@@ -74,6 +75,8 @@
 {
     if (!m_frame)
         return String();
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::AppVersion);
     String appVersion = NavigatorBase::appVersion();
     if (shouldHideFourDot(*m_frame))
         appVersion.replace("4.", "4_");
@@ -82,7 +85,11 @@
 
 const String& Navigator::userAgent() const
 {
-    if (m_userAgent.isNull() && m_frame && m_frame->page())
+    if (!m_frame || !m_frame->page())
+        return m_userAgent;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::UserAgent);
+    if (m_userAgent.isNull())
         m_userAgent = m_frame->loader().userAgent(m_frame->document()->url());
     return m_userAgent;
 }
@@ -136,6 +143,10 @@
 
 DOMPluginArray& Navigator::plugins()
 {
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+        if (m_frame)
+            ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::Plugins);
+    }
     if (!m_plugins)
         m_plugins = DOMPluginArray::create(m_frame);
     return *m_plugins;
@@ -143,6 +154,10 @@
 
 DOMMimeTypeArray& Navigator::mimeTypes()
 {
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
+        if (m_frame)
+            ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::MimeTypes);
+    }
     if (!m_mimeTypes)
         m_mimeTypes = DOMMimeTypeArray::create(m_frame);
     return *m_mimeTypes;
@@ -153,6 +168,9 @@
     if (!m_frame)
         return false;
 
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::CookieEnabled);
+
     if (m_frame->page() && !m_frame->page()->settings().cookieEnabled())
         return false;
 
@@ -168,6 +186,9 @@
     if (!m_frame)
         return false;
 
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logNavigatorAPIAccessed(*m_frame->document(), ResourceLoadStatistics::NavigatorAPI::JavaEnabled);
+
     if (!m_frame->settings().isJavaEnabled())
         return false;
     if (m_frame->document()->securityOrigin().isLocal() && !m_frame->settings().isJavaEnabledForLocalFiles())

Modified: trunk/Source/WebCore/page/Screen.cpp (235896 => 235897)


--- trunk/Source/WebCore/page/Screen.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebCore/page/Screen.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -33,6 +33,8 @@
 #include "Frame.h"
 #include "FrameView.h"
 #include "PlatformScreen.h"
+#include "ResourceLoadObserver.h"
+#include "RuntimeEnabledFeatures.h"
 
 namespace WebCore {
 
@@ -45,6 +47,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::Height);
     long height = static_cast<long>(screenRect(m_frame->view()).height());
     return static_cast<unsigned>(height);
 }
@@ -53,6 +57,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::Width);
     long width = static_cast<long>(screenRect(m_frame->view()).width());
     return static_cast<unsigned>(width);
 }
@@ -61,6 +67,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::ColorDepth);
     return static_cast<unsigned>(screenDepth(m_frame->view()));
 }
 
@@ -68,6 +76,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::PixelDepth);
     return static_cast<unsigned>(screenDepth(m_frame->view()));
 }
 
@@ -75,6 +85,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::AvailLeft);
     return static_cast<int>(screenAvailableRect(m_frame->view()).x());
 }
 
@@ -82,6 +94,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::AvailTop);
     return static_cast<int>(screenAvailableRect(m_frame->view()).y());
 }
 
@@ -89,6 +103,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::AvailHeight);
     return static_cast<unsigned>(screenAvailableRect(m_frame->view()).height());
 }
 
@@ -96,6 +112,8 @@
 {
     if (!m_frame)
         return 0;
+    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
+        ResourceLoadObserver::shared().logScreenAPIAccessed(*m_frame->document(), ResourceLoadStatistics::ScreenAPI::AvailWidth);
     return static_cast<unsigned>(screenAvailableRect(m_frame->view()).width());
 }
 

Modified: trunk/Source/WebKit/ChangeLog (235896 => 235897)


--- trunk/Source/WebKit/ChangeLog	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebKit/ChangeLog	2018-09-11 17:14:07 UTC (rev 235897)
@@ -1 +1,14 @@
+2018-09-11  Woodrow Wang  <[email protected]>
+
+        Add Web API Statistics Collection
+        https://bugs.webkit.org/show_bug.cgi?id=187773
+        <rdar://problem/44155162>
+
+        Reviewed by Brent Fulgham.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<ResourceLoadStatistics>::encode):
+        (IPC::ArgumentCoder<ResourceLoadStatistics>::decode):
+        * UIProcess/ResourceLoadStatisticsMemoryStore.cpp:
+
 == Rolled over to ChangeLog-2018-09-11 ==

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (235896 => 235897)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -2664,6 +2664,16 @@
     encoder << statistics.isPrevalentResource;
     encoder << statistics.isVeryPrevalentResource;
     encoder << statistics.dataRecordsRemoved;
+    
+    encoder << statistics.fontsFailedToLoad;
+    encoder << statistics.fontsSuccessfullyLoaded;
+    encoder << statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs;
+    
+    encoder << statistics.canvasActivityRecord;
+    
+    encoder << statistics.navigatorFunctionsAccessed;
+    encoder << statistics.screenFunctionsAccessed;
+    
 }
 
 std::optional<ResourceLoadStatistics> ArgumentCoder<ResourceLoadStatistics>::decode(Decoder& decoder)
@@ -2723,7 +2733,25 @@
     
     if (!decoder.decode(statistics.dataRecordsRemoved))
         return std::nullopt;
-
+    
+    if (!decoder.decode(statistics.fontsFailedToLoad))
+        return std::nullopt;
+    
+    if (!decoder.decode(statistics.fontsSuccessfullyLoaded))
+        return std::nullopt;
+    
+    if (!decoder.decode(statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs))
+        return std::nullopt;
+    
+    if (!decoder.decode(statistics.canvasActivityRecord))
+        return std::nullopt;
+    
+    if (!decoder.decode(statistics.navigatorFunctionsAccessed))
+        return std::nullopt;
+    
+    if (!decoder.decode(statistics.screenFunctionsAccessed))
+        return std::nullopt;
+    
     return WTFMove(statistics);
 }
 

Modified: trunk/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp (235896 => 235897)


--- trunk/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp	2018-09-11 16:24:21 UTC (rev 235896)
+++ trunk/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp	2018-09-11 17:14:07 UTC (rev 235897)
@@ -46,7 +46,7 @@
 namespace WebKit {
 using namespace WebCore;
 
-constexpr unsigned statisticsModelVersion { 12 };
+constexpr unsigned statisticsModelVersion { 13 };
 constexpr unsigned maxNumberOfRecursiveCallsInRedirectTraceBack { 50 };
 constexpr Seconds minimumStatisticsProcessingInterval { 5_s };
 constexpr unsigned operatingDatesWindow { 30 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to