<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[285620] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/285620">285620</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2021-11-10 22:12:07 -0800 (Wed, 10 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/283863">r283863</a>): `<attachment>` with a long `action` do not render correctly
https://bugs.webkit.org/show_bug.cgi?id=232645
<rdar://problem/84558377>

Reviewed by Myles C. Maxfield.

Source/WebCore:

Unlike the `DisplayList` concept in WebCore, when using `CGContextDelegateRef` (which is
what `DrawGlyphsRecorder` uses on Cocoa platforms) the callbacks for each action are only
told about the current state of all-the-things at the time of that action, not each of the
corresponding API-level calls that resulted in that final state (e.g. where `DisplayList`
would see separate `scale` and `rotate` calls, `CGContextDelegateRef` would only be able to
get the final calculated CTM). In order for `DrawGlyphsRecorder` to (re)generate WebCore
calls, it needs to have information about the starting state of the `CGContext` before any
actions are performed so it can at least derive some diff/idea of what happened.

This is further complicated by the fact that when drawing text CG separates the state of
all-the-things into two: the CTM and the text matrix. WebKit does not have this separation,
however, so it needs to combine the two into a single CTM, but only when dealing with text.

A new path (`drawNativeText`) was added in <a href="http://trac.webkit.org/projects/webkit/changeset/283863">r283863</a> that allows `DrawGlyphsRecorder` to be
used directly with native text-related objects (e.g. `CTLineRef`) instead of objects/data
derived in WebCore. A result of this on Cocoa platforms is that now a single `drawNativeText`
can result in multiple `recordDrawGlyphs` invocations if the `CTLineRef` contains multiple
"groupings" of glyphs to draw (e.g. if a line is truncated with a "..." in the middle then
the three groups will be the remaining text before, the "..." and the remaining text after).

AFAICT before this new path it was never the case that the text matrix had a translate, only
rotate/skew/etc., meaning that when `DrawGlyphsRecorder` needed to convert from the CG's
computed glyph positions back into WebCore's glyph advances it could use the text matrix
since there would be no translation. With this new path, however, if a `drawNativeText` call
results in multiple `recordDrawGlyphs` then there will be a translation in the text matrix
to account for that. As such, we end up double counting the text matrix: once when we
(re)generate the CTM to give to WebCore and _again_ when we (re)compute the WebCore advances.

Since we've already counted the text matrix once, we don't need to do it again. Also, by
this point we've already modified WebCore's CTM, so we only really need to account for the
difference from the original position when we first called `drawNativeText`. As such, we
just need invert what was used to generate CG positions from WebCore advances.

Note that in the name of expediently fixing a regression, this change only considers
horizontal text as `<attachment>` are never drawn vertically. Fixing vertical text will be
done in a followup <https://webkit.org/b/232917>.

Test: fast/attachment/attachment-truncated-action.html

* platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp:
(WebCore::DrawGlyphsRecorder::recordDrawGlyphs):

* platform/graphics/FontCascade.h:
* platform/graphics/coretext/FontCascadeCoreText.cpp:
(WebCore::fillVectorWithHorizontalGlyphPositions):
(WebCore::fillVectorWithVerticalGlyphPositions):
Add a comment indicating the related nature of these functions with `DrawGlyphsRecorder::recordDrawGlyphs`.
Drive-by: `fillVectorWithHorizontalGlyphPositions` is only called by this class, so don't export it.

LayoutTests:

* fast/attachment/attachment-truncated-action.html: Added.
* fast/attachment/attachment-truncated-action-expected-mismatch.html: Added.

* TestExpectations:
* platform/ios/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformiosTestExpectations">trunk/LayoutTests/platform/ios/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsFontCascadeh">trunk/Source/WebCore/platform/graphics/FontCascade.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscoretextDrawGlyphsRecorderCoreTextcpp">trunk/Source/WebCore/platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscoretextFontCascadeCoreTextcpp">trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastattachmentattachmenttruncatedactionexpectedmismatchhtml">trunk/LayoutTests/fast/attachment/attachment-truncated-action-expected-mismatch.html</a></li>
<li><a href="#trunkLayoutTestsfastattachmentattachmenttruncatedactionhtml">trunk/LayoutTests/fast/attachment/attachment-truncated-action.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/LayoutTests/ChangeLog 2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2021-11-10  Devin Rousso  <drousso@apple.com>
+
+        REGRESSION(r283863): `<attachment>` with a long `action` do not render correctly
+        https://bugs.webkit.org/show_bug.cgi?id=232645
+        <rdar://problem/84558377>
+
+        Reviewed by Myles C. Maxfield.
+
+        * fast/attachment/attachment-truncated-action.html: Added.
+        * fast/attachment/attachment-truncated-action-expected-mismatch.html: Added.
+
+        * TestExpectations:
+        * platform/ios/TestExpectations:
+
</ins><span class="cx"> 2021-11-10  Said Abou-Hallawa  <said@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [GPU Process] Make CSSFilter be a composite of FilterFunctions
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations       2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/LayoutTests/TestExpectations  2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -226,6 +226,7 @@
</span><span class="cx"> fast/attachment/attachment-subtitle-resize.html [ Skip ]
</span><span class="cx"> 
</span><span class="cx"> # This test only makes sense on iOS
</span><ins>+fast/attachment/attachment-truncated-action.html [ Skip ]
</ins><span class="cx"> fast/attachment/attachment-wrapping-action.html [ Skip ]
</span><span class="cx"> fast/attachment/attachment-borderless.html [ Skip ]
</span><span class="cx"> fast/attachment/attachment-dynamic-type.html [ Skip ]
</span></span></pre></div>
<a id="trunkLayoutTestsfastattachmentattachmenttruncatedactionexpectedmismatchhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/attachment/attachment-truncated-action-expected-mismatch.html (0 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/attachment/attachment-truncated-action-expected-mismatch.html                             (rev 0)
+++ trunk/LayoutTests/fast/attachment/attachment-truncated-action-expected-mismatch.html        2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+<div></div>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastattachmentattachmenttruncatedactionhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/attachment/attachment-truncated-action.html (0 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/attachment/attachment-truncated-action.html                               (rev 0)
+++ trunk/LayoutTests/fast/attachment/attachment-truncated-action.html  2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+<!DOCTYPE html><!-- webkit-test-runner [ AttachmentElementEnabled=true ] -->
+<html>
+<body>
+<attachment action="this is very very very very very very very very very very long action" title="title" style="clip-path: inset(45% 25% 40% 50%)"></attachment>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiosTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios/TestExpectations (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios/TestExpectations  2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/LayoutTests/platform/ios/TestExpectations     2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -2411,6 +2411,7 @@
</span><span class="cx"> 
</span><span class="cx"> imported/w3c/web-platform-tests/dom/events/scrolling [ Pass ]
</span><span class="cx"> 
</span><ins>+fast/attachment/attachment-truncated-action.html [ Pass ]
</ins><span class="cx"> fast/attachment/attachment-wrapping-action.html [ Pass ]
</span><span class="cx"> fast/attachment/attachment-borderless.html [ Pass ]
</span><span class="cx"> fast/attachment/attachment-dynamic-type.html [ Pass ]
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/Source/WebCore/ChangeLog      2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -1,3 +1,60 @@
</span><ins>+2021-11-10  Devin Rousso  <drousso@apple.com>
+
+        REGRESSION(r283863): `<attachment>` with a long `action` do not render correctly
+        https://bugs.webkit.org/show_bug.cgi?id=232645
+        <rdar://problem/84558377>
+
+        Reviewed by Myles C. Maxfield.
+
+        Unlike the `DisplayList` concept in WebCore, when using `CGContextDelegateRef` (which is
+        what `DrawGlyphsRecorder` uses on Cocoa platforms) the callbacks for each action are only
+        told about the current state of all-the-things at the time of that action, not each of the
+        corresponding API-level calls that resulted in that final state (e.g. where `DisplayList`
+        would see separate `scale` and `rotate` calls, `CGContextDelegateRef` would only be able to
+        get the final calculated CTM). In order for `DrawGlyphsRecorder` to (re)generate WebCore
+        calls, it needs to have information about the starting state of the `CGContext` before any
+        actions are performed so it can at least derive some diff/idea of what happened.
+
+        This is further complicated by the fact that when drawing text CG separates the state of
+        all-the-things into two: the CTM and the text matrix. WebKit does not have this separation,
+        however, so it needs to combine the two into a single CTM, but only when dealing with text.
+
+        A new path (`drawNativeText`) was added in r283863 that allows `DrawGlyphsRecorder` to be
+        used directly with native text-related objects (e.g. `CTLineRef`) instead of objects/data
+        derived in WebCore. A result of this on Cocoa platforms is that now a single `drawNativeText`
+        can result in multiple `recordDrawGlyphs` invocations if the `CTLineRef` contains multiple
+        "groupings" of glyphs to draw (e.g. if a line is truncated with a "..." in the middle then
+        the three groups will be the remaining text before, the "..." and the remaining text after).
+
+        AFAICT before this new path it was never the case that the text matrix had a translate, only
+        rotate/skew/etc., meaning that when `DrawGlyphsRecorder` needed to convert from the CG's
+        computed glyph positions back into WebCore's glyph advances it could use the text matrix
+        since there would be no translation. With this new path, however, if a `drawNativeText` call
+        results in multiple `recordDrawGlyphs` then there will be a translation in the text matrix
+        to account for that. As such, we end up double counting the text matrix: once when we
+        (re)generate the CTM to give to WebCore and _again_ when we (re)compute the WebCore advances.
+
+        Since we've already counted the text matrix once, we don't need to do it again. Also, by
+        this point we've already modified WebCore's CTM, so we only really need to account for the
+        difference from the original position when we first called `drawNativeText`. As such, we
+        just need invert what was used to generate CG positions from WebCore advances.
+
+        Note that in the name of expediently fixing a regression, this change only considers
+        horizontal text as `<attachment>` are never drawn vertically. Fixing vertical text will be
+        done in a followup <https://webkit.org/b/232917>.
+
+        Test: fast/attachment/attachment-truncated-action.html
+
+        * platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp:
+        (WebCore::DrawGlyphsRecorder::recordDrawGlyphs):
+
+        * platform/graphics/FontCascade.h:
+        * platform/graphics/coretext/FontCascadeCoreText.cpp:
+        (WebCore::fillVectorWithHorizontalGlyphPositions):
+        (WebCore::fillVectorWithVerticalGlyphPositions):
+        Add a comment indicating the related nature of these functions with `DrawGlyphsRecorder::recordDrawGlyphs`.
+        Drive-by: `fillVectorWithHorizontalGlyphPositions` is only called by this class, so don't export it.
+
</ins><span class="cx"> 2021-11-10  Said Abou-Hallawa  <said@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [GPU Process] Make CSSFilter be a composite of FilterFunctions
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsFontCascadeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/FontCascade.h (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/FontCascade.h     2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.h        2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -91,7 +91,6 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> #if USE(CORE_TEXT)
</span><del>-void fillVectorWithHorizontalGlyphPositions(Vector<CGPoint, 256>& positions, CGContextRef, const CGSize* advances, unsigned count, const FloatPoint&);
</del><span class="cx"> AffineTransform computeOverallTextMatrix(const Font&);
</span><span class="cx"> AffineTransform computeVerticalTextMatrix(const Font&, const AffineTransform& previousTextMatrix);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscoretextDrawGlyphsRecorderCoreTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp   2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/Source/WebCore/platform/graphics/coretext/DrawGlyphsRecorderCoreText.cpp      2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -333,8 +333,19 @@
</span><span class="cx"> 
</span><span class="cx">     auto fontSize = CGGStateGetFontSize(gstate);
</span><span class="cx">     Ref font = m_deriveFontFromContext == DeriveFontFromContext::No ? *m_originalFont : Font::create(FontPlatformData(adoptCF(CTFontCreateWithGraphicsFont(usedFont, fontSize, nullptr, nullptr)), fontSize));
</span><del>-    m_owner.drawGlyphsAndCacheFont(font, glyphs, computeAdvancesFromPositions(positions, count, currentTextMatrix).data(), count, currentTextMatrix.mapPoint(positions[0]), m_smoothingMode);
</del><span class="cx"> 
</span><ins>+    // The above does the work of ensuring the right CTM (which is the combination of CG's CTM and
+    // CG's text matrix) is set for the replayer, but in order to provide the right values to
+    // `FontCascade::drawGlyphs` we need to recalculate the original advances from the resulting
+    // positions by inverting the operations applied to the original advances.
+    auto textMatrix = m_originalTextMatrix;
+    if (font->platformData().orientation() == FontOrientation::Vertical) {
+        // Keep this in sync as the inverse of `fillVectorWithVerticalGlyphPositions`.
+        // FIXME: <https://webkit.org/b/232917> (`DrawGlyphsRecorder` should be able to record+replay vertical text)
+    }
+
+    m_owner.drawGlyphsAndCacheFont(font, glyphs, computeAdvancesFromPositions(positions, count, textMatrix).data(), count, textMatrix.mapPoint(positions[0]), m_smoothingMode);
+
</ins><span class="cx">     m_owner.concatCTM(inverseCTMFixup);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscoretextFontCascadeCoreTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp (285619 => 285620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp  2021-11-11 05:03:15 UTC (rev 285619)
+++ trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp     2021-11-11 06:12:07 UTC (rev 285620)
</span><span class="lines">@@ -118,8 +118,9 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void fillVectorWithHorizontalGlyphPositions(Vector<CGPoint, 256>& positions, CGContextRef context, const CGSize* advances, unsigned count, const FloatPoint& point)
</del><ins>+static void fillVectorWithHorizontalGlyphPositions(Vector<CGPoint, 256>& positions, CGContextRef context, const CGSize* advances, unsigned count, const FloatPoint& point)
</ins><span class="cx"> {
</span><ins>+    // Keep this in sync as the inverse of `DrawGlyphsRecorder::recordDrawGlyphs`.
</ins><span class="cx">     // The input positions are in the context's coordinate system, without the text matrix.
</span><span class="cx">     // However, the positions that CT/CG accept are in the text matrix's coordinate system.
</span><span class="cx">     // CGContextGetTextMatrix() gives us the matrix that maps from text's coordinate system to the context's (non-text) coordinate system.
</span><span class="lines">@@ -139,6 +140,7 @@
</span><span class="cx"> 
</span><span class="cx"> static void fillVectorWithVerticalGlyphPositions(Vector<CGPoint, 256>& positions, CGContextRef context, const CGSize* translations, const CGSize* advances, unsigned count, const FloatPoint& point, float ascentDelta)
</span><span class="cx"> {
</span><ins>+    // Keep this in sync as the inverse of `DrawGlyphsRecorder::recordDrawGlyphs`.
</ins><span class="cx">     CGAffineTransform transform = CGAffineTransformInvert(CGContextGetTextMatrix(context));
</span><span class="cx"> 
</span><span class="cx">     auto position = CGPointMake(point.x(), point.y() + ascentDelta);
</span></span></pre>
</div>
</div>

</body>
</html>