From 1212d919fd87bf1580be10216d1607f58fbc8567 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Sat, 14 Oct 2023 22:02:42 +0000 Subject: [PATCH] Emulate IMM32 vertical writing protocol in TSF mozc_renderer indeed has had logic to avoid its candidate window from being placed over the composing text in vertical writing scenario. This logic was, however, fully implemented only in Mozc's IMM32 DLLs. Mozc's TIP modules have not yet propagated the same information to mozc_renderer. As a result, Mozc's candidate window always overwraps composing text in the vertical writing mode, and Chromium ended up implementing a workaround for this behavior [1]. With this commit, Mozc's TIP DLLs start filling CharacterPosition in the same way as Mozc's IMM32 DLLs used to do in the vertical writing mode. Now the observable behavior in the vertical writing mode should be the same as IMM32 Mozc. Closes #362. [1]: https://chromium-review.googlesource.com/c/chromium/src/+/4023235 PiperOrigin-RevId: 573515844 --- src/protocol/renderer_command.proto | 3 ++ src/renderer/win32/win32_renderer_util.cc | 9 +++-- src/win32/tip/tip_range_util.cc | 27 +++++++++++++++ src/win32/tip/tip_range_util.h | 5 +++ src/win32/tip/tip_ui_handler_conventional.cc | 35 ++++++++++++++++++-- 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/protocol/renderer_command.proto b/src/protocol/renderer_command.proto index f366303c9..1758479a6 100644 --- a/src/protocol/renderer_command.proto +++ b/src/protocol/renderer_command.proto @@ -76,6 +76,9 @@ message RendererCommand { optional Point top_left = 2; optional uint32 line_height = 3; optional Rectangle document_area = 4; + // A quick solution for vertical writing support. + // Strictly speaking, this is not part of IMECHARPOSITION in IMM32. + optional bool vertical_writing = 5; } // Visual information about mode indicator. diff --git a/src/renderer/win32/win32_renderer_util.cc b/src/renderer/win32/win32_renderer_util.cc index 317ae96cc..71416baec 100644 --- a/src/renderer/win32/win32_renderer_util.cc +++ b/src/renderer/win32/win32_renderer_util.cc @@ -763,9 +763,12 @@ double LayoutManager::GetScalingFactor(HWND window_handle) const { LayoutManager::WritingDirection LayoutManager::GetWritingDirection( const commands::RendererCommand_ApplicationInfo &app_info) { - // TODO(https://github.com/google/mozc/issues/362): Implement this for TSF. - // When fixing this, we also need to update Chromium. - // https://chromium-review.googlesource.com/c/chromium/src/+/4023235 + const commands::RendererCommand::CharacterPosition &composition_target = + app_info.composition_target(); + if (composition_target.has_vertical_writing()) { + return composition_target.vertical_writing() ? VERTICAL_WRITING + : HORIZONTAL_WRITING; + } return WRITING_DIRECTION_UNSPECIFIED; } diff --git a/src/win32/tip/tip_range_util.cc b/src/win32/tip/tip_range_util.cc index 9231b8f3a..45d3c3dfa 100644 --- a/src/win32/tip/tip_range_util.cc +++ b/src/win32/tip/tip_range_util.cc @@ -55,6 +55,13 @@ constexpr GUID kGuidPropInputscope = { 0x4a5b, {0x9a, 0xf6, 0x59, 0x2a, 0x59, 0x5c, 0x77, 0x8d}}; +// TSATTRID_Text_VerticalWriting +constexpr GUID kGuidAttrIdTextVerticalWriting = { + 0x6bba8195, + 0x046f, + 0x4ea9, + {0xb3, 0x11, 0x97, 0xfd, 0x66, 0xc4, 0x27, 0x4b}}; + HRESULT GetReadOnlyAppProperty(ITfRange *range, TfEditCookie read_cookie, const GUID &guid, VARIANT *variant_addr) { HRESULT result = S_OK; @@ -214,6 +221,26 @@ HRESULT TipRangeUtil::GetInputScopes(ITfRange *range, TfEditCookie read_cookie, return S_OK; } +HRESULT TipRangeUtil::IsVerticalWriting(ITfRange *range, + TfEditCookie read_cookie, + bool *vertical_writing) { + if (vertical_writing == nullptr) { + return E_FAIL; + } + *vertical_writing = false; + + wil::unique_variant variant; + HRESULT result = GetReadOnlyAppProperty(range, + read_cookie, + kGuidAttrIdTextVerticalWriting, + variant.reset_and_addressof()); + if (FAILED(result)) { + return result; + } + *vertical_writing = (variant.vt == VT_BOOL && variant.boolVal != 0); + return S_OK; +} + bool TipRangeUtil::IsRangeCovered(TfEditCookie edit_cookie, ITfRange *range_test, ITfRange *range_cover) { HRESULT result = S_OK; diff --git a/src/win32/tip/tip_range_util.h b/src/win32/tip/tip_range_util.h index e46644f78..f7b97476a 100644 --- a/src/win32/tip/tip_range_util.h +++ b/src/win32/tip/tip_range_util.h @@ -69,6 +69,11 @@ class TipRangeUtil { static HRESULT GetInputScopes(ITfRange *range, TfEditCookie read_cookie, std::vector *input_scopes); + // Retrieves whether the specified |range| is for vertical writing or not. + // Returns the general result code. + static HRESULT IsVerticalWriting(ITfRange *range, TfEditCookie read_cookie, + bool *vertical_writing); + // Checks whether or not |range_test| becomes a subset of |range_cover|. static bool IsRangeCovered(TfEditCookie edit_cookie, ITfRange *range_test, ITfRange *range_cover); diff --git a/src/win32/tip/tip_ui_handler_conventional.cc b/src/win32/tip/tip_ui_handler_conventional.cc index 76d1e1a5a..56e027e89 100644 --- a/src/win32/tip/tip_ui_handler_conventional.cc +++ b/src/win32/tip/tip_ui_handler_conventional.cc @@ -277,10 +277,39 @@ bool FillCharPosition(TipPrivateContext *private_context, ITfContext *context, app_info->mutable_composition_target(); composition_target->set_position(0); + bool vertical_writing = false; + if (SUCCEEDED(TipRangeUtil::IsVerticalWriting( + target_range.get(), read_cookie, &vertical_writing))) { + composition_target->set_vertical_writing(vertical_writing); + } + RendererCommand::Point *point = composition_target->mutable_top_left(); - point->set_x(text_rect.left); - point->set_y(text_rect.top); - composition_target->set_line_height(text_rect.bottom - text_rect.top); + if (vertical_writing) { + // [Vertical Writing] + // | + // +-----< (pt) + // | | + // |-----+ + // | (cLineHeight) + // | + // | + // v + // (Base Line) + point->set_x(text_rect.right); + point->set_y(text_rect.top); + composition_target->set_line_height(text_rect.right - text_rect.left); + } else { + // [Horizontal Writing] + // (pt) + // v_____ + // | | + // | | (cLineHeight) + // | | + // --+-----+----------> (Base Line) + point->set_x(text_rect.left); + point->set_y(text_rect.top); + composition_target->set_line_height(text_rect.bottom - text_rect.top); + } RendererCommand::Rectangle *area = composition_target->mutable_document_area();