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/synchronization/condition_variable.h" 13#include "base/synchronization/lock.h" 14#include "content/common/content_export.h" 15#include "ui/gfx/point.h" 16 17template <typename T> struct DefaultSingletonTraits; 18 19namespace content { 20class RenderWidgetHost; 21 22// This class helps with the Mac OS X dictionary popup. For the design overview, 23// look at this document: 24// http://dev.chromium.org/developers/design-documents/system-dictionary-pop-up-architecture 25// 26// This service is used to marshall information for these three methods that are 27// implemented in RenderWidgetHostViewMac: 28// -[NSTextInput characterIndexForPoint:] 29// -[NSTextInput attributedSubstringFromRange:] 30// -[NSTextInput firstRectForCharacterRange:] 31// 32// Because these methods are part of a synchronous system API, implementing them 33// requires getting information from the renderer synchronously. Rather than 34// using an actual sync IPC message, a normal async ViewMsg is used with a lock 35// and condition (managed by this service). 36// 37// Mac OS 10.8 introduced -[NSResponder quickLookWithEvent:]. 38// We can use it to implement asynchronous dictionary lookup when the user 39// taps a word using three fingers. 40// But currently the "Look Up in Dictionary" context menu item still goes 41// through the above synchronous IPC. 42class CONTENT_EXPORT TextInputClientMac { 43 public: 44 // Returns the singleton instance. 45 static TextInputClientMac* GetInstance(); 46 47 // Each of the three methods mentioned above has an associated pair of methods 48 // to get data from the renderer. The Get*() methods block the calling thread 49 // (always the UI thread) with a short timeout after the async message has 50 // been sent to the renderer to lookup the information needed to respond to 51 // the system. The Set*AndSignal() methods store the looked up information in 52 // this service and signal the condition to allow the Get*() methods to 53 // unlock and return that stored value. 54 // 55 // Returns NSNotFound if the request times out or is not completed. 56 NSUInteger GetCharacterIndexAtPoint(RenderWidgetHost* rwh, gfx::Point point); 57 // Returns nil if the request times out or is completed. 58 NSAttributedString* GetAttributedSubstringFromRange( 59 RenderWidgetHost* rwh, NSRange range); 60 // Returns NSZeroRect if the request times out or is not completed. The result 61 // is in WebKit coordinates. 62 NSRect GetFirstRectForRange(RenderWidgetHost* rwh, NSRange range); 63 64 // When the renderer sends the ViewHostMsg reply, the RenderMessageFilter will 65 // call the corresponding method on the IO thread to unlock the condition and 66 // allow the Get*() methods to continue/return. 67 void SetCharacterIndexAndSignal(NSUInteger index); 68 void SetFirstRectAndSignal(NSRect first_rect); 69 void SetSubstringAndSignal(NSAttributedString* string); 70 71 // This async method is invoked from RenderWidgetHostViewCocoa's 72 // -quickLookWithEvent:, when the user taps a word using 3 fingers. 73 // The reply callback will be invoked from the IO thread, the caller is 74 // responsible for bouncing to the main thread if necessary. 75 // The callback parameters provide the attributed word under the point and 76 // the lower left baseline point of the text. 77 void GetStringAtPoint(RenderWidgetHost* rwh, 78 gfx::Point point, 79 void (^replyHandler)(NSAttributedString*, NSPoint)); 80 // This is called on the IO thread when we get the renderer's reply for 81 // GetStringAtPoint. 82 void GetStringAtPointReply(NSAttributedString*, NSPoint); 83 84 private: 85 friend struct DefaultSingletonTraits<TextInputClientMac>; 86 TextInputClientMac(); 87 ~TextInputClientMac(); 88 89 // The critical sections that the Condition guards are in Get*() methods. 90 // These methods lock the internal condition for use before the asynchronous 91 // message is sent to the renderer to lookup the required information. These 92 // are only used on the UI thread. 93 void BeforeRequest(); 94 // Called at the end of a critical section. This will release the lock and 95 // condition. 96 void AfterRequest(); 97 98 NSUInteger character_index_; 99 NSRect first_rect_; 100 base::scoped_nsobject<NSAttributedString> substring_; 101 102 base::Lock lock_; 103 base::ConditionVariable condition_; 104 105 base::mac::ScopedBlock<void(^)(NSAttributedString*, NSPoint)> replyHandler_; 106 107 DISALLOW_COPY_AND_ASSIGN(TextInputClientMac); 108}; 109 110} // namespace content 111 112#endif // CONTENT_BROWSER_RENDERER_HOST_TEXT_INPUT_CLIENT_MAC_H_ 113