Add support for specifying background colors when setting marked text
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Feb 2020 00:44:07 +0000 (00:44 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Feb 2020 00:44:07 +0000 (00:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=207065
<rdar://problem/57876140>

Reviewed by Tim Horton.

Source/WebCore:

Add support for rendering custom highlights (background colors) behind marked text in WebCore. To do this, we
plumb a Vector of CompositionHighlights alongside the Vector of CompositionUnderlines to Editor. At paint time,
we then consult this highlight data to determine which ranges of text in the composition should paint using
custom background colors.

Note that in the future, we should consider refactoring both composition underlines and highlights to use the
MarkedText mechanism for decorating ranges of text instead.

Test: editing/input/composition-highlights.html

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
* editing/CompositionHighlight.h: Added.
(WebCore::CompositionHighlight::CompositionHighlight):
(WebCore::CompositionHighlight::encode const):
(WebCore::CompositionHighlight::decode):

Add CompositionHighlight, which represents a range in the composition that should be highlighted with a given
background color.

* editing/Editor.cpp:
(WebCore::Editor::clear):
(WebCore::Editor::setComposition):

Add logic for clearing and updating m_customCompositionHighlights.

* editing/Editor.h:
(WebCore::Editor::compositionUsesCustomHighlights const):
(WebCore::Editor::customCompositionHighlights const):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paintCompositionBackground):

If custom composition highlights are given, use those when painting the composition background; otherwise,
default to painting the entire composition range using `Color::compositionFill`.

Source/WebCore/PAL:

Add an SPI soft-linking declaration for NSMarkedClauseSegmentAttributeName.

* pal/spi/cocoa/NSAttributedStringSPI.h:

Source/WebKit:

Implement -setAttributedMarkedText:selectedRange: on WKContentView, and have it extract highlight color
information from the given attributed string. Plumb this through to the web process by serializing and
deserializing `WebCore::CompositionHighlight`s.

* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::setMarkedText):
* UIProcess/WebPageProxy.cpp:
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(compositionHighlights):

For each marked text clause, grab the specified background color (defaulting to Color::compositionFill) and use
it to create a list of CompositionHighlights.

(-[WKContentView setAttributedMarkedText:selectedRange:]):
(-[WKContentView setMarkedText:selectedRange:]):
(-[WKContentView _setMarkedText:highlights:selectedRange:]):
* WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
(WKBundlePageSetComposition):

Add testing support for specifying highlight ranges when setting marked text.

* WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h:
* WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp:
(WebKit::WebEditorClient::didDispatchInputMethodKeydown):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::setCompositionForTesting):
(WebKit::WebPage::setCompositionAsync):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Source/WebKitLegacy/mac:

Adjust some call sites of Editor::setComposition().

* WebView/WebFrame.mm:
(-[WebFrame setMarkedText:selectedRange:]):
(-[WebFrame setMarkedText:forCandidates:]):
* WebView/WebHTMLView.mm:
(-[WebHTMLView setMarkedText:selectedRange:]):

Source/WebKitLegacy/win:

Adjust some call sites of Editor::setComposition().

* WebView.cpp:
(WebView::onIMEComposition):
(WebView::setCompositionForTesting):

Tools:

Add support in WebKitTestRunner for specifying a list of highlight ranges when setting marked text. This comes
in the form of an additional argument to TextInputController::setMarkedText, which contains an array of objects,
each describing one range (in the composition) to highlight.

* DumpRenderTree/ios/TextInputControllerIOS.m:
(+[TextInputController isSelectorExcludedFromWebScript:]):
(+[TextInputController webScriptNameForSelector:]):
(-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:highlights:]):
(-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:]): Deleted.
* DumpRenderTree/mac/TextInputControllerMac.m:
(+[TextInputController isSelectorExcludedFromWebScript:]):
(+[TextInputController webScriptNameForSelector:]):
(-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:highlights:]):
(-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:]): Deleted.
* WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl:
* WebKitTestRunner/InjectedBundle/TextInputController.cpp:
(WTR::arrayLength):
(WTR::createCompositionHighlightData):

Add logic to convert a given JSObject containing the composition highlight information into a WKArrayRef, which
is then passed into WebKit via WKBundlePageSetComposition.

(WTR::TextInputController::setMarkedText):
* WebKitTestRunner/InjectedBundle/TextInputController.h:

LayoutTests:

Add a test to check that highlighting different parts of a composition range results in the same behavior as
applying background colors using CSS. This test is currently only supported in WebKit2.

* TestExpectations:
* editing/input/composition-highlights-expected.html: Added.
* editing/input/composition-highlights.html: Added.
* platform/wk2/TestExpectations:

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

36 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/editing/input/composition-highlights-expected.html [new file with mode: 0644]
LayoutTests/editing/input/composition-highlights.html [new file with mode: 0644]
LayoutTests/platform/wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cocoa/NSAttributedStringSPI.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/editing/CompositionHighlight.h [new file with mode: 0644]
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/Editor.h
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp
Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h
Source/WebKit/WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebFrame.mm
Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebView.cpp
Tools/ChangeLog
Tools/DumpRenderTree/ios/TextInputControllerIOS.m
Tools/DumpRenderTree/mac/TextInputControllerMac.m
Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl
Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp
Tools/WebKitTestRunner/InjectedBundle/TextInputController.h

index 4b13f7b..41fa894 100644 (file)
@@ -1,3 +1,19 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Add a test to check that highlighting different parts of a composition range results in the same behavior as
+        applying background colors using CSS. This test is currently only supported in WebKit2.
+
+        * TestExpectations:
+        * editing/input/composition-highlights-expected.html: Added.
+        * editing/input/composition-highlights.html: Added.
+        * platform/wk2/TestExpectations:
+
 2020-01-31  Justin Fan  <justin_fan@apple.com>
 
         [WebGL] Revert logging added to investigate 205757
index bc80a15..711b32c 100644 (file)
@@ -75,6 +75,9 @@ compositing/layer-creation/clipping-scope [ Skip ]
 printing/printing-events.html [ Skip ]
 fast/forms/enterkeyhint-attribute-values.html [ Skip ]
 
+# Highlighting marked text ranges from layout tests is only supported in WebKit2.
+editing/input/composition-highlights.html [ Skip ]
+
 http/tests/security/xss-DENIED-xsl-external-entity-no-logging.xml [ Skip ]
 
 # window.showModalDialog is only tested in DumpRenderTree on Mac.
diff --git a/LayoutTests/editing/input/composition-highlights-expected.html b/LayoutTests/editing/input/composition-highlights-expected.html
new file mode 100644 (file)
index 0000000..dacf845
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div[contenteditable] {
+    font-size: 20px;
+}
+#red { background-color: #FF000033; }
+#green { background-color: #00FF0033; }
+#blue { background-color: #0000FF33; }
+</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>
+</body>
+</html>
diff --git a/LayoutTests/editing/input/composition-highlights.html b/LayoutTests/editing/input/composition-highlights.html
new file mode 100644 (file)
index 0000000..84f2294
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div[contenteditable] {
+    font-size: 20px;
+    outline: none;
+    caret-color: transparent;
+}
+</style>
+</head>
+<body>
+This test verifies that highlights can be specified when setting marked text.
+<div contenteditable>Test:&nbsp;</div>
+
+<script>
+const editor = document.querySelector("div[contenteditable]");
+editor.focus();
+getSelection().setPosition(editor, 1);
+
+if (window.textInputController) {
+    textInputController.setMarkedText("onetwothree", 11, 11, true, [
+        { from: 0, length: 3, color: "#FF000033" },
+        { from: 3, length: 3, color: "#00FF0033" },
+        { from: 6, length: 5, color: "#0000FF33" }
+    ]);
+}
+</script>
+</body>
+</html>
index 8e259ed..906a91d 100644 (file)
@@ -768,6 +768,9 @@ inspector/runtime/callFunctionOn-emulateUserGesture-userIsInteracting.html [ Pas
 # Target domain is only present in WebKit2.
 http/tests/inspector/target [ Pass ]
 
+# Highlighting marked text ranges from layout tests is only supported in WebKit2.
+editing/input/composition-highlights.html [ Pass ]
+
 ### END OF (5) Progressions, expected successes that are expected failures in WebKit1.
 ########################################
 
index 0e77a11..86c0b8a 100644 (file)
@@ -1,3 +1,46 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Add support for rendering custom highlights (background colors) behind marked text in WebCore. To do this, we
+        plumb a Vector of CompositionHighlights alongside the Vector of CompositionUnderlines to Editor. At paint time,
+        we then consult this highlight data to determine which ranges of text in the composition should paint using
+        custom background colors.
+
+        Note that in the future, we should consider refactoring both composition underlines and highlights to use the
+        MarkedText mechanism for decorating ranges of text instead.
+
+        Test: editing/input/composition-highlights.html
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * editing/CompositionHighlight.h: Added.
+        (WebCore::CompositionHighlight::CompositionHighlight):
+        (WebCore::CompositionHighlight::encode const):
+        (WebCore::CompositionHighlight::decode):
+
+        Add CompositionHighlight, which represents a range in the composition that should be highlighted with a given
+        background color.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::clear):
+        (WebCore::Editor::setComposition):
+
+        Add logic for clearing and updating m_customCompositionHighlights.
+
+        * editing/Editor.h:
+        (WebCore::Editor::compositionUsesCustomHighlights const):
+        (WebCore::Editor::customCompositionHighlights const):
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::paintCompositionBackground):
+
+        If custom composition highlights are given, use those when painting the composition background; otherwise,
+        default to painting the entire composition range using `Color::compositionFill`.
+
 2020-01-31  Justin Fan  <justin_fan@apple.com>
 
         [WebGL] Revert logging added to investigate 205757
index 54db716..52b3641 100644 (file)
@@ -483,6 +483,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     dom/messageports/MessageWithMessagePorts.h
 
     editing/ClipboardAccessPolicy.h
+    editing/CompositionHighlight.h
     editing/CompositionUnderline.h
     editing/DictationAlternative.h
     editing/DictionaryPopupInfo.h
index 0b817a1..e97e28c 100644 (file)
@@ -1,3 +1,15 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Add an SPI soft-linking declaration for NSMarkedClauseSegmentAttributeName.
+
+        * pal/spi/cocoa/NSAttributedStringSPI.h:
+
 2020-01-30  Alex Christensen  <achristensen@webkit.org>
 
         Add WKNavigationDelegate SPI to disable TLS 1.0 and 1.1
index 2a8b524..0ff3345 100644 (file)
@@ -93,6 +93,8 @@ SOFT_LINK_CONSTANT(UIFoundation, NSCocoaVersionDocumentAttribute, NSString *)
 #define NSCocoaVersionDocumentAttribute getNSCocoaVersionDocumentAttribute()
 SOFT_LINK_CONSTANT(UIFoundation, NSBackgroundColorDocumentAttribute, NSString *)
 #define NSBackgroundColorDocumentAttribute getNSBackgroundColorDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSMarkedClauseSegmentAttributeName, NSString *)
+#define NSMarkedClauseSegmentAttributeName getNSMarkedClauseSegmentAttributeName()
 
 // We don't softlink NSSuperscriptAttributeName because UIFoundation stopped exporting it.
 // This attribute is being deprecated at the API level, but internally UIFoundation
index 987a639..af04412 100644 (file)
                F440E77A233D94D70063F9AB /* NavigatorClipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F440E76F233D94D30063F9AB /* NavigatorClipboard.h */; };
                F440E77B233D94D70063F9AB /* ClipboardItem.h in Headers */ = {isa = PBXBuildFile; fileRef = F440E770233D94D40063F9AB /* ClipboardItem.h */; };
                F440E77D233D94D70063F9AB /* Clipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F440E772233D94D50063F9AB /* Clipboard.h */; };
+               F442C35923E3ADD200499582 /* CompositionHighlight.h in Headers */ = {isa = PBXBuildFile; fileRef = F442C35723E3AC5100499582 /* CompositionHighlight.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F44A5F591FED38F2007F5944 /* LegacyNSPasteboardTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F44A5F571FED3830007F5944 /* LegacyNSPasteboardTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F44EBBD91DB5D21400277334 /* StaticRange.h in Headers */ = {isa = PBXBuildFile; fileRef = F44EBBD81DB5D21400277334 /* StaticRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */ = {isa = PBXBuildFile; fileRef = F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F440E775233D94D60063F9AB /* ClipboardItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClipboardItem.cpp; sourceTree = "<group>"; };
                F440E777233D94D70063F9AB /* ClipboardItem.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ClipboardItem.idl; sourceTree = "<group>"; };
                F442850B2140412500CCDA22 /* FontAttributeChanges.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FontAttributeChanges.cpp; sourceTree = "<group>"; };
+               F442C35723E3AC5100499582 /* CompositionHighlight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompositionHighlight.h; sourceTree = "<group>"; };
                F44A5F571FED3830007F5944 /* LegacyNSPasteboardTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyNSPasteboardTypes.h; sourceTree = "<group>"; };
                F44EBBD61DB5D1B600277334 /* StaticRange.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = StaticRange.idl; sourceTree = "<group>"; };
                F44EBBD81DB5D21400277334 /* StaticRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticRange.h; sourceTree = "<group>"; };
                                7C3A91E51C963B8800D1A7E3 /* ClipboardAccessPolicy.h */,
                                93309D8D099E64910056E581 /* CompositeEditCommand.cpp */,
                                93309D8E099E64910056E581 /* CompositeEditCommand.h */,
+                               F442C35723E3AC5100499582 /* CompositionHighlight.h */,
                                2DD5A7261EBEE47D009BA597 /* CompositionUnderline.h */,
                                D0B0556709C6700100307E43 /* CreateLinkCommand.cpp */,
                                D0B0556609C6700100307E43 /* CreateLinkCommand.h */,
                                71247E371FEA5F86008C08CE /* CompositeOperation.h in Headers */,
                                7111243E216FA71100EB7B67 /* CompositeOperationOrAuto.h in Headers */,
                                79F2F5A21091939A000D87CB /* CompositionEvent.h in Headers */,
+                               F442C35923E3ADD200499582 /* CompositionHighlight.h in Headers */,
                                2DD5A7271EBEE47D009BA597 /* CompositionUnderline.h in Headers */,
                                7116E2CC1FED75DC00C06FDE /* ComputedEffectTiming.h in Headers */,
                                FD31608F12B026F700C1A359 /* Cone.h in Headers */,
diff --git a/Source/WebCore/editing/CompositionHighlight.h b/Source/WebCore/editing/CompositionHighlight.h
new file mode 100644 (file)
index 0000000..709bee4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Color.h"
+#include <wtf/Optional.h>
+
+namespace WebCore {
+
+struct CompositionHighlight {
+    CompositionHighlight() = default;
+    CompositionHighlight(unsigned startOffset, unsigned endOffset, const Color& c)
+        : startOffset(startOffset)
+        , endOffset(endOffset)
+        , color(c)
+    {
+    }
+
+    unsigned startOffset { 0 };
+    unsigned endOffset { 0 };
+    Color color { Color::compositionFill };
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static Optional<CompositionHighlight> decode(Decoder&);
+};
+
+template<class Encoder>
+void CompositionHighlight::encode(Encoder& encoder) const
+{
+    encoder << startOffset;
+    encoder << endOffset;
+    encoder << color;
+}
+
+template<class Decoder>
+Optional<CompositionHighlight> CompositionHighlight::decode(Decoder& decoder)
+{
+    Optional<unsigned> startOffset;
+    decoder >> startOffset;
+    if (!startOffset)
+        return WTF::nullopt;
+
+    Optional<unsigned> endOffset;
+    decoder >> endOffset;
+    if (!endOffset)
+        return WTF::nullopt;
+
+    Optional<Color> color;
+    decoder >> color;
+    if (!color)
+        return WTF::nullopt;
+
+    return {{ *startOffset, *endOffset, *color }};
+}
+
+} // namespace WebCore
index 87a8035..291ba6c 100644 (file)
@@ -38,6 +38,7 @@
 #include "ChangeListTypeCommand.h"
 #include "ClipboardEvent.h"
 #include "CompositionEvent.h"
+#include "CompositionHighlight.h"
 #include "CreateLinkCommand.h"
 #include "CustomUndoStep.h"
 #include "DataTransfer.h"
@@ -1217,6 +1218,7 @@ void Editor::clear()
             client->discardedComposition(&m_frame);
     }
     m_customCompositionUnderlines.clear();
+    m_customCompositionHighlights.clear();
     m_shouldStyleWithCSS = false;
     m_defaultParagraphSeparator = EditorParagraphSeparatorIsDiv;
     m_mark = { };
@@ -1970,6 +1972,7 @@ void Editor::setComposition(const String& text, SetCompositionMode mode)
 
     m_compositionNode = nullptr;
     m_customCompositionUnderlines.clear();
+    m_customCompositionHighlights.clear();
 
     if (m_frame.selection().isNone())
         return;
@@ -1991,7 +1994,7 @@ void Editor::setComposition(const String& text, SetCompositionMode mode)
     }
 }
 
-void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
+void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, const Vector<CompositionHighlight>& highlights, unsigned selectionStart, unsigned selectionEnd)
 {
     SetCompositionScope setCompositionScope(m_frame);
 
@@ -2063,6 +2066,7 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
 
     m_compositionNode = nullptr;
     m_customCompositionUnderlines.clear();
+    m_customCompositionHighlights.clear();
 
     if (!text.isEmpty()) {
         TypingCommand::insertText(document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionPending);
@@ -2084,6 +2088,11 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
                 underline.startOffset += baseOffset;
                 underline.endOffset += baseOffset;
             }
+            m_customCompositionHighlights = highlights;
+            for (auto& highlight : m_customCompositionHighlights) {
+                highlight.startOffset += baseOffset;
+                highlight.endOffset += baseOffset;
+            }
             if (baseNode->renderer())
                 baseNode->renderer()->repaint();
 
index 3c05a85..6ea8922 100644 (file)
@@ -83,6 +83,7 @@ class Text;
 class TextCheckerClient;
 class TextEvent;
 
+struct CompositionHighlight;
 struct FontAttributes;
 struct PasteboardPlainText;
 struct PasteboardURL;
@@ -355,7 +356,7 @@ public:
 
     // international text input composition
     bool hasComposition() const { return m_compositionNode; }
-    WEBCORE_EXPORT void setComposition(const String&, const Vector<CompositionUnderline>&, unsigned selectionStart, unsigned selectionEnd);
+    WEBCORE_EXPORT void setComposition(const String&, const Vector<CompositionUnderline>&, const Vector<CompositionHighlight>&, unsigned selectionStart, unsigned selectionEnd);
     WEBCORE_EXPORT void confirmComposition();
     WEBCORE_EXPORT void confirmComposition(const String&); // if no existing composition, replaces selection
     WEBCORE_EXPORT void cancelComposition();
@@ -369,6 +370,8 @@ public:
     unsigned compositionEnd() const { return m_compositionEnd; }
     bool compositionUsesCustomUnderlines() const { return !m_customCompositionUnderlines.isEmpty(); }
     const Vector<CompositionUnderline>& customCompositionUnderlines() const { return m_customCompositionUnderlines; }
+    bool compositionUsesCustomHighlights() const { return !m_customCompositionHighlights.isEmpty(); }
+    const Vector<CompositionHighlight>& customCompositionHighlights() const { return m_customCompositionHighlights; }
 
     enum class RevealSelection { No, Yes };
     WEBCORE_EXPORT void setIgnoreSelectionChanges(bool, RevealSelection shouldRevealExistingSelection = RevealSelection::Yes);
@@ -601,6 +604,7 @@ private:
     unsigned m_compositionStart;
     unsigned m_compositionEnd;
     Vector<CompositionUnderline> m_customCompositionUnderlines;
+    Vector<CompositionHighlight> m_customCompositionHighlights;
     bool m_ignoreSelectionChanges { false };
     bool m_shouldStartNewKillRingSequence { false };
     bool m_shouldStyleWithCSS { false };
index 73f8c5e..b4df6b8 100644 (file)
@@ -24,6 +24,7 @@
 #include "InlineTextBox.h"
 
 #include "BreakLines.h"
+#include "CompositionHighlight.h"
 #include "DashArray.h"
 #include "Document.h"
 #include "DocumentMarkerController.h"
@@ -1224,7 +1225,23 @@ void InlineTextBox::paintMarkedTextDecoration(PaintInfo& paintInfo, const FloatR
 
 void InlineTextBox::paintCompositionBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin)
 {
-    paintMarkedTextBackground(paintInfo, boxOrigin, Color::compositionFill, clampedOffset(renderer().frame().editor().compositionStart()), clampedOffset(renderer().frame().editor().compositionEnd()));
+    if (!renderer().frame().editor().compositionUsesCustomHighlights()) {
+        paintMarkedTextBackground(paintInfo, boxOrigin, Color::compositionFill, clampedOffset(renderer().frame().editor().compositionStart()), clampedOffset(renderer().frame().editor().compositionEnd()));
+        return;
+    }
+
+    for (auto& highlight : renderer().frame().editor().customCompositionHighlights()) {
+        if (highlight.endOffset <= m_start)
+            continue;
+
+        if (highlight.startOffset >= end())
+            break;
+
+        paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedOffset(highlight.startOffset), clampedOffset(highlight.endOffset));
+
+        if (highlight.endOffset > end())
+            break;
+    }
 }
 
 void InlineTextBox::paintCompositionUnderlines(PaintInfo& paintInfo, const FloatPoint& boxOrigin) const
index 5bbc233..a577cb3 100644 (file)
@@ -1,3 +1,42 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Implement -setAttributedMarkedText:selectedRange: on WKContentView, and have it extract highlight color
+        information from the given attributed string. Plumb this through to the web process by serializing and
+        deserializing `WebCore::CompositionHighlight`s.
+
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::setMarkedText):
+        * UIProcess/WebPageProxy.cpp:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (compositionHighlights):
+
+        For each marked text clause, grab the specified background color (defaulting to Color::compositionFill) and use
+        it to create a list of CompositionHighlights.
+
+        (-[WKContentView setAttributedMarkedText:selectedRange:]):
+        (-[WKContentView setMarkedText:selectedRange:]):
+        (-[WKContentView _setMarkedText:highlights:selectedRange:]):
+        * WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
+        (WKBundlePageSetComposition):
+
+        Add testing support for specifying highlight ranges when setting marked text.
+
+        * WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h:
+        * WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp:
+        (WebKit::WebEditorClient::didDispatchInputMethodKeydown):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::setCompositionForTesting):
+        (WebKit::WebPage::setCompositionAsync):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2020-01-31  Andy Estes  <aestes@apple.com>
 
         Unreviewed build fix after r255522.
index 8561105..027357e 100644 (file)
@@ -83,6 +83,7 @@
 #import <WebCore/AXObjectCache.h>
 #import <WebCore/ActivityState.h>
 #import <WebCore/ColorMac.h>
+#import <WebCore/CompositionHighlight.h>
 #import <WebCore/DictionaryLookup.h>
 #import <WebCore/DragData.h>
 #import <WebCore/DragItem.h>
@@ -5043,7 +5044,7 @@ void WebViewImpl::setMarkedText(id string, NSRange selectedRange, NSRange replac
         return;
     }
 
-    m_page->setCompositionAsync(text, underlines, selectedRange, replacementRange);
+    m_page->setCompositionAsync(text, underlines, { }, selectedRange, replacementRange);
 }
 
 // Synchronous NSTextInputClient is still implemented to catch spurious sync calls. Remove when that is no longer needed.
index b8f48b1..b093948 100644 (file)
 #include "WebsiteDataStore.h"
 #include <WebCore/AdClickAttribution.h>
 #include <WebCore/BitmapImage.h>
+#include <WebCore/CompositionHighlight.h>
 #include <WebCore/CrossSiteNavigationDataTransfer.h>
 #include <WebCore/DOMPasteAccess.h>
 #include <WebCore/DeprecatedGlobalSettings.h>
@@ -8499,7 +8500,7 @@ void WebPageProxy::firstRectForCharacterRangeAsync(const EditingRange& range, WT
     send(Messages::WebPage::FirstRectForCharacterRangeAsync(range, callbackID));
 }
 
-void WebPageProxy::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const EditingRange& selectionRange, const EditingRange& replacementRange)
+void WebPageProxy::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const Vector<CompositionHighlight>& highlights, const EditingRange& selectionRange, const EditingRange& replacementRange)
 {
     if (!hasRunningProcess()) {
         // If this fails, we should call -discardMarkedText on input context to notify the input method.
@@ -8507,7 +8508,7 @@ void WebPageProxy::setCompositionAsync(const String& text, const Vector<Composit
         return;
     }
 
-    send(Messages::WebPage::SetCompositionAsync(text, underlines, selectionRange, replacementRange));
+    send(Messages::WebPage::SetCompositionAsync(text, underlines, highlights, selectionRange, replacementRange));
 }
 
 void WebPageProxy::confirmCompositionAsync()
index 2432893..f33717a 100644 (file)
@@ -222,6 +222,7 @@ enum class WritingDirection : uint8_t;
 
 struct ApplicationManifest;
 struct BackForwardItemIdentifier;
+struct CompositionHighlight;
 struct ContentRuleListResults;
 struct DataListSuggestionInformation;
 struct DictionaryPopupInfo;
@@ -841,7 +842,7 @@ public:
     void getSelectedRangeAsync(WTF::Function<void (EditingRange, CallbackBase::Error)>&&);
     void characterIndexForPointAsync(const WebCore::IntPoint&, WTF::Function<void (uint64_t, CallbackBase::Error)>&&);
     void firstRectForCharacterRangeAsync(const EditingRange&, WTF::Function<void (const WebCore::IntRect&, const EditingRange&, CallbackBase::Error)>&&);
-    void setCompositionAsync(const String& text, const Vector<WebCore::CompositionUnderline>& underlines, const EditingRange& selectionRange, const EditingRange& replacementRange);
+    void setCompositionAsync(const String& text, const Vector<WebCore::CompositionUnderline>&, const Vector<WebCore::CompositionHighlight>&, const EditingRange& selectionRange, const EditingRange& replacementRange);
     void confirmCompositionAsync();
 
     void setScrollPerformanceDataCollectionEnabled(bool);
index bd675d8..dd298cb 100644 (file)
@@ -90,6 +90,8 @@
 #import <CoreText/CTFontDescriptor.h>
 #import <MobileCoreServices/UTCoreTypes.h>
 #import <WebCore/Color.h>
+#import <WebCore/ColorIOS.h>
+#import <WebCore/CompositionHighlight.h>
 #import <WebCore/DOMPasteAccess.h>
 #import <WebCore/DataDetection.h>
 #import <WebCore/FloatQuad.h>
 #import <pal/spi/cg/CoreGraphicsSPI.h>
 #import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
 #import <pal/spi/cocoa/LaunchServicesSPI.h>
+#import <pal/spi/cocoa/NSAttributedStringSPI.h>
 #import <pal/spi/ios/DataDetectorsUISPI.h>
 #import <pal/spi/ios/GraphicsServicesSPI.h>
 #import <pal/spi/ios/ManagedConfigurationSPI.h>
@@ -4519,13 +4522,41 @@ static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoi
 {
 }
 
+static Vector<WebCore::CompositionHighlight> compositionHighlights(NSAttributedString *string)
+{
+    if (!string.length)
+        return { };
+
+    Vector<WebCore::CompositionHighlight> highlights;
+    [string enumerateAttributesInRange:NSMakeRange(0, string.length) options:0 usingBlock:[&highlights](NSDictionary<NSAttributedStringKey, id> *attributes, NSRange range, BOOL *) {
+        if (!attributes[NSMarkedClauseSegmentAttributeName])
+            return;
+
+        WebCore::Color highlightColor { WebCore::Color::compositionFill };
+        if (UIColor *uiColor = attributes[NSBackgroundColorAttributeName])
+            highlightColor = WebCore::colorFromUIColor(uiColor);
+        highlights.append({ static_cast<unsigned>(range.location), static_cast<unsigned>(NSMaxRange(range)), highlightColor });
+    }];
+    return highlights;
+}
+
+- (void)setAttributedMarkedText:(NSAttributedString *)markedText selectedRange:(NSRange)selectedRange
+{
+    [self _setMarkedText:markedText.string highlights:compositionHighlights(markedText) selectedRange:selectedRange];
+}
+
 - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
 {
+    [self _setMarkedText:markedText highlights:Vector<WebCore::CompositionHighlight> { } selectedRange:selectedRange];
+}
+
+- (void)_setMarkedText:(NSString *)markedText highlights:(const Vector<WebCore::CompositionHighlight>&)highlights selectedRange:(NSRange)selectedRange
+{
 #if USE(UIKIT_KEYBOARD_ADDITIONS)
     _candidateViewNeedsUpdate = !self.hasMarkedText;
 #endif
     _markedText = markedText;
-    _page->setCompositionAsync(markedText, Vector<WebCore::CompositionUnderline>(), selectedRange, WebKit::EditingRange());
+    _page->setCompositionAsync(markedText, { }, highlights, selectedRange, { });
 }
 
 - (void)unmarkText
index c6c2a6a..385199c 100644 (file)
@@ -28,7 +28,9 @@
 #include "WKBundlePagePrivate.h"
 
 #include "APIArray.h"
+#include "APIDictionary.h"
 #include "APIFrameHandle.h"
+#include "APINumber.h"
 #include "APIString.h"
 #include "APIURL.h"
 #include "APIURLRequest.h"
@@ -58,6 +60,7 @@
 #include <WebCore/AXObjectCache.h>
 #include <WebCore/AccessibilityObjectInterface.h>
 #include <WebCore/ApplicationCacheStorage.h>
+#include <WebCore/CompositionHighlight.h>
 #include <WebCore/FocusController.h>
 #include <WebCore/Frame.h>
 #include <WebCore/Page.h>
@@ -610,9 +613,22 @@ WKArrayRef WKBundlePageCopyTrackedRepaintRects(WKBundlePageRef pageRef)
     return WebKit::toAPI(&WebKit::toImpl(pageRef)->trackedRepaintRects().leakRef());
 }
 
-void WKBundlePageSetComposition(WKBundlePageRef pageRef, WKStringRef text, int from, int length, bool suppressUnderline)
+void WKBundlePageSetComposition(WKBundlePageRef pageRef, WKStringRef text, int from, int length, bool suppressUnderline, WKArrayRef highlightData)
 {
-    WebKit::toImpl(pageRef)->setCompositionForTesting(WebKit::toWTFString(text), from, length, suppressUnderline);
+    Vector<WebCore::CompositionHighlight> highlights;
+    if (highlightData) {
+        auto* highlightDataArray = WebKit::toImpl(highlightData);
+        highlights.reserveInitialCapacity(highlightDataArray->size());
+        for (auto dictionary : highlightDataArray->elementsOfType<API::Dictionary>()) {
+            auto startOffset = static_cast<API::UInt64*>(dictionary->get("from"))->value();
+            highlights.uncheckedAppend({
+                static_cast<unsigned>(startOffset),
+                static_cast<unsigned>(startOffset + static_cast<API::UInt64*>(dictionary->get("length"))->value()),
+                WebCore::Color(static_cast<API::String*>(dictionary->get("color"))->string())
+            });
+        }
+    }
+    WebKit::toImpl(pageRef)->setCompositionForTesting(WebKit::toWTFString(text), from, length, suppressUnderline, highlights);
 }
 
 bool WKBundlePageHasComposition(WKBundlePageRef pageRef)
index 3a98814..3aca53d 100644 (file)
@@ -84,7 +84,7 @@ WK_EXPORT bool WKBundlePageIsTrackingRepaints(WKBundlePageRef page);
 WK_EXPORT void WKBundlePageResetTrackedRepaints(WKBundlePageRef page);
 WK_EXPORT WKArrayRef WKBundlePageCopyTrackedRepaintRects(WKBundlePageRef page);
 
-WK_EXPORT void WKBundlePageSetComposition(WKBundlePageRef page, WKStringRef text, int from, int length, bool suppressUnderline);
+WK_EXPORT void WKBundlePageSetComposition(WKBundlePageRef page, WKStringRef text, int from, int length, bool suppressUnderline, WKArrayRef highlightData);
 WK_EXPORT bool WKBundlePageHasComposition(WKBundlePageRef page);
 WK_EXPORT void WKBundlePageConfirmComposition(WKBundlePageRef page);
 WK_EXPORT void WKBundlePageConfirmCompositionWithText(WKBundlePageRef page, WKStringRef text);
index 96e8257..485f1fd 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "WebEditorClient.h"
 
+#include <WebCore/CompositionHighlight.h>
 #include <WebCore/Document.h>
 #include <WebCore/Editor.h>
 #include <WebCore/Frame.h>
@@ -47,7 +48,7 @@ void WebEditorClient::didDispatchInputMethodKeydown(KeyboardEvent& event)
     if (const auto& underlines = platformEvent->preeditUnderlines()) {
         auto rangeStart = platformEvent->preeditSelectionRangeStart().valueOr(0);
         auto rangeLength = platformEvent->preeditSelectionRangeLength().valueOr(0);
-        frame->editor().setComposition(platformEvent->text(), underlines.value(), rangeStart, rangeStart + rangeLength);
+        frame->editor().setComposition(platformEvent->text(), underlines.value(), { }, rangeStart, rangeStart + rangeLength);
     } else
         frame->editor().confirmComposition(platformEvent->text());
 }
index e303c22..3a1a9e8 100644 (file)
@@ -5100,7 +5100,7 @@ void WebPage::simulateMouseMotion(WebCore::IntPoint position, WallTime time)
     mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, 0, position, position, 0, 0, 0, 0, OptionSet<WebEvent::Modifier> { }, time, 0, WebMouseEvent::NoTap));
 }
 
-void WebPage::setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline)
+void WebPage::setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline, const Vector<CompositionHighlight>& highlights)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
     if (!frame.editor().canEdit())
@@ -5110,7 +5110,7 @@ void WebPage::setCompositionForTesting(const String& compositionString, uint64_t
     if (!suppressUnderline)
         underlines.append(CompositionUnderline(0, compositionString.length(), CompositionUnderlineColor::TextColor, Color(Color::black), false));
 
-    frame.editor().setComposition(compositionString, underlines, from, from + length);
+    frame.editor().setComposition(compositionString, underlines, highlights, from, from + length);
 }
 
 bool WebPage::hasCompositionForTesting()
@@ -5349,7 +5349,7 @@ void WebPage::firstRectForCharacterRangeAsync(const EditingRange& editingRange,
     send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, editingRange, callbackID));
 }
 
-void WebPage::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const EditingRange& selection, const EditingRange& replacementEditingRange)
+void WebPage::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const Vector<CompositionHighlight>& highlights, const EditingRange& selection, const EditingRange& replacementEditingRange)
 {
     platformWillPerformEditingCommand();
 
@@ -5363,7 +5363,7 @@ void WebPage::setCompositionAsync(const String& text, const Vector<CompositionUn
                 frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
         }
 
-        frame.editor().setComposition(text, underlines, selection.location, selection.location + selection.length);
+        frame.editor().setComposition(text, underlines, highlights, selection.location, selection.location + selection.length);
     }
 }
 
index a275376..b9ed9d4 100644 (file)
@@ -196,6 +196,7 @@ enum class TextIndicatorPresentationTransition : uint8_t;
 enum class WritingDirection : uint8_t;
 
 struct BackForwardItemIdentifier;
+struct CompositionHighlight;
 struct CompositionUnderline;
 struct DictationAlternative;
 struct ElementContext;
@@ -824,7 +825,7 @@ public:
     void getSelectedRangeAsync(CallbackID);
     void characterIndexForPointAsync(const WebCore::IntPoint&, CallbackID);
     void firstRectForCharacterRangeAsync(const EditingRange&, CallbackID);
-    void setCompositionAsync(const String& text, const Vector<WebCore::CompositionUnderline>& underlines, const EditingRange& selectionRange, const EditingRange& replacementRange);
+    void setCompositionAsync(const String& text, const Vector<WebCore::CompositionUnderline>&, const Vector<WebCore::CompositionHighlight>&, const EditingRange& selectionRange, const EditingRange& replacementRange);
     void confirmCompositionAsync();
 
     void readSelectionFromPasteboard(const String& pasteboardName, CompletionHandler<void(bool&&)>&&);
@@ -845,7 +846,7 @@ public:
     void replaceSelectionWithPasteboardData(const Vector<String>& types, const IPC::DataReference&);
 #endif
 
-    void setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline);
+    void setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline, const Vector<WebCore::CompositionHighlight>&);
     bool hasCompositionForTesting();
     void confirmCompositionForTesting(const String& compositionString);
 
index e9ad60f..dcb1234 100644 (file)
@@ -453,7 +453,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
     GetSelectedRangeAsync(WebKit::CallbackID callbackID)
     CharacterIndexForPointAsync(WebCore::IntPoint point, WebKit::CallbackID callbackID);
     FirstRectForCharacterRangeAsync(struct WebKit::EditingRange range, WebKit::CallbackID callbackID);
-    SetCompositionAsync(String text, Vector<WebCore::CompositionUnderline> underlines, struct WebKit::EditingRange selectionRange, struct WebKit::EditingRange replacementRange)
+    SetCompositionAsync(String text, Vector<WebCore::CompositionUnderline> underlines, Vector<WebCore::CompositionHighlight> highlights, struct WebKit::EditingRange selectionRange, struct WebKit::EditingRange replacementRange)
     ConfirmCompositionAsync()
 #endif
 #if PLATFORM(MAC)
index 7461920..43aa1be 100644 (file)
@@ -1,3 +1,19 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Adjust some call sites of Editor::setComposition().
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame setMarkedText:selectedRange:]):
+        (-[WebFrame setMarkedText:forCandidates:]):
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView setMarkedText:selectedRange:]):
+
 2020-01-31  Antoine Quint  <graouts@apple.com>
 
         [WK1] hiddenPageCSSAnimationSuspensionEnabled should be enabled by default for Cocoa platforms
index f994c5c..2fecbb5 100644 (file)
@@ -66,6 +66,7 @@
 #import <WebCore/CachedResourceLoader.h>
 #import <WebCore/Chrome.h>
 #import <WebCore/ColorMac.h>
+#import <WebCore/CompositionHighlight.h>
 #import <WebCore/DatabaseManager.h>
 #import <WebCore/DocumentFragment.h>
 #import <WebCore/DocumentLoader.h>
@@ -1649,7 +1650,7 @@ static WebFrameLoadType toWebFrameLoadType(WebCore::FrameLoadType frameLoadType)
     
     Vector<WebCore::CompositionUnderline> underlines;
     frame->page()->chrome().client().suppressFormNotifications();
-    frame->editor().setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange));
+    frame->editor().setComposition(text, underlines, { }, newSelRange.location, NSMaxRange(newSelRange));
     frame->page()->chrome().client().restoreFormNotifications();
 }
 
@@ -1660,7 +1661,7 @@ static WebFrameLoadType toWebFrameLoadType(WebCore::FrameLoadType frameLoadType)
         return;
         
     Vector<WebCore::CompositionUnderline> underlines;
-    frame->editor().setComposition(text, underlines, 0, [text length]);
+    frame->editor().setComposition(text, underlines, { }, 0, [text length]);
 }
 
 - (void)confirmMarkedText:(NSString *)text
index b2a1d08..472773e 100644 (file)
@@ -80,6 +80,7 @@
 #import <WebCore/CachedResourceLoader.h>
 #import <WebCore/Chrome.h>
 #import <WebCore/ColorMac.h>
+#import <WebCore/CompositionHighlight.h>
 #import <WebCore/ContextMenu.h>
 #import <WebCore/ContextMenuController.h>
 #import <WebCore/DictionaryLookup.h>
@@ -6570,7 +6571,7 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     if (replacementRange.location != NSNotFound)
         [[self _frame] _selectNSRange:replacementRange];
 
-    coreFrame->editor().setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange));
+    coreFrame->editor().setComposition(text, underlines, { }, newSelRange.location, NSMaxRange(newSelRange));
 }
 
 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
index 337c3cd..222017e 100644 (file)
@@ -1,3 +1,17 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Adjust some call sites of Editor::setComposition().
+
+        * WebView.cpp:
+        (WebView::onIMEComposition):
+        (WebView::setCompositionForTesting):
+
 2020-01-27  Antoine Quint  <graouts@apple.com>
 
         [Web Animations] Make Animation.timeline read-write only if a runtime flag is enabled
index e38b53b..6aa0aee 100644 (file)
@@ -85,6 +85,7 @@
 #include <WebCore/BitmapInfo.h>
 #include <WebCore/CacheStorageProvider.h>
 #include <WebCore/Chrome.h>
+#include <WebCore/CompositionHighlight.h>
 #include <WebCore/ContextMenu.h>
 #include <WebCore/ContextMenuController.h>
 #include <WebCore/CookieJar.h>
@@ -6399,7 +6400,7 @@ bool WebView::onIMEComposition(LPARAM lparam)
 
         int cursorPosition = LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0));
 
-        targetFrame.editor().setComposition(compositionString, underlines, cursorPosition, 0);
+        targetFrame.editor().setComposition(compositionString, underlines, { }, cursorPosition, 0);
     }
 
     return true;
@@ -7692,7 +7693,7 @@ HRESULT WebView::setCompositionForTesting(_In_ BSTR composition, UINT from, UINT
 
     Vector<CompositionUnderline> underlines;
     underlines.append(CompositionUnderline(0, compositionStr.length(), CompositionUnderlineColor::TextColor, Color(Color::black), false));
-    frame.editor().setComposition(compositionStr, underlines, from, from + length);
+    frame.editor().setComposition(compositionStr, underlines, { }, from, from + length);
 
     return S_OK;
 }
index 4118158..cb1da6b 100644 (file)
@@ -1,3 +1,36 @@
+2020-01-31  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Add support for specifying background colors when setting marked text
+        https://bugs.webkit.org/show_bug.cgi?id=207065
+        <rdar://problem/57876140>
+
+        Reviewed by Tim Horton.
+
+        Add support in WebKitTestRunner for specifying a list of highlight ranges when setting marked text. This comes
+        in the form of an additional argument to TextInputController::setMarkedText, which contains an array of objects,
+        each describing one range (in the composition) to highlight.
+
+        * DumpRenderTree/ios/TextInputControllerIOS.m:
+        (+[TextInputController isSelectorExcludedFromWebScript:]):
+        (+[TextInputController webScriptNameForSelector:]):
+        (-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:highlights:]):
+        (-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:]): Deleted.
+        * DumpRenderTree/mac/TextInputControllerMac.m:
+        (+[TextInputController isSelectorExcludedFromWebScript:]):
+        (+[TextInputController webScriptNameForSelector:]):
+        (-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:highlights:]):
+        (-[TextInputController setMarkedText:selectedFrom:length:suppressUnderline:]): Deleted.
+        * WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl:
+        * WebKitTestRunner/InjectedBundle/TextInputController.cpp:
+        (WTR::arrayLength):
+        (WTR::createCompositionHighlightData):
+
+        Add logic to convert a given JSObject containing the composition highlight information into a WKArrayRef, which
+        is then passed into WebKit via WKBundlePageSetComposition.
+
+        (WTR::TextInputController::setMarkedText):
+        * WebKitTestRunner/InjectedBundle/TextInputController.h:
+
 2020-01-31  Alex Christensen  <achristensen@webkit.org>
 
         Add KVO SPI WKWebView._negotiatedLegacyTLS
index 092efe4..9d127d6 100644 (file)
@@ -39,7 +39,7 @@
 + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
 {
     if (aSelector == @selector(insertText:)
-        || aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:)
+        || aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:highlights:)
         || aSelector == @selector(markedRange))
         return NO;
 
@@ -50,7 +50,7 @@
 {
     if (aSelector == @selector(insertText:))
         return @"insertText";
-    if (aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:))
+    if (aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:highlights:))
         return @"setMarkedText";
     if (aSelector == @selector(markedRange))
         return @"markedRange";
@@ -83,7 +83,7 @@
     [[webView mainFrame] confirmMarkedText:text];
 }
 
-- (void)setMarkedText:(NSString *)text selectedFrom:(NSInteger)selectionStart length:(NSInteger)selectionLength suppressUnderline:(BOOL)suppressUnderline
+- (void)setMarkedText:(NSString *)text selectedFrom:(NSInteger)selectionStart length:(NSInteger)selectionLength suppressUnderline:(BOOL)suppressUnderline highlights:(NSArray<NSDictionary *> *)highlights
 {
     if (selectionStart == -1)
         selectionStart = NSNotFound;
index 56fe967..1cbbd71 100644 (file)
@@ -224,7 +224,7 @@ NSString *NSTextInsertionUndoableAttributeName;
 {
     if (aSelector == @selector(insertText:)
         || aSelector == @selector(doCommand:)
-        || aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:)
+        || aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:highlights:)
         || aSelector == @selector(unmarkText)
         || aSelector == @selector(hasMarkedText)
         || aSelector == @selector(conversationIdentifier)
@@ -251,7 +251,7 @@ NSString *NSTextInsertionUndoableAttributeName;
         return @"insertText";
     if (aSelector == @selector(doCommand:))
         return @"doCommand";
-    if (aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:))
+    if (aSelector == @selector(setMarkedText:selectedFrom:length:suppressUnderline:highlights:))
         return @"setMarkedText";
     if (aSelector == @selector(substringFrom:length:))
         return @"substringFromRange";
@@ -314,7 +314,7 @@ NSString *NSTextInsertionUndoableAttributeName;
         [textInput doCommandBySelector:NSSelectorFromString(aCommand)];
 }
 
-- (void)setMarkedText:(NSString *)aString selectedFrom:(int)from length:(int)length suppressUnderline:(BOOL)suppressUnderline
+- (void)setMarkedText:(NSString *)aString selectedFrom:(int)from length:(int)length suppressUnderline:(BOOL)suppressUnderline highlights:(NSArray<NSDictionary *> *)highlights
 {
     NSObject <NSTextInput> *textInput = [self textInput];
 
index a73ad96..8775649 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 interface TextInputController {
-    void setMarkedText(DOMString string, long from, long length, boolean suppressUnderline);
+    void setMarkedText(DOMString string, long from, long length, boolean suppressUnderline, object highlights);
     boolean hasMarkedText();
     void unmarkText();
     void insertText(DOMString string);
index 3366c70..64ac819 100644 (file)
@@ -30,6 +30,7 @@
 #include "InjectedBundlePage.h"
 #include "JSTextInputController.h"
 #include "StringFunctions.h"
+#include <WebKit/WKBundleFrame.h>
 #include <WebKit/WKBundlePagePrivate.h>
 
 namespace WTR {
@@ -57,9 +58,72 @@ void TextInputController::makeWindowObject(JSContextRef context, JSObjectRef win
     setProperty(context, windowObject, "textInputController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
 }
 
-void TextInputController::setMarkedText(JSStringRef text, int from, int length, bool suppressUnderline)
+static unsigned arrayLength(JSContextRef context, JSObjectRef array)
 {
-    WKBundlePageSetComposition(InjectedBundle::singleton().page()->page(), toWK(text).get(), from, length, suppressUnderline);
+    auto lengthString = adopt(JSStringCreateWithUTF8CString("length"));
+    if (auto lengthValue = JSObjectGetProperty(context, array, lengthString.get(), nullptr))
+        return static_cast<unsigned>(JSValueToNumber(context, lengthValue, nullptr));
+    return 0;
+}
+
+static WKArrayRef createCompositionHighlightData(JSContextRef context, JSValueRef jsHighlightsValue)
+{
+    if (!jsHighlightsValue || !JSValueIsArray(context, jsHighlightsValue))
+        return nullptr;
+
+    auto result = WKMutableArrayCreate();
+    auto jsHighlightsArray = const_cast<JSObjectRef>(jsHighlightsValue);
+    unsigned length = arrayLength(context, jsHighlightsArray);
+    if (!length)
+        return result;
+
+    auto jsFromKey = adopt(JSStringCreateWithUTF8CString("from"));
+    auto jsLengthKey = adopt(JSStringCreateWithUTF8CString("length"));
+    auto jsColorKey = adopt(JSStringCreateWithUTF8CString("color"));
+
+    auto wkFromKey = adoptWK(WKStringCreateWithUTF8CString("from"));
+    auto wkLengthKey = adoptWK(WKStringCreateWithUTF8CString("length"));
+    auto wkColorKey = adoptWK(WKStringCreateWithUTF8CString("color"));
+
+    for (size_t i = 0; i < length; ++i) {
+        JSValueRef exception = nullptr;
+        auto jsObjectValue = JSObjectGetPropertyAtIndex(context, jsHighlightsArray, i, &exception);
+        if (exception || !JSValueIsObject(context, jsObjectValue))
+            continue;
+
+        auto jsObject = const_cast<JSObjectRef>(jsObjectValue);
+        auto jsFromValue = JSObjectGetProperty(context, jsObject, jsFromKey.get(), nullptr);
+        if (!jsFromValue || !JSValueIsNumber(context, jsFromValue))
+            continue;
+
+        auto jsLengthValue = JSObjectGetProperty(context, jsObject, jsLengthKey.get(), nullptr);
+        if (!jsLengthValue || !JSValueIsNumber(context, jsLengthValue))
+            continue;
+
+        auto jsColorValue = JSObjectGetProperty(context, jsObject, jsColorKey.get(), nullptr);
+        if (!jsColorValue || !JSValueIsString(context, jsColorValue))
+            continue;
+
+        auto color = adopt(JSValueToStringCopy(context, jsColorValue, nullptr));
+        auto wkColor = adoptWK(WKStringCreateWithJSString(color.get()));
+        auto wkFrom = adoptWK(WKUInt64Create(lround(JSValueToNumber(context, jsFromValue, nullptr))));
+        auto wkLength = adoptWK(WKUInt64Create(lround(JSValueToNumber(context, jsLengthValue, nullptr))));
+
+        auto dictionary = adoptWK(WKMutableDictionaryCreate());
+        WKDictionarySetItem(dictionary.get(), wkFromKey.get(), wkFrom.get());
+        WKDictionarySetItem(dictionary.get(), wkLengthKey.get(), wkLength.get());
+        WKDictionarySetItem(dictionary.get(), wkColorKey.get(), wkColor.get());
+        WKArrayAppendItem(result, dictionary.get());
+    }
+
+    return result;
+}
+
+void TextInputController::setMarkedText(JSStringRef text, int from, int length, bool suppressUnderline, JSValueRef jsHighlightsValue)
+{
+    auto page = InjectedBundle::singleton().page()->page();
+    auto highlights = adoptWK(createCompositionHighlightData(WKBundleFrameGetJavaScriptContext(WKBundlePageGetMainFrame(page)), jsHighlightsValue));
+    WKBundlePageSetComposition(page, toWK(text).get(), from, length, suppressUnderline, highlights.get());
 }
 
 bool TextInputController::hasMarkedText()
index 4ea7204..558c2e6 100644 (file)
@@ -40,7 +40,7 @@ public:
 
     void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
 
-    void setMarkedText(JSStringRef text, int from, int length, bool suppressUnderline);
+    void setMarkedText(JSStringRef text, int from, int length, bool suppressUnderline, JSValueRef highlights);
     bool hasMarkedText();
     void unmarkText();
     void insertText(JSStringRef text);