⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 219970 in webkit


Ignore:
Timestamp:
Jul 26, 2017, 4:53:26 PM (9 years ago)
Author:
commit-queue@webkit.org
Message:

Implement new TextMetrics, returned by canvas measureText()
​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 <Fujii Hironori> 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 <Fujii Hironori> 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.
Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r219968 r219970  
     12017-07-26  Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori  <Hironori.Fujii@sony.com>
     2
     3        Implement new TextMetrics, returned by canvas measureText()
     4        https://bugs.webkit.org/show_bug.cgi?id=82798
     5
     6        Reviewed by Dean Jackson.
     7
     8        Create a test that checks that:
     9             - ascent + descent is greater than zero
     10             - actualBoundingBoxLeft + actualBoundingBoxRight is somewhere
     11               quite close to width
     12             - when baseline is top, emHeightAscent is 0 (respectively
     13               bottom/emHeightDescent)
     14             - when baseline is hanging, hangingBaseline in 0 (respectively
     15               alphabetic and ideographic)
     16             - order of different vertical measures (for example,
     17               emHeightAscent is always higher that alphabeticBaseline)
     18
     19        * fast/canvas/canvas-measureText-2-expected.txt: Added.
     20        * fast/canvas/canvas-measureText-2.html: Added.
     21
    1222017-07-26  Matt Lewis  <jlewis3@apple.com>
    223
  • trunk/Source/WebCore/ChangeLog

    r219964 r219970  
     12017-07-26  Arnaud Renevier  <a.renevier@sisa.samsung.com> and Fujii Hironori  <Hironori.Fujii@sony.com>
     2
     3        Implement new TextMetrics, returned by canvas measureText()
     4        https://bugs.webkit.org/show_bug.cgi?id=82798
     5        <rdar://problem/11159332>
     6
     7        Reviewed by Dean Jackson.
     8
     9        The specification: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-measuretext
     10
     11        Add new attributes to TextMetrics.
     12
     13        Add a new method textOffset() of CanvasRenderingContext2D by
     14        extracting from drawTextInternal() to use the same horizontal and
     15        vertical offsets of a text in both drawTextInternal() and
     16        measureText().
     17
     18        Test: fast/canvas/canvas-measureText-2.html
     19
     20        * html/TextMetrics.h:
     21        (WebCore::TextMetrics::actualBoundingBoxLeft):
     22        (WebCore::TextMetrics::setActualBoundingBoxLeft):
     23        (WebCore::TextMetrics::actualBoundingBoxRight):
     24        (WebCore::TextMetrics::setActualBoundingBoxRight):
     25        (WebCore::TextMetrics::fontBoundingBoxAscent):
     26        (WebCore::TextMetrics::setFontBoundingBoxAscent):
     27        (WebCore::TextMetrics::fontBoundingBoxDescent):
     28        (WebCore::TextMetrics::setFontBoundingBoxDescent):
     29        (WebCore::TextMetrics::actualBoundingBoxAscent):
     30        (WebCore::TextMetrics::setActualBoundingBoxAscent):
     31        (WebCore::TextMetrics::actualBoundingBoxDescent):
     32        (WebCore::TextMetrics::setActualBoundingBoxDescent):
     33        (WebCore::TextMetrics::emHeightAscent):
     34        (WebCore::TextMetrics::setEmHeightAscent):
     35        (WebCore::TextMetrics::emHeightDescent):
     36        (WebCore::TextMetrics::setEmHeightDescent):
     37        (WebCore::TextMetrics::hangingBaseline):
     38        (WebCore::TextMetrics::setHangingBaseline):
     39        (WebCore::TextMetrics::alphabeticBaseline):
     40        (WebCore::TextMetrics::setAlphabeticBaseline):
     41        (WebCore::TextMetrics::ideographicBaseline):
     42        (WebCore::TextMetrics::setIdeographicBaseline):
     43        Added getters and setters.
     44        (WebCore::TextMetrics::TextMetrics): Deleted.
     45        * html/TextMetrics.idl: Added new attributes.
     46        * html/canvas/CanvasRenderingContext2D.cpp:
     47        (WebCore::CanvasRenderingContext2D::FontProxy::fontMetrics):
     48        Changed the return value type to a const reference of FontMetrics
     49        not to copy it.
     50        (WebCore::CanvasRenderingContext2D::FontProxy::width):
     51        Added the second arguemnt of GlyphOverflow type.
     52        (WebCore::CanvasRenderingContext2D::measureText): Calculate and
     53        set the new attributes of TextMetrics.
     54        (WebCore::CanvasRenderingContext2D::textOffset): Extracted from drawTextInternal.
     55        (WebCore::CanvasRenderingContext2D::drawTextInternal): Removed the
     56        offset calculation code and call textOffset.
     57        * html/canvas/CanvasRenderingContext2D.h: Added the method
     58        declaration of textOffset. Change types of fontMetrics and width
     59        methods.
     60        * platform/graphics/cairo/FontCairoHarfbuzzNG.cpp:
     61        (WebCore::FontCascade::floatWidthForComplexText): Added a dummy
     62        implementation of calculating GlyphOverflow.
     63
    1642017-07-26  Devin Rousso  <drousso@apple.com>
    265
  • trunk/Source/WebCore/html/TextMetrics.h

    r208179 r219970  
    3838    void setWidth(float w) { m_width = w; }
    3939
     40    float actualBoundingBoxLeft() const { return m_actualBoundingBoxLeft; }
     41    void setActualBoundingBoxLeft(float value) { m_actualBoundingBoxLeft = value; }
     42
     43    float actualBoundingBoxRight() const { return m_actualBoundingBoxRight; }
     44    void setActualBoundingBoxRight(float value) { m_actualBoundingBoxRight = value; }
     45
     46    float fontBoundingBoxAscent() const { return m_fontBoundingBoxAscent; }
     47    void setFontBoundingBoxAscent(float value) {  m_fontBoundingBoxAscent = value; }
     48
     49    float fontBoundingBoxDescent() const { return m_fontBoundingBoxDescent; }
     50    void setFontBoundingBoxDescent(float value) {  m_fontBoundingBoxDescent = value; }
     51
     52    float actualBoundingBoxAscent() const { return m_actualBoundingBoxAscent; }
     53    void setActualBoundingBoxAscent(float value) {  m_actualBoundingBoxAscent = value; }
     54
     55    float actualBoundingBoxDescent() const { return m_actualBoundingBoxDescent; }
     56    void setActualBoundingBoxDescent(float value) {  m_actualBoundingBoxDescent = value; }
     57
     58    float emHeightAscent() const { return m_emHeightAscent; }
     59    void setEmHeightAscent(float value) {  m_emHeightAscent = value; }
     60
     61    float emHeightDescent() const { return m_emHeightDescent; }
     62    void setEmHeightDescent(float value) {  m_emHeightDescent = value; }
     63
     64    float hangingBaseline() const { return m_hangingBaseline; }
     65    void setHangingBaseline(float value) {  m_hangingBaseline = value; }
     66
     67    float alphabeticBaseline() const { return m_alphabeticBaseline; }
     68    void setAlphabeticBaseline(float value) {  m_alphabeticBaseline = value; }
     69
     70    float ideographicBaseline() const { return m_ideographicBaseline; }
     71    void setIdeographicBaseline(float value) {  m_ideographicBaseline = value; }
     72
    4073private:
    41     TextMetrics()
    42         : m_width(0)
    43     { }
    44 
    45     float m_width;
     74    float m_width { 0 };
     75    float m_actualBoundingBoxLeft { 0 };
     76    float m_actualBoundingBoxRight { 0 };
     77    float m_fontBoundingBoxAscent { 0 };
     78    float m_fontBoundingBoxDescent { 0 };
     79    float m_actualBoundingBoxAscent { 0 };
     80    float m_actualBoundingBoxDescent { 0 };
     81    float m_emHeightAscent { 0 };
     82    float m_emHeightDescent { 0 };
     83    float m_hangingBaseline { 0 };
     84    float m_alphabeticBaseline { 0 };
     85    float m_ideographicBaseline { 0 };
    4686};
    4787
  • trunk/Source/WebCore/html/TextMetrics.idl

    r168302 r219970  
    2727] interface TextMetrics {
    2828    readonly attribute unrestricted float width;
     29    readonly attribute unrestricted float actualBoundingBoxLeft;
     30    readonly attribute unrestricted float actualBoundingBoxRight;
     31    readonly attribute unrestricted float fontBoundingBoxAscent;
     32    readonly attribute unrestricted float fontBoundingBoxDescent;
     33    readonly attribute unrestricted float actualBoundingBoxAscent;
     34    readonly attribute unrestricted float actualBoundingBoxDescent;
     35    readonly attribute unrestricted float emHeightAscent;
     36    readonly attribute unrestricted float emHeightDescent;
     37    readonly attribute unrestricted float hangingBaseline;
     38    readonly attribute unrestricted float alphabeticBaseline;
     39    readonly attribute unrestricted float ideographicBaseline;
    2940};
    3041
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r219964 r219970  
    329329}
    330330
    331 inline FontMetrics CanvasRenderingContext2D::FontProxy::fontMetrics() const
     331inline const FontMetrics& CanvasRenderingContext2D::FontProxy::fontMetrics() const
    332332{
    333333    return m_font.fontMetrics();
    … …  
    339339}
    340340
    341 inline float CanvasRenderingContext2D::FontProxy::width(const TextRun& textRun) const
    342 {
    343     return m_font.width(textRun);
     341inline float CanvasRenderingContext2D::FontProxy::width(const TextRun& textRun, GlyphOverflow* overflow) const
     342{
     343    return m_font.width(textRun, 0, overflow);
    344344}
    345345
    … …  
    23452345    normalizeSpaces(normalizedText);
    23462346
    2347     metrics->setWidth(fontProxy().width(TextRun(normalizedText)));
    2348 
    2349     return metrics;
    2350 }
    2351 
    2352 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth)
    2353 {
    2354     auto& fontProxy = this->fontProxy();
    2355     const auto& fontMetrics = fontProxy.fontMetrics();
    2356 
    2357     auto* c = drawingContext();
    2358     if (!c)
    2359         return;
    2360     if (!state().hasInvertibleTransform)
    2361         return;
    2362     if (!std::isfinite(x) | !std::isfinite(y))
    2363         return;
    2364     if (maxWidth && (!std::isfinite(maxWidth.value()) || maxWidth.value() <= 0))
    2365         return;
    2366 
    2367     // If gradient size is zero, then paint nothing.
    2368     auto* gradient = c->strokeGradient();
    2369     if (!fill && gradient && gradient->isZeroSize())
    2370         return;
    2371 
    2372     gradient = c->fillGradient();
    2373     if (fill && gradient && gradient->isZeroSize())
    2374         return;
    2375 
    2376     String normalizedText = text;
    2377     normalizeSpaces(normalizedText);
    2378 
    2379     // FIXME: Need to turn off font smoothing.
    2380 
    23812347    const RenderStyle* computedStyle;
    23822348    auto direction = toTextDirection(state().direction, &computedStyle);
    2383     bool isRTL = direction == RTL;
    23842349    bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
    23852350
    23862351    TextRun textRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override, true);
    2387     // Draw the item text at the correct point.
    2388     FloatPoint location(x, y);
     2352    auto& font = fontProxy();
     2353    auto& fontMetrics = font.fontMetrics();
     2354
     2355    GlyphOverflow glyphOverflow;
     2356    glyphOverflow.computeBounds = true;
     2357    float fontWidth = font.width(textRun, &glyphOverflow);
     2358    metrics->setWidth(fontWidth);
     2359
     2360    FloatPoint offset = textOffset(fontWidth, direction);
     2361
     2362    metrics->setActualBoundingBoxAscent(glyphOverflow.top - offset.y());
     2363    metrics->setActualBoundingBoxDescent(glyphOverflow.bottom + offset.y());
     2364    metrics->setFontBoundingBoxAscent(fontMetrics.ascent() - offset.y());
     2365    metrics->setFontBoundingBoxDescent(fontMetrics.descent() + offset.y());
     2366    metrics->setEmHeightAscent(fontMetrics.ascent() - offset.y());
     2367    metrics->setEmHeightDescent(fontMetrics.descent() + offset.y());
     2368    metrics->setHangingBaseline(fontMetrics.ascent() - offset.y());
     2369    metrics->setAlphabeticBaseline(-offset.y());
     2370    metrics->setIdeographicBaseline(-fontMetrics.descent() - offset.y());
     2371
     2372    metrics->setActualBoundingBoxLeft(glyphOverflow.left - offset.x());
     2373    metrics->setActualBoundingBoxRight(fontWidth + glyphOverflow.right + offset.x());
     2374
     2375    return metrics;
     2376}
     2377
     2378FloatPoint CanvasRenderingContext2D::textOffset(float width, TextDirection direction)
     2379{
     2380    auto& fontMetrics = fontProxy().fontMetrics();
     2381    FloatPoint offset;
     2382
    23892383    switch (state().textBaseline) {
    23902384    case TopTextBaseline:
    23912385    case HangingTextBaseline:
    2392         location.setY(y + fontMetrics.ascent());
     2386        offset.setY(fontMetrics.ascent());
    23932387        break;
    23942388    case BottomTextBaseline:
    23952389    case IdeographicTextBaseline:
    2396         location.setY(y - fontMetrics.descent());
     2390        offset.setY(-fontMetrics.descent());
    23972391        break;
    23982392    case MiddleTextBaseline:
    2399         location.setY(y - fontMetrics.descent() + fontMetrics.height() / 2);
     2393        offset.setY(fontMetrics.height() / 2 - fontMetrics.descent());
    24002394        break;
    24012395    case AlphabeticTextBaseline:
    24022396    default:
    2403          // Do nothing.
    24042397        break;
    24052398    }
    24062399
    2407     float fontWidth = fontProxy.width(TextRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override));
    2408 
    2409     bool useMaxWidth = maxWidth && maxWidth.value() < fontWidth;
    2410     float width = useMaxWidth ? maxWidth.value() : fontWidth;
    2411 
     2400    bool isRTL = direction == RTL;
    24122401    auto align = state().textAlign;
    24132402    if (align == StartTextAlign)
    … …  
    24182407    switch (align) {
    24192408    case CenterTextAlign:
    2420         location.setX(location.x() - width / 2);
     2409        offset.setX(-width / 2);
    24212410        break;
    24222411    case RightTextAlign:
    2423         location.setX(location.x() - width);
     2412        offset.setX(-width);
    24242413        break;
    24252414    default:
    24262415        break;
    24272416    }
     2417    return offset;
     2418}
     2419
     2420void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth)
     2421{
     2422    auto& fontProxy = this->fontProxy();
     2423    const auto& fontMetrics = fontProxy.fontMetrics();
     2424
     2425    auto* c = drawingContext();
     2426    if (!c)
     2427        return;
     2428    if (!state().hasInvertibleTransform)
     2429        return;
     2430    if (!std::isfinite(x) | !std::isfinite(y))
     2431        return;
     2432    if (maxWidth && (!std::isfinite(maxWidth.value()) || maxWidth.value() <= 0))
     2433        return;
     2434
     2435    // If gradient size is zero, then paint nothing.
     2436    auto* gradient = c->strokeGradient();
     2437    if (!fill && gradient && gradient->isZeroSize())
     2438        return;
     2439
     2440    gradient = c->fillGradient();
     2441    if (fill && gradient && gradient->isZeroSize())
     2442        return;
     2443
     2444    String normalizedText = text;
     2445    normalizeSpaces(normalizedText);
     2446
     2447    // FIXME: Need to turn off font smoothing.
     2448
     2449    const RenderStyle* computedStyle;
     2450    auto direction = toTextDirection(state().direction, &computedStyle);
     2451    bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
     2452
     2453    TextRun textRun(normalizedText, 0, 0, AllowTrailingExpansion, direction, override, true);
     2454    float fontWidth = fontProxy.width(textRun);
     2455    bool useMaxWidth = maxWidth && maxWidth.value() < fontWidth;
     2456    float width = useMaxWidth ? maxWidth.value() : fontWidth;
     2457    FloatPoint location(x, y);
     2458    location += textOffset(width, direction);
    24282459
    24292460    // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h

    r219964 r219970  
    251251        bool realized() const { return m_font.fontSelector(); }
    252252        void initialize(FontSelector&, const RenderStyle&);
    253         FontMetrics fontMetrics() const;
     253        const FontMetrics& fontMetrics() const;
    254254        const FontCascadeDescription& fontDescription() const;
    255         float width(const TextRun&) const;
     255        float width(const TextRun&, GlyphOverflow* = 0) const;
    256256        void drawBidiText(GraphicsContext&, const TextRun&, const FloatPoint&, FontCascade::CustomFontNotReadyAction) const;
    257257
    … …  
    391391    TextDirection toTextDirection(Direction, const RenderStyle** computedStyle = nullptr) const;
    392392
     393    FloatPoint textOffset(float width, TextDirection);
     394
    393395#if ENABLE(ACCELERATED_2D_CANVAS)
    394396    PlatformLayer* platformLayer() const override;
  • trunk/Source/WebCore/platform/graphics/cairo/FontCairoHarfbuzzNG.cpp

    r211836 r219970  
    6363}
    6464
    65 float FontCascade::floatWidthForComplexText(const TextRun& run, HashSet<const Font*>*, GlyphOverflow*) const
     65float FontCascade::floatWidthForComplexText(const TextRun& run, HashSet<const Font*>*, GlyphOverflow* glyphOverflow) const
    6666{
     67    if (glyphOverflow) {
     68        // FIXME: Calculate the actual values rather than just the font's ascent and descent
     69        glyphOverflow->top = glyphOverflow->computeBounds ? fontMetrics().ascent() : 0;
     70        glyphOverflow->bottom = glyphOverflow->computeBounds ? fontMetrics().descent() : 0;
     71        glyphOverflow->left = 0;
     72        glyphOverflow->right = 0;
     73    }
    6774    HarfBuzzShaper shaper(this, run);
    6875    if (shaper.shape())
Note: See TracChangeset for help on using the changeset viewer.