WebKit Bugzilla
Attachment 349353 Details for
Bug 187773
: Add Web API Statistics Collection
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-187773-20180910162832.patch (text/plain), 72.93 KB, created by
Woodrow Wang
on 2018-09-10 16:28:33 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Woodrow Wang
Created:
2018-09-10 16:28:33 PDT
Size:
72.93 KB
patch
obsolete
>Subversion Revision: 235872 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 4f6b22377e0c13c242185cc8be0dad07afb774be..19b670417bdc01a59c8f1b4660273a2928e8f198 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,114 @@ >+2018-09-10 Woodrow Wang <woodrow_wang@apple.com> >+ >+ 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-04 Woodrow Wang <woodrow_wang@apple.com> > > Add functionality to encode and decode a uint64_t in KeyedCoding >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 310936ba71b3231e4ecbf5c6bd3cb8955ee74923..f3913cce2e72eea125520bb82460723a3915ced9 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,16 @@ >+2018-09-10 Woodrow Wang <woodrow_wang@apple.com> >+ >+ 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: >+ > 2018-08-31 Woodrow Wang <woodrow_wang@apple.com> > > Add infrastructure to dump resource load statistics >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index 7801b309938570718d9a774c01542379a2a6dcb9..e387b0c9e43f01a01d69e16988bcaf8857d3eeba 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1250,6 +1250,7 @@ layout/layouttree/LayoutInlineContainer.cpp > layout/layouttree/LayoutReplaced.cpp > layout/layouttree/LayoutTreeBuilder.cpp > >+loader/CanvasActivityRecord.cpp > loader/ContentFilter.cpp > loader/CookieJar.cpp > loader/CrossOriginAccessControl.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index f40f41e6462febd60fccd076b060cd0666e20bb7..f43da8df0aa182d10101adb80c9d2d3d4f67a70b 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -4815,6 +4815,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, ); }; }; >@@ -14504,6 +14505,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>"; }; >@@ -24238,6 +24241,8 @@ > 93A1EAA20A5634D8006960A0 /* mac */, > 63152D181F9531EE007A5E4B /* ApplicationManifestLoader.cpp */, > 63152D171F9531EE007A5E4B /* ApplicationManifestLoader.h */, >+ EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */, >+ EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */, > A149786C1ABAF33800CEF7E4 /* ContentFilter.cpp */, > A149786D1ABAF33800CEF7E4 /* ContentFilter.h */, > E1424C91164B52C800F32D40 /* CookieJar.cpp */, >@@ -27320,6 +27325,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 */, >diff --git a/Source/WebCore/css/CSSFontFaceSource.cpp b/Source/WebCore/css/CSSFontFaceSource.cpp >index 4d603b5769587cad4cd6669ad2a65ba37baeb8e8..dc2bd7e5bc31e15815399f8b59f68d3c67617082 100644 >--- a/Source/WebCore/css/CSSFontFaceSource.cpp >+++ b/Source/WebCore/css/CSSFontFaceSource.cpp >@@ -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 @@ void CSSFontFaceSource::load(CSSFontSelector* fontSelector) > 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); > } >diff --git a/Source/WebCore/css/CSSFontSelector.cpp b/Source/WebCore/css/CSSFontSelector.cpp >index a2e5eb2fbd7e334a53c1533cfda9a6987991642f..d55127bec949a99571c4eec9557f8e62926ccd07 100644 >--- a/Source/WebCore/css/CSSFontSelector.cpp >+++ b/Source/WebCore/css/CSSFontSelector.cpp >@@ -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 @@ FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescr > > 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 @@ RefPtr<Font> CSSFontSelector::fallbackFontAt(const FontDescription& fontDescript > > 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; > } > > } >diff --git a/Source/WebCore/html/HTMLCanvasElement.cpp b/Source/WebCore/html/HTMLCanvasElement.cpp >index 6298643a2d96092a4cfee988dd28b6d937c5da73..4537bbbe45b6046d9c90fb148aec0be9303bc8a4 100644 >--- a/Source/WebCore/html/HTMLCanvasElement.cpp >+++ b/Source/WebCore/html/HTMLCanvasElement.cpp >@@ -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 @@ ExceptionOr<UncachedString> HTMLCanvasElement::toDataURL(const String& mimeType, > > 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 @@ ExceptionOr<void> HTMLCanvasElement::toBlob(ScriptExecutionContext& context, Ref > 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 @@ ExceptionOr<void> HTMLCanvasElement::toBlob(ScriptExecutionContext& context, Ref > 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 @@ RefPtr<MediaSample> HTMLCanvasElement::toMediaSample() > auto* imageBuffer = buffer(); > if (!imageBuffer) > return nullptr; >+ if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) >+ ResourceLoadObserver::shared().logCanvasRead(document()); > > #if PLATFORM(COCOA) > makeRenderingResultsAvailable(); >@@ -781,6 +791,8 @@ ExceptionOr<Ref<MediaStream>> HTMLCanvasElement::captureStream(ScriptExecutionCo > { > 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); >diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp >index e27d95194819b02e9414d49bfa8faff2ea1761de..d15dec460ed7548bb576c17951639d9a28716037 100644 >--- a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp >+++ b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp >@@ -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 @@ static void normalizeSpaces(String& text) > > 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 @@ FloatPoint CanvasRenderingContext2D::textOffset(float width, TextDirection direc > > 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(); > >diff --git a/Source/WebCore/loader/CanvasActivityRecord.cpp b/Source/WebCore/loader/CanvasActivityRecord.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..1bd789df3339b101d3cb768cc25663c50ffb98ef >--- /dev/null >+++ b/Source/WebCore/loader/CanvasActivityRecord.cpp >@@ -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 >diff --git a/Source/WebCore/loader/CanvasActivityRecord.h b/Source/WebCore/loader/CanvasActivityRecord.h >new file mode 100644 >index 0000000000000000000000000000000000000000..1e13f48cba6d2c83f0e7a30f3d361950bc124e51 >--- /dev/null >+++ b/Source/WebCore/loader/CanvasActivityRecord.h >@@ -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 >diff --git a/Source/WebCore/loader/DocumentThreadableLoader.cpp b/Source/WebCore/loader/DocumentThreadableLoader.cpp >index 373549005bf4b1e09cc90e440738d0e40095f7a2..da17102d5abf3d54c3623e8d3fdcd1d6045ccdbc 100644 >--- a/Source/WebCore/loader/DocumentThreadableLoader.cpp >+++ b/Source/WebCore/loader/DocumentThreadableLoader.cpp >@@ -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" >diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp >index d7318b110f22d91073de02295206cc304c195605..6ab68551f8584d3faddbbfb8198c8d5d5a2f0857 100644 >--- a/Source/WebCore/loader/FrameLoader.cpp >+++ b/Source/WebCore/loader/FrameLoader.cpp >@@ -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> >diff --git a/Source/WebCore/loader/ResourceLoadObserver.cpp b/Source/WebCore/loader/ResourceLoadObserver.cpp >index 8d03ba06755fa4570650f4e6d9b03bb68483df3a..467e2699ab521c1e95d665d81616961920c73a9a 100644 >--- a/Source/WebCore/loader/ResourceLoadObserver.cpp >+++ b/Source/WebCore/loader/ResourceLoadObserver.cpp >@@ -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 @@ void ResourceLoadObserver::requestStorageAccessUnderOpener(const String& domainI > } > #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] { >diff --git a/Source/WebCore/loader/ResourceLoadObserver.h b/Source/WebCore/loader/ResourceLoadObserver.h >index 5b6d9188fbd2228a913f81f33ad7dbc90534bb26..5f051bb058e055cf816547e72064d84038d8d056 100644 >--- a/Source/WebCore/loader/ResourceLoadObserver.h >+++ b/Source/WebCore/loader/ResourceLoadObserver.h >@@ -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 @@ public: > 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&); > >diff --git a/Source/WebCore/loader/ResourceLoadStatistics.cpp b/Source/WebCore/loader/ResourceLoadStatistics.cpp >index 9e2b7cf31519ceb3856c38616c75720724f70ede..32596d1fad57052e68085605288ad3b80142dd93 100644 >--- a/Source/WebCore/loader/ResourceLoadStatistics.cpp >+++ b/Source/WebCore/loader/ResourceLoadStatistics.cpp >@@ -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,13 +50,43 @@ static void encodeHashCountedSet(KeyedEncoder& encoder, const String& label, con > }); > } > >-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); >+ }); > }); > } > >@@ -71,7 +102,7 @@ void ResourceLoadStatistics::encode(KeyedEncoder& encoder) const > 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 @@ void ResourceLoadStatistics::encode(KeyedEncoder& encoder) const > > 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 decodeHashCountedSet(KeyedDecoder& decoder, const String& label, Has > }); > } > >-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 decodeHashSet(KeyedDecoder& decoder, const String& label, HashSet<St > }); > } > >+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 @@ bool ResourceLoadStatistics::decode(KeyedDecoder& decoder, unsigned modelVersion > return false; > > // Storage access >- decodeHashSet(decoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins); >+ decodeOriginHashSet(decoder, "storageAccessUnderTopFrameOrigins", storageAccessUnderTopFrameOrigins); > > // Top frame stats > if (modelVersion >= 11) { >@@ -180,6 +252,16 @@ bool ResourceLoadStatistics::decode(KeyedDecoder& decoder, unsigned modelVersion > 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 void appendHashSet(StringBuilder& builder, const String& label, const Has > } > } > >+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 @@ String ResourceLoadStatistics::toString() const > 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 @@ String ResourceLoadStatistics::toString() const > > // 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,6 +422,14 @@ String ResourceLoadStatistics::toString() const > 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 @@ void ResourceLoadStatistics::merge(const ResourceLoadStatistics& other) > > // 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) >diff --git a/Source/WebCore/loader/ResourceLoadStatistics.h b/Source/WebCore/loader/ResourceLoadStatistics.h >index 27a17ff93551619013ebb8ec05ac25d3d561b668..f94d6fd19e7746df5e683a957f0fd99a772d321a 100644 >--- a/Source/WebCore/loader/ResourceLoadStatistics.h >+++ b/Source/WebCore/loader/ResourceLoadStatistics.h >@@ -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 @@ struct ResourceLoadStatistics { > > // 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 >diff --git a/Source/WebCore/loader/ResourceTiming.cpp b/Source/WebCore/loader/ResourceTiming.cpp >index a6ab6802761c7256ea9a08677323936acdb4271c..4c25981a8779e3bf6f37817ab0886acc1d799384 100644 >--- a/Source/WebCore/loader/ResourceTiming.cpp >+++ b/Source/WebCore/loader/ResourceTiming.cpp >@@ -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 { > >diff --git a/Source/WebCore/page/Navigator.cpp b/Source/WebCore/page/Navigator.cpp >index 7569ca854ec6bb0993e5c3a7d0ee82419f52b3a3..21f9e3e46a4cb4a28f9061fd1a84339190ebfd99 100644 >--- a/Source/WebCore/page/Navigator.cpp >+++ b/Source/WebCore/page/Navigator.cpp >@@ -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 @@ String Navigator::appVersion() const > { > 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 @@ String Navigator::appVersion() const > > 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 @@ void Navigator::share(ScriptExecutionContext& context, ShareData data, Ref<Defer > > 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 @@ DOMPluginArray& Navigator::plugins() > > 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 @@ bool Navigator::cookieEnabled() const > 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 @@ bool Navigator::javaEnabled() const > 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()) >diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp >index ff487d7cad06c754f00fbbd0244bdaa87ae9d2c0..b20abe40641020f0a619620c30f2c13a98a317ed 100644 >--- a/Source/WebCore/page/Screen.cpp >+++ b/Source/WebCore/page/Screen.cpp >@@ -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 @@ unsigned Screen::height() const > { > 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 @@ unsigned Screen::width() const > { > 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 @@ unsigned Screen::colorDepth() const > { > 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 @@ unsigned Screen::pixelDepth() const > { > 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 @@ int Screen::availLeft() const > { > 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 @@ int Screen::availTop() const > { > 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 @@ unsigned Screen::availHeight() const > { > 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 @@ unsigned Screen::availWidth() const > { > 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()); > } > >diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >index 9dab37dd60302bf2ea0e296c396809ca6cd80d70..886059275690653a1c5b919af78a51dee1697079 100644 >--- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >@@ -2664,6 +2664,16 @@ void ArgumentCoder<ResourceLoadStatistics>::encode(Encoder& encoder, const WebCo > 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 @@ std::optional<ResourceLoadStatistics> ArgumentCoder<ResourceLoadStatistics>::dec > > 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); > } > >diff --git a/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp b/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp >index b545adf5d10bf44c87988578d44e72b1d5ad40c7..14c837ad59d5d7e393726597320b56ae451985fe 100644 >--- a/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp >+++ b/Source/WebKit/UIProcess/ResourceLoadStatisticsMemoryStore.cpp >@@ -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 }; >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index f944ecf070564843f072e19a044fcddbed1123a4..00d3fddf38c2ef188e397318763267a8eb95f15a 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,25 @@ >+2018-09-10 Woodrow Wang <woodrow_wang@apple.com> >+ >+ 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-10 Ryan Haddad <ryanhaddad@apple.com> > > Unreviewed test gardening, rebaseline fast/events/ios/keyup.html after r235818. >diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations >index a081bb2e9ce49849389c2751d0c28caa27f93a02..294edd9247ff3850dfd8db85bd404061044523e7 100644 >--- a/LayoutTests/TestExpectations >+++ b/LayoutTests/TestExpectations >@@ -2243,3 +2243,5 @@ fast/gradients/conic-off-center.html [ Skip ] > 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 ] >diff --git a/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt b/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..16a6e6986af2c01396302f2e16e9d967b727934e >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection-expected.txt >@@ -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 >+ >diff --git a/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html b/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html >new file mode 100644 >index 0000000000000000000000000000000000000000..153b09b79d39729c070e6e25422cb3bae484fc3a >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/canvas-read-and-write-data-collection.html >@@ -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="/js-test-resources/js-test.js"></script> >+</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 >diff --git a/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt b/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a9ef32f34faab89b1bc211fff4c59be35601f791 >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection-expected.txt >@@ -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 >+ >diff --git a/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html b/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html >new file mode 100644 >index 0000000000000000000000000000000000000000..bf92b3ad65d88e6adc32466b26c11b9be08e8691 >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/font-load-data-collection.html >@@ -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="/js-test-resources/js-test.js"></script> >+</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 >diff --git a/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt b/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..05310683d2ca1f8ef8e07de40635d4489184a24f >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection-expected.txt >@@ -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 >+ >diff --git a/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html b/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html >new file mode 100644 >index 0000000000000000000000000000000000000000..bdbf164060e8c679f65fe66505f1f8041515b78a >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/navigator-functions-accessed-data-collection.html >@@ -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="/js-test-resources/js-test.js"></script> >+</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 >diff --git a/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt b/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..c1eaaa5d07abbaf29489d53d72a09618f73ce595 >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection-expected.txt >@@ -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 >+ >diff --git a/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html b/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html >new file mode 100644 >index 0000000000000000000000000000000000000000..070310bcbda0bc11f3e05d6fb7f469e074078d30 >--- /dev/null >+++ b/LayoutTests/http/tests/webAPIStatistics/screen-functions-accessed-data-collection.html >@@ -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="/js-test-resources/js-test.js"></script> >+</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 >diff --git a/LayoutTests/platform/ios-wk2/TestExpectations b/LayoutTests/platform/ios-wk2/TestExpectations >index 1ed6743d882a80169a84ab439210a7c16d2d2734..0b27c86017c7244272bce0f4bc2a27645cf4af8d 100644 >--- a/LayoutTests/platform/ios-wk2/TestExpectations >+++ b/LayoutTests/platform/ios-wk2/TestExpectations >@@ -50,6 +50,8 @@ http/tests/security/contentSecurityPolicy/manifest-src-allowed.html [ Pass ] > http/tests/security/contentSecurityPolicy/manifest-src-blocked.html [ Pass ] > applicationmanifest/ [ Pass ] > >+webkit.org/b/187773 http/tests/webAPIStatistics [ Pass ] >+ > #////////////////////////////////////////////////////////////////////////////////////////// > # End platform-specific directories. > #////////////////////////////////////////////////////////////////////////////////////////// >diff --git a/LayoutTests/platform/mac-wk2/TestExpectations b/LayoutTests/platform/mac-wk2/TestExpectations >index 53e4c9de41f2db4d0f017f6d3fb8882e1c702ced..a3c501d7f809def9ebe11f7a4f8d6ef37424bb95 100644 >--- a/LayoutTests/platform/mac-wk2/TestExpectations >+++ b/LayoutTests/platform/mac-wk2/TestExpectations >@@ -57,6 +57,8 @@ webkit.org/b/187183 http/tests/security/pasteboard-file-url.html [ Pass ] > > fast/misc/valid-primary-screen-displayID.html [ Pass ] > >+webkit.org/b/187773 http/tests/webAPIStatistics [ Pass ] >+ > #////////////////////////////////////////////////////////////////////////////////////////// > # End platform-specific directories. > #//////////////////////////////////////////////////////////////////////////////////////////
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 187773
:
345263
|
345271
|
345272
|
345274
|
345278
|
345335
|
345578
|
345617
|
345851
|
345865
|
345969
|
346072
|
346089
|
346092
|
346108
|
346115
|
346123
|
346126
|
346127
|
346172
|
347273
|
347277
|
347282
|
348041
|
348057
|
348065
|
348067
|
348068
|
348070
|
348227
|
348230
|
348253
|
348309
|
348323
|
348326
|
348512
|
348523
|
348528
|
348542
|
348653
|
348660
|
348682
|
348693
|
348964
|
348968
|
348976
|
349156
|
349175
|
349193
|
349196
|
349314
|
349328
|
349330
| 349353