blob: 26c2a970a233655404ce22b5c5fabee62ba839b6 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/scheme_registry.h"
#include "third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom-blink.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/frame/deprecation/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/task_environment.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace {
const char kExtensionFeaturesHistogramName[] =
"Blink.UseCounter.Extensions.Features";
const char kExtensionUrl[] = "chrome-extension://dummysite/";
int GetPageVisitsBucketforHistogram(const std::string& histogram_name) {
if (histogram_name.find("CSS") == std::string::npos) {
return static_cast<int>(blink::mojom::WebFeature::kPageVisits);
}
// For CSS histograms, the page visits bucket should be 1.
return static_cast<int>(
blink::mojom::blink::CSSSampleId::kTotalPagesMeasured);
}
} // namespace
namespace blink {
using WebFeature = mojom::WebFeature;
class UseCounterImplTest : public testing::Test {
public:
class DummyLocalFrameClient : public EmptyLocalFrameClient {
public:
DummyLocalFrameClient() = default;
const std::vector<UseCounterFeature>& observed_features() const {
return observed_features_;
}
private:
void DidObserveNewFeatureUsage(const UseCounterFeature& feature) override {
observed_features_.push_back(feature);
}
std::vector<UseCounterFeature> observed_features_;
};
UseCounterImplTest()
: dummy_(std::make_unique<DummyPageHolder>(
/* initial_view_size= */ gfx::Size(),
/* chrome_client= */ nullptr,
/* local_frame_client= */
MakeGarbageCollected<DummyLocalFrameClient>())) {
Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
}
int ToSampleId(CSSPropertyID property) const {
return static_cast<int>(GetCSSSampleId(property));
}
bool IsInternal(CSSPropertyID property) const {
return CSSProperty::Get(property).IsInternal();
}
// Returns all alternative properties. In other words, a set of of all
// properties marked with 'alternative_of' in css_properties.json5.
//
// This is useful for checking whether or not a given CSSPropertyID is an
// an alternative property.
HashSet<CSSPropertyID> GetAlternatives() const {
HashSet<CSSPropertyID> alternatives;
for (CSSPropertyID property : CSSPropertyIDList()) {
if (CSSPropertyID alternative_id =
CSSUnresolvedProperty::Get(property).GetAlternative();
alternative_id != CSSPropertyID::kInvalid) {
alternatives.insert(alternative_id);
}
}
for (CSSPropertyID property : kCSSPropertyAliasList) {
if (CSSPropertyID alternative_id =
CSSUnresolvedProperty::Get(property).GetAlternative();
alternative_id != CSSPropertyID::kInvalid) {
alternatives.insert(alternative_id);
}
}
return alternatives;
}
protected:
LocalFrame* GetFrame() { return &dummy_->GetFrame(); }
void SetIsViewSource() { dummy_->GetDocument().SetIsViewSource(true); }
void SetURL(const KURL& url) { dummy_->GetDocument().SetURL(url); }
Document& GetDocument() { return dummy_->GetDocument(); }
test::TaskEnvironment task_environment_;
std::unique_ptr<DummyPageHolder> dummy_;
base::HistogramTester histogram_tester_;
void UpdateAllLifecyclePhases(Document& document) {
document.View()->UpdateAllLifecyclePhasesForTest();
}
};
class UseCounterImplBrowserReportTest
: public UseCounterImplTest,
public ::testing::WithParamInterface</* URL */ const char*> {};
INSTANTIATE_TEST_SUITE_P(All,
UseCounterImplBrowserReportTest,
::testing::Values("chrome-extension://dummysite/",
"file://dummyfile",
"data:;base64,",
"ftp://ftp.dummy/dummy.txt",
"http://foo.com",
"https://bar.com"));
// UseCounter should not send events to browser when handling page with
// Non HTTP Family URLs, as these events will be discarded on the browser side
// in |MetricsWebContentsObserver::DoesTimingUpdateHaveError|.
TEST_P(UseCounterImplBrowserReportTest, ReportOnlyHTTPFamily) {
KURL url = url_test_helpers::ToKURL(GetParam());
SetURL(url);
UseCounterImpl use_counter;
use_counter.DidCommitLoad(GetFrame());
// Count every feature types in UseCounterFeatureType.
use_counter.Count(mojom::WebFeature::kFetch, GetFrame());
use_counter.Count(CSSPropertyID::kHeight,
UseCounterImpl::CSSPropertyType::kDefault, GetFrame());
use_counter.Count(CSSPropertyID::kHeight,
UseCounterImpl::CSSPropertyType::kAnimation, GetFrame());
auto* dummy_client =
static_cast<UseCounterImplBrowserReportTest::DummyLocalFrameClient*>(
GetFrame()->Client());
EXPECT_EQ(!dummy_client->observed_features().empty(),
url.ProtocolIsInHTTPFamily());
}
TEST_F(UseCounterImplTest, RecordingExtensions) {
const std::string histogram = kExtensionFeaturesHistogramName;
constexpr auto item = mojom::WebFeature::kFetch;
constexpr auto second_item = WebFeature::kFetchBodyStream;
const std::string url = kExtensionUrl;
CommonSchemeRegistry::RegisterURLSchemeAsExtension("chrome-extension");
UseCounterImpl::Context context = UseCounterImpl::kExtensionContext;
int page_visits_bucket = GetPageVisitsBucketforHistogram(histogram);
UseCounterImpl use_counter0(context, UseCounterImpl::kCommited);
// Test recording a single (arbitrary) counter
EXPECT_FALSE(use_counter0.IsCounted(item));
use_counter0.Count(item, GetFrame());
EXPECT_TRUE(use_counter0.IsCounted(item));
histogram_tester_.ExpectUniqueSample(histogram, static_cast<int>(item), 1);
// Test that repeated measurements have no effect
use_counter0.Count(item, GetFrame());
histogram_tester_.ExpectUniqueSample(histogram, static_cast<int>(item), 1);
// Test recording a different sample
EXPECT_FALSE(use_counter0.IsCounted(second_item));
use_counter0.Count(second_item, GetFrame());
EXPECT_TRUE(use_counter0.IsCounted(second_item));
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 1);
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(second_item),
1);
histogram_tester_.ExpectTotalCount(histogram, 2);
// After a page load, the histograms will be updated, even when the URL
// scheme is internal
UseCounterImpl use_counter1(context);
SetURL(url_test_helpers::ToKURL(url));
use_counter1.DidCommitLoad(GetFrame());
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 1);
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(second_item),
1);
histogram_tester_.ExpectBucketCount(histogram, page_visits_bucket, 1);
histogram_tester_.ExpectTotalCount(histogram, 3);
// Now a repeat measurement should get recorded again, exactly once
EXPECT_FALSE(use_counter1.IsCounted(item));
use_counter1.Count(item, GetFrame());
use_counter1.Count(item, GetFrame());
EXPECT_TRUE(use_counter1.IsCounted(item));
histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 2);
histogram_tester_.ExpectTotalCount(histogram, 4);
CommonSchemeRegistry::RemoveURLSchemeAsExtensionForTest("chrome-extension");
}
TEST_F(UseCounterImplTest, CSSSelectorPseudoWhere) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoWhere;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>.a+:where(.b, .c+.d) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoIs));
}
/*
* Counter-specific tests
*
* NOTE: Most individual UseCounters don't need dedicated test cases. They are
* "tested" by analyzing the data they generate including on some known pages.
* Feel free to add tests for counters where the triggering logic is
* non-trivial, but it's not required. Manual analysis is necessary to trust the
* data anyway, real-world pages are full of edge-cases and surprises that you
* won't find in unit testing anyway.
*/
TEST_F(UseCounterImplTest, CSSSelectorPseudoAnyLink) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoAnyLink;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:any-link { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSSelectorPseudoWebkitAnyLink) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoWebkitAnyLink;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:-webkit-any-link { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSTypedOMStylePropertyMap) {
UseCounterImpl use_counter;
WebFeature feature = WebFeature::kCSSTypedOMStylePropertyMap;
EXPECT_FALSE(GetDocument().IsUseCounted(feature));
GetDocument().CountUse(feature);
EXPECT_TRUE(GetDocument().IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSSelectorPseudoIs) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoIs;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>.a+:is(.b, .c+.d) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoWhere));
}
TEST_F(UseCounterImplTest, CSSSelectorPseudoDir) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorPseudoDir;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<style>:dir(ltr) { color: red; }</style>");
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-grid; grid-template-columns: 50%;'>"
"</div>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSFlexibleBox) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: flex;'>flexbox</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSFlexibleBoxInline) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(
"<div style='display: inline-flex;'>flexbox</div>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSFlexibleBoxButton) {
// LayoutButton is a subclass of LayoutFlexibleBox, however we don't want
// it to be counted as usage of flexboxes as it's an implementation detail.
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSFlexibleBox;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML("<button>button</button>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, HTMLRootContained) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHTMLRootContained;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->SetInlineStyleProperty(CSSPropertyID::kDisplay,
"none");
document.documentElement()->SetInlineStyleProperty(CSSPropertyID::kContain,
"paint");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->SetInlineStyleProperty(CSSPropertyID::kDisplay,
"block");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, HTMLBodyContained) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHTMLBodyContained;
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->SetInlineStyleProperty(CSSPropertyID::kDisplay, "none");
document.body()->SetInlineStyleProperty(CSSPropertyID::kContain, "paint");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->SetInlineStyleProperty(CSSPropertyID::kDisplay, "block");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
class DeprecationTest : public testing::Test {
public:
DeprecationTest()
: dummy_(std::make_unique<DummyPageHolder>()),
deprecation_(dummy_->GetPage().GetDeprecation()),
use_counter_(dummy_->GetDocument().Loader()->GetUseCounter()) {
Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
}
protected:
LocalFrame* GetFrame() { return &dummy_->GetFrame(); }
test::TaskEnvironment task_environment_;
std::unique_ptr<DummyPageHolder> dummy_;
Deprecation& deprecation_;
UseCounterImpl& use_counter_;
};
TEST_F(DeprecationTest, InspectorDisablesDeprecation) {
// The specific feature we use here isn't important.
WebFeature feature =
WebFeature::kCSSSelectorInternalMediaControlsOverlayCastButton;
deprecation_.MuteForInspector();
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.IsCounted(feature));
deprecation_.MuteForInspector();
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.IsCounted(feature));
deprecation_.UnmuteForInspector();
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_FALSE(use_counter_.IsCounted(feature));
deprecation_.UnmuteForInspector();
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
EXPECT_TRUE(use_counter_.IsCounted(feature));
}
TEST_F(UseCounterImplTest, CSSUnknownNamespacePrefixInSelector) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSUnknownNamespacePrefixInSelector;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML(R"HTML(
<style>
@namespace svg url(http://www.w3.org/2000/svg);
svg|a {}
a {}
</style>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML("<style>foo|a {}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSSelectorHostContextInLiveProfile) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorHostContextInLiveProfile;
document.body()->setInnerHTML(R"HTML(
<div id="parent">
<div id="host"></div>
</div>
)HTML");
Element* host = document.getElementById(AtomicString("host"));
ASSERT_TRUE(host);
ShadowRoot& shadow_root =
host->AttachShadowRootForTesting(ShadowRootMode::kOpen);
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
shadow_root.setInnerHTML(R"HTML(
<style>
:host-context(#parent) span {
color: green
}
</style>
<span></span>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSSelectorHostContextInSnapshotProfile) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kCSSSelectorHostContextInSnapshotProfile;
document.body()->setInnerHTML(R"HTML(
<div id="parent">
<div id="host"></div>
</div>
)HTML");
Element* host = document.getElementById(AtomicString("host"));
ASSERT_TRUE(host);
ShadowRoot& shadow_root =
host->AttachShadowRootForTesting(ShadowRootMode::kOpen);
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
shadow_root.setInnerHTML("<span></span>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
Element* span =
shadow_root.QuerySelector(AtomicString(":host-context(#parent) span"));
EXPECT_TRUE(span);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, UniqueCSSSampleIds) {
HashSet<int> ids;
HashSet<CSSPropertyID> alternatives = GetAlternatives();
for (CSSPropertyID property : CSSPropertyIDList()) {
if (IsInternal(property)) {
continue;
}
if (alternatives.Contains(property)) {
// Alternative properties should use the same CSSSampleId as the
// corresponding main property.
continue;
}
EXPECT_FALSE(ids.Contains(ToSampleId(property)));
ids.insert(ToSampleId(property));
}
for (CSSPropertyID property : kCSSPropertyAliasList) {
if (alternatives.Contains(property)) {
// Alternative properties should use the same CSSSampleId as the
// corresponding main property.
continue;
}
EXPECT_FALSE(ids.Contains(ToSampleId(property)));
ids.insert(ToSampleId(property));
}
}
TEST_F(UseCounterImplTest, MaximumCSSSampleId) {
int max_sample_id = 0;
for (CSSPropertyID property : CSSPropertyIDList()) {
if (IsInternal(property)) {
continue;
}
max_sample_id = std::max(max_sample_id, ToSampleId(property));
}
for (CSSPropertyID property : kCSSPropertyAliasList) {
max_sample_id = std::max(max_sample_id, ToSampleId(property));
}
EXPECT_EQ(static_cast<int>(mojom::blink::CSSSampleId::kMaxValue),
max_sample_id);
}
TEST_F(UseCounterImplTest, CSSMarkerPseudoElementUA) {
// Check that UA styles for list markers are not counted.
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHasMarkerPseudoElement;
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->setInnerHTML(R"HTML(
<style>
li::before {
content: "[before]";
display: list-item;
}
</style>
<ul>
<li style="list-style: decimal outside"></li>
<li style="list-style: decimal inside"></li>
<li style="list-style: disc outside"></li>
<li style="list-style: disc inside"></li>
<li style="list-style: '- ' outside"></li>
<li style="list-style: '- ' inside"></li>
<li style="list-style: linear-gradient(blue, cyan) outside"></li>
<li style="list-style: linear-gradient(blue, cyan) inside"></li>
<li style="list-style: none outside"></li>
<li style="list-style: none inside"></li>
</ul>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, CSSMarkerPseudoElementAuthor) {
// Check that author styles for list markers are counted.
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kHasMarkerPseudoElement;
EXPECT_FALSE(document.IsUseCounted(feature));
document.body()->setInnerHTML(R"HTML(
<style>
li::marker {
color: blue;
}
</style>
<ul>
<li></li>
</ul>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature));
}
TEST_F(UseCounterImplTest, BackgroundClip) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{background-clip: border-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{background-clip: content-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{background-clip: padding-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: border-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: content-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: padding-box;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: text;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
// We dropped the support for keywords without suffix.
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: border;}</style>");
UpdateAllLifecyclePhases(document);
if (RuntimeEnabledFeatures::CSSBackgroundClipUnprefixEnabled()) {
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
} else {
EXPECT_TRUE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
}
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.ClearUseCounterForTesting(WebFeature::kCSSBackgroundClipBorder);
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: content;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
if (RuntimeEnabledFeatures::CSSBackgroundClipUnprefixEnabled()) {
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
} else {
EXPECT_TRUE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
}
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
document.ClearUseCounterForTesting(WebFeature::kCSSBackgroundClipContent);
document.documentElement()->setInnerHTML(
"<style>html{-webkit-background-clip: padding;}</style>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipBorder));
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipContent));
if (RuntimeEnabledFeatures::CSSBackgroundClipUnprefixEnabled()) {
EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
} else {
EXPECT_TRUE(document.IsUseCounted(WebFeature::kCSSBackgroundClipPadding));
}
}
TEST_F(UseCounterImplTest, H1UserAgentFontSizeInSectionApplied) {
auto dummy_page_holder =
std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
Document& document = dummy_page_holder->GetDocument();
WebFeature feature = WebFeature::kH1UserAgentFontSizeInSectionApplied;
EXPECT_FALSE(document.IsUseCounted(feature));
document.documentElement()->setInnerHTML("<h1></h1>");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature))
<< "Not inside sectioning element";
document.documentElement()->setInnerHTML(R"HTML(
<article><h1 style="font-size: 10px"></h1></article>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_FALSE(document.IsUseCounted(feature))
<< "Inside sectioning element with author font-size";
document.documentElement()->setInnerHTML(R"HTML(
<article><h1></h1></article>
)HTML");
UpdateAllLifecyclePhases(document);
EXPECT_TRUE(document.IsUseCounted(feature))
<< "Inside sectioning element with UA font-size";
}
} // namespace blink