Commit 87fd5aa1 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

Add metric override descriptors to FontFace JS interface

Following the CSSWG resolution to add metric override descriptors
to @font-face, this patch also adds these descriptors as attributes
to the JavaScript FontFace interface.

Bug: 1098355
Change-Id: Ia5ef4ad870559457834fe9fafaaab79b24a0e08b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425484Reviewed-by: default avatarAnders Hartvoll Ruud <andruud@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810907}
parent 46941db5
...@@ -238,7 +238,14 @@ FontFace::FontFace(ExecutionContext* context, ...@@ -238,7 +238,14 @@ FontFace::FontFace(ExecutionContext* context,
AtRuleDescriptorID::FontFeatureSettings); AtRuleDescriptorID::FontFeatureSettings);
SetPropertyFromString(context, descriptors->display(), SetPropertyFromString(context, descriptors->display(),
AtRuleDescriptorID::FontDisplay); AtRuleDescriptorID::FontDisplay);
// TODO(xiaochengh): Add override descriptors to FontFaceDescriptors if (RuntimeEnabledFeatures::CSSFontMetricsOverrideEnabled()) {
SetPropertyFromString(context, descriptors->ascentOverride(),
AtRuleDescriptorID::AscentOverride);
SetPropertyFromString(context, descriptors->descentOverride(),
AtRuleDescriptorID::DescentOverride);
SetPropertyFromString(context, descriptors->lineGapOverride(),
AtRuleDescriptorID::LineGapOverride);
}
} }
FontFace::~FontFace() = default; FontFace::~FontFace() = default;
...@@ -271,6 +278,18 @@ String FontFace::display() const { ...@@ -271,6 +278,18 @@ String FontFace::display() const {
return display_ ? display_->CssText() : "auto"; return display_ ? display_->CssText() : "auto";
} }
String FontFace::ascentOverride() const {
return ascent_override_ ? ascent_override_->CssText() : "normal";
}
String FontFace::descentOverride() const {
return descent_override_ ? descent_override_->CssText() : "normal";
}
String FontFace::lineGapOverride() const {
return line_gap_override_ ? line_gap_override_->CssText() : "normal";
}
void FontFace::setStyle(ExecutionContext* context, void FontFace::setStyle(ExecutionContext* context,
const String& s, const String& s,
ExceptionState& exception_state) { ExceptionState& exception_state) {
...@@ -320,6 +339,27 @@ void FontFace::setDisplay(ExecutionContext* context, ...@@ -320,6 +339,27 @@ void FontFace::setDisplay(ExecutionContext* context,
&exception_state); &exception_state);
} }
void FontFace::setAscentOverride(ExecutionContext* context,
const String& s,
ExceptionState& exception_state) {
SetPropertyFromString(context, s, AtRuleDescriptorID::AscentOverride,
&exception_state);
}
void FontFace::setDescentOverride(ExecutionContext* context,
const String& s,
ExceptionState& exception_state) {
SetPropertyFromString(context, s, AtRuleDescriptorID::DescentOverride,
&exception_state);
}
void FontFace::setLineGapOverride(ExecutionContext* context,
const String& s,
ExceptionState& exception_state) {
SetPropertyFromString(context, s, AtRuleDescriptorID::LineGapOverride,
&exception_state);
}
void FontFace::SetPropertyFromString(const ExecutionContext* context, void FontFace::SetPropertyFromString(const ExecutionContext* context,
const String& s, const String& s,
AtRuleDescriptorID descriptor_id, AtRuleDescriptorID descriptor_id,
......
...@@ -87,6 +87,9 @@ class CORE_EXPORT FontFace : public ScriptWrappable, ...@@ -87,6 +87,9 @@ class CORE_EXPORT FontFace : public ScriptWrappable,
String variant() const; String variant() const;
String featureSettings() const; String featureSettings() const;
String display() const; String display() const;
String ascentOverride() const;
String descentOverride() const;
String lineGapOverride() const;
// FIXME: Changing these attributes should affect font matching. // FIXME: Changing these attributes should affect font matching.
void setFamily(ExecutionContext*, const AtomicString& s, ExceptionState&) { void setFamily(ExecutionContext*, const AtomicString& s, ExceptionState&) {
...@@ -99,6 +102,9 @@ class CORE_EXPORT FontFace : public ScriptWrappable, ...@@ -99,6 +102,9 @@ class CORE_EXPORT FontFace : public ScriptWrappable,
void setVariant(ExecutionContext*, const String&, ExceptionState&); void setVariant(ExecutionContext*, const String&, ExceptionState&);
void setFeatureSettings(ExecutionContext*, const String&, ExceptionState&); void setFeatureSettings(ExecutionContext*, const String&, ExceptionState&);
void setDisplay(ExecutionContext*, const String&, ExceptionState&); void setDisplay(ExecutionContext*, const String&, ExceptionState&);
void setAscentOverride(ExecutionContext*, const String&, ExceptionState&);
void setDescentOverride(ExecutionContext*, const String&, ExceptionState&);
void setLineGapOverride(ExecutionContext*, const String&, ExceptionState&);
String status() const; String status() const;
ScriptPromise loaded(ScriptState* script_state) { ScriptPromise loaded(ScriptState* script_state) {
......
...@@ -51,6 +51,9 @@ enum FontFaceLoadStatus { ...@@ -51,6 +51,9 @@ enum FontFaceLoadStatus {
[RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString variant; [RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString variant;
[RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString featureSettings; [RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString featureSettings;
[RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString display; [RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString display;
[RaisesException=Setter, SetterCallWith=ExecutionContext, RuntimeEnabled=CSSFontMetricsOverride] attribute DOMString ascentOverride;
[RaisesException=Setter, SetterCallWith=ExecutionContext, RuntimeEnabled=CSSFontMetricsOverride] attribute DOMString descentOverride;
[RaisesException=Setter, SetterCallWith=ExecutionContext, RuntimeEnabled=CSSFontMetricsOverride] attribute DOMString lineGapOverride;
readonly attribute FontFaceLoadStatus status; readonly attribute FontFaceLoadStatus status;
......
...@@ -12,4 +12,7 @@ dictionary FontFaceDescriptors { ...@@ -12,4 +12,7 @@ dictionary FontFaceDescriptors {
DOMString variant = "normal"; DOMString variant = "normal";
DOMString featureSettings = "normal"; DOMString featureSettings = "normal";
DOMString display = "auto"; DOMString display = "auto";
[RuntimeEnabled=CSSFontMetricsOverride] DOMString ascentOverride = "normal";
[RuntimeEnabled=CSSFontMetricsOverride] DOMString descentOverride = "normal";
[RuntimeEnabled=CSSFontMetricsOverride] DOMString lineGapOverride = "normal";
}; };
<!DOCTYPE html>
<title>Tests getters and setters of the font metrics override descriptors of FontFace</title>
<link rel="author" href="mailto:xiaochengh@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function rejection(promise) {
return new Promise((resolve, reject) => promise.then(reject, resolve));
}
// ascentOverride
test(() => {
const face = new FontFace(
'ascent-override-initial',
'url(https://example.com/font.woff)');
assert_equals(face.ascentOverride, 'normal');
}, "Initial value of ascentOverride should be 'normal'");
test(() => {
const face = new FontFace(
'ascent-override-initialize-with-normal',
'url(https://example.com/font.woff)',
{ascentOverride: 'normal'});
assert_equals(face.ascentOverride, 'normal');
}, "Initialize ascentOverride with 'normal' should succeed");
test(() => {
const face = new FontFace(
'ascent-override-initialize-with-percentage',
'url(https://example.com/font.woff)',
{ascentOverride: '50%'});
assert_equals(face.ascentOverride, '50%');
}, "Initialize ascentOverride with a percentage should succeed");
promise_test(async () => {
const face = new FontFace(
'ascent-override-initialize-with-negative-percentage',
'url(https://example.com/font.woff)',
{ascentOverride: '-50%'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize ascentOverride with a negative percentage should fail");
promise_test(async () => {
const face = new FontFace(
'ascent-override-initialize-with-non-percentage',
'url(https://example.com/font.woff)',
{ascentOverride: '10px'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize ascentOverride with a non-percentage should fail");
test(() => {
const face = new FontFace(
'ascent-override-normal-to-percentage',
'url(https://example.com/font.woff)',
{ascentOverride: 'normal'});
face.ascentOverride = '50%';
assert_equals(face.ascentOverride, '50%');
}, "Changing ascentOverride from 'normal' to percentage should succeed");
test(() => {
const face = new FontFace(
'ascent-override-percentage-to-normal',
'url(https://example.com/font.woff)',
{ascentOverride: '50%'});
face.ascentOverride = 'normal';
assert_equals(face.ascentOverride, 'normal');
}, "Changing ascentOverride from percentage to 'normal' should succeed");
test(() => {
const face = new FontFace(
'ascent-override-set-to-invalid',
'url(https://example.com/font.woff)');
assert_throws_dom('SyntaxError', () => {face.ascentOverride = '10px'});
}, "Changing ascentOverride to invalid value should fail");
// descentOverride
test(() => {
const face = new FontFace(
'descent-override-initial',
'url(https://example.com/font.woff)');
assert_equals(face.descentOverride, 'normal');
}, "Initial value of descentOverride should be 'normal'");
test(() => {
const face = new FontFace(
'descent-override-initialize-with-normal',
'url(https://example.com/font.woff)',
{descentOverride: 'normal'});
assert_equals(face.descentOverride, 'normal');
}, "Initialize descentOverride with 'normal' should succeed");
test(() => {
const face = new FontFace(
'descent-override-initialize-with-percentage',
'url(https://example.com/font.woff)',
{descentOverride: '50%'});
assert_equals(face.descentOverride, '50%');
}, "Initialize descentOverride with a percentage should succeed");
promise_test(async () => {
const face = new FontFace(
'descent-override-initialize-with-negative-percentage',
'url(https://example.com/font.woff)',
{descentOverride: '-50%'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize descentOverride with a negative percentage should fail");
promise_test(async () => {
const face = new FontFace(
'descent-override-initialize-with-non-percentage',
'url(https://example.com/font.woff)',
{descentOverride: '10px'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize descentOverride with a non-percentage should fail");
test(() => {
const face = new FontFace(
'descent-override-normal-to-percentage',
'url(https://example.com/font.woff)',
{descentOverride: 'normal'});
face.descentOverride = '50%';
assert_equals(face.descentOverride, '50%');
}, "Changing descentOverride from 'normal' to percentage should succeed");
test(() => {
const face = new FontFace(
'descent-override-percentage-to-normal',
'url(https://example.com/font.woff)',
{descentOverride: '50%'});
face.descentOverride = 'normal';
assert_equals(face.descentOverride, 'normal');
}, "Changing descentOverride from percentage to 'normal' should succeed");
test(() => {
const face = new FontFace(
'descent-override-set-to-invalid',
'url(https://example.com/font.woff)');
assert_throws_dom('SyntaxError', () => {face.descentOverride = '10px'});
}, "Changing descentOverride to invalid value should fail");
// lineGapOverride
test(() => {
const face = new FontFace(
'lineGap-override-initial',
'url(https://example.com/font.woff)');
assert_equals(face.lineGapOverride, 'normal');
}, "Initial value of lineGapOverride should be 'normal'");
test(() => {
const face = new FontFace(
'lineGap-override-initialize-with-normal',
'url(https://example.com/font.woff)',
{lineGapOverride: 'normal'});
assert_equals(face.lineGapOverride, 'normal');
}, "Initialize lineGapOverride with 'normal' should succeed");
test(() => {
const face = new FontFace(
'lineGap-override-initialize-with-percentage',
'url(https://example.com/font.woff)',
{lineGapOverride: '50%'});
assert_equals(face.lineGapOverride, '50%');
}, "Initialize lineGapOverride with a percentage should succeed");
promise_test(async () => {
const face = new FontFace(
'lineGap-override-initialize-with-negative-percentage',
'url(https://example.com/font.woff)',
{lineGapOverride: '-50%'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize lineGapOverride with a negative percentage should fail");
promise_test(async () => {
const face = new FontFace(
'lineGap-override-initialize-with-non-percentage',
'url(https://example.com/font.woff)',
{lineGapOverride: '10px'});
const error = await rejection(face.load());
assert_equals('error', face.status);
assert_throws_dom('SyntaxError', () => {throw error});
}, "Initialize lineGapOverride with a non-percentage should fail");
test(() => {
const face = new FontFace(
'lineGap-override-normal-to-percentage',
'url(https://example.com/font.woff)',
{lineGapOverride: 'normal'});
face.lineGapOverride = '50%';
assert_equals(face.lineGapOverride, '50%');
}, "Changing lineGapOverride from 'normal' to percentage should succeed");
test(() => {
const face = new FontFace(
'lineGap-override-percentage-to-normal',
'url(https://example.com/font.woff)',
{lineGapOverride: '50%'});
face.lineGapOverride = 'normal';
assert_equals(face.lineGapOverride, 'normal');
}, "Changing lineGapOverride from percentage to 'normal' should succeed");
test(() => {
const face = new FontFace(
'lineGap-override-set-to-invalid',
'url(https://example.com/font.woff)');
assert_throws_dom('SyntaxError', () => {face.lineGapOverride = '10px'});
}, "Changing lineGapOverride to invalid value should fail");
</script>
<!DOCTYPE html>
<title>Tests that the ascentOverride, descentOverride and lineGapOverride attributes of FontFace work</title>
<link rel="stylesheet" herf="/fonts/ahem.css">
<style>
#target {
position: absolute;
font-family: Ahem;
font-size: 20px;
}
#first-line {
position: absolute;
left: 0;
top: 0.7em;
}
#second-line {
position: absolute;
left: 0;
top: 3.7em;
}
</style>
<div id="target">
<div id="first-line">XXXXX</div>
<div id="second-line">XXXXX</div>
</div>
<!DOCTYPE html>
<title>Tests that the ascentOverride, descentOverride and lineGapOverride attributes of FontFace work</title>
<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc">
<link rel="match" href="fontface-override-descriptors-ref.html">
<script>
const face = new FontFace(
'ahem-overridden',
'local("Ahem"), url("/fonts/Ahem.ttf")',
{ascentOverride: '100%', descentOverride: '100%', lineGapOverride: '100%'});
document.fonts.add(face);
// Line height is ascent + descent + lineGap = 3em
// Baseline is placed at lineGap * 0.5 + ascent = 1.5em below line box top
// Since each Ahem 'X' glyph has 0.8em above baseline, the top of each glyph
// should be placed at 0.7em below line box top
</script>
<style>
#target {
position: absolute;
font-family: ahem-overridden;
font-size: 20px;
}
</style>
<div id="target">
XXXXX<br>
XXXXX
</div>
...@@ -726,6 +726,7 @@ AHEM SYSTEM FONT: acid/acid3/test.html ...@@ -726,6 +726,7 @@ AHEM SYSTEM FONT: acid/acid3/test.html
AHEM SYSTEM FONT: resource-timing/resources/all_resource_types.htm AHEM SYSTEM FONT: resource-timing/resources/all_resource_types.htm
AHEM SYSTEM FONT: resource-timing/resources/iframe-reload-TAO.sub.html AHEM SYSTEM FONT: resource-timing/resources/iframe-reload-TAO.sub.html
AHEM SYSTEM FONT: html/canvas/element/drawing-text-to-the-canvas/2d.text.measure.fontBoundingBox.ahem.html AHEM SYSTEM FONT: html/canvas/element/drawing-text-to-the-canvas/2d.text.measure.fontBoundingBox.ahem.html
AHEM SYSTEM FONT: css/css-font-loading/fontface-override-descriptors.html
# TODO: The following should be deleted along with the Ahem web font cleanup # TODO: The following should be deleted along with the Ahem web font cleanup
# PR (https://github.com/web-platform-tests/wpt/pull/18702) # PR (https://github.com/web-platform-tests/wpt/pull/18702)
......
...@@ -592,9 +592,12 @@ interface FileSystemWritableFileStream : WritableStream ...@@ -592,9 +592,12 @@ interface FileSystemWritableFileStream : WritableStream
method write method write
interface FontFace interface FontFace
attribute @@toStringTag attribute @@toStringTag
getter ascentOverride
getter descentOverride
getter display getter display
getter family getter family
getter featureSettings getter featureSettings
getter lineGapOverride
getter loaded getter loaded
getter status getter status
getter stretch getter stretch
...@@ -604,9 +607,12 @@ interface FontFace ...@@ -604,9 +607,12 @@ interface FontFace
getter weight getter weight
method constructor method constructor
method load method load
setter ascentOverride
setter descentOverride
setter display setter display
setter family setter family
setter featureSettings setter featureSettings
setter lineGapOverride
setter stretch setter stretch
setter style setter style
setter unicodeRange setter unicodeRange
......
...@@ -526,9 +526,12 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -526,9 +526,12 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] method write [Worker] method write
[Worker] interface FontFace [Worker] interface FontFace
[Worker] attribute @@toStringTag [Worker] attribute @@toStringTag
[Worker] getter ascentOverride
[Worker] getter descentOverride
[Worker] getter display [Worker] getter display
[Worker] getter family [Worker] getter family
[Worker] getter featureSettings [Worker] getter featureSettings
[Worker] getter lineGapOverride
[Worker] getter loaded [Worker] getter loaded
[Worker] getter status [Worker] getter status
[Worker] getter stretch [Worker] getter stretch
...@@ -538,9 +541,12 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -538,9 +541,12 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] getter weight [Worker] getter weight
[Worker] method constructor [Worker] method constructor
[Worker] method load [Worker] method load
[Worker] setter ascentOverride
[Worker] setter descentOverride
[Worker] setter display [Worker] setter display
[Worker] setter family [Worker] setter family
[Worker] setter featureSettings [Worker] setter featureSettings
[Worker] setter lineGapOverride
[Worker] setter stretch [Worker] setter stretch
[Worker] setter style [Worker] setter style
[Worker] setter unicodeRange [Worker] setter unicodeRange
......
...@@ -2493,9 +2493,12 @@ interface FocusEvent : UIEvent ...@@ -2493,9 +2493,12 @@ interface FocusEvent : UIEvent
method constructor method constructor
interface FontFace interface FontFace
attribute @@toStringTag attribute @@toStringTag
getter ascentOverride
getter descentOverride
getter display getter display
getter family getter family
getter featureSettings getter featureSettings
getter lineGapOverride
getter loaded getter loaded
getter status getter status
getter stretch getter stretch
...@@ -2505,9 +2508,12 @@ interface FontFace ...@@ -2505,9 +2508,12 @@ interface FontFace
getter weight getter weight
method constructor method constructor
method load method load
setter ascentOverride
setter descentOverride
setter display setter display
setter family setter family
setter featureSettings setter featureSettings
setter lineGapOverride
setter stretch setter stretch
setter style setter style
setter unicodeRange setter unicodeRange
......
...@@ -521,9 +521,12 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -521,9 +521,12 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] method write [Worker] method write
[Worker] interface FontFace [Worker] interface FontFace
[Worker] attribute @@toStringTag [Worker] attribute @@toStringTag
[Worker] getter ascentOverride
[Worker] getter descentOverride
[Worker] getter display [Worker] getter display
[Worker] getter family [Worker] getter family
[Worker] getter featureSettings [Worker] getter featureSettings
[Worker] getter lineGapOverride
[Worker] getter loaded [Worker] getter loaded
[Worker] getter status [Worker] getter status
[Worker] getter stretch [Worker] getter stretch
...@@ -533,9 +536,12 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -533,9 +536,12 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] getter weight [Worker] getter weight
[Worker] method constructor [Worker] method constructor
[Worker] method load [Worker] method load
[Worker] setter ascentOverride
[Worker] setter descentOverride
[Worker] setter display [Worker] setter display
[Worker] setter family [Worker] setter family
[Worker] setter featureSettings [Worker] setter featureSettings
[Worker] setter lineGapOverride
[Worker] setter stretch [Worker] setter stretch
[Worker] setter style [Worker] setter style
[Worker] setter unicodeRange [Worker] setter unicodeRange
......
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