Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / views / cocoa / bridged_content_view.mm
blobb5b1b96739ca53d474e6e30cf11712c7e1385017
1 // Copyright 2014 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 "ui/views/cocoa/bridged_content_view.h"
7 #include "base/logging.h"
8 #import "base/mac/scoped_nsobject.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "ui/base/ime/text_input_client.h"
11 #include "ui/gfx/canvas_paint_mac.h"
12 #include "ui/gfx/geometry/rect.h"
13 #include "ui/strings/grit/ui_strings.h"
14 #include "ui/views/view.h"
15 #include "ui/views/widget/widget.h"
17 @interface BridgedContentView ()
19 // Translates the location of |theEvent| to toolkit-views coordinates and passes
20 // the event to NativeWidgetMac for handling.
21 - (void)handleMouseEvent:(NSEvent*)theEvent;
23 // Execute a command on the currently focused TextInputClient.
24 // |commandId| should be a resource ID from ui_strings.grd.
25 - (void)doCommandByID:(int)commandId;
27 @end
29 @implementation BridgedContentView
31 @synthesize hostedView = hostedView_;
32 @synthesize textInputClient = textInputClient_;
34 - (id)initWithView:(views::View*)viewToHost {
35   DCHECK(viewToHost);
36   gfx::Rect bounds = viewToHost->bounds();
37   // To keep things simple, assume the origin is (0, 0) until there exists a use
38   // case for something other than that.
39   DCHECK(bounds.origin().IsOrigin());
40   NSRect initialFrame = NSMakeRect(0, 0, bounds.width(), bounds.height());
41   if ((self = [super initWithFrame:initialFrame])) {
42     hostedView_ = viewToHost;
44     trackingArea_.reset(
45         [[CrTrackingArea alloc] initWithRect:NSZeroRect
46                                      options:NSTrackingMouseMoved |
47                                              NSTrackingActiveAlways |
48                                              NSTrackingInVisibleRect
49                                        owner:self
50                                     userInfo:nil]);
51     [self addTrackingArea:trackingArea_.get()];
52   }
53   return self;
56 - (void)clearView {
57   hostedView_ = NULL;
58   [trackingArea_.get() clearOwner];
59   [self removeTrackingArea:trackingArea_.get()];
62 // BridgedContentView private implementation.
64 - (void)handleMouseEvent:(NSEvent*)theEvent {
65   if (!hostedView_)
66     return;
68   ui::MouseEvent event(theEvent);
69   hostedView_->GetWidget()->OnMouseEvent(&event);
72 - (void)doCommandByID:(int)commandId {
73   if (textInputClient_ && textInputClient_->IsEditingCommandEnabled(commandId))
74     textInputClient_->ExecuteEditingCommand(commandId);
77 // NSView implementation.
79 - (BOOL)acceptsFirstResponder {
80   return YES;
83 - (void)setFrameSize:(NSSize)newSize {
84   [super setFrameSize:newSize];
85   if (!hostedView_)
86     return;
88   hostedView_->SetSize(gfx::Size(newSize.width, newSize.height));
91 - (void)drawRect:(NSRect)dirtyRect {
92   if (!hostedView_)
93     return;
95   gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */);
96   hostedView_->Paint(&canvas, views::CullSet());
99 // NSResponder implementation.
101 - (void)keyDown:(NSEvent*)theEvent {
102   if (textInputClient_)
103     [self interpretKeyEvents:@[ theEvent ]];
104   else
105     [super keyDown:theEvent];
108 - (void)mouseDown:(NSEvent*)theEvent {
109   [self handleMouseEvent:theEvent];
112 - (void)rightMouseDown:(NSEvent*)theEvent {
113   [self handleMouseEvent:theEvent];
116 - (void)otherMouseDown:(NSEvent*)theEvent {
117   [self handleMouseEvent:theEvent];
120 - (void)mouseUp:(NSEvent*)theEvent {
121   [self handleMouseEvent:theEvent];
124 - (void)rightMouseUp:(NSEvent*)theEvent {
125   [self handleMouseEvent:theEvent];
128 - (void)otherMouseUp:(NSEvent*)theEvent {
129   [self handleMouseEvent:theEvent];
132 - (void)mouseDragged:(NSEvent*)theEvent {
133   [self handleMouseEvent:theEvent];
136 - (void)rightMouseDragged:(NSEvent*)theEvent {
137   [self handleMouseEvent:theEvent];
140 - (void)otherMouseDragged:(NSEvent*)theEvent {
141   [self handleMouseEvent:theEvent];
144 - (void)mouseMoved:(NSEvent*)theEvent {
145   // Note: mouseEntered: and mouseExited: are not handled separately.
146   // |hostedView_| is responsible for converting the move events into entered
147   // and exited events for the view heirarchy.
148   [self handleMouseEvent:theEvent];
151 - (void)scrollWheel:(NSEvent*)theEvent {
152   [self handleMouseEvent:theEvent];
155 - (void)deleteBackward:(id)sender {
156   [self doCommandByID:IDS_DELETE_BACKWARD];
159 - (void)deleteForward:(id)sender {
160   [self doCommandByID:IDS_DELETE_FORWARD];
163 - (void)moveLeft:(id)sender {
164   [self doCommandByID:IDS_MOVE_LEFT];
167 - (void)moveRight:(id)sender {
168   [self doCommandByID:IDS_MOVE_RIGHT];
171 - (void)insertText:(id)text {
172   if (textInputClient_)
173     textInputClient_->InsertText(base::SysNSStringToUTF16(text));
176 // Support for Services in context menus.
177 // Currently we only support reading and writing plain strings.
178 - (id)validRequestorForSendType:(NSString*)sendType
179                      returnType:(NSString*)returnType {
180   BOOL canWrite = [sendType isEqualToString:NSStringPboardType] &&
181                   [self selectedRange].length > 0;
182   BOOL canRead = [returnType isEqualToString:NSStringPboardType];
183   // Valid if (sendType, returnType) is either (string, nil), (nil, string),
184   // or (string, string).
185   BOOL valid = textInputClient_ && ((canWrite && (canRead || !returnType)) ||
186                                     (canRead && (canWrite || !sendType)));
187   return valid ? self : [super validRequestorForSendType:sendType
188                                               returnType:returnType];
191 // NSServicesRequests informal protocol.
193 - (BOOL)writeSelectionToPasteboard:(NSPasteboard*)pboard types:(NSArray*)types {
194   DCHECK([types containsObject:NSStringPboardType]);
195   if (!textInputClient_)
196     return NO;
198   gfx::Range selectionRange;
199   if (!textInputClient_->GetSelectionRange(&selectionRange))
200     return NO;
202   base::string16 text;
203   textInputClient_->GetTextFromRange(selectionRange, &text);
204   return [pboard writeObjects:@[ base::SysUTF16ToNSString(text) ]];
207 - (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard {
208   NSArray* objects =
209       [pboard readObjectsForClasses:@[ [NSString class] ] options:0];
210   DCHECK([objects count] == 1);
211   [self insertText:[objects lastObject]];
212   return YES;
215 // NSTextInputClient protocol implementation.
217 - (NSAttributedString*)
218     attributedSubstringForProposedRange:(NSRange)range
219                             actualRange:(NSRangePointer)actualRange {
220   base::string16 substring;
221   if (textInputClient_) {
222     gfx::Range textRange;
223     textInputClient_->GetTextRange(&textRange);
224     gfx::Range subrange = textRange.Intersect(gfx::Range(range));
225     textInputClient_->GetTextFromRange(subrange, &substring);
226     if (actualRange)
227       *actualRange = subrange.ToNSRange();
228   }
229   return [[[NSAttributedString alloc]
230       initWithString:base::SysUTF16ToNSString(substring)] autorelease];
233 - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
234   NOTIMPLEMENTED();
235   return 0;
238 - (void)doCommandBySelector:(SEL)selector {
239   if ([self respondsToSelector:selector])
240     [self performSelector:selector withObject:nil];
241   else
242     [[self nextResponder] doCommandBySelector:selector];
245 - (NSRect)firstRectForCharacterRange:(NSRange)range
246                          actualRange:(NSRangePointer)actualRange {
247   NOTIMPLEMENTED();
248   return NSZeroRect;
251 - (BOOL)hasMarkedText {
252   return textInputClient_ && textInputClient_->HasCompositionText();
255 - (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
256   if (!textInputClient_)
257     return;
259   if ([text isKindOfClass:[NSAttributedString class]])
260     text = [text string];
261   textInputClient_->DeleteRange(gfx::Range(replacementRange));
262   textInputClient_->InsertText(base::SysNSStringToUTF16(text));
265 - (NSRange)markedRange {
266   if (!textInputClient_)
267     return NSMakeRange(NSNotFound, 0);
269   gfx::Range range;
270   textInputClient_->GetCompositionTextRange(&range);
271   return range.ToNSRange();
274 - (NSRange)selectedRange {
275   if (!textInputClient_)
276     return NSMakeRange(NSNotFound, 0);
278   gfx::Range range;
279   textInputClient_->GetSelectionRange(&range);
280   return range.ToNSRange();
283 - (void)setMarkedText:(id)text
284         selectedRange:(NSRange)selectedRange
285      replacementRange:(NSRange)replacementRange {
286   if (!textInputClient_)
287     return;
289   if ([text isKindOfClass:[NSAttributedString class]])
290     text = [text string];
291   ui::CompositionText composition;
292   composition.text = base::SysNSStringToUTF16(text);
293   composition.selection = gfx::Range(selectedRange);
294   textInputClient_->SetCompositionText(composition);
297 - (void)unmarkText {
298   if (textInputClient_)
299     textInputClient_->ConfirmCompositionText();
302 - (NSArray*)validAttributesForMarkedText {
303   return @[];
306 // NSAccessibility informal protocol implementation.
308 - (id)accessibilityAttributeValue:(NSString*)attribute {
309   if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
310     return @[ hostedView_->GetNativeViewAccessible() ];
311   }
313   return [super accessibilityAttributeValue:attribute];
316 - (id)accessibilityHitTest:(NSPoint)point {
317   return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point];
320 @end