Skip to content

Commit

Permalink
Bug 1778910 - Hook up rendering support for canvas2d fontVariantCaps,…
Browse files Browse the repository at this point in the history
… 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 whatwg/html#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
  • Loading branch information
jfkthame committed Jul 6, 2023
1 parent c5a0f79 commit 6c6d971
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 2 deletions.
75 changes: 73 additions & 2 deletions dom/canvas/CanvasRenderingContext2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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 comments on commit 6c6d971

Please sign in to comment.