Commit 6fb35256 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

RemoteMacViews: Store ui::TextInputClient in views::TextInputHost

There is currently a ui::TextInputClient* stored in BridgedContentView.
This is problematic because the ui::TextInputClient lives in the
browser process while the BridgedContentView lives in the app process.

Cut-and-paste-move textInputClient_ and pendingTextInputClient_  from
BridgedContentView to TextInputHost, and make it a member of the
BridgedNativeWidgetHostImpl class, using the views_bridge_mac::
BridgedNativeWidgetHostHelper structure to close the gap between the
two.

This leaves many direct accesses of the ui::TextInputClient from the
app process, which we can now replace one-by-one with mojo calls in
subsequent patches.

Bug: 901490
Change-Id: Ib4497afd4dd7a4e41541eaab170157e1c7eeb90e
Reviewed-on: https://chromium-review.googlesource.com/c/1391879
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarSidney San Martín <sdy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#619321}
parent a4084eb7
......@@ -480,6 +480,8 @@ jumbo_component("views") {
"cocoa/bridged_native_widget_host_impl.mm",
"cocoa/drag_drop_client_mac.h",
"cocoa/drag_drop_client_mac.mm",
"cocoa/text_input_host.h",
"cocoa/text_input_host.mm",
"cocoa/tooltip_manager_mac.h",
"cocoa/tooltip_manager_mac.mm",
"controls/button/label_button_label.cc",
......
......@@ -38,6 +38,7 @@ namespace views {
class BridgedNativeWidgetImpl;
class NativeWidgetMac;
class TextInputHost;
// The portion of NativeWidgetMac that lives in the browser process. This
// communicates to the BridgedNativeWidgetImpl, which interacts with the Cocoa
......@@ -86,6 +87,8 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
return bridge_factory_host_;
}
TextInputHost* text_input_host() const { return text_input_host_.get(); }
// A NSWindow that is guaranteed to exist in this process. If the bridge
// object for this host is in this process, then this points to the bridge's
// NSWindow. Otherwise, it mirrors the id and bounds of the child window.
......@@ -205,6 +208,8 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
static NSView* GetGlobalCaptureView();
private:
friend class TextInputHost;
void UpdateCompositorProperties();
void DestroyCompositor();
void RankNSViewsRecursive(View* view, std::map<NSView*, int>* rank) const;
......@@ -225,6 +230,8 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
gfx::Point* baseline_point) override;
double SheetPositionY() override;
views_bridge_mac::DragDropClient* GetDragDropClient() override;
ui::TextInputClient* GetTextInputClient() override;
void GetHasInputContext(bool* has_text_input_context) override;
// BridgeFactoryHost::Observer:
void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) override;
......@@ -374,7 +381,10 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// The id that may be used to look up the NSView for |root_view_|.
const uint64_t root_view_id_;
views::View* root_view_ = nullptr; // Weak. Owned by |native_widget_mac_|.
// Weak. Owned by |native_widget_mac_|.
views::View* root_view_ = nullptr;
std::unique_ptr<DragDropClientMac> drag_drop_client_;
// The mojo pointer to a BridgedNativeWidget, which may exist in another
......@@ -401,6 +411,7 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
std::unique_ptr<TooltipManager> tooltip_manager_;
std::unique_ptr<ui::InputMethod> input_method_;
std::unique_ptr<TextInputHost> text_input_host_;
FocusManager* focus_manager_ = nullptr; // Weak. Owned by our Widget.
base::string16 window_title_;
......
......@@ -17,6 +17,7 @@
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/mac/coordinate_conversion.h"
#include "ui/native_theme/native_theme_mac.h"
#include "ui/views/cocoa/text_input_host.h"
#include "ui/views/cocoa/tooltip_manager_mac.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller.h"
......@@ -90,6 +91,7 @@ BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(NativeWidgetMac* owner)
native_widget_mac_(owner),
root_view_id_(ui::NSViewIds::GetNewId()),
accessibility_focus_overrider_(this),
text_input_host_(new TextInputHost(this)),
host_mojo_binding_(this) {
DCHECK(GetIdToWidgetHostImplMap().find(widget_id_) ==
GetIdToWidgetHostImplMap().end());
......@@ -526,6 +528,10 @@ BridgedNativeWidgetHostImpl::GetDragDropClient() {
return drag_drop_client_.get();
}
ui::TextInputClient* BridgedNativeWidgetHostImpl::GetTextInputClient() {
return text_input_host_->GetTextInputClient();
}
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, BridgeFactoryHost::Observer:
void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
......@@ -1129,16 +1135,19 @@ void BridgedNativeWidgetHostImpl::OnDidChangeFocus(View* focused_before,
View* focused_now) {
ui::InputMethod* input_method =
native_widget_mac_->GetWidget()->GetInputMethod();
if (input_method) {
ui::TextInputClient* input_client = input_method->GetTextInputClient();
// Sanity check: When focus moves away from the widget (i.e. |focused_now|
// is nil), then the textInputClient will be cleared.
DCHECK(!!focused_now || !input_client);
// TODO(ccameron): TextInputClient is not handled across process borders
// yet.
if (bridge_impl_)
bridge_impl_->SetTextInputClient(input_client);
}
if (!input_method)
return;
ui::TextInputClient* new_text_input_client =
input_method->GetTextInputClient();
// Sanity check: When focus moves away from the widget (i.e. |focused_now|
// is nil), then the textInputClient will be cleared.
DCHECK(!!focused_now || !new_text_input_client);
text_input_host_->SetTextInputClient(new_text_input_client);
}
void BridgedNativeWidgetHostImpl::GetHasInputContext(bool* has_input_context) {
return text_input_host_->GetHasInputContext(has_input_context);
}
////////////////////////////////////////////////////////////////////////////////
......
......@@ -26,6 +26,7 @@
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#import "ui/views/cocoa/text_input_host.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/controls/textfield/textfield_model.h"
......@@ -550,7 +551,7 @@ Textfield* BridgedNativeWidgetTest::InstallTextField(
// schedules a task to flash the cursor, so this requires |message_loop_|.
textfield->RequestFocus();
[ns_view_ setTextInputClient:textfield];
bridge_host()->text_input_host()->SetTextInputClient(textfield);
// Initialize the dummy text view. Initializing this with NSZeroRect causes
// weird NSTextView behavior on OSX 10.9.
......@@ -930,7 +931,7 @@ TEST_F(BridgedNativeWidgetTest, InputContext) {
EXPECT_FALSE([ns_view_ inputContext]);
InstallTextField(test_string, ui::TEXT_INPUT_TYPE_TEXT);
EXPECT_TRUE([ns_view_ inputContext]);
[ns_view_ setTextInputClient:nil];
bridge_host()->text_input_host()->SetTextInputClient(nullptr);
EXPECT_FALSE([ns_view_ inputContext]);
InstallTextField(test_string, ui::TEXT_INPUT_TYPE_NONE);
EXPECT_FALSE([ns_view_ inputContext]);
......@@ -1339,7 +1340,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteCommands) {
// Test that we don't crash during an action message even if the TextInputClient
// is nil. Regression test for crbug.com/615745.
TEST_F(BridgedNativeWidgetTest, NilTextInputClient) {
[ns_view_ setTextInputClient:nil];
bridge_host()->text_input_host()->SetTextInputClient(nullptr);
NSMutableArray* selectors = [NSMutableArray array];
[selectors addObjectsFromArray:kMoveActions];
[selectors addObjectsFromArray:kSelectActions];
......@@ -1751,7 +1752,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
bool saw_update_windows = false;
base::RepeatingClosure update_windows_closure = base::BindRepeating(
[](bool* saw_update_windows, BridgedContentView* view,
Textfield* textfield) {
BridgedNativeWidgetHostImpl* host, Textfield* textfield) {
// Ensure updateWindows is not invoked recursively.
EXPECT_FALSE(*saw_update_windows);
*saw_update_windows = true;
......@@ -1768,7 +1769,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
// reacting to InsertChar could theoretically do this, but toolkit-views
// DCHECKs if there is recursive event dispatch, so call
// setTextInputClient directly.
[view setTextInputClient:textfield];
host->text_input_host()->SetTextInputClient(textfield);
// Finally simulate what -[NSApp updateWindows] should _actually_ do,
// which is to update the input context (from the first responder).
......@@ -1777,20 +1778,21 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
// Now, the |textfield| set above should have been set again.
EXPECT_TRUE(g_fake_current_input_context);
},
&saw_update_windows, ns_view_, textfield);
&saw_update_windows, ns_view_, bridge_host(), textfield);
SetHandleKeyEventCallback(base::BindRepeating(
[](int* saw_return_count, BridgedContentView* view, Textfield* textfield,
[](int* saw_return_count, BridgedContentView* view,
BridgedNativeWidgetHostImpl* host, Textfield* textfield,
const ui::KeyEvent& event) {
if (event.key_code() == ui::VKEY_RETURN) {
*saw_return_count += 1;
// Simulate Textfield::OnBlur() by clearing the input method.
// Textfield needs to be in a Widget to do this normally.
[view setTextInputClient:nullptr];
host->text_input_host()->SetTextInputClient(nullptr);
}
return false;
},
&vkey_return_count, ns_view_));
&vkey_return_count, ns_view_, bridge_host()));
// Starting text (just insert it).
[ns_view_ insertText:@"ㅂ" replacementRange:NSMakeRange(NSNotFound, 0)];
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
#define UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
#include "base/macros.h"
#include "ui/views/views_export.h"
namespace ui {
class TextInputClient;
} // namespace ui
namespace views {
class BridgedNativeWidgetHostImpl;
class VIEWS_EXPORT TextInputHost {
public:
TextInputHost(BridgedNativeWidgetHostImpl* host_impl);
~TextInputHost();
// Set the current TextInputClient.
void SetTextInputClient(ui::TextInputClient* new_text_input_client);
// Return true if -[NSView inputContext] should return a non-nil value.
void GetHasInputContext(bool* has_input_context);
// Return a pointer to the host's ui::TextInputClient.
// TODO(ccameron): Remove the need for this call.
ui::TextInputClient* GetTextInputClient() const;
private:
// Weak. If non-null the TextInputClient of the currently focused views::View
// in the hierarchy rooted at the root view of |host_impl_|. Owned by the
// focused views::View.
ui::TextInputClient* text_input_client_ = nullptr;
// The TextInputClient about to be set. Requests for a new -inputContext will
// use this, but while the input is changing the NSView still needs to service
// IME requests using the old |text_input_client_|.
ui::TextInputClient* pending_text_input_client_ = nullptr;
BridgedNativeWidgetHostImpl* const host_impl_;
DISALLOW_COPY_AND_ASSIGN(TextInputHost);
};
} // namespace views
#endif // UI_VIEWS_COCOA_TEXT_INPUT_HOST_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/cocoa/text_input_host.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
namespace views {
TextInputHost::TextInputHost(BridgedNativeWidgetHostImpl* host_impl)
: host_impl_(host_impl) {}
TextInputHost::~TextInputHost() {}
ui::TextInputClient* TextInputHost::GetTextInputClient() const {
return text_input_client_;
}
void TextInputHost::SetTextInputClient(
ui::TextInputClient* new_text_input_client) {
if (pending_text_input_client_ == new_text_input_client)
return;
// This method may cause the IME window to dismiss, which may cause it to
// insert text (e.g. to replace marked text with "real" text). That should
// happen in the old -inputContext (which AppKit stores a reference to).
// Unfortunately, the only way to invalidate the the old -inputContext is to
// invoke -[NSApp updateWindows], which also wants a reference to the _new_
// -inputContext. So put the new inputContext in |pendingTextInputClient_| and
// only use it for -inputContext.
ui::TextInputClient* old_text_input_client = text_input_client_;
// Since dismissing an IME may insert text, a misbehaving IME or a
// ui::TextInputClient that acts on InsertChar() to change focus a second time
// may invoke -setTextInputClient: recursively; with [NSApp updateWindows]
// still on the stack. Calling [NSApp updateWindows] recursively may upset
// an IME. Since the rest of this method is only to decide whether to call
// updateWindows, and we're already calling it, just bail out.
if (text_input_client_ != pending_text_input_client_) {
pending_text_input_client_ = new_text_input_client;
return;
}
// Start by assuming no need to invoke -updateWindows.
text_input_client_ = new_text_input_client;
pending_text_input_client_ = new_text_input_client;
if (host_impl_->bridge_impl_ &&
host_impl_->bridge_impl_->NeedsUpdateWindows()) {
text_input_client_ = old_text_input_client;
[NSApp updateWindows];
// Note: |pending_text_input_client_| (and therefore +[NSTextInputContext
// currentInputContext] may have changed if called recursively.
text_input_client_ = pending_text_input_client_;
}
}
void TextInputHost::GetHasInputContext(bool* has_input_context) {
*has_input_context = false;
// If the textInputClient_ does not exist, return nil since this view does not
// conform to NSTextInputClient protocol.
if (!pending_text_input_client_)
return;
// If a menu is active, and -[NSView interpretKeyEvents:] asks for the
// input context, return nil. This ensures the action message is sent to
// the view, rather than any NSTextInputClient a subview has installed.
bool has_menu_controller = false;
host_impl_->GetHasMenuController(&has_menu_controller);
if (has_menu_controller)
return;
// When not in an editable mode, or while entering passwords
// (http://crbug.com/23219), we don't want to show IME candidate windows.
// Returning nil prevents this view from getting messages defined as part of
// the NSTextInputClient protocol.
switch (pending_text_input_client_->GetTextInputType()) {
case ui::TEXT_INPUT_TYPE_NONE:
case ui::TEXT_INPUT_TYPE_PASSWORD:
return;
default:
*has_input_context = true;
}
}
} // namespace views
......@@ -77,6 +77,13 @@ class Bridge : public BridgedNativeWidgetHostHelper {
// Drag-drop only doesn't work across mojo yet.
return nullptr;
}
ui::TextInputClient* GetTextInputClient() override {
// Text input doesn't work across mojo yet.
return nullptr;
}
void GetHasInputContext(bool* has_input_context) override {
*has_input_context = false;
}
mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr_;
std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
......
......@@ -32,17 +32,6 @@ VIEWS_EXPORT
// Weak, reset by clearView.
views::BridgedNativeWidgetImpl* bridge_;
// Weak. If non-null the TextInputClient of the currently focused View in the
// hierarchy rooted at |hostedView_|. Owned by the focused View.
// TODO(ccameron): Remove this member.
ui::TextInputClient* textInputClient_;
// The TextInputClient about to be set. Requests for a new -inputContext will
// use this, but while the input is changing, |self| still needs to service
// IME requests using the old |textInputClient_|.
// TODO(ccameron): Remove this member.
ui::TextInputClient* pendingTextInputClient_;
// A tracking area installed to enable mouseMoved events.
ui::ScopedCrTrackingArea cursorTrackingArea_;
......@@ -62,7 +51,6 @@ VIEWS_EXPORT
}
@property(readonly, nonatomic) views::BridgedNativeWidgetImpl* bridge;
@property(assign, nonatomic) ui::TextInputClient* textInputClient;
@property(assign, nonatomic) BOOL drawMenuBackgroundForBlur;
// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
......@@ -85,6 +73,14 @@ VIEWS_EXPORT
// or not.
- (void)updateFullKeyboardAccess;
// The TextInputClient of the currently focused views::View.
// TODO(ccameron): This cannot be relied on across processes.
- (ui::TextInputClient*)textInputClient;
// Returns true if it is needed to call -[NSApp updateWindows] while updating
// the text input client.
- (bool)needsUpdateWindows;
@end
#endif // UI_VIEWS_BRIDGE_MAC_BRIDGED_CONTENT_VIEW_H_
......@@ -270,7 +270,6 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@implementation BridgedContentView
@synthesize bridge = bridge_;
@synthesize textInputClient = textInputClient_;
@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
- (instancetype)initWithBridge:(views::BridgedNativeWidgetImpl*)bridge
......@@ -309,6 +308,10 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
return self;
}
- (ui::TextInputClient*)textInputClient {
return bridge_ ? bridge_->host_helper()->GetTextInputClient() : nullptr;
}
- (void)dealloc {
// By the time |self| is dealloc'd, it should never be in an NSWindow, and it
// should never be the current input context.
......@@ -320,41 +323,13 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)clearView {
[self setTextInputClient:nullptr];
bridge_ = nullptr;
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
[cursorTrackingArea_.get() clearOwner];
[self removeTrackingArea:cursorTrackingArea_.get()];
}
- (void)setTextInputClient:(ui::TextInputClient*)newTextInputClient {
if (pendingTextInputClient_ == newTextInputClient)
return;
// This method may cause the IME window to dismiss, which may cause it to
// insert text (e.g. to replace marked text with "real" text). That should
// happen in the old -inputContext (which AppKit stores a reference to).
// Unfortunately, the only way to invalidate the the old -inputContext is to
// invoke -[NSApp updateWindows], which also wants a reference to the _new_
// -inputContext. So put the new inputContext in |pendingTextInputClient_| and
// only use it for -inputContext.
ui::TextInputClient* oldInputClient = textInputClient_;
// Since dismissing an IME may insert text, a misbehaving IME or a
// ui::TextInputClient that acts on InsertChar() to change focus a second time
// may invoke -setTextInputClient: recursively; with [NSApp updateWindows]
// still on the stack. Calling [NSApp updateWindows] recursively may upset
// an IME. Since the rest of this method is only to decide whether to call
// updateWindows, and we're already calling it, just bail out.
if (textInputClient_ != pendingTextInputClient_) {
pendingTextInputClient_ = newTextInputClient;
return;
}
// Start by assuming no need to invoke -updateWindows.
textInputClient_ = newTextInputClient;
pendingTextInputClient_ = newTextInputClient;
- (bool)needsUpdateWindows {
// If |self| was being used for the input context, and would now report a
// different input context, manually invoke [NSApp updateWindows]. This is
// necessary because AppKit holds on to a raw pointer to a NSTextInputContext
......@@ -365,7 +340,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// the inputContext may change before further event processing.
NSTextInputContext* current = [NSTextInputContext currentInputContext];
if (!current)
return;
return false;
NSTextInputContext* newContext = [self inputContext];
// If the newContext is non-nil, then it can only be [super inputContext]. So
......@@ -373,17 +348,10 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// both cases, there's no need to call -updateWindows.
if (newContext) {
DCHECK_EQ(newContext, [super inputContext]);
return;
return false;
}
if (current == [super inputContext]) {
DCHECK_NE(oldInputClient, textInputClient_);
textInputClient_ = oldInputClient;
[NSApp updateWindows];
// Note: |pendingTextInputClient_| (and therefore +[NSTextInputContext
// currentInputContext] may have changed if called recursively.
textInputClient_ = pendingTextInputClient_;
}
return current == [super inputContext];
}
// If |point| is classified as a draggable background (HTCAPTION), return nil so
......@@ -511,8 +479,10 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// If there's an active TextInputClient, schedule the editing command to be
// performed.
if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command))
textInputClient_->SetTextEditCommandForNextKeyEvent(command);
if ([self textInputClient] &&
[self textInputClient] -> IsTextEditCommandEnabled(command)) {
[self textInputClient] -> SetTextEditCommandForNextKeyEvent(command);
}
[self dispatchKeyEvent:&event];
}
......@@ -591,7 +561,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
// Forward the |text| to |textInputClient_| if no menu is active.
if (textInputClient_ && ![self hasActiveMenuController]) {
if ([self textInputClient] && ![self hasActiveMenuController]) {
// If a single character is inserted by keyDown's call to
// interpretKeyEvents: then use InsertChar() to allow editing events to be
// merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible
......@@ -606,11 +576,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// |text|. This is because |keyDownEvent_| will correspond to the event that
// caused the composition text to be confirmed, say, Return key press.
if (isCharacterEvent) {
textInputClient_->InsertChar(
ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN,
ui::DomCode::NONE, ui::EF_NONE));
[self textInputClient] -> InsertChar(ui::KeyEvent(
[text characterAtIndex:0], ui::VKEY_UNKNOWN,
ui::DomCode::NONE, ui::EF_NONE));
} else {
textInputClient_->InsertText(base::SysNSStringToUTF16(text));
[self textInputClient] -> InsertText(base::SysNSStringToUTF16(text));
}
// Suppress accelerators that may be bound to this key, since it inserted
// text instead. But note that IME may follow with -insertNewLine:, which
......@@ -791,28 +761,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (NSTextInputContext*)inputContext {
// If the textInputClient_ does not exist, return nil since this view does not
// conform to NSTextInputClient protocol.
if (!pendingTextInputClient_)
return nil;
// If a menu is active, and -[NSView interpretKeyEvents:] asks for the
// input context, return nil. This ensures the action message is sent to
// the view, rather than any NSTextInputClient a subview has installed.
if ([self hasActiveMenuController])
if (!bridge_)
return nil;
// When not in an editable mode, or while entering passwords
// (http://crbug.com/23219), we don't want to show IME candidate windows.
// Returning nil prevents this view from getting messages defined as part of
// the NSTextInputClient protocol.
switch (pendingTextInputClient_->GetTextInputType()) {
case ui::TEXT_INPUT_TYPE_NONE:
case ui::TEXT_INPUT_TYPE_PASSWORD:
return nil;
default:
return [super inputContext];
}
bool has_text_input_context = false;
bridge_->host_helper()->GetHasInputContext(&has_text_input_context);
return has_text_input_context ? [super inputContext] : nil;
}
// NSResponder implementation.
......@@ -1244,23 +1197,23 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)moveToLeftEndOfLine:(id)sender {
IsTextRTL(textInputClient_) ? [self moveToEndOfLine:sender]
: [self moveToBeginningOfLine:sender];
IsTextRTL([self textInputClient]) ? [self moveToEndOfLine:sender]
: [self moveToBeginningOfLine:sender];
}
- (void)moveToRightEndOfLine:(id)sender {
IsTextRTL(textInputClient_) ? [self moveToBeginningOfLine:sender]
: [self moveToEndOfLine:sender];
IsTextRTL([self textInputClient]) ? [self moveToBeginningOfLine:sender]
: [self moveToEndOfLine:sender];
}
- (void)moveToLeftEndOfLineAndModifySelection:(id)sender {
IsTextRTL(textInputClient_)
IsTextRTL([self textInputClient])
? [self moveToEndOfLineAndModifySelection:sender]
: [self moveToBeginningOfLineAndModifySelection:sender];
}
- (void)moveToRightEndOfLineAndModifySelection:(id)sender {
IsTextRTL(textInputClient_)
IsTextRTL([self textInputClient])
? [self moveToBeginningOfLineAndModifySelection:sender]
: [self moveToEndOfLineAndModifySelection:sender];
}
......@@ -1358,8 +1311,9 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
BOOL canRead = [returnType isEqualToString:utf8Type];
// Valid if (sendType, returnType) is either (string, nil), (nil, string),
// or (string, string).
BOOL valid = textInputClient_ && ((canWrite && (canRead || !returnType)) ||
(canRead && (canWrite || !sendType)));
BOOL valid =
[self textInputClient] && ((canWrite && (canRead || !returnType)) ||
(canRead && (canWrite || !sendType)));
return valid
? self
: [super validRequestorForSendType:sendType returnType:returnType];
......@@ -1373,15 +1327,15 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// either for when it is upgraded.
DCHECK([types containsObject:NSStringPboardType] ||
[types containsObject:base::mac::CFToNSCast(kUTTypeUTF8PlainText)]);
if (!textInputClient_)
if (![self textInputClient])
return NO;
gfx::Range selectionRange;
if (!textInputClient_->GetEditableSelectionRange(&selectionRange))
if (![self textInputClient] -> GetEditableSelectionRange(&selectionRange))
return NO;
base::string16 text;
textInputClient_->GetTextFromRange(selectionRange, &text);
[self textInputClient] -> GetTextFromRange(selectionRange, &text);
return [pboard writeObjects:@[ base::SysUTF16ToNSString(text) ]];
}
......@@ -1395,7 +1349,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// NSTextInputClient protocol implementation.
// IMPORTANT: Always null-check |textInputClient_|. It can change (or be
// IMPORTANT: Always null-check |[self textInputClient]|. It can change (or be
// cleared) in -setTextInputClient:, which requires informing AppKit that the
// -inputContext has changed and to update its raw pointer. However, the AppKit
// method which does that may also spin a nested run loop communicating with an
......@@ -1414,7 +1368,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
gfx::Range actual_range;
base::string16 substring = AttributedSubstringForRangeHelper(
textInputClient_, gfx::Range(range), &actual_range);
[self textInputClient], gfx::Range(range), &actual_range);
if (actualRange) {
// To maintain consistency with NSTextView, return range {0,0} for an out of
// bounds requested range.
......@@ -1480,7 +1434,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (NSRect)firstRectForCharacterRange:(NSRange)range
actualRange:(NSRangePointer)actualNSRange {
gfx::Range actualRange;
gfx::Rect rect = GetFirstRectForRangeHelper(textInputClient_,
gfx::Rect rect = GetFirstRectForRangeHelper([self textInputClient],
gfx::Range(range), &actualRange);
if (actualNSRange)
*actualNSRange = actualRange.ToNSRange();
......@@ -1488,45 +1442,46 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (BOOL)hasMarkedText {
return textInputClient_ && textInputClient_->HasCompositionText();
return
[self textInputClient] && [self textInputClient] -> HasCompositionText();
}
- (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
if (!bridge_ || !textInputClient_)
if (!bridge_ || ![self textInputClient])
return;
textInputClient_->DeleteRange(gfx::Range(replacementRange));
[self textInputClient] -> DeleteRange(gfx::Range(replacementRange));
[self insertTextInternal:text];
}
- (NSRange)markedRange {
if (!textInputClient_)
if (![self textInputClient])
return NSMakeRange(NSNotFound, 0);
gfx::Range range;
textInputClient_->GetCompositionTextRange(&range);
[self textInputClient] -> GetCompositionTextRange(&range);
return range.ToNSRange();
}
- (NSRange)selectedRange {
if (!textInputClient_)
if (![self textInputClient])
return NSMakeRange(NSNotFound, 0);
gfx::Range range;
textInputClient_->GetEditableSelectionRange(&range);
[self textInputClient] -> GetEditableSelectionRange(&range);
return range.ToNSRange();
}
- (void)setMarkedText:(id)text
selectedRange:(NSRange)selectedRange
replacementRange:(NSRange)replacementRange {
if (!textInputClient_)
if (![self textInputClient])
return;
if ([text isKindOfClass:[NSAttributedString class]])
text = [text string];
textInputClient_->DeleteRange(gfx::Range(replacementRange));
[self textInputClient] -> DeleteRange(gfx::Range(replacementRange));
ui::CompositionText composition;
composition.text = base::SysNSStringToUTF16(text);
composition.selection = gfx::Range(selectedRange);
......@@ -1541,15 +1496,15 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
composition.ime_text_spans.push_back(
ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, [text length],
ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
textInputClient_->SetCompositionText(composition);
[self textInputClient] -> SetCompositionText(composition);
hasUnhandledKeyDownEvent_ = NO;
}
- (void)unmarkText {
if (!textInputClient_)
if (![self textInputClient])
return;
textInputClient_->ConfirmCompositionText();
[self textInputClient] -> ConfirmCompositionText();
hasUnhandledKeyDownEvent_ = NO;
}
......@@ -1565,8 +1520,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (command == ui::TextEditCommand::INVALID_COMMAND)
return NO;
if (textInputClient_)
return textInputClient_->IsTextEditCommandEnabled(command);
if ([self textInputClient])
return [self textInputClient] -> IsTextEditCommandEnabled(command);
// views::Label does not implement the TextInputClient interface but still
// needs to intercept the Copy and Select All menu actions.
......
......@@ -13,6 +13,10 @@
@class NSView;
namespace ui {
class TextInputClient;
} // namespace ui
namespace views_bridge_mac {
class DragDropClient;
......@@ -57,6 +61,14 @@ class VIEWS_BRIDGE_MAC_EXPORT BridgedNativeWidgetHostHelper {
// Return a pointer to host's DragDropClientMac.
// TODO(ccameron): Drag-drop behavior needs to be implemented over mojo.
virtual DragDropClient* GetDragDropClient() = 0;
// Return a pointer to the host's ui::TextInputClient.
// TODO(ccameron): Remove the needs for this call.
virtual ui::TextInputClient* GetTextInputClient() = 0;
// Return true if -[NSView inputContext] should return a non-nil value.
// TODO(ccameron): Move this function to the mojo interface.
virtual void GetHasInputContext(bool* has_input_context) = 0;
};
} // namespace views_bridge_mac
......
......@@ -234,9 +234,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
const base::string16& characters_ignoring_modifiers,
uint32_t key_code) override;
// TODO(ccameron): This method exists temporarily as we move all direct access
// of TextInputClient out of BridgedContentView.
void SetTextInputClient(ui::TextInputClient* text_input_client);
// Return true if [NSApp updateWindows] needs to be called after updating the
// TextInputClient.
bool NeedsUpdateWindows();
// Compute the window and content size, and forward them to |host_|. This will
// update widget and compositor size.
......
......@@ -1180,9 +1180,8 @@ void BridgedNativeWidgetImpl::UpdateTooltip() {
[bridged_view_ updateTooltipIfRequiredAt:point];
}
void BridgedNativeWidgetImpl::SetTextInputClient(
ui::TextInputClient* text_input_client) {
[bridged_view_ setTextInputClient:text_input_client];
bool BridgedNativeWidgetImpl::NeedsUpdateWindows() {
return [bridged_view_ needsUpdateWindows];
}
void BridgedNativeWidgetImpl::RedispatchKeyEvent(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment