<!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>[180950] 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/180950">180950</a></dd>
<dt>Author</dt> <dd>timothy_horton@apple.com</dd>
<dt>Date</dt> <dd>2015-03-03 12:16:50 -0800 (Tue, 03 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>&lt;attachment&gt; label can get very wide, doesn't wrap/truncate
https://bugs.webkit.org/show_bug.cgi?id=142214
&lt;rdar://problem/19982499&gt;

Reviewed by Simon Fraser.

Test: fast/attachment/attachment-label-highlight.html

* rendering/RenderThemeMac.h:
* rendering/RenderThemeMac.mm:
(WebCore::labelTextColorForAttachment):
(WebCore::AttachmentLayout::addLine):
(WebCore::AttachmentLayout::layOutText):
(WebCore::AttachmentLayout::AttachmentLayout):
Make it possible to lay out multiple lines of label text.
We lay out the whole string normally, but then only draw N (where N=1 for now,
but is adjustable) of the lines. The remainder of the string is then
merged into a single line, which is middle-truncated with an ellipsis
and drawn in place of the N+1 line.

(WebCore::addAttachmentLabelBackgroundRightCorner):
(WebCore::addAttachmentLabelBackgroundLeftCorner):
(WebCore::paintAttachmentLabelBackground):
Wrap the label background around the multiple lines of text with curved edges.
We run first down the right side of the label, determining whether to use
concave or convex arcs based on the relative widths of adjacent lines.
Then, we run back up the left side of the label doing the same thing.

If the background rects of two lines are very similar (within the rounded rect radius),
they will be expanded to the larger of the two, because otherwise the arcs
look quite wrong.

(WebCore::paintAttachmentLabel):
Draw the label with CoreText directly instead of bothering with WebCore
text layout primitives. There's no need, and it makes wrapping much more complicated.

(WebCore::RenderThemeMac::paintAttachment):
(WebCore::RenderThemeMac::paintAttachmentLabelBackground): Deleted.
(WebCore::RenderThemeMac::paintAttachmentLabel): Deleted.

* fast/attachment/attachment-label-highlight.html: Added.
* platform/mac/fast/attachment/attachment-label-highlight-expected.png: Added.
* platform/mac/fast/attachment/attachment-label-highlight-expected.txt: Added.
Add a test for various &lt;attachment&gt; highlight cases.

* platform/mac/fast/attachment/attachment-rendering-expected.txt:
Update expected result for attachment-rendering, which changed size
because we now bail from text layout if we don't have any text.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformmacfastattachmentattachmentrenderingexpectedtxt">trunk/LayoutTests/platform/mac/fast/attachment/attachment-rendering-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderThemeMach">trunk/Source/WebCore/rendering/RenderThemeMac.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderThemeMacmm">trunk/Source/WebCore/rendering/RenderThemeMac.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastattachmentattachmentlabelhighlighthtml">trunk/LayoutTests/fast/attachment/attachment-label-highlight.html</a></li>
<li><a href="#trunkLayoutTestsplatformmacfastattachmentattachmentlabelhighlightexpectedpng">trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.png</a></li>
<li><a href="#trunkLayoutTestsplatformmacfastattachmentattachmentlabelhighlightexpectedtxt">trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (180949 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-03-03 20:13:01 UTC (rev 180949)
+++ trunk/LayoutTests/ChangeLog        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2015-03-03  Timothy Horton  &lt;timothy_horton@apple.com&gt;
+
+        &lt;attachment&gt; label can get very wide, doesn't wrap/truncate
+        https://bugs.webkit.org/show_bug.cgi?id=142214
+        &lt;rdar://problem/19982499&gt;
+
+        Reviewed by Simon Fraser.
+
+        * fast/attachment/attachment-label-highlight.html: Added.
+        * platform/mac/fast/attachment/attachment-label-highlight-expected.png: Added.
+        * platform/mac/fast/attachment/attachment-label-highlight-expected.txt: Added.
+        Add a test for various &lt;attachment&gt; highlight cases.
+
+        * platform/mac/fast/attachment/attachment-rendering-expected.txt:
+        Update expected result for attachment-rendering, which changed size
+        because we now bail from text layout if we don't have any text.
+
</ins><span class="cx"> 2015-03-03  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Win] Document more debug assertions.
</span></span></pre></div>
<a id="trunkLayoutTestsfastattachmentattachmentlabelhighlighthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/attachment/attachment-label-highlight.html (0 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/attachment/attachment-label-highlight.html                                (rev 0)
+++ trunk/LayoutTests/fast/attachment/attachment-label-highlight.html        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script&gt;
+var attachmentShortLabel = document.createElement(&quot;attachment&quot;);
+var attachmentLongOnTopLabel = document.createElement(&quot;attachment&quot;);
+var attachmentLongOnBottomLabel = document.createElement(&quot;attachment&quot;);
+var attachmentWrappedLabel = document.createElement(&quot;attachment&quot;);
+var attachmentEqualSizeLabel = document.createElement(&quot;attachment&quot;);
+var attachmentNearlyEqualSizeLabel = document.createElement(&quot;attachment&quot;);
+
+if (window.internals) {
+    attachmentShortLabel.file = window.internals.createFile(&quot;short&quot;);
+    attachmentLongOnTopLabel.file = window.internals.createFile(&quot;short verylongword&quot;);
+    attachmentLongOnBottomLabel.file = window.internals.createFile(&quot;verylongword short&quot;);
+    attachmentWrappedLabel.file = window.internals.createFile(&quot;quite-a-long-filename-that-goes-on-without-an-end-in-sight&quot;);
+    attachmentEqualSizeLabel.file = window.internals.createFile(&quot;abunchofletters abunchofletters&quot;);
+    attachmentNearlyEqualSizeLabel.file = window.internals.createFile(&quot;abunchofletters abunchoflletters&quot;);
+}
+
+document.body.appendChild(attachmentShortLabel);
+document.body.appendChild(attachmentLongOnTopLabel);
+document.body.appendChild(attachmentLongOnBottomLabel);
+document.body.appendChild(attachmentWrappedLabel);
+document.body.appendChild(attachmentEqualSizeLabel);
+document.body.appendChild(attachmentNearlyEqualSizeLabel);
+
+document.execCommand(&quot;SelectAll&quot;);
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacfastattachmentattachmentlabelhighlightexpectedpng"></a>
<div class="binary"><h4>Added: trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Property changes on: trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.png
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="trunkLayoutTestsplatformmacfastattachmentattachmentlabelhighlightexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.txt (0 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/mac/fast/attachment/attachment-label-highlight-expected.txt        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x108
+  RenderBlock {HTML} at (0,0) size 800x108
+    RenderBody {BODY} at (8,8) size 784x92
+      RenderAttachment {ATTACHMENT} at (0,0) size 60x77
+      RenderAttachment {ATTACHMENT} at (60,0) size 90x92
+      RenderAttachment {ATTACHMENT} at (150,0) size 90x92
+      RenderAttachment {ATTACHMENT} at (240,0) size 96x92
+      RenderAttachment {ATTACHMENT} at (336,0) size 102x92
+      RenderAttachment {ATTACHMENT} at (438,0) size 106x92
+      RenderText {#text} at (0,0) size 0x0
+selection start: position 0 of child 2 {ATTACHMENT} of body
+selection end:   position 1 of child 7 {ATTACHMENT} of body
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacfastattachmentattachmentrenderingexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/fast/attachment/attachment-rendering-expected.txt (180949 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/fast/attachment/attachment-rendering-expected.txt        2015-03-03 20:13:01 UTC (rev 180949)
+++ trunk/LayoutTests/platform/mac/fast/attachment/attachment-rendering-expected.txt        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -6,6 +6,6 @@
</span><span class="cx">       RenderBlock {P} at (0,0) size 784x18
</span><span class="cx">         RenderText {#text} at (0,0) size 326x18
</span><span class="cx">           text run at (0,0) width 326: &quot;This tests that attachments have a custom renderer.&quot;
</span><del>-      RenderBlock (anonymous) at (0,34) size 784x77
-        RenderAttachment {ATTACHMENT} at (0,0) size 60x77
</del><ins>+      RenderBlock (anonymous) at (0,34) size 784x60
+        RenderAttachment {ATTACHMENT} at (0,0) size 60x60
</ins><span class="cx">         RenderText {#text} at (0,0) size 0x0
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (180949 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-03 20:13:01 UTC (rev 180949)
+++ trunk/Source/WebCore/ChangeLog        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -1,3 +1,45 @@
</span><ins>+2015-03-03  Timothy Horton  &lt;timothy_horton@apple.com&gt;
+
+        &lt;attachment&gt; label can get very wide, doesn't wrap/truncate
+        https://bugs.webkit.org/show_bug.cgi?id=142214
+        &lt;rdar://problem/19982499&gt;
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/attachment/attachment-label-highlight.html
+
+        * rendering/RenderThemeMac.h:
+        * rendering/RenderThemeMac.mm:
+        (WebCore::labelTextColorForAttachment):
+        (WebCore::AttachmentLayout::addLine):
+        (WebCore::AttachmentLayout::layOutText):
+        (WebCore::AttachmentLayout::AttachmentLayout):
+        Make it possible to lay out multiple lines of label text.
+        We lay out the whole string normally, but then only draw N (where N=1 for now,
+        but is adjustable) of the lines. The remainder of the string is then
+        merged into a single line, which is middle-truncated with an ellipsis
+        and drawn in place of the N+1 line.
+
+        (WebCore::addAttachmentLabelBackgroundRightCorner):
+        (WebCore::addAttachmentLabelBackgroundLeftCorner):
+        (WebCore::paintAttachmentLabelBackground):
+        Wrap the label background around the multiple lines of text with curved edges.
+        We run first down the right side of the label, determining whether to use
+        concave or convex arcs based on the relative widths of adjacent lines.
+        Then, we run back up the left side of the label doing the same thing.
+
+        If the background rects of two lines are very similar (within the rounded rect radius),
+        they will be expanded to the larger of the two, because otherwise the arcs
+        look quite wrong.
+
+        (WebCore::paintAttachmentLabel):
+        Draw the label with CoreText directly instead of bothering with WebCore
+        text layout primitives. There's no need, and it makes wrapping much more complicated.
+
+        (WebCore::RenderThemeMac::paintAttachment):
+        (WebCore::RenderThemeMac::paintAttachmentLabelBackground): Deleted.
+        (WebCore::RenderThemeMac::paintAttachmentLabel): Deleted.
+
</ins><span class="cx"> 2015-03-03  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Avoid applying the clip-path when painting, if a layer also has a shape layer mask
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderThemeMach"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderThemeMac.h (180949 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderThemeMac.h        2015-03-03 20:13:01 UTC (rev 180949)
+++ trunk/Source/WebCore/rendering/RenderThemeMac.h        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -233,11 +233,6 @@
</span><span class="cx">     NSServicesRolloverButtonCell *servicesRolloverButtonCell() const;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#if ENABLE(ATTACHMENT_ELEMENT)
-    void paintAttachmentLabelBackground(const RenderAttachment&amp;, GraphicsContext&amp;, AttachmentLayout&amp;) const;
-    void paintAttachmentLabel(const RenderAttachment&amp;, GraphicsContext&amp;, AttachmentLayout&amp;, bool useSelectedStyle) const;
-#endif
-
</del><span class="cx">     mutable RetainPtr&lt;NSPopUpButtonCell&gt; m_popupButton;
</span><span class="cx">     mutable RetainPtr&lt;NSSearchFieldCell&gt; m_search;
</span><span class="cx">     mutable RetainPtr&lt;NSMenu&gt; m_searchMenuTemplate;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderThemeMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderThemeMac.mm (180949 => 180950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderThemeMac.mm        2015-03-03 20:13:01 UTC (rev 180949)
+++ trunk/Source/WebCore/rendering/RenderThemeMac.mm        2015-03-03 20:16:50 UTC (rev 180950)
</span><span class="lines">@@ -2086,6 +2086,8 @@
</span><span class="cx"> const CGFloat attachmentLabelFontSize = 12;
</span><span class="cx"> const CGFloat attachmentLabelBackgroundRadius = 3;
</span><span class="cx"> const CGFloat attachmentLabelBackgroundPadding = 3;
</span><ins>+const CGFloat attachmentLabelMaximumWidth = 100 - (attachmentLabelBackgroundPadding * 2);
+const CFIndex attachmentLabelMaximumLineCount = 2;
</ins><span class="cx"> 
</span><span class="cx"> static Color attachmentLabelInactiveBackgroundColor() { return Color(204, 204, 204, 255); }
</span><span class="cx"> static Color attachmentLabelInactiveTextColor() { return Color(100, 100, 100, 255); }
</span><span class="lines">@@ -2093,10 +2095,16 @@
</span><span class="cx"> const CGFloat attachmentMargin = 3;
</span><span class="cx"> 
</span><span class="cx"> struct AttachmentLayout {
</span><del>-    AttachmentLayout(const RenderAttachment&amp;);
</del><ins>+    explicit AttachmentLayout(const RenderAttachment&amp;);
</ins><span class="cx"> 
</span><del>-    FloatRect textRect;
-    FloatRect textBackgroundRect;
</del><ins>+    struct LabelLine {
+        FloatRect backgroundRect;
+        FloatPoint origin;
+        RetainPtr&lt;CTLineRef&gt; line;
+    };
+
+    Vector&lt;LabelLine&gt; lines;
+
</ins><span class="cx">     FloatRect iconRect;
</span><span class="cx">     FloatRect iconBackgroundRect;
</span><span class="cx">     FloatRect attachmentRect;
</span><span class="lines">@@ -2104,33 +2112,118 @@
</span><span class="cx">     int baseline;
</span><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;CTFontRef&gt; labelFont;
</span><del>-    FontCascade labelFontCascade;
-    std::unique_ptr&lt;TextRun&gt; labelTextRun;
</del><ins>+
+private:
+    void layOutLabel(const RenderAttachment&amp;);
+    void addLine(CTLineRef, CGFloat&amp; yOffset, Vector&lt;CGPoint&gt; origins, CFIndex lineIndex, const RenderAttachment&amp;);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-AttachmentLayout::AttachmentLayout(const RenderAttachment&amp; attachment)
</del><ins>+static NSColor *labelTextColorForAttachment(const RenderAttachment&amp; attachment)
</ins><span class="cx"> {
</span><del>-    // FIXME: We should have a limit on the width of the label.
-    // FIXME: We should support line-breaking (up to two lines) and always middle-truncate the second line.
</del><ins>+    if (attachment.isSelected()) {
+        if (attachment.frame().selection().isFocusedAndActive())
+            return [NSColor alternateSelectedControlTextColor];    
+        return (NSColor *)cachedCGColor(attachmentLabelInactiveTextColor(), ColorSpaceDeviceRGB);
+    }
+
+    return [NSColor blackColor];
+}
+
+void AttachmentLayout::addLine(CTLineRef line, CGFloat&amp; yOffset, Vector&lt;CGPoint&gt; origins, CFIndex lineIndex, const RenderAttachment&amp; attachment)
+{
+    CGRect lineBounds = CTLineGetBoundsWithOptions(line, 0);
+    CGFloat trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(line);
+    CGFloat lineWidthIgnoringTrailingWhitespace = lineBounds.size.width - trailingWhitespaceWidth;
+    CGFloat lineHeight = CGCeiling(lineBounds.size.height);
+
+    // Center the line relative to the icon.
+    CGFloat xOffset = (attachmentIconBackgroundSize / 2) - (lineWidthIgnoringTrailingWhitespace / 2);
+
+    if (lineIndex)
+        yOffset += origins[lineIndex - 1].y - origins[lineIndex].y;
+
+    LabelLine labelLine;
+    labelLine.origin = FloatPoint(xOffset, yOffset + lineHeight - origins.last().y);
+    labelLine.line = line;
+    labelLine.backgroundRect = FloatRect(xOffset, yOffset, lineWidthIgnoringTrailingWhitespace, lineHeight);
+    labelLine.backgroundRect.inflateX(attachmentLabelBackgroundPadding);
+    labelLine.backgroundRect = encloseRectToDevicePixels(labelLine.backgroundRect, attachment.document().deviceScaleFactor());
+
+    // If the text rects are close in size, the curved enclosing background won't
+    // look right, so make them the same exact size.
+    if (!lines.isEmpty()) {
+        float previousBackgroundRectWidth = lines.last().backgroundRect.width();
+        if (fabs(labelLine.backgroundRect.width() - previousBackgroundRectWidth) &lt; attachmentLabelBackgroundRadius * 4) {
+            float newBackgroundRectWidth = std::max(previousBackgroundRectWidth, labelLine.backgroundRect.width());
+            labelLine.backgroundRect.inflateX((newBackgroundRectWidth - labelLine.backgroundRect.width()) / 2);
+            lines.last().backgroundRect.inflateX((newBackgroundRectWidth - previousBackgroundRectWidth) / 2);
+        }
+    }
+
+    lines.append(labelLine);
+}
+
+void AttachmentLayout::layOutLabel(const RenderAttachment&amp; attachment)
+{
</ins><span class="cx">     File* file = attachment.attachmentElement().file();
</span><span class="cx"> 
</span><span class="cx">     labelFont = adoptCF(CTFontCreateUIFontForLanguage(kCTFontSystemFontType, attachmentLabelFontSize, nullptr));
</span><del>-    labelFontCascade = FontCascade(FontPlatformData(labelFont.get(), attachmentLabelFontSize));
-
</del><span class="cx">     String filename = file ? file-&gt;name() : String();
</span><del>-    labelTextRun = std::make_unique&lt;TextRun&gt;(filename);
-    labelTextRun-&gt;setDirection(filename.defaultWritingDirection() == U_LEFT_TO_RIGHT ? LTR : RTL);
-    float textWidth = labelFontCascade.width(*labelTextRun);
-    float textHeight = labelFontCascade.fontMetrics().height();
-    float xOffset = (attachmentIconBackgroundSize / 2) - (textWidth / 2);
</del><ins>+    NSDictionary *textAttributes = @{
+        (id)kCTFontAttributeName: (id)labelFont.get(),
+        (id)kCTForegroundColorAttributeName: labelTextColorForAttachment(attachment)
+    };
+    RetainPtr&lt;NSAttributedString&gt; attributedFilename = adoptNS([[NSAttributedString alloc] initWithString:filename attributes:textAttributes]);
+    RetainPtr&lt;CTFramesetterRef&gt; labelFramesetter = adoptCF(CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedFilename.get()));
</ins><span class="cx"> 
</span><del>-    baseline = CGRound(attachmentIconBackgroundSize + attachmentIconToLabelMargin + labelFontCascade.fontMetrics().ascent());
</del><ins>+    CFRange fitRange;
+    CGSize labelTextSize = CTFramesetterSuggestFrameSizeWithConstraints(labelFramesetter.get(), CFRangeMake(0, 0), nullptr, CGSizeMake(attachmentLabelMaximumWidth, CGFLOAT_MAX), &amp;fitRange);
</ins><span class="cx"> 
</span><del>-    textRect = FloatRect(xOffset, attachmentIconBackgroundSize + attachmentIconToLabelMargin, textWidth, textHeight);
-    textBackgroundRect = textRect;
-    textBackgroundRect.inflateX(attachmentLabelBackgroundPadding);
-    textBackgroundRect = encloseRectToDevicePixels(textBackgroundRect, attachment.document().deviceScaleFactor());
</del><ins>+    RetainPtr&lt;CGPathRef&gt; labelPath = adoptCF(CGPathCreateWithRect(CGRectMake(0, 0, labelTextSize.width, labelTextSize.height), nullptr));
+    RetainPtr&lt;CTFrameRef&gt; labelFrame = adoptCF(CTFramesetterCreateFrame(labelFramesetter.get(), fitRange, labelPath.get(), nullptr));
</ins><span class="cx"> 
</span><ins>+    CFArrayRef ctLines = CTFrameGetLines(labelFrame.get());
+    CFIndex lineCount = CFArrayGetCount(ctLines);
+    if (!lineCount)
+        return;
+
+    Vector&lt;CGPoint&gt; origins(lineCount);
+    CTFrameGetLineOrigins(labelFrame.get(), CFRangeMake(0, 0), origins.data());
+
+    // Lay out and record the first (attachmentLabelMaximumLineCount - 1) lines.
+    CFIndex lineIndex = 0;
+    CGFloat yOffset = attachmentIconBackgroundSize + attachmentIconToLabelMargin;
+    for (; lineIndex &lt; std::min(attachmentLabelMaximumLineCount - 1, lineCount); ++lineIndex) {
+        CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
+        addLine(line, yOffset, origins, lineIndex, attachment);
+    }
+
+    if (lineIndex == lineCount)
+        return;
+
+    // We had text that didn't fit in the first (attachmentLabelMaximumLineCount - 1) lines.
+    // Combine it into one last line, and center-truncate it.
+    CTLineRef firstRemainingLine = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
+    CFIndex remainingRangeStart = CTLineGetStringRange(firstRemainingLine).location;
+    NSRange remainingRange = NSMakeRange(remainingRangeStart, [attributedFilename length] - remainingRangeStart);
+    NSAttributedString *remainingString = [attributedFilename attributedSubstringFromRange:remainingRange];
+    RetainPtr&lt;CTLineRef&gt; remainingLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)remainingString));
+    RetainPtr&lt;NSAttributedString&gt; ellipsisString = adoptNS([[NSAttributedString alloc] initWithString:@&quot;\u2026&quot; attributes:textAttributes]);
+    RetainPtr&lt;CTLineRef&gt; ellipsisLine = adoptCF(CTLineCreateWithAttributedString((CFAttributedStringRef)ellipsisString.get()));
+    RetainPtr&lt;CTLineRef&gt; truncatedLine = adoptCF(CTLineCreateTruncatedLine(remainingLine.get(), attachmentLabelMaximumWidth, kCTLineTruncationMiddle, ellipsisLine.get()));
+
+    if (!truncatedLine)
+        truncatedLine = remainingLine;
+
+    addLine(truncatedLine.get(), yOffset, origins, lineIndex, attachment);
+}
+
+AttachmentLayout::AttachmentLayout(const RenderAttachment&amp; attachment)
+{
+    layOutLabel(attachment);
+
+    baseline = CGRound(attachmentIconBackgroundSize + attachmentIconToLabelMargin + CTFontGetAscent(labelFont.get()));
+
</ins><span class="cx">     iconBackgroundRect = FloatRect(0, 0, attachmentIconBackgroundSize, attachmentIconBackgroundSize);
</span><span class="cx"> 
</span><span class="cx">     iconRect = iconBackgroundRect;
</span><span class="lines">@@ -2138,7 +2231,8 @@
</span><span class="cx">     iconRect.move(attachmentIconBackgroundPadding / 2, attachmentIconBackgroundPadding / 2);
</span><span class="cx"> 
</span><span class="cx">     attachmentRect = iconBackgroundRect;
</span><del>-    attachmentRect.unite(textBackgroundRect);
</del><ins>+    for (const auto&amp; line : lines)
+        attachmentRect.unite(line.backgroundRect);
</ins><span class="cx">     attachmentRect.inflate(attachmentMargin);
</span><span class="cx">     attachmentRect = encloseRectToDevicePixels(attachmentRect, attachment.document().deviceScaleFactor());
</span><span class="cx"> }
</span><span class="lines">@@ -2202,11 +2296,136 @@
</span><span class="cx">     context.drawNativeImage(icon.get(), iconSizeInPoints, ColorSpaceDeviceRGB, layout.iconRect, FloatRect(FloatPoint(), iconSizeInPoints));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderThemeMac::paintAttachmentLabelBackground(const RenderAttachment&amp; attachment, GraphicsContext&amp; context, AttachmentLayout&amp; layout) const
</del><ins>+static void addAttachmentLabelBackgroundRightCorner(Path&amp; path, const FloatRect* fromRect, const FloatRect* toRect)
</ins><span class="cx"> {
</span><ins>+    FloatSize horizontalRadius(attachmentLabelBackgroundRadius, 0);
+    FloatSize verticalRadius(0, attachmentLabelBackgroundRadius);
+
+    if (!fromRect) {
+        // For the first (top) rect:
+
+        path.moveTo(toRect-&gt;minXMinYCorner() + horizontalRadius);
+
+        // Across the top, towards the right.
+        path.addLineTo(toRect-&gt;maxXMinYCorner() - horizontalRadius);
+
+        // Arc the top corner.
+        path.addArcTo(toRect-&gt;maxXMinYCorner(), toRect-&gt;maxXMinYCorner() + verticalRadius, attachmentLabelBackgroundRadius);
+
+        // Down the right.
+        path.addLineTo(toRect-&gt;maxXMaxYCorner() - verticalRadius);
+    } else if (!toRect) {
+        // For the last rect:
+
+        // Arc the bottom corner.
+        path.addArcTo(fromRect-&gt;maxXMaxYCorner(), fromRect-&gt;maxXMaxYCorner() - horizontalRadius, attachmentLabelBackgroundRadius);
+    } else {
+        // For middle rects:
+
+        float widthDifference = toRect-&gt;width() - fromRect-&gt;width();
+
+        // Skip over very similar-width rects, because we can't make
+        // sensible curves between them.
+        if (fabs(widthDifference) &lt; std::numeric_limits&lt;float&gt;::epsilon())
+            return;
+
+        if (widthDifference &lt; 0) {
+            // Arc the outer corner.
+            path.addArcTo(FloatPoint(fromRect-&gt;maxX(), toRect-&gt;y()), FloatPoint(fromRect-&gt;maxX(), toRect-&gt;y()) - horizontalRadius, attachmentLabelBackgroundRadius);
+
+            // Across the bottom, towards the left.
+            path.addLineTo(toRect-&gt;maxXMinYCorner() + horizontalRadius);
+
+            // Arc the inner corner.
+            path.addArcTo(toRect-&gt;maxXMinYCorner(), toRect-&gt;maxXMinYCorner() + verticalRadius, attachmentLabelBackgroundRadius);
+        } else {
+            // Arc the inner corner.
+            path.addArcTo(FloatPoint(fromRect-&gt;maxX(), toRect-&gt;y()), FloatPoint(fromRect-&gt;maxX(), toRect-&gt;y()) + horizontalRadius, attachmentLabelBackgroundRadius);
+
+            // Across the bottom, towards the right.
+            path.addLineTo(toRect-&gt;maxXMinYCorner() - horizontalRadius);
+
+            // Arc the outer corner.
+            path.addArcTo(toRect-&gt;maxXMinYCorner(), toRect-&gt;maxXMinYCorner() + verticalRadius, attachmentLabelBackgroundRadius);
+        }
+
+        // Down the right.
+        path.addLineTo(toRect-&gt;maxXMaxYCorner() - verticalRadius);
+    }
+}
+
+static void addAttachmentLabelBackgroundLeftCorner(Path&amp; path, const FloatRect* fromRect, const FloatRect* toRect)
+{
+    FloatSize horizontalRadius(attachmentLabelBackgroundRadius, 0);
+    FloatSize verticalRadius(0, attachmentLabelBackgroundRadius);
+
+    if (!fromRect) {
+        // For the first (bottom) rect:
+
+        // Across the bottom, towards the left.
+        path.addLineTo(toRect-&gt;minXMaxYCorner() + horizontalRadius);
+
+        // Arc the bottom corner.
+        path.addArcTo(toRect-&gt;minXMaxYCorner(), toRect-&gt;minXMaxYCorner() - verticalRadius, attachmentLabelBackgroundRadius);
+
+        // Up the left.
+        path.addLineTo(toRect-&gt;minXMinYCorner() + verticalRadius);
+    } else if (!toRect) {
+        // For the last (top) rect:
+
+        // Arc the top corner.
+        path.addArcTo(fromRect-&gt;minXMinYCorner(), fromRect-&gt;minXMinYCorner() + horizontalRadius, attachmentLabelBackgroundRadius);
+    } else {
+        // For middle rects:
+        float widthDifference = toRect-&gt;width() - fromRect-&gt;width();
+
+        // Skip over very similar-width rects, because we can't make
+        // sensible curves between them.
+        if (fabs(widthDifference) &lt; std::numeric_limits&lt;float&gt;::epsilon())
+            return;
+
+        if (widthDifference &lt; 0) {
+            // Arc the inner corner.
+            path.addArcTo(FloatPoint(fromRect-&gt;x(), toRect-&gt;maxY()), FloatPoint(fromRect-&gt;x(), toRect-&gt;maxY()) + horizontalRadius, attachmentLabelBackgroundRadius);
+
+            // Across the bottom, towards the right.
+            path.addLineTo(toRect-&gt;minXMaxYCorner() - horizontalRadius);
+
+            // Arc the outer corner.
+            path.addArcTo(toRect-&gt;minXMaxYCorner(), toRect-&gt;minXMaxYCorner() - verticalRadius, attachmentLabelBackgroundRadius);
+        } else {
+            // Arc the outer corner.
+            path.addArcTo(FloatPoint(fromRect-&gt;x(), toRect-&gt;maxY()), FloatPoint(fromRect-&gt;x(), toRect-&gt;maxY()) - horizontalRadius, attachmentLabelBackgroundRadius);
+
+            // Across the bottom, towards the left.
+            path.addLineTo(toRect-&gt;minXMaxYCorner() + horizontalRadius);
+
+            // Arc the inner corner.
+            path.addArcTo(toRect-&gt;minXMaxYCorner(), toRect-&gt;minXMaxYCorner() - verticalRadius, attachmentLabelBackgroundRadius);
+        }
+        
+        // Up the right.
+        path.addLineTo(toRect-&gt;minXMinYCorner() + verticalRadius);
+    }
+}
+
+static void paintAttachmentLabelBackground(const RenderAttachment&amp; attachment, GraphicsContext&amp; context, AttachmentLayout&amp; layout)
+{
+    if (layout.lines.isEmpty())
+        return;
+
</ins><span class="cx">     Path backgroundPath;
</span><del>-    backgroundPath.addRoundedRect(layout.textBackgroundRect, FloatSize(attachmentLabelBackgroundRadius, attachmentLabelBackgroundRadius));
</del><span class="cx"> 
</span><ins>+    for (size_t i = 0; i &lt;= layout.lines.size(); ++i)
+        addAttachmentLabelBackgroundRightCorner(backgroundPath, i ? &amp;layout.lines[i - 1].backgroundRect : nullptr, i &lt; layout.lines.size() ? &amp;layout.lines[i].backgroundRect : nullptr);
+
+    for (size_t i = 0; i &lt;= layout.lines.size(); ++i) {
+        size_t reverseIndex = layout.lines.size() - i;
+        addAttachmentLabelBackgroundLeftCorner(backgroundPath, reverseIndex &lt; layout.lines.size() ? &amp;layout.lines[reverseIndex].backgroundRect : nullptr, reverseIndex ? &amp;layout.lines[reverseIndex - 1].backgroundRect : nullptr);
+    }
+
+    backgroundPath.closeSubpath();
+
</ins><span class="cx">     Color backgroundColor;
</span><span class="cx">     if (attachment.frame().selection().isFocusedAndActive())
</span><span class="cx">         backgroundColor = convertNSColorToColor([NSColor alternateSelectedControlColor]);
</span><span class="lines">@@ -2217,22 +2436,17 @@
</span><span class="cx">     context.fillPath(backgroundPath);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderThemeMac::paintAttachmentLabel(const RenderAttachment&amp; attachment, GraphicsContext&amp; context, AttachmentLayout&amp; layout, bool useSelectedStyle) const
</del><ins>+static void paintAttachmentLabel(const RenderAttachment&amp;, GraphicsContext&amp; context, AttachmentLayout&amp; layout) 
</ins><span class="cx"> {
</span><del>-    FloatPoint textLocation = layout.textRect.minXMaxYCorner();
-    textLocation.move(0, -layout.labelFontCascade.fontMetrics().descent());
</del><ins>+    for (const auto&amp; line : layout.lines) {
+        GraphicsContextStateSaver saver(context);
</ins><span class="cx"> 
</span><del>-    Color textColor;
-    if (useSelectedStyle) {
-        if (attachment.frame().selection().isFocusedAndActive())
-            textColor = convertNSColorToColor([NSColor alternateSelectedControlTextColor]);
-        else
-            textColor = attachmentLabelInactiveTextColor();
-    } else
-        textColor = Color::black;
</del><ins>+        context.translate(toFloatSize(line.origin));
+        context.scale(FloatSize(1, -1));
</ins><span class="cx"> 
</span><del>-    context.setFillColor(textColor, ColorSpaceDeviceRGB);
-    context.drawBidiText(layout.labelFontCascade, *layout.labelTextRun, textLocation);
</del><ins>+        CGContextSetTextMatrix(context.platformContext(), CGAffineTransformIdentity);
+        CTLineDraw(line.line.get(), context.platformContext());
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool RenderThemeMac::paintAttachment(const RenderObject&amp; renderer, const PaintInfo&amp; paintInfo, const IntRect&amp; paintRect)
</span><span class="lines">@@ -2258,7 +2472,7 @@
</span><span class="cx">     paintAttachmentIcon(attachment, context, layout);
</span><span class="cx">     if (useSelectedStyle)
</span><span class="cx">         paintAttachmentLabelBackground(attachment, context, layout);
</span><del>-    paintAttachmentLabel(attachment, context, layout, useSelectedStyle);
</del><ins>+    paintAttachmentLabel(attachment, context, layout);
</ins><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>