Skip to content

Commit

Permalink
[Unified Text Replacement] Replacement document markers do not have t…
Browse files Browse the repository at this point in the history
…heir relevant marked text ranges

https://bugs.webkit.org/show_bug.cgi?id=268708
rdar://122254085

Reviewed by Megan Gardner.

* Source/WebCore/dom/DocumentMarker.h:
(WebCore::DocumentMarker::description const):
* Source/WebCore/dom/DocumentMarkerController.cpp:
(WebCore::shouldInsertAsSeparateMarker):
* Source/WebCore/rendering/MarkedText.cpp:
(WebCore::MarkedText::collectForDocumentMarkers):
* Source/WebKit/WebProcess/WebPage/UnifiedTextReplacementController.cpp:
(WebKit::replaceTextInRange):
(WebKit::UnifiedTextReplacementController::willBeginTextReplacementSession):
(WebKit::UnifiedTextReplacementController::textReplacementSessionDidReceiveReplacements):

Canonical link: https://commits.webkit.org/274193@main
  • Loading branch information
rr-codes committed Feb 7, 2024
1 parent 0d2bc11 commit 1721c34
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 20 deletions.
30 changes: 27 additions & 3 deletions Source/WebCore/dom/DocumentMarker.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <variant>
#include <wtf/Forward.h>
#include <wtf/OptionSet.h>
#include <wtf/UUID.h>
#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>

Expand Down Expand Up @@ -100,6 +101,18 @@ class DocumentMarker : public CanMakeWeakPtr<DocumentMarker> {
};
#endif

#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
struct UnifiedTextReplacementData {
enum class ApplyIndicator: bool {
No, Yes
};

String originalText;
WTF::UUID uuid;
ApplyIndicator applyIndicator { ApplyIndicator::No };
};
#endif

using Data = std::variant<
String
, DictationData // DictationAlternatives
Expand All @@ -110,6 +123,9 @@ class DocumentMarker : public CanMakeWeakPtr<DocumentMarker> {
, RefPtr<Node> // DraggedContent
#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)
, PlatformTextCheckingData // PlatformTextChecking
#endif
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
, UnifiedTextReplacementData // UnifiedTextReplacement
#endif
>;

Expand All @@ -119,7 +135,7 @@ class DocumentMarker : public CanMakeWeakPtr<DocumentMarker> {
unsigned startOffset() const { return m_range.start; }
unsigned endOffset() const { return m_range.end; }

const String& description() const;
String description() const;

const Data& data() const { return m_data; }
void clearData() { m_data = String { }; }
Expand Down Expand Up @@ -180,9 +196,17 @@ inline void DocumentMarker::shiftOffsets(int delta)
m_range.end += delta;
}

inline const String& DocumentMarker::description() const
inline String DocumentMarker::description() const
{
return std::holds_alternative<String>(m_data) ? std::get<String>(m_data) : emptyString();
if (auto* description = std::get_if<String>(&m_data))
return *description;

#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
if (auto* description = std::get_if<DocumentMarker::UnifiedTextReplacementData>(&m_data))
return makeString("('", description->originalText, "', indicator: ", description->applyIndicator == DocumentMarker::UnifiedTextReplacementData::ApplyIndicator::Yes, ")");
#endif

return emptyString();
}

} // namespace WebCore
17 changes: 13 additions & 4 deletions Source/WebCore/dom/DocumentMarkerController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,29 @@ Vector<FloatRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMark

static bool shouldInsertAsSeparateMarker(const DocumentMarker& marker)
{
switch (marker.type()) {
#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)
if (marker.type() == DocumentMarker::Type::PlatformTextChecking)
case DocumentMarker::Type::PlatformTextChecking:
return true;
#endif

#if PLATFORM(IOS_FAMILY)
if (marker.type() == DocumentMarker::Type::DictationPhraseWithAlternatives || marker.type() == DocumentMarker::Type::DictationResult)
case DocumentMarker::Type::DictationPhraseWithAlternatives:
case DocumentMarker::Type::DictationResult:
return true;
#endif

if (marker.type() == DocumentMarker::Type::DraggedContent)
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
case DocumentMarker::Type::UnifiedTextReplacement:
return true;
#endif

case DocumentMarker::Type::DraggedContent:
return is<RenderReplaced>(std::get<RefPtr<Node>>(marker.data())->renderer());

return false;
default:
return false;
}
}

// Markers are stored in order sorted by their start offset.
Expand Down
19 changes: 18 additions & 1 deletion Source/WebCore/rendering/MarkedText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ Vector<MarkedText> MarkedText::collectForDocumentMarkers(const RenderText& rende
return MarkedText::Type::GrammarError;
case DocumentMarker::Type::CorrectionIndicator:
return MarkedText::Type::Correction;
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
case DocumentMarker::Type::UnifiedTextReplacement:
return MarkedText::Type::Correction;
#endif
case DocumentMarker::Type::TextMatch:
return MarkedText::Type::TextMatch;
case DocumentMarker::Type::DictationAlternatives:
Expand Down Expand Up @@ -240,6 +244,9 @@ Vector<MarkedText> MarkedText::collectForDocumentMarkers(const RenderText& rende
break;
FALLTHROUGH;
case DocumentMarker::Type::CorrectionIndicator:
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
case DocumentMarker::Type::UnifiedTextReplacement:
#endif
case DocumentMarker::Type::Replacement:
case DocumentMarker::Type::DictationAlternatives:
#if PLATFORM(IOS_FAMILY)
Expand Down Expand Up @@ -282,6 +289,9 @@ Vector<MarkedText> MarkedText::collectForDocumentMarkers(const RenderText& rende
switch (marker->type()) {
case DocumentMarker::Type::Spelling:
case DocumentMarker::Type::CorrectionIndicator:
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
case DocumentMarker::Type::UnifiedTextReplacement:
#endif
case DocumentMarker::Type::DictationAlternatives:
case DocumentMarker::Type::Grammar:
#if PLATFORM(IOS_FAMILY)
Expand All @@ -290,7 +300,14 @@ Vector<MarkedText> MarkedText::collectForDocumentMarkers(const RenderText& rende
#endif
case DocumentMarker::Type::TextMatch: {
auto [clampedStart, clampedEnd] = selectableRange.clamp(marker->startOffset(), marker->endOffset());
markedTexts.append({ clampedStart, clampedEnd, markedTextTypeForMarkerType(marker->type()), marker.get() });

auto markedTextType = markedTextTypeForMarkerType(marker->type());
#if ENABLE(UNIFIED_TEXT_REPLACEMENT)
if (marker->type() == DocumentMarker::Type::UnifiedTextReplacement && std::get<DocumentMarker::UnifiedTextReplacementData>(marker->data()).applyIndicator == DocumentMarker::UnifiedTextReplacementData::ApplyIndicator::No)
markedTextType = MarkedText::Type::Unmarked;
#endif

markedTexts.append({ clampedStart, clampedEnd, markedTextType, marker.get() });
break;
}
case DocumentMarker::Type::Replacement:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,27 @@
#include "WebPage.h"
#include "WebUnifiedTextReplacementContextData.h"
#include <WebCore/DocumentMarkerController.h>
#include <WebCore/Editor.h>
#include <WebCore/HTMLConverter.h>
#include <WebCore/TextIterator.h>

namespace WebKit {
using namespace WebCore;

static void replaceTextInRange(WebCore::LocalFrame& frame, const SimpleRange& range, const String& replacementText)
{
RefPtr document = frame.document();
if (!document)
return;

WebCore::VisibleSelection visibleSelection(range);

constexpr OptionSet temporarySelectionOptions { WebCore::TemporarySelectionOption::DoNotSetFocus, WebCore::TemporarySelectionOption::IgnoreSelectionChanges };
WebCore::TemporarySelectionChange selectionChange(*document, visibleSelection, temporarySelectionOptions);

frame.editor().replaceSelectionWithText(replacementText, WebCore::Editor::SelectReplacement::Yes, WebCore::Editor::SmartReplace::No, WebCore::EditAction::InsertReplacement);
}

UnifiedTextReplacementController::UnifiedTextReplacementController(WebPage& webPage)
: m_webPage(webPage)
{
Expand All @@ -47,32 +62,38 @@ void UnifiedTextReplacementController::willBeginTextReplacementSession(const WTF
{
RELEASE_LOG(UnifiedTextReplacement, "UnifiedTextReplacementController::willBeginTextReplacementSession (%s)", uuid.toString().utf8().data());

if (!m_webPage)
if (!m_webPage) {
ASSERT_NOT_REACHED();
completionHandler({ });
return;
}

auto* corePage = m_webPage->corePage();
if (!corePage)
if (!corePage) {
ASSERT_NOT_REACHED();
completionHandler({ });
return;

Ref frame = CheckedRef(corePage->focusController())->focusedOrMainFrame();
}

auto contextRange = m_webPage->autocorrectionContextRange();
if (!contextRange)
if (!contextRange) {
completionHandler({ });
return;
}

auto liveRange = createLiveRange(*contextRange);

ASSERT(!m_contextRanges.contains(uuid));

m_contextRanges.set(uuid, liveRange);

Ref frame = CheckedRef(corePage->focusController())->focusedOrMainFrame();

auto selectedTextRange = frame->selection().selection().firstRange();

auto attributedStringFromRange = attributedString(*contextRange);

auto selectedTextCharacterRange = WebCore::characterRange(*contextRange, *selectedTextRange);

completionHandler({ WebUnifiedTextReplacementContextData { WTF::UUID { 0 }, attributedStringFromRange, selectedTextCharacterRange } });
completionHandler({ { WTF::UUID { 0 }, attributedStringFromRange, selectedTextCharacterRange } });
}

void UnifiedTextReplacementController::didBeginTextReplacementSession(const WTF::UUID& uuid, const Vector<WebKit::WebUnifiedTextReplacementContextData>& contexts)
Expand All @@ -87,17 +108,42 @@ void UnifiedTextReplacementController::textReplacementSessionDidReceiveReplaceme
if (!m_webPage)
return;

auto* corePage = m_webPage->corePage();
if (!corePage) {
ASSERT_NOT_REACHED();
return;
}

Ref frame = CheckedRef(corePage->focusController())->focusedOrMainFrame();

ASSERT(m_contextRanges.contains(uuid));

auto liveRange = m_contextRanges.get(uuid);
auto sessionRange = makeSimpleRange(liveRange);
if (!sessionRange)
if (!sessionRange) {
ASSERT_NOT_REACHED();
return;
}

frame->selection().clear();

size_t additionalOffset = 0;

for (const auto& replacementData : replacements) {
auto locationWithOffset = replacementData.originalRange.location + additionalOffset;

auto originalRangeWithOffset = CharacterRange { locationWithOffset, replacementData.originalRange.length };
auto resolvedRange = resolveCharacterRange(*sessionRange, originalRangeWithOffset);

replaceTextInRange(frame.get(), resolvedRange, replacementData.replacement);

auto newRangeWithOffset = CharacterRange { locationWithOffset, replacementData.replacement.length() };
auto newResolvedRange = resolveCharacterRange(*sessionRange, newRangeWithOffset);

for (const auto& replacement : replacements) {
auto resolvedRange = resolveCharacterRange(*sessionRange, replacement.originalRange);
auto markerData = DocumentMarker::UnifiedTextReplacementData { replacementData.originalString.string, replacementData.uuid, DocumentMarker::UnifiedTextReplacementData::ApplyIndicator::Yes };
addMarker(resolvedRange, DocumentMarker::Type::UnifiedTextReplacement, markerData);

addMarker(resolvedRange, DocumentMarker::Type::UnifiedTextReplacement, replacement.originalString.string);
additionalOffset += replacementData.replacement.length() - replacementData.originalRange.length;
}
}

Expand Down

0 comments on commit 1721c34

Please sign in to comment.