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();