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. 4 5 #ifndef CONTENT_BROWSER_RENDERER_HOST_TEXT_INPUT_CLIENT_MAC_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_TEXT_INPUT_CLIENT_MAC_H_ 7 8 #import <Cocoa/Cocoa.h> 9 10 #include "base/mac/scoped_block.h" 11 #include "base/mac/scoped_nsobject.h" 12 #include "base/macros.h" 13 #include "base/synchronization/condition_variable.h" 14 #include "base/synchronization/lock.h" 15 #include "content/common/content_export.h" 16 #include "content/common/mac/attributed_string_coder.h" 17 #include "ui/gfx/geometry/point.h" 18 #include "ui/gfx/geometry/rect.h" 19 20 namespace base { 21 template <typename T> 22 struct DefaultSingletonTraits; 23 } // namespace base 24 25 namespace gfx { 26 class Range; 27 } 28 29 namespace content { 30 class RenderWidgetHost; 31 32 // This class helps with the Mac OS X dictionary popup. For the design overview, 33 // look at this document: 34 // http://dev.chromium.org/developers/design-documents/system-dictionary-pop-up-architecture 35 // 36 // This service is used to marshall information for these three methods that are 37 // implemented in RenderWidgetHostViewMac: 38 // -[NSTextInput characterIndexForPoint:] 39 // -[NSTextInput attributedSubstringFromRange:] 40 // -[NSTextInput firstRectForCharacterRange:] 41 // 42 // Because these methods are part of a synchronous system API, implementing them 43 // requires getting information from the renderer synchronously. Rather than 44 // using an actual sync IPC message, a normal async ViewMsg is used with a lock 45 // and condition (managed by this service). 46 // 47 // Mac OS 10.8 introduced -[NSResponder quickLookWithEvent:]. 48 // We can use it to implement asynchronous dictionary lookup when the user 49 // taps a word using three fingers. 50 // But currently the "Look Up in Dictionary" context menu item still goes 51 // through the above synchronous IPC. 52 class CONTENT_EXPORT TextInputClientMac { 53 public: 54 // Returns the singleton instance. 55 static TextInputClientMac* GetInstance(); 56 57 // Each of the three methods mentioned above has an associated pair of methods 58 // to get data from the renderer. The Get*() methods block the calling thread 59 // (always the UI thread) with a short timeout after the async message has 60 // been sent to the renderer to lookup the information needed to respond to 61 // the system. The Set*AndSignal() methods store the looked up information in 62 // this service and signal the condition to allow the Get*() methods to 63 // unlock and return that stored value. 64 // 65 // Returns UINT32_MAX if the request times out or is not completed. 66 uint32_t GetCharacterIndexAtPoint(RenderWidgetHost* rwh, 67 const gfx::Point& point); 68 // Returns NSZeroRect if the request times out or is not completed. The result 69 // is in WebKit coordinates. 70 gfx::Rect GetFirstRectForRange(RenderWidgetHost* rwh, 71 const gfx::Range& range); 72 73 // When the renderer sends the ViewHostMsg reply, the RenderMessageFilter will 74 // call the corresponding method on the IO thread to unlock the condition and 75 // allow the Get*() methods to continue/return. 76 void SetCharacterIndexAndSignal(uint32_t index); 77 void SetFirstRectAndSignal(const gfx::Rect& first_rect); 78 79 typedef base::OnceCallback< 80 void(const mac::AttributedStringCoder::EncodedString&, gfx::Point)> 81 GetStringCallback; 82 83 // This async method is invoked from RenderWidgetHostViewCocoa's 84 // -quickLookWithEvent:, when the user taps a word using 3 fingers. 85 // The reply callback will be invoked from the IO thread; the caller is 86 // responsible for bouncing to the main thread if necessary. 87 // The callback parameters provide the attributed word under the point and 88 // the lower left baseline point of the text. 89 void GetStringAtPoint(RenderWidgetHost* rwh, 90 const gfx::Point& point, 91 GetStringCallback callback); 92 93 // This is called on the IO thread when we get the renderer's reply for 94 // GetStringAtPoint. 95 void GetStringAtPointReply( 96 const mac::AttributedStringCoder::EncodedString& string, 97 const gfx::Point& point); 98 99 // This async method is invoked when browser tries to retreive the text for 100 // certain range and doesn't want to wait for the reply from blink. 101 // The reply callback will be invoked from the IO thread; the caller is 102 // responsible for bouncing to the main thread if necessary. 103 // The callback parameters provide the attributed word under the point and 104 // the lower left baseline point of the text. 105 void GetStringFromRange(RenderWidgetHost* rwh, 106 const gfx::Range& range, 107 GetStringCallback callback); 108 109 // This is called on the IO thread when we get the renderer's reply for 110 // GetStringFromRange. 111 void GetStringFromRangeReply( 112 const mac::AttributedStringCoder::EncodedString& string, 113 const gfx::Point& point); 114 115 private: 116 friend struct base::DefaultSingletonTraits<TextInputClientMac>; 117 TextInputClientMac(); 118 ~TextInputClientMac(); 119 120 // The critical sections that the Condition guards are in Get*() methods. 121 // These methods lock the internal condition for use before the asynchronous 122 // message is sent to the renderer to lookup the required information. These 123 // are only used on the UI thread. 124 void BeforeRequest() EXCLUSIVE_LOCK_FUNCTION(lock_); 125 // Called at the end of a critical section. This will release the lock and 126 // condition. 127 void AfterRequest() UNLOCK_FUNCTION(lock_); 128 129 uint32_t character_index_; 130 gfx::Rect first_rect_; 131 132 base::Lock lock_; 133 base::ConditionVariable condition_; 134 135 // The callback when received IPC TextInputClientReplyMsg_GotStringAtPoint. 136 GetStringCallback replyForPointHandler_; 137 138 // The callback when received IPC TextInputClientReplyMsg_GotStringForRange. 139 GetStringCallback replyForRangeHandler_; 140 141 DISALLOW_COPY_AND_ASSIGN(TextInputClientMac); 142 }; 143 144 } // namespace content 145 146 #endif // CONTENT_BROWSER_RENDERER_HOST_TEXT_INPUT_CLIENT_MAC_H_ 147