Composition highlight rects should be rounded and inset
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Feb 2020 23:16:52 +0000 (23:16 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Feb 2020 23:16:52 +0000 (23:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=207655
<rdar://problem/59362474>

Reviewed by Tim Horton.

Source/WebCore:

Apply a couple of minor adjustments to the appearance of composition highlight rects that appear behind marked
text, in the case where the client specifies attributed marked text with background colors.

Test: editing/input/composition-highlights.html

* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paintMarkedTextBackground):
(WebCore::InlineTextBox::paintCompositionBackground):

In the case where custom composition rects are specified, add a half-pixel inset to all sides of the background
rect, and add a slight corner radius around each background rect.

* rendering/InlineTextBox.h:

Source/WebKit:

Stitch adjacent highlight rects together if they have the same highlight color; this minimizes the number of
composition highlight rects we hand to the web process when changing the marked text.

* UIProcess/ios/WKContentViewInteraction.mm:
(compositionHighlights):

LayoutTests:

Make this existing layout test work with the new composition highlight appearance by covering up the edges of
the composition highlight rect with a black border. Due to subpixel insets around the composition highlight
rect, the reference image would be offset by a half pixel without this change (even when changing the spans to
have a `border-radius`).

* editing/input/composition-highlights-expected.html:
* editing/input/composition-highlights.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@256485 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/input/composition-highlights-expected.html
LayoutTests/editing/input/composition-highlights.html
Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/InlineTextBox.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

index bdd840e..afa64f1 100644 (file)
@@ -1,3 +1,19 @@
+2020-02-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Composition highlight rects should be rounded and inset
+        https://bugs.webkit.org/show_bug.cgi?id=207655
+        <rdar://problem/59362474>
+
+        Reviewed by Tim Horton.
+
+        Make this existing layout test work with the new composition highlight appearance by covering up the edges of
+        the composition highlight rect with a black border. Due to subpixel insets around the composition highlight
+        rect, the reference image would be offset by a half pixel without this change (even when changing the spans to
+        have a `border-radius`).
+
+        * editing/input/composition-highlights-expected.html:
+        * editing/input/composition-highlights.html:
+
 2020-02-12  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r256463.
index ea54d40..c95b245 100644 (file)
@@ -3,15 +3,59 @@
 <head>
 <style>
 div[contenteditable] {
+    top: 0;
+    left: 0;
+    position: absolute;
     font-size: 20px;
 }
+
+.container {
+    position: relative;
+}
+
+#red, #green, #blue {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    z-index: -1;
+    box-sizing: border-box;
+}
+
 #red { background-color: #FF000033; }
 #green { background-color: #00FF0033; }
 #blue { background-color: #0000FF33; }
+
+#overlay {
+    position: fixed;
+    font-size: 20px;
+    visibility: hidden;
+    top: 0;
+    left: 0;
+}
+
+.container {
+    position: relative;
+}
+
+.box {
+    visibility: visible;
+    width: calc(100% + 4px);
+    height: calc(100% + 4px);
+    border: 4px solid black;
+    box-sizing: border-box;
+    left: -2px;
+    top: -2px;
+    position: absolute;
+}
+
+.description {
+    margin-top: 100px;
+}
 </style>
 </head>
 <body>
-This test verifies that highlights can be specified when setting marked text.
-<div contenteditable>Test&nbsp;<span id="red">one</span><span id="green">two</span><span id="blue">three</span></div>
+<div contenteditable>Test&nbsp;<span class="container"><span id="red"></span>one</span><span class="container"><span id="green"></span>two</span><span class="container"><span id="blue"></span>three</span></div>
+<p class="description">This test verifies that highlights can be specified when setting marked text.</p>
+<div id="overlay">Test&nbsp;<span class="container"><span class="box"></span>one</span><span class="container"><span class="box"></span>two</span><span class="container"><span class="box"></span>three</span></div>
 </body>
 </html>
index b6d13b2..a473070 100644 (file)
@@ -3,15 +3,46 @@
 <head>
 <style>
 div[contenteditable] {
+    top: 0;
+    left: 0;
+    position: absolute;
     font-size: 20px;
     outline: none;
     caret-color: transparent;
 }
+
+#overlay {
+    position: fixed;
+    font-size: 20px;
+    visibility: hidden;
+    top: 0;
+    left: 0;
+}
+
+.container {
+    position: relative;
+}
+
+.box {
+    visibility: visible;
+    width: calc(100% + 4px);
+    height: calc(100% + 4px);
+    border: 4px solid black;
+    box-sizing: border-box;
+    left: -2px;
+    top: -2px;
+    position: absolute;
+}
+
+.description {
+    margin-top: 100px;
+}
 </style>
 </head>
 <body>
-This test verifies that highlights can be specified when setting marked text.
 <div contenteditable>Test&nbsp;</div>
+<p class="description">This test verifies that highlights can be specified when setting marked text.</p>
+<div id="overlay">Test&nbsp;<span class="container"><span class="box"></span>one</span><span class="container"><span class="box"></span>two</span><span class="container"><span class="box"></span>three</span></div>
 
 <script>
 const editor = document.querySelector("div[contenteditable]");
index 8059000..f4d7c2f 100644 (file)
@@ -1,3 +1,25 @@
+2020-02-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Composition highlight rects should be rounded and inset
+        https://bugs.webkit.org/show_bug.cgi?id=207655
+        <rdar://problem/59362474>
+
+        Reviewed by Tim Horton.
+
+        Apply a couple of minor adjustments to the appearance of composition highlight rects that appear behind marked
+        text, in the case where the client specifies attributed marked text with background colors.
+
+        Test: editing/input/composition-highlights.html
+
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::paintMarkedTextBackground):
+        (WebCore::InlineTextBox::paintCompositionBackground):
+
+        In the case where custom composition rects are specified, add a half-pixel inset to all sides of the background
+        rect, and add a slight corner radius around each background rect.
+
+        * rendering/InlineTextBox.h:
+
 2020-02-12  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r256463.
index 407c819..9062d95 100644 (file)
@@ -1110,7 +1110,7 @@ void InlineTextBox::paintMarkedTexts(PaintInfo& paintInfo, TextPaintPhase phase,
     }
 }
 
-void InlineTextBox::paintMarkedTextBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin, const Color& color, unsigned clampedStartOffset, unsigned clampedEndOffset)
+void InlineTextBox::paintMarkedTextBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin, const Color& color, unsigned clampedStartOffset, unsigned clampedEndOffset, MarkedTextBackgroundStyle style)
 {
     if (clampedStartOffset >= clampedEndOffset)
         return;
@@ -1136,7 +1136,15 @@ void InlineTextBox::paintMarkedTextBackground(PaintInfo& paintInfo, const FloatP
     lineFont().adjustSelectionRectForText(textRun, selectionRect, clampedStartOffset, clampedEndOffset);
 
     // FIXME: Support painting combined text. See <https://bugs.webkit.org/show_bug.cgi?id=180993>.
-    context.fillRect(snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), textRun.ltr()), color);
+    auto backgroundRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), textRun.ltr());
+    if (style == MarkedTextBackgroundStyle::Rounded) {
+        backgroundRect.expand(-1, -1);
+        backgroundRect.move(0.5, 0.5);
+        context.fillRoundedRect(FloatRoundedRect { backgroundRect, FloatRoundedRect::Radii { 2 } }, color);
+        return;
+    }
+
+    context.fillRect(backgroundRect, color);
 }
 
 void InlineTextBox::paintMarkedTextForeground(PaintInfo& paintInfo, const FloatRect& boxRect, const StyledMarkedText& markedText)
@@ -1251,7 +1259,7 @@ void InlineTextBox::paintCompositionBackground(PaintInfo& paintInfo, const Float
         if (highlight.startOffset >= end())
             break;
 
-        paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedOffset(highlight.startOffset), clampedOffset(highlight.endOffset));
+        paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedOffset(highlight.startOffset), clampedOffset(highlight.endOffset), MarkedTextBackgroundStyle::Rounded);
 
         if (highlight.endOffset > end())
             break;
index 42d7455..8784d85 100644 (file)
@@ -193,7 +193,8 @@ private:
     void paintCompositionUnderlines(PaintInfo&, const FloatPoint& boxOrigin) const;
     void paintCompositionUnderline(PaintInfo&, const FloatPoint& boxOrigin, const CompositionUnderline&) const;
 
-    void paintMarkedTextBackground(PaintInfo&, const FloatPoint& boxOrigin, const Color&, unsigned clampedStartOffset, unsigned clampedEndOffset);
+    enum class MarkedTextBackgroundStyle : bool { Default, Rounded };
+    void paintMarkedTextBackground(PaintInfo&, const FloatPoint& boxOrigin, const Color&, unsigned clampedStartOffset, unsigned clampedEndOffset, MarkedTextBackgroundStyle = MarkedTextBackgroundStyle::Default);
     void paintMarkedTextForeground(PaintInfo&, const FloatRect& boxRect, const StyledMarkedText&);
     void paintMarkedTextDecoration(PaintInfo&, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText&);
 
index afadd4c..6a178d9 100644 (file)
@@ -1,3 +1,17 @@
+2020-02-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Composition highlight rects should be rounded and inset
+        https://bugs.webkit.org/show_bug.cgi?id=207655
+        <rdar://problem/59362474>
+
+        Reviewed by Tim Horton.
+
+        Stitch adjacent highlight rects together if they have the same highlight color; this minimizes the number of
+        composition highlight rects we hand to the web process when changing the marked text.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (compositionHighlights):
+
 2020-02-12  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r256463.
index 6c6622c..f4c095d 100644 (file)
@@ -4543,7 +4543,25 @@ static Vector<WebCore::CompositionHighlight> compositionHighlights(NSAttributedS
             highlightColor = WebCore::colorFromUIColor(uiColor);
         highlights.append({ static_cast<unsigned>(range.location), static_cast<unsigned>(NSMaxRange(range)), highlightColor });
     }];
-    return highlights;
+
+    std::sort(highlights.begin(), highlights.end(), [](auto& a, auto& b) {
+        if (a.startOffset < b.startOffset)
+            return true;
+        if (a.startOffset > b.startOffset)
+            return false;
+        return a.endOffset < b.endOffset;
+    });
+
+    Vector<WebCore::CompositionHighlight> mergedHighlights;
+    mergedHighlights.reserveInitialCapacity(highlights.size());
+    for (auto& highlight : highlights) {
+        if (mergedHighlights.isEmpty() || mergedHighlights.last().color != highlight.color)
+            mergedHighlights.append(highlight);
+        else
+            mergedHighlights.last().endOffset = highlight.endOffset;
+    }
+
+    return mergedHighlights;
 }
 
 - (void)setAttributedMarkedText:(NSAttributedString *)markedText selectedRange:(NSRange)selectedRange