Changeset 270102 in webkit


Ignore:
Timestamp:
Nov 20, 2020 3:40:06 AM (3 years ago)
Author:
Chris Lord
Message:

Enable font functions on OffscreenCanvas for main-thread
https://bugs.webkit.org/show_bug.cgi?id=219088

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

Update test expectations for OffscreenCanvas text tests and add where
they were missing.

  • web-platform-tests/html/canvas/offscreen/text/*:

Source/WebCore:

Move some font-related code from CanvasRenderingContext2D to
CanvasRenderingContext2DBase so it can be shared by OffscreenCanvas
and enable font functions on the OffscreenCanvas rendering context.
Font setting only works when a Document is available, so this only
enables drawing/measuring of text on the main thread.

No new tests. Rebaselined existing tests.

  • html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::measureText):
(WebCore::CanvasRenderingContext2D::fontProxy const):
(WebCore::CanvasRenderingContext2D::drawTextInternal):

  • html/canvas/CanvasRenderingContext2D.h:
  • html/canvas/CanvasRenderingContext2DBase.cpp:

(WebCore::CanvasRenderingContext2DBase::font const):
(WebCore::toCanvasTextAlign):
(WebCore::fromCanvasTextAlign):
(WebCore::CanvasRenderingContext2DBase::textAlign const):
(WebCore::CanvasRenderingContext2DBase::setTextAlign):
(WebCore::toCanvasTextBaseline):
(WebCore::fromCanvasTextBaseline):
(WebCore::CanvasRenderingContext2DBase::textBaseline const):
(WebCore::CanvasRenderingContext2DBase::setTextBaseline):
(WebCore::CanvasRenderingContext2DBase::setDirection):
(WebCore::CanvasRenderingContext2DBase::canDrawTextWithParams):
(WebCore::CanvasRenderingContext2DBase::normalizeSpaces):
(WebCore::CanvasRenderingContext2DBase::drawText):
(WebCore::CanvasRenderingContext2DBase::drawTextUnchecked):
(WebCore::CanvasRenderingContext2DBase::measureTextInternal):
(WebCore::CanvasRenderingContext2DBase::textOffset):

  • html/canvas/CanvasRenderingContext2DBase.h:

(WebCore::CanvasRenderingContext2DBase::fontProxy):

  • html/canvas/OffscreenCanvasRenderingContext2D.cpp:

(WebCore::OffscreenCanvasRenderingContext2D::setFont):
(WebCore::OffscreenCanvasRenderingContext2D::direction const):
(WebCore::OffscreenCanvasRenderingContext2D::fontProxy const):
(WebCore::OffscreenCanvasRenderingContext2D::fillText):
(WebCore::OffscreenCanvasRenderingContext2D::strokeText):
(WebCore::OffscreenCanvasRenderingContext2D::measureText):

  • html/canvas/OffscreenCanvasRenderingContext2D.h:
  • html/canvas/OffscreenCanvasRenderingContext2D.idl:

LayoutTests:

Enable running OffscreenCanvas text tests.

  • platform/glib/TestExpectations:
Location:
trunk
Files:
23 added
87 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r270101 r270102  
     12020-11-20  Chris Lord  <clord@igalia.com>
     2
     3        Enable font functions on OffscreenCanvas for main-thread
     4        https://bugs.webkit.org/show_bug.cgi?id=219088
     5
     6        Reviewed by Simon Fraser.
     7
     8        Enable running OffscreenCanvas text tests.
     9
     10        * platform/glib/TestExpectations:
     11
    1122020-11-20  Youenn Fablet  <youenn@apple.com>
    213
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r270101 r270102  
     12020-11-20  Chris Lord  <clord@igalia.com>
     2
     3        Enable font functions on OffscreenCanvas for main-thread
     4        https://bugs.webkit.org/show_bug.cgi?id=219088
     5
     6        Reviewed by Simon Fraser.
     7
     8        Update test expectations for OffscreenCanvas text tests and add where
     9        they were missing.
     10
     11        * web-platform-tests/html/canvas/offscreen/text/*:
     12
    1132020-11-20  Youenn Fablet  <youenn@apple.com>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.align.default-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.align.default assert_equals: ctx.textAlign === 'start' (got [undefined], expected start[string]) expected (string) "start" but got (undefined) undefined
     4PASS OffscreenCanvas test: 2d.text.align.default
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.align.default.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.textAlign === 'start' (got [undefined], expected start[string]) expected (string) "start" but got (undefined) undefined
     2PASS 2d
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.align.invalid-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.align.invalid assert_equals: ctx.textAlign === 'start' (got bogus[string], expected start[string]) expected "start" but got "bogus"
     4PASS OffscreenCanvas test: 2d.text.align.invalid
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.align.invalid.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.textAlign === 'start' (got bogus[string], expected start[string]) expected "start" but got "bogus"
     2PASS 2d
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.baseline.default-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.baseline.default assert_equals: ctx.textBaseline === 'alphabetic' (got [undefined], expected alphabetic[string]) expected (string) "alphabetic" but got (undefined) undefined
     4PASS OffscreenCanvas test: 2d.text.baseline.default
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.baseline.default.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.textBaseline === 'alphabetic' (got [undefined], expected alphabetic[string]) expected (string) "alphabetic" but got (undefined) undefined
     2PASS 2d
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.baseline.invalid-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.baseline.invalid assert_equals: ctx.textBaseline === 'top' (got bogus[string], expected top[string]) expected "top" but got "bogus"
     4PASS OffscreenCanvas test: 2d.text.baseline.invalid
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.baseline.invalid.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.textBaseline === 'top' (got bogus[string], expected top[string]) expected "top" but got "bogus"
     2PASS 2d
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.center.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign center is the center of the em squares (not the bounding box)
     2FAIL textAlign center is the center of the em squares (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.end.ltr.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign end with ltr is the right edge
     2FAIL textAlign end with ltr is the right edge Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.end.rtl.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign end with rtl is the left edge
     2FAIL textAlign end with rtl is the left edge Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.left.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign left is the left of the first em square (not the bounding box)
     2FAIL textAlign left is the left of the first em square (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.right.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign right is the right of the last em square (not the bounding box)
     2FAIL textAlign right is the right of the last em square (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.start.ltr.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign start with ltr is the left edge
     2FAIL textAlign start with ltr is the left edge Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.align.start.rtl.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textAlign start with rtl is the right edge
     2FAIL textAlign start with rtl is the right edge Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.alphabetic.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL 2d Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.bottom-expected.txt

    r267646 r270102  
    44
    55
    6 PASS textBaseline bottom is the bottom of the em square (not the bounding box)
     6FAIL textBaseline bottom is the bottom of the em square (not the bounding box) assert_approx_equals: Red channel of the pixel at (25, 25) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.bottom.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textBaseline bottom is the bottom of the em square (not the bounding box)
     2FAIL textBaseline bottom is the bottom of the em square (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.hanging-expected.txt

    r267646 r270102  
    22
    33
    4 PASS OffscreenCanvas test: 2d.text.draw.baseline.hanging
     4FAIL OffscreenCanvas test: 2d.text.draw.baseline.hanging assert_approx_equals: Red channel of the pixel at (5, 5) expected 0 +/- 2 but got 255
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.hanging.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL 2d Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.ideographic-expected.txt

    r267646 r270102  
    22
    33
    4 PASS OffscreenCanvas test: 2d.text.draw.baseline.ideographic
     4FAIL OffscreenCanvas test: 2d.text.draw.baseline.ideographic assert_approx_equals: Red channel of the pixel at (5, 5) expected 0 +/- 2 but got 255
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.ideographic.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL 2d Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.middle-expected.txt

    r267646 r270102  
    44
    55
    6 PASS textBaseline middle is the middle of the em square (not the bounding box)
     6FAIL textBaseline middle is the middle of the em square (not the bounding box) assert_approx_equals: Red channel of the pixel at (5, 5) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.middle.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textBaseline middle is the middle of the em square (not the bounding box)
     2FAIL textBaseline middle is the middle of the em square (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.top-expected.txt

    r267646 r270102  
    44
    55
    6 PASS textBaseline top is the top of the em square (not the bounding box)
     6FAIL textBaseline top is the top of the em square (not the bounding box) assert_approx_equals: Red channel of the pixel at (5, 5) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.baseline.top.worker-expected.txt

    r267646 r270102  
    11
    2 PASS textBaseline top is the top of the em square (not the bounding box)
     2FAIL textBaseline top is the top of the em square (not the bounding box) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.basic-manual.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText draws filled text ctx.fillText is not a function. (In 'ctx.fillText('PASS', 5, 35)', 'ctx.fillText' is undefined)
     2PASS fillText draws filled text
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.NaN-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, NaN)', 'ctx.fillText' is undefined)
     6PASS fillText handles maxWidth correctly
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.NaN.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, NaN)', 'ctx.fillText' is undefined)
     2PASS fillText handles maxWidth correctly
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.bound.worker-expected.txt

    r267646 r270102  
    11
    2 PASS fillText handles maxWidth based on line size, not bounding box size
     2FAIL fillText handles maxWidth based on line size, not bounding box size Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.fontface.worker-expected.txt

    r267646 r270102  
    11
    2 PASS fillText works on @font-face fonts
     2FAIL fillText works on @font-face fonts Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.large-manual.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('PASS', 5, 35, 200)', 'ctx.fillText' is undefined)
     2PASS fillText handles maxWidth correctly
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.negative-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, -1)', 'ctx.fillText' is undefined)
     6PASS fillText handles maxWidth correctly
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.negative.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, -1)', 'ctx.fillText' is undefined)
     2PASS fillText handles maxWidth correctly
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.small-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', -100, 35, 90)', 'ctx.fillText' is undefined)
     6PASS fillText handles maxWidth correctly
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.small.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', -100, 35, 90)', 'ctx.fillText' is undefined)
     2PASS fillText handles maxWidth correctly
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.zero-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, 0)', 'ctx.fillText' is undefined)
     6PASS fillText handles maxWidth correctly
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.zero.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText handles maxWidth correctly ctx.fillText is not a function. (In 'ctx.fillText('fail fail fail fail fail', 5, 35, 0)', 'ctx.fillText' is undefined)
     2PASS fillText handles maxWidth correctly
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.rtl-manual.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText respects Right-To-Left Override characters ctx.fillText is not a function. (In 'ctx.fillText('\u202eFAIL \xa0 \xa0 SSAP', 5, 35)', 'ctx.fillText' is undefined)
     2PASS fillText respects Right-To-Left Override characters
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.unaffected-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL fillText does not start a new path or subpath ctx.fillText is not a function. (In 'ctx.fillText('FAIL', 5, 35)', 'ctx.fillText' is undefined)
     6PASS fillText does not start a new path or subpath
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fill.unaffected.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL fillText does not start a new path or subpath ctx.fillText is not a function. (In 'ctx.fillText('FAIL', 5, 35)', 'ctx.fillText' is undefined)
     2PASS fillText does not start a new path or subpath
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fontface.notinpage.worker-expected.txt

    r267646 r270102  
    11
    2 PASS @font-face fonts should work even if they are not used in the page
     2FAIL @font-face fonts should work even if they are not used in the page Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fontface.repeat-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL Draw with the font immediately, then wait a bit until and draw again. (This crashes some version of WebKit.) ctx.fillText is not a function. (In 'ctx.fillText('AA', 0, 50)', 'ctx.fillText' is undefined)
     6PASS Draw with the font immediately, then wait a bit until and draw again. (This crashes some version of WebKit.)
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fontface.repeat.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL Draw with the font immediately, then wait a bit until and draw again. (This crashes some version of WebKit.) ctx.fillText is not a function. (In 'ctx.fillText('AA', 0, 50)', 'ctx.fillText' is undefined)
     2FAIL Draw with the font immediately, then wait a bit until and draw again. (This crashes some version of WebKit.) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.fontface.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL 2d Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.kern.consistent-manual.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL Stroked and filled text should have exactly the same kerning so it overlaps ctx.fillText is not a function. (In 'ctx.fillText('VAVAVAVAVAVAVA', -50, 25)', 'ctx.fillText' is undefined)
     2PASS Stroked and filled text should have exactly the same kerning so it overlaps
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.basic.worker-expected.txt

    r267646 r270102  
    11
    2 PASS U+0020 is rendered the correct size (1em wide)
     2FAIL U+0020 is rendered the correct size (1em wide) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.end-expected.txt

    r267646 r270102  
    44
    55
    6 PASS Space characters at the end of a line are collapsed (per CSS)
     6FAIL Space characters at the end of a line are collapsed (per CSS) assert_approx_equals: Red channel of the pixel at (75, 25) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.end.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Space characters at the end of a line are collapsed (per CSS)
     2FAIL Space characters at the end of a line are collapsed (per CSS) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.nonspace.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Non-space characters are not converted to U+0020 and collapsed
     2FAIL Non-space characters are not converted to U+0020 and collapsed Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.other-expected.txt

    r267646 r270102  
    44
    55
    6 PASS Space characters are converted to U+0020, and collapsed (per CSS)
     6FAIL Space characters are converted to U+0020, and collapsed (per CSS) assert_approx_equals: Red channel of the pixel at (25, 25) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.other.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Space characters are converted to U+0020, and collapsed (per CSS)
     2FAIL Space characters are converted to U+0020, and collapsed (per CSS) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.space-expected.txt

    r267646 r270102  
    44
    55
    6 PASS Space characters are converted to U+0020, and collapsed (per CSS)
     6FAIL Space characters are converted to U+0020, and collapsed (per CSS) assert_approx_equals: Red channel of the pixel at (25, 25) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.space.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Space characters are converted to U+0020, and collapsed (per CSS)
     2FAIL Space characters are converted to U+0020, and collapsed (per CSS) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.start-expected.txt

    r267646 r270102  
    44
    55
    6 PASS Space characters at the start of a line are collapsed (per CSS)
     6FAIL Space characters at the start of a line are collapsed (per CSS) assert_approx_equals: Red channel of the pixel at (25, 25) expected 0 +/- 2 but got 255
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.space.collapse.start.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Space characters at the start of a line are collapsed (per CSS)
     2FAIL Space characters at the start of a line are collapsed (per CSS) Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.stroke.basic-manual.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL strokeText draws stroked text ctx.strokeText is not a function. (In 'ctx.strokeText('PASS', 5, 35)', 'ctx.strokeText' is undefined)
     2PASS strokeText draws stroked text
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.stroke.unaffected-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL strokeText does not start a new path or subpath ctx.strokeText is not a function. (In 'ctx.strokeText('FAIL', 5, 35)', 'ctx.strokeText' is undefined)
     6PASS strokeText does not start a new path or subpath
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.draw.stroke.unaffected.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL strokeText does not start a new path or subpath ctx.strokeText is not a function. (In 'ctx.strokeText('FAIL', 5, 35)', 'ctx.strokeText' is undefined)
     2PASS strokeText does not start a new path or subpath
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.default-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.font.default assert_equals: ctx.font === '10px sans-serif' (got [undefined], expected 10px sans-serif[string]) expected (string) "10px sans-serif" but got (undefined) undefined
     4PASS OffscreenCanvas test: 2d.text.font.default
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.default.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.font === '10px sans-serif' (got [undefined], expected 10px sans-serif[string]) expected (string) "10px sans-serif" but got (undefined) undefined
     2PASS 2d
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.basic-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.font.parse.basic assert_equals: ctx.font === '20px serif' (got 20PX   SERIF[string], expected 20px serif[string]) expected "20px serif" but got "20PX   SERIF"
     4PASS OffscreenCanvas test: 2d.text.font.parse.basic
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.basic.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.font === '20px serif' (got 20PX   SERIF[string], expected 20px serif[string]) expected "20px serif" but got "20PX   SERIF"
     2FAIL 2d assert_equals: ctx.font === '20px serif' (got 10px sans-serif[string], expected 20px serif[string]) expected "20px serif" but got "10px sans-serif"
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.complex-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.font.parse.complex assert_equals: ctx.font === 'italic small-caps 12px "Unknown Font", sans-serif' (got small-caps italic 400 12px/2 Unknown Font, sans-serif[string], expected italic small-caps 12px "Unknown Font", sans-serif[string]) expected "italic small-caps 12px \"Unknown Font\", sans-serif" but got "small-caps italic 400 12px/2 Unknown Font, sans-serif"
     4PASS OffscreenCanvas test: 2d.text.font.parse.complex
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.complex.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.font === 'italic small-caps 12px "Unknown Font", sans-serif' (got small-caps italic 400 12px/2 Unknown Font, sans-serif[string], expected italic small-caps 12px "Unknown Font", sans-serif[string]) expected "italic small-caps 12px \"Unknown Font\", sans-serif" but got "small-caps italic 400 12px/2 Unknown Font, sans-serif"
     2FAIL 2d assert_equals: ctx.font === 'italic small-caps 12px "Unknown Font", sans-serif' (got 10px sans-serif[string], expected italic small-caps 12px "Unknown Font", sans-serif[string]) expected "italic small-caps 12px \"Unknown Font\", sans-serif" but got "10px sans-serif"
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.invalid-expected.txt

    r262615 r270102  
    22
    33
    4 FAIL OffscreenCanvas test: 2d.text.font.parse.invalid assert_equals: ctx.font === '20px serif' (got bogus[string], expected 20px serif[string]) expected "20px serif" but got "bogus"
     4PASS OffscreenCanvas test: 2d.text.font.parse.invalid
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.invalid.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL 2d assert_equals: ctx.font === '20px serif' (got bogus[string], expected 20px serif[string]) expected "20px serif" but got "bogus"
     2FAIL 2d assert_equals: ctx.font === '20px serif' (got 10px sans-serif[string], expected 20px serif[string]) expected "20px serif" but got "10px sans-serif"
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.system-expected.txt

    r262615 r270102  
    44
    55
    6 FAIL System fonts must be computed to explicit values assert_not_equals: ctx.font !== 'message-box' (got message-box[string], expected not message-box[string]) got disallowed value "message-box"
     6PASS System fonts must be computed to explicit values
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.system.worker-expected.txt

    r262615 r270102  
    11
    2 FAIL System fonts must be computed to explicit values assert_not_equals: ctx.font !== 'message-box' (got message-box[string], expected not message-box[string]) got disallowed value "message-box"
     2PASS System fonts must be computed to explicit values
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.font.parse.tiny.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL 2d assert_equals: ctx.font === '1px sans-serif' (got 10px sans-serif[string], expected 1px sans-serif[string]) expected "1px sans-serif" but got "10px sans-serif"
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.basic-expected.txt

    r267646 r270102  
    112d.text.measure.width.basic
    22
     3The width of character is same as font used for OffscreenCanvas
    34
    4 PASS OffscreenCanvas test: 2d.text.measure.width.basic
    55
     6PASS The width of character is same as font used for OffscreenCanvas
     7
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.basic.worker-expected.txt

    r267646 r270102  
    11
    2 PASS 2d
     2FAIL The width of character is same as font used for OffscreenCanvas Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.empty-expected.txt

    r267646 r270102  
    112d.text.measure.width.empty
    22
    3 The empty string has zero width
     3The empty string has zero width for OffscreenCanvas
    44
    55
    6 PASS The empty string has zero width
     6PASS The empty string has zero width for OffscreenCanvas
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.empty.worker-expected.txt

    r267646 r270102  
    11
    2 PASS The empty string has zero width
     2FAIL The empty string has zero width for OffscreenCanvas Can't find variable: FontFace
    33
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space-expected.txt

    r267646 r270102  
    112d.text.measure.width.space
    22
    3 Space characters are converted to U+0020 and collapsed (per CSS)
     3Space characters are converted to U+0020 and collapsed (per CSS) for OffscreenCanvas
    44
    55
    6 PASS Space characters are converted to U+0020 and collapsed (per CSS)
     6FAIL Space characters are converted to U+0020 and collapsed (per CSS) for OffscreenCanvas assert_equals: ctx.measureText('A \x09\x0a\x0c\x0d  \x09\x0a\x0c\x0dB').width === 150 (got 650[number], expected 150[number]) expected 150 but got 650
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space.worker-expected.txt

    r267646 r270102  
    11
    2 PASS Space characters are converted to U+0020 and collapsed (per CSS)
     2FAIL Space characters are converted to U+0020 and collapsed (per CSS) for OffscreenCanvas Can't find variable: FontFace
    33
  • trunk/LayoutTests/platform/glib/TestExpectations

    r270017 r270102  
    527527#////////////////////////////////////////////////////////////////////////////////////////
    528528
    529 webkit.org/b/186759 imported/w3c/web-platform-tests/html/canvas/offscreen/text [ Skip ]
    530529webkit.org/b/203146 fast/canvas/offscreen-enabled.html [ Pass ]
    531530webkit.org/b/203146 http/wpt/offscreen-canvas [ Pass ]
  • trunk/Source/WebCore/ChangeLog

    r270101 r270102  
     12020-11-20  Chris Lord  <clord@igalia.com>
     2
     3        Enable font functions on OffscreenCanvas for main-thread
     4        https://bugs.webkit.org/show_bug.cgi?id=219088
     5
     6        Reviewed by Simon Fraser.
     7
     8        Move some font-related code from CanvasRenderingContext2D to
     9        CanvasRenderingContext2DBase so it can be shared by OffscreenCanvas
     10        and enable font functions on the OffscreenCanvas rendering context.
     11        Font setting only works when a Document is available, so this only
     12        enables drawing/measuring of text on the main thread.
     13
     14        No new tests. Rebaselined existing tests.
     15
     16        * html/canvas/CanvasRenderingContext2D.cpp:
     17        (WebCore::CanvasRenderingContext2D::measureText):
     18        (WebCore::CanvasRenderingContext2D::fontProxy const):
     19        (WebCore::CanvasRenderingContext2D::drawTextInternal):
     20        * html/canvas/CanvasRenderingContext2D.h:
     21        * html/canvas/CanvasRenderingContext2DBase.cpp:
     22        (WebCore::CanvasRenderingContext2DBase::font const):
     23        (WebCore::toCanvasTextAlign):
     24        (WebCore::fromCanvasTextAlign):
     25        (WebCore::CanvasRenderingContext2DBase::textAlign const):
     26        (WebCore::CanvasRenderingContext2DBase::setTextAlign):
     27        (WebCore::toCanvasTextBaseline):
     28        (WebCore::fromCanvasTextBaseline):
     29        (WebCore::CanvasRenderingContext2DBase::textBaseline const):
     30        (WebCore::CanvasRenderingContext2DBase::setTextBaseline):
     31        (WebCore::CanvasRenderingContext2DBase::setDirection):
     32        (WebCore::CanvasRenderingContext2DBase::canDrawTextWithParams):
     33        (WebCore::CanvasRenderingContext2DBase::normalizeSpaces):
     34        (WebCore::CanvasRenderingContext2DBase::drawText):
     35        (WebCore::CanvasRenderingContext2DBase::drawTextUnchecked):
     36        (WebCore::CanvasRenderingContext2DBase::measureTextInternal):
     37        (WebCore::CanvasRenderingContext2DBase::textOffset):
     38        * html/canvas/CanvasRenderingContext2DBase.h:
     39        (WebCore::CanvasRenderingContext2DBase::fontProxy):
     40        * html/canvas/OffscreenCanvasRenderingContext2D.cpp:
     41        (WebCore::OffscreenCanvasRenderingContext2D::setFont):
     42        (WebCore::OffscreenCanvasRenderingContext2D::direction const):
     43        (WebCore::OffscreenCanvasRenderingContext2D::fontProxy const):
     44        (WebCore::OffscreenCanvasRenderingContext2D::fillText):
     45        (WebCore::OffscreenCanvasRenderingContext2D::strokeText):
     46        (WebCore::OffscreenCanvasRenderingContext2D::measureText):
     47        * html/canvas/OffscreenCanvasRenderingContext2D.h:
     48        * html/canvas/OffscreenCanvasRenderingContext2D.idl:
     49
    1502020-11-20  Youenn Fablet  <youenn@apple.com>
    251
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r269957 r270102  
    9999}
    100100
    101 String CanvasRenderingContext2D::font() const
    102 {
    103     if (!state().font.realized())
    104         return DefaultFont;
    105 
    106     StringBuilder serializedFont;
    107     const auto& fontDescription = state().font.fontDescription();
    108 
    109     if (fontDescription.italic())
    110         serializedFont.appendLiteral("italic ");
    111     if (fontDescription.variantCaps() == FontVariantCaps::Small)
    112         serializedFont.appendLiteral("small-caps ");
    113 
    114     serializedFont.appendNumber(fontDescription.computedPixelSize());
    115     serializedFont.appendLiteral("px");
    116 
    117     for (unsigned i = 0; i < fontDescription.familyCount(); ++i) {
    118         if (i)
    119             serializedFont.append(',');
    120 
    121         // FIXME: We should append family directly to serializedFont rather than building a temporary string.
    122         String family = fontDescription.familyAt(i);
    123         if (family.startsWith("-webkit-"))
    124             family = family.substring(8);
    125         if (family.contains(' '))
    126             family = makeString('"', family, '"');
    127 
    128         serializedFont.append(' ', family);
    129     }
    130 
    131     return serializedFont.toString();
    132 }
    133 
    134101void CanvasRenderingContext2D::setFont(const String& newFont)
    135102{
     
    167134    if (auto fontStyle = Style::resolveForFontRaw(*fontRaw, WTFMove(fontDescription), document))
    168135        modifiableState().font.initialize(document.fontSelector(), *fontStyle);
    169 }
    170 
    171 static CanvasTextAlign toCanvasTextAlign(TextAlign textAlign)
    172 {
    173     switch (textAlign) {
    174     case StartTextAlign:
    175         return CanvasTextAlign::Start;
    176     case EndTextAlign:
    177         return CanvasTextAlign::End;
    178     case LeftTextAlign:
    179         return CanvasTextAlign::Left;
    180     case RightTextAlign:
    181         return CanvasTextAlign::Right;
    182     case CenterTextAlign:
    183         return CanvasTextAlign::Center;
    184     }
    185 
    186     ASSERT_NOT_REACHED();
    187     return CanvasTextAlign::Start;
    188 }
    189 
    190 static TextAlign fromCanvasTextAlign(CanvasTextAlign canvasTextAlign)
    191 {
    192     switch (canvasTextAlign) {
    193     case CanvasTextAlign::Start:
    194         return StartTextAlign;
    195     case CanvasTextAlign::End:
    196         return EndTextAlign;
    197     case CanvasTextAlign::Left:
    198         return LeftTextAlign;
    199     case CanvasTextAlign::Right:
    200         return RightTextAlign;
    201     case CanvasTextAlign::Center:
    202         return CenterTextAlign;
    203     }
    204 
    205     ASSERT_NOT_REACHED();
    206     return StartTextAlign;
    207 }
    208 
    209 CanvasTextAlign CanvasRenderingContext2D::textAlign() const
    210 {
    211     return toCanvasTextAlign(state().textAlign);
    212 }
    213 
    214 void CanvasRenderingContext2D::setTextAlign(CanvasTextAlign canvasTextAlign)
    215 {
    216     auto textAlign = fromCanvasTextAlign(canvasTextAlign);
    217     if (state().textAlign == textAlign)
    218         return;
    219     realizeSaves();
    220     modifiableState().textAlign = textAlign;
    221 }
    222 
    223 static CanvasTextBaseline toCanvasTextBaseline(TextBaseline textBaseline)
    224 {
    225     switch (textBaseline) {
    226     case TopTextBaseline:
    227         return CanvasTextBaseline::Top;
    228     case HangingTextBaseline:
    229         return CanvasTextBaseline::Hanging;
    230     case MiddleTextBaseline:
    231         return CanvasTextBaseline::Middle;
    232     case AlphabeticTextBaseline:
    233         return CanvasTextBaseline::Alphabetic;
    234     case IdeographicTextBaseline:
    235         return CanvasTextBaseline::Ideographic;
    236     case BottomTextBaseline:
    237         return CanvasTextBaseline::Bottom;
    238     }
    239 
    240     ASSERT_NOT_REACHED();
    241     return CanvasTextBaseline::Top;
    242 }
    243 
    244 static TextBaseline fromCanvasTextBaseline(CanvasTextBaseline canvasTextBaseline)
    245 {
    246     switch (canvasTextBaseline) {
    247     case CanvasTextBaseline::Top:
    248         return TopTextBaseline;
    249     case CanvasTextBaseline::Hanging:
    250         return HangingTextBaseline;
    251     case CanvasTextBaseline::Middle:
    252         return MiddleTextBaseline;
    253     case CanvasTextBaseline::Alphabetic:
    254         return AlphabeticTextBaseline;
    255     case CanvasTextBaseline::Ideographic:
    256         return IdeographicTextBaseline;
    257     case CanvasTextBaseline::Bottom:
    258         return BottomTextBaseline;
    259     }
    260 
    261     ASSERT_NOT_REACHED();
    262     return TopTextBaseline;
    263 }
    264 
    265 CanvasTextBaseline CanvasRenderingContext2D::textBaseline() const
    266 {
    267     return toCanvasTextBaseline(state().textBaseline);
    268 }
    269 
    270 void CanvasRenderingContext2D::setTextBaseline(CanvasTextBaseline canvasTextBaseline)
    271 {
    272     auto textBaseline = fromCanvasTextBaseline(canvasTextBaseline);
    273     if (state().textBaseline == textBaseline)
    274         return;
    275     realizeSaves();
    276     modifiableState().textBaseline = textBaseline;
    277136}
    278137
     
    301160}
    302161
    303 void CanvasRenderingContext2D::setDirection(CanvasDirection direction)
    304 {
    305     if (state().direction == direction)
    306         return;
    307 
    308     realizeSaves();
    309     modifiableState().direction = direction;
    310 }
    311 
    312162void CanvasRenderingContext2D::fillText(const String& text, float x, float y, Optional<float> maxWidth)
    313163{
     
    331181}
    332182
    333 static void normalizeSpaces(String& text)
    334 {
    335     size_t i = text.find(isSpaceThatNeedsReplacing);
    336     if (i == notFound)
    337         return;
    338 
    339     unsigned textLength = text.length();
    340     Vector<UChar> charVector(textLength);
    341     StringView(text).getCharactersWithUpconvert(charVector.data());
    342 
    343     charVector[i++] = ' ';
    344 
    345     for (; i < textLength; ++i) {
    346         if (isSpaceThatNeedsReplacing(charVector[i]))
    347             charVector[i] = ' ';
    348     }
    349     text = String::adopt(WTFMove(charVector));
    350 }
    351 
    352183Ref<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
    353184{
     
    357188        ResourceLoadObserver::shared().logCanvasRead(canvas.document());
    358189    }
    359    
     190
    360191    Ref<TextMetrics> metrics = TextMetrics::create();
    361192
     
    368199
    369200    TextRun textRun(normalizedText, 0, 0, AllowRightExpansion, direction, override, true);
    370     auto& font = fontProxy();
    371     auto& fontMetrics = font.fontMetrics();
    372 
    373     GlyphOverflow glyphOverflow;
    374     glyphOverflow.computeBounds = true;
    375     float fontWidth = font.width(textRun, &glyphOverflow);
    376     metrics->setWidth(fontWidth);
    377 
    378     FloatPoint offset = textOffset(fontWidth, direction);
    379 
    380     metrics->setActualBoundingBoxAscent(glyphOverflow.top - offset.y());
    381     metrics->setActualBoundingBoxDescent(glyphOverflow.bottom + offset.y());
    382     metrics->setFontBoundingBoxAscent(fontMetrics.ascent() - offset.y());
    383     metrics->setFontBoundingBoxDescent(fontMetrics.descent() + offset.y());
    384     metrics->setEmHeightAscent(fontMetrics.ascent() - offset.y());
    385     metrics->setEmHeightDescent(fontMetrics.descent() + offset.y());
    386     metrics->setHangingBaseline(fontMetrics.ascent() - offset.y());
    387     metrics->setAlphabeticBaseline(-offset.y());
    388     metrics->setIdeographicBaseline(-fontMetrics.descent() - offset.y());
    389 
    390     metrics->setActualBoundingBoxLeft(glyphOverflow.left - offset.x());
    391     metrics->setActualBoundingBoxRight(fontWidth + glyphOverflow.right + offset.x());
    392 
    393     return metrics;
    394 }
    395 
    396 auto CanvasRenderingContext2D::fontProxy() -> const FontProxy& {
     201    return measureTextInternal(textRun);
     202}
     203
     204auto CanvasRenderingContext2D::fontProxy() -> const FontProxy* {
    397205    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
    398206    canvas.document().updateStyleIfNeeded();
    399207    if (!state().font.realized())
    400208        setFont(state().unparsedFont);
    401     return state().font;
    402 }
    403 
    404 FloatPoint CanvasRenderingContext2D::textOffset(float width, TextDirection direction)
    405 {
    406     auto& fontMetrics = fontProxy().fontMetrics();
    407     FloatPoint offset;
    408 
    409     switch (state().textBaseline) {
    410     case TopTextBaseline:
    411     case HangingTextBaseline:
    412         offset.setY(fontMetrics.ascent());
    413         break;
    414     case BottomTextBaseline:
    415     case IdeographicTextBaseline:
    416         offset.setY(-fontMetrics.descent());
    417         break;
    418     case MiddleTextBaseline:
    419         offset.setY(fontMetrics.height() / 2 - fontMetrics.descent());
    420         break;
    421     case AlphabeticTextBaseline:
    422     default:
    423         break;
    424     }
    425 
    426     bool isRTL = direction == TextDirection::RTL;
    427     auto align = state().textAlign;
    428     if (align == StartTextAlign)
    429         align = isRTL ? RightTextAlign : LeftTextAlign;
    430     else if (align == EndTextAlign)
    431         align = isRTL ? LeftTextAlign : RightTextAlign;
    432 
    433     switch (align) {
    434     case CenterTextAlign:
    435         offset.setX(-width / 2);
    436         break;
    437     case RightTextAlign:
    438         offset.setX(-width);
    439         break;
    440     default:
    441         break;
    442     }
    443     return offset;
     209    return &state().font;
    444210}
    445211
     
    448214    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
    449215        ResourceLoadObserver::shared().logCanvasWriteOrMeasure(this->canvas().document(), text);
    450    
    451     auto& fontProxy = this->fontProxy();
    452     const auto& fontMetrics = fontProxy.fontMetrics();
    453 
    454     auto* c = drawingContext();
    455     if (!c)
    456         return;
    457     if (!state().hasInvertibleTransform)
    458         return;
    459     if (!std::isfinite(x) | !std::isfinite(y))
    460         return;
    461     if (maxWidth && (!std::isfinite(maxWidth.value()) || maxWidth.value() <= 0))
    462         return;
    463 
    464     // If gradient size is zero, then paint nothing.
    465     auto gradient = c->strokeGradient();
    466     if (!fill && gradient && gradient->isZeroSize())
    467         return;
    468 
    469     gradient = c->fillGradient();
    470     if (fill && gradient && gradient->isZeroSize())
     216
     217    if (!canDrawTextWithParams(x, y, fill, maxWidth))
    471218        return;
    472219
    473220    String normalizedText = text;
    474221    normalizeSpaces(normalizedText);
    475 
    476     // FIXME: Need to turn off font smoothing.
    477222
    478223    const RenderStyle* computedStyle;
     
    481226
    482227    TextRun textRun(normalizedText, 0, 0, AllowRightExpansion, direction, override, true);
    483     float fontWidth = fontProxy.width(textRun);
    484     bool useMaxWidth = maxWidth && maxWidth.value() < fontWidth;
    485     float width = useMaxWidth ? maxWidth.value() : fontWidth;
    486     FloatPoint location(x, y);
    487     location += textOffset(width, direction);
    488 
    489     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
    490     FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
    491         width + fontMetrics.height(), fontMetrics.lineSpacing());
    492     if (!fill)
    493         inflateStrokeRect(textRect);
    494 
    495 #if USE(CG)
    496     const CanvasStyle& drawStyle = fill ? state().fillStyle : state().strokeStyle;
    497     if (drawStyle.canvasGradient() || drawStyle.canvasPattern()) {
    498         IntRect maskRect = enclosingIntRect(textRect);
    499 
    500         // If we have a shadow, we need to draw it before the mask operation.
    501         // Follow a procedure similar to paintTextWithShadows in TextPainter.
    502 
    503         if (shouldDrawShadows()) {
    504             GraphicsContextStateSaver stateSaver(*c);
    505 
    506             FloatSize offset(0, 2 * maskRect.height());
    507 
    508             FloatSize shadowOffset;
    509             float shadowRadius;
    510             Color shadowColor;
    511             c->getShadow(shadowOffset, shadowRadius, shadowColor);
    512 
    513             FloatRect shadowRect(maskRect);
    514             shadowRect.inflate(shadowRadius * 1.4);
    515             shadowRect.move(shadowOffset * -1);
    516             c->clip(shadowRect);
    517 
    518             shadowOffset += offset;
    519 
    520             c->setLegacyShadow(shadowOffset, shadowRadius, shadowColor);
    521 
    522             if (fill)
    523                 c->setFillColor(Color::black);
    524             else
    525                 c->setStrokeColor(Color::black);
    526 
    527             fontProxy.drawBidiText(*c, textRun, location + offset, FontCascade::UseFallbackIfFontNotReady);
    528         }
    529 
    530         GraphicsContextStateSaver stateSaver(*c);
    531 
    532         auto paintMaskImage = [&] (GraphicsContext& maskImageContext) {
    533             if (fill)
    534                 maskImageContext.setFillColor(Color::black);
    535             else {
    536                 maskImageContext.setStrokeColor(Color::black);
    537                 maskImageContext.setStrokeThickness(c->strokeThickness());
    538             }
    539 
    540             maskImageContext.setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
    541 
    542             if (useMaxWidth) {
    543                 maskImageContext.translate(location - maskRect.location());
    544                 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
    545                 maskImageContext.scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
    546                 fontProxy.drawBidiText(maskImageContext, textRun, FloatPoint(0, 0), FontCascade::UseFallbackIfFontNotReady);
    547             } else {
    548                 maskImageContext.translate(-maskRect.location());
    549                 fontProxy.drawBidiText(maskImageContext, textRun, location, FontCascade::UseFallbackIfFontNotReady);
    550             }
    551         };
    552 
    553         if (c->clipToDrawingCommands(maskRect, ColorSpace::SRGB, WTFMove(paintMaskImage)) == GraphicsContext::ClipToDrawingCommandsResult::FailedToCreateImageBuffer)
    554             return;
    555 
    556         drawStyle.applyFillColor(*c);
    557         c->fillRect(maskRect);
    558         return;
    559     }
    560 #endif
    561 
    562     c->setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
    563 
    564     GraphicsContextStateSaver stateSaver(*c);
    565     if (useMaxWidth) {
    566         c->translate(location);
    567         // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
    568         c->scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
    569         location = FloatPoint();
    570     }
    571 
    572     if (isFullCanvasCompositeMode(state().globalComposite)) {
    573         beginCompositeLayer();
    574         fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
    575         endCompositeLayer();
    576         didDrawEntireCanvas();
    577     } else if (state().globalComposite == CompositeOperator::Copy) {
    578         clearCanvas();
    579         fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
    580         didDrawEntireCanvas();
    581     } else {
    582         fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
    583         didDraw(textRect);
    584     }
     228    drawTextUnchecked(textRun, x, y, fill, maxWidth);
    585229}
    586230
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h

    r246285 r270102  
    2929#include "CanvasTextAlign.h"
    3030#include "CanvasTextBaseline.h"
    31 #include "FontCascade.h"
    32 #include "FontSelectorClient.h"
    3331#include "HTMLCanvasElement.h"
    3432#include <memory>
     
    5250    float webkitBackingStorePixelRatio() const { return 1; }
    5351
    54     String font() const;
    5552    void setFont(const String&);
    5653
    57     CanvasTextAlign textAlign() const;
    58     void setTextAlign(CanvasTextAlign);
    59 
    60     CanvasTextBaseline textBaseline() const;
    61     void setTextBaseline(CanvasTextBaseline);
    62 
    6354    CanvasDirection direction() const;
    64     void setDirection(CanvasDirection);
    6555
    6656    void fillText(const String& text, float x, float y, Optional<float> maxWidth = WTF::nullopt);
     
    7363    CanvasRenderingContext2D(CanvasBase&, bool usesCSSCompatibilityParseMode);
    7464
    75     // The relationship between FontCascade and CanvasRenderingContext2D::FontProxy must hold certain invariants.
    76     // Therefore, all font operations must pass through the State.
    77     const FontProxy& fontProxy();
     65    const FontProxy* fontProxy() final;
    7866
    7967    void drawTextInternal(const String& text, float x, float y, bool fill, Optional<float> maxWidth = WTF::nullopt);
     
    8270
    8371    TextDirection toTextDirection(CanvasRenderingContext2DBase::Direction, const RenderStyle** computedStyle = nullptr) const;
    84 
    85     FloatPoint textOffset(float width, TextDirection);
    8672};
    8773
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp

    r269614 r270102  
    22532253}
    22542254
     2255String CanvasRenderingContext2DBase::font() const
     2256{
     2257    if (!state().font.realized())
     2258        return DefaultFont;
     2259
     2260    StringBuilder serializedFont;
     2261    const auto& fontDescription = state().font.fontDescription();
     2262
     2263    if (fontDescription.italic())
     2264        serializedFont.appendLiteral("italic ");
     2265    if (fontDescription.variantCaps() == FontVariantCaps::Small)
     2266        serializedFont.appendLiteral("small-caps ");
     2267
     2268    serializedFont.appendNumber(fontDescription.computedPixelSize());
     2269    serializedFont.appendLiteral("px");
     2270
     2271    for (unsigned i = 0; i < fontDescription.familyCount(); ++i) {
     2272        if (i)
     2273            serializedFont.append(',');
     2274
     2275        // FIXME: We should append family directly to serializedFont rather than building a temporary string.
     2276        String family = fontDescription.familyAt(i);
     2277        if (family.startsWith("-webkit-"))
     2278            family = family.substring(8);
     2279        if (family.contains(' '))
     2280            family = makeString('"', family, '"');
     2281
     2282        serializedFont.append(' ', family);
     2283    }
     2284
     2285    return serializedFont.toString();
     2286}
     2287
     2288static CanvasTextAlign toCanvasTextAlign(TextAlign textAlign)
     2289{
     2290    switch (textAlign) {
     2291    case StartTextAlign:
     2292        return CanvasTextAlign::Start;
     2293    case EndTextAlign:
     2294        return CanvasTextAlign::End;
     2295    case LeftTextAlign:
     2296        return CanvasTextAlign::Left;
     2297    case RightTextAlign:
     2298        return CanvasTextAlign::Right;
     2299    case CenterTextAlign:
     2300        return CanvasTextAlign::Center;
     2301    }
     2302
     2303    ASSERT_NOT_REACHED();
     2304    return CanvasTextAlign::Start;
     2305}
     2306
     2307static TextAlign fromCanvasTextAlign(CanvasTextAlign canvasTextAlign)
     2308{
     2309    switch (canvasTextAlign) {
     2310    case CanvasTextAlign::Start:
     2311        return StartTextAlign;
     2312    case CanvasTextAlign::End:
     2313        return EndTextAlign;
     2314    case CanvasTextAlign::Left:
     2315        return LeftTextAlign;
     2316    case CanvasTextAlign::Right:
     2317        return RightTextAlign;
     2318    case CanvasTextAlign::Center:
     2319        return CenterTextAlign;
     2320    }
     2321
     2322    ASSERT_NOT_REACHED();
     2323    return StartTextAlign;
     2324}
     2325
     2326CanvasTextAlign CanvasRenderingContext2DBase::textAlign() const
     2327{
     2328    return toCanvasTextAlign(state().textAlign);
     2329}
     2330
     2331void CanvasRenderingContext2DBase::setTextAlign(CanvasTextAlign canvasTextAlign)
     2332{
     2333    auto textAlign = fromCanvasTextAlign(canvasTextAlign);
     2334    if (state().textAlign == textAlign)
     2335        return;
     2336    realizeSaves();
     2337    modifiableState().textAlign = textAlign;
     2338}
     2339
     2340static CanvasTextBaseline toCanvasTextBaseline(TextBaseline textBaseline)
     2341{
     2342    switch (textBaseline) {
     2343    case TopTextBaseline:
     2344        return CanvasTextBaseline::Top;
     2345    case HangingTextBaseline:
     2346        return CanvasTextBaseline::Hanging;
     2347    case MiddleTextBaseline:
     2348        return CanvasTextBaseline::Middle;
     2349    case AlphabeticTextBaseline:
     2350        return CanvasTextBaseline::Alphabetic;
     2351    case IdeographicTextBaseline:
     2352        return CanvasTextBaseline::Ideographic;
     2353    case BottomTextBaseline:
     2354        return CanvasTextBaseline::Bottom;
     2355    }
     2356
     2357    ASSERT_NOT_REACHED();
     2358    return CanvasTextBaseline::Top;
     2359}
     2360
     2361static TextBaseline fromCanvasTextBaseline(CanvasTextBaseline canvasTextBaseline)
     2362{
     2363    switch (canvasTextBaseline) {
     2364    case CanvasTextBaseline::Top:
     2365        return TopTextBaseline;
     2366    case CanvasTextBaseline::Hanging:
     2367        return HangingTextBaseline;
     2368    case CanvasTextBaseline::Middle:
     2369        return MiddleTextBaseline;
     2370    case CanvasTextBaseline::Alphabetic:
     2371        return AlphabeticTextBaseline;
     2372    case CanvasTextBaseline::Ideographic:
     2373        return IdeographicTextBaseline;
     2374    case CanvasTextBaseline::Bottom:
     2375        return BottomTextBaseline;
     2376    }
     2377
     2378    ASSERT_NOT_REACHED();
     2379    return TopTextBaseline;
     2380}
     2381
     2382CanvasTextBaseline CanvasRenderingContext2DBase::textBaseline() const
     2383{
     2384    return toCanvasTextBaseline(state().textBaseline);
     2385}
     2386
     2387void CanvasRenderingContext2DBase::setTextBaseline(CanvasTextBaseline canvasTextBaseline)
     2388{
     2389    auto textBaseline = fromCanvasTextBaseline(canvasTextBaseline);
     2390    if (state().textBaseline == textBaseline)
     2391        return;
     2392    realizeSaves();
     2393    modifiableState().textBaseline = textBaseline;
     2394}
     2395
     2396void CanvasRenderingContext2DBase::setDirection(Direction direction)
     2397{
     2398    if (state().direction == direction)
     2399        return;
     2400
     2401    realizeSaves();
     2402    modifiableState().direction = direction;
     2403}
     2404
     2405bool CanvasRenderingContext2DBase::canDrawTextWithParams(float x, float y, bool fill, Optional<float> maxWidth)
     2406{
     2407    auto* c = drawingContext();
     2408    if (!c)
     2409        return false;
     2410    if (!this->fontProxy()->realized())
     2411        return false;
     2412    if (!state().hasInvertibleTransform)
     2413        return false;
     2414    if (!std::isfinite(x) | !std::isfinite(y))
     2415        return false;
     2416    if (maxWidth && (!std::isfinite(maxWidth.value()) || maxWidth.value() <= 0))
     2417        return false;
     2418
     2419    // If gradient size is zero, nothing would be painted.
     2420    auto gradient = c->strokeGradient();
     2421    if (!fill && gradient && gradient->isZeroSize())
     2422        return false;
     2423
     2424    gradient = c->fillGradient();
     2425    if (fill && gradient && gradient->isZeroSize())
     2426        return false;
     2427
     2428    return true;
     2429}
     2430
     2431void CanvasRenderingContext2DBase::normalizeSpaces(String& text)
     2432{
     2433    size_t i = text.find(isSpaceThatNeedsReplacing);
     2434    if (i == notFound)
     2435        return;
     2436
     2437    unsigned textLength = text.length();
     2438    Vector<UChar> charVector(textLength);
     2439    StringView(text).getCharactersWithUpconvert(charVector.data());
     2440
     2441    charVector[i++] = ' ';
     2442
     2443    for (; i < textLength; ++i) {
     2444        if (isSpaceThatNeedsReplacing(charVector[i]))
     2445            charVector[i] = ' ';
     2446    }
     2447    text = String::adopt(WTFMove(charVector));
     2448}
     2449
     2450void CanvasRenderingContext2DBase::drawText(const String& text, float x, float y, bool fill, Optional<float> maxWidth)
     2451{
     2452    if (!canDrawTextWithParams(x, y, fill, maxWidth))
     2453        return;
     2454
     2455    String normalizedText = text;
     2456    normalizeSpaces(normalizedText);
     2457
     2458    auto direction = (state().direction == Direction::Rtl) ? TextDirection::RTL : TextDirection::LTR;
     2459    TextRun textRun(normalizedText, 0, 0, AllowRightExpansion, direction, false, true);
     2460
     2461    drawTextUnchecked(textRun, x, y, fill, maxWidth);
     2462}
     2463
     2464void CanvasRenderingContext2DBase::drawTextUnchecked(const TextRun& textRun, float x, float y, bool fill, Optional<float> maxWidth)
     2465{
     2466    auto* c = drawingContext();
     2467    auto& fontProxy = *this->fontProxy();
     2468    const auto& fontMetrics = fontProxy.fontMetrics();
     2469
     2470    // FIXME: Need to turn off font smoothing.
     2471
     2472    float fontWidth = fontProxy.width(textRun);
     2473    bool useMaxWidth = maxWidth && maxWidth.value() < fontWidth;
     2474    float width = useMaxWidth ? maxWidth.value() : fontWidth;
     2475    FloatPoint location(x, y);
     2476    location += textOffset(width, textRun.direction());
     2477
     2478    // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
     2479    FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
     2480        width + fontMetrics.height(), fontMetrics.lineSpacing());
     2481    if (!fill)
     2482        inflateStrokeRect(textRect);
     2483
     2484#if USE(CG)
     2485    const CanvasStyle& drawStyle = fill ? state().fillStyle : state().strokeStyle;
     2486    if (drawStyle.canvasGradient() || drawStyle.canvasPattern()) {
     2487        IntRect maskRect = enclosingIntRect(textRect);
     2488
     2489        // If we have a shadow, we need to draw it before the mask operation.
     2490        // Follow a procedure similar to paintTextWithShadows in TextPainter.
     2491
     2492        if (shouldDrawShadows()) {
     2493            GraphicsContextStateSaver stateSaver(*c);
     2494
     2495            FloatSize offset(0, 2 * maskRect.height());
     2496
     2497            FloatSize shadowOffset;
     2498            float shadowRadius;
     2499            Color shadowColor;
     2500            c->getShadow(shadowOffset, shadowRadius, shadowColor);
     2501
     2502            FloatRect shadowRect(maskRect);
     2503            shadowRect.inflate(shadowRadius * 1.4);
     2504            shadowRect.move(shadowOffset * -1);
     2505            c->clip(shadowRect);
     2506
     2507            shadowOffset += offset;
     2508
     2509            c->setLegacyShadow(shadowOffset, shadowRadius, shadowColor);
     2510
     2511            if (fill)
     2512                c->setFillColor(Color::black);
     2513            else
     2514                c->setStrokeColor(Color::black);
     2515
     2516            fontProxy.drawBidiText(*c, textRun, location + offset, FontCascade::UseFallbackIfFontNotReady);
     2517        }
     2518
     2519        GraphicsContextStateSaver stateSaver(*c);
     2520
     2521        auto paintMaskImage = [&] (GraphicsContext& maskImageContext) {
     2522            if (fill)
     2523                maskImageContext.setFillColor(Color::black);
     2524            else {
     2525                maskImageContext.setStrokeColor(Color::black);
     2526                maskImageContext.setStrokeThickness(c->strokeThickness());
     2527            }
     2528
     2529            maskImageContext.setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
     2530
     2531            if (useMaxWidth) {
     2532                maskImageContext.translate(location - maskRect.location());
     2533                // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
     2534                maskImageContext.scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
     2535                fontProxy.drawBidiText(maskImageContext, textRun, FloatPoint(0, 0), FontCascade::UseFallbackIfFontNotReady);
     2536            } else {
     2537                maskImageContext.translate(-maskRect.location());
     2538                fontProxy.drawBidiText(maskImageContext, textRun, location, FontCascade::UseFallbackIfFontNotReady);
     2539            }
     2540        };
     2541
     2542        if (c->clipToDrawingCommands(maskRect, ColorSpace::SRGB, WTFMove(paintMaskImage)) == GraphicsContext::ClipToDrawingCommandsResult::FailedToCreateImageBuffer)
     2543            return;
     2544
     2545        drawStyle.applyFillColor(*c);
     2546        c->fillRect(maskRect);
     2547        return;
     2548    }
     2549#endif
     2550
     2551    c->setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
     2552
     2553    GraphicsContextStateSaver stateSaver(*c);
     2554    if (useMaxWidth) {
     2555        c->translate(location);
     2556        // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
     2557        c->scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
     2558        location = FloatPoint();
     2559    }
     2560
     2561    if (isFullCanvasCompositeMode(state().globalComposite)) {
     2562        beginCompositeLayer();
     2563        fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
     2564        endCompositeLayer();
     2565        didDrawEntireCanvas();
     2566    } else if (state().globalComposite == CompositeOperator::Copy) {
     2567        clearCanvas();
     2568        fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
     2569        didDrawEntireCanvas();
     2570    } else {
     2571        fontProxy.drawBidiText(*c, textRun, location, FontCascade::UseFallbackIfFontNotReady);
     2572        didDraw(textRect);
     2573    }
     2574}
     2575
     2576Ref<TextMetrics> CanvasRenderingContext2DBase::measureTextInternal(const String& text)
     2577{
     2578    String normalizedText = text;
     2579    normalizeSpaces(normalizedText);
     2580
     2581    auto direction = (state().direction == Direction::Rtl) ? TextDirection::RTL : TextDirection::LTR;
     2582    TextRun textRun(normalizedText, 0, 0, AllowRightExpansion, direction, false, true);
     2583
     2584    return measureTextInternal(textRun);
     2585}
     2586
     2587Ref<TextMetrics> CanvasRenderingContext2DBase::measureTextInternal(const TextRun& textRun)
     2588{
     2589    Ref<TextMetrics> metrics = TextMetrics::create();
     2590
     2591    auto& font = *fontProxy();
     2592    auto& fontMetrics = font.fontMetrics();
     2593
     2594    GlyphOverflow glyphOverflow;
     2595    glyphOverflow.computeBounds = true;
     2596    float fontWidth = font.width(textRun, &glyphOverflow);
     2597    metrics->setWidth(fontWidth);
     2598
     2599    FloatPoint offset = textOffset(fontWidth, textRun.direction());
     2600
     2601    metrics->setActualBoundingBoxAscent(glyphOverflow.top - offset.y());
     2602    metrics->setActualBoundingBoxDescent(glyphOverflow.bottom + offset.y());
     2603    metrics->setFontBoundingBoxAscent(fontMetrics.ascent() - offset.y());
     2604    metrics->setFontBoundingBoxDescent(fontMetrics.descent() + offset.y());
     2605    metrics->setEmHeightAscent(fontMetrics.ascent() - offset.y());
     2606    metrics->setEmHeightDescent(fontMetrics.descent() + offset.y());
     2607    metrics->setHangingBaseline(fontMetrics.ascent() - offset.y());
     2608    metrics->setAlphabeticBaseline(-offset.y());
     2609    metrics->setIdeographicBaseline(-fontMetrics.descent() - offset.y());
     2610
     2611    metrics->setActualBoundingBoxLeft(glyphOverflow.left - offset.x());
     2612    metrics->setActualBoundingBoxRight(fontWidth + glyphOverflow.right + offset.x());
     2613
     2614    return metrics;
     2615}
     2616
     2617FloatPoint CanvasRenderingContext2DBase::textOffset(float width, TextDirection direction)
     2618{
     2619    auto& fontMetrics = fontProxy()->fontMetrics();
     2620    FloatPoint offset;
     2621
     2622    switch (state().textBaseline) {
     2623    case TopTextBaseline:
     2624    case HangingTextBaseline:
     2625        offset.setY(fontMetrics.ascent());
     2626        break;
     2627    case BottomTextBaseline:
     2628    case IdeographicTextBaseline:
     2629        offset.setY(-fontMetrics.descent());
     2630        break;
     2631    case MiddleTextBaseline:
     2632        offset.setY(fontMetrics.height() / 2 - fontMetrics.descent());
     2633        break;
     2634    case AlphabeticTextBaseline:
     2635    default:
     2636        break;
     2637    }
     2638
     2639    bool isRTL = direction == TextDirection::RTL;
     2640    auto align = state().textAlign;
     2641    if (align == StartTextAlign)
     2642        align = isRTL ? RightTextAlign : LeftTextAlign;
     2643    else if (align == EndTextAlign)
     2644        align = isRTL ? LeftTextAlign : RightTextAlign;
     2645
     2646    switch (align) {
     2647    case CenterTextAlign:
     2648        offset.setX(-width / 2);
     2649        break;
     2650    case RightTextAlign:
     2651        offset.setX(-width);
     2652        break;
     2653    default:
     2654        break;
     2655    }
     2656    return offset;
     2657}
     2658
    22552659} // namespace WebCore
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h

    r269331 r270102  
    220220    void setUsesDisplayListDrawing(bool flag) { m_usesDisplayListDrawing = flag; };
    221221
     222    String font() const;
     223
     224    CanvasTextAlign textAlign() const;
     225    void setTextAlign(CanvasTextAlign);
     226
     227    CanvasTextBaseline textBaseline() const;
     228    void setTextBaseline(CanvasTextBaseline);
     229
    222230    using Direction = CanvasDirection;
     231    void setDirection(Direction);
    223232
    224233    class FontProxy : public FontSelectorClient {
     
    372381    bool hasInvertibleTransform() const override { return state().hasInvertibleTransform; }
    373382
     383    // The relationship between FontCascade and CanvasRenderingContext2D::FontProxy must hold certain invariants.
     384    // Therefore, all font operations must pass through the proxy.
     385    virtual const FontProxy* fontProxy() { return nullptr; }
     386
     387    static void normalizeSpaces(String&);
     388    bool canDrawTextWithParams(float x, float y, bool fill, Optional<float> maxWidth = WTF::nullopt);
     389    void drawText(const String& text, float x, float y, bool fill, Optional<float> maxWidth = WTF::nullopt);
     390    void drawTextUnchecked(const TextRun&, float x, float y, bool fill, Optional<float> maxWidth = WTF::nullopt);
     391    Ref<TextMetrics> measureTextInternal(const String& text);
     392    Ref<TextMetrics> measureTextInternal(const TextRun&);
     393
     394    FloatPoint textOffset(float width, TextDirection);
     395
    374396    static const unsigned MaxSaveCount = 1024 * 16;
    375397    Vector<State, 1> m_stateStack;
  • trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp

    r265543 r270102  
    3636#if ENABLE(OFFSCREEN_CANVAS)
    3737
     38#include "CSSFontSelector.h"
     39#include "CSSParser.h"
     40#include "CSSPropertyParserHelpers.h"
     41#include "Document.h"
     42#include "RenderStyle.h"
     43#include "StyleResolveForFontRaw.h"
     44#include "TextMetrics.h"
    3845#include <wtf/IsoMallocInlines.h>
    3946
     
    5461}
    5562
     63void OffscreenCanvasRenderingContext2D::setFont(const String& newFont)
     64{
     65    auto& context = *canvasBase().scriptExecutionContext();
     66    if (!is<Document>(context))
     67        return;
     68
     69    if (newFont.isEmpty())
     70        return;
     71
     72    if (newFont == state().unparsedFont && state().font.realized())
     73        return;
     74
     75    // According to http://lists.w3.org/Archives/Public/public-html/2009Jul/0947.html,
     76    // the "inherit" and "initial" values must be ignored. parseFontWorkerSafe() ignores these.
     77    auto fontRaw = CSSParser::parseFontWorkerSafe(newFont, strictToCSSParserMode(!m_usesCSSCompatibilityParseMode));
     78    if (!fontRaw)
     79        return;
     80
     81    // The parse succeeded.
     82    String newFontSafeCopy(newFont); // Create a string copy since newFont can be deleted inside realizeSaves.
     83    realizeSaves();
     84    modifiableState().unparsedFont = newFontSafeCopy;
     85
     86    // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
     87    // relative to the default font.
     88    FontCascadeDescription fontDescription;
     89    fontDescription.setOneFamily(DefaultFontFamily);
     90    fontDescription.setSpecifiedSize(DefaultFontSize);
     91    fontDescription.setComputedSize(DefaultFontSize);
     92
     93    auto& document = downcast<Document>(context);
     94    auto fontStyle = Style::resolveForFontRaw(*fontRaw, WTFMove(fontDescription), document);
     95
     96    if (fontStyle)
     97        modifiableState().font.initialize(document.fontSelector(), *fontStyle);
     98}
     99
     100CanvasDirection OffscreenCanvasRenderingContext2D::direction() const
     101{
     102    // FIXME: What should we do about inherit here?
     103    switch (state().direction) {
     104    case Direction::Inherit:
     105    case Direction::Ltr:
     106        return Direction::Ltr;
     107    case Direction::Rtl:
     108        return Direction::Rtl;
     109    }
     110    ASSERT_NOT_REACHED();
     111    return Direction::Ltr;
     112}
     113
     114auto OffscreenCanvasRenderingContext2D::fontProxy() -> const FontProxy* {
     115    if (!state().font.realized())
     116        setFont(state().unparsedFont);
     117    return &state().font;
     118}
     119
     120void OffscreenCanvasRenderingContext2D::fillText(const String& text, float x, float y, Optional<float> maxWidth)
     121{
     122    drawText(text, x, y, true, maxWidth);
     123}
     124
     125void OffscreenCanvasRenderingContext2D::strokeText(const String& text, float x, float y, Optional<float> maxWidth)
     126{
     127    drawText(text, x, y, false, maxWidth);
     128}
     129
     130Ref<TextMetrics> OffscreenCanvasRenderingContext2D::measureText(const String& text)
     131{
     132    return measureTextInternal(text);
     133}
     134
    56135} // namespace WebCore
    57136
  • trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h

    r265543 r270102  
    4545
    4646    void commit();
     47
     48    void setFont(const String&);
     49    CanvasDirection direction() const;
     50    void fillText(const String& text, float x, float y, Optional<float> maxWidth = WTF::nullopt);
     51    void strokeText(const String& text, float x, float y, Optional<float> maxWidth = WTF::nullopt);
     52    Ref<TextMetrics> measureText(const String& text);
     53
     54private:
     55    const FontProxy* fontProxy() final;
    4756};
    4857
  • trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl

    r266523 r270102  
    5151OffscreenCanvasRenderingContext2D includes CanvasRect;
    5252OffscreenCanvasRenderingContext2D includes CanvasDrawPath;
     53OffscreenCanvasRenderingContext2D includes CanvasText;
    5354OffscreenCanvasRenderingContext2D includes CanvasDrawImage;
    5455OffscreenCanvasRenderingContext2D includes CanvasImageData;
    5556OffscreenCanvasRenderingContext2D includes CanvasPathDrawingStyles;
     57OffscreenCanvasRenderingContext2D includes CanvasTextDrawingStyles;
    5658OffscreenCanvasRenderingContext2D includes CanvasPath;
Note: See TracChangeset for help on using the changeset viewer.