/tests/cefclient/browser/browser_window_osr_mac.mm

https://bitbucket.org/icedtoast/cef · Objective C++ · 1589 lines · 1190 code · 307 blank · 92 comment · 175 complexity · 1487844363b686d22831c0377fc52bf7 MD5 · raw file

  1. // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
  2. // reserved. Use of this source code is governed by a BSD-style license that
  3. // can be found in the LICENSE file.
  4. #include "tests/cefclient/browser/browser_window_osr_mac.h"
  5. #include <Cocoa/Cocoa.h>
  6. #include <OpenGL/gl.h>
  7. #import <objc/runtime.h>
  8. #include "include/base/cef_logging.h"
  9. #include "include/cef_parser.h"
  10. #include "include/wrapper/cef_closure_task.h"
  11. #include "tests/cefclient/browser/bytes_write_handler.h"
  12. #include "tests/cefclient/browser/main_context.h"
  13. #include "tests/cefclient/browser/osr_accessibility_helper.h"
  14. #include "tests/cefclient/browser/osr_accessibility_node.h"
  15. #include "tests/cefclient/browser/text_input_client_osr_mac.h"
  16. #include "tests/shared/browser/geometry_util.h"
  17. #include "tests/shared/browser/main_message_loop.h"
  18. #import <AppKit/NSAccessibility.h>
  19. namespace {
  20. CefTextInputClientOSRMac* GetInputClientFromContext(
  21. const NSTextInputContext* context) {
  22. if (!context)
  23. return NULL;
  24. return reinterpret_cast<CefTextInputClientOSRMac*>([context client]);
  25. }
  26. } // namespace
  27. @interface BrowserOpenGLView
  28. : NSOpenGLView<NSDraggingSource, NSDraggingDestination, NSAccessibility> {
  29. @private
  30. NSTrackingArea* tracking_area_;
  31. client::BrowserWindowOsrMac* browser_window_;
  32. client::OsrRenderer* renderer_;
  33. NSPoint last_mouse_pos_;
  34. NSPoint cur_mouse_pos_;
  35. bool rotating_;
  36. bool was_last_mouse_down_on_view_;
  37. float device_scale_factor_;
  38. // Drag and drop.
  39. CefRefPtr<CefDragData> current_drag_data_;
  40. NSDragOperation current_drag_op_;
  41. NSDragOperation current_allowed_ops_;
  42. NSPasteboard* pasteboard_;
  43. CFStringRef fileUTI_;
  44. // For intreacting with IME.
  45. NSTextInputContext* text_input_context_osr_mac_;
  46. // Manages Accessibility Tree
  47. client::OsrAccessibilityHelper* accessibility_helper_;
  48. // Event monitor for scroll wheel end event.
  49. id endWheelMonitor_;
  50. }
  51. - (id)initWithFrame:(NSRect)frame
  52. andBrowserWindow:(client::BrowserWindowOsrMac*)browser_window
  53. andRenderer:(client::OsrRenderer*)renderer;
  54. - (void)detach;
  55. - (CefRefPtr<CefBrowser>)getBrowser;
  56. - (NSPoint)getClickPointForEvent:(NSEvent*)event;
  57. - (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event;
  58. - (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event;
  59. - (void)getMouseEvent:(CefMouseEvent&)mouseEvent
  60. forDragInfo:(id<NSDraggingInfo>)info;
  61. - (int)getModifiersForEvent:(NSEvent*)event;
  62. - (BOOL)isKeyUpEvent:(NSEvent*)event;
  63. - (BOOL)isKeyPadEvent:(NSEvent*)event;
  64. - (BOOL)startDragging:(CefRefPtr<CefDragData>)drag_data
  65. allowedOps:(NSDragOperation)ops
  66. point:(NSPoint)p;
  67. - (void)setCurrentDragOp:(NSDragOperation)op;
  68. - (void)resetDragDrop;
  69. - (void)fillPasteboard;
  70. - (void)populateDropData:(CefRefPtr<CefDragData>)data
  71. fromPasteboard:(NSPasteboard*)pboard;
  72. - (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint;
  73. - (void)resetDeviceScaleFactor;
  74. - (void)setDeviceScaleFactor:(float)device_scale_factor;
  75. - (float)getDeviceScaleFactor;
  76. - (void)windowDidChangeBackingProperties:(NSNotification*)notification;
  77. - (bool)isOverPopupWidgetX:(int)x andY:(int)y;
  78. - (void)applyPopupOffsetToX:(int&)x andY:(int&)y;
  79. - (int)getPopupXOffset;
  80. - (int)getPopupYOffset;
  81. - (void)sendMouseClick:(NSEvent*)event
  82. button:(CefBrowserHost::MouseButtonType)type
  83. isUp:(bool)isUp;
  84. - (NSPoint)convertPointFromBackingInternal:(NSPoint)aPoint;
  85. - (NSPoint)convertPointToBackingInternal:(NSPoint)aPoint;
  86. - (NSRect)convertRectFromBackingInternal:(NSRect)aRect;
  87. - (NSRect)convertRectToBackingInternal:(NSRect)aRect;
  88. - (void)ChangeCompositionRange:(CefRange)range
  89. character_bounds:
  90. (const CefRenderHandler::RectList&)character_bounds;
  91. - (void)UpdateAccessibilityTree:(CefRefPtr<CefValue>)value;
  92. @end
  93. namespace {
  94. NSString* const kCEFDragDummyPboardType = @"org.CEF.drag-dummy-type";
  95. NSString* const kNSURLTitlePboardType = @"public.url-name";
  96. class ScopedGLContext {
  97. public:
  98. ScopedGLContext(BrowserOpenGLView* view, bool swap_buffers)
  99. : swap_buffers_(swap_buffers) {
  100. context_ = [view openGLContext];
  101. [context_ makeCurrentContext];
  102. }
  103. ~ScopedGLContext() {
  104. [NSOpenGLContext clearCurrentContext];
  105. if (swap_buffers_)
  106. [context_ flushBuffer];
  107. }
  108. private:
  109. NSOpenGLContext* context_;
  110. const bool swap_buffers_;
  111. };
  112. BrowserOpenGLView* GLView(NSView* view) {
  113. return static_cast<BrowserOpenGLView*>(view);
  114. }
  115. NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
  116. NSRect point_rect = NSMakeRect(point.x, point.y, 0, 0);
  117. return [window convertRectToScreen:point_rect].origin;
  118. }
  119. } // namespace
  120. @implementation BrowserOpenGLView
  121. - (id)initWithFrame:(NSRect)frame
  122. andBrowserWindow:(client::BrowserWindowOsrMac*)browser_window
  123. andRenderer:(client::OsrRenderer*)renderer {
  124. NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc]
  125. initWithAttributes:(NSOpenGLPixelFormatAttribute[]){
  126. NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 32,
  127. 0}];
  128. [pixelFormat autorelease];
  129. if (self = [super initWithFrame:frame pixelFormat:pixelFormat]) {
  130. browser_window_ = browser_window;
  131. renderer_ = renderer;
  132. rotating_ = false;
  133. endWheelMonitor_ = nil;
  134. device_scale_factor_ = 1.0f;
  135. tracking_area_ = [[NSTrackingArea alloc]
  136. initWithRect:frame
  137. options:NSTrackingMouseMoved | NSTrackingActiveInActiveApp |
  138. NSTrackingInVisibleRect
  139. owner:self
  140. userInfo:nil];
  141. [self addTrackingArea:tracking_area_];
  142. // enable HiDPI buffer
  143. [self setWantsBestResolutionOpenGLSurface:YES];
  144. [self resetDragDrop];
  145. NSArray* types = [NSArray
  146. arrayWithObjects:kCEFDragDummyPboardType, NSStringPboardType,
  147. NSFilenamesPboardType, NSPasteboardTypeString, nil];
  148. [self registerForDraggedTypes:types];
  149. }
  150. return self;
  151. }
  152. - (void)dealloc {
  153. [[NSNotificationCenter defaultCenter]
  154. removeObserver:self
  155. name:NSWindowDidChangeBackingPropertiesNotification
  156. object:nil];
  157. if (text_input_context_osr_mac_) {
  158. [GetInputClientFromContext(text_input_context_osr_mac_) release];
  159. [text_input_context_osr_mac_ release];
  160. }
  161. [super dealloc];
  162. }
  163. - (void)detach {
  164. renderer_ = NULL;
  165. browser_window_ = NULL;
  166. if (text_input_context_osr_mac_)
  167. [GetInputClientFromContext(text_input_context_osr_mac_) detach];
  168. }
  169. - (CefRefPtr<CefBrowser>)getBrowser {
  170. if (browser_window_)
  171. return browser_window_->GetBrowser();
  172. return NULL;
  173. }
  174. - (void)setFrame:(NSRect)frameRect {
  175. CefRefPtr<CefBrowser> browser = [self getBrowser];
  176. if (!browser.get())
  177. return;
  178. [super setFrame:frameRect];
  179. browser->GetHost()->WasResized();
  180. }
  181. - (void)sendMouseClick:(NSEvent*)event
  182. button:(CefBrowserHost::MouseButtonType)type
  183. isUp:(bool)isUp {
  184. CefRefPtr<CefBrowser> browser = [self getBrowser];
  185. if (!browser.get())
  186. return;
  187. CefMouseEvent mouseEvent;
  188. [self getMouseEvent:mouseEvent forEvent:event];
  189. // |point| is in OS X view coordinates.
  190. NSPoint point = [self getClickPointForEvent:event];
  191. // Convert to device coordinates.
  192. point = [self convertPointToBackingInternal:point];
  193. if (!isUp) {
  194. was_last_mouse_down_on_view_ =
  195. ![self isOverPopupWidgetX:point.x andY:point.y];
  196. } else if (was_last_mouse_down_on_view_ &&
  197. [self isOverPopupWidgetX:point.x andY:point.y] &&
  198. ([self getPopupXOffset] || [self getPopupYOffset])) {
  199. return;
  200. }
  201. browser->GetHost()->SendMouseClickEvent(mouseEvent, type, isUp,
  202. [event clickCount]);
  203. }
  204. - (void)mouseDown:(NSEvent*)event {
  205. [self sendMouseClick:event button:MBT_LEFT isUp:false];
  206. }
  207. - (void)rightMouseDown:(NSEvent*)event {
  208. if ([event modifierFlags] & NSShiftKeyMask) {
  209. // Start rotation effect.
  210. last_mouse_pos_ = cur_mouse_pos_ = [self getClickPointForEvent:event];
  211. rotating_ = true;
  212. return;
  213. }
  214. [self sendMouseClick:event button:MBT_RIGHT isUp:false];
  215. }
  216. - (void)otherMouseDown:(NSEvent*)event {
  217. [self sendMouseClick:event button:MBT_MIDDLE isUp:false];
  218. }
  219. - (void)mouseUp:(NSEvent*)event {
  220. [self sendMouseClick:event button:MBT_LEFT isUp:true];
  221. }
  222. - (void)rightMouseUp:(NSEvent*)event {
  223. if (rotating_) {
  224. // End rotation effect.
  225. renderer_->SetSpin(0, 0);
  226. rotating_ = false;
  227. [self setNeedsDisplay:YES];
  228. return;
  229. }
  230. [self sendMouseClick:event button:MBT_RIGHT isUp:true];
  231. }
  232. - (void)otherMouseUp:(NSEvent*)event {
  233. [self sendMouseClick:event button:MBT_MIDDLE isUp:true];
  234. }
  235. - (void)mouseMoved:(NSEvent*)event {
  236. CefRefPtr<CefBrowser> browser = [self getBrowser];
  237. if (!browser.get())
  238. return;
  239. if (rotating_) {
  240. // Apply rotation effect.
  241. cur_mouse_pos_ = [self getClickPointForEvent:event];
  242. ;
  243. renderer_->IncrementSpin((cur_mouse_pos_.x - last_mouse_pos_.x),
  244. (cur_mouse_pos_.y - last_mouse_pos_.y));
  245. last_mouse_pos_ = cur_mouse_pos_;
  246. [self setNeedsDisplay:YES];
  247. return;
  248. }
  249. CefMouseEvent mouseEvent;
  250. [self getMouseEvent:mouseEvent forEvent:event];
  251. browser->GetHost()->SendMouseMoveEvent(mouseEvent, false);
  252. }
  253. - (void)mouseDragged:(NSEvent*)event {
  254. [self mouseMoved:event];
  255. }
  256. - (void)rightMouseDragged:(NSEvent*)event {
  257. [self mouseMoved:event];
  258. }
  259. - (void)otherMouseDragged:(NSEvent*)event {
  260. [self mouseMoved:event];
  261. }
  262. - (void)mouseEntered:(NSEvent*)event {
  263. [self mouseMoved:event];
  264. }
  265. - (void)mouseExited:(NSEvent*)event {
  266. CefRefPtr<CefBrowser> browser = [self getBrowser];
  267. if (!browser.get())
  268. return;
  269. CefMouseEvent mouseEvent;
  270. [self getMouseEvent:mouseEvent forEvent:event];
  271. browser->GetHost()->SendMouseMoveEvent(mouseEvent, true);
  272. }
  273. - (void)keyDown:(NSEvent*)event {
  274. CefRefPtr<CefBrowser> browser = [self getBrowser];
  275. if (!browser.get() || !text_input_context_osr_mac_)
  276. return;
  277. if ([event type] != NSFlagsChanged) {
  278. CefTextInputClientOSRMac* client =
  279. GetInputClientFromContext(text_input_context_osr_mac_);
  280. if (client) {
  281. [client HandleKeyEventBeforeTextInputClient:event];
  282. // The return value of this method seems to always be set to YES, thus we
  283. // ignore it and ask the host view whether IME is active or not.
  284. [text_input_context_osr_mac_ handleEvent:event];
  285. CefKeyEvent keyEvent;
  286. [self getKeyEvent:keyEvent forEvent:event];
  287. [client HandleKeyEventAfterTextInputClient:keyEvent];
  288. }
  289. }
  290. }
  291. - (void)keyUp:(NSEvent*)event {
  292. CefRefPtr<CefBrowser> browser = [self getBrowser];
  293. if (!browser.get())
  294. return;
  295. CefKeyEvent keyEvent;
  296. [self getKeyEvent:keyEvent forEvent:event];
  297. keyEvent.type = KEYEVENT_KEYUP;
  298. browser->GetHost()->SendKeyEvent(keyEvent);
  299. }
  300. - (void)flagsChanged:(NSEvent*)event {
  301. if ([self isKeyUpEvent:event])
  302. [self keyUp:event];
  303. else
  304. [self keyDown:event];
  305. }
  306. - (void)shortCircuitScrollWheelEvent:(NSEvent*)event {
  307. if ([event phase] != NSEventPhaseEnded &&
  308. [event phase] != NSEventPhaseCancelled)
  309. return;
  310. [self sendScrollWheelEvet:event];
  311. if (endWheelMonitor_) {
  312. [NSEvent removeMonitor:endWheelMonitor_];
  313. endWheelMonitor_ = nil;
  314. }
  315. }
  316. - (void)scrollWheel:(NSEvent*)event {
  317. // Use an NSEvent monitor to listen for the wheel-end end. This ensures that
  318. // the event is received even when the mouse cursor is no longer over the
  319. // view when the scrolling ends. Also it avoids sending duplicate scroll
  320. // events to the renderer.
  321. if ([event phase] == NSEventPhaseBegan && !endWheelMonitor_) {
  322. endWheelMonitor_ = [NSEvent
  323. addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
  324. handler:^(NSEvent* blockEvent) {
  325. [self shortCircuitScrollWheelEvent:
  326. blockEvent];
  327. return blockEvent;
  328. }];
  329. }
  330. [self sendScrollWheelEvet:event];
  331. }
  332. - (void)sendScrollWheelEvet:(NSEvent*)event {
  333. CefRefPtr<CefBrowser> browser = [self getBrowser];
  334. if (!browser.get())
  335. return;
  336. CGEventRef cgEvent = [event CGEvent];
  337. DCHECK(cgEvent);
  338. int deltaX =
  339. CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2);
  340. int deltaY =
  341. CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
  342. CefMouseEvent mouseEvent;
  343. [self getMouseEvent:mouseEvent forEvent:event];
  344. browser->GetHost()->SendMouseWheelEvent(mouseEvent, deltaX, deltaY);
  345. }
  346. - (BOOL)canBecomeKeyView {
  347. CefRefPtr<CefBrowser> browser = [self getBrowser];
  348. return (browser.get() != NULL);
  349. }
  350. - (BOOL)acceptsFirstResponder {
  351. CefRefPtr<CefBrowser> browser = [self getBrowser];
  352. return (browser.get() != NULL);
  353. }
  354. - (BOOL)becomeFirstResponder {
  355. CefRefPtr<CefBrowser> browser = [self getBrowser];
  356. if (browser.get()) {
  357. browser->GetHost()->SendFocusEvent(true);
  358. return [super becomeFirstResponder];
  359. }
  360. return NO;
  361. }
  362. - (BOOL)resignFirstResponder {
  363. CefRefPtr<CefBrowser> browser = [self getBrowser];
  364. if (browser.get()) {
  365. browser->GetHost()->SendFocusEvent(false);
  366. return [super resignFirstResponder];
  367. }
  368. return NO;
  369. }
  370. - (void)undo:(id)sender {
  371. CefRefPtr<CefBrowser> browser = [self getBrowser];
  372. if (browser.get())
  373. browser->GetFocusedFrame()->Undo();
  374. }
  375. - (void)redo:(id)sender {
  376. CefRefPtr<CefBrowser> browser = [self getBrowser];
  377. if (browser.get())
  378. browser->GetFocusedFrame()->Redo();
  379. }
  380. - (void)cut:(id)sender {
  381. CefRefPtr<CefBrowser> browser = [self getBrowser];
  382. if (browser.get())
  383. browser->GetFocusedFrame()->Cut();
  384. }
  385. - (void)copy:(id)sender {
  386. CefRefPtr<CefBrowser> browser = [self getBrowser];
  387. if (browser.get())
  388. browser->GetFocusedFrame()->Copy();
  389. }
  390. - (void)paste:(id)sender {
  391. CefRefPtr<CefBrowser> browser = [self getBrowser];
  392. if (browser.get())
  393. browser->GetFocusedFrame()->Paste();
  394. }
  395. - (void) delete:(id)sender {
  396. CefRefPtr<CefBrowser> browser = [self getBrowser];
  397. if (browser.get())
  398. browser->GetFocusedFrame()->Delete();
  399. }
  400. - (void)selectAll:(id)sender {
  401. CefRefPtr<CefBrowser> browser = [self getBrowser];
  402. if (browser.get())
  403. browser->GetFocusedFrame()->SelectAll();
  404. }
  405. - (NSPoint)getClickPointForEvent:(NSEvent*)event {
  406. NSPoint windowLocal = [event locationInWindow];
  407. NSPoint contentLocal = [self convertPoint:windowLocal fromView:nil];
  408. NSPoint point;
  409. point.x = contentLocal.x;
  410. point.y = [self frame].size.height - contentLocal.y; // Flip y.
  411. return point;
  412. }
  413. - (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event {
  414. if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
  415. NSString* s = [event characters];
  416. if ([s length] > 0)
  417. keyEvent.character = [s characterAtIndex:0];
  418. s = [event charactersIgnoringModifiers];
  419. if ([s length] > 0)
  420. keyEvent.unmodified_character = [s characterAtIndex:0];
  421. }
  422. if ([event type] == NSFlagsChanged) {
  423. keyEvent.character = 0;
  424. keyEvent.unmodified_character = 0;
  425. }
  426. keyEvent.native_key_code = [event keyCode];
  427. keyEvent.modifiers = [self getModifiersForEvent:event];
  428. }
  429. - (NSTextInputContext*)inputContext {
  430. if (!text_input_context_osr_mac_) {
  431. CefTextInputClientOSRMac* text_input_client =
  432. [[[CefTextInputClientOSRMac alloc] initWithBrowser:[self getBrowser]]
  433. retain];
  434. text_input_context_osr_mac_ =
  435. [[[NSTextInputContext alloc] initWithClient:text_input_client] retain];
  436. }
  437. return text_input_context_osr_mac_;
  438. }
  439. - (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event {
  440. const float device_scale_factor = [self getDeviceScaleFactor];
  441. // |point| is in OS X view coordinates.
  442. NSPoint point = [self getClickPointForEvent:event];
  443. // Convert to device coordinates.
  444. point = [self convertPointToBackingInternal:point];
  445. int device_x = point.x;
  446. int device_y = point.y;
  447. if ([self isOverPopupWidgetX:device_x andY:device_y])
  448. [self applyPopupOffsetToX:device_x andY:device_y];
  449. // Convert to browser view coordinates.
  450. mouseEvent.x = client::DeviceToLogical(device_x, device_scale_factor);
  451. mouseEvent.y = client::DeviceToLogical(device_y, device_scale_factor);
  452. mouseEvent.modifiers = [self getModifiersForEvent:event];
  453. }
  454. - (void)getMouseEvent:(CefMouseEvent&)mouseEvent
  455. forDragInfo:(id<NSDraggingInfo>)info {
  456. const float device_scale_factor = [self getDeviceScaleFactor];
  457. // |point| is in OS X view coordinates.
  458. NSPoint windowPoint = [info draggingLocation];
  459. NSPoint point = [self flipWindowPointToView:windowPoint];
  460. // Convert to device coordinates.
  461. point = [self convertPointToBackingInternal:point];
  462. // Convert to browser view coordinates.
  463. mouseEvent.x = client::DeviceToLogical(point.x, device_scale_factor);
  464. mouseEvent.y = client::DeviceToLogical(point.y, device_scale_factor);
  465. mouseEvent.modifiers = [NSEvent modifierFlags];
  466. }
  467. - (int)getModifiersForEvent:(NSEvent*)event {
  468. int modifiers = 0;
  469. if ([event modifierFlags] & NSControlKeyMask)
  470. modifiers |= EVENTFLAG_CONTROL_DOWN;
  471. if ([event modifierFlags] & NSShiftKeyMask)
  472. modifiers |= EVENTFLAG_SHIFT_DOWN;
  473. if ([event modifierFlags] & NSAlternateKeyMask)
  474. modifiers |= EVENTFLAG_ALT_DOWN;
  475. if ([event modifierFlags] & NSCommandKeyMask)
  476. modifiers |= EVENTFLAG_COMMAND_DOWN;
  477. if ([event modifierFlags] & NSAlphaShiftKeyMask)
  478. modifiers |= EVENTFLAG_CAPS_LOCK_ON;
  479. if ([event type] == NSKeyUp || [event type] == NSKeyDown ||
  480. [event type] == NSFlagsChanged) {
  481. // Only perform this check for key events
  482. if ([self isKeyPadEvent:event])
  483. modifiers |= EVENTFLAG_IS_KEY_PAD;
  484. }
  485. // OS X does not have a modifier for NumLock, so I'm not entirely sure how to
  486. // set EVENTFLAG_NUM_LOCK_ON;
  487. //
  488. // There is no EVENTFLAG for the function key either.
  489. // Mouse buttons
  490. switch ([event type]) {
  491. case NSLeftMouseDragged:
  492. case NSLeftMouseDown:
  493. case NSLeftMouseUp:
  494. modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
  495. break;
  496. case NSRightMouseDragged:
  497. case NSRightMouseDown:
  498. case NSRightMouseUp:
  499. modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
  500. break;
  501. case NSOtherMouseDragged:
  502. case NSOtherMouseDown:
  503. case NSOtherMouseUp:
  504. modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
  505. break;
  506. default:
  507. break;
  508. }
  509. return modifiers;
  510. }
  511. - (BOOL)isKeyUpEvent:(NSEvent*)event {
  512. if ([event type] != NSFlagsChanged)
  513. return [event type] == NSKeyUp;
  514. // FIXME: This logic fails if the user presses both Shift keys at once, for
  515. // example: we treat releasing one of them as keyDown.
  516. switch ([event keyCode]) {
  517. case 54: // Right Command
  518. case 55: // Left Command
  519. return ([event modifierFlags] & NSCommandKeyMask) == 0;
  520. case 57: // Capslock
  521. return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
  522. case 56: // Left Shift
  523. case 60: // Right Shift
  524. return ([event modifierFlags] & NSShiftKeyMask) == 0;
  525. case 58: // Left Alt
  526. case 61: // Right Alt
  527. return ([event modifierFlags] & NSAlternateKeyMask) == 0;
  528. case 59: // Left Ctrl
  529. case 62: // Right Ctrl
  530. return ([event modifierFlags] & NSControlKeyMask) == 0;
  531. case 63: // Function
  532. return ([event modifierFlags] & NSFunctionKeyMask) == 0;
  533. }
  534. return false;
  535. }
  536. - (BOOL)isKeyPadEvent:(NSEvent*)event {
  537. if ([event modifierFlags] & NSNumericPadKeyMask)
  538. return true;
  539. switch ([event keyCode]) {
  540. case 71: // Clear
  541. case 81: // =
  542. case 75: // /
  543. case 67: // *
  544. case 78: // -
  545. case 69: // +
  546. case 76: // Enter
  547. case 65: // .
  548. case 82: // 0
  549. case 83: // 1
  550. case 84: // 2
  551. case 85: // 3
  552. case 86: // 4
  553. case 87: // 5
  554. case 88: // 6
  555. case 89: // 7
  556. case 91: // 8
  557. case 92: // 9
  558. return true;
  559. }
  560. return false;
  561. }
  562. - (void)windowDidChangeBackingProperties:(NSNotification*)notification {
  563. // This delegate method is only called on 10.7 and later, so don't worry about
  564. // other backing changes calling it on 10.6 or earlier
  565. [self resetDeviceScaleFactor];
  566. }
  567. - (void)drawRect:(NSRect)dirtyRect {
  568. CefRefPtr<CefBrowser> browser = [self getBrowser];
  569. if ([self inLiveResize] || !browser.get()) {
  570. // Fill with the background color.
  571. const cef_color_t background_color =
  572. client::MainContext::Get()->GetBackgroundColor();
  573. NSColor* color = [NSColor
  574. colorWithCalibratedRed:float(CefColorGetR(background_color)) / 255.0f
  575. green:float(CefColorGetG(background_color)) / 255.0f
  576. blue:float(CefColorGetB(background_color)) / 255.0f
  577. alpha:1.f];
  578. [color setFill];
  579. NSRectFill(dirtyRect);
  580. }
  581. // The Invalidate below fixes flicker when resizing.
  582. if ([self inLiveResize] && browser.get())
  583. browser->GetHost()->Invalidate(PET_VIEW);
  584. }
  585. // Drag and drop
  586. - (BOOL)startDragging:(CefRefPtr<CefDragData>)drag_data
  587. allowedOps:(NSDragOperation)ops
  588. point:(NSPoint)position {
  589. DCHECK(!pasteboard_);
  590. DCHECK(!fileUTI_);
  591. DCHECK(!current_drag_data_.get());
  592. [self resetDragDrop];
  593. current_allowed_ops_ = ops;
  594. current_drag_data_ = drag_data;
  595. [self fillPasteboard];
  596. NSEvent* currentEvent = [[NSApplication sharedApplication] currentEvent];
  597. NSWindow* window = [self window];
  598. NSTimeInterval eventTime = [currentEvent timestamp];
  599. NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
  600. location:position
  601. modifierFlags:NSLeftMouseDraggedMask
  602. timestamp:eventTime
  603. windowNumber:[window windowNumber]
  604. context:nil
  605. eventNumber:0
  606. clickCount:1
  607. pressure:1.0];
  608. // TODO(cef): Pass a non-nil value to dragImage (see issue #1715). For now
  609. // work around the "callee requires a non-null argument" error that occurs
  610. // when building with the 10.11 SDK.
  611. id nilArg = nil;
  612. [window dragImage:nilArg
  613. at:position
  614. offset:NSZeroSize
  615. event:dragEvent
  616. pasteboard:pasteboard_
  617. source:self
  618. slideBack:YES];
  619. return YES;
  620. }
  621. - (void)setCurrentDragOp:(NSDragOperation)op {
  622. current_drag_op_ = op;
  623. }
  624. // NSDraggingSource Protocol
  625. - (NSDragOperation)draggingSession:(NSDraggingSession*)session
  626. sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
  627. switch (context) {
  628. case NSDraggingContextOutsideApplication:
  629. return current_allowed_ops_;
  630. case NSDraggingContextWithinApplication:
  631. default:
  632. return current_allowed_ops_;
  633. }
  634. }
  635. - (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
  636. if (![dropDest isFileURL])
  637. return nil;
  638. if (!current_drag_data_)
  639. return nil;
  640. size_t expected_size = current_drag_data_->GetFileContents(NULL);
  641. if (expected_size == 0)
  642. return nil;
  643. std::string path = [[dropDest path] UTF8String];
  644. path.append("/");
  645. path.append(current_drag_data_->GetFileName().ToString());
  646. CefRefPtr<CefStreamWriter> writer = CefStreamWriter::CreateForFile(path);
  647. if (!writer)
  648. return nil;
  649. if (current_drag_data_->GetFileContents(writer) != expected_size)
  650. return nil;
  651. return @[ [NSString stringWithUTF8String:path.c_str()] ];
  652. }
  653. - (void)draggedImage:(NSImage*)anImage
  654. endedAt:(NSPoint)screenPoint
  655. operation:(NSDragOperation)operation {
  656. CefRefPtr<CefBrowser> browser = [self getBrowser];
  657. if (!browser.get())
  658. return;
  659. if (operation == (NSDragOperationMove | NSDragOperationCopy))
  660. operation &= ~NSDragOperationMove;
  661. NSPoint windowPoint = [[self window] convertScreenToBase:screenPoint];
  662. NSPoint pt = [self flipWindowPointToView:windowPoint];
  663. CefRenderHandler::DragOperation op =
  664. static_cast<CefRenderHandler::DragOperation>(operation);
  665. browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, op);
  666. browser->GetHost()->DragSourceSystemDragEnded();
  667. [self resetDragDrop];
  668. }
  669. // NSDraggingDestination Protocol
  670. - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
  671. CefRefPtr<CefBrowser> browser = [self getBrowser];
  672. if (!browser.get())
  673. return NSDragOperationNone;
  674. CefRefPtr<CefDragData> drag_data;
  675. if (!current_drag_data_) {
  676. drag_data = CefDragData::Create();
  677. [self populateDropData:drag_data fromPasteboard:[info draggingPasteboard]];
  678. } else {
  679. drag_data = current_drag_data_->Clone();
  680. drag_data->ResetFileContents();
  681. }
  682. CefMouseEvent mouseEvent;
  683. [self getMouseEvent:mouseEvent forDragInfo:info];
  684. NSDragOperation mask = [info draggingSourceOperationMask];
  685. CefBrowserHost::DragOperationsMask allowed_ops =
  686. static_cast<CefBrowserHost::DragOperationsMask>(mask);
  687. browser->GetHost()->DragTargetDragEnter(drag_data, mouseEvent, allowed_ops);
  688. browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
  689. current_drag_op_ = NSDragOperationCopy;
  690. return current_drag_op_;
  691. }
  692. - (void)draggingExited:(id<NSDraggingInfo>)sender {
  693. CefRefPtr<CefBrowser> browser = [self getBrowser];
  694. if (browser.get())
  695. browser->GetHost()->DragTargetDragLeave();
  696. }
  697. - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
  698. return YES;
  699. }
  700. - (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
  701. CefRefPtr<CefBrowser> browser = [self getBrowser];
  702. if (!browser.get())
  703. return NO;
  704. CefMouseEvent mouseEvent;
  705. [self getMouseEvent:mouseEvent forDragInfo:info];
  706. browser->GetHost()->DragTargetDrop(mouseEvent);
  707. return YES;
  708. }
  709. - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
  710. CefRefPtr<CefBrowser> browser = [self getBrowser];
  711. if (!browser.get())
  712. return NSDragOperationNone;
  713. CefMouseEvent mouseEvent;
  714. [self getMouseEvent:mouseEvent forDragInfo:info];
  715. NSDragOperation mask = [info draggingSourceOperationMask];
  716. CefBrowserHost::DragOperationsMask allowed_ops =
  717. static_cast<CefBrowserHost::DragOperationsMask>(mask);
  718. browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
  719. return current_drag_op_;
  720. }
  721. // NSPasteboardOwner Protocol
  722. - (void)pasteboard:(NSPasteboard*)pboard provideDataForType:(NSString*)type {
  723. if (!current_drag_data_) {
  724. return;
  725. }
  726. // URL.
  727. if ([type isEqualToString:NSURLPboardType]) {
  728. DCHECK(current_drag_data_->IsLink());
  729. NSString* strUrl =
  730. [NSString stringWithUTF8String:current_drag_data_->GetLinkURL()
  731. .ToString()
  732. .c_str()];
  733. NSURL* url = [NSURL URLWithString:strUrl];
  734. [url writeToPasteboard:pboard];
  735. // URL title.
  736. } else if ([type isEqualToString:kNSURLTitlePboardType]) {
  737. NSString* strTitle =
  738. [NSString stringWithUTF8String:current_drag_data_->GetLinkTitle()
  739. .ToString()
  740. .c_str()];
  741. [pboard setString:strTitle forType:kNSURLTitlePboardType];
  742. // File contents.
  743. } else if ([type isEqualToString:(NSString*)fileUTI_]) {
  744. size_t size = current_drag_data_->GetFileContents(NULL);
  745. DCHECK_GT(size, 0U);
  746. CefRefPtr<client::BytesWriteHandler> handler =
  747. new client::BytesWriteHandler(size);
  748. CefRefPtr<CefStreamWriter> writer =
  749. CefStreamWriter::CreateForHandler(handler.get());
  750. current_drag_data_->GetFileContents(writer);
  751. DCHECK_EQ(handler->GetDataSize(), static_cast<int64>(size));
  752. [pboard setData:[NSData dataWithBytes:handler->GetData()
  753. length:handler->GetDataSize()]
  754. forType:(NSString*)fileUTI_];
  755. // Plain text.
  756. } else if ([type isEqualToString:NSStringPboardType]) {
  757. NSString* strTitle =
  758. [NSString stringWithUTF8String:current_drag_data_->GetFragmentText()
  759. .ToString()
  760. .c_str()];
  761. [pboard setString:strTitle forType:NSStringPboardType];
  762. } else if ([type isEqualToString:kCEFDragDummyPboardType]) {
  763. // The dummy type _was_ promised and someone decided to call the bluff.
  764. [pboard setData:[NSData data] forType:kCEFDragDummyPboardType];
  765. }
  766. }
  767. // NSAccessibility Protocol implementation.
  768. - (BOOL)accessibilityIsIgnored {
  769. if (!accessibility_helper_)
  770. return YES;
  771. else
  772. return NO;
  773. }
  774. - (id)accessibilityAttributeValue:(NSString*)attribute {
  775. if (!accessibility_helper_)
  776. return [super accessibilityAttributeValue:attribute];
  777. if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
  778. return NSAccessibilityGroupRole;
  779. } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
  780. client::OsrAXNode* node = accessibility_helper_->GetRootNode();
  781. std::string desc = node ? node->AxDescription() : "";
  782. return [NSString stringWithUTF8String:desc.c_str()];
  783. } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
  784. client::OsrAXNode* node = accessibility_helper_->GetRootNode();
  785. std::string desc = node ? node->AxValue() : "";
  786. return [NSString stringWithUTF8String:desc.c_str()];
  787. } else if ([attribute
  788. isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
  789. return NSAccessibilityRoleDescriptionForUIElement(self);
  790. } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
  791. client::OsrAXNode* node = accessibility_helper_->GetRootNode();
  792. // Add Root as first Kid
  793. NSMutableArray* kids = [NSMutableArray arrayWithCapacity:1];
  794. NSObject* child = node->GetNativeAccessibleObject(NULL);
  795. [kids addObject:child];
  796. return NSAccessibilityUnignoredChildren(kids);
  797. } else {
  798. return [super accessibilityAttributeValue:attribute];
  799. }
  800. }
  801. - (id)accessibilityFocusedUIElement {
  802. if (accessibility_helper_) {
  803. client::OsrAXNode* node = accessibility_helper_->GetFocusedNode();
  804. return node ? node->GetNativeAccessibleObject(NULL) : nil;
  805. }
  806. return nil;
  807. }
  808. // Utility methods.
  809. - (void)resetDragDrop {
  810. current_drag_op_ = NSDragOperationNone;
  811. current_allowed_ops_ = NSDragOperationNone;
  812. current_drag_data_ = NULL;
  813. if (fileUTI_) {
  814. CFRelease(fileUTI_);
  815. fileUTI_ = NULL;
  816. }
  817. if (pasteboard_) {
  818. [pasteboard_ release];
  819. pasteboard_ = nil;
  820. }
  821. }
  822. - (void)fillPasteboard {
  823. DCHECK(!pasteboard_);
  824. pasteboard_ = [[NSPasteboard pasteboardWithName:NSDragPboard] retain];
  825. [pasteboard_ declareTypes:@[ kCEFDragDummyPboardType ] owner:self];
  826. // URL (and title).
  827. if (current_drag_data_->IsLink()) {
  828. [pasteboard_ addTypes:@[ NSURLPboardType, kNSURLTitlePboardType ]
  829. owner:self];
  830. }
  831. // MIME type.
  832. CefString mimeType;
  833. size_t contents_size = current_drag_data_->GetFileContents(NULL);
  834. CefString download_metadata = current_drag_data_->GetLinkMetadata();
  835. CefString file_name = current_drag_data_->GetFileName();
  836. // File.
  837. if (contents_size > 0) {
  838. std::string file_name = current_drag_data_->GetFileName().ToString();
  839. size_t sep = file_name.find_last_of(".");
  840. CefString extension = file_name.substr(sep + 1);
  841. mimeType = CefGetMimeType(extension);
  842. if (!mimeType.empty()) {
  843. CFStringRef mimeTypeCF;
  844. mimeTypeCF = CFStringCreateWithCString(kCFAllocatorDefault,
  845. mimeType.ToString().c_str(),
  846. kCFStringEncodingUTF8);
  847. fileUTI_ = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
  848. mimeTypeCF, NULL);
  849. CFRelease(mimeTypeCF);
  850. // File (HFS) promise.
  851. NSArray* fileUTIList = @[ (NSString*)fileUTI_ ];
  852. [pasteboard_ addTypes:@[ NSFilesPromisePboardType ] owner:self];
  853. [pasteboard_ setPropertyList:fileUTIList
  854. forType:NSFilesPromisePboardType];
  855. [pasteboard_ addTypes:fileUTIList owner:self];
  856. }
  857. }
  858. // Plain text.
  859. if (!current_drag_data_->GetFragmentText().empty()) {
  860. [pasteboard_ addTypes:@[ NSStringPboardType ] owner:self];
  861. }
  862. }
  863. - (void)populateDropData:(CefRefPtr<CefDragData>)data
  864. fromPasteboard:(NSPasteboard*)pboard {
  865. DCHECK(data);
  866. DCHECK(pboard);
  867. DCHECK(data && !data->IsReadOnly());
  868. NSArray* types = [pboard types];
  869. // Get plain text.
  870. if ([types containsObject:NSStringPboardType]) {
  871. data->SetFragmentText(
  872. [[pboard stringForType:NSStringPboardType] UTF8String]);
  873. }
  874. // Get files.
  875. if ([types containsObject:NSFilenamesPboardType]) {
  876. NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
  877. if ([files isKindOfClass:[NSArray class]] && [files count]) {
  878. for (NSUInteger i = 0; i < [files count]; i++) {
  879. NSString* filename = [files objectAtIndex:i];
  880. BOOL exists =
  881. [[NSFileManager defaultManager] fileExistsAtPath:filename];
  882. if (exists) {
  883. data->AddFile([filename UTF8String], CefString());
  884. }
  885. }
  886. }
  887. }
  888. }
  889. - (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint {
  890. NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
  891. NSRect viewFrame = [self frame];
  892. viewPoint.y = viewFrame.size.height - viewPoint.y;
  893. return viewPoint;
  894. }
  895. - (void)resetDeviceScaleFactor {
  896. float device_scale_factor = 1.0f;
  897. NSWindow* window = [self window];
  898. if (window)
  899. device_scale_factor = [window backingScaleFactor];
  900. [self setDeviceScaleFactor:device_scale_factor];
  901. }
  902. - (void)setDeviceScaleFactor:(float)device_scale_factor {
  903. if (device_scale_factor == device_scale_factor_)
  904. return;
  905. // Apply some sanity checks.
  906. if (device_scale_factor < 1.0f || device_scale_factor > 4.0f)
  907. return;
  908. device_scale_factor_ = device_scale_factor;
  909. CefRefPtr<CefBrowser> browser = [self getBrowser];
  910. if (browser) {
  911. browser->GetHost()->NotifyScreenInfoChanged();
  912. browser->GetHost()->WasResized();
  913. }
  914. }
  915. - (float)getDeviceScaleFactor {
  916. return device_scale_factor_;
  917. }
  918. - (void)viewDidChangeBackingProperties {
  919. const CGFloat device_scale_factor = [self getDeviceScaleFactor];
  920. if (device_scale_factor == device_scale_factor_)
  921. return;
  922. CefRefPtr<CefBrowser> browser = [self getBrowser];
  923. if (browser) {
  924. browser->GetHost()->NotifyScreenInfoChanged();
  925. browser->GetHost()->WasResized();
  926. }
  927. }
  928. - (bool)isOverPopupWidgetX:(int)x andY:(int)y {
  929. CefRect rc = renderer_->popup_rect();
  930. int popup_right = rc.x + rc.width;
  931. int popup_bottom = rc.y + rc.height;
  932. return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
  933. }
  934. - (int)getPopupXOffset {
  935. return renderer_->original_popup_rect().x - renderer_->popup_rect().x;
  936. }
  937. - (int)getPopupYOffset {
  938. return renderer_->original_popup_rect().y - renderer_->popup_rect().y;
  939. }
  940. - (void)applyPopupOffsetToX:(int&)x andY:(int&)y {
  941. if ([self isOverPopupWidgetX:x andY:y]) {
  942. x += [self getPopupXOffset];
  943. y += [self getPopupYOffset];
  944. }
  945. }
  946. // Convert from scaled coordinates to view coordinates.
  947. - (NSPoint)convertPointFromBackingInternal:(NSPoint)aPoint {
  948. return [self convertPointFromBacking:aPoint];
  949. }
  950. // Convert from view coordinates to scaled coordinates.
  951. - (NSPoint)convertPointToBackingInternal:(NSPoint)aPoint {
  952. return [self convertPointToBacking:aPoint];
  953. }
  954. // Convert from scaled coordinates to view coordinates.
  955. - (NSRect)convertRectFromBackingInternal:(NSRect)aRect {
  956. return [self convertRectFromBacking:aRect];
  957. }
  958. // Convert from view coordinates to scaled coordinates.
  959. - (NSRect)convertRectToBackingInternal:(NSRect)aRect {
  960. return [self convertRectToBacking:aRect];
  961. }
  962. - (void)ChangeCompositionRange:(CefRange)range
  963. character_bounds:(const CefRenderHandler::RectList&)bounds {
  964. CefTextInputClientOSRMac* client =
  965. GetInputClientFromContext(text_input_context_osr_mac_);
  966. if (client)
  967. [client ChangeCompositionRange:range character_bounds:bounds];
  968. }
  969. - (void)UpdateAccessibilityTree:(CefRefPtr<CefValue>)value {
  970. if (!accessibility_helper_) {
  971. accessibility_helper_ =
  972. new client::OsrAccessibilityHelper(value, [self getBrowser]);
  973. } else {
  974. accessibility_helper_->UpdateAccessibilityTree(value);
  975. }
  976. if (accessibility_helper_) {
  977. NSAccessibilityPostNotification(self,
  978. NSAccessibilityValueChangedNotification);
  979. }
  980. return;
  981. }
  982. @end
  983. namespace client {
  984. BrowserWindowOsrMac::BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
  985. const std::string& startup_url,
  986. const OsrRenderer::Settings& settings)
  987. : BrowserWindow(delegate),
  988. renderer_(settings),
  989. nsview_(NULL),
  990. hidden_(false),
  991. painting_popup_(false) {
  992. client_handler_ = new ClientHandlerOsr(this, this, startup_url);
  993. }
  994. BrowserWindowOsrMac::~BrowserWindowOsrMac() {
  995. if (nsview_) {
  996. // Disassociate the view with |this|.
  997. [GLView(nsview_) detach];
  998. }
  999. }
  1000. void BrowserWindowOsrMac::CreateBrowser(
  1001. ClientWindowHandle parent_handle,
  1002. const CefRect& rect,
  1003. const CefBrowserSettings& settings,
  1004. CefRefPtr<CefRequestContext> request_context) {
  1005. REQUIRE_MAIN_THREAD();
  1006. // Create the native NSView.
  1007. Create(parent_handle, rect);
  1008. CefWindowInfo window_info;
  1009. window_info.SetAsWindowless(nsview_);
  1010. // Create the browser asynchronously.
  1011. CefBrowserHost::CreateBrowser(window_info, client_handler_,
  1012. client_handler_->startup_url(), settings,
  1013. request_context);
  1014. }
  1015. void BrowserWindowOsrMac::GetPopupConfig(CefWindowHandle temp_handle,
  1016. CefWindowInfo& windowInfo,
  1017. CefRefPtr<CefClient>& client,
  1018. CefBrowserSettings& settings) {
  1019. CEF_REQUIRE_UI_THREAD();
  1020. windowInfo.SetAsWindowless(temp_handle);
  1021. client = client_handler_;
  1022. }
  1023. void BrowserWindowOsrMac::ShowPopup(ClientWindowHandle parent_handle,
  1024. int x,
  1025. int y,
  1026. size_t width,
  1027. size_t height) {
  1028. REQUIRE_MAIN_THREAD();
  1029. DCHECK(browser_.get());
  1030. // Create the native NSView.
  1031. Create(parent_handle,
  1032. CefRect(x, y, static_cast<int>(width), static_cast<int>(height)));
  1033. // Send resize notification so the compositor is assigned the correct
  1034. // viewport size and begins rendering.
  1035. browser_->GetHost()->WasResized();
  1036. Show();
  1037. }
  1038. void BrowserWindowOsrMac::Show() {
  1039. REQUIRE_MAIN_THREAD();
  1040. if (hidden_) {
  1041. // Set the browser as visible.
  1042. browser_->GetHost()->WasHidden(false);
  1043. hidden_ = false;
  1044. }
  1045. // Give focus to the browser.
  1046. browser_->GetHost()->SendFocusEvent(true);
  1047. }
  1048. void BrowserWindowOsrMac::Hide() {
  1049. REQUIRE_MAIN_THREAD();
  1050. if (!browser_.get())
  1051. return;
  1052. // Remove focus from the browser.
  1053. browser_->GetHost()->SendFocusEvent(false);
  1054. if (!hidden_) {
  1055. // Set the browser as hidden.
  1056. browser_->GetHost()->WasHidden(true);
  1057. hidden_ = true;
  1058. }
  1059. }
  1060. void BrowserWindowOsrMac::SetBounds(int x, int y, size_t width, size_t height) {
  1061. REQUIRE_MAIN_THREAD();
  1062. // Nothing to do here. GTK will take care of positioning in the container.
  1063. }
  1064. void BrowserWindowOsrMac::SetFocus(bool focus) {
  1065. REQUIRE_MAIN_THREAD();
  1066. if (nsview_)
  1067. [[nsview_ window] makeFirstResponder:nsview_];
  1068. }
  1069. void BrowserWindowOsrMac::SetDeviceScaleFactor(float device_scale_factor) {
  1070. REQUIRE_MAIN_THREAD();
  1071. if (nsview_)
  1072. [GLView(nsview_) setDeviceScaleFactor:device_scale_factor];
  1073. }
  1074. float BrowserWindowOsrMac::GetDeviceScaleFactor() const {
  1075. REQUIRE_MAIN_THREAD();
  1076. if (nsview_)
  1077. return [GLView(nsview_) getDeviceScaleFactor];
  1078. return 1.0f;
  1079. }
  1080. ClientWindowHandle BrowserWindowOsrMac::GetWindowHandle() const {
  1081. REQUIRE_MAIN_THREAD();
  1082. return nsview_;
  1083. }
  1084. void BrowserWindowOsrMac::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  1085. CEF_REQUIRE_UI_THREAD();
  1086. }
  1087. void BrowserWindowOsrMac::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  1088. CEF_REQUIRE_UI_THREAD();
  1089. REQUIRE_MAIN_THREAD();
  1090. // Detach |this| from the ClientHandlerOsr.
  1091. static_cast<ClientHandlerOsr*>(client_handler_.get())->DetachOsrDelegate();
  1092. }
  1093. bool BrowserWindowOsrMac::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
  1094. CefRect& rect) {
  1095. CEF_REQUIRE_UI_THREAD();
  1096. return false;
  1097. }
  1098. bool BrowserWindowOsrMac::GetViewRect(CefRefPtr<CefBrowser> browser,
  1099. CefRect& rect) {
  1100. CEF_REQUIRE_UI_THREAD();
  1101. REQUIRE_MAIN_THREAD();
  1102. if (!nsview_)
  1103. return false;
  1104. const float device_scale_factor = [GLView(nsview_) getDeviceScaleFactor];
  1105. // |bounds| is in OS X view coordinates.
  1106. NSRect bounds = [nsview_ bounds];
  1107. // Convert to device coordinates.
  1108. bounds = [GLView(nsview_) convertRectToBackingInternal:bounds];
  1109. // Convert to browser view coordinates.
  1110. rect.x = rect.y = 0;
  1111. rect.width = DeviceToLogical(bounds.size.width, device_scale_factor);
  1112. rect.height = DeviceToLogical(bounds.size.height, device_scale_factor);
  1113. return true;
  1114. }
  1115. bool BrowserWindowOsrMac::GetScreenPoint(CefRefPtr<CefBrowser> browser,
  1116. int viewX,
  1117. int viewY,
  1118. int& screenX,
  1119. int& screenY) {
  1120. CEF_REQUIRE_UI_THREAD();
  1121. REQUIRE_MAIN_THREAD();
  1122. if (!nsview_)
  1123. return false;
  1124. const float device_scale_factor = [GLView(nsview_) getDeviceScaleFactor];
  1125. // (viewX, viewX) is in browser view coordinates.
  1126. // Convert to device coordinates.
  1127. NSPoint view_pt = NSMakePoint(LogicalToDevice(viewX, device_scale_factor),
  1128. LogicalToDevice(viewY, device_scale_factor));
  1129. // Convert to OS X view coordinates.
  1130. view_pt = [GLView(nsview_) convertPointFromBackingInternal:view_pt];
  1131. // Reverse the Y component.
  1132. const NSRect bounds = [nsview_ bounds];
  1133. view_pt.y = bounds.size.height - view_pt.y;
  1134. // Convert to screen coordinates.
  1135. NSPoint window_pt = [nsview_ convertPoint:view_pt toView:nil];
  1136. NSPoint screen_pt =
  1137. ConvertPointFromWindowToScreen([nsview_ window], window_pt);
  1138. screenX = screen_pt.x;
  1139. screenY = screen_pt.y;
  1140. return true;
  1141. }
  1142. bool BrowserWindowOsrMac::GetScreenInfo(CefRefPtr<CefBrowser> browser,
  1143. CefScreenInfo& screen_info) {
  1144. CEF_REQUIRE_UI_THREAD();
  1145. REQUIRE_MAIN_THREAD();
  1146. if (!nsview_)
  1147. return false;
  1148. CefRect view_rect;
  1149. GetViewRect(browser, view_rect);
  1150. screen_info.device_scale_factor = [GLView(nsview_) getDeviceScaleFactor];
  1151. // The screen info rectangles are used by the renderer to create and position
  1152. // popups. Keep popups inside the view rectangle.
  1153. screen_info.rect = view_rect;
  1154. screen_info.available_rect = view_rect;
  1155. return true;
  1156. }
  1157. void BrowserWindowOsrMac::OnPopupShow(CefRefPtr<CefBrowser> browser,
  1158. bool show) {
  1159. CEF_REQUIRE_UI_THREAD();
  1160. REQUIRE_MAIN_THREAD();
  1161. if (!nsview_)
  1162. return;
  1163. if (!show) {
  1164. renderer_.ClearPopupRects();
  1165. browser->GetHost()->Invalidate(PET_VIEW);
  1166. }
  1167. renderer_.OnPopupShow(browser, show);
  1168. }
  1169. void BrowserWindowOsrMac::OnPopupSize(CefRefPtr<CefBrowser> browser,
  1170. const CefRect& rect) {
  1171. CEF_REQUIRE_UI_THREAD();
  1172. REQUIRE_MAIN_THREAD();
  1173. if (!nsview_)
  1174. return;
  1175. const float device_scale_factor = [GLView(nsview_) getDeviceScaleFactor];
  1176. // |rect| is in browser view coordinates. Convert to device coordinates.
  1177. CefRect device_rect = LogicalToDevice(rect, device_scale_factor);
  1178. renderer_.OnPopupSize(browser, device_rect);
  1179. }
  1180. void BrowserWindowOsrMac::OnPaint(CefRefPtr<CefBrowser> browser,
  1181. CefRenderHandler::PaintElementType type,
  1182. const CefRenderHandler::RectList& dirtyRects,
  1183. const void* buffer,
  1184. int width,
  1185. int height) {
  1186. CEF_REQUIRE_UI_THREAD();
  1187. REQUIRE_MAIN_THREAD();
  1188. if (!nsview_)
  1189. return;
  1190. if (width <= 2 && height <= 2) {
  1191. // Ignore really small buffer sizes while the widget is starting up.
  1192. return;
  1193. }
  1194. if (painting_popup_) {
  1195. renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
  1196. return;
  1197. }
  1198. ScopedGLContext scoped_gl_context(GLView(nsview_), true);
  1199. renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
  1200. if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
  1201. painting_popup_ = true;
  1202. browser->GetHost()->Invalidate(PET_POPUP);
  1203. painting_popup_ = false;
  1204. }
  1205. renderer_.Render();
  1206. }
  1207. void BrowserWindowOsrMac::OnCursorChange(
  1208. CefRefPtr<CefBrowser> browser,
  1209. CefCursorHandle cursor,
  1210. CefRenderHandler::CursorType type,
  1211. const CefCursorInfo& custom_cursor_info) {
  1212. CEF_REQUIRE_UI_THREAD();
  1213. REQUIRE_MAIN_THREAD();
  1214. [cursor set];
  1215. }
  1216. bool BrowserWindowOsrMac::StartDragging(
  1217. CefRefPtr<CefBrowser> browser,
  1218. CefRefPtr<CefDragData> drag_data,
  1219. CefRenderHandler::DragOperationsMask allowed_ops,
  1220. int x,
  1221. int y) {
  1222. CEF_REQUIRE_UI_THREAD();
  1223. REQUIRE_MAIN_THREAD();
  1224. if (!nsview_)
  1225. return false;
  1226. static float device_scale_factor = [GLView(nsview_) getDeviceScaleFactor];
  1227. // |point| is in browser view coordinates.
  1228. NSPoint point = NSMakePoint(x, y);
  1229. // Convert to device coordinates.
  1230. point.x = LogicalToDevice(point.x, device_scale_factor);
  1231. point.y = LogicalToDevice(point.y, device_scale_factor);
  1232. // Convert to OS X view coordinates.
  1233. point = [GLView(nsview_) convertPointFromBackingInternal:point];
  1234. return
  1235. [GLView(nsview_) startDragging:drag_data
  1236. allowedOps:static_cast<NSDragOperation>(allowed_ops)
  1237. point:point];
  1238. }
  1239. void BrowserWindowOsrMac::UpdateDragCursor(
  1240. CefRefPtr<CefBrowser> browser,
  1241. CefRenderHandler::DragOperation operation) {
  1242. CEF_REQUIRE_UI_THREAD();
  1243. REQUIRE_MAIN_THREAD();
  1244. if (nsview_)
  1245. [GLView(nsview_) setCurrentDragOp:operation];
  1246. }
  1247. void BrowserWindowOsrMac::OnImeCompositionRangeChanged(
  1248. CefRefPtr<CefBrowser> browser,
  1249. const CefRange& selection_range,
  1250. const CefRenderHandler::RectList& bounds) {
  1251. CEF_REQUIRE_UI_THREAD();
  1252. if (nsview_) {
  1253. [GLView(nsview_) ChangeCompositionRange:selection_range
  1254. character_bounds:bounds];
  1255. }
  1256. }
  1257. void BrowserWindowOsrMac::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
  1258. CEF_REQUIRE_UI_THREAD();
  1259. if (nsview_) {
  1260. [GLView(nsview_) UpdateAccessibilityTree:value];
  1261. }
  1262. }
  1263. void BrowserWindowOsrMac::Create(ClientWindowHandle parent_handle,
  1264. const CefRect& rect) {
  1265. REQUIRE_MAIN_THREAD();
  1266. DCHECK(!nsview_);
  1267. NSRect window_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height);
  1268. nsview_ = [[BrowserOpenGLView alloc] initWithFrame:window_rect
  1269. andBrowserWindow:this
  1270. andRenderer:&renderer_];
  1271. [nsview_ setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
  1272. [nsview_ setAutoresizesSubviews:true];
  1273. [parent_handle addSubview:nsview_];
  1274. // Determine the default scale factor.
  1275. [GLView(nsview_) resetDeviceScaleFactor];
  1276. [[NSNotificationCenter defaultCenter]
  1277. addObserver:nsview_
  1278. selector:@selector(windowDidChangeBackingProperties:)
  1279. name:NSWindowDidChangeBackingPropertiesNotification
  1280. object:[nsview_ window]];
  1281. }
  1282. } // namespace client