Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / renderer_host / text_input_client_mac.mm
blobdac24b364f2cbba9be67881751044d8fe436eb4d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "content/browser/renderer_host/text_input_client_mac.h"
7 #include "base/memory/singleton.h"
8 #include "base/metrics/histogram.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "base/time/time.h"
11 #include "content/browser/renderer_host/render_widget_host_impl.h"
12 #include "content/common/text_input_client_messages.h"
14 namespace content {
16 // The amount of time in milliseconds that the browser process will wait for a
17 // response from the renderer.
18 // TODO(rsesek): Using the histogram data, find the best upper-bound for this
19 // value.
20 const float kWaitTimeout = 1500;
22 TextInputClientMac::TextInputClientMac()
23     : character_index_(NSNotFound),
24       lock_(),
25       condition_(&lock_) {
28 TextInputClientMac::~TextInputClientMac() {
31 // static
32 TextInputClientMac* TextInputClientMac::GetInstance() {
33   return base::Singleton<TextInputClientMac>::get();
36 void TextInputClientMac::GetStringAtPoint(
37     RenderWidgetHost* rwh,
38     gfx::Point point,
39     void (^replyHandler)(NSAttributedString*, NSPoint)) {
40   DCHECK(replyHandler_.get() == nil);
41   replyHandler_.reset(replyHandler, base::scoped_policy::RETAIN);
42   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh);
43   rwhi->Send(new TextInputClientMsg_StringAtPoint(rwhi->GetRoutingID(), point));
46 void TextInputClientMac::GetStringAtPointReply(NSAttributedString* string,
47                                                NSPoint point) {
48   if (replyHandler_.get()) {
49     replyHandler_.get()(string, point);
50     replyHandler_.reset();
51   }
54 NSUInteger TextInputClientMac::GetCharacterIndexAtPoint(RenderWidgetHost* rwh,
55     gfx::Point point) {
56   base::TimeTicks start = base::TimeTicks::Now();
58   BeforeRequest();
59   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh);
60   rwhi->Send(new TextInputClientMsg_CharacterIndexForPoint(rwhi->GetRoutingID(),
61                                                           point));
62   // http://crbug.com/121917
63   base::ThreadRestrictions::ScopedAllowWait allow_wait;
64   condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout));
65   AfterRequest();
67   base::TimeDelta delta(base::TimeTicks::Now() - start);
68   UMA_HISTOGRAM_LONG_TIMES("TextInputClient.CharacterIndex",
69                            delta * base::Time::kMicrosecondsPerMillisecond);
71   return character_index_;
74 NSRect TextInputClientMac::GetFirstRectForRange(RenderWidgetHost* rwh,
75     NSRange range) {
76   base::TimeTicks start = base::TimeTicks::Now();
78   BeforeRequest();
79   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh);
80   rwhi->Send(
81       new TextInputClientMsg_FirstRectForCharacterRange(rwhi->GetRoutingID(),
82                                                         gfx::Range(range)));
83   // http://crbug.com/121917
84   base::ThreadRestrictions::ScopedAllowWait allow_wait;
85   condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout));
86   AfterRequest();
88   base::TimeDelta delta(base::TimeTicks::Now() - start);
89   UMA_HISTOGRAM_LONG_TIMES("TextInputClient.FirstRect",
90                            delta * base::Time::kMicrosecondsPerMillisecond);
92   return first_rect_;
95 NSAttributedString* TextInputClientMac::GetAttributedSubstringFromRange(
96     RenderWidgetHost* rwh,
97     NSRange range) {
98   base::TimeTicks start = base::TimeTicks::Now();
100   BeforeRequest();
101   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh);
102   rwhi->Send(new TextInputClientMsg_StringForRange(rwhi->GetRoutingID(),
103                                                    gfx::Range(range)));
104   // http://crbug.com/121917
105   base::ThreadRestrictions::ScopedAllowWait allow_wait;
106   condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout));
107   AfterRequest();
109   base::TimeDelta delta(base::TimeTicks::Now() - start);
110   UMA_HISTOGRAM_LONG_TIMES("TextInputClient.Substring",
111                            delta * base::Time::kMicrosecondsPerMillisecond);
113   // Lookup.framework calls this method repeatedly and expects that repeated
114   // calls don't deallocate previous results immediately. Returning an
115   // autoreleased string is better convention anyway.
116   return [[substring_.get() retain] autorelease];
119 void TextInputClientMac::SetCharacterIndexAndSignal(NSUInteger index) {
120   lock_.Acquire();
121   character_index_ = index;
122   lock_.Release();
123   condition_.Signal();
126 void TextInputClientMac::SetFirstRectAndSignal(NSRect first_rect) {
127   lock_.Acquire();
128   first_rect_ = first_rect;
129   lock_.Release();
130   condition_.Signal();
133 void TextInputClientMac::SetSubstringAndSignal(NSAttributedString* string) {
134   lock_.Acquire();
135   substring_.reset([string copy]);
136   lock_.Release();
137   condition_.Signal();
140 void TextInputClientMac::BeforeRequest() {
141   base::TimeTicks start = base::TimeTicks::Now();
143   lock_.Acquire();
145   base::TimeDelta delta(base::TimeTicks::Now() - start);
146   UMA_HISTOGRAM_LONG_TIMES("TextInputClient.LockWait",
147                            delta * base::Time::kMicrosecondsPerMillisecond);
149   character_index_ = NSNotFound;
150   first_rect_ = NSZeroRect;
151   substring_.reset();
154 void TextInputClientMac::AfterRequest() {
155   lock_.Release();
158 }  // namespace content