Diff
Modified: trunk/LayoutTests/ChangeLog (219969 => 219970)
--- trunk/LayoutTests/ChangeLog 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/LayoutTests/ChangeLog 2017-07-26 23:53:26 UTC (rev 219970)
@@ -1,3 +1,24 @@
+2017-07-26 Arnaud Renevier <[email protected]> and Fujii Hironori <[email protected]>
+
+ Implement new TextMetrics, returned by canvas measureText()
+ https://bugs.webkit.org/show_bug.cgi?id=82798
+
+ Reviewed by Dean Jackson.
+
+ Create a test that checks that:
+ - ascent + descent is greater than zero
+ - actualBoundingBoxLeft + actualBoundingBoxRight is somewhere
+ quite close to width
+ - when baseline is top, emHeightAscent is 0 (respectively
+ bottom/emHeightDescent)
+ - when baseline is hanging, hangingBaseline in 0 (respectively
+ alphabetic and ideographic)
+ - order of different vertical measures (for example,
+ emHeightAscent is always higher that alphabeticBaseline)
+
+ * fast/canvas/canvas-measureText-2-expected.txt: Added.
+ * fast/canvas/canvas-measureText-2.html: Added.
+
2017-07-26 Matt Lewis <[email protected]>
Marked Multiple imported/w3c/web-platform-tests/ as failing.
Added: trunk/LayoutTests/fast/canvas/canvas-measureText-2-expected.txt (0 => 219970)
--- trunk/LayoutTests/fast/canvas/canvas-measureText-2-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-measureText-2-expected.txt 2017-07-26 23:53:26 UTC (rev 219970)
@@ -0,0 +1,594 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+baseline=top align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=start text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=end text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=left text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=right text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=center text="Some simple text"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=top align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightAscent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=hanging align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.hangingBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=middle align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=alphabetic align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.alphabeticBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=ideographic align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.ideographicBaseline) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=start text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=end text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=left text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=right text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+baseline=bottom align=center text="དབུ་མེད་"
+PASS metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width is within 1 of 0
+PASS metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent is >= 0
+PASS metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent is >= 0
+PASS metrics.emHeightAscent + metrics.emHeightDescent is >= 0
+PASS Math.abs(metrics.emHeightDescent) is 0
+PASS metrics.emHeightAscent is >= metrics.hangingBaseline
+PASS metrics.hangingBaseline is >= metrics.alphabeticBaseline
+PASS metrics.alphabeticBaseline is >= metrics.ideographicBaseline
+PASS metrics.ideographicBaseline is >= -metrics.emHeightDescent
+
Added: trunk/LayoutTests/fast/canvas/canvas-measureText-2.html (0 => 219970)
--- trunk/LayoutTests/fast/canvas/canvas-measureText-2.html (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-measureText-2.html 2017-07-26 23:53:26 UTC (rev 219970)
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=UTF-8>
+
+ <script src=""
+
+ <script>
+ var texts = ['Some simple text', 'དབུ་མེད་']; // tibetan script triggers complex path
+ var baselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'];
+ var aligns = ['start', 'end', 'left', 'right', 'center'];
+
+ function tests() {
+ var canvas = document.getElementById("canvas");
+ var ctx = canvas.getContext("2d");
+ ctx.font = "14px sans-serif";
+
+ for (var i = 0; i < texts.length; i++) {
+ for (var j = 0; j < baselines.length; j++) {
+ for (var k = 0; k < aligns.length; k++) {
+ var text = texts[i];
+ var align = aligns[k];
+ var baseline = baselines[j];
+ debug('baseline=' + baseline + ' align=' + align + ' text="' + text + '"');
+ ctx.textBaseline = baseline;
+ ctx.textAlign = align;
+ metrics = ctx.measureText(text);
+
+ shouldBeCloseTo("metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight - metrics.width", 0, 1);
+
+ shouldBeGreaterThanOrEqual("metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent", "0");
+ shouldBeGreaterThanOrEqual("metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent", "0");
+ shouldBeGreaterThanOrEqual("metrics.emHeightAscent + metrics.emHeightDescent", "0");
+
+ if (baseline === 'top')
+ shouldBeZero("Math.abs(metrics.emHeightAscent)");
+ if (baseline === 'bottom')
+ shouldBeZero("Math.abs(metrics.emHeightDescent)");
+ if (baseline === 'hanging')
+ shouldBeZero("Math.abs(metrics.hangingBaseline)");
+ if (baseline === 'alphabetic')
+ shouldBeZero("Math.abs(metrics.alphabeticBaseline)");
+ if (baseline === 'ideographic')
+ shouldBeZero("Math.abs(metrics.ideographicBaseline)");
+
+ shouldBeGreaterThanOrEqual("metrics.emHeightAscent", "metrics.hangingBaseline");
+ shouldBeGreaterThanOrEqual("metrics.hangingBaseline", "metrics.alphabeticBaseline");
+ shouldBeGreaterThanOrEqual("metrics.alphabeticBaseline", "metrics.ideographicBaseline");
+ shouldBeGreaterThanOrEqual("metrics.ideographicBaseline", "-metrics.emHeightDescent");
+ }
+ }
+ }
+
+ }
+
+ window.addEventListener('load', tests, true);
+
+ </script>
+
+ </head>
+
+ <body>
+
+ <canvas id="canvas"></canvas>
+
+ <script src=""
+ </body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (219969 => 219970)
--- trunk/Source/WebCore/ChangeLog 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/ChangeLog 2017-07-26 23:53:26 UTC (rev 219970)
@@ -1,3 +1,66 @@
+2017-07-26 Arnaud Renevier <[email protected]> and Fujii Hironori <[email protected]>
+
+ Implement new TextMetrics, returned by canvas measureText()
+ https://bugs.webkit.org/show_bug.cgi?id=82798
+ <rdar://problem/11159332>
+
+ Reviewed by Dean Jackson.
+
+ The specification: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-measuretext
+
+ Add new attributes to TextMetrics.
+
+ Add a new method textOffset() of CanvasRenderingContext2D by
+ extracting from drawTextInternal() to use the same horizontal and
+ vertical offsets of a text in both drawTextInternal() and
+ measureText().
+
+ Test: fast/canvas/canvas-measureText-2.html
+
+ * html/TextMetrics.h:
+ (WebCore::TextMetrics::actualBoundingBoxLeft):
+ (WebCore::TextMetrics::setActualBoundingBoxLeft):
+ (WebCore::TextMetrics::actualBoundingBoxRight):
+ (WebCore::TextMetrics::setActualBoundingBoxRight):
+ (WebCore::TextMetrics::fontBoundingBoxAscent):
+ (WebCore::TextMetrics::setFontBoundingBoxAscent):
+ (WebCore::TextMetrics::fontBoundingBoxDescent):
+ (WebCore::TextMetrics::setFontBoundingBoxDescent):
+ (WebCore::TextMetrics::actualBoundingBoxAscent):
+ (WebCore::TextMetrics::setActualBoundingBoxAscent):
+ (WebCore::TextMetrics::actualBoundingBoxDescent):
+ (WebCore::TextMetrics::setActualBoundingBoxDescent):
+ (WebCore::TextMetrics::emHeightAscent):
+ (WebCore::TextMetrics::setEmHeightAscent):
+ (WebCore::TextMetrics::emHeightDescent):
+ (WebCore::TextMetrics::setEmHeightDescent):
+ (WebCore::TextMetrics::hangingBaseline):
+ (WebCore::TextMetrics::setHangingBaseline):
+ (WebCore::TextMetrics::alphabeticBaseline):
+ (WebCore::TextMetrics::setAlphabeticBaseline):
+ (WebCore::TextMetrics::ideographicBaseline):
+ (WebCore::TextMetrics::setIdeographicBaseline):
+ Added getters and setters.
+ (WebCore::TextMetrics::TextMetrics): Deleted.
+ * html/TextMetrics.idl: Added new attributes.
+ * html/canvas/CanvasRenderingContext2D.cpp:
+ (WebCore::CanvasRenderingContext2D::FontProxy::fontMetrics):
+ Changed the return value type to a const reference of FontMetrics
+ not to copy it.
+ (WebCore::CanvasRenderingContext2D::FontProxy::width):
+ Added the second arguemnt of GlyphOverflow type.
+ (WebCore::CanvasRenderingContext2D::measureText): Calculate and
+ set the new attributes of TextMetrics.
+ (WebCore::CanvasRenderingContext2D::textOffset): Extracted from drawTextInternal.
+ (WebCore::CanvasRenderingContext2D::drawTextInternal): Removed the
+ offset calculation code and call textOffset.
+ * html/canvas/CanvasRenderingContext2D.h: Added the method
+ declaration of textOffset. Change types of fontMetrics and width
+ methods.
+ * platform/graphics/cairo/FontCairoHarfbuzzNG.cpp:
+ (WebCore::FontCascade::floatWidthForComplexText): Added a dummy
+ implementation of calculating GlyphOverflow.
+
2017-07-26 Devin Rousso <[email protected]>
Web Inspector: create protocol for recording Canvas contexts
Modified: trunk/Source/WebCore/html/TextMetrics.h (219969 => 219970)
--- trunk/Source/WebCore/html/TextMetrics.h 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/html/TextMetrics.h 2017-07-26 23:53:26 UTC (rev 219970)
@@ -37,12 +37,52 @@
float width() const { return m_width; }
void setWidth(float w) { m_width = w; }
+ float actualBoundingBoxLeft() const { return m_actualBoundingBoxLeft; }
+ void setActualBoundingBoxLeft(float value) { m_actualBoundingBoxLeft = value; }
+
+ float actualBoundingBoxRight() const { return m_actualBoundingBoxRight; }
+ void setActualBoundingBoxRight(float value) { m_actualBoundingBoxRight = value; }
+
+ float fontBoundingBoxAscent() const { return m_fontBoundingBoxAscent; }
+ void setFontBoundingBoxAscent(float value) { m_fontBoundingBoxAscent = value; }
+
+ float fontBoundingBoxDescent() const { return m_fontBoundingBoxDescent; }
+ void setFontBoundingBoxDescent(float value) { m_fontBoundingBoxDescent = value; }
+
+ float actualBoundingBoxAscent() const { return m_actualBoundingBoxAscent; }
+ void setActualBoundingBoxAscent(float value) { m_actualBoundingBoxAscent = value; }
+
+ float actualBoundingBoxDescent() const { return m_actualBoundingBoxDescent; }
+ void setActualBoundingBoxDescent(float value) { m_actualBoundingBoxDescent = value; }
+
+ float emHeightAscent() const { return m_emHeightAscent; }
+ void setEmHeightAscent(float value) { m_emHeightAscent = value; }
+
+ float emHeightDescent() const { return m_emHeightDescent; }
+ void setEmHeightDescent(float value) { m_emHeightDescent = value; }
+
+ float hangingBaseline() const { return m_hangingBaseline; }
+ void setHangingBaseline(float value) { m_hangingBaseline = value; }
+
+ float alphabeticBaseline() const { return m_alphabeticBaseline; }
+ void setAlphabeticBaseline(float value) { m_alphabeticBaseline = value; }
+
+ float ideographicBaseline() const { return m_ideographicBaseline; }
+ void setIdeographicBaseline(float value) { m_ideographicBaseline = value; }
+
private:
- TextMetrics()
- : m_width(0)
- { }
-
- float m_width;
+ float m_width { 0 };
+ float m_actualBoundingBoxLeft { 0 };
+ float m_actualBoundingBoxRight { 0 };
+ float m_fontBoundingBoxAscent { 0 };
+ float m_fontBoundingBoxDescent { 0 };
+ float m_actualBoundingBoxAscent { 0 };
+ float m_actualBoundingBoxDescent { 0 };
+ float m_emHeightAscent { 0 };
+ float m_emHeightDescent { 0 };
+ float m_hangingBaseline { 0 };
+ float m_alphabeticBaseline { 0 };
+ float m_ideographicBaseline { 0 };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/TextMetrics.idl (219969 => 219970)
--- trunk/Source/WebCore/html/TextMetrics.idl 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/html/TextMetrics.idl 2017-07-26 23:53:26 UTC (rev 219970)
@@ -26,5 +26,16 @@
ImplementationLacksVTable,
] interface TextMetrics {
readonly attribute unrestricted float width;
+ readonly attribute unrestricted float actualBoundingBoxLeft;
+ readonly attribute unrestricted float actualBoundingBoxRight;
+ readonly attribute unrestricted float fontBoundingBoxAscent;
+ readonly attribute unrestricted float fontBoundingBoxDescent;
+ readonly attribute unrestricted float actualBoundingBoxAscent;
+ readonly attribute unrestricted float actualBoundingBoxDescent;
+ readonly attribute unrestricted float emHeightAscent;
+ readonly attribute unrestricted float emHeightDescent;
+ readonly attribute unrestricted float hangingBaseline;
+ readonly attribute unrestricted float alphabeticBaseline;
+ readonly attribute unrestricted float ideographicBaseline;
};
Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (219969 => 219970)
--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp 2017-07-26 23:53:26 UTC (rev 219970)
@@ -328,7 +328,7 @@
m_font.fontSelector()->registerForInvalidationCallbacks(*this);
}
-inline FontMetrics CanvasRenderingContext2D::FontProxy::fontMetrics() const
+inline const FontMetrics& CanvasRenderingContext2D::FontProxy::fontMetrics() const
{
return m_font.fontMetrics();
}
@@ -338,9 +338,9 @@
return m_font.fontDescription();
}
-inline float CanvasRenderingContext2D::FontProxy::width(const TextRun& textRun) const
+inline float CanvasRenderingContext2D::FontProxy::width(const TextRun& textRun, GlyphOverflow* overflow) const
{
- return m_font.width(textRun);
+ return m_font.width(textRun, 0, overflow);
}
inline void CanvasRenderingContext2D::FontProxy::drawBidiText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, FontCascade::CustomFontNotReadyAction action) const
@@ -2344,11 +2344,79 @@
String normalizedText = text;
normalizeSpaces(normalizedText);
- metrics->setWidth(fontProxy().width(TextRun(normalizedText)));
+ const RenderStyle* computedStyle;
+ auto direction = toTextDirection(state().direction, &computedStyle);
+ bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
+ TextRun textRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override, true);
+ auto& font = fontProxy();
+ auto& fontMetrics = font.fontMetrics();
+
+ GlyphOverflow glyphOverflow;
+ glyphOverflow.computeBounds = true;
+ float fontWidth = font.width(textRun, &glyphOverflow);
+ metrics->setWidth(fontWidth);
+
+ FloatPoint offset = textOffset(fontWidth, direction);
+
+ metrics->setActualBoundingBoxAscent(glyphOverflow.top - offset.y());
+ metrics->setActualBoundingBoxDescent(glyphOverflow.bottom + offset.y());
+ metrics->setFontBoundingBoxAscent(fontMetrics.ascent() - offset.y());
+ metrics->setFontBoundingBoxDescent(fontMetrics.descent() + offset.y());
+ metrics->setEmHeightAscent(fontMetrics.ascent() - offset.y());
+ metrics->setEmHeightDescent(fontMetrics.descent() + offset.y());
+ metrics->setHangingBaseline(fontMetrics.ascent() - offset.y());
+ metrics->setAlphabeticBaseline(-offset.y());
+ metrics->setIdeographicBaseline(-fontMetrics.descent() - offset.y());
+
+ metrics->setActualBoundingBoxLeft(glyphOverflow.left - offset.x());
+ metrics->setActualBoundingBoxRight(fontWidth + glyphOverflow.right + offset.x());
+
return metrics;
}
+FloatPoint CanvasRenderingContext2D::textOffset(float width, TextDirection direction)
+{
+ auto& fontMetrics = fontProxy().fontMetrics();
+ FloatPoint offset;
+
+ switch (state().textBaseline) {
+ case TopTextBaseline:
+ case HangingTextBaseline:
+ offset.setY(fontMetrics.ascent());
+ break;
+ case BottomTextBaseline:
+ case IdeographicTextBaseline:
+ offset.setY(-fontMetrics.descent());
+ break;
+ case MiddleTextBaseline:
+ offset.setY(fontMetrics.height() / 2 - fontMetrics.descent());
+ break;
+ case AlphabeticTextBaseline:
+ default:
+ break;
+ }
+
+ bool isRTL = direction == RTL;
+ auto align = state().textAlign;
+ if (align == StartTextAlign)
+ align = isRTL ? RightTextAlign : LeftTextAlign;
+ else if (align == EndTextAlign)
+ align = isRTL ? LeftTextAlign : RightTextAlign;
+
+ switch (align) {
+ case CenterTextAlign:
+ offset.setX(-width / 2);
+ break;
+ case RightTextAlign:
+ offset.setX(-width);
+ break;
+ default:
+ break;
+ }
+ return offset;
+}
+
void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth)
{
auto& fontProxy = this->fontProxy();
@@ -2380,52 +2448,15 @@
const RenderStyle* computedStyle;
auto direction = toTextDirection(state().direction, &computedStyle);
- bool isRTL = direction == RTL;
bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
TextRun textRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override, true);
- // Draw the item text at the correct point.
- FloatPoint location(x, y);
- switch (state().textBaseline) {
- case TopTextBaseline:
- case HangingTextBaseline:
- location.setY(y + fontMetrics.ascent());
- break;
- case BottomTextBaseline:
- case IdeographicTextBaseline:
- location.setY(y - fontMetrics.descent());
- break;
- case MiddleTextBaseline:
- location.setY(y - fontMetrics.descent() + fontMetrics.height() / 2);
- break;
- case AlphabeticTextBaseline:
- default:
- // Do nothing.
- break;
- }
-
- float fontWidth = fontProxy.width(TextRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override));
-
+ float fontWidth = fontProxy.width(textRun);
bool useMaxWidth = maxWidth && maxWidth.value() < fontWidth;
float width = useMaxWidth ? maxWidth.value() : fontWidth;
+ FloatPoint location(x, y);
+ location += textOffset(width, direction);
- auto align = state().textAlign;
- if (align == StartTextAlign)
- align = isRTL ? RightTextAlign : LeftTextAlign;
- else if (align == EndTextAlign)
- align = isRTL ? LeftTextAlign : RightTextAlign;
-
- switch (align) {
- case CenterTextAlign:
- location.setX(location.x() - width / 2);
- break;
- case RightTextAlign:
- location.setX(location.x() - width);
- break;
- default:
- break;
- }
-
// The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
width + fontMetrics.height(), fontMetrics.lineSpacing());
Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h (219969 => 219970)
--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h 2017-07-26 23:53:26 UTC (rev 219970)
@@ -250,9 +250,9 @@
bool realized() const { return m_font.fontSelector(); }
void initialize(FontSelector&, const RenderStyle&);
- FontMetrics fontMetrics() const;
+ const FontMetrics& fontMetrics() const;
const FontCascadeDescription& fontDescription() const;
- float width(const TextRun&) const;
+ float width(const TextRun&, GlyphOverflow* = 0) const;
void drawBidiText(GraphicsContext&, const TextRun&, const FloatPoint&, FontCascade::CustomFontNotReadyAction) const;
private:
@@ -390,6 +390,8 @@
bool hasInvertibleTransform() const override { return state().hasInvertibleTransform; }
TextDirection toTextDirection(Direction, const RenderStyle** computedStyle = nullptr) const;
+ FloatPoint textOffset(float width, TextDirection);
+
#if ENABLE(ACCELERATED_2D_CANVAS)
PlatformLayer* platformLayer() const override;
#endif
Modified: trunk/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp (219969 => 219970)
--- trunk/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp 2017-07-26 23:29:25 UTC (rev 219969)
+++ trunk/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp 2017-07-26 23:53:26 UTC (rev 219970)
@@ -62,8 +62,15 @@
return false;
}
-float FontCascade::floatWidthForComplexText(const TextRun& run, HashSet<const Font*>*, GlyphOverflow*) const
+float FontCascade::floatWidthForComplexText(const TextRun& run, HashSet<const Font*>*, GlyphOverflow* glyphOverflow) const
{
+ if (glyphOverflow) {
+ // FIXME: Calculate the actual values rather than just the font's ascent and descent
+ glyphOverflow->top = glyphOverflow->computeBounds ? fontMetrics().ascent() : 0;
+ glyphOverflow->bottom = glyphOverflow->computeBounds ? fontMetrics().descent() : 0;
+ glyphOverflow->left = 0;
+ glyphOverflow->right = 0;
+ }
HarfBuzzShaper shaper(this, run);
if (shaper.shape())
return shaper.totalWidth();