diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index 82e87ba5..8ba2f0eb 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -37173,6 +37173,80 @@ namespace vl::presentation::elements { using namespace collections; +/*********************************************************************** +GuiRemoteCaretCache +***********************************************************************/ + + GuiRemoteCaretCache::GuiRemoteCaretCache(const WString& text, remoteprotocol::CharacterEncoding encoding) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::elements::GuiRemoteCaretCache::GuiRemoteCaretCache(const WString&, remoteprotocol::CharacterEncoding)#" + CHECK_ERROR( + encoding == remoteprotocol::CharacterEncoding::UTF8 || + encoding == remoteprotocol::CharacterEncoding::UTF16 || + encoding == remoteprotocol::CharacterEncoding::UTF32, + ERROR_MESSAGE_PREFIX L"Unknown character encoding."); + + List nativeMapping; + List remoteMapping; + vint nativePos = 0; + vint remotePos = 0; + while (nativePos < text.Length()) + { + char32_t scalar = 0; + auto nativeLength = vl::encoding::UtfConversion::To32( + text.Buffer() + nativePos, + text.Length() - nativePos, + scalar); + + vint remoteLength = 1; + if (nativeLength == -1) + { + nativeLength = 1; + } + else + { + switch (encoding) + { + case remoteprotocol::CharacterEncoding::UTF8: + { + char8_t buffer[vl::encoding::UtfConversion::BufferLength]; + remoteLength = vl::encoding::UtfConversion::From32(scalar, buffer); + } + break; + case remoteprotocol::CharacterEncoding::UTF16: + { + char16_t buffer[vl::encoding::UtfConversion::BufferLength]; + remoteLength = vl::encoding::UtfConversion::From32(scalar, buffer); + } + break; + case remoteprotocol::CharacterEncoding::UTF32: + remoteLength = 1; + break; + } + if (remoteLength == -1) + { + remoteLength = 1; + } + } + + for (vint i = 0; i < nativeLength; i++) + { + nativeMapping.Add(remotePos); + } + for (vint i = 0; i < remoteLength; i++) + { + remoteMapping.Add(nativePos); + } + nativePos += nativeLength; + remotePos += remoteLength; + } + nativeMapping.Add(remotePos); + remoteMapping.Add(nativePos); + CopyFrom(nativeToRemote, nativeMapping); + CopyFrom(remoteToNative, remoteMapping); +#undef ERROR_MESSAGE_PREFIX + } + /*********************************************************************** GuiRemoteGraphicsParagraph ***********************************************************************/ @@ -37245,6 +37319,12 @@ GuiRemoteGraphicsParagraph desc.maxWidth = maxWidth; desc.id = id; DiffRuns(committedRuns, stagedRuns, desc); + for (vint i = 0; i < desc.runsDiff->Count(); i++) + { + auto&& run = (*desc.runsDiff.Obj())[i]; + run.caretBegin = NativeTextPosToRemoteTextPos(run.caretBegin); + run.caretEnd = NativeTextPosToRemoteTextPos(run.caretEnd); + } auto& messages = renderTarget->GetRemoteMessages(); vint requestId = messages.RequestRendererUpdateElement_DocumentParagraph(desc); @@ -37294,8 +37374,8 @@ GuiRemoteGraphicsParagraph { return false; } - range.caretBegin = NativeTextPosToRemoteTextPos(start); - range.caretEnd = NativeTextPosToRemoteTextPos(start + length); + range.caretBegin = start; + range.caretEnd = start + length; return true; } @@ -37317,14 +37397,39 @@ GuiRemoteGraphicsParagraph cachedInlineObjectBounds.Set(callbackId, bounds); } + GuiRemoteCaretCache* GuiRemoteGraphicsParagraph::GetCaretCache() + { + auto encoding = remote->GetGlobalConfig().documentCaretFromEncoding; +#if defined VCZH_WCHAR_UTF16 + constexpr auto nativeEncoding = remoteprotocol::CharacterEncoding::UTF16; +#elif defined VCZH_WCHAR_UTF32 + constexpr auto nativeEncoding = remoteprotocol::CharacterEncoding::UTF32; +#endif + if (encoding == nativeEncoding) + { + return nullptr; + } + + auto index = caretCaches.Keys().IndexOf(encoding); + if (index == -1) + { + auto cache = Ptr(new GuiRemoteCaretCache(text, encoding)); + caretCaches.Add(encoding, cache); + return cache.Obj(); + } + return caretCaches.Values()[index].Obj(); + } + vint GuiRemoteGraphicsParagraph::NativeTextPosToRemoteTextPos(vint textPos) { - return textPos; + auto cache = GetCaretCache(); + return cache ? cache->nativeToRemote[textPos] : textPos; } vint GuiRemoteGraphicsParagraph::RemoteTextPosToNativeTextPos(vint textPos) { - return textPos; + auto cache = GetCaretCache(); + return cache ? cache->remoteToNative[textPos] : textPos; } IGuiGraphicsLayoutProvider* GuiRemoteGraphicsParagraph::GetProvider() @@ -37635,13 +37740,14 @@ GuiRemoteGraphicsParagraph cachedCaretBounds = messages.RetrieveDocumentParagraph_GetCaretBounds(requestId); } + auto remoteCaret = NativeTextPosToRemoteTextPos(caret); if (frontSide) { - bounds = cachedCaretBounds.frontSideBounds->Get(caret); + bounds = cachedCaretBounds.frontSideBounds->Get(remoteCaret); } else { - bounds = cachedCaretBounds.backSideBounds->Get(caret); + bounds = cachedCaretBounds.backSideBounds->Get(remoteCaret); } return true; } @@ -37731,8 +37837,8 @@ GuiRemoteGraphicsParagraph } CaretRange range; - range.caretBegin = response.Value().caretBegin; - range.caretEnd = response.Value().caretEnd; + range.caretBegin = RemoteTextPosToNativeTextPos(response.Value().caretBegin); + range.caretEnd = RemoteTextPosToNativeTextPos(response.Value().caretEnd); vint index = inlineObjectProperties.Keys().IndexOf(range); if (index == -1) @@ -37740,8 +37846,8 @@ GuiRemoteGraphicsParagraph return {}; } - start = RemoteTextPosToNativeTextPos(range.caretBegin); - length = RemoteTextPosToNativeTextPos(range.caretEnd) - start; + start = range.caretBegin; + length = range.caretEnd - start; return inlineObjectProperties.Values()[index]; } @@ -40699,10 +40805,6 @@ GuiRemoteWindow void GuiRemoteWindow::SubmitStateAfterControllerConnect() { - if (suggestedMinClientSize != NativeSize{ {0},{0} }) - { - remoteMessages.RequestWindowNotifyMinSize(suggestedMinClientSize); - } remoteMessages.RequestWindowNotifySetTitle(styleTitle); remoteMessages.RequestWindowNotifySetEnabled(styleEnabled); remoteMessages.RequestWindowNotifySetTopMost(styleTopMost); @@ -40714,6 +40816,13 @@ GuiRemoteWindow remoteMessages.RequestWindowNotifySetSizeBox(styleSizeBox); remoteMessages.RequestWindowNotifySetIconVisible(styleIconVisible); remoteMessages.RequestWindowNotifySetTitleBar(styleTitleBar); + if (suggestedMinClientSize != NativeSize{ {0},{0} }) + { + // The renderer calculates its outer minimum from the current + // native frame. Apply frame styles first so reconnecting from a + // platform-default window does not include stale decorations. + remoteMessages.RequestWindowNotifyMinSize(suggestedMinClientSize); + } if (statusCapturing) { remoteMessages.RequestIORequireCapture(); @@ -40741,8 +40850,19 @@ GuiRemoteWindow (events) scalingX = remote->remoteScreenConfig.scalingX; scalingY = remote->remoteScreenConfig.scalingY; + auto bounds = remoteWindowSizingConfig.bounds; + if (remote->applicationRunning) + { + // A replacement renderer creates its native window with platform + // defaults. Restore the application frame style before applying + // the saved bounds so client-size calculations use the right frame. + // Style changes report the renderer's temporary bounds back to the + // core, so keep the saved bounds in a local variable. + SubmitStateAfterControllerConnect(); + } + sizingConfigInvalidated = true; - remoteMessages.RequestWindowNotifySetBounds(remoteWindowSizingConfig.bounds); + remoteMessages.RequestWindowNotifySetBounds(bounds); RequestGetBounds(); // TODO: @@ -40750,11 +40870,6 @@ GuiRemoteWindow (events) // Refactor to make it more elegant. for (auto l : listeners) l->DpiChanged(true); for (auto l : listeners) l->DpiChanged(false); - - if (remote->applicationRunning) - { - SubmitStateAfterControllerConnect(); - } } void GuiRemoteWindow::OnControllerDisconnect() @@ -44320,7 +44435,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::LeftButtonDown(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Left; arguments.info = info; @@ -44330,7 +44445,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::LeftButtonUp(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Left; arguments.info = info; @@ -44340,7 +44455,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::LeftButtonDoubleClick(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Left; arguments.info = info; @@ -44350,7 +44465,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::RightButtonDown(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Right; arguments.info = info; @@ -44360,7 +44475,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::RightButtonUp(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Right; arguments.info = info; @@ -44370,7 +44485,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::RightButtonDoubleClick(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Right; arguments.info = info; @@ -44380,7 +44495,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::MiddleButtonDown(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Middle; arguments.info = info; @@ -44390,7 +44505,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::MiddleButtonUp(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Middle; arguments.info = info; @@ -44400,7 +44515,7 @@ namespace vl::presentation::remote_renderer void GuiRemoteRendererSingle::MiddleButtonDoubleClick(const NativeWindowMouseInfo& info) { if (!CanSendEvents()) return; - pendingMouseMove.Reset(); + SendAccumulatedMessages(); IOMouseInfoWithButton arguments; arguments.button = IOMouseButton::Middle; arguments.info = info; diff --git a/Import/GacUI.h b/Import/GacUI.h index e17d8baf..2626a93c 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -22019,10 +22019,21 @@ GuiRemoteGraphicsParagraph class GuiRemoteGraphicsResourceManager; class GuiRemoteGraphicsRenderTarget; + class GuiRemoteCaretCache : public Object + { + public: + collections::Array nativeToRemote; + collections::Array remoteToNative; + + GuiRemoteCaretCache(const WString& text, remoteprotocol::CharacterEncoding encoding); + }; + class GuiRemoteGraphicsParagraph : public Object, public IGuiGraphicsParagraph { protected: WString text; + collections::Dictionary> + caretCaches; GuiRemoteController* remote = nullptr; GuiRemoteGraphicsResourceManager* resourceManager = nullptr; GuiRemoteGraphicsRenderTarget* renderTarget = nullptr; @@ -22054,6 +22065,7 @@ GuiRemoteGraphicsParagraph vint GetParagraphId() const; protected: + GuiRemoteCaretCache* GetCaretCache(); vint NativeTextPosToRemoteTextPos(vint textPos); vint RemoteTextPosToNativeTextPos(vint textPos); bool TryBuildCaretRange(vint start, vint length, CaretRange& range);