Implement new TextMetrics, returned by canvas measureText()
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Jul 2017 23:53:26 +0000 (23:53 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Jul 2017 23:53:26 +0000 (23:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=82798
Source/WebCore:

<rdar://problem/11159332>

Patch by Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori <Hironori.Fujii@sony.com> on 2017-07-26
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.

LayoutTests:

Patch by Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori <Hironori.Fujii@sony.com> on 2017-07-26
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219970 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/canvas/canvas-measureText-2-expected.txt [new file with mode: 0644]
LayoutTests/fast/canvas/canvas-measureText-2.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/TextMetrics.h
Source/WebCore/html/TextMetrics.idl
Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
Source/WebCore/html/canvas/CanvasRenderingContext2D.h
Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp

index a9261b58728b241b747a23833b3449c54865b286..a6e91b07490841187f63e7d7328d9d7323b87da1 100644 (file)
@@ -1,3 +1,24 @@
+2017-07-26  Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori  <Hironori.Fujii@sony.com>
+
+        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  <jlewis3@apple.com>
 
         Marked Multiple imported/w3c/web-platform-tests/ as failing.
diff --git a/LayoutTests/fast/canvas/canvas-measureText-2-expected.txt b/LayoutTests/fast/canvas/canvas-measureText-2-expected.txt
new file mode 100644 (file)
index 0000000..b197095
--- /dev/null
@@ -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
+
diff --git a/LayoutTests/fast/canvas/canvas-measureText-2.html b/LayoutTests/fast/canvas/canvas-measureText-2.html
new file mode 100644 (file)
index 0000000..f1ae629
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset=UTF-8>
+
+        <script src="../../resources/js-test-pre.js"></script>
+
+        <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="../../resources/js-test-post.js"></script>
+    </body>
+</html>
index 587857065765b03b2c81f474f3e1955008b39b62..2cfa8deb6cca22af9ff603ab7a71307cfecd9e5b 100644 (file)
@@ -1,3 +1,66 @@
+2017-07-26  Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori  <Hironori.Fujii@sony.com>
+
+        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  <drousso@apple.com>
 
         Web Inspector: create protocol for recording Canvas contexts
index a7ed7d8e1c135e571926e9de73425227a68864f5..0fccffe76edf5d16678e233453d67d7c213afa5b 100644 (file)
@@ -37,12 +37,52 @@ public:
     float width() const { return m_width; }
     void setWidth(float w) { m_width = w; }
 
-private:
-    TextMetrics()
-        : m_width(0)
-    { }
+    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 m_width;
+    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:
+    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
index b570999654546630eb16fbeadc665f4f43d2bb01..361706c8a8cd7a304905068e113091caa6ff96a5 100644 (file)
     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;
 };
 
index c4779dd92f06e6181e735f134f2d134db8bef14b..3d4f64ac6ff3eea3e95585a44cad46f1679993b2 100644 (file)
@@ -328,7 +328,7 @@ inline void CanvasRenderingContext2D::FontProxy::initialize(FontSelector& fontSe
     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 @@ inline const FontCascadeDescription& CanvasRenderingContext2D::FontProxy::fontDe
     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 @@ Ref<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
     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,51 +2448,14 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo
 
     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;
-
-    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;
-    }
+    FloatPoint location(x, y);
+    location += textOffset(width, direction);
 
     // 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(),
index 68012256441bf4f80499250afa462ee889a8e388..143385d1762327a23370bb7bfffc1239fd5b0720 100644 (file)
@@ -250,9 +250,9 @@ public:
 
         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 @@ private:
     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
index cc37d7d5814183f8a1ac6d85499ccb466a0485ba..e5a74f7f91fe11919980c762b0f063085f654808 100644 (file)
@@ -62,8 +62,15 @@ bool FontCascade::canExpandAroundIdeographsInComplexText()
     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();