Bug 1778910 - Hook up rendering support for canvas2d fontVariantCaps, and add WPT reftests. r=gfx-reviewers,lsalzman

The behavior in some of these cases is open to debate, as the spec is quite unclear;
see https://github.com/whatwg/html/issues/8103. What I've implemented here gives the
same rendering result as Chrome for these tests, so hopefully we can get this clarified
in the spec as well.

Differential Revision: https://phabricator.services.mozilla.com/D182567
This commit is contained in:
Jonathan Kew 2023-07-06 19:05:53 +00:00
Родитель c5a0f7995c
Коммит 6c6d97166b
10 изменённых файлов: 214 добавлений и 2 удалений

Просмотреть файл

@ -3693,6 +3693,10 @@ void CanvasRenderingContext2D::SetFont(const nsACString& aFont,
return;
}
// Setting the font attribute magically resets fontVariantCaps to normal.
// (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
SetFontVariantCaps(CanvasFontVariantCaps::Normal);
// If letterSpacing or wordSpacing is present, recompute to account for
// changes to font-relative dimensions.
UpdateSpacing();
@ -3752,6 +3756,38 @@ bool CanvasRenderingContext2D::SetFontInternal(const nsACString& aFont,
resizedFont.kerning = CanvasToGfx(CurrentState().fontKerning);
// fontVariantCaps handling: if fontVariantCaps is not 'normal', apply it;
// if it is, then use the smallCaps boolean from the shorthand.
// XXX(jfkthame) The interaction between the shorthand and the separate attr
// here is not clearly spec'd, and we may want to reconsider it (or revise
// the available values); see https://github.com/whatwg/html/issues/8103.
switch (CurrentState().fontVariantCaps) {
case CanvasFontVariantCaps::Normal:
// Leave whatever the shorthand set.
break;
case CanvasFontVariantCaps::Small_caps:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_SMALLCAPS;
break;
case CanvasFontVariantCaps::All_small_caps:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_ALLSMALL;
break;
case CanvasFontVariantCaps::Petite_caps:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_PETITECAPS;
break;
case CanvasFontVariantCaps::All_petite_caps:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_ALLPETITE;
break;
case CanvasFontVariantCaps::Unicase:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_UNICASE;
break;
case CanvasFontVariantCaps::Titling_caps:
resizedFont.variantCaps = NS_FONT_VARIANT_CAPS_TITLING;
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown caps value");
break;
}
c->Document()->FlushUserFontSet();
nsFontMetrics::Params params;
@ -3857,8 +3893,42 @@ bool CanvasRenderingContext2D::SetFontInternalDisconnected(
}
fontStyle.size = QuantizeFontSize(size);
fontStyle.variantCaps =
smallCaps ? NS_FONT_VARIANT_CAPS_SMALLCAPS : NS_FONT_VARIANT_CAPS_NORMAL;
// fontVariantCaps handling: if fontVariantCaps is not 'normal', apply it;
// if it is, then use the smallCaps boolean from the shorthand.
// XXX(jfkthame) The interaction between the shorthand and the separate attr
// here is not clearly spec'd, and we may want to reconsider it (or revise
// the available values); see https://github.com/whatwg/html/issues/8103.
switch (CurrentState().fontVariantCaps) {
case CanvasFontVariantCaps::Normal:
fontStyle.variantCaps = smallCaps ? NS_FONT_VARIANT_CAPS_SMALLCAPS
: NS_FONT_VARIANT_CAPS_NORMAL;
break;
case CanvasFontVariantCaps::Small_caps:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_SMALLCAPS;
break;
case CanvasFontVariantCaps::All_small_caps:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_ALLSMALL;
break;
case CanvasFontVariantCaps::Petite_caps:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_PETITECAPS;
break;
case CanvasFontVariantCaps::All_petite_caps:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_ALLPETITE;
break;
case CanvasFontVariantCaps::Unicase:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_UNICASE;
break;
case CanvasFontVariantCaps::Titling_caps:
fontStyle.variantCaps = NS_FONT_VARIANT_CAPS_TITLING;
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown caps value");
break;
}
// If variantCaps is set, we need to disable a gfxFont fast-path.
fontStyle.noFallbackVariantFeatures =
(fontStyle.variantCaps == NS_FONT_VARIANT_CAPS_NORMAL);
// Set the kerning feature, if required by the fontKerning attribute.
gfxFontFeature setting{TRUETYPE_TAG('k', 'e', 'r', 'n'), 0};
@ -3907,6 +3977,7 @@ bool CanvasRenderingContext2D::SetFontInternalDisconnected(
SerializeFontForCanvas(list, fontStyle, CurrentState().font);
CurrentState().fontFont = nsFont(StyleFontFamily{list, false, false},
StyleCSSPixelLength::FromPixels(size));
CurrentState().fontFont.variantCaps = fontStyle.variantCaps;
CurrentState().fontLanguage = nullptr;
CurrentState().fontExplicitLanguage = false;
return true;

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="match" href="reference/fontVariantCaps-1-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "32px serif";
ctx.fontVariantCaps = "small-caps";
// This should render the same as font = "small-caps 32px serif".
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="mismatch" href="reference/fontVariantCaps-2-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "small-caps 32px serif";
// "mismatch" test, to verify that small-caps does change the rendering.
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="match" href="reference/fontVariantCaps-3-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "32px serif";
ctx.fontVariantCaps = "all-small-caps";
// This should render the same as using font = "small-caps 32px serif"
// with all the underlying text in lowercase.
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="match" href="reference/fontVariantCaps-3-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "small-caps 32px serif";
// fontVariantCaps overrides the small-caps setting from the font attribute
// (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
ctx.fontVariantCaps = "all-small-caps";
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="match" href="reference/fontVariantCaps-1-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "small-caps 32px serif";
// fontVariantCaps 'normal' does not override the setting from the font attribute.
// (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
ctx.fontVariantCaps = "normal";
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas Test: the 'fontVariantCaps' property</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fontvariantcaps">
<link rel="match" href="reference/fontVariantCaps-2-ref.html">
<meta name="assert" content="text rendering respects the fontVariantCaps property">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
// fontVariantCaps is reset when the font attribute is set.
// (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
ctx.fontVariantCaps = "all-small-caps";
ctx.font = "32px serif";
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas reference</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "small-caps 32px serif";
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas reference</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "32px serif";
ctx.fillText("Hello World", 20, 100);
</script>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Canvas reference</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<canvas id="c"></canvas>
<script>
let ctx = c.getContext("2d");
ctx.font = "small-caps 32px serif";
ctx.fillText("hello world", 20, 100);
</script>