Skip to content
Permalink
Browse files
Web Inspector: Show warnings in the Font details sidebar for synthesi…
…zed boldness/obliqueness

https://bugs.webkit.org/show_bug.cgi?id=244718
rdar://99496142

Reviewed by Devin Rousso.

Added test cases to: LayoutTests/inspector/css/getComputedPrimaryFontForNode.html

* LayoutTests/inspector/css/getComputedPrimaryFontForNode.html:
* LayoutTests/inspector/css/getComputedPrimaryFontForNode-expected.txt:

* Source/JavaScriptCore/inspector/protocol/CSS.json:
* Source/WebCore/inspector/agents/InspectorCSSAgent.cpp:
(WebCore::buildObjectForFont):
- Send the already existing information about font synthesis to the frontend.

* Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js:
* Source/WebInspectorUI/UserInterface/Models/Font.js:
(WI.Font.fromPayload):
(WI.Font.prototype.get synthesizedBold):
(WI.Font.prototype.get synthesizedOblique):

* Source/WebInspectorUI/UserInterface/Views/DetailsSection.css:
(.details-section > .content > .group > .row.simple:has(.warning)):
(.details-section > .content > .group > .row.simple > .warning):
* Source/WebInspectorUI/UserInterface/Views/DetailsSectionSimpleRow.js:
(WI.DetailsSectionSimpleRow):
(WI.DetailsSectionSimpleRow.prototype.get warningMessage):
(WI.DetailsSectionSimpleRow.prototype.set warningMessage):
- Add support for putting the row in a warning state.

* Source/WebInspectorUI/UserInterface/Views/FontDetailsPanel.js:
(WI.FontDetailsPanel.prototype.refresh):
(WI.FontDetailsPanel.prototype.initialLayout):
- Adopt DetailsSectionWarnableSimpleRow and show warnings when the font is synthesized in some way.

Canonical link: https://commits.webkit.org/254188@main
  • Loading branch information
patrickangle committed Sep 6, 2022
1 parent 1765166 commit 805dec11f1f29a24a3754cf7519c9c06e342ba92
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 8 deletions.
@@ -8,6 +8,11 @@ Webfont Test 2
¥Yen
¥Yen
Variable Font Test 1
Synthetic Weight Test 1
Synthetic Weight Test 2
Synthetic Oblique Test 1
Synthetic Oblique Test 2
Synthetic Oblique Test 3

== Running test suite: CSS.getComputedPrimaryFontForNode
-- Running test case: CSS.getComputedPrimaryFontForNode.Fallback1
@@ -61,3 +66,28 @@ PASS: Width axis minimum should be '0'.
PASS: Width axis maximum should be '1000'.
PASS: Width axis default should be '750'.

-- Running test setup.
PASS: Font should be loaded.
-- Running test case: CSS.getComputedPrimaryFontForNode.SyntheticWeightFromNormal
PASS: Font should not have a synthesized weight.

-- Running test setup.
PASS: Font should be loaded.
-- Running test case: CSS.getComputedPrimaryFontForNode.SyntheticWeightFromBold
PASS: Font should have a synthesized weight.

-- Running test setup.
PASS: Font should be loaded.
-- Running test case: CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromNormal
PASS: Font should not have a synthesized obliqueness.

-- Running test setup.
PASS: Font should be loaded.
-- Running test case: CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromItalic
PASS: Font should have a synthesized obliqueness.

-- Running test setup.
PASS: Font should be loaded.
-- Running test case: CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromOblique
PASS: Font should have a synthesized obliqueness.

@@ -163,6 +163,66 @@
}
});

addTestCase({
name: "CSS.getComputedPrimaryFontForNode.SyntheticWeightFromNormal",
description: "Ensure that text does not get a synthesized font weight for the node '#synthetic-weight-from-normal-test'.",
async setup() {
return loadFontFace("normal normal 12px AhemNormal", " ", "TestPage-SyntheticWeightFromNormalLoaded");
},
selector: "#synthetic-weight-from-normal-test",
computedFontHandler(font) {
InspectorTest.expectFalse(font.synthesizedBold, "Font should not have a synthesized weight.");
}
});

addTestCase({
name: "CSS.getComputedPrimaryFontForNode.SyntheticWeightFromBold",
description: "Ensure that text does get a synthesized font weight for the node '#synthetic-weight-from-bold-test'.",
async setup() {
return loadFontFace("bold normal 12px AhemNormal", " ", "TestPage-SyntheticWeightFromBoldLoaded");
},
selector: "#synthetic-weight-from-bold-test",
computedFontHandler(font) {
InspectorTest.expectTrue(font.synthesizedBold, "Font should have a synthesized weight.");
}
});

addTestCase({
name: "CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromNormal",
description: "Ensure that text does not get a synthesized font style for the node '#synthetic-oblique-from-normal-test'.",
async setup() {
return loadFontFace("normal normal 12px AhemNormal", " ", "TestPage-SyntheticObliqueFromNormalLoaded");
},
selector: "#synthetic-oblique-from-normal-test",
computedFontHandler(font) {
InspectorTest.expectFalse(font.synthesizedOblique, "Font should not have a synthesized obliqueness.");
}
});

addTestCase({
name: "CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromItalic",
description: "Ensure that text does get a synthesized font style for the node '#synthetic-oblique-from-italic-test'.",
async setup() {
return loadFontFace("italic normal 12px AhemNormal", " ", "TestPage-SyntheticObliqueFromItalicLoaded");
},
selector: "#synthetic-oblique-from-italic-test",
computedFontHandler(font) {
InspectorTest.expectTrue(font.synthesizedOblique, "Font should have a synthesized obliqueness.");
}
});

addTestCase({
name: "CSS.getComputedPrimaryFontForNode.SyntheticObliqueFromOblique",
description: "Ensure that text does get a synthesized font style for the node '#synthetic-oblique-from-oblique-test'.",
async setup() {
return loadFontFace("oblique normal 12px AhemNormal", " ", "TestPage-SyntheticObliqueFromObliqueLoaded");
},
selector: "#synthetic-oblique-from-oblique-test",
computedFontHandler(font) {
InspectorTest.expectTrue(font.synthesizedOblique, "Font should have a synthesized obliqueness.");
}
});

WI.domManager.requestDocument((node) => {
documentNode = node;
suite.runTestCasesAndFinish();
@@ -204,6 +264,13 @@
src: url("../../animations/font-variations/resources/Boxis-VF.ttf");
}

@font-face {
font-family: "AhemNormal";
font-weight: normal;
font-style: normal;
src: url("../../resources/Ahem.otf") format("opentype");
}

</style>
</head>
<body onload="runTest();">
@@ -220,6 +287,13 @@
<div id="webfont-cjk-test-2" style="font-family: SomethingElse, WebFontWithCJKAndLatin, sans-serif;">&#x00A5Yen</div>

<div id="variable-font-test-1" style="font-family: VariableFont;">Variable Font Test 1</div>

<div id="synthetic-weight-from-normal-test" style="font-family: AhemNormal; font-weight: normal;">Synthetic Weight Test 1</div>
<div id="synthetic-weight-from-bold-test" style="font-family: AhemNormal; font-weight: bold;">Synthetic Weight Test 2</div>

<div id="synthetic-oblique-from-normal-test" style="font-family: AhemNormal; font-style: normal;">Synthetic Oblique Test 1</div>
<div id="synthetic-oblique-from-italic-test" style="font-family: AhemNormal; font-style: italic;">Synthetic Oblique Test 2</div>
<div id="synthetic-oblique-from-oblique-test" style="font-family: AhemNormal; font-style: oblique;">Synthetic Oblique Test 3</div>
</div>
</body>
</html>
@@ -253,7 +253,9 @@
"description": "A representation of WebCore::Font. Conceptually this is backed by either a font file on disk or from the network.",
"properties": [
{ "name": "displayName", "type": "string", "description": "The display name defined by the font." },
{ "name": "variationAxes", "type": "array", "items": { "$ref": "FontVariationAxis" }, "description": "The variation axes defined by the font." }
{ "name": "variationAxes", "type": "array", "items": { "$ref": "FontVariationAxis" }, "description": "The variation axes defined by the font." },
{ "name": "synthesizedBold", "type": "boolean", "optional": true, "description": "Whether the font has synthesized its boldness or not." },
{ "name": "synthesizedOblique", "type": "boolean", "optional": true, "description": "Whether the font has synthesized its obliqueness or not" }
]
},
{
@@ -542,8 +542,10 @@ Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Protocol::CSS::CSSComputedStylePropert

static Ref<Protocol::CSS::Font> buildObjectForFont(const Font& font)
{
auto& fontPlatformData = font.platformData();

auto resultVariationAxes = JSON::ArrayOf<Protocol::CSS::FontVariationAxis>::create();
for (auto& variationAxis : font.platformData().variationAxes(ShouldLocalizeAxisNames::Yes)) {
for (auto& variationAxis : fontPlatformData.variationAxes(ShouldLocalizeAxisNames::Yes)) {
auto axis = Protocol::CSS::FontVariationAxis::create()
.setTag(variationAxis.tag())
.setMinimumValue(variationAxis.minimumValue())
@@ -556,11 +558,16 @@ static Ref<Protocol::CSS::Font> buildObjectForFont(const Font& font)

resultVariationAxes->addItem(WTFMove(axis));
}
return Protocol::CSS::Font::create()

auto protocolFont = Protocol::CSS::Font::create()
.setDisplayName(font.platformData().familyName())
.setVariationAxes(WTFMove(resultVariationAxes))
.release();

protocolFont->setSynthesizedBold(fontPlatformData.syntheticBold());
protocolFont->setSynthesizedOblique(fontPlatformData.syntheticOblique());

return protocolFont;
}

Protocol::ErrorStringOr<Ref<Protocol::CSS::Font>> InspectorCSSAgent::getFontDataForNode(Protocol::DOM::NodeId nodeId)
@@ -715,6 +715,10 @@ localizedStrings["Focused"] = "Focused";
localizedStrings["Font"] = "Font";
/* Title for the Font details sidebar. */
localizedStrings["Font @ Font Details Sidebar Title"] = "Font";
/* A warning that is shown in the Font Details Sidebar when the font had to be synthesized to support the provided weight. */
localizedStrings["Font was synthesized to be bold because no bold font is available."] = "Font was synthesized to be bold because no bold font is available.";
/* A warning that is shown in the Font Details Sidebar when the font had to be synthesized to support the provided style. */
localizedStrings["Font was synthesized to be oblique because no oblique font is available."] = "Font was synthesized to be oblique because no oblique font is available.";
localizedStrings["Fonts"] = "Fonts";
localizedStrings["Force Dark Appearance"] = "Force Dark Appearance";
localizedStrings["Force Light Appearance"] = "Force Light Appearance";
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 Apple Inc. All rights reserved.
* Copyright (C) 2020-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,24 +25,34 @@

WI.Font = class Font
{
constructor(name, variationAxes)
constructor(name, variationAxes, {synthesizedBold, synthesizedOblique} = {})
{
this._name = name;
this._variationAxes = variationAxes;

// COMPATIBILITY (macOS 13.0, iOS 16.0): CSS.Font.synthesizedBold and CSS.Font.synthesizedOblique did not exist yet.
this._synthesizedBold = !!synthesizedBold;
this._synthesizedOblique = !!synthesizedOblique;
}

// Static

static fromPayload(payload)
{
let variationAxes = payload.variationAxes.map((axisPayload) => WI.FontVariationAxis.fromPayload(axisPayload));
return new WI.Font(payload.displayName, variationAxes);

let synthesizedBold = payload.synthesizedBold;
let synthesizedOblique = payload.synthesizedOblique;

return new WI.Font(payload.displayName, variationAxes, {synthesizedBold, synthesizedOblique});
}

// Public

get name() { return this._name; }
get variationAxes() { return this._variationAxes; }
get synthesizedBold() { return this._synthesizedBold; }
get synthesizedOblique() { return this._synthesizedOblique; }

variationAxis(tag)
{
@@ -252,6 +252,29 @@ body[dir=rtl] .details-section > .header::before {
margin-inline-start: 5px;
}

.details-section > .content > .group > .row.simple:has(.warning) {
background-color: var(--warning-background-color-secondary);
}

.details-section > .content > .group > .row.simple > .warning {
position: absolute;
right: 0;
display: inline-block;
width: calc(var(--warning-badge-arrow-depth) + var(--warning-icon-inline-padding) + var(--warning-icon-size) + var(--warning-icon-inline-padding) + 4px);
height: 18px;
margin-block-start: 0.5px;
background-image: url(/Images/Warning.svg);
background-color: var(--warning-background-color);
background-repeat: no-repeat;
background-size: var(--warning-icon-size);
background-position-y: center;
background-position-x: calc(var(--warning-badge-arrow-depth) + var(--warning-icon-inline-padding));
clip-path: polygon(0% 50%, var(--warning-badge-arrow-depth) 0%, 100% 0%, 100% 100%, var(--warning-badge-arrow-depth) 100%);
--warning-icon-size: 11px;
--warning-icon-inline-padding: 2px;
--warning-badge-arrow-depth: 6px;
}

.details-section > .content > .group > .row.simple.data > .value {
word-break: break-all;
}
@@ -67,6 +67,9 @@ WI.DetailsSectionSimpleRow = class DetailsSectionSimpleRow extends WI.DetailsSec

this.label = label;
this.value = value;

this._warningMessage = null;
this._warningElement = null;
}

// Public
@@ -125,6 +128,30 @@ WI.DetailsSectionSimpleRow = class DetailsSectionSimpleRow extends WI.DetailsSec
{
this._valueElement.title = x;
}

get warningMessage()
{
return this._warningMessage;
}

set warningMessage(message)
{
if (this._warningMessage === message)
return;

this._warningMessage = message;
this.element.title = this._warningMessage ?? "";

if (!this._warningElement) {
this._warningElement = document.createElement("div");
this._warningElement.className = "warning";
}

if (!this._warningElement.parentNode && this._warningMessage)
this.element.appendChild(this._warningElement);
else
this._warningElement.remove();
}
};

WI.DetailsSectionSimpleRow.DataStyleClassName = "data";
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 Apple Inc. All rights reserved.
* Copyright (C) 2020-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,8 +51,13 @@ WI.FontDetailsPanel = class FontDetailsPanel extends WI.StyleDetailsPanel
this._fontNameRow.value = this.nodeStyles.computedPrimaryFont.name;

this._fontSizeRow.value = this._formatSizeValue(this._fontPropertiesMap.get("font-size"));

this._fontStyleRow.value = this._formatStyleValue(this._fontPropertiesMap.get("font-style"));
this._fontStyleRow.warningMessage = this.nodeStyles.computedPrimaryFont?.synthesizedOblique ? WI.UIString("Font was synthesized to be oblique because no oblique font is available.", "A warning that is shown in the Font Details Sidebar when the font had to be synthesized to support the provided style.") : null;

this._fontWeightRow.value = this._formatSimpleSingleValue(this._fontPropertiesMap.get("font-weight"), "wght", "%s");
this._fontWeightRow.warningMessage = this.nodeStyles.computedPrimaryFont?.synthesizedBold ? WI.UIString("Font was synthesized to be bold because no bold font is available.", "A warning that is shown in the Font Details Sidebar when the font had to be synthesized to support the provided weight.") : null;

this._fontStretchRow.value = this._formatSimpleSingleValue(this._fontPropertiesMap.get("font-stretch"), "wdth", WI.UIString("%s%%", "%s%% @ Font Details Sidebar", "A single value expressed as a percentage where the value has already been converted from a number to a string."));

this._fontVariantLigaturesRow.value = this._formatLigatureValue(this._fontPropertiesMap.get("font-variant-ligatures"));

0 comments on commit 805dec1

Please sign in to comment.