<!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>[210399] 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/210399">210399</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2017-01-05 17:04:34 -0800 (Thu, 05 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Carets can split up marriages and families
https://bugs.webkit.org/show_bug.cgi?id=166711
&lt;rdar://problem/29019333&gt;

Reviewed by Alex Christensen.

Source/WTF:

There are four code points which should be allowed to accept emoji modifiers:
- U+1F46A FAMILY
- U+1F46B MAN AND WOMAN HOLDING HANDS
- U+1F46C TWO MEN HOLDING HANDS
- U+1F46D TWO WOMEN HOLDING HANDS

Even though macOS's and iOS's emoji keyboard don't allow users to actually type
these combinations, we may still receive them from other platforms. We should
therefore treat these as joining sequences. Rendering isn't a problem because
the fonts accept the emoji modifiers, but our caret placement code isn't educated
about it. Currently, we treat these emoji groups as ligatures, allowing the caret
to be placed between the two code points, which visually shows as being horizontally
centered in the glyph. Instead, we should treat these code points as accepting
emoji modifiers.

Tests: editing/caret/emoji.html
       editing/caret/ios/emoji.html

* wtf/text/TextBreakIterator.cpp:
(WTF::cursorMovementIterator):

LayoutTests:

AFAICT we don't have a test where we arrow-through a set of emoji. We do
have tests where we backspace-through a set of emoji. Add a new test for
the arrow keys.

* platform/ios/TestExpectations:
* platform/mac/editing/caret/emoji-expected.txt: Added.
* editing/caret/emoji.html: Added.
* editing/caret/ios/emoji-expected.txt: Added.
* editing/caret/ios/emoji.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorTestExpectations">trunk/LayoutTests/platform/ios-simulator/TestExpectations</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextTextBreakIteratorcpp">trunk/Source/WTF/wtf/text/TextBreakIterator.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingcaretemojihtml">trunk/LayoutTests/editing/caret/emoji.html</a></li>
<li><a href="#trunkLayoutTestseditingcaretiosemojiexpectedhtml">trunk/LayoutTests/editing/caret/ios/emoji-expected.html</a></li>
<li><a href="#trunkLayoutTestseditingcaretiosemojihtml">trunk/LayoutTests/editing/caret/ios/emoji.html</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingcaretemojiexpectedtxt">trunk/LayoutTests/platform/mac/editing/caret/emoji-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (210398 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-06 00:24:11 UTC (rev 210398)
+++ trunk/LayoutTests/ChangeLog        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2017-01-05  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Carets can split up marriages and families
+        https://bugs.webkit.org/show_bug.cgi?id=166711
+        &lt;rdar://problem/29019333&gt;
+
+        Reviewed by Alex Christensen.
+
+        AFAICT we don't have a test where we arrow-through a set of emoji. We do
+        have tests where we backspace-through a set of emoji. Add a new test for
+        the arrow keys.
+
+        * platform/ios/TestExpectations:
+        * platform/mac/editing/caret/emoji-expected.txt: Added.
+        * editing/caret/emoji.html: Added.
+        * editing/caret/ios/emoji-expected.txt: Added.
+        * editing/caret/ios/emoji.html: Added.
+
</ins><span class="cx"> 2017-01-05  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rebaseline fast/canvas/webgl/context-creation-attributes.html after r210372.
</span></span></pre></div>
<a id="trunkLayoutTestseditingcaretemojihtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/caret/emoji.html (0 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/caret/emoji.html                                (rev 0)
+++ trunk/LayoutTests/editing/caret/emoji.html        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;test&quot; contenteditable=&quot;true&quot;&gt;&amp;#x1f46b;&amp;#x1f46b;&amp;#x1f3fb;&amp;#x1f46b;&amp;#x1f3ff;&amp;#x1f46c;&amp;#x1f46c;&amp;#x1f3fb;&amp;#x1f46c;&amp;#x1f3ff;&amp;#x1f46d;&amp;#x1f46d;&amp;#x1f3fb;&amp;#x1f46d;&amp;#x1f3ff;&amp;#x1f46a;&amp;#x1f46a;&amp;#x1f3fb;&amp;#x1f46a;&amp;#x1f3ff;
+&lt;/div&gt;
+&lt;script src=&quot;../../resources/dump-as-markup.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+Markup.description(&quot;This test verifies that deletions are correct over emoji groups and emoji with variations&quot;);
+var testElement = document.getElementById('test');
+getSelection().setBaseAndExtent(testElement.firstChild, testElement.firstChild.length, testElement.firstChild, testElement.firstChild.length);
+Markup.dump(&quot;test&quot;);
+if (window.eventSender) {
+        while (window.getSelection().getRangeAt(0).startOffset &gt; 0) {
+            eventSender.keyDown(&quot;leftArrow&quot;);
+            Markup.dump(&quot;test&quot;);
+        }
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestseditingcaretiosemojiexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/caret/ios/emoji-expected.html (0 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/caret/ios/emoji-expected.html                                (rev 0)
+++ trunk/LayoutTests/editing/caret/ios/emoji-expected.html        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS currentWidth is within 1 of 15
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestseditingcaretiosemojihtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/caret/ios/emoji.html (0 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/caret/ios/emoji.html                                (rev 0)
+++ trunk/LayoutTests/editing/caret/ios/emoji.html        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+&lt;!DOCTYPE html&gt; &lt;!-- webkit-test-runner [ useFlexibleViewport=true ] --&gt;
+&lt;html&gt;
+&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, user-scalable=no&quot;&gt;
+&lt;head&gt;
+    &lt;script src=&quot;../../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+    &lt;style&gt;
+        body {
+            margin: 0;
+        }
+
+        input {
+            width: 100%;
+            height: 50px;
+            position: absolute;
+            left: 0;
+            top: 0;
+        }
+
+        div {
+            background-image: linear-gradient(0deg, blue, red);
+            height: 4000px;
+        }
+    &lt;/style&gt;
+    &lt;script&gt;
+    window.jsTestIsAsync = true;
+
+    function tapInInputScript(tapX, tapY)
+    {
+        return `
+        var caretPositions = [];
+
+        function pressArrow() {
+            uiController.typeCharacterUsingHardwareKeyboard(&quot;leftArrow&quot;, function() {
+                uiController.doAfterNextStablePresentationUpdate(function() {
+                    var selectionRectLeft = uiController.textSelectionCaretRect.left;
+                    var caretPositionsLength = caretPositions.length;
+                    if (caretPositionsLength == 0 || caretPositions[caretPositionsLength - 1] != selectionRectLeft) {
+                        caretPositions.push(selectionRectLeft);
+                        pressArrow();
+                    } else
+                        uiController.uiScriptComplete(JSON.stringify(caretPositions));
+                });
+            });
+        };
+
+        (function() {
+            uiController.didShowKeyboardCallback = function() {
+                uiController.doAfterNextStablePresentationUpdate(function() {
+                    pressArrow();
+                });
+            };
+            uiController.singleTapAtPoint(${tapX}, ${tapY}, function() { });
+        })()`;
+    }
+
+    var pixelWidth;
+    var currentWidth;
+    function run()
+    {
+        if (!window.testRunner || !testRunner.runUIScript) {
+            description(&quot;To manually test, place the caret in the field above and use the arrow keys to make sure the carets don't appear in the middle of characters.&quot;);
+            return;
+        }
+
+        testRunner.runUIScript(tapInInputScript(window.innerWidth * 2 / 3, 30), caretPositions =&gt; {
+            caretPositions = JSON.parse(caretPositions);
+            pixelWidth = -1;
+            for (var i = 0; i &lt; caretPositions.length - 1; ++i) {
+                currentWidth = caretPositions[i] - caretPositions[i + 1];
+                if (pixelWidth == -1)
+                    pixelWidth = currentWidth;
+                else
+                    shouldBeCloseTo(&quot;currentWidth&quot;, pixelWidth, 1);
+            }
+            finishJSTest();
+        });
+    }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=run()&gt;
+    &lt;input value=&quot;&amp;#x1f46b;&amp;#x1f46b;&amp;#x1f3fb;&amp;#x1f46b;&amp;#x1f3ff;&amp;#x1f46c;&amp;#x1f46c;&amp;#x1f3fb;&amp;#x1f46c;&amp;#x1f3ff;&amp;#x1f46d;&amp;#x1f46d;&amp;#x1f3fb;&amp;#x1f46d;&amp;#x1f3ff;&amp;#x1f46a;&amp;#x1f46a;&amp;#x1f3fb;&amp;#x1f46a;&amp;#x1f3ff;&quot;&gt;&lt;/input&gt;
+    &lt;script src=&quot;../../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (210398 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/TestExpectations        2017-01-06 00:24:11 UTC (rev 210398)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -2770,3 +2770,6 @@
</span><span class="cx"> media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html [ Skip ]
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/166736 fast/scrolling/page-cache-back-overflow-scroll-restore.html [ Skip ]
</span><ins>+
+# editing/caret/ios/emoji.html is used instead.
+editing/caret/emoji.html [ Failure ]
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingcaretemojiexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/mac/editing/caret/emoji-expected.txt (0 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/caret/emoji-expected.txt                                (rev 0)
+++ trunk/LayoutTests/platform/mac/editing/caret/emoji-expected.txt        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+This test verifies that deletions are correct over emoji groups and emoji with variations
+
+Dump of markup 1:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿&lt;#selection-caret&gt;
+&quot;
+
+Dump of markup 2:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻&lt;#selection-caret&gt;πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 3:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺ&lt;#selection-caret&gt;πŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 4:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏ&lt;#selection-caret&gt;πŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 5:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»&lt;#selection-caret&gt;πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 6:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­&lt;#selection-caret&gt;πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 7:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏ&lt;#selection-caret&gt;πŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 8:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»&lt;#selection-caret&gt;πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 9:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬&lt;#selection-caret&gt;πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 10:
+| &quot;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏ&lt;#selection-caret&gt;πŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 11:
+| &quot;πŸ‘«πŸ‘«πŸ»&lt;#selection-caret&gt;πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 12:
+| &quot;πŸ‘«&lt;#selection-caret&gt;πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
+
+Dump of markup 13:
+| &quot;&lt;#selection-caret&gt;πŸ‘«πŸ‘«πŸ»πŸ‘«πŸΏπŸ‘¬πŸ‘¬πŸ»πŸ‘¬πŸΏπŸ‘­πŸ‘­πŸ»πŸ‘­πŸΏπŸ‘ͺπŸ‘ͺ🏻πŸ‘ͺ🏿
+&quot;
</ins><span class="cx">Property changes on: trunk/LayoutTests/platform/mac/editing/caret/emoji-expected.txt
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="svnkeywords"></a>
<div class="addfile"><h4>Added: svn:keywords</h4></div>
<ins>+Author Date Id Rev URL
</ins><span class="cx">\ No newline at end of property
</span><a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (210398 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-01-06 00:24:11 UTC (rev 210398)
+++ trunk/Source/WTF/ChangeLog        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2017-01-05  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Carets can split up marriages and families
+        https://bugs.webkit.org/show_bug.cgi?id=166711
+        &lt;rdar://problem/29019333&gt;
+
+        Reviewed by Alex Christensen.
+
+        There are four code points which should be allowed to accept emoji modifiers:
+        - U+1F46A FAMILY
+        - U+1F46B MAN AND WOMAN HOLDING HANDS
+        - U+1F46C TWO MEN HOLDING HANDS
+        - U+1F46D TWO WOMEN HOLDING HANDS
+
+        Even though macOS's and iOS's emoji keyboard don't allow users to actually type
+        these combinations, we may still receive them from other platforms. We should
+        therefore treat these as joining sequences. Rendering isn't a problem because
+        the fonts accept the emoji modifiers, but our caret placement code isn't educated
+        about it. Currently, we treat these emoji groups as ligatures, allowing the caret
+        to be placed between the two code points, which visually shows as being horizontally
+        centered in the glyph. Instead, we should treat these code points as accepting
+        emoji modifiers.
+
+        Tests: editing/caret/emoji.html
+               editing/caret/ios/emoji.html
+
+        * wtf/text/TextBreakIterator.cpp:
+        (WTF::cursorMovementIterator):
+
</ins><span class="cx"> 2017-01-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AutomaticThread timeout shutdown leaves a small window where notify() would think that the thread is still running
</span></span></pre></div>
<a id="trunkSourceWTFwtftextTextBreakIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/TextBreakIterator.cpp (210398 => 210399)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/TextBreakIterator.cpp        2017-01-06 00:24:11 UTC (rev 210398)
+++ trunk/Source/WTF/wtf/text/TextBreakIterator.cpp        2017-01-06 01:04:34 UTC (rev 210399)
</span><span class="lines">@@ -216,7 +216,7 @@
</span><span class="cx">         &quot;$EmojiVar = [\\uFE0F];&quot; // Emoji-style variation selector
</span><span class="cx"> #if ADDITIONAL_EMOJI_SUPPORT
</span><span class="cx">         &quot;$EmojiForSeqs = [\\u2640 \\u2642 \\u26F9 \\u2764 \\U0001F308 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA-\\U0001F3CC \\U0001F3F3 \\U0001F441 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F46F \\U0001F471 \\U0001F473 \\U0001F477 \\U0001F481-\\U0001F482 \\U0001F486-\\U0001F487 \\U0001F48B \\U0001F575 \\U0001F5E8 \\U0001F645-\\U0001F647 \\U0001F64B \\U0001F64D-\\U0001F64E \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\u2695-\\u2696 \\u2708 \\U0001F33E \\U0001F373 \\U0001F393 \\U0001F3A4 \\U0001F3A8 \\U0001F3EB \\U0001F3ED \\U0001F4BB-\\U0001F4BC \\U0001F527 \\U0001F52C \\U0001F680 \\U0001F692 \\U0001F926 \\U0001F937-\\U0001F939 \\U0001F93C-\\U0001F93E];&quot; // Emoji that participate in ZWJ sequences
</span><del>-        &quot;$EmojiForMods = [\\u261D \\u26F9 \\u270A-\\u270D \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA \\U0001F3CB \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F575 \\U0001F590 \\U0001F595 \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0 \\U0001F918 \\U0001F3C2 \\U0001F3C7 \\U0001F3CC \\U0001F574 \\U0001F57A \\U0001F6CC \\U0001F919-\\U0001F91E \\U0001F926 \\U0001F930 \\U0001F933-\\U0001F939 \\U0001F93C-\\U0001F93E] ;&quot; // Emoji that take Fitzpatrick modifiers
</del><ins>+        &quot;$EmojiForMods = [\\u261D \\u26F9 \\u270A-\\u270D \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA \\U0001F3CB \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F575 \\U0001F590 \\U0001F595 \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0 \\U0001F918 \\U0001F3C2 \\U0001F3C7 \\U0001F3CC \\U0001F574 \\U0001F57A \\U0001F6CC \\U0001F919-\\U0001F91E \\U0001F926 \\U0001F930 \\U0001F933-\\U0001F939 \\U0001F93C-\\U0001F93E] ;&quot; // Emoji that take Fitzpatrick modifiers
</ins><span class="cx"> #else
</span><span class="cx">         &quot;$EmojiForSeqs = [\\u2764 \\U0001F466-\\U0001F469 \\U0001F48B];&quot; // Emoji that participate in ZWJ sequences
</span><span class="cx">         &quot;$EmojiForMods = [\\u261D \\u270A-\\u270C \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3C7 \\U0001F3CA \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0] ;&quot; // Emoji that take Fitzpatrick modifiers
</span><span class="lines">@@ -449,7 +449,7 @@
</span><span class="cx">     &quot;$EmojiVar = \\uFE0F;&quot;
</span><span class="cx"> #if ADDITIONAL_EMOJI_SUPPORT
</span><span class="cx">     &quot;$EmojiForSeqs = [\\u2640 \\u2642 \\u26F9 \\u2764 \\U0001F308 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA-\\U0001F3CC \\U0001F3F3 \\U0001F441 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F46F \\U0001F471 \\U0001F473 \\U0001F477 \\U0001F481-\\U0001F482 \\U0001F486-\\U0001F487 \\U0001F48B \\U0001F575 \\U0001F5E8 \\U0001F645-\\U0001F647 \\U0001F64B \\U0001F64D-\\U0001F64E \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\u2695-\\u2696 \\u2708 \\U0001F33E \\U0001F373 \\U0001F393 \\U0001F3A4 \\U0001F3A8 \\U0001F3EB \\U0001F3ED \\U0001F4BB-\\U0001F4BC \\U0001F527 \\U0001F52C \\U0001F680 \\U0001F692 \\U0001F926 \\U0001F937-\\U0001F939 \\U0001F93C-\\U0001F93E];&quot; // Emoji that participate in ZWJ sequences
</span><del>-    &quot;$EmojiForMods = [\\u261D \\u26F9 \\u270A-\\u270D \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA \\U0001F3CB \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F575 \\U0001F590 \\U0001F595 \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0 \\U0001F918 \\U0001F3C2 \\U0001F3C7 \\U0001F3CC \\U0001F574 \\U0001F57A \\U0001F6CC \\U0001F919-\\U0001F91E \\U0001F926 \\U0001F930 \\U0001F933-\\U0001F939 \\U0001F93C-\\U0001F93E] ;&quot; // Emoji that take Fitzpatrick modifiers
</del><ins>+    &quot;$EmojiForMods = [\\u261D \\u26F9 \\u270A-\\u270D \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3CA \\U0001F3CB \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F575 \\U0001F590 \\U0001F595 \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0 \\U0001F918 \\U0001F3C2 \\U0001F3C7 \\U0001F3CC \\U0001F574 \\U0001F57A \\U0001F6CC \\U0001F919-\\U0001F91E \\U0001F926 \\U0001F930 \\U0001F933-\\U0001F939 \\U0001F93C-\\U0001F93E] ;&quot; // Emoji that take Fitzpatrick modifiers
</ins><span class="cx"> #else
</span><span class="cx">     &quot;$EmojiForSeqs = [\\u2764 \\U0001F466-\\U0001F469 \\U0001F48B];&quot;
</span><span class="cx">     &quot;$EmojiForMods = [\\u261D \\u270A-\\u270C \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3C7 \\U0001F3CA \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F466-\\U0001F469 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F596 \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6A3 \\U0001F6B4-\\U0001F6B6 \\U0001F6C0] ;&quot; // Emoji that take Fitzpatrick modifiers
</span></span></pre>
</div>
</div>

</body>
</html>