Commit bedc36ac authored by Dominik Röttsches's avatar Dominik Röttsches Committed by Commit Bot

Add a BrowserTest comparing matched fonts using DevTools protocol

For issue 828317 we need an end to test for checking whether the correct
fonts have been selected for @font-face { src: local(<fontname>) }
rules. Since this cannot be reliable verified with web platform API, I
am using DevTools to connect to the content instance and retrieve
information about the selected fonts, just like in the style panel of
DevTools. The DevTools protocol communication is modeled after
content/browser/devtools/protocol/devtools_protocol_browsertest.cc

I appreciate feedback on whether I should duplicate this DevTools
communication code here, whether there is an easier way to achieve this,
or whether we should factor out the relevant parts of
content/browser/devtools/protocol/devtools_protocol_browsertest.cc into
a separate file that I can reuse here for the FontUniqueNameBrowserTest.

Bug: 874059
Change-Id: I4a2beeb81a3b5e4cec68cf196fcf0ebf29287d38
Reviewed-on: https://chromium-review.googlesource.com/1174540Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Commit-Queue: Dominik Röttsches <drott@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585916}
parent 35aa0ef4
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
namespace content {
namespace {
const char* kExpectedFontFamilyNames[] = {"AndroidClock",
"Roboto",
"Droid Sans Mono",
"Roboto",
"Noto Color Emoji",
"Noto Sans Bengali",
"Noto Sans Bengali",
"Noto Sans Bengali UI",
"Noto Sans Bengali UI",
"Noto Sans Devanagari",
"Noto Sans Devanagari",
"Noto Sans Devanagari UI",
"Noto Sans Devanagari UI",
"Noto Sans Kannada",
"Noto Sans Kannada",
"Noto Sans Kannada UI",
"Noto Sans Kannada UI",
"Noto Sans Lao",
"Noto Sans Lao",
"Noto Sans Lao UI",
"Noto Sans Lao UI",
"Noto Sans Malayalam",
"Noto Sans Malayalam",
"Noto Sans Malayalam UI",
"Noto Sans Malayalam UI",
"Noto Sans Tamil",
"Noto Sans Tamil",
"Noto Sans Tamil UI",
"Noto Sans Tamil UI",
"Noto Sans Telugu",
"Noto Sans Telugu",
"Noto Sans Telugu UI",
"Noto Sans Telugu UI",
"Noto Sans Thai",
"Noto Sans Thai",
"Noto Sans Thai UI",
"Noto Sans Thai UI",
"Roboto",
"Roboto Condensed",
"Roboto Condensed",
"Roboto Condensed",
"Roboto Condensed",
"Roboto"};
} // namespace
class FontUniqueNameBrowserTest : public DevToolsProtocolTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
feature_list_.InitAndEnableFeature(features::kFontSrcLocalMatching);
}
void LoadAndWait(const std::string& url) {
ASSERT_TRUE(embedded_test_server()->Start());
TestNavigationObserver navigation_observer(
static_cast<WebContentsImpl*>(shell()->web_contents()));
NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url));
ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
}
private:
base::test::ScopedFeatureList feature_list_;
};
#if defined(OS_ANDROID)
#define MAYBE_ContentLocalFontsMatching ContentLocalFontsMatching
#else
#define MAYBE_ContentLocalFontsMatching DISABLED_ContentLocalFontsMatching
#endif
IN_PROC_BROWSER_TEST_F(FontUniqueNameBrowserTest,
MAYBE_ContentLocalFontsMatching) {
LoadAndWait("/font_src_local_matching.html");
Attach();
base::Value* dom_enable_result = SendCommand("DOM.enable", nullptr, true);
ASSERT_TRUE(dom_enable_result);
base::Value* css_enable_result = SendCommand("CSS.enable", nullptr, true);
ASSERT_TRUE(css_enable_result);
unsigned num_added_nodes = static_cast<unsigned>(
content::EvalJs(shell(), "addTestNodes()").ExtractInt());
ASSERT_EQ(num_added_nodes, base::size(kExpectedFontFamilyNames));
std::unique_ptr<base::DictionaryValue> params =
std::make_unique<base::DictionaryValue>();
params->SetInteger("depth", 0);
base::Value* result = SendCommand("DOM.getDocument", std::move(params));
result = result->FindPath({"root", "nodeId"});
ASSERT_TRUE(result);
ASSERT_TRUE(result->is_int());
params.reset(new base::DictionaryValue());
params->SetInteger("nodeId", result->GetInt());
params->SetString("selector", ".testnode");
result = SendCommand("DOM.querySelectorAll", std::move(params));
// This needs a Clone() because node_list otherwise gets invalid after the
// next SendCommand call.
base::Value node_list =
result->FindKeyOfType("nodeIds", base::Value::Type::LIST)->Clone();
std::vector<base::Value>& nodes_vector = node_list.GetList();
ASSERT_EQ(nodes_vector.size(), num_added_nodes);
ASSERT_EQ(nodes_vector.size(), base::size(kExpectedFontFamilyNames));
for (size_t i = 0; i < nodes_vector.size(); ++i) {
base::Value& nodeId = nodes_vector[i];
params.reset(new base::DictionaryValue());
params->SetInteger("nodeId", nodeId.GetInt());
base::Value* font_info =
SendCommand("CSS.getPlatformFontsForNode", std::move(params));
ASSERT_TRUE(font_info->is_dict());
base::Value* font_list = font_info->FindKey("fonts");
ASSERT_TRUE(font_list->is_list());
base::Value& first_font_info = font_list->GetList()[0];
ASSERT_TRUE(first_font_info.is_dict());
base::Value* first_font_name = first_font_info.FindKey("familyName");
ASSERT_TRUE(first_font_name->is_string());
ASSERT_GT(first_font_name->GetString().size(), 0u);
ASSERT_EQ(first_font_name->GetString(), kExpectedFontFamilyNames[i]);
}
}
} // namespace content
......@@ -754,6 +754,7 @@ test("content_browsertests") {
"../browser/fileapi/fileapi_browsertest.cc",
"../browser/find_request_manager_browsertest.cc",
"../browser/font_unique_name_lookup/font_unique_name_browsertest.cc",
"../browser/frame_host/blocked_scheme_navigation_browsertest.cc",
"../browser/frame_host/form_submission_throttle_browsertest.cc",
"../browser/frame_host/frame_tree_browsertest.cc",
......
<meta charset="utf-8">
<style id="fontfaces">
</style>
<body>
<script>
function getFontsWithTestCharsForOS() {
if (navigator.userAgent.indexOf("Android") !== -1)
// Intersection of available fonts of Android Kitkat to Oreo that kept the
// same family names to compare against for these postscript or full font
// names. (RobotoThin* and RobotoLight* had differing family names on
// different Android versions.
return [
["AndroidClock-Regular", "0"],
["Roboto-Bold", "0"],
["DroidSansMono", "0"],
["Roboto-Regular", "0"],
["Noto Color Emoji", ""],
["NotoSansBengali-Bold", "0"],
["NotoSansBengali", "0"],
["NotoSansBengaliUI-Bold", "0"],
["NotoSansBengaliUI", "0"],
["NotoSansDevanagari-Bold", "0"],
["NotoSansDevanagari", "0"],
["NotoSansDevanagariUI-Bold", "0"],
["NotoSansDevanagariUI", "0"],
["NotoSansKannada-Bold", "0"],
["NotoSansKannada", "0"],
["NotoSansKannadaUI-Bold", "0"],
["NotoSansKannadaUI", "0"],
["NotoSansLao-Bold", "0"],
["NotoSansLao", "0"],
["NotoSansLaoUI-Bold", "0"],
["NotoSansLaoUI", "0"],
["NotoSansMalayalam-Bold", "0"],
["NotoSansMalayalam", "0"],
["NotoSansMalayalamUI-Bold", "0"],
["NotoSansMalayalamUI", "0"],
["NotoSansTamil-Bold", "0"],
["NotoSansTamil", "0"],
["NotoSansTamilUI-Bold", "0"],
["NotoSansTamilUI", "0"],
["NotoSansTelugu-Bold", "0"],
["NotoSansTelugu", "0"],
["NotoSansTeluguUI-Bold", "0"],
["NotoSansTeluguUI", "0"],
["NotoSansThai-Bold", ""],
["NotoSansThai", ""],
["NotoSansThaiUI-Bold", ""],
["NotoSansThaiUI", ""],
["Roboto-BoldItalic", "0"],
["RobotoCondensed-BoldItalic", "0"],
["RobotoCondensed-Bold", "0"],
["RobotoCondensed-Italic", "0"],
["RobotoCondensed-Regular", "0"],
["Roboto-Italic", "0"],
];
return [];
}
function stripSpaces(fontName) {
return fontName.replace(/\s+/g, '');
}
function addTestNodes() {
var containerDiv = document.createElement("div");
var fontFaceDeclarations = "";
for (font_name_and_testchars of getFontsWithTestCharsForOS()) {
var font_name = font_name_and_testchars[0];
// Add cursive to font stack to avoid ignoring failures when Roboto is used as fallback.
fontFaceDeclarations +=
`@font-face { font-family: ${stripSpaces(font_name)}_webfont; \
src: local("${font_name}"); } .${stripSpaces(font_name)}_style \
{ font-family: ${stripSpaces(font_name)}_webfont, cursive; } `;
var testElement = document.createElement("div");
testElement.classList += `testnode ${stripSpaces(font_name)}_style`;
testElement.innerText = font_name_and_testchars[1];
containerDiv.appendChild(testElement);
}
fontfaces.innerText = fontFaceDeclarations;
document.body.appendChild(containerDiv);
return containerDiv.children.length;
}
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment