From c55cd753485d4cc7010241ab2e4e770394823879 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 08:58:04 +0000 Subject: [PATCH 01/13] Add RendererReceiver class as a proxy to receive messages from MozcRenderer. * RendererReceiver receives IPC calls from the MozcRenderer process via NSConnection. * The same logic exists in GoogleJapaneseInputServer, and this class will be used as the delegated module instead of that logic. * This replacement will be done in following CLs. #codehealth PiperOrigin-RevId: 683088658 --- src/mac/BUILD.bazel | 22 +++++++ src/mac/mac.gyp | 2 + src/mac/renderer_receiver.h | 48 ++++++++++++++ src/mac/renderer_receiver.mm | 86 +++++++++++++++++++++++++ src/mac/renderer_receiver_test.mm | 100 ++++++++++++++++++++++++++++++ 5 files changed, 258 insertions(+) create mode 100644 src/mac/renderer_receiver.h create mode 100644 src/mac/renderer_receiver.mm create mode 100644 src/mac/renderer_receiver_test.mm diff --git a/src/mac/BUILD.bazel b/src/mac/BUILD.bazel index ca613674c..3437c14b9 100644 --- a/src/mac/BUILD.bazel +++ b/src/mac/BUILD.bazel @@ -181,6 +181,28 @@ mozc_objc_test( ], ) +mozc_objc_library( + name = "renderer_receiver", + srcs = ["renderer_receiver.mm"], + hdrs = ["renderer_receiver.h"], + sdk_frameworks = ["Foundation"], + deps = [ + ":common", + "//protocol:commands_cc_proto", + ], +) + +mozc_objc_test( + name = "renderer_receiver_test", + size = "small", + srcs = ["renderer_receiver_test.mm"], + deps = [ + ":renderer_receiver", + "//protocol:commands_cc_proto", + "//testing:gunit_main_objc", + ], +) + mozc_objc_library( name = "imk_server", srcs = ["GoogleJapaneseInputServer.mm"], diff --git a/src/mac/mac.gyp b/src/mac/mac.gyp index 9dfa2fd69..77d75619e 100644 --- a/src/mac/mac.gyp +++ b/src/mac/mac.gyp @@ -63,6 +63,8 @@ 'GoogleJapaneseInputServer_test.mm', 'KeyCodeMap.mm', 'KeyCodeMap_test.mm', + 'renderer_receiver.mm', + 'renderer_receiver_test.mm', ], 'link_settings': { 'libraries': [ diff --git a/src/mac/renderer_receiver.h b/src/mac/renderer_receiver.h new file mode 100644 index 000000000..e1d45f985 --- /dev/null +++ b/src/mac/renderer_receiver.h @@ -0,0 +1,48 @@ +// Copyright 2010-2021, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 THE COPYRIGHT +// OWNER 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. + +#ifndef MOZC_MAC_RENDERER_RECEIVER_H_ +#define MOZC_MAC_RENDERER_RECEIVER_H_ + +#import + +#import "mac/common.h" + +/** RendererReceiver is a class to receive messages from the renderer process. */ +@interface RendererReceiver : NSObject + +/** Initializes the receiver with the given connection name. + * + * @param name The connection name (e.g. "Mozc_Renderer_Connection"). + */ +- (id)initWithName:(NSString *)name; + +@end + +#endif // MOZC_MAC_RENDERER_RECEIVER_H_ diff --git a/src/mac/renderer_receiver.mm b/src/mac/renderer_receiver.mm new file mode 100644 index 000000000..cf20e3906 --- /dev/null +++ b/src/mac/renderer_receiver.mm @@ -0,0 +1,86 @@ +// Copyright 2010-2021, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 THE COPYRIGHT +// OWNER 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. + +#import "mac/renderer_receiver.h" + +#include "protocol/commands.pb.h" + +@implementation RendererReceiver { + /** The current active controller that handles events from the renderer process. */ + id _currentController; + + /** NSConnection to communicate with the renderer process. */ + NSConnection *_rendererConnection; +} + +- (id)initWithName:(NSString *)name { + self = [super init]; + if (self) { + // _rendererConnection receives IPC calls from the renderer process. + // See: renderer/mac/mac_server_send_command.mm + _rendererConnection = [[NSConnection alloc] init]; + [_rendererConnection setRootObject:self]; + [_rendererConnection registerName:name]; + } + return self; +} + +#pragma mark ServerCallback +// Methods inherited from the ServerCallback protocol (see: common.h). + +// sendData is a method of the ServerCallback protocol. +- (void)sendData:(NSData *)data { + if (!_currentController) { + return; + } + + mozc::commands::SessionCommand command; + int32_t length = static_cast([data length]); + if (!command.ParseFromArray([data bytes], length)) { + return; + } + [_currentController sendCommand:command]; +} + +// outputResult is a method of the ServerCallback protocol. +- (void)outputResult:(NSData *)data { + mozc::commands::Output output; + int32_t length = static_cast([data length]); + if (!output.ParseFromArray([data bytes], length)) { + return; + } + + [_currentController outputResult:&output]; +} + +// setCurrentController is a method of the ServerCallback protocol. +- (void)setCurrentController:(id)controller { + _currentController = controller; +} +@end diff --git a/src/mac/renderer_receiver_test.mm b/src/mac/renderer_receiver_test.mm new file mode 100644 index 000000000..45bf2c100 --- /dev/null +++ b/src/mac/renderer_receiver_test.mm @@ -0,0 +1,100 @@ +// Copyright 2010-2021, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 THE COPYRIGHT +// OWNER 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. + +#import "mac/renderer_receiver.h" + +#include "protocol/commands.pb.h" +#include "testing/gunit.h" + +class RendererReceiverTest : public testing::Test { + protected: + void SetUp() { + // Initialize RendererReceiver with init rather than initWithName. + // This is because the test does not use renderer_connection_. + _receiver = [[RendererReceiver alloc] init]; + } + + RendererReceiver *_receiver; +}; + +@interface MockController : NSObject { + int _numSendCommand; + mozc::commands::SessionCommand _receivedSessionCommand; + int _numOutputResult; + mozc::commands::Output _receivedOutput; +} +@property(readonly) int numSendCommand; +@property(readonly) mozc::commands::SessionCommand receivedSessionCommand; +@property(readonly) int numOutputResult; +@property(readonly) mozc::commands::Output receivedOutput; +@end + +@implementation MockController + +- (void)sendCommand:(mozc::commands::SessionCommand &)data { + _receivedSessionCommand = data; + ++_numSendCommand; +} + +- (void)outputResult:(mozc::commands::Output *)data { + _receivedOutput = *data; + ++_numOutputResult; +} +@end + +TEST_F(RendererReceiverTest, sendData) { + MockController *controller = [[MockController alloc] init]; + [_receiver setCurrentController:controller]; + + mozc::commands::SessionCommand command; + command.Clear(); + command.set_type(mozc::commands::SessionCommand::SELECT_CANDIDATE); + command.set_id(0); + + std::string commandData = command.SerializeAsString(); + [_receiver sendData:[NSData dataWithBytes:commandData.data() length:commandData.size()]]; + EXPECT_EQ(controller.numSendCommand, 1); + EXPECT_EQ(controller.receivedSessionCommand.DebugString(), command.DebugString()); +} + +TEST_F(RendererReceiverTest, outputResult) { + MockController *controller = [[MockController alloc] init]; + [_receiver setCurrentController:controller]; + + mozc::commands::Output output; + output.Clear(); + output.mutable_result()->set_type(mozc::commands::Result::STRING); + output.mutable_result()->set_key("foobar"); + output.mutable_result()->set_value("baz"); + + std::string outputData = output.SerializeAsString(); + [_receiver outputResult:[NSData dataWithBytes:outputData.data() length:outputData.size()]]; + EXPECT_EQ(controller.numOutputResult, 1); + EXPECT_EQ(controller.receivedOutput.DebugString(), output.DebugString()); +} From 120bd9342587febf910612be1854340bd6ee469c Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 09:00:27 +0000 Subject: [PATCH 02/13] Fix the limitation of mouse event on the candidate window on macOS 15. * Used the RendererReceiver class as a proxy to receive messages from MozcRenderer. PiperOrigin-RevId: 683089226 --- src/mac/BUILD.bazel | 2 ++ src/mac/GoogleJapaneseInputController.h | 8 ++++++++ src/mac/GoogleJapaneseInputController.mm | 16 +++++++++++----- src/mac/mac.gyp | 1 + src/mac/main.mm | 15 ++++++++------- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/mac/BUILD.bazel b/src/mac/BUILD.bazel index 3437c14b9..35d857ae8 100644 --- a/src/mac/BUILD.bazel +++ b/src/mac/BUILD.bazel @@ -108,6 +108,7 @@ mozc_objc_library( deps = [ ":imk_controller", ":imk_server", + ":renderer_receiver", "//base:const", "//base:crash_report_handler", "//base:init_mozc", @@ -145,6 +146,7 @@ mozc_objc_library( ":common", ":imk_server", ":keycode_map", + ":renderer_receiver", "//base:const", "//base:process", "//base:util", diff --git a/src/mac/GoogleJapaneseInputController.h b/src/mac/GoogleJapaneseInputController.h index 82edddf5b..ffe0ce988 100644 --- a/src/mac/GoogleJapaneseInputController.h +++ b/src/mac/GoogleJapaneseInputController.h @@ -32,6 +32,7 @@ #import "mac/KeyCodeMap.h" #import "mac/common.h" +#import "mac/renderer_receiver.h" #include #include @@ -106,6 +107,12 @@ IBOutlet NSMenu *menu_; } +/** Sets the RendererReceiver used by all instances of the controller. + * the RendererReceiver is a singleton object used as a proxy to receive messages from + * the renderer process and propage it to the active controller instance. + */ ++ (void)setGlobalRendererReceiver:(RendererReceiver *)rendererReceiver; + /** sendCommand: is called to send SessionCommand to the server from the renderer, when the user * clicks a candidate item in candidate windows or when the renderer sends the usage stats event * information. */ @@ -134,4 +141,5 @@ /** Sets the RendererInterface to use in the controller. */ - (void)setRenderer:(std::unique_ptr)newRenderer; + @end diff --git a/src/mac/GoogleJapaneseInputController.mm b/src/mac/GoogleJapaneseInputController.mm index 2cbf67cc5..300de6e20 100644 --- a/src/mac/GoogleJapaneseInputController.mm +++ b/src/mac/GoogleJapaneseInputController.mm @@ -49,6 +49,7 @@ #import "mac/GoogleJapaneseInputControllerInterface.h" #import "mac/GoogleJapaneseInputServer.h" #import "mac/KeyCodeMap.h" +#import "mac/renderer_receiver.h" #include "absl/log/log.h" #include "absl/strings/string_view.h" @@ -77,6 +78,10 @@ using SetOfString = std::set>; namespace { +// Global object used as a singleton used as a proxy to receive messages from +// the renderer process. +RendererReceiver *gRendererReceiver = nil; + // TODO(horo): This value should be get from system configuration. // DoubleClickInterval can be get from NSEvent (MacOSX ver >= 10.6) constexpr NSTimeInterval kDoubleTapInterval = 0.5; @@ -280,11 +285,8 @@ - (void)activateServer:(id)sender { } [self handleConfig]; - // This is a workaroud due to the crash issue on macOS 15. - NSOperatingSystemVersion versionInfo = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (versionInfo.majorVersion < 15) { - [imkServer_ setCurrentController:self]; - } + // Sets this controller as the active controller to receive messages from the renderer process. + [gRendererReceiver setCurrentController:self]; std::string window_name, window_owner; if (mozc::MacUtil::GetFrontmostWindowNameAndOwner(&window_name, &window_owner)) { @@ -955,4 +957,8 @@ - (void)outputResult:(mozc::commands::Output *)output { } [self commitText:output->result().value().c_str() client:[self client]]; } + ++ (void)setGlobalRendererReceiver:(RendererReceiver *)rendererReceiver { + gRendererReceiver = rendererReceiver; +} @end diff --git a/src/mac/mac.gyp b/src/mac/mac.gyp index 77d75619e..3f36e6db0 100644 --- a/src/mac/mac.gyp +++ b/src/mac/mac.gyp @@ -273,6 +273,7 @@ 'GoogleJapaneseInputServer.mm', 'KeyCodeMap.mm', 'main.mm', + 'renderer_receiver.mm', ], 'product_name': '<(branding)', 'dependencies': [ diff --git a/src/mac/main.mm b/src/mac/main.mm index b9c1f2acd..7c05d3d0b 100644 --- a/src/mac/main.mm +++ b/src/mac/main.mm @@ -28,11 +28,13 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import - -#include +#import #import "mac/GoogleJapaneseInputController.h" #import "mac/GoogleJapaneseInputServer.h" +#import "mac/renderer_receiver.h" + +#include #include "absl/flags/flag.h" #include "absl/log/log.h" @@ -69,11 +71,10 @@ int main(int argc, char *argv[]) { } DLOG(INFO) << mozc::kProductNameInEnglish << " initialized"; - // This is a workaroud due to the crash issue on macOS 15. - NSOperatingSystemVersion versionInfo = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (versionInfo.majorVersion < 15) { - [imkServer registerRendererConnection]; - } + NSString *rendererConnectionName = @kProductPrefix "_Renderer_Connection"; + RendererReceiver *rendererReceiver = + [[RendererReceiver alloc] initWithName:rendererConnectionName]; + [GoogleJapaneseInputController setGlobalRendererReceiver:rendererReceiver]; // Start the converter server at this time explicitly to prevent the // slow-down of the response for initial key event. From f4d34f1407693b770427da535c565d7713a2e9ca Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 09:02:20 +0000 Subject: [PATCH 03/13] Remove GoogleJapaneseInputServer. We no longer need to create a subclass of IMKInputServer since the same logic has been migrated to RendererReceiver. #codehealth PiperOrigin-RevId: 683089874 --- docs/design_doc/mac_version.md | 11 +-- src/mac/BUILD.bazel | 32 ------ src/mac/GoogleJapaneseInputController.h | 3 - src/mac/GoogleJapaneseInputController.mm | 2 - src/mac/GoogleJapaneseInputServer.h | 46 --------- src/mac/GoogleJapaneseInputServer.mm | 73 -------------- src/mac/GoogleJapaneseInputServer_test.mm | 114 ---------------------- src/mac/README.md | 3 +- src/mac/mac.gyp | 3 - src/mac/main.mm | 8 +- 10 files changed, 7 insertions(+), 288 deletions(-) delete mode 100644 src/mac/GoogleJapaneseInputServer.h delete mode 100644 src/mac/GoogleJapaneseInputServer.mm delete mode 100644 src/mac/GoogleJapaneseInputServer_test.mm diff --git a/docs/design_doc/mac_version.md b/docs/design_doc/mac_version.md index 25ff5e812..d29312680 100644 --- a/docs/design_doc/mac_version.md +++ b/docs/design_doc/mac_version.md @@ -23,10 +23,7 @@ convert the NSEvent to Mozc's key event and send to the converter. Also, this class handles the OS status change such like mode change by mouse clicks. IMKInputServer handles all of the connection between applications, and invokes -IMKInputController. Normally we don't need to inherit IMKInputServer but use the -standard server class directly, but we do inherit this as -GoogleJapaneseInputServer for some reasons. See *Communication with renderer* -section for the details. +IMKInputController. The IMKit.framework configurations are in Info.plist of the client application. You'll see the GoogleJapaneseInputController class name in mac/Info.plist. @@ -95,10 +92,8 @@ the client. That's tricky because renderer is an IPC server and client does not run Mozc's IPC server system -- it already has a standard NSRunloop event handling due to IMKit.framework. -This is why we inherit IMKInputServer, as I described above. The -GoogleJapaneseInputServer registers a new event handling for a new connection -actually. When a click happens, the renderer packs the protobuf data into a -binary string, pack it into NSData, and send this to the client's connection by +When a click happens, the renderer packs the protobuf data into a +binary string, pack it into NSData, and sends this to the client's connection by a standard Cocoa's IPC using NSConnection. You may notice "wait, does NSConnection cause memory leaks?" This is absolutely diff --git a/src/mac/BUILD.bazel b/src/mac/BUILD.bazel index 35d857ae8..788be4643 100644 --- a/src/mac/BUILD.bazel +++ b/src/mac/BUILD.bazel @@ -107,7 +107,6 @@ mozc_objc_library( tags = ["manual"], deps = [ ":imk_controller", - ":imk_server", ":renderer_receiver", "//base:const", "//base:crash_report_handler", @@ -144,7 +143,6 @@ mozc_objc_library( ], deps = [ ":common", - ":imk_server", ":keycode_map", ":renderer_receiver", "//base:const", @@ -205,36 +203,6 @@ mozc_objc_test( ], ) -mozc_objc_library( - name = "imk_server", - srcs = ["GoogleJapaneseInputServer.mm"], - hdrs = ["GoogleJapaneseInputServer.h"], - sdk_frameworks = [ - "Foundation", - "InputMethodKit", - ], - tags = ["manual"], - deps = [ - ":common", - "//base:const", - "//protocol:commands_cc_proto", - "@com_google_absl//absl/base", - "@com_google_absl//absl/log", - ], -) - -mozc_objc_test( - name = "imk_server_test", - size = "small", - srcs = ["GoogleJapaneseInputServer_test.mm"], - sdk_frameworks = ["InputMethodKit"], - deps = [ - ":imk_server", - "//protocol:commands_cc_proto", - "//testing:gunit_main_objc", - ], -) - mozc_objc_library( name = "keycode_map", srcs = ["KeyCodeMap.mm"], diff --git a/src/mac/GoogleJapaneseInputController.h b/src/mac/GoogleJapaneseInputController.h index ffe0ce988..05059fe89 100644 --- a/src/mac/GoogleJapaneseInputController.h +++ b/src/mac/GoogleJapaneseInputController.h @@ -97,9 +97,6 @@ /** |mozcClient_| manages connection to the mozc server. */ std::unique_ptr mozcClient_; - /** |imkServer_| holds the reference to GoogleJapaneseInputServer. */ - id imkServer_; - /** |imkClientForTest_| holds the reference to the client object for unit test. */ id imkClientForTest_; diff --git a/src/mac/GoogleJapaneseInputController.mm b/src/mac/GoogleJapaneseInputController.mm index 300de6e20..bd5f1315f 100644 --- a/src/mac/GoogleJapaneseInputController.mm +++ b/src/mac/GoogleJapaneseInputController.mm @@ -47,7 +47,6 @@ #include #import "mac/GoogleJapaneseInputControllerInterface.h" -#import "mac/GoogleJapaneseInputServer.h" #import "mac/KeyCodeMap.h" #import "mac/renderer_receiver.h" @@ -220,7 +219,6 @@ - (id)initWithServer:(IMKServer *)server delegate:(id)delegate client:(id)inputC yenSignCharacter_ = mozc::config::Config::YEN_SIGN; mozcRenderer_ = std::make_unique(); mozcClient_ = mozc::client::ClientFactory::NewClient(); - imkServer_ = reinterpret_cast>(server); imkClientForTest_ = nil; lastKeyDownTime_ = 0; lastKeyCode_ = 0; diff --git a/src/mac/GoogleJapaneseInputServer.h b/src/mac/GoogleJapaneseInputServer.h deleted file mode 100644 index 63b06a5bd..000000000 --- a/src/mac/GoogleJapaneseInputServer.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2010-2021, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE COPYRIGHT -// OWNER 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. - -#import -#import - -#import "mac/common.h" - -// GoogleJapaneseInputServer is a subclass of IMKServer but implements -// RendererCallback, so it can accept user's click event. -@interface GoogleJapaneseInputServer : IMKServer { - // The controller which accepts user's clicks - id current_controller_; - // NSConnection to communicate with the renderer process - NSConnection *renderer_conection_; -} - -// Register the NSConnection for the renderer process -- (BOOL)registerRendererConnection; -@end diff --git a/src/mac/GoogleJapaneseInputServer.mm b/src/mac/GoogleJapaneseInputServer.mm deleted file mode 100644 index 39344ad63..000000000 --- a/src/mac/GoogleJapaneseInputServer.mm +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2010-2021, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE COPYRIGHT -// OWNER 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. - -#import "mac/GoogleJapaneseInputServer.h" - -#include - -#include "absl/log/log.h" -#include "base/const.h" -#include "protocol/commands.pb.h" - -@implementation GoogleJapaneseInputServer -- (BOOL)registerRendererConnection { - NSString *connectionName = @kProductPrefix "_Renderer_Connection"; - renderer_conection_ = [[NSConnection alloc] init]; - [renderer_conection_ setRootObject:self]; - return [renderer_conection_ registerName:connectionName]; -} - -- (void)sendData:(NSData *)data { - if (current_controller_ == nil) { - return; - } - - mozc::commands::SessionCommand command; - int32_t length = static_cast([data length]); - if (!command.ParseFromArray([data bytes], length)) { - return; - } - - [current_controller_ sendCommand:command]; -} - -- (void)outputResult:(NSData *)data { - mozc::commands::Output output; - int32_t length = static_cast([data length]); - if (!output.ParseFromArray([data bytes], length)) { - return; - } - - [current_controller_ outputResult:&output]; -} - -- (void)setCurrentController:(id)controller { - current_controller_ = controller; -} -@end diff --git a/src/mac/GoogleJapaneseInputServer_test.mm b/src/mac/GoogleJapaneseInputServer_test.mm deleted file mode 100644 index b9253592b..000000000 --- a/src/mac/GoogleJapaneseInputServer_test.mm +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2010-2021, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE COPYRIGHT -// OWNER 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. - -#import "mac/GoogleJapaneseInputServer.h" - -#include "protocol/commands.pb.h" -#include "testing/googletest.h" -#include "testing/gunit.h" - -class GoogleJapaneseInputServerTest : public testing::Test { - protected: - void SetUp() { - // Although GoogleJapaneseInputServer is a subclass of IMKServer, - // it does not use initWithName:... method to instantiate the - // object because we don't test those IMKServer functionality - // during this test. - server_ = [[GoogleJapaneseInputServer alloc] init]; - } - - protected: - GoogleJapaneseInputServer *server_; -}; - -@interface MockController : NSObject { - int numSendData_; - mozc::commands::SessionCommand *expectedCommand_; - int numOutputResult_; - mozc::commands::Output *expectedData_; -} -@property(readonly) int numSendData; -@property(readwrite, assign) mozc::commands::SessionCommand *expectedCommand; -@property(readonly) int numOutputResult; -@property(readwrite, assign) mozc::commands::Output *expectedData; - -- (void)sendCommand:(mozc::commands::SessionCommand &)command; -- (void)outputResult:(mozc::commands::Output *)data; -@end - -@implementation MockController -@synthesize numSendData = numSendData_; -@synthesize expectedCommand = expectedCommand_; -@synthesize numOutputResult = numOutputResult_; -@synthesize expectedData = expectedData_; - -- (void)sendCommand:(mozc::commands::SessionCommand &)command { - ASSERT_NE((void *)0, expectedCommand_); - EXPECT_EQ(command.DebugString(), expectedCommand_->DebugString()); - ++numSendData_; -} - -- (void)outputResult:(mozc::commands::Output *)data { - ASSERT_NE(data, (void *)0); - ASSERT_NE(expectedData_, (void *)0); - EXPECT_EQ(data->DebugString(), expectedData_->DebugString()); - ++numOutputResult_; -} -@end - -TEST_F(GoogleJapaneseInputServerTest, sendData) { - MockController *controller = [[MockController alloc] init]; - [server_ setCurrentController:controller]; - - mozc::commands::SessionCommand command; - command.Clear(); - command.set_type(mozc::commands::SessionCommand::SELECT_CANDIDATE); - command.set_id(0); - controller.expectedCommand = &command; - - std::string commandData = command.SerializeAsString(); - [server_ sendData:[NSData dataWithBytes:commandData.data() length:commandData.size()]]; - EXPECT_EQ(controller.numSendData, 1); -} - -TEST_F(GoogleJapaneseInputServerTest, outputResult) { - MockController *controller = [[MockController alloc] init]; - [server_ setCurrentController:controller]; - - mozc::commands::Output output; - output.Clear(); - output.mutable_result()->set_type(mozc::commands::Result::STRING); - output.mutable_result()->set_key("foobar"); - output.mutable_result()->set_value("baz"); - controller.expectedData = &output; - - std::string outputData = output.SerializeAsString(); - [server_ outputResult:[NSData dataWithBytes:outputData.data() length:outputData.size()]]; - EXPECT_EQ(controller.numOutputResult, 1); -} diff --git a/src/mac/README.md b/src/mac/README.md index f894009d2..bf22c0363 100644 --- a/src/mac/README.md +++ b/src/mac/README.md @@ -6,8 +6,7 @@ It contains * Installer * Uninstaller -* Interface classes for macOS IMF (i.e. subclasses of `IMKController` and - `IMKServer`). +* Interface classes for macOS IMF (i.e. the subclass of `IMKInputController`). ## ActivatePane / DevConfirmPane diff --git a/src/mac/mac.gyp b/src/mac/mac.gyp index 3f36e6db0..691d62b42 100644 --- a/src/mac/mac.gyp +++ b/src/mac/mac.gyp @@ -59,8 +59,6 @@ 'sources': [ 'GoogleJapaneseInputController.mm', 'GoogleJapaneseInputController_test.mm', - 'GoogleJapaneseInputServer.mm', - 'GoogleJapaneseInputServer_test.mm', 'KeyCodeMap.mm', 'KeyCodeMap_test.mm', 'renderer_receiver.mm', @@ -270,7 +268,6 @@ 'mac_bundle': 1, 'sources': [ 'GoogleJapaneseInputController.mm', - 'GoogleJapaneseInputServer.mm', 'KeyCodeMap.mm', 'main.mm', 'renderer_receiver.mm', diff --git a/src/mac/main.mm b/src/mac/main.mm index 7c05d3d0b..c95b2a6cc 100644 --- a/src/mac/main.mm +++ b/src/mac/main.mm @@ -29,9 +29,9 @@ #import #import +#import #import "mac/GoogleJapaneseInputController.h" -#import "mac/GoogleJapaneseInputServer.h" #import "mac/renderer_receiver.h" #include @@ -61,10 +61,8 @@ int main(int argc, char *argv[]) { NSBundle *bundle = [NSBundle mainBundle]; NSDictionary *infoDictionary = [bundle infoDictionary]; NSString *connectionName = [infoDictionary objectForKey:@"InputMethodConnectionName"]; - GoogleJapaneseInputServer *imkServer = - [[GoogleJapaneseInputServer alloc] initWithName:connectionName - bundleIdentifier:[bundle bundleIdentifier]]; - + IMKServer *imkServer = [[IMKServer alloc] initWithName:connectionName + bundleIdentifier:[bundle bundleIdentifier]]; if (!imkServer) { LOG(FATAL) << mozc::kProductNameInEnglish << " failed to initialize"; return -1; From da9e0eb6cd5f2fa50b5edb03da7b65dece6505b5 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 09:04:12 +0000 Subject: [PATCH 04/13] Merge GoogleJapaneseInputControllerInterface.h to GoogleJapaneseInputController.h * There is no specific reason to split the declaration of the class. #codehealth PiperOrigin-RevId: 683090530 --- src/mac/BUILD.bazel | 3 - src/mac/GoogleJapaneseInputController.h | 146 ++++++++++++++++-- src/mac/GoogleJapaneseInputController.mm | 57 ++++--- .../GoogleJapaneseInputControllerInterface.h | 102 ------------ src/mac/GoogleJapaneseInputController_test.mm | 11 +- 5 files changed, 174 insertions(+), 145 deletions(-) delete mode 100644 src/mac/GoogleJapaneseInputControllerInterface.h diff --git a/src/mac/BUILD.bazel b/src/mac/BUILD.bazel index 788be4643..9aedaa4b8 100644 --- a/src/mac/BUILD.bazel +++ b/src/mac/BUILD.bazel @@ -138,9 +138,6 @@ mozc_objc_library( "InputMethodKit", ], tags = ["manual"], - textual_hdrs = [ - "GoogleJapaneseInputControllerInterface.h", - ], deps = [ ":common", ":keycode_map", diff --git a/src/mac/GoogleJapaneseInputController.h b/src/mac/GoogleJapaneseInputController.h index 05059fe89..b7e7a9c8a 100644 --- a/src/mac/GoogleJapaneseInputController.h +++ b/src/mac/GoogleJapaneseInputController.h @@ -104,39 +104,167 @@ IBOutlet NSMenu *menu_; } +/** These are externally accessible to achieve tests. */ +@property(readonly) mozc::client::ClientInterface *mozcClient; +@property(readwrite, retain, nonatomic) KeyCodeMap *keyCodeMap; +@property(readonly) mozc::renderer::RendererInterface *renderer; +@property(readonly) mozc::config::Config::YenSignCharacter yenSignCharacter; +@property(readwrite, assign) mozc::commands::CompositionMode mode; +@property(readonly) const mozc::commands::RendererCommand &rendererCommand; +@property(readwrite, assign) NSRange replacementRange; +@property(readwrite, retain) id imkClientForTest; + /** Sets the RendererReceiver used by all instances of the controller. * the RendererReceiver is a singleton object used as a proxy to receive messages from * the renderer process and propage it to the active controller instance. + * + * @param rendererReceiver The RendererReceiver object referred by all instances of the controller. */ + (void)setGlobalRendererReceiver:(RendererReceiver *)rendererReceiver; /** sendCommand: is called to send SessionCommand to the server from the renderer, when the user * clicks a candidate item in candidate windows or when the renderer sends the usage stats event - * information. */ + * information. + * + * @param command The protobuf of command sent to the server. + */ - (void)sendCommand:(const mozc::commands::SessionCommand &)command; -/** reconversionClicked: is called when the user clicks "Reconversion" menu item. */ +/** reconversionClicked: is called when the user clicks "Reconversion" menu item. + * + * @param sender The sender of this request (unused). + */ - (IBAction)reconversionClicked:(id)sender; -/** configClicked: is called when the user clicks "Configure Mozc..." menu item. */ +/** configClicked: is called when the user clicks "Configure Mozc..." menu item. + * + * @param sender The sender of this request (unused). + */ - (IBAction)configClicked:(id)sender; -/** dictionaryToolClicked: is called when the user clicks "Dictionary Tool..." menu item. */ +/** dictionaryToolClicked: is called when the user clicks "Dictionary Tool..." menu item. + * + * @param sender The sender of this request (unused). + */ - (IBAction)dictionaryToolClicked:(id)sender; -/** registerWordClicked: is called when the user clicks "Add a word..." menu item. */ +/** registerWordClicked: is called when the user clicks "Add a word..." menu item. + * + * @param sender The sender of this request (unused). + */ - (IBAction)registerWordClicked:(id)sender; -/** aboutDialogClicked: is called when the user clicks "About Mozc..." menu item. */ +/** aboutDialogClicked: is called when the user clicks "About Mozc..." menu item. + * + * @param sender The sender of this request (unused). + */ - (IBAction)aboutDialogClicked:(id)sender; -/** outputResult: put result text in the specified |output| into the client application. */ +/** outputResult: put result text in the specified |output| into the client application. + * + * @param output The protobuf of the output data. + */ - (void)outputResult:(mozc::commands::Output *)output; -/** Sets the ClientInterface to use in the controller. */ +/** Sets the ClientInterface to use in the controller. + * + * @param newMozcClient The client object to communicate with the Mozc server process. + */ - (void)setMozcClient:(std::unique_ptr)newMozcClient; -/** Sets the RendererInterface to use in the controller. */ +/** Sets the RendererInterface to use in the controller. + * + * @param newRenderer The client object to communicate with the candidate renderer process. + */ - (void)setRenderer:(std::unique_ptr)newRenderer; +/** Updates |composedString_| from the result of a key event and puts the updated composed string to + * the client application. + * + * @param preedit The protobuf data representing the composed string. + */ +- (void)updateComposedString:(const mozc::commands::Preedit *)preedit; + +/** Updates |candidates_| from the result of a key event. + * + * @param output The protobuf data that contains the data of candidate words. + */ +- (void)updateCandidates:(const mozc::commands::Output *)output; + +/** Clears all candidate data in |candidates_|. */ +- (void)clearCandidates; + +/** Opens a link specified by the URL. + * + * @param url The URL information. + */ +- (void)openLink:(NSURL *)url; + +/** Switches to a new mode and sync the current mode with the converter. + * + * @param new_mode The protobuf enum of the new input mode. + * @param sender The sender of this request. + */ +- (void)switchMode:(mozc::commands::CompositionMode)new_mode client:(id)sender; + +/** Switches the mode icon in the task bar according to |mode_|. */ +- (void)switchDisplayMode; + +/** Commits the specified text to the current client. + * + * @param text The text to be committed. + * @param sender The sender of this request. + */ +- (void)commitText:(const char *)text client:(id)sender; + +/** Conducts the reconvert event. It could have several tricks such like invoking UNDO instead if + * nothing is selected. |sender| has to be the proxy object to the client application, which might + * not be same as the sender of the click event itself when the user clicks the menu item. + * + * @param command The protobuf data to send to the Mozc server process. + * @param sender The sender of this request. + */ +- (void)invokeReconvert:(const mozc::commands::SessionCommand *)command client:(id)sender; + +/** Conducts the undo command. + * + * @param sender The sender of this request. + */ +- (void)invokeUndo:(id)sender; + +/** Processes output fields such as preedit, output text, candidates, and modes and calls methods + * above. + * + * @param output The protobuf of the output data. + * @param sender The sender of this request. + */ +- (void)processOutput:(const mozc::commands::Output *)output client:(id)sender; + +/** Obtains the current configuration from the server and update client-specific configurations. */ +- (void)handleConfig; + +/** Sets up the client capability */ +- (void)setupCapability; + +/** Sets up the client bundle for the sender. + * + * @param sender The sender of this request. + */ +- (void)setupClientBundle:(id)sender; + +/** Launches the word register tool with the current selection range. + * + * @param client The host application. The selection data in this client is used as an input. + */ +- (void)launchWordRegisterTool:(id)client; + +/** Fills the surrounding context (preceding_text and following_text). Returns false if fails to get + * the surrounding context from the client. + * + * @param context The protobuf data used to be fill with the context information. + * @param client The host application as the source of surrounding context. + * @return YES if context was filled; NO otherwise. + */ +- (BOOL)fillSurroundingContext:(mozc::commands::Context *)context client:(id)client; + @end diff --git a/src/mac/GoogleJapaneseInputController.mm b/src/mac/GoogleJapaneseInputController.mm index bd5f1315f..7e6dc6e70 100644 --- a/src/mac/GoogleJapaneseInputController.mm +++ b/src/mac/GoogleJapaneseInputController.mm @@ -46,7 +46,6 @@ #include #include -#import "mac/GoogleJapaneseInputControllerInterface.h" #import "mac/KeyCodeMap.h" #import "mac/renderer_receiver.h" @@ -391,38 +390,46 @@ - (void)switchModeToDirect:(id)sender { } } -// change the mode to the new mode and turn-on the IME if necessary. -- (void)switchModeInternal:(CompositionMode)new_mode { - if (mode_ == mozc::commands::DIRECT) { - // Input mode changes from direct to an active mode. - DLOG(INFO) << "Mode switch: DIRECT -> HIRAGANA, KATAKANA, etc."; +- (void)switchMode:(CompositionMode)new_mode client:(id)sender { + if (mode_ == new_mode) { + return; + } + + if (new_mode == mozc::commands::DIRECT) { + // Turn off the IME and commit the composing text. + DLOG(INFO) << "Mode switch: HIRAGANA, KATAKANA, etc. -> DIRECT"; KeyEvent keyEvent; Output output; - keyEvent.set_special_key(mozc::commands::KeyEvent::ON); + keyEvent.set_special_key(mozc::commands::KeyEvent::OFF); mozcClient_->SendKey(keyEvent, &output); + if (output.has_result()) { + [self commitText:output.result().value().c_str() client:sender]; + } + if ([composedString_ length] > 0) { + [self updateComposedString:nullptr]; + [self clearCandidates]; + } + mode_ = mozc::commands::DIRECT; + return; } - if (mode_ != new_mode) { - // Switch input mode. - DLOG(INFO) << "Switch input mode."; - SessionCommand command; - command.set_type(mozc::commands::SessionCommand::SWITCH_INPUT_MODE); - command.set_composition_mode(new_mode); + if (mode_ == mozc::commands::DIRECT) { + // Turn on the IME as the input mode is changed from DIRECT to an active mode. + DLOG(INFO) << "Mode switch: DIRECT -> HIRAGANA, KATAKANA, etc."; + KeyEvent keyEvent; Output output; - mozcClient_->SendCommand(command, &output); - mode_ = new_mode; + keyEvent.set_special_key(mozc::commands::KeyEvent::ON); + mozcClient_->SendKey(keyEvent, &output); } -} -- (void)switchMode:(CompositionMode)new_mode client:(id)sender { - if (mode_ == new_mode) { - return; - } - if (mode_ != mozc::commands::DIRECT && new_mode == mozc::commands::DIRECT) { - [self switchModeToDirect:sender]; - } else if (new_mode != mozc::commands::DIRECT) { - [self switchModeInternal:new_mode]; - } + // Switch input mode. + DLOG(INFO) << "Switch input mode."; + SessionCommand command; + command.set_type(mozc::commands::SessionCommand::SWITCH_INPUT_MODE); + command.set_composition_mode(new_mode); + Output output; + mozcClient_->SendCommand(command, &output); + mode_ = new_mode; } - (void)switchDisplayMode { diff --git a/src/mac/GoogleJapaneseInputControllerInterface.h b/src/mac/GoogleJapaneseInputControllerInterface.h deleted file mode 100644 index db85fff84..000000000 --- a/src/mac/GoogleJapaneseInputControllerInterface.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2010-2021, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 THE COPYRIGHT -// OWNER 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. - -#import -#import - -#import "mac/KeyCodeMap.h" - -#include "client/client_interface.h" -#include "protocol/commands.pb.h" -#include "renderer/renderer_interface.h" - -@interface GoogleJapaneseInputController () -/** Updates |composedString_| from the result of a key event and put the updated composed string to - * the client application. */ -- (void)updateComposedString:(const mozc::commands::Preedit *)preedit; - -/** Updates |candidates_| from the result of a key event. */ -- (void)updateCandidates:(const mozc::commands::Output *)output; - -/** Clears all candidate data in |candidates_|. */ -- (void)clearCandidates; - -/** Opens a link specified by the URL. */ -- (void)openLink:(NSURL *)url; - -/** Auxiliary methods for switchMode: below. */ -- (void)switchModeToDirect:(id)sender; -- (void)switchModeInternal:(mozc::commands::CompositionMode)new_mode; - -/** Switches to a new mode and sync the current mode with the converter. */ -- (void)switchMode:(mozc::commands::CompositionMode)new_mode client:(id)sender; - -/** Switches the mode icon in the task bar according to |mode_|. */ -- (void)switchDisplayMode; - -/** Commits the specified text to the current client. */ -- (void)commitText:(const char *)text client:(id)sender; - -/** Conducts the reconvert event. It could have several tricks such like invoking UNDO instead if - * nothing is selected. |sender| has to be the proxy object to the client application, which might - * not be same as the sender of the click event itself when the user clicks the menu item. */ -- (void)invokeReconvert:(const mozc::commands::SessionCommand *)command client:(id)sender; - -/** Conducts the undo command. */ -- (void)invokeUndo:(id)sender; - -/** Processes output fields such as preedit, output text, candidates, and modes and calls methods - * above. */ -- (void)processOutput:(const mozc::commands::Output *)output client:(id)sender; - -/** Obtains the current configuration from the server and update client-specific configurations. */ -- (void)handleConfig; - -/** Sets up the client capability */ -- (void)setupCapability; -/** Sets up the client bundle for the sender. */ -- (void)setupClientBundle:(id)sender; - -/** Launches the word register tool with the current selection range. */ -- (void)launchWordRegisterTool:(id)client; - -/** Fills the surrounding context (preceding_text and following_text). Returns false if fails to get - * the surrounding context from the client. */ -- (BOOL)fillSurroundingContext:(mozc::commands::Context *)context client:(id)client; - -/** These are externally accessible to achieve tests. */ -@property(readonly) mozc::client::ClientInterface *mozcClient; -@property(readwrite, retain, nonatomic) KeyCodeMap *keyCodeMap; -@property(readonly) mozc::renderer::RendererInterface *renderer; -@property(readonly) mozc::config::Config::YenSignCharacter yenSignCharacter; -@property(readwrite, assign) mozc::commands::CompositionMode mode; -@property(readonly) const mozc::commands::RendererCommand &rendererCommand; -@property(readwrite, assign) NSRange replacementRange; -@property(readwrite, retain) id imkClientForTest; -@end diff --git a/src/mac/GoogleJapaneseInputController_test.mm b/src/mac/GoogleJapaneseInputController_test.mm index 6298cbed1..619742169 100644 --- a/src/mac/GoogleJapaneseInputController_test.mm +++ b/src/mac/GoogleJapaneseInputController_test.mm @@ -32,7 +32,6 @@ #import #import -#import "mac/GoogleJapaneseInputControllerInterface.h" #import "mac/KeyCodeMap.h" #include @@ -521,7 +520,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control SendKeyWithContext(HasSpecialKey(commands::KeyEvent::OFF), _, NotNull())) .WillOnce(DoAll(SetArgPointee<2>(output), Return(true))); - [controller_ switchModeToDirect:mock_client_]; + [controller_ switchMode:commands::DIRECT client:mock_client_]; EXPECT_EQ(controller_.mode, commands::DIRECT); EXPECT_EQ([mock_client_ getCounter:"insertText:replacementRange:"], 1); EXPECT_TRUE([@"foo" isEqualToString:mock_client_.insertedText]); @@ -529,7 +528,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_FALSE(controller_.rendererCommand.visible()); } -TEST_F(GoogleJapaneseInputControllerTest, SwitchModeInternal) { +TEST_F(GoogleJapaneseInputControllerTest, SwitchMode) { // When a mode changes from DIRECT, it should invoke "ON" command beforehand. EXPECT_CALL(*mock_mozc_client_, SendKeyWithContext(HasSpecialKey(commands::KeyEvent::ON), _, NotNull())) @@ -540,21 +539,21 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control .WillRepeatedly(DoAll(SaveArg<0>(&actual_command), Return(true))); controller_.mode = commands::DIRECT; - [controller_ switchModeInternal:commands::HIRAGANA]; + [controller_ switchMode:commands::HIRAGANA client:mock_client_]; EXPECT_EQ(controller_.mode, commands::HIRAGANA); EXPECT_THAT(actual_command, Type(commands::SessionCommand::SWITCH_INPUT_MODE)); EXPECT_THAT(actual_command, CompositionMode(commands::HIRAGANA)); // Switch from HIRAGANA to KATAKANA. Just sending mode switching command. controller_.mode = commands::HIRAGANA; - [controller_ switchModeInternal:commands::HALF_KATAKANA]; + [controller_ switchMode:commands::HALF_KATAKANA client:mock_client_]; EXPECT_EQ(controller_.mode, commands::HALF_KATAKANA); EXPECT_THAT(actual_command, Type(commands::SessionCommand::SWITCH_INPUT_MODE)); EXPECT_THAT(actual_command, CompositionMode(commands::HALF_KATAKANA)); Mock::VerifyAndClearExpectations(&mock_mozc_client_); // going to same mode does not cause sendcommand - [controller_ switchModeInternal:commands::HALF_KATAKANA]; + [controller_ switchMode:commands::HALF_KATAKANA client:mock_client_]; EXPECT_EQ(controller_.mode, commands::HALF_KATAKANA); } From 75818803b27e850ce90b6bdd6f9a1a970eb26376 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 09:06:21 +0000 Subject: [PATCH 05/13] Rename the files of GoogleJapaneseInputController to mozc_imk_input_controller. * The next CL will change the class name from GoogleJapaneseInputController to MozcImkInputController. * Changed the naming style of files for the consistency among the project. #codehealth PiperOrigin-RevId: 683091217 --- src/mac/BUILD.bazel | 18 +++++++----------- src/mac/mac.gyp | 6 +++--- src/mac/main.mm | 2 +- ...ontroller.h => mozc_imk_input_controller.h} | 0 ...troller.mm => mozc_imk_input_controller.mm} | 2 +- ...st.mm => mozc_imk_input_controller_test.mm} | 2 +- 6 files changed, 13 insertions(+), 17 deletions(-) rename src/mac/{GoogleJapaneseInputController.h => mozc_imk_input_controller.h} (100%) rename src/mac/{GoogleJapaneseInputController.mm => mozc_imk_input_controller.mm} (99%) rename src/mac/{GoogleJapaneseInputController_test.mm => mozc_imk_input_controller_test.mm} (99%) diff --git a/src/mac/BUILD.bazel b/src/mac/BUILD.bazel index 9aedaa4b8..7966893a8 100644 --- a/src/mac/BUILD.bazel +++ b/src/mac/BUILD.bazel @@ -106,7 +106,7 @@ mozc_objc_library( ], tags = ["manual"], deps = [ - ":imk_controller", + ":mozc_imk_input_controller", ":renderer_receiver", "//base:const", "//base:crash_report_handler", @@ -120,13 +120,9 @@ mozc_objc_library( ) mozc_objc_library( - name = "imk_controller", - srcs = [ - "GoogleJapaneseInputController.mm", - ], - hdrs = [ - "GoogleJapaneseInputController.h", - ], + name = "mozc_imk_input_controller", + srcs = ["mozc_imk_input_controller.mm"], + hdrs = ["mozc_imk_input_controller.h"], data = [ "English.lproj/Config.xib", "Japanese.lproj/Config.xib", @@ -161,12 +157,12 @@ mozc_objc_library( ) mozc_objc_test( - name = "imk_controller_test", + name = "mozc_imk_input_controller_test", size = "small", - srcs = ["GoogleJapaneseInputController_test.mm"], + srcs = ["mozc_imk_input_controller_test.mm"], deps = [ - ":imk_controller", ":keycode_map", + ":mozc_imk_input_controller", "//base/mac:mac_util", "//client:client_mock", "//protocol:candidates_cc_proto", diff --git a/src/mac/mac.gyp b/src/mac/mac.gyp index 691d62b42..4091ee9c7 100644 --- a/src/mac/mac.gyp +++ b/src/mac/mac.gyp @@ -57,10 +57,10 @@ 'conditions': [ ['OS=="mac"', { 'sources': [ - 'GoogleJapaneseInputController.mm', - 'GoogleJapaneseInputController_test.mm', 'KeyCodeMap.mm', 'KeyCodeMap_test.mm', + 'mozc_imk_input_controller.mm', + 'mozc_imk_input_controller_test.mm', 'renderer_receiver.mm', 'renderer_receiver_test.mm', ], @@ -267,9 +267,9 @@ 'type': 'executable', 'mac_bundle': 1, 'sources': [ - 'GoogleJapaneseInputController.mm', 'KeyCodeMap.mm', 'main.mm', + 'mozc_imk_input_controller.mm', 'renderer_receiver.mm', ], 'product_name': '<(branding)', diff --git a/src/mac/main.mm b/src/mac/main.mm index c95b2a6cc..5e955ab5e 100644 --- a/src/mac/main.mm +++ b/src/mac/main.mm @@ -31,7 +31,7 @@ #import #import -#import "mac/GoogleJapaneseInputController.h" +#import "mac/mozc_imk_input_controller.h" #import "mac/renderer_receiver.h" #include diff --git a/src/mac/GoogleJapaneseInputController.h b/src/mac/mozc_imk_input_controller.h similarity index 100% rename from src/mac/GoogleJapaneseInputController.h rename to src/mac/mozc_imk_input_controller.h diff --git a/src/mac/GoogleJapaneseInputController.mm b/src/mac/mozc_imk_input_controller.mm similarity index 99% rename from src/mac/GoogleJapaneseInputController.mm rename to src/mac/mozc_imk_input_controller.mm index 7e6dc6e70..2af37fb38 100644 --- a/src/mac/GoogleJapaneseInputController.mm +++ b/src/mac/mozc_imk_input_controller.mm @@ -27,7 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#import "mac/GoogleJapaneseInputController.h" +#import "mac/mozc_imk_input_controller.h" #import #import diff --git a/src/mac/GoogleJapaneseInputController_test.mm b/src/mac/mozc_imk_input_controller_test.mm similarity index 99% rename from src/mac/GoogleJapaneseInputController_test.mm rename to src/mac/mozc_imk_input_controller_test.mm index 619742169..225e475a3 100644 --- a/src/mac/GoogleJapaneseInputController_test.mm +++ b/src/mac/mozc_imk_input_controller_test.mm @@ -27,7 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#import "mac/GoogleJapaneseInputController.h" +#import "mac/mozc_imk_input_controller.h" #import #import From 90bd14050b0ac0fdf80d8f1ad0d991f47b132945 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Mon, 7 Oct 2024 09:08:51 +0000 Subject: [PATCH 06/13] Rename the class of GoogleJapaneseInputController to MozcImkInputController. We need to keep GoogleJapaneseInputController as an alias of MozcImkInputController for backward compatibility. This will be removed in the future when all clients are migrated to the new name and performed relogin at least once. #codehealth PiperOrigin-RevId: 683091904 --- docs/design_doc/mac_version.md | 2 +- src/mac/Info.plist | 6 ++-- src/mac/main.mm | 2 +- src/mac/mozc_imk_input_controller.h | 11 ++++-- src/mac/mozc_imk_input_controller.mm | 10 ++++-- src/mac/mozc_imk_input_controller_test.mm | 44 +++++++++++------------ src/renderer/mac/CandidateController.mm | 4 +-- src/renderer/mac/CandidateView.h | 2 +- 8 files changed, 46 insertions(+), 35 deletions(-) diff --git a/docs/design_doc/mac_version.md b/docs/design_doc/mac_version.md index d29312680..7e9b2a008 100644 --- a/docs/design_doc/mac_version.md +++ b/docs/design_doc/mac_version.md @@ -26,7 +26,7 @@ IMKInputServer handles all of the connection between applications, and invokes IMKInputController. The IMKit.framework configurations are in Info.plist of the client application. -You'll see the GoogleJapaneseInputController class name in mac/Info.plist. +You'll see the MozcImkInputController class name in mac/Info.plist. ## Communication with converter diff --git a/src/mac/Info.plist b/src/mac/Info.plist index 6cf80e840..e5cf33ccb 100644 --- a/src/mac/Info.plist +++ b/src/mac/Info.plist @@ -180,11 +180,11 @@ InputMethodConnectionName ${PRODUCT_NAME}_1_Connection InputMethodServerControllerClass - GoogleJapaneseInputController + MozcImkInputController InputMethodServerDelegateClass - GoogleJapaneseInputController + MozcImkInputController InputMethodServerDataSourceClass - GoogleJapaneseInputController + MozcImkInputController LSBackgroundOnly 1 LSUIElement diff --git a/src/mac/main.mm b/src/mac/main.mm index 5e955ab5e..ad7cafb49 100644 --- a/src/mac/main.mm +++ b/src/mac/main.mm @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { NSString *rendererConnectionName = @kProductPrefix "_Renderer_Connection"; RendererReceiver *rendererReceiver = [[RendererReceiver alloc] initWithName:rendererConnectionName]; - [GoogleJapaneseInputController setGlobalRendererReceiver:rendererReceiver]; + [MozcImkInputController setGlobalRendererReceiver:rendererReceiver]; // Start the converter server at this time explicitly to prevent the // slow-down of the response for initial key event. diff --git a/src/mac/mozc_imk_input_controller.h b/src/mac/mozc_imk_input_controller.h index b7e7a9c8a..825ca28e2 100644 --- a/src/mac/mozc_imk_input_controller.h +++ b/src/mac/mozc_imk_input_controller.h @@ -45,13 +45,13 @@ #include "protocol/renderer_command.pb.h" #include "renderer/renderer_interface.h" -/** GoogleJapaneseInputController is a subclass of |IMKInputController|, which holds a connection +/** MozcImkInputController is a subclass of |IMKInputController|, which holds a connection * from a client application to the mozc server (Japanese IME server) on the machine. * * For the detail of IMKInputController itself, see the ADC document * http://developer.apple.com/documentation/Cocoa/Reference/IMKInputController_Class/ */ -@interface GoogleJapaneseInputController : IMKInputController { +@interface MozcImkInputController : IMKInputController { @private /** Instance variables are all strong references. */ @@ -268,3 +268,10 @@ - (BOOL)fillSurroundingContext:(mozc::commands::Context *)context client:(id)client; @end + +/** GoogleJapaneseInputController is an alias of MozcImkInputController for backward compatibility. + * This will be removed in the future when all clients are migrated to the new name and performed + * relogin at least once. + */ +@interface GoogleJapaneseInputController : MozcImkInputController {} +@end diff --git a/src/mac/mozc_imk_input_controller.mm b/src/mac/mozc_imk_input_controller.mm index 2af37fb38..14e5dd6ad 100644 --- a/src/mac/mozc_imk_input_controller.mm +++ b/src/mac/mozc_imk_input_controller.mm @@ -178,7 +178,7 @@ bool CanSurroundingText(absl::string_view bundle_id) { } } // namespace -@implementation GoogleJapaneseInputController +@implementation MozcImkInputController #pragma mark accessors for testing @synthesize keyCodeMap = keyCodeMap_; @synthesize yenSignCharacter = yenSignCharacter_; @@ -621,10 +621,10 @@ - (void)processOutput:(const mozc::commands::Output *)output client:(id)sender { #pragma mark Mozc Server methods #pragma mark IMKServerInput Protocol -// Currently GoogleJapaneseInputController uses handleEvent:client: +// Currently MozcImkInputController uses handleEvent:client: // method to handle key events. It does not support inputText:client: // nor inputText:key:modifiers:client:. -// Because GoogleJapaneseInputController does not use IMKCandidates, +// Because MozcImkInputController does not use IMKCandidates, // the following methods are not needed to implement: // candidates // @@ -967,3 +967,7 @@ + (void)setGlobalRendererReceiver:(RendererReceiver *)rendererReceiver { gRendererReceiver = rendererReceiver; } @end + +// An alias of MozcImkInputController for backward compatibility. +@implementation GoogleJapaneseInputController +@end diff --git a/src/mac/mozc_imk_input_controller_test.mm b/src/mac/mozc_imk_input_controller_test.mm index 225e475a3..71e2de228 100644 --- a/src/mac/mozc_imk_input_controller_test.mm +++ b/src/mac/mozc_imk_input_controller_test.mm @@ -237,7 +237,7 @@ bool IsAvailable() const override { commands::RendererCommand called_command_; }; -class GoogleJapaneseInputControllerTest : public testing::Test { +class MozcImkInputControllerTest : public testing::Test { protected: void SetUp() override { mock_server_ = [[MockIMKServer alloc] init]; @@ -261,7 +261,7 @@ void TearDown() override { } void SetUpController() { - controller_ = [[GoogleJapaneseInputController alloc] initWithServer:mock_server_ + controller_ = [[MozcImkInputController alloc] initWithServer:mock_server_ delegate:nil client:mock_client_]; controller_.imkClientForTest = mock_client_; @@ -284,7 +284,7 @@ void ResetClientBundleIdentifier(NSString *new_bundle_id) { MockClient *mock_client_; const MockRenderer *mock_renderer_; - GoogleJapaneseInputController *controller_; + MozcImkInputController *controller_; private: MockIMKServer *mock_server_; @@ -368,7 +368,7 @@ NSTimeInterval GetDoubleTapInterval() { return kDoubleTapInterval; } -BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *controller, +BOOL SendKeyEvent(unsigned short keyCode, MozcImkInputController *controller, MockClient *client) { // tap Kana-key NSEvent *kanaKeyEvent = [NSEvent keyEventWithType:NSEventTypeKeyDown @@ -384,7 +384,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control return [controller handleEvent:kanaKeyEvent client:client]; } -TEST_F(GoogleJapaneseInputControllerTest, UpdateComposedString) { +TEST_F(MozcImkInputControllerTest, UpdateComposedString) { // If preedit is nullptr, it still calls setMarkedText, with an empty string. NSMutableAttributedString *expected = [[NSMutableAttributedString alloc] initWithString:@""]; [controller_ updateComposedString:nullptr]; @@ -423,14 +423,14 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control << [[NSString stringWithFormat:@"expected:%@ actual:%@", expected, actual] UTF8String]; } -TEST_F(GoogleJapaneseInputControllerTest, ClearCandidates) { +TEST_F(MozcImkInputControllerTest, ClearCandidates) { [controller_ clearCandidates]; EXPECT_EQ(mock_renderer_->counter_ExecCommand(), 1); // After clearing candidates, the candidate window has to be invisible. EXPECT_FALSE(mock_renderer_->CalledCommand().visible()); } -TEST_F(GoogleJapaneseInputControllerTest, UpdateCandidates) { +TEST_F(MozcImkInputControllerTest, UpdateCandidates) { // When output is null, same as ClearCandidate [controller_ updateCandidates:nullptr]; // Run the runloop so "delayedUpdateCandidates" can be called @@ -490,7 +490,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_FALSE(rendererCommand.visible()); } -TEST_F(GoogleJapaneseInputControllerTest, OpenLink) { +TEST_F(MozcImkInputControllerTest, OpenLink) { EXPECT_EQ(gOpenURLCount, 0); [controller_ openLink:[NSURL URLWithString:@"http://www.example.com/"]]; // openURL is invoked @@ -504,7 +504,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(gOpenURLCount, 1); } -TEST_F(GoogleJapaneseInputControllerTest, SwitchModeToDirect) { +TEST_F(MozcImkInputControllerTest, SwitchModeToDirect) { // setup the IME status controller_.mode = commands::HIRAGANA; commands::Preedit preedit; @@ -528,7 +528,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_FALSE(controller_.rendererCommand.visible()); } -TEST_F(GoogleJapaneseInputControllerTest, SwitchMode) { +TEST_F(MozcImkInputControllerTest, SwitchMode) { // When a mode changes from DIRECT, it should invoke "ON" command beforehand. EXPECT_CALL(*mock_mozc_client_, SendKeyWithContext(HasSpecialKey(commands::KeyEvent::ON), _, NotNull())) @@ -557,7 +557,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(controller_.mode, commands::HALF_KATAKANA); } -TEST_F(GoogleJapaneseInputControllerTest, SwitchDisplayMode) { +TEST_F(MozcImkInputControllerTest, SwitchDisplayMode) { EXPECT_TRUE(mock_client_.selectedMode.empty()); EXPECT_EQ(controller_.mode, commands::DIRECT); [controller_ switchDisplayMode]; @@ -565,7 +565,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(mock_client_.selectedMode, "com.apple.inputmethod.Roman"); // Does not change the display mode for MS Word. See - // GoogleJapaneseInputController.mm for the detailed information. + // MozcImkInputController.mm for the detailed information. ResetClientBundleIdentifier(@"com.microsoft.Word"); [controller_ switchMode:commands::HIRAGANA client:mock_client_]; EXPECT_EQ(controller_.mode, commands::HIRAGANA); @@ -575,7 +575,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(mock_client_.selectedMode, "com.apple.inputmethod.Roman"); } -TEST_F(GoogleJapaneseInputControllerTest, commitText) { +TEST_F(MozcImkInputControllerTest, commitText) { controller_.replacementRange = NSMakeRange(0, 1); [controller_ commitText:"foo" client:mock_client_]; @@ -585,7 +585,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ([controller_ replacementRange].location, NSNotFound); } -TEST_F(GoogleJapaneseInputControllerTest, handleConfig) { +TEST_F(MozcImkInputControllerTest, handleConfig) { // Does not support multiple-calculation config::Config config; config.set_preedit_method(config::Config::KANA); @@ -602,7 +602,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control << [mock_client_.overriddenLayout UTF8String]; } -TEST_F(GoogleJapaneseInputControllerTest, DoubleTapKanaReconvert) { +TEST_F(MozcImkInputControllerTest, DoubleTapKanaReconvert) { // tap (short) tap -> emit undo command controller_.mode = commands::HIRAGANA; @@ -629,7 +629,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_THAT(actual_command, Text("bcd")); } -TEST_F(GoogleJapaneseInputControllerTest, DoubleTapKanaUndo) { +TEST_F(MozcImkInputControllerTest, DoubleTapKanaUndo) { // tap (short) tap -> emit undo command controller_.mode = commands::HIRAGANA; @@ -652,7 +652,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Kana, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, DoubleTapKanaUndoTimeOver) { +TEST_F(MozcImkInputControllerTest, DoubleTapKanaUndoTimeOver) { // tap (long) tap -> don't emit undo command controller_.mode = commands::HIRAGANA; @@ -670,7 +670,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Kana, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, SingleAndDoubleTapKanaUndo) { +TEST_F(MozcImkInputControllerTest, SingleAndDoubleTapKanaUndo) { // tap (long) tap (short) tap -> emit once controller_.mode = commands::HIRAGANA; @@ -699,7 +699,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Kana, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, TripleTapKanaUndo) { +TEST_F(MozcImkInputControllerTest, TripleTapKanaUndo) { // tap (short) tap (short) tap -> emit twice controller_.mode = commands::HIRAGANA; @@ -729,7 +729,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Kana, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, QuadrupleTapKanaUndo) { +TEST_F(MozcImkInputControllerTest, QuadrupleTapKanaUndo) { // tap (short) tap (short) tap (short) tap -> emit thrice controller_.mode = commands::HIRAGANA; @@ -764,7 +764,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Kana, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, DoubleTapEisuCommitRawText) { +TEST_F(MozcImkInputControllerTest, DoubleTapEisuCommitRawText) { // Send Eisu-key. // Because of special hack for Eisu/Kana keys, it returns YES. EXPECT_EQ(SendKeyEvent(kVK_JIS_Eisu, controller_, mock_client_), YES); @@ -780,7 +780,7 @@ BOOL SendKeyEvent(unsigned short keyCode, GoogleJapaneseInputController *control EXPECT_EQ(SendKeyEvent(kVK_JIS_Eisu, controller_, mock_client_), YES); } -TEST_F(GoogleJapaneseInputControllerTest, fillSurroundingContext) { +TEST_F(MozcImkInputControllerTest, fillSurroundingContext) { [mock_client_ setAttributedString:[[NSAttributedString alloc] initWithString:@"abcde"]]; mock_client_.expectedRange = NSMakeRange(2, 1); commands::Context context; diff --git a/src/renderer/mac/CandidateController.mm b/src/renderer/mac/CandidateController.mm index eac336370..4f4993e57 100644 --- a/src/renderer/mac/CandidateController.mm +++ b/src/renderer/mac/CandidateController.mm @@ -202,7 +202,7 @@ int GetBaseScreenHeight() { command_.preedit_rectangle().right() - command_.preedit_rectangle().left(), command_.preedit_rectangle().bottom() - command_.preedit_rectangle().top()); // The origin point of command_.preedit_rectangle() is the left-top of the - // base screen which is set in GoogleJapaneseInputController. It is + // base screen which is set in MozcImkInputController. It is // unnecessary calculation but to support older version of GoogleJapaneseInput // process we should not change it. So we minus the height of the screen here. mozc::Rect preedit_rect(mozc::Point(command_.preedit_rectangle().left(), @@ -211,7 +211,7 @@ int GetBaseScreenHeight() { // This is a hacky way to check vertical writing. // TODO(komatsu): We should use the return value of attributesForCharacterIndex - // in GoogleJapaneseInputController.mm as a proper way. + // in MozcImkInputController as a proper way. const bool is_vertical = (preedit_size.height < preedit_size.width); // Expand the rect size to make a margin to the candidate window. diff --git a/src/renderer/mac/CandidateView.h b/src/renderer/mac/CandidateView.h index abe5b7ed3..ad3d66764 100644 --- a/src/renderer/mac/CandidateView.h +++ b/src/renderer/mac/CandidateView.h @@ -73,7 +73,7 @@ enum COLUMN_TYPE { // setCandidates: sets the candidates to be rendered. - (void)setCandidates:(const mozc::commands::Candidates *)candidates; -// setController: sets the reference of GoogleJapaneseInputController. +// setController: sets the reference of MozcImkInputController. // It will be used when mouse clicks. It doesn't take ownerships of // |controller|. - (void)setSendCommandInterface:(mozc::client::SendCommandInterface *)command_sender; From 835623d08ade4dded6f8f2722770a114bd578bfd Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Tue, 8 Oct 2024 03:12:01 +0000 Subject: [PATCH 07/13] Remove NSImage:setFlipped. * NSImage:setFlipped has been deprecated since macOS 10.6 (Snow Leopard). #codehealth PiperOrigin-RevId: 683431178 --- src/renderer/mac/CandidateView.mm | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/renderer/mac/CandidateView.mm b/src/renderer/mac/CandidateView.mm index da2993931..908c45149 100644 --- a/src/renderer/mac/CandidateView.mm +++ b/src/renderer/mac/CandidateView.mm @@ -27,10 +27,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include - #import "renderer/mac/CandidateView.h" +#import + +#include + #include "absl/base/call_once.h" #include "absl/log/log.h" #include "client/client_interface.h" @@ -65,11 +67,6 @@ void InitializeDefaultStyle() { std::string logo_file_name = style.logo_file_name(); g_LogoImage = [NSImage imageNamed:[NSString stringWithUTF8String:logo_file_name.c_str()]]; if (g_LogoImage) { - // setFlipped is deprecated at Snow Leopard, but we use this because - // it works well with Snow Leopard and new method to deal with - // flipped view doesn't work with Leopard. - [g_LogoImage setFlipped:YES]; - // Fix the image size. Sometimes the size can be smaller than the // actual size because of blank margin. NSArray *logoReps = [g_LogoImage representations]; @@ -361,11 +358,15 @@ - (void)drawFooter { // Draw logo if (footer.logo_visible() && g_LogoImage) { - [g_LogoImage drawAtPoint:footerRect.origin - fromRect:NSZeroRect /* means draw entire image */ - operation:NSCompositingOperationSourceOver - fraction:1.0 /* opacity */]; - NSSize logoSize = [g_LogoImage size]; + const NSPoint logoPoint = footerRect.origin; + const NSSize logoSize = g_LogoImage.size; + const NSRect logoRect = NSMakeRect(logoPoint.x, logoPoint.y, logoSize.width, logoSize.height); + [g_LogoImage drawInRect:logoRect + fromRect:NSZeroRect // Draw the entire image + operation:NSCompositingOperationSourceOver + fraction:1.0 // Opacity + respectFlipped:YES + hints:nil]; footerRect.origin.x += logoSize.width; footerRect.size.width -= logoSize.width; } From b3e136e19fcc25f48339f1cfa6dcc038104a0678 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Tue, 8 Oct 2024 03:13:59 +0000 Subject: [PATCH 08/13] Refactoring of the CandidateView class. * Move instance variables from .h to .mm. * Allocate the variables from heap to stack. #codehealth PiperOrigin-RevId: 683431606 --- src/renderer/mac/CandidateView.h | 16 +--- src/renderer/mac/CandidateView.mm | 147 +++++++++++++++--------------- 2 files changed, 77 insertions(+), 86 deletions(-) diff --git a/src/renderer/mac/CandidateView.h b/src/renderer/mac/CandidateView.h index ad3d66764..e40a02142 100644 --- a/src/renderer/mac/CandidateView.h +++ b/src/renderer/mac/CandidateView.h @@ -54,21 +54,7 @@ enum COLUMN_TYPE { // CandidateView is an NSView subclass to draw the candidate window // according to the current candidates. -@interface CandidateView : NSView { - @private - mozc::commands::Candidates candidates_; - mozc::renderer::TableLayout *tableLayout_; - const mozc::renderer::RendererStyle *style_; - - // The row which has focused background. - int focusedRow_; - - // Cache of attributed strings which is allocated at updateLayout. - NSArray *candidateStringsCache_; - - // |command_sender_| holds a callback for mouse clicks. - mozc::client::SendCommandInterface *command_sender_; -} +@interface CandidateView : NSView // setCandidates: sets the candidates to be rendered. - (void)setCandidates:(const mozc::commands::Candidates *)candidates; diff --git a/src/renderer/mac/CandidateView.mm b/src/renderer/mac/CandidateView.mm index 908c45149..6507f4fda 100644 --- a/src/renderer/mac/CandidateView.mm +++ b/src/renderer/mac/CandidateView.mm @@ -102,24 +102,30 @@ - (void)drawFooter; - (void)drawVScrollBar; @end -@implementation CandidateView +@implementation CandidateView { + mozc::commands::Candidates candidates_; + mozc::renderer::TableLayout tableLayout_; + mozc::renderer::RendererStyle style_; + + // The row which has focused background. + int focusedRow_; + + // Cache of attributed strings which is allocated at updateLayout. + NSArray *candidateStringsCache_; + + // |command_sender_| holds a callback for mouse clicks. + mozc::client::SendCommandInterface *command_sender_; +} + #pragma mark initialization - (id)initWithFrame:(NSRect)frame { absl::call_once(g_OnceForInitializeStyle, &InitializeDefaultStyle); self = [super initWithFrame:frame]; if (self) { - tableLayout_ = new (std::nothrow) TableLayout; - RendererStyle *style = new (std::nothrow) RendererStyle; - if (style) { - RendererStyleHandler::GetRendererStyle(style); - } - style_ = style; + RendererStyleHandler::GetRendererStyle(&style_); focusedRow_ = -1; } - if (!tableLayout_ || !style_) { - self = nil; - } return self; } @@ -131,18 +137,17 @@ - (void)setSendCommandInterface:(SendCommandInterface *)command_sender { command_sender_ = command_sender; } +// Override of NSView. - (BOOL)isFlipped { return YES; } - (void)dealloc { candidateStringsCache_ = nil; - delete tableLayout_; - delete style_; } - (const TableLayout *)tableLayout { - return tableLayout_; + return &tableLayout_; } #pragma mark drawing @@ -150,8 +155,8 @@ - (const TableLayout *)tableLayout { #define max(x, y) (((x) > (y)) ? (x) : (y)) - (NSSize)updateLayout { candidateStringsCache_ = nil; - tableLayout_->Initialize(candidates_.candidate_size(), NUMBER_OF_COLUMNS); - tableLayout_->SetWindowBorder(style_->window_border()); + tableLayout_.Initialize(candidates_.candidate_size(), NUMBER_OF_COLUMNS); + tableLayout_.SetWindowBorder(style_.window_border()); // calculating focusedRow_ if (candidates_.has_focused_index() && candidates_.candidate_size() > 0) { @@ -169,18 +174,18 @@ - (NSSize)updateLayout { if (footer.has_label()) { NSAttributedString *footerLabel = - MacViewUtil::ToNSAttributedString(footer.label(), style_->footer_style()); + MacViewUtil::ToNSAttributedString(footer.label(), style_.footer_style()); NSSize footerLabelSize = - MacViewUtil::applyTheme([footerLabel size], style_ -> footer_style()); + MacViewUtil::applyTheme([footerLabel size], style_.footer_style()); footerSize.width += footerLabelSize.width; footerSize.height = max(footerSize.height, footerLabelSize.height); } if (footer.has_sub_label()) { NSAttributedString *footerSubLabel = - MacViewUtil::ToNSAttributedString(footer.sub_label(), style_->footer_sub_label_style()); + MacViewUtil::ToNSAttributedString(footer.sub_label(), style_.footer_sub_label_style()); NSSize footerSubLabelSize = - MacViewUtil::applyTheme([footerSubLabel size], style_ -> footer_sub_label_style()); + MacViewUtil::applyTheme([footerSubLabel size], style_.footer_sub_label_style()); footerSize.width += footerSubLabelSize.width; footerSize.height = max(footerSize.height, footerSubLabelSize.height); } @@ -196,31 +201,31 @@ - (NSSize)updateLayout { const int totalItems = candidates_.size(); NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex + 1, totalItems]; NSAttributedString *footerAttributedIndex = - MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_ -> footer_style()); + MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); NSSize footerIndexSize = - MacViewUtil::applyTheme([footerAttributedIndex size], style_ -> footer_style()); + MacViewUtil::applyTheme([footerAttributedIndex size], style_.footer_style()); footerSize.width += footerIndexSize.width; footerSize.height = max(footerSize.height, footerIndexSize.height); } - footerSize.height += style_->footer_border_colors_size(); - tableLayout_->EnsureFooterSize(MacViewUtil::ToSize(footerSize)); + footerSize.height += style_.footer_border_colors_size(); + tableLayout_.EnsureFooterSize(MacViewUtil::ToSize(footerSize)); } - tableLayout_->SetRowRectPadding(style_->row_rect_padding()); + tableLayout_.SetRowRectPadding(style_.row_rect_padding()); if (candidates_.candidate_size() < candidates_.size()) { - tableLayout_->SetVScrollBar(style_->scrollbar_width()); + tableLayout_.SetVScrollBar(style_.scrollbar_width()); } NSAttributedString *gap1 = - MacViewUtil::ToNSAttributedString(" ", style_->text_styles(COLUMN_GAP1)); - tableLayout_->EnsureCellSize(COLUMN_GAP1, MacViewUtil::ToSize([gap1 size])); + MacViewUtil::ToNSAttributedString(" ", style_.text_styles(COLUMN_GAP1)); + tableLayout_.EnsureCellSize(COLUMN_GAP1, MacViewUtil::ToSize([gap1 size])); NSMutableArray *newCache = [[NSMutableArray array] init]; for (size_t i = 0; i < candidates_.candidate_size(); ++i) { const Candidates::Candidate &candidate = candidates_.candidate(i); NSAttributedString *shortcut = MacViewUtil::ToNSAttributedString( - candidate.annotation().shortcut(), style_->text_styles(COLUMN_SHORTCUT)); + candidate.annotation().shortcut(), style_.text_styles(COLUMN_SHORTCUT)); std::string value = candidate.value(); if (candidate.annotation().has_prefix()) { value = candidate.annotation().prefix() + value; @@ -233,34 +238,34 @@ - (NSSize)updateLayout { } NSAttributedString *candidateValue = - MacViewUtil::ToNSAttributedString(value, style_->text_styles(COLUMN_CANDIDATE)); + MacViewUtil::ToNSAttributedString(value, style_.text_styles(COLUMN_CANDIDATE)); NSAttributedString *description = MacViewUtil::ToNSAttributedString( - candidate.annotation().description(), style_->text_styles(COLUMN_DESCRIPTION)); + candidate.annotation().description(), style_.text_styles(COLUMN_DESCRIPTION)); if ([shortcut length] > 0) { NSSize shortcutSize = - MacViewUtil::applyTheme([shortcut size], style_ -> text_styles(COLUMN_SHORTCUT)); - tableLayout_->EnsureCellSize(COLUMN_SHORTCUT, MacViewUtil::ToSize(shortcutSize)); + MacViewUtil::applyTheme([shortcut size], style_.text_styles(COLUMN_SHORTCUT)); + tableLayout_.EnsureCellSize(COLUMN_SHORTCUT, MacViewUtil::ToSize(shortcutSize)); } if ([candidateValue length] > 0) { NSSize valueSize = - MacViewUtil::applyTheme([candidateValue size], style_ -> text_styles(COLUMN_CANDIDATE)); - tableLayout_->EnsureCellSize(COLUMN_CANDIDATE, MacViewUtil::ToSize(valueSize)); + MacViewUtil::applyTheme([candidateValue size], style_.text_styles(COLUMN_CANDIDATE)); + tableLayout_.EnsureCellSize(COLUMN_CANDIDATE, MacViewUtil::ToSize(valueSize)); } if ([description length] > 0) { NSSize descriptionSize = - MacViewUtil::applyTheme([description size], style_ -> text_styles(COLUMN_DESCRIPTION)); - tableLayout_->EnsureCellSize(COLUMN_DESCRIPTION, MacViewUtil::ToSize(descriptionSize)); + MacViewUtil::applyTheme([description size], style_.text_styles(COLUMN_DESCRIPTION)); + tableLayout_.EnsureCellSize(COLUMN_DESCRIPTION, MacViewUtil::ToSize(descriptionSize)); } [newCache addObject:[NSArray arrayWithObjects:shortcut, gap1, candidateValue, description, nil]]; } - tableLayout_->EnsureColumnsWidth(COLUMN_CANDIDATE, COLUMN_DESCRIPTION, g_column_minimum_width); + tableLayout_.EnsureColumnsWidth(COLUMN_CANDIDATE, COLUMN_DESCRIPTION, g_column_minimum_width); candidateStringsCache_ = newCache; - tableLayout_->FreezeLayout(); - return MacViewUtil::ToNSSize(tableLayout_->GetTotalSize()); + tableLayout_.FreezeLayout(); + return MacViewUtil::ToNSSize(tableLayout_.GetTotalSize()); } - (void)drawRect:(NSRect)rect { @@ -279,8 +284,8 @@ - (void)drawRect:(NSRect)rect { [self drawFooter]; // Draw the window border at last - [MacViewUtil::ToNSColor(style_->border_color()) set]; - mozc::Size windowSize = tableLayout_->GetTotalSize(); + [MacViewUtil::ToNSColor(style_.border_color()) set]; + mozc::Size windowSize = tableLayout_.GetTotalSize(); [NSBezierPath strokeRect:NSMakeRect(0.5, 0.5, windowSize.width - 1, windowSize.height - 1)]; } @@ -289,10 +294,10 @@ - (void)drawRect:(NSRect)rect { - (void)drawRow:(int)row { if (row == focusedRow_) { // Draw focused background - NSRect focusedRect = MacViewUtil::ToNSRect(tableLayout_->GetRowRect(focusedRow_)); - [MacViewUtil::ToNSColor(style_->focused_background_color()) set]; + NSRect focusedRect = MacViewUtil::ToNSRect(tableLayout_.GetRowRect(focusedRow_)); + [MacViewUtil::ToNSColor(style_.focused_background_color()) set]; [NSBezierPath fillRect:focusedRect]; - [MacViewUtil::ToNSColor(style_->focused_border_color()) set]; + [MacViewUtil::ToNSColor(style_.focused_border_color()) set]; // Fix the border position. Because a line should be drawn at the // middle point of the pixel, origin should be shifted by 0.5 unit // and the size should be shrinked by 1.0 unit. @@ -304,10 +309,10 @@ - (void)drawRow:(int)row { } else { // Draw normal background for (int i = COLUMN_SHORTCUT; i < NUMBER_OF_COLUMNS; ++i) { - mozc::Rect cellRect = tableLayout_->GetCellRect(row, i); + mozc::Rect cellRect = tableLayout_.GetCellRect(row, i); if (cellRect.size.width > 0 && cellRect.size.height > 0 && - style_->text_styles(i).has_background_color()) { - [MacViewUtil::ToNSColor(style_->text_styles(i).background_color()) set]; + style_.text_styles(i).has_background_color()) { + [MacViewUtil::ToNSColor(style_.text_styles(i).background_color()) set]; [NSBezierPath fillRect:MacViewUtil::ToNSRect(cellRect)]; } } @@ -316,17 +321,17 @@ - (void)drawRow:(int)row { NSArray *candidate = [candidateStringsCache_ objectAtIndex:row]; for (int i = COLUMN_SHORTCUT; i < NUMBER_OF_COLUMNS; ++i) { NSAttributedString *text = [candidate objectAtIndex:i]; - NSRect cellRect = MacViewUtil::ToNSRect(tableLayout_->GetCellRect(row, i)); + NSRect cellRect = MacViewUtil::ToNSRect(tableLayout_.GetCellRect(row, i)); NSPoint &candidatePosition = cellRect.origin; // Adjust the positions - candidatePosition.x += style_->text_styles(i).left_padding(); + candidatePosition.x += style_.text_styles(i).left_padding(); candidatePosition.y += (cellRect.size.height - [text size].height) / 2; [text drawAtPoint:candidatePosition]; } if (candidates_.candidate(row).has_information_id()) { - NSRect rect = MacViewUtil::ToNSRect(tableLayout_->GetRowRect(row)); - [MacViewUtil::ToNSColor(style_->focused_border_color()) set]; + NSRect rect = MacViewUtil::ToNSRect(tableLayout_.GetRowRect(row)); + [MacViewUtil::ToNSColor(style_.focused_border_color()) set]; rect.origin.x += rect.size.width - 6.0; rect.size.width = 4.0; rect.origin.y += 2.0; @@ -338,11 +343,11 @@ - (void)drawRow:(int)row { - (void)drawFooter { if (candidates_.has_footer()) { const mozc::commands::Footer &footer = candidates_.footer(); - NSRect footerRect = MacViewUtil::ToNSRect(tableLayout_->GetFooterRect()); + NSRect footerRect = MacViewUtil::ToNSRect(tableLayout_.GetFooterRect()); // Draw footer border - for (int i = 0; i < style_->footer_border_colors_size(); ++i) { - [MacViewUtil::ToNSColor(style_->footer_border_colors(i)) set]; + for (int i = 0; i < style_.footer_border_colors_size(); ++i) { + [MacViewUtil::ToNSColor(style_.footer_border_colors(i)) set]; NSPoint fromPoint = NSMakePoint(footerRect.origin.x, footerRect.origin.y + 0.5); NSPoint toPoint = NSMakePoint(footerRect.origin.x + footerRect.size.width, footerRect.origin.y + 0.5); @@ -352,8 +357,8 @@ - (void)drawFooter { // Draw Footer background and data if necessary NSGradient *footerBackground = [[NSGradient alloc] - initWithStartingColor:MacViewUtil::ToNSColor(style_->footer_top_color()) - endingColor:MacViewUtil::ToNSColor(style_->footer_bottom_color())]; + initWithStartingColor:MacViewUtil::ToNSColor(style_.footer_top_color()) + endingColor:MacViewUtil::ToNSColor(style_.footer_bottom_color())]; [footerBackground drawInRect:footerRect angle:90.0]; // Draw logo @@ -374,8 +379,8 @@ - (void)drawFooter { // Draw label if (footer.has_label()) { NSAttributedString *footerLabel = - MacViewUtil::ToNSAttributedString(footer.label(), style_->footer_style()); - footerRect.origin.x += style_->footer_style().left_padding(); + MacViewUtil::ToNSAttributedString(footer.label(), style_.footer_style()); + footerRect.origin.x += style_.footer_style().left_padding(); NSSize labelSize = [footerLabel size]; NSPoint labelPosition = footerRect.origin; labelPosition.y += (footerRect.size.height - labelSize.height) / 2; @@ -385,8 +390,8 @@ - (void)drawFooter { // Draw sub_label if (footer.has_sub_label()) { NSAttributedString *footerSubLabel = - MacViewUtil::ToNSAttributedString(footer.sub_label(), style_->footer_sub_label_style()); - footerRect.origin.x += style_->footer_sub_label_style().left_padding(); + MacViewUtil::ToNSAttributedString(footer.sub_label(), style_.footer_sub_label_style()); + footerRect.origin.x += style_.footer_sub_label_style().left_padding(); NSSize subLabelSize = [footerSubLabel size]; NSPoint subLabelPosition = footerRect.origin; subLabelPosition.y += (footerRect.size.height - subLabelSize.height) / 2; @@ -399,30 +404,30 @@ - (void)drawFooter { int totalItems = candidates_.size(); NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex + 1, totalItems]; NSAttributedString *footerAttributedIndex = - MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_ -> footer_style()); + MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); NSSize footerSize = [footerAttributedIndex size]; NSPoint footerPosition = footerRect.origin; footerPosition.x = footerPosition.x + footerRect.size.width - footerSize.width - - style_->footer_style().right_padding(); + style_.footer_style().right_padding(); [footerAttributedIndex drawAtPoint:footerPosition]; } } } - (void)drawVScrollBar { - const mozc::Rect &vscrollRect = tableLayout_->GetVScrollBarRect(); + const mozc::Rect &vscrollRect = tableLayout_.GetVScrollBarRect(); if (!vscrollRect.IsRectEmpty() && candidates_.candidate_size() > 0) { const int beginIndex = candidates_.candidate(0).index(); const int candidatesTotal = candidates_.size(); const int endIndex = candidates_.candidate(candidates_.candidate_size() - 1).index(); - [MacViewUtil::ToNSColor(style_->scrollbar_background_color()) set]; + [MacViewUtil::ToNSColor(style_.scrollbar_background_color()) set]; [NSBezierPath fillRect:MacViewUtil::ToNSRect(vscrollRect)]; const mozc::Rect &indicatorRect = - tableLayout_->GetVScrollIndicatorRect(beginIndex, endIndex, candidatesTotal); - [MacViewUtil::ToNSColor(style_->scrollbar_indicator_color()) set]; + tableLayout_.GetVScrollIndicatorRect(beginIndex, endIndex, candidatesTotal); + [MacViewUtil::ToNSColor(style_.scrollbar_indicator_color()) set]; [NSBezierPath fillRect:MacViewUtil::ToNSRect(indicatorRect)]; } } @@ -435,8 +440,8 @@ - (void)mouseDown:(NSEvent *)event { mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] fromView:nil]); int clickedRow = -1; - for (int i = 0; i < tableLayout_->number_of_rows(); ++i) { - mozc::Rect rowRect = tableLayout_->GetRowRect(i); + for (int i = 0; i < tableLayout_.number_of_rows(); ++i) { + mozc::Rect rowRect = tableLayout_.GetRowRect(i); if (rowRect.PtrInRect(localPos)) { clickedRow = i; break; @@ -455,11 +460,11 @@ - (void)mouseUp:(NSEvent *)event { if (command_sender_ == nullptr) { return; } - if (candidates_.candidate_size() < tableLayout_->number_of_rows()) { + if (candidates_.candidate_size() < tableLayout_.number_of_rows()) { return; } - for (int i = 0; i < tableLayout_->number_of_rows(); ++i) { - mozc::Rect rowRect = tableLayout_->GetRowRect(i); + for (int i = 0; i < tableLayout_.number_of_rows(); ++i) { + mozc::Rect rowRect = tableLayout_.GetRowRect(i); if (rowRect.PtrInRect(localPos)) { SessionCommand command; command.set_type(SessionCommand::SELECT_CANDIDATE); From b5cf5e799b05eb0fe9b2cb34d26917f0fc6c3cf6 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Tue, 8 Oct 2024 03:15:54 +0000 Subject: [PATCH 09/13] Refactoring of CandidateView. * Use const for local variables. * Use insert() instead of operator+ for std::string. * Use early return in drawFooter() and drawVScrollBar(). #codehealth PiperOrigin-RevId: 683432020 --- src/renderer/mac/CandidateView.mm | 209 +++++++++++++++--------------- 1 file changed, 106 insertions(+), 103 deletions(-) diff --git a/src/renderer/mac/CandidateView.mm b/src/renderer/mac/CandidateView.mm index 6507f4fda..0492f866d 100644 --- a/src/renderer/mac/CandidateView.mm +++ b/src/renderer/mac/CandidateView.mm @@ -173,25 +173,25 @@ - (NSSize)updateLayout { const mozc::commands::Footer &footer = candidates_.footer(); if (footer.has_label()) { - NSAttributedString *footerLabel = + const NSAttributedString *footerLabel = MacViewUtil::ToNSAttributedString(footer.label(), style_.footer_style()); - NSSize footerLabelSize = + const NSSize footerLabelSize = MacViewUtil::applyTheme([footerLabel size], style_.footer_style()); footerSize.width += footerLabelSize.width; footerSize.height = max(footerSize.height, footerLabelSize.height); } if (footer.has_sub_label()) { - NSAttributedString *footerSubLabel = + const NSAttributedString *footerSubLabel = MacViewUtil::ToNSAttributedString(footer.sub_label(), style_.footer_sub_label_style()); - NSSize footerSubLabelSize = + const NSSize footerSubLabelSize = MacViewUtil::applyTheme([footerSubLabel size], style_.footer_sub_label_style()); footerSize.width += footerSubLabelSize.width; footerSize.height = max(footerSize.height, footerSubLabelSize.height); } if (footer.logo_visible() && g_LogoImage) { - NSSize logoSize = [g_LogoImage size]; + const NSSize logoSize = [g_LogoImage size]; footerSize.width += logoSize.width; footerSize.height = max(footerSize.height, logoSize.height); } @@ -199,10 +199,11 @@ - (NSSize)updateLayout { if (footer.index_visible()) { const int focusedIndex = candidates_.focused_index(); const int totalItems = candidates_.size(); - NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex + 1, totalItems]; - NSAttributedString *footerAttributedIndex = + const NSString *footerIndex = + [NSString stringWithFormat:@"%d/%d", focusedIndex + 1, totalItems]; + const NSAttributedString *footerAttributedIndex = MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); - NSSize footerIndexSize = + const NSSize footerIndexSize = MacViewUtil::applyTheme([footerAttributedIndex size], style_.footer_style()); footerSize.width += footerIndexSize.width; footerSize.height = max(footerSize.height, footerIndexSize.height); @@ -217,18 +218,18 @@ - (NSSize)updateLayout { tableLayout_.SetVScrollBar(style_.scrollbar_width()); } - NSAttributedString *gap1 = + const NSAttributedString *gap1 = MacViewUtil::ToNSAttributedString(" ", style_.text_styles(COLUMN_GAP1)); tableLayout_.EnsureCellSize(COLUMN_GAP1, MacViewUtil::ToSize([gap1 size])); NSMutableArray *newCache = [[NSMutableArray array] init]; for (size_t i = 0; i < candidates_.candidate_size(); ++i) { const Candidates::Candidate &candidate = candidates_.candidate(i); - NSAttributedString *shortcut = MacViewUtil::ToNSAttributedString( + const NSAttributedString *shortcut = MacViewUtil::ToNSAttributedString( candidate.annotation().shortcut(), style_.text_styles(COLUMN_SHORTCUT)); std::string value = candidate.value(); if (candidate.annotation().has_prefix()) { - value = candidate.annotation().prefix() + value; + value.insert(0, candidate.annotation().prefix()); // Prepend the prefix() to value. } if (candidate.annotation().has_suffix()) { value.append(candidate.annotation().suffix()); @@ -237,22 +238,22 @@ - (NSSize)updateLayout { value.append(" "); } - NSAttributedString *candidateValue = + const NSAttributedString *candidateValue = MacViewUtil::ToNSAttributedString(value, style_.text_styles(COLUMN_CANDIDATE)); - NSAttributedString *description = MacViewUtil::ToNSAttributedString( + const NSAttributedString *description = MacViewUtil::ToNSAttributedString( candidate.annotation().description(), style_.text_styles(COLUMN_DESCRIPTION)); if ([shortcut length] > 0) { - NSSize shortcutSize = + const NSSize shortcutSize = MacViewUtil::applyTheme([shortcut size], style_.text_styles(COLUMN_SHORTCUT)); tableLayout_.EnsureCellSize(COLUMN_SHORTCUT, MacViewUtil::ToSize(shortcutSize)); } if ([candidateValue length] > 0) { - NSSize valueSize = + const NSSize valueSize = MacViewUtil::applyTheme([candidateValue size], style_.text_styles(COLUMN_CANDIDATE)); tableLayout_.EnsureCellSize(COLUMN_CANDIDATE, MacViewUtil::ToSize(valueSize)); } if ([description length] > 0) { - NSSize descriptionSize = + const NSSize descriptionSize = MacViewUtil::applyTheme([description size], style_.text_styles(COLUMN_DESCRIPTION)); tableLayout_.EnsureCellSize(COLUMN_DESCRIPTION, MacViewUtil::ToSize(descriptionSize)); } @@ -285,7 +286,7 @@ - (void)drawRect:(NSRect)rect { // Draw the window border at last [MacViewUtil::ToNSColor(style_.border_color()) set]; - mozc::Size windowSize = tableLayout_.GetTotalSize(); + const mozc::Size windowSize = tableLayout_.GetTotalSize(); [NSBezierPath strokeRect:NSMakeRect(0.5, 0.5, windowSize.width - 1, windowSize.height - 1)]; } @@ -309,7 +310,7 @@ - (void)drawRow:(int)row { } else { // Draw normal background for (int i = COLUMN_SHORTCUT; i < NUMBER_OF_COLUMNS; ++i) { - mozc::Rect cellRect = tableLayout_.GetCellRect(row, i); + const mozc::Rect cellRect = tableLayout_.GetCellRect(row, i); if (cellRect.size.width > 0 && cellRect.size.height > 0 && style_.text_styles(i).has_background_color()) { [MacViewUtil::ToNSColor(style_.text_styles(i).background_color()) set]; @@ -320,7 +321,7 @@ - (void)drawRow:(int)row { NSArray *candidate = [candidateStringsCache_ objectAtIndex:row]; for (int i = COLUMN_SHORTCUT; i < NUMBER_OF_COLUMNS; ++i) { - NSAttributedString *text = [candidate objectAtIndex:i]; + const NSAttributedString *text = [candidate objectAtIndex:i]; NSRect cellRect = MacViewUtil::ToNSRect(tableLayout_.GetCellRect(row, i)); NSPoint &candidatePosition = cellRect.origin; // Adjust the positions @@ -341,95 +342,97 @@ - (void)drawRow:(int)row { } - (void)drawFooter { - if (candidates_.has_footer()) { - const mozc::commands::Footer &footer = candidates_.footer(); - NSRect footerRect = MacViewUtil::ToNSRect(tableLayout_.GetFooterRect()); - - // Draw footer border - for (int i = 0; i < style_.footer_border_colors_size(); ++i) { - [MacViewUtil::ToNSColor(style_.footer_border_colors(i)) set]; - NSPoint fromPoint = NSMakePoint(footerRect.origin.x, footerRect.origin.y + 0.5); - NSPoint toPoint = - NSMakePoint(footerRect.origin.x + footerRect.size.width, footerRect.origin.y + 0.5); - [NSBezierPath strokeLineFromPoint:fromPoint toPoint:toPoint]; - footerRect.origin.y += 1; - } - - // Draw Footer background and data if necessary - NSGradient *footerBackground = [[NSGradient alloc] - initWithStartingColor:MacViewUtil::ToNSColor(style_.footer_top_color()) - endingColor:MacViewUtil::ToNSColor(style_.footer_bottom_color())]; - [footerBackground drawInRect:footerRect angle:90.0]; + if (!candidates_.has_footer()) { + return; + } + const mozc::commands::Footer &footer = candidates_.footer(); + NSRect footerRect = MacViewUtil::ToNSRect(tableLayout_.GetFooterRect()); + + // Draw footer border + for (int i = 0; i < style_.footer_border_colors_size(); ++i) { + [MacViewUtil::ToNSColor(style_.footer_border_colors(i)) set]; + const NSPoint fromPoint = NSMakePoint(footerRect.origin.x, footerRect.origin.y + 0.5); + const NSPoint toPoint = + NSMakePoint(footerRect.origin.x + footerRect.size.width, footerRect.origin.y + 0.5); + [NSBezierPath strokeLineFromPoint:fromPoint toPoint:toPoint]; + footerRect.origin.y += 1; + } - // Draw logo - if (footer.logo_visible() && g_LogoImage) { - const NSPoint logoPoint = footerRect.origin; - const NSSize logoSize = g_LogoImage.size; - const NSRect logoRect = NSMakeRect(logoPoint.x, logoPoint.y, logoSize.width, logoSize.height); - [g_LogoImage drawInRect:logoRect - fromRect:NSZeroRect // Draw the entire image - operation:NSCompositingOperationSourceOver - fraction:1.0 // Opacity - respectFlipped:YES - hints:nil]; - footerRect.origin.x += logoSize.width; - footerRect.size.width -= logoSize.width; - } + // Draw Footer background and data if necessary + const NSGradient *footerBackground = [[NSGradient alloc] + initWithStartingColor:MacViewUtil::ToNSColor(style_.footer_top_color()) + endingColor:MacViewUtil::ToNSColor(style_.footer_bottom_color())]; + [footerBackground drawInRect:footerRect angle:90.0]; + + // Draw logo + if (footer.logo_visible() && g_LogoImage) { + const NSPoint logoPoint = footerRect.origin; + const NSSize logoSize = g_LogoImage.size; + const NSRect logoRect = NSMakeRect(logoPoint.x, logoPoint.y, logoSize.width, logoSize.height); + [g_LogoImage drawInRect:logoRect + fromRect:NSZeroRect // Draw the entire image + operation:NSCompositingOperationSourceOver + fraction:1.0 // Opacity + respectFlipped:YES + hints:nil]; + footerRect.origin.x += logoSize.width; + footerRect.size.width -= logoSize.width; + } - // Draw label - if (footer.has_label()) { - NSAttributedString *footerLabel = - MacViewUtil::ToNSAttributedString(footer.label(), style_.footer_style()); - footerRect.origin.x += style_.footer_style().left_padding(); - NSSize labelSize = [footerLabel size]; - NSPoint labelPosition = footerRect.origin; - labelPosition.y += (footerRect.size.height - labelSize.height) / 2; - [footerLabel drawAtPoint:labelPosition]; - } + // Draw label + if (footer.has_label()) { + const NSAttributedString *footerLabel = + MacViewUtil::ToNSAttributedString(footer.label(), style_.footer_style()); + footerRect.origin.x += style_.footer_style().left_padding(); + const NSSize labelSize = [footerLabel size]; + NSPoint labelPosition = footerRect.origin; + labelPosition.y += (footerRect.size.height - labelSize.height) / 2; + [footerLabel drawAtPoint:labelPosition]; + } - // Draw sub_label - if (footer.has_sub_label()) { - NSAttributedString *footerSubLabel = - MacViewUtil::ToNSAttributedString(footer.sub_label(), style_.footer_sub_label_style()); - footerRect.origin.x += style_.footer_sub_label_style().left_padding(); - NSSize subLabelSize = [footerSubLabel size]; - NSPoint subLabelPosition = footerRect.origin; - subLabelPosition.y += (footerRect.size.height - subLabelSize.height) / 2; - [footerSubLabel drawAtPoint:subLabelPosition]; - } + // Draw sub_label + if (footer.has_sub_label()) { + const NSAttributedString *footerSubLabel = + MacViewUtil::ToNSAttributedString(footer.sub_label(), style_.footer_sub_label_style()); + footerRect.origin.x += style_.footer_sub_label_style().left_padding(); + const NSSize subLabelSize = [footerSubLabel size]; + NSPoint subLabelPosition = footerRect.origin; + subLabelPosition.y += (footerRect.size.height - subLabelSize.height) / 2; + [footerSubLabel drawAtPoint:subLabelPosition]; + } - // Draw footer index (e.g. "10/120") - if (footer.index_visible()) { - int focusedIndex = candidates_.focused_index(); - int totalItems = candidates_.size(); - NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex + 1, totalItems]; - NSAttributedString *footerAttributedIndex = - MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); - NSSize footerSize = [footerAttributedIndex size]; - NSPoint footerPosition = footerRect.origin; - footerPosition.x = footerPosition.x + footerRect.size.width - footerSize.width - - style_.footer_style().right_padding(); - [footerAttributedIndex drawAtPoint:footerPosition]; - } + // Draw footer index (e.g. "10/120") + if (footer.index_visible()) { + const int focusedIndex = candidates_.focused_index() + 1; // +1 to 1-origin from 0-origin. + const int totalItems = candidates_.size(); + const NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex, totalItems]; + const NSAttributedString *footerAttributedIndex = + MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); + const NSSize footerSize = [footerAttributedIndex size]; + NSPoint footerPosition = footerRect.origin; + footerPosition.x = footerPosition.x + footerRect.size.width - footerSize.width - + style_.footer_style().right_padding(); + [footerAttributedIndex drawAtPoint:footerPosition]; } } - (void)drawVScrollBar { - const mozc::Rect &vscrollRect = tableLayout_.GetVScrollBarRect(); + const mozc::Rect vscrollRect = tableLayout_.GetVScrollBarRect(); + if (vscrollRect.IsRectEmpty() || candidates_.candidate_size() <= 0) { + return; + } - if (!vscrollRect.IsRectEmpty() && candidates_.candidate_size() > 0) { - const int beginIndex = candidates_.candidate(0).index(); - const int candidatesTotal = candidates_.size(); - const int endIndex = candidates_.candidate(candidates_.candidate_size() - 1).index(); + const int beginIndex = candidates_.candidate(0).index(); + const int candidatesTotal = candidates_.size(); + const int endIndex = candidates_.candidate(candidates_.candidate_size() - 1).index(); - [MacViewUtil::ToNSColor(style_.scrollbar_background_color()) set]; - [NSBezierPath fillRect:MacViewUtil::ToNSRect(vscrollRect)]; + [MacViewUtil::ToNSColor(style_.scrollbar_background_color()) set]; + [NSBezierPath fillRect:MacViewUtil::ToNSRect(vscrollRect)]; - const mozc::Rect &indicatorRect = - tableLayout_.GetVScrollIndicatorRect(beginIndex, endIndex, candidatesTotal); - [MacViewUtil::ToNSColor(style_.scrollbar_indicator_color()) set]; - [NSBezierPath fillRect:MacViewUtil::ToNSRect(indicatorRect)]; - } + const mozc::Rect indicatorRect = + tableLayout_.GetVScrollIndicatorRect(beginIndex, endIndex, candidatesTotal); + [MacViewUtil::ToNSColor(style_.scrollbar_indicator_color()) set]; + [NSBezierPath fillRect:MacViewUtil::ToNSRect(indicatorRect)]; } #pragma mark event handling callbacks @@ -437,11 +440,11 @@ - (void)drawVScrollBar { const char *Inspect(id obj) { return [[NSString stringWithFormat:@"%@", obj] UTF8String]; } - (void)mouseDown:(NSEvent *)event { - mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] - fromView:nil]); + const mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] + fromView:nil]); int clickedRow = -1; for (int i = 0; i < tableLayout_.number_of_rows(); ++i) { - mozc::Rect rowRect = tableLayout_.GetRowRect(i); + const mozc::Rect rowRect = tableLayout_.GetRowRect(i); if (rowRect.PtrInRect(localPos)) { clickedRow = i; break; @@ -455,8 +458,8 @@ - (void)mouseDown:(NSEvent *)event { } - (void)mouseUp:(NSEvent *)event { - mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] - fromView:nil]); + const mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] + fromView:nil]); if (command_sender_ == nullptr) { return; } @@ -464,7 +467,7 @@ - (void)mouseUp:(NSEvent *)event { return; } for (int i = 0; i < tableLayout_.number_of_rows(); ++i) { - mozc::Rect rowRect = tableLayout_.GetRowRect(i); + const mozc::Rect rowRect = tableLayout_.GetRowRect(i); if (rowRect.PtrInRect(localPos)) { SessionCommand command; command.set_type(SessionCommand::SELECT_CANDIDATE); From 18df316e2605f75b8eea8de436b0f94b882e7a26 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Tue, 8 Oct 2024 04:03:12 +0000 Subject: [PATCH 10/13] Remove global variables from CandidateView #codehealth PiperOrigin-RevId: 683443591 --- src/renderer/BUILD.bazel | 3 +- src/renderer/mac/CandidateView.mm | 109 ++++++++++++++---------------- 2 files changed, 54 insertions(+), 58 deletions(-) diff --git a/src/renderer/BUILD.bazel b/src/renderer/BUILD.bazel index a49541143..6654ab964 100644 --- a/src/renderer/BUILD.bazel +++ b/src/renderer/BUILD.bazel @@ -291,6 +291,7 @@ mozc_objc_library( sdk_frameworks = [ "Carbon", "Cocoa", + "Foundation", ], deps = [ ":renderer_interface", @@ -307,9 +308,9 @@ mozc_objc_library( "//protocol:candidates_cc_proto", "//protocol:commands_cc_proto", "//protocol:renderer_cc_proto", - "@com_google_absl//absl/base", "@com_google_absl//absl/log", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/synchronization", ], ) diff --git a/src/renderer/mac/CandidateView.mm b/src/renderer/mac/CandidateView.mm index 0492f866d..6374f6d2a 100644 --- a/src/renderer/mac/CandidateView.mm +++ b/src/renderer/mac/CandidateView.mm @@ -31,10 +31,11 @@ #import +#include #include -#include "absl/base/call_once.h" #include "absl/log/log.h" +#include "absl/strings/str_format.h" #include "client/client_interface.h" #include "protocol/commands.pb.h" #include "protocol/renderer_style.pb.h" @@ -46,7 +47,6 @@ using mozc::commands::Candidates; using mozc::commands::Output; using mozc::commands::SessionCommand; -using mozc::renderer::RendererStyle; using mozc::renderer::RendererStyleHandler; using mozc::renderer::TableLayout; using mozc::renderer::mac::MacViewUtil; @@ -55,43 +55,10 @@ // native candidate window. // TODO(mukai): integrate and share the code among Win and Mac. -namespace { -const NSImage *g_LogoImage = nullptr; -int g_column_minimum_width = 0; -absl::once_flag g_OnceForInitializeStyle; - -void InitializeDefaultStyle() { - RendererStyle style; - RendererStyleHandler::GetRendererStyle(&style); - - std::string logo_file_name = style.logo_file_name(); - g_LogoImage = [NSImage imageNamed:[NSString stringWithUTF8String:logo_file_name.c_str()]]; - if (g_LogoImage) { - // Fix the image size. Sometimes the size can be smaller than the - // actual size because of blank margin. - NSArray *logoReps = [g_LogoImage representations]; - if (logoReps && [logoReps count] > 0) { - NSImageRep *representation = [logoReps objectAtIndex:0]; - [g_LogoImage setSize:NSMakeSize([representation pixelsWide], [representation pixelsHigh])]; - } - } - - NSString *nsstr = [NSString stringWithUTF8String:style.column_minimum_width_string().c_str()]; - NSDictionary *attr = [NSDictionary dictionaryWithObject:[NSFont messageFontOfSize:14] - forKey:NSFontAttributeName]; - NSAttributedString *defaultMessage = [[NSAttributedString alloc] initWithString:nsstr - attributes:attr]; - g_column_minimum_width = [defaultMessage size].width; - - // default line width is specified as 1.0 *pt*, but we want to draw - // it as 1.0 px. - [NSBezierPath setDefaultLineWidth:1.0]; - [NSBezierPath setDefaultLineJoinStyle:NSLineJoinStyleMiter]; -} -} // namespace - // Private method declarations. @interface CandidateView () +- (void)initializeDefaultStyle; + // Draw the |row|-th row. - (void)drawRow:(int)row; @@ -103,6 +70,9 @@ - (void)drawVScrollBar; @end @implementation CandidateView { + const NSImage *logoImage_; + int columnMinimumWidth_; + mozc::commands::Candidates candidates_; mozc::renderer::TableLayout tableLayout_; mozc::renderer::RendererStyle style_; @@ -120,17 +90,44 @@ @implementation CandidateView { #pragma mark initialization - (id)initWithFrame:(NSRect)frame { - absl::call_once(g_OnceForInitializeStyle, &InitializeDefaultStyle); self = [super initWithFrame:frame]; if (self) { - RendererStyleHandler::GetRendererStyle(&style_); + [self initializeDefaultStyle]; focusedRow_ = -1; } return self; } +- (void)initializeDefaultStyle { + RendererStyleHandler::GetRendererStyle(&style_); + + const std::string &logo_file_name = style_.logo_file_name(); + logoImage_ = [NSImage imageNamed:[NSString stringWithUTF8String:logo_file_name.c_str()]]; + if (logoImage_) { + // Fix the image size. Sometimes the size can be smaller than the + // actual size because of blank margin. + const NSArray *logoReps = [logoImage_ representations]; + if (logoReps && [logoReps count] > 0) { + const NSImageRep *representation = [logoReps objectAtIndex:0]; + [logoImage_ setSize:NSMakeSize([representation pixelsWide], [representation pixelsHigh])]; + } + } + + NSString *nsstr = [NSString stringWithUTF8String:style_.column_minimum_width_string().c_str()]; + NSDictionary *attr = [NSDictionary dictionaryWithObject:[NSFont messageFontOfSize:14] + forKey:NSFontAttributeName]; + const NSAttributedString *defaultMessage = [[NSAttributedString alloc] initWithString:nsstr + attributes:attr]; + columnMinimumWidth_ = [defaultMessage size].width; + + // default line width is specified as 1.0 *pt*, but we want to draw + // it as 1.0 px. + [NSBezierPath setDefaultLineWidth:1.0]; + [NSBezierPath setDefaultLineJoinStyle:NSLineJoinStyleMiter]; +} + - (void)setCandidates:(const Candidates *)candidates { - candidates_.CopyFrom(*candidates); + candidates_ = *candidates; } - (void)setSendCommandInterface:(SendCommandInterface *)command_sender { @@ -152,7 +149,6 @@ - (const TableLayout *)tableLayout { #pragma mark drawing -#define max(x, y) (((x) > (y)) ? (x) : (y)) - (NSSize)updateLayout { candidateStringsCache_ = nil; tableLayout_.Initialize(candidates_.candidate_size(), NUMBER_OF_COLUMNS); @@ -178,7 +174,7 @@ - (NSSize)updateLayout { const NSSize footerLabelSize = MacViewUtil::applyTheme([footerLabel size], style_.footer_style()); footerSize.width += footerLabelSize.width; - footerSize.height = max(footerSize.height, footerLabelSize.height); + footerSize.height = std::max(footerSize.height, footerLabelSize.height); } if (footer.has_sub_label()) { @@ -187,13 +183,13 @@ - (NSSize)updateLayout { const NSSize footerSubLabelSize = MacViewUtil::applyTheme([footerSubLabel size], style_.footer_sub_label_style()); footerSize.width += footerSubLabelSize.width; - footerSize.height = max(footerSize.height, footerSubLabelSize.height); + footerSize.height = std::max(footerSize.height, footerSubLabelSize.height); } - if (footer.logo_visible() && g_LogoImage) { - const NSSize logoSize = [g_LogoImage size]; + if (footer.logo_visible() && logoImage_) { + const NSSize logoSize = [logoImage_ size]; footerSize.width += logoSize.width; - footerSize.height = max(footerSize.height, logoSize.height); + footerSize.height = std::max(footerSize.height, logoSize.height); } if (footer.index_visible()) { @@ -206,7 +202,7 @@ - (NSSize)updateLayout { const NSSize footerIndexSize = MacViewUtil::applyTheme([footerAttributedIndex size], style_.footer_style()); footerSize.width += footerIndexSize.width; - footerSize.height = max(footerSize.height, footerIndexSize.height); + footerSize.height = std::max(footerSize.height, footerIndexSize.height); } footerSize.height += style_.footer_border_colors_size(); @@ -262,7 +258,7 @@ - (NSSize)updateLayout { addObject:[NSArray arrayWithObjects:shortcut, gap1, candidateValue, description, nil]]; } - tableLayout_.EnsureColumnsWidth(COLUMN_CANDIDATE, COLUMN_DESCRIPTION, g_column_minimum_width); + tableLayout_.EnsureColumnsWidth(COLUMN_CANDIDATE, COLUMN_DESCRIPTION, columnMinimumWidth_); candidateStringsCache_ = newCache; tableLayout_.FreezeLayout(); @@ -365,11 +361,11 @@ - (void)drawFooter { [footerBackground drawInRect:footerRect angle:90.0]; // Draw logo - if (footer.logo_visible() && g_LogoImage) { + if (footer.logo_visible() && logoImage_) { const NSPoint logoPoint = footerRect.origin; - const NSSize logoSize = g_LogoImage.size; + const NSSize logoSize = logoImage_.size; const NSRect logoRect = NSMakeRect(logoPoint.x, logoPoint.y, logoSize.width, logoSize.height); - [g_LogoImage drawInRect:logoRect + [logoImage_ drawInRect:logoRect fromRect:NSZeroRect // Draw the entire image operation:NSCompositingOperationSourceOver fraction:1.0 // Opacity @@ -403,11 +399,12 @@ - (void)drawFooter { // Draw footer index (e.g. "10/120") if (footer.index_visible()) { - const int focusedIndex = candidates_.focused_index() + 1; // +1 to 1-origin from 0-origin. - const int totalItems = candidates_.size(); - const NSString *footerIndex = [NSString stringWithFormat:@"%d/%d", focusedIndex, totalItems]; + const std::string footerIndex = + absl::StrFormat("%d/%d", + candidates_.focused_index() + 1, // +1 to 1-origin from 0-origin. + candidates_.size()); const NSAttributedString *footerAttributedIndex = - MacViewUtil::ToNSAttributedString([footerIndex UTF8String], style_.footer_style()); + MacViewUtil::ToNSAttributedString(footerIndex, style_.footer_style()); const NSSize footerSize = [footerAttributedIndex size]; NSPoint footerPosition = footerRect.origin; footerPosition.x = footerPosition.x + footerRect.size.width - footerSize.width - @@ -437,8 +434,6 @@ - (void)drawVScrollBar { #pragma mark event handling callbacks -const char *Inspect(id obj) { return [[NSString stringWithFormat:@"%@", obj] UTF8String]; } - - (void)mouseDown:(NSEvent *)event { const mozc::Point localPos = MacViewUtil::ToPoint([self convertPoint:[event locationInWindow] fromView:nil]); From 4ce92e58fe9d299f87ec5fb129bc9e7f1007e35a Mon Sep 17 00:00:00 2001 From: Toshiyuki Hanaoka Date: Tue, 8 Oct 2024 06:44:45 +0000 Subject: [PATCH 11/13] =?UTF-8?q?Add=20exceptional=20entries=20to=20expand?= =?UTF-8?q?=20number=20variations=20for=20general=20noun=20entries.=20For?= =?UTF-8?q?=20example,=20"=E5=9B=9B=E5=AD=A3"=20was=20expanded=20to=20"4?= =?UTF-8?q?=E5=AD=A3"=20with=20the=20previous=20implementation.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PiperOrigin-RevId: 683487924 --- src/rewriter/BUILD.bazel | 2 ++ src/rewriter/number_compound_util.cc | 24 ++++++++++++++++++++++- src/rewriter/number_compound_util_test.cc | 21 ++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/rewriter/BUILD.bazel b/src/rewriter/BUILD.bazel index 01b20fc89..30a13c390 100644 --- a/src/rewriter/BUILD.bazel +++ b/src/rewriter/BUILD.bazel @@ -1584,6 +1584,8 @@ mozc_cc_library( "//base/container:serialized_string_array", "//converter:segments", "//dictionary:pos_matcher", + "@com_google_absl//absl/base:no_destructor", + "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/strings", ], ) diff --git a/src/rewriter/number_compound_util.cc b/src/rewriter/number_compound_util.cc index 7f33c5343..62dab3c66 100644 --- a/src/rewriter/number_compound_util.cc +++ b/src/rewriter/number_compound_util.cc @@ -31,7 +31,10 @@ #include #include +#include +#include "absl/base/no_destructor.h" +#include "absl/container/flat_hash_set.h" #include "absl/strings/string_view.h" #include "base/container/serialized_string_array.h" #include "base/util.h" @@ -112,7 +115,7 @@ bool IsNumber(const SerializedStringArray &suffix_array, // check the opportunities of rewriting such number nouns. // TODO(toshiyuki, team): It may be better to set number POS to such number // noun entries at dictionary build time. correct POS. Then, we can omit the - // following runtime strcture check. + // following runtime structure check. if (!pos_matcher.IsGeneralNoun(cand.lid)) { return false; } @@ -126,6 +129,25 @@ bool IsNumber(const SerializedStringArray &suffix_array, suffix_array, cand.content_value, &number, &suffix, &script_type)) { return false; } + // Some number including general noun should be excluded from IsNumber(). + static const absl::NoDestructor< + absl::flat_hash_set>> + kExceptions({ + {"いっこう", "一行"}, + {"さんしゃ", "三者"}, + {"さんきゃく", "三脚"}, + {"しきゅう", "四球"}, + {"しき", "四季"}, + {"ろっぽう", "六法"}, + {"ろっぽう", "六方"}, + {"ろっかい", "六界"}, + {"ろくどう", "六道"}, + {"しちりん", "七輪"}, + {"やえ", "八重"}, + }); + if (kExceptions->contains(std::make_pair(cand.key, cand.value))) { + return false; + } return !number.empty(); } diff --git a/src/rewriter/number_compound_util_test.cc b/src/rewriter/number_compound_util_test.cc index 1dfb2464c..4cfd82fe1 100644 --- a/src/rewriter/number_compound_util_test.cc +++ b/src/rewriter/number_compound_util_test.cc @@ -136,7 +136,9 @@ TEST(NumberCompoundUtilTest, IsNumber) { std::unique_ptr buf; const absl::string_view data = SerializedStringArray::SerializeToBuffer( { + // Should be sorted "回", + "行", "階", }, &buf); @@ -178,6 +180,25 @@ TEST(NumberCompoundUtilTest, IsNumber) { c.lid = pos_matcher.GetAdverbId(); c.rid = pos_matcher.GetAdverbId(); EXPECT_FALSE(IsNumber(suffix_array, pos_matcher, c)); + + c = Segment::Candidate(); + c.key = "いちぎょう"; + c.content_key = "いちぎょう"; + c.value = "一行"; + c.content_value = "一行"; + c.lid = pos_matcher.GetGeneralNounId(); + c.rid = pos_matcher.GetGeneralNounId(); + EXPECT_TRUE(IsNumber(suffix_array, pos_matcher, c)); + + // Exception entry + c = Segment::Candidate(); + c.key = "いっこう"; + c.content_key = "いっこう"; + c.value = "一行"; + c.content_value = "一行"; + c.lid = pos_matcher.GetGeneralNounId(); + c.rid = pos_matcher.GetGeneralNounId(); + EXPECT_FALSE(IsNumber(suffix_array, pos_matcher, c)); } } // namespace number_compound_util From 4999630b9466945f096921dbe9f4f5287e466174 Mon Sep 17 00:00:00 2001 From: Hiroyuki Komatsu Date: Tue, 8 Oct 2024 08:13:19 +0000 Subject: [PATCH 12/13] Update SHA256 values of zip code files in MODULE.bazel * Follow the update of the upstream data files. PiperOrigin-RevId: 683511499 --- src/MODULE.bazel | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MODULE.bazel b/src/MODULE.bazel index 8da229707..4c3ae30da 100644 --- a/src/MODULE.bazel +++ b/src/MODULE.bazel @@ -255,8 +255,8 @@ http_archive( # Since the URL is shared among multiple versions, we cannot specify the SHA256. # For offline build (with the --repository_cache flag), SHA256 should be specified. # -# SHA256 as of 2024-08-14 -# SHA256_ZIP_CODE_KEN_ALL = "d2d177ef64b9459a618d8aaa96b6c5f081cb3f37f6e9c00ba912001e66b81f3e" +# SHA256 as of 2024-10-08 +# SHA256_ZIP_CODE_KEN_ALL = "e5a32c0199ebc890ea5c48c06fd817a168b26d68ce1c3a86ba0ae1cdf6c2d1c4" SHA256_ZIP_CODE_KEN_ALL = None http_archive( @@ -266,8 +266,8 @@ http_archive( url = "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip", ) -# SHA256 as of 2024-08-14 -# SHA256_ZIP_CODE_JIGYOSYO="ab6fd92df35e63c4566d29f70456da1603d8178ce3fec073f7c27b28d0af2e10" +# SHA256 as of 2024-10-08 +# SHA256_ZIP_CODE_JIGYOSYO = "5d52511ce6613fcc0c5b24ac59b463e927cff76ac466c2ae07a511a64bb5913f" SHA256_ZIP_CODE_JIGYOSYO = None http_archive( From db78a43f240588e6cc4068268997e85bb026dc59 Mon Sep 17 00:00:00 2001 From: Taku Kudo Date: Tue, 8 Oct 2024 08:16:46 +0000 Subject: [PATCH 13/13] Update Next ID. PiperOrigin-RevId: 683512354 --- src/protocol/commands.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocol/commands.proto b/src/protocol/commands.proto index 62d28e7fc..9ff401be0 100644 --- a/src/protocol/commands.proto +++ b/src/protocol/commands.proto @@ -573,7 +573,7 @@ message Capability { [default = NO_TEXT_DELETION_CAPABILITY]; } -// Next ID: 97 +// Next ID: 98 // Bundles together some Android experiment flags so that they can be easily // retrieved throughout the native code. These flags are generally specific to // the decoder, and are made available when the decoder is initialized.