mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2024-12-15 19:09:00 +01:00
019611c764
Under ARC (Automatic Reference Counting), assigning to an Objective-C pointer has different semantics than assigning to a void* pointer. This makes it dangerous to treat the same memory address as an Objective-C pointer in some cases and as a "regular C pointer" in other cases. This change removes the conditional type defines and instead uses void* everywhere. Explicit type casting in combination with ARC annotations makes it safe to get typed Objective-C pointers from the void* pointers. This change enables ARC by default in the CEF binary distribution CMake configuration for the cefclient and cefsimple sample applications. It can be disabled by adding `-DOPTION_USE_ARC=Off` to the CMake command line. ARC is not supported when building Chromium due to the substantial number of changes that would be required in the Chromium code base.
1914 lines
58 KiB
Plaintext
1914 lines
58 KiB
Plaintext
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
|
// reserved. Use of this source code is governed by a BSD-style license that
|
|
// can be found in the LICENSE file.
|
|
|
|
#include "tests/cefclient/browser/browser_window_osr_mac.h"
|
|
|
|
#include <Cocoa/Cocoa.h>
|
|
#include <OpenGL/gl.h>
|
|
#import <objc/runtime.h>
|
|
|
|
#include "include/base/cef_logging.h"
|
|
#include "include/cef_parser.h"
|
|
#include "include/wrapper/cef_closure_task.h"
|
|
#include "tests/cefclient/browser/bytes_write_handler.h"
|
|
#include "tests/cefclient/browser/main_context.h"
|
|
#include "tests/cefclient/browser/osr_accessibility_helper.h"
|
|
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
|
#include "tests/cefclient/browser/text_input_client_osr_mac.h"
|
|
#include "tests/shared/browser/geometry_util.h"
|
|
#include "tests/shared/browser/main_message_loop.h"
|
|
|
|
#import <AppKit/NSAccessibility.h>
|
|
|
|
@interface BrowserOpenGLView
|
|
: NSOpenGLView <NSDraggingSource, NSDraggingDestination, NSAccessibility> {
|
|
@private
|
|
NSTrackingArea* tracking_area_;
|
|
client::BrowserWindowOsrMac* browser_window_;
|
|
client::OsrRenderer* renderer_;
|
|
NSPoint last_mouse_pos_;
|
|
NSPoint cur_mouse_pos_;
|
|
bool rotating_;
|
|
|
|
bool was_last_mouse_down_on_view_;
|
|
|
|
float device_scale_factor_;
|
|
|
|
// Drag and drop.
|
|
CefRefPtr<CefDragData> current_drag_data_;
|
|
NSDragOperation current_drag_op_;
|
|
NSDragOperation current_allowed_ops_;
|
|
NSPasteboard* pasteboard_;
|
|
NSString* fileUTI_;
|
|
|
|
// For intreacting with IME.
|
|
NSTextInputContext* text_input_context_osr_mac_;
|
|
CefTextInputClientOSRMac* text_input_client_;
|
|
|
|
// Manages Accessibility Tree
|
|
client::OsrAccessibilityHelper* accessibility_helper_;
|
|
|
|
// Event monitor for scroll wheel end event.
|
|
id endWheelMonitor_;
|
|
}
|
|
|
|
@end // @interface BrowserOpenGLView
|
|
|
|
namespace {
|
|
|
|
NSString* const kCEFDragDummyPboardType = @"org.CEF.drag-dummy-type";
|
|
NSString* const kNSURLTitlePboardType = @"public.url-name";
|
|
|
|
class ScopedGLContext {
|
|
public:
|
|
ScopedGLContext(BrowserOpenGLView* view, bool swap_buffers)
|
|
: swap_buffers_(swap_buffers) {
|
|
context_ = [view openGLContext];
|
|
[context_ makeCurrentContext];
|
|
}
|
|
~ScopedGLContext() {
|
|
[NSOpenGLContext clearCurrentContext];
|
|
if (swap_buffers_)
|
|
[context_ flushBuffer];
|
|
}
|
|
|
|
private:
|
|
NSOpenGLContext* context_;
|
|
const bool swap_buffers_;
|
|
};
|
|
|
|
NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
|
|
NSRect point_rect = NSMakeRect(point.x, point.y, 0, 0);
|
|
return [window convertRectToScreen:point_rect].origin;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
@implementation BrowserOpenGLView
|
|
|
|
- (id)initWithFrame:(NSRect)frame
|
|
andBrowserWindow:(client::BrowserWindowOsrMac*)browser_window
|
|
andRenderer:(client::OsrRenderer*)renderer {
|
|
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc]
|
|
initWithAttributes:(NSOpenGLPixelFormatAttribute[]){
|
|
NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 32,
|
|
0}];
|
|
#if !__has_feature(objc_arc)
|
|
[pixelFormat autorelease];
|
|
#endif // !__has_feature(objc_arc)
|
|
|
|
if (self = [super initWithFrame:frame pixelFormat:pixelFormat]) {
|
|
browser_window_ = browser_window;
|
|
renderer_ = renderer;
|
|
rotating_ = false;
|
|
endWheelMonitor_ = nil;
|
|
device_scale_factor_ = 1.0f;
|
|
|
|
tracking_area_ = [[NSTrackingArea alloc]
|
|
initWithRect:frame
|
|
options:NSTrackingMouseMoved | NSTrackingActiveInActiveApp |
|
|
NSTrackingInVisibleRect
|
|
owner:self
|
|
userInfo:nil];
|
|
[self addTrackingArea:tracking_area_];
|
|
|
|
// enable HiDPI buffer
|
|
[self setWantsBestResolutionOpenGLSurface:YES];
|
|
|
|
[self resetDragDrop];
|
|
|
|
NSArray* types = [NSArray
|
|
arrayWithObjects:kCEFDragDummyPboardType, NSStringPboardType,
|
|
NSFilenamesPboardType, NSPasteboardTypeString, nil];
|
|
[self registerForDraggedTypes:types];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[[NSNotificationCenter defaultCenter]
|
|
removeObserver:self
|
|
name:NSWindowDidChangeBackingPropertiesNotification
|
|
object:nil];
|
|
#if !__has_feature(objc_arc)
|
|
if (text_input_context_osr_mac_) {
|
|
[text_input_client_ release];
|
|
[text_input_context_osr_mac_ release];
|
|
}
|
|
[super dealloc];
|
|
#endif // !__has_feature(objc_arc)
|
|
}
|
|
|
|
- (void)detach {
|
|
renderer_ = NULL;
|
|
browser_window_ = NULL;
|
|
if (text_input_client_)
|
|
[text_input_client_ detach];
|
|
}
|
|
|
|
- (CefRefPtr<CefBrowser>)getBrowser {
|
|
if (browser_window_)
|
|
return browser_window_->GetBrowser();
|
|
return NULL;
|
|
}
|
|
|
|
- (void)setFrame:(NSRect)frameRect {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
[super setFrame:frameRect];
|
|
browser->GetHost()->WasResized();
|
|
}
|
|
|
|
- (void)sendMouseClick:(NSEvent*)event
|
|
button:(CefBrowserHost::MouseButtonType)type
|
|
isUp:(bool)isUp {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forEvent:event];
|
|
|
|
// |point| is in OS X view coordinates.
|
|
NSPoint point = [self getClickPointForEvent:event];
|
|
|
|
// Convert to device coordinates.
|
|
point = [self convertPointToBackingInternal:point];
|
|
|
|
if (!isUp) {
|
|
was_last_mouse_down_on_view_ = ![self isOverPopupWidgetX:point.x
|
|
andY:point.y];
|
|
} else if (was_last_mouse_down_on_view_ &&
|
|
[self isOverPopupWidgetX:point.x andY:point.y] &&
|
|
([self getPopupXOffset] || [self getPopupYOffset])) {
|
|
return;
|
|
}
|
|
|
|
browser->GetHost()->SendMouseClickEvent(mouseEvent, type, isUp,
|
|
[event clickCount]);
|
|
}
|
|
|
|
- (void)mouseDown:(NSEvent*)event {
|
|
[self sendMouseClick:event button:MBT_LEFT isUp:false];
|
|
}
|
|
|
|
- (void)rightMouseDown:(NSEvent*)event {
|
|
if ([event modifierFlags] & NSShiftKeyMask) {
|
|
// Start rotation effect.
|
|
last_mouse_pos_ = cur_mouse_pos_ = [self getClickPointForEvent:event];
|
|
rotating_ = true;
|
|
return;
|
|
}
|
|
|
|
[self sendMouseClick:event button:MBT_RIGHT isUp:false];
|
|
}
|
|
|
|
- (void)otherMouseDown:(NSEvent*)event {
|
|
[self sendMouseClick:event button:MBT_MIDDLE isUp:false];
|
|
}
|
|
|
|
- (void)mouseUp:(NSEvent*)event {
|
|
[self sendMouseClick:event button:MBT_LEFT isUp:true];
|
|
}
|
|
|
|
- (void)rightMouseUp:(NSEvent*)event {
|
|
if (rotating_) {
|
|
// End rotation effect.
|
|
renderer_->SetSpin(0, 0);
|
|
rotating_ = false;
|
|
[self setNeedsDisplay:YES];
|
|
return;
|
|
}
|
|
[self sendMouseClick:event button:MBT_RIGHT isUp:true];
|
|
}
|
|
|
|
- (void)otherMouseUp:(NSEvent*)event {
|
|
[self sendMouseClick:event button:MBT_MIDDLE isUp:true];
|
|
}
|
|
|
|
- (void)mouseMoved:(NSEvent*)event {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
if (rotating_) {
|
|
// Apply rotation effect.
|
|
cur_mouse_pos_ = [self getClickPointForEvent:event];
|
|
;
|
|
renderer_->IncrementSpin((cur_mouse_pos_.x - last_mouse_pos_.x),
|
|
(cur_mouse_pos_.y - last_mouse_pos_.y));
|
|
last_mouse_pos_ = cur_mouse_pos_;
|
|
[self setNeedsDisplay:YES];
|
|
return;
|
|
}
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forEvent:event];
|
|
|
|
browser->GetHost()->SendMouseMoveEvent(mouseEvent, false);
|
|
}
|
|
|
|
- (void)mouseDragged:(NSEvent*)event {
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)rightMouseDragged:(NSEvent*)event {
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)otherMouseDragged:(NSEvent*)event {
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)mouseEntered:(NSEvent*)event {
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)mouseExited:(NSEvent*)event {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forEvent:event];
|
|
|
|
browser->GetHost()->SendMouseMoveEvent(mouseEvent, true);
|
|
}
|
|
|
|
- (void)keyDown:(NSEvent*)event {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get() || !text_input_context_osr_mac_)
|
|
return;
|
|
|
|
if ([event type] != NSFlagsChanged) {
|
|
if (text_input_client_) {
|
|
[text_input_client_ HandleKeyEventBeforeTextInputClient:event];
|
|
|
|
// The return value of this method seems to always be set to YES, thus we
|
|
// ignore it and ask the host view whether IME is active or not.
|
|
[text_input_context_osr_mac_ handleEvent:event];
|
|
|
|
CefKeyEvent keyEvent;
|
|
[self getKeyEvent:keyEvent forEvent:event];
|
|
|
|
[text_input_client_ HandleKeyEventAfterTextInputClient:keyEvent];
|
|
}
|
|
}
|
|
|
|
// Check for Caps lock and Toggle Touch Emulation
|
|
if (client::MainContext::Get()->TouchEventsEnabled())
|
|
[self toggleTouchEmulation:event];
|
|
}
|
|
|
|
// OSX does not have touch screens, so we emulate it by mapping multitouch
|
|
// events on TrackPad to Touch Events on Screen. To ensure it does not
|
|
// interfere with other Trackpad events, this mapping is only enabled if
|
|
// touch-events=enabled commandline is passed and caps lock key is on.
|
|
- (void)toggleTouchEmulation:(NSEvent*)event {
|
|
if ([event type] == NSFlagsChanged && [event keyCode] == 0x39) {
|
|
NSUInteger flags = [event modifierFlags];
|
|
BOOL touch_enabled = flags & NSAlphaShiftKeyMask ? YES : NO;
|
|
[self setAcceptsTouchEvents:touch_enabled];
|
|
}
|
|
}
|
|
|
|
- (cef_touch_event_type_t)getTouchPhase:(NSTouchPhase)phase {
|
|
cef_touch_event_type_t event_type = CEF_TET_RELEASED;
|
|
switch (phase) {
|
|
case NSTouchPhaseBegan:
|
|
event_type = CEF_TET_PRESSED;
|
|
break;
|
|
case NSTouchPhaseMoved:
|
|
event_type = CEF_TET_MOVED;
|
|
break;
|
|
case NSTouchPhaseEnded:
|
|
event_type = CEF_TET_RELEASED;
|
|
break;
|
|
case NSTouchPhaseCancelled:
|
|
event_type = CEF_TET_CANCELLED;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return event_type;
|
|
}
|
|
|
|
// Translate NSTouch events to CefTouchEvents and send to browser.
|
|
- (void)sendTouchEvent:(NSEvent*)event touchPhase:(NSTouchPhase)phase {
|
|
int modifiers = [self getModifiersForEvent:event];
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
|
|
NSSet* touches = [event touchesMatchingPhase:phase inView:self];
|
|
|
|
for (NSTouch* touch in touches) {
|
|
// Convert NSTouch to CefTouchEvent.
|
|
CefTouchEvent touch_event;
|
|
|
|
// NSTouch.identity is unique during the life of the touch
|
|
touch_event.id = touch.identity.hash;
|
|
touch_event.type = [self getTouchPhase:phase];
|
|
|
|
NSPoint scaled_pos = [touch normalizedPosition];
|
|
NSSize view_size = [self bounds].size;
|
|
|
|
// Map point on Touch Device to View coordinates.
|
|
NSPoint touch_point = NSMakePoint(scaled_pos.x * view_size.width,
|
|
scaled_pos.y * view_size.height);
|
|
|
|
NSPoint contentLocal = [self convertPoint:touch_point fromView:nil];
|
|
NSPoint point;
|
|
point.x = contentLocal.x;
|
|
point.y = [self frame].size.height - contentLocal.y; // Flip y.
|
|
|
|
// Convert to device coordinates.
|
|
point = [self convertPointToBackingInternal:point];
|
|
|
|
int device_x = point.x;
|
|
int device_y = point.y;
|
|
|
|
const float device_scale_factor = [self getDeviceScaleFactor];
|
|
// Convert to browser view coordinates.
|
|
touch_event.x = client::DeviceToLogical(device_x, device_scale_factor);
|
|
touch_event.y = client::DeviceToLogical(device_y, device_scale_factor);
|
|
|
|
touch_event.radius_x = 0;
|
|
touch_event.radius_y = 0;
|
|
|
|
touch_event.rotation_angle = 0;
|
|
touch_event.pressure = 0;
|
|
|
|
touch_event.modifiers = modifiers;
|
|
|
|
// Notify the browser of touch event.
|
|
browser->GetHost()->SendTouchEvent(touch_event);
|
|
}
|
|
}
|
|
|
|
- (void)touchesBeganWithEvent:(NSEvent*)event {
|
|
[self sendTouchEvent:event touchPhase:NSTouchPhaseBegan];
|
|
}
|
|
|
|
- (void)touchesMovedWithEvent:(NSEvent*)event {
|
|
[self sendTouchEvent:event touchPhase:NSTouchPhaseMoved];
|
|
}
|
|
|
|
- (void)touchesEndedWithEvent:(NSEvent*)event {
|
|
[self sendTouchEvent:event touchPhase:NSTouchPhaseEnded];
|
|
}
|
|
|
|
- (void)touchesCancelledWithEvent:(NSEvent*)event {
|
|
[self sendTouchEvent:event touchPhase:NSTouchPhaseCancelled];
|
|
}
|
|
|
|
- (void)keyUp:(NSEvent*)event {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
CefKeyEvent keyEvent;
|
|
[self getKeyEvent:keyEvent forEvent:event];
|
|
|
|
keyEvent.type = KEYEVENT_KEYUP;
|
|
browser->GetHost()->SendKeyEvent(keyEvent);
|
|
}
|
|
|
|
- (void)flagsChanged:(NSEvent*)event {
|
|
if ([self isKeyUpEvent:event])
|
|
[self keyUp:event];
|
|
else
|
|
[self keyDown:event];
|
|
}
|
|
|
|
- (void)shortCircuitScrollWheelEvent:(NSEvent*)event {
|
|
if ([event phase] != NSEventPhaseEnded &&
|
|
[event phase] != NSEventPhaseCancelled)
|
|
return;
|
|
|
|
[self sendScrollWheelEvet:event];
|
|
|
|
if (endWheelMonitor_) {
|
|
[NSEvent removeMonitor:endWheelMonitor_];
|
|
endWheelMonitor_ = nil;
|
|
}
|
|
}
|
|
|
|
- (void)scrollWheel:(NSEvent*)event {
|
|
// Use an NSEvent monitor to listen for the wheel-end end. This ensures that
|
|
// the event is received even when the mouse cursor is no longer over the
|
|
// view when the scrolling ends. Also it avoids sending duplicate scroll
|
|
// events to the renderer.
|
|
if ([event phase] == NSEventPhaseBegan && !endWheelMonitor_) {
|
|
endWheelMonitor_ = [NSEvent
|
|
addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
|
|
handler:^(NSEvent* blockEvent) {
|
|
[self shortCircuitScrollWheelEvent:
|
|
blockEvent];
|
|
return blockEvent;
|
|
}];
|
|
}
|
|
|
|
[self sendScrollWheelEvet:event];
|
|
}
|
|
|
|
- (void)sendScrollWheelEvet:(NSEvent*)event {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
CGEventRef cgEvent = [event CGEvent];
|
|
DCHECK(cgEvent);
|
|
|
|
int deltaX =
|
|
CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2);
|
|
int deltaY =
|
|
CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forEvent:event];
|
|
|
|
browser->GetHost()->SendMouseWheelEvent(mouseEvent, deltaX, deltaY);
|
|
}
|
|
|
|
- (BOOL)canBecomeKeyView {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
return (browser.get() != NULL);
|
|
}
|
|
|
|
- (BOOL)acceptsFirstResponder {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
return (browser.get() != NULL);
|
|
}
|
|
|
|
- (BOOL)becomeFirstResponder {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get()) {
|
|
browser->GetHost()->SendFocusEvent(true);
|
|
return [super becomeFirstResponder];
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)resignFirstResponder {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get()) {
|
|
browser->GetHost()->SendFocusEvent(false);
|
|
return [super resignFirstResponder];
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)undo:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Undo();
|
|
}
|
|
|
|
- (void)redo:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Redo();
|
|
}
|
|
|
|
- (void)cut:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Cut();
|
|
}
|
|
|
|
- (void)copy:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Copy();
|
|
}
|
|
|
|
- (void)paste:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Paste();
|
|
}
|
|
|
|
- (void)delete:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->Delete();
|
|
}
|
|
|
|
- (void)selectAll:(id)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetFocusedFrame()->SelectAll();
|
|
}
|
|
|
|
- (NSPoint)getClickPointForEvent:(NSEvent*)event {
|
|
NSPoint windowLocal = [event locationInWindow];
|
|
NSPoint contentLocal = [self convertPoint:windowLocal fromView:nil];
|
|
|
|
NSPoint point;
|
|
point.x = contentLocal.x;
|
|
point.y = [self frame].size.height - contentLocal.y; // Flip y.
|
|
return point;
|
|
}
|
|
|
|
- (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event {
|
|
if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
|
|
NSString* s = [event characters];
|
|
if ([s length] > 0)
|
|
keyEvent.character = [s characterAtIndex:0];
|
|
|
|
s = [event charactersIgnoringModifiers];
|
|
if ([s length] > 0)
|
|
keyEvent.unmodified_character = [s characterAtIndex:0];
|
|
}
|
|
|
|
if ([event type] == NSFlagsChanged) {
|
|
keyEvent.character = 0;
|
|
keyEvent.unmodified_character = 0;
|
|
}
|
|
|
|
keyEvent.native_key_code = [event keyCode];
|
|
|
|
keyEvent.modifiers = [self getModifiersForEvent:event];
|
|
}
|
|
|
|
- (NSTextInputContext*)inputContext {
|
|
if (!text_input_context_osr_mac_) {
|
|
text_input_client_ =
|
|
[[CefTextInputClientOSRMac alloc] initWithBrowser:[self getBrowser]];
|
|
text_input_context_osr_mac_ =
|
|
[[NSTextInputContext alloc] initWithClient:text_input_client_];
|
|
#if !__has_feature(objc_arc)
|
|
[text_input_client_ retain];
|
|
[text_input_context_osr_mac_ retain];
|
|
#endif // !__has_feature(objc_arc)
|
|
}
|
|
|
|
return text_input_context_osr_mac_;
|
|
}
|
|
|
|
- (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event {
|
|
const float device_scale_factor = [self getDeviceScaleFactor];
|
|
|
|
// |point| is in OS X view coordinates.
|
|
NSPoint point = [self getClickPointForEvent:event];
|
|
|
|
// Convert to device coordinates.
|
|
point = [self convertPointToBackingInternal:point];
|
|
|
|
int device_x = point.x;
|
|
int device_y = point.y;
|
|
if ([self isOverPopupWidgetX:device_x andY:device_y])
|
|
[self applyPopupOffsetToX:device_x andY:device_y];
|
|
|
|
// Convert to browser view coordinates.
|
|
mouseEvent.x = client::DeviceToLogical(device_x, device_scale_factor);
|
|
mouseEvent.y = client::DeviceToLogical(device_y, device_scale_factor);
|
|
|
|
mouseEvent.modifiers = [self getModifiersForEvent:event];
|
|
}
|
|
|
|
- (void)getMouseEvent:(CefMouseEvent&)mouseEvent
|
|
forDragInfo:(id<NSDraggingInfo>)info {
|
|
const float device_scale_factor = [self getDeviceScaleFactor];
|
|
|
|
// |point| is in OS X view coordinates.
|
|
NSPoint windowPoint = [info draggingLocation];
|
|
NSPoint point = [self flipWindowPointToView:windowPoint];
|
|
|
|
// Convert to device coordinates.
|
|
point = [self convertPointToBackingInternal:point];
|
|
|
|
// Convert to browser view coordinates.
|
|
mouseEvent.x = client::DeviceToLogical(point.x, device_scale_factor);
|
|
mouseEvent.y = client::DeviceToLogical(point.y, device_scale_factor);
|
|
|
|
mouseEvent.modifiers = [NSEvent modifierFlags];
|
|
}
|
|
|
|
- (int)getModifiersForEvent:(NSEvent*)event {
|
|
int modifiers = 0;
|
|
|
|
if ([event modifierFlags] & NSControlKeyMask)
|
|
modifiers |= EVENTFLAG_CONTROL_DOWN;
|
|
if ([event modifierFlags] & NSShiftKeyMask)
|
|
modifiers |= EVENTFLAG_SHIFT_DOWN;
|
|
if ([event modifierFlags] & NSAlternateKeyMask)
|
|
modifiers |= EVENTFLAG_ALT_DOWN;
|
|
if ([event modifierFlags] & NSCommandKeyMask)
|
|
modifiers |= EVENTFLAG_COMMAND_DOWN;
|
|
if ([event modifierFlags] & NSAlphaShiftKeyMask)
|
|
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
|
|
|
|
if ([event type] == NSKeyUp || [event type] == NSKeyDown ||
|
|
[event type] == NSFlagsChanged) {
|
|
// Only perform this check for key events
|
|
if ([self isKeyPadEvent:event])
|
|
modifiers |= EVENTFLAG_IS_KEY_PAD;
|
|
}
|
|
|
|
// OS X does not have a modifier for NumLock, so I'm not entirely sure how to
|
|
// set EVENTFLAG_NUM_LOCK_ON;
|
|
//
|
|
// There is no EVENTFLAG for the function key either.
|
|
|
|
// Mouse buttons
|
|
switch ([event type]) {
|
|
case NSLeftMouseDragged:
|
|
case NSLeftMouseDown:
|
|
case NSLeftMouseUp:
|
|
modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
|
|
break;
|
|
case NSRightMouseDragged:
|
|
case NSRightMouseDown:
|
|
case NSRightMouseUp:
|
|
modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
|
|
break;
|
|
case NSOtherMouseDragged:
|
|
case NSOtherMouseDown:
|
|
case NSOtherMouseUp:
|
|
modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return modifiers;
|
|
}
|
|
|
|
- (BOOL)isKeyUpEvent:(NSEvent*)event {
|
|
if ([event type] != NSFlagsChanged)
|
|
return [event type] == NSKeyUp;
|
|
|
|
// FIXME: This logic fails if the user presses both Shift keys at once, for
|
|
// example: we treat releasing one of them as keyDown.
|
|
switch ([event keyCode]) {
|
|
case 54: // Right Command
|
|
case 55: // Left Command
|
|
return ([event modifierFlags] & NSCommandKeyMask) == 0;
|
|
|
|
case 57: // Capslock
|
|
return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
|
|
|
|
case 56: // Left Shift
|
|
case 60: // Right Shift
|
|
return ([event modifierFlags] & NSShiftKeyMask) == 0;
|
|
|
|
case 58: // Left Alt
|
|
case 61: // Right Alt
|
|
return ([event modifierFlags] & NSAlternateKeyMask) == 0;
|
|
|
|
case 59: // Left Ctrl
|
|
case 62: // Right Ctrl
|
|
return ([event modifierFlags] & NSControlKeyMask) == 0;
|
|
|
|
case 63: // Function
|
|
return ([event modifierFlags] & NSFunctionKeyMask) == 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
- (BOOL)isKeyPadEvent:(NSEvent*)event {
|
|
if ([event modifierFlags] & NSNumericPadKeyMask)
|
|
return true;
|
|
|
|
switch ([event keyCode]) {
|
|
case 71: // Clear
|
|
case 81: // =
|
|
case 75: // /
|
|
case 67: // *
|
|
case 78: // -
|
|
case 69: // +
|
|
case 76: // Enter
|
|
case 65: // .
|
|
case 82: // 0
|
|
case 83: // 1
|
|
case 84: // 2
|
|
case 85: // 3
|
|
case 86: // 4
|
|
case 87: // 5
|
|
case 88: // 6
|
|
case 89: // 7
|
|
case 91: // 8
|
|
case 92: // 9
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
- (void)windowDidChangeBackingProperties:(NSNotification*)notification {
|
|
// This delegate method is only called on 10.7 and later, so don't worry about
|
|
// other backing changes calling it on 10.6 or earlier
|
|
[self resetDeviceScaleFactor];
|
|
}
|
|
|
|
- (void)drawRect:(NSRect)dirtyRect {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if ([self inLiveResize] || !browser.get()) {
|
|
// Fill with the background color.
|
|
const cef_color_t background_color =
|
|
client::MainContext::Get()->GetBackgroundColor();
|
|
NSColor* color = [NSColor
|
|
colorWithCalibratedRed:float(CefColorGetR(background_color)) / 255.0f
|
|
green:float(CefColorGetG(background_color)) / 255.0f
|
|
blue:float(CefColorGetB(background_color)) / 255.0f
|
|
alpha:1.f];
|
|
[color setFill];
|
|
NSRectFill(dirtyRect);
|
|
}
|
|
|
|
// The Invalidate below fixes flicker when resizing.
|
|
if ([self inLiveResize] && browser.get())
|
|
browser->GetHost()->Invalidate(PET_VIEW);
|
|
}
|
|
|
|
// Drag and drop
|
|
|
|
- (BOOL)startDragging:(CefRefPtr<CefDragData>)drag_data
|
|
allowedOps:(NSDragOperation)ops
|
|
point:(NSPoint)position {
|
|
DCHECK(!pasteboard_);
|
|
DCHECK(!fileUTI_);
|
|
DCHECK(!current_drag_data_.get());
|
|
|
|
[self resetDragDrop];
|
|
|
|
current_allowed_ops_ = ops;
|
|
current_drag_data_ = drag_data;
|
|
|
|
[self fillPasteboard];
|
|
|
|
NSEvent* currentEvent = [[NSApplication sharedApplication] currentEvent];
|
|
NSWindow* window = [self window];
|
|
NSTimeInterval eventTime = [currentEvent timestamp];
|
|
|
|
NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
|
|
location:position
|
|
modifierFlags:NSLeftMouseDraggedMask
|
|
timestamp:eventTime
|
|
windowNumber:[window windowNumber]
|
|
context:nil
|
|
eventNumber:0
|
|
clickCount:1
|
|
pressure:1.0];
|
|
|
|
// TODO(cef): Pass a non-nil value to dragImage (see issue #1715). For now
|
|
// work around the "callee requires a non-null argument" error that occurs
|
|
// when building with the 10.11 SDK.
|
|
id nilArg = nil;
|
|
[window dragImage:nilArg
|
|
at:position
|
|
offset:NSZeroSize
|
|
event:dragEvent
|
|
pasteboard:pasteboard_
|
|
source:self
|
|
slideBack:YES];
|
|
return YES;
|
|
}
|
|
|
|
- (void)setCurrentDragOp:(NSDragOperation)op {
|
|
current_drag_op_ = op;
|
|
}
|
|
|
|
// NSDraggingSource Protocol
|
|
|
|
- (NSDragOperation)draggingSession:(NSDraggingSession*)session
|
|
sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
|
|
switch (context) {
|
|
case NSDraggingContextOutsideApplication:
|
|
return current_allowed_ops_;
|
|
|
|
case NSDraggingContextWithinApplication:
|
|
default:
|
|
return current_allowed_ops_;
|
|
}
|
|
}
|
|
|
|
- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
|
|
if (![dropDest isFileURL])
|
|
return nil;
|
|
|
|
if (!current_drag_data_)
|
|
return nil;
|
|
|
|
size_t expected_size = current_drag_data_->GetFileContents(NULL);
|
|
if (expected_size == 0)
|
|
return nil;
|
|
|
|
std::string path = [[dropDest path] UTF8String];
|
|
path.append("/");
|
|
path.append(current_drag_data_->GetFileName().ToString());
|
|
|
|
CefRefPtr<CefStreamWriter> writer = CefStreamWriter::CreateForFile(path);
|
|
if (!writer)
|
|
return nil;
|
|
|
|
if (current_drag_data_->GetFileContents(writer) != expected_size)
|
|
return nil;
|
|
|
|
return @[ [NSString stringWithUTF8String:path.c_str()] ];
|
|
}
|
|
|
|
- (void)draggedImage:(NSImage*)anImage
|
|
endedAt:(NSPoint)screenPoint
|
|
operation:(NSDragOperation)operation {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return;
|
|
|
|
if (operation == (NSDragOperationMove | NSDragOperationCopy))
|
|
operation &= ~NSDragOperationMove;
|
|
|
|
NSPoint windowPoint = [[self window] convertScreenToBase:screenPoint];
|
|
NSPoint pt = [self flipWindowPointToView:windowPoint];
|
|
CefRenderHandler::DragOperation op =
|
|
static_cast<CefRenderHandler::DragOperation>(operation);
|
|
browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, op);
|
|
browser->GetHost()->DragSourceSystemDragEnded();
|
|
[self resetDragDrop];
|
|
}
|
|
|
|
// NSDraggingDestination Protocol
|
|
|
|
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return NSDragOperationNone;
|
|
|
|
CefRefPtr<CefDragData> drag_data;
|
|
if (!current_drag_data_) {
|
|
drag_data = CefDragData::Create();
|
|
[self populateDropData:drag_data fromPasteboard:[info draggingPasteboard]];
|
|
} else {
|
|
drag_data = current_drag_data_->Clone();
|
|
drag_data->ResetFileContents();
|
|
}
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forDragInfo:info];
|
|
|
|
NSDragOperation mask = [info draggingSourceOperationMask];
|
|
CefBrowserHost::DragOperationsMask allowed_ops =
|
|
static_cast<CefBrowserHost::DragOperationsMask>(mask);
|
|
|
|
browser->GetHost()->DragTargetDragEnter(drag_data, mouseEvent, allowed_ops);
|
|
browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
|
|
|
|
current_drag_op_ = NSDragOperationCopy;
|
|
return current_drag_op_;
|
|
}
|
|
|
|
- (void)draggingExited:(id<NSDraggingInfo>)sender {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser.get())
|
|
browser->GetHost()->DragTargetDragLeave();
|
|
}
|
|
|
|
- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return NO;
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forDragInfo:info];
|
|
|
|
browser->GetHost()->DragTargetDrop(mouseEvent);
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (!browser.get())
|
|
return NSDragOperationNone;
|
|
|
|
CefMouseEvent mouseEvent;
|
|
[self getMouseEvent:mouseEvent forDragInfo:info];
|
|
|
|
NSDragOperation mask = [info draggingSourceOperationMask];
|
|
CefBrowserHost::DragOperationsMask allowed_ops =
|
|
static_cast<CefBrowserHost::DragOperationsMask>(mask);
|
|
|
|
browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
|
|
|
|
return current_drag_op_;
|
|
}
|
|
|
|
// NSPasteboardOwner Protocol
|
|
|
|
- (void)pasteboard:(NSPasteboard*)pboard provideDataForType:(NSString*)type {
|
|
if (!current_drag_data_) {
|
|
return;
|
|
}
|
|
|
|
// URL.
|
|
if ([type isEqualToString:NSURLPboardType]) {
|
|
DCHECK(current_drag_data_->IsLink());
|
|
NSString* strUrl =
|
|
[NSString stringWithUTF8String:current_drag_data_->GetLinkURL()
|
|
.ToString()
|
|
.c_str()];
|
|
NSURL* url = [NSURL URLWithString:strUrl];
|
|
[url writeToPasteboard:pboard];
|
|
// URL title.
|
|
} else if ([type isEqualToString:kNSURLTitlePboardType]) {
|
|
NSString* strTitle =
|
|
[NSString stringWithUTF8String:current_drag_data_->GetLinkTitle()
|
|
.ToString()
|
|
.c_str()];
|
|
[pboard setString:strTitle forType:kNSURLTitlePboardType];
|
|
|
|
// File contents.
|
|
} else if ([type isEqualToString:fileUTI_]) {
|
|
size_t size = current_drag_data_->GetFileContents(NULL);
|
|
DCHECK_GT(size, 0U);
|
|
CefRefPtr<client::BytesWriteHandler> handler =
|
|
new client::BytesWriteHandler(size);
|
|
CefRefPtr<CefStreamWriter> writer =
|
|
CefStreamWriter::CreateForHandler(handler.get());
|
|
current_drag_data_->GetFileContents(writer);
|
|
DCHECK_EQ(handler->GetDataSize(), static_cast<int64>(size));
|
|
|
|
[pboard setData:[NSData dataWithBytes:handler->GetData()
|
|
length:handler->GetDataSize()]
|
|
forType:fileUTI_];
|
|
|
|
// Plain text.
|
|
} else if ([type isEqualToString:NSStringPboardType]) {
|
|
NSString* strTitle =
|
|
[NSString stringWithUTF8String:current_drag_data_->GetFragmentText()
|
|
.ToString()
|
|
.c_str()];
|
|
[pboard setString:strTitle forType:NSStringPboardType];
|
|
|
|
} else if ([type isEqualToString:kCEFDragDummyPboardType]) {
|
|
// The dummy type _was_ promised and someone decided to call the bluff.
|
|
[pboard setData:[NSData data] forType:kCEFDragDummyPboardType];
|
|
}
|
|
}
|
|
|
|
// NSAccessibility Protocol implementation.
|
|
- (BOOL)accessibilityIsIgnored {
|
|
if (!accessibility_helper_)
|
|
return YES;
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
|
if (!accessibility_helper_)
|
|
return [super accessibilityAttributeValue:attribute];
|
|
if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
|
|
return NSAccessibilityGroupRole;
|
|
} else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
|
|
client::OsrAXNode* node = accessibility_helper_->GetRootNode();
|
|
std::string desc = node ? node->AxDescription() : "";
|
|
return [NSString stringWithUTF8String:desc.c_str()];
|
|
} else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
|
|
client::OsrAXNode* node = accessibility_helper_->GetRootNode();
|
|
std::string desc = node ? node->AxValue() : "";
|
|
return [NSString stringWithUTF8String:desc.c_str()];
|
|
} else if ([attribute
|
|
isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
|
|
return NSAccessibilityRoleDescriptionForUIElement(self);
|
|
} else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
|
|
client::OsrAXNode* node = accessibility_helper_->GetRootNode();
|
|
// Add Root as first Kid
|
|
NSMutableArray* kids = [NSMutableArray arrayWithCapacity:1];
|
|
NSObject* child = CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
|
|
node->GetNativeAccessibleObject(NULL));
|
|
[kids addObject:child];
|
|
return NSAccessibilityUnignoredChildren(kids);
|
|
} else {
|
|
return [super accessibilityAttributeValue:attribute];
|
|
}
|
|
}
|
|
|
|
- (id)accessibilityFocusedUIElement {
|
|
if (accessibility_helper_) {
|
|
client::OsrAXNode* node = accessibility_helper_->GetFocusedNode();
|
|
return node ? CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
|
|
node->GetNativeAccessibleObject(NULL))
|
|
: nil;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
// Utility methods.
|
|
- (void)resetDragDrop {
|
|
current_drag_op_ = NSDragOperationNone;
|
|
current_allowed_ops_ = NSDragOperationNone;
|
|
current_drag_data_ = NULL;
|
|
if (fileUTI_) {
|
|
#if !__has_feature(objc_arc)
|
|
[fileUTI_ release];
|
|
#endif // !__has_feature(objc_arc)
|
|
fileUTI_ = nil;
|
|
}
|
|
if (pasteboard_) {
|
|
#if !__has_feature(objc_arc)
|
|
[pasteboard_ release];
|
|
#endif // !__has_feature(objc_arc)
|
|
pasteboard_ = nil;
|
|
}
|
|
}
|
|
|
|
- (void)fillPasteboard {
|
|
DCHECK(!pasteboard_);
|
|
pasteboard_ = [NSPasteboard pasteboardWithName:NSDragPboard];
|
|
#if !__has_feature(objc_arc)
|
|
[pasteboard_ retain];
|
|
#endif // !__has_feature(objc_arc)
|
|
|
|
[pasteboard_ declareTypes:@[ kCEFDragDummyPboardType ] owner:self];
|
|
|
|
// URL (and title).
|
|
if (current_drag_data_->IsLink()) {
|
|
[pasteboard_ addTypes:@[ NSURLPboardType, kNSURLTitlePboardType ]
|
|
owner:self];
|
|
}
|
|
|
|
// MIME type.
|
|
CefString mimeType;
|
|
size_t contents_size = current_drag_data_->GetFileContents(NULL);
|
|
CefString download_metadata = current_drag_data_->GetLinkMetadata();
|
|
CefString file_name = current_drag_data_->GetFileName();
|
|
|
|
// File.
|
|
if (contents_size > 0) {
|
|
std::string file_name = current_drag_data_->GetFileName().ToString();
|
|
size_t sep = file_name.find_last_of(".");
|
|
CefString extension = file_name.substr(sep + 1);
|
|
|
|
mimeType = CefGetMimeType(extension);
|
|
|
|
if (!mimeType.empty()) {
|
|
CFStringRef mimeTypeCF;
|
|
mimeTypeCF = CFStringCreateWithCString(kCFAllocatorDefault,
|
|
mimeType.ToString().c_str(),
|
|
kCFStringEncodingUTF8);
|
|
fileUTI_ = (__bridge NSString*)UTTypeCreatePreferredIdentifierForTag(
|
|
kUTTagClassMIMEType, mimeTypeCF, NULL);
|
|
CFRelease(mimeTypeCF);
|
|
// File (HFS) promise.
|
|
NSArray* fileUTIList = @[ fileUTI_ ];
|
|
[pasteboard_ addTypes:@[ NSFilesPromisePboardType ] owner:self];
|
|
[pasteboard_ setPropertyList:fileUTIList
|
|
forType:NSFilesPromisePboardType];
|
|
|
|
[pasteboard_ addTypes:fileUTIList owner:self];
|
|
}
|
|
}
|
|
|
|
// Plain text.
|
|
if (!current_drag_data_->GetFragmentText().empty()) {
|
|
[pasteboard_ addTypes:@[ NSStringPboardType ] owner:self];
|
|
}
|
|
}
|
|
|
|
- (void)populateDropData:(CefRefPtr<CefDragData>)data
|
|
fromPasteboard:(NSPasteboard*)pboard {
|
|
DCHECK(data);
|
|
DCHECK(pboard);
|
|
DCHECK(data && !data->IsReadOnly());
|
|
NSArray* types = [pboard types];
|
|
|
|
// Get plain text.
|
|
if ([types containsObject:NSStringPboardType]) {
|
|
data->SetFragmentText(
|
|
[[pboard stringForType:NSStringPboardType] UTF8String]);
|
|
}
|
|
|
|
// Get files.
|
|
if ([types containsObject:NSFilenamesPboardType]) {
|
|
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
|
|
if ([files isKindOfClass:[NSArray class]] && [files count]) {
|
|
for (NSUInteger i = 0; i < [files count]; i++) {
|
|
NSString* filename = [files objectAtIndex:i];
|
|
BOOL exists =
|
|
[[NSFileManager defaultManager] fileExistsAtPath:filename];
|
|
if (exists) {
|
|
data->AddFile([filename UTF8String], CefString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint {
|
|
NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
|
|
NSRect viewFrame = [self frame];
|
|
viewPoint.y = viewFrame.size.height - viewPoint.y;
|
|
return viewPoint;
|
|
}
|
|
|
|
- (void)resetDeviceScaleFactor {
|
|
float device_scale_factor = 1.0f;
|
|
NSWindow* window = [self window];
|
|
if (window)
|
|
device_scale_factor = [window backingScaleFactor];
|
|
[self setDeviceScaleFactor:device_scale_factor];
|
|
}
|
|
|
|
- (void)setDeviceScaleFactor:(float)device_scale_factor {
|
|
if (device_scale_factor == device_scale_factor_)
|
|
return;
|
|
|
|
// Apply some sanity checks.
|
|
if (device_scale_factor < 1.0f || device_scale_factor > 4.0f)
|
|
return;
|
|
|
|
device_scale_factor_ = device_scale_factor;
|
|
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser) {
|
|
browser->GetHost()->NotifyScreenInfoChanged();
|
|
browser->GetHost()->WasResized();
|
|
}
|
|
}
|
|
|
|
- (float)getDeviceScaleFactor {
|
|
return device_scale_factor_;
|
|
}
|
|
|
|
- (void)viewDidChangeBackingProperties {
|
|
const CGFloat device_scale_factor = [self getDeviceScaleFactor];
|
|
|
|
if (device_scale_factor == device_scale_factor_)
|
|
return;
|
|
|
|
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
|
if (browser) {
|
|
browser->GetHost()->NotifyScreenInfoChanged();
|
|
browser->GetHost()->WasResized();
|
|
}
|
|
}
|
|
|
|
- (bool)isOverPopupWidgetX:(int)x andY:(int)y {
|
|
CefRect rc = renderer_->popup_rect();
|
|
int popup_right = rc.x + rc.width;
|
|
int popup_bottom = rc.y + rc.height;
|
|
return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
|
|
}
|
|
|
|
- (int)getPopupXOffset {
|
|
return renderer_->original_popup_rect().x - renderer_->popup_rect().x;
|
|
}
|
|
|
|
- (int)getPopupYOffset {
|
|
return renderer_->original_popup_rect().y - renderer_->popup_rect().y;
|
|
}
|
|
|
|
- (void)applyPopupOffsetToX:(int&)x andY:(int&)y {
|
|
if ([self isOverPopupWidgetX:x andY:y]) {
|
|
x += [self getPopupXOffset];
|
|
y += [self getPopupYOffset];
|
|
}
|
|
}
|
|
|
|
// Convert from scaled coordinates to view coordinates.
|
|
- (NSPoint)convertPointFromBackingInternal:(NSPoint)aPoint {
|
|
return [self convertPointFromBacking:aPoint];
|
|
}
|
|
|
|
// Convert from view coordinates to scaled coordinates.
|
|
- (NSPoint)convertPointToBackingInternal:(NSPoint)aPoint {
|
|
return [self convertPointToBacking:aPoint];
|
|
}
|
|
|
|
// Convert from scaled coordinates to view coordinates.
|
|
- (NSRect)convertRectFromBackingInternal:(NSRect)aRect {
|
|
return [self convertRectFromBacking:aRect];
|
|
}
|
|
|
|
// Convert from view coordinates to scaled coordinates.
|
|
- (NSRect)convertRectToBackingInternal:(NSRect)aRect {
|
|
return [self convertRectToBacking:aRect];
|
|
}
|
|
|
|
- (void)ChangeCompositionRange:(CefRange)range
|
|
character_bounds:(const CefRenderHandler::RectList&)bounds {
|
|
if (text_input_client_)
|
|
[text_input_client_ ChangeCompositionRange:range character_bounds:bounds];
|
|
}
|
|
|
|
- (void)UpdateAccessibilityTree:(CefRefPtr<CefValue>)value {
|
|
if (!accessibility_helper_) {
|
|
accessibility_helper_ =
|
|
new client::OsrAccessibilityHelper(value, [self getBrowser]);
|
|
} else {
|
|
accessibility_helper_->UpdateAccessibilityTree(value);
|
|
}
|
|
|
|
if (accessibility_helper_) {
|
|
NSAccessibilityPostNotification(self,
|
|
NSAccessibilityValueChangedNotification);
|
|
}
|
|
return;
|
|
}
|
|
|
|
- (void)UpdateAccessibilityLocation:(CefRefPtr<CefValue>)value {
|
|
if (accessibility_helper_) {
|
|
accessibility_helper_->UpdateAccessibilityLocation(value);
|
|
}
|
|
|
|
if (accessibility_helper_) {
|
|
NSAccessibilityPostNotification(self,
|
|
NSAccessibilityValueChangedNotification);
|
|
}
|
|
return;
|
|
}
|
|
@end
|
|
|
|
namespace client {
|
|
|
|
class BrowserWindowOsrMacImpl {
|
|
public:
|
|
BrowserWindowOsrMacImpl(BrowserWindow::Delegate* delegate,
|
|
const std::string& startup_url,
|
|
const OsrRendererSettings& settings,
|
|
BrowserWindowOsrMac& browser_window);
|
|
~BrowserWindowOsrMacImpl();
|
|
|
|
// BrowserWindow methods.
|
|
void CreateBrowser(ClientWindowHandle parent_handle,
|
|
const CefRect& rect,
|
|
const CefBrowserSettings& settings,
|
|
CefRefPtr<CefRequestContext> request_context);
|
|
void GetPopupConfig(CefWindowHandle temp_handle,
|
|
CefWindowInfo& windowInfo,
|
|
CefRefPtr<CefClient>& client,
|
|
CefBrowserSettings& settings);
|
|
void ShowPopup(ClientWindowHandle parent_handle,
|
|
int x,
|
|
int y,
|
|
size_t width,
|
|
size_t height);
|
|
void Show();
|
|
void Hide();
|
|
void SetBounds(int x, int y, size_t width, size_t height);
|
|
void SetFocus(bool focus);
|
|
void SetDeviceScaleFactor(float device_scale_factor);
|
|
float GetDeviceScaleFactor() const;
|
|
ClientWindowHandle GetWindowHandle() const;
|
|
|
|
// ClientHandlerOsr::OsrDelegate methods.
|
|
void OnAfterCreated(CefRefPtr<CefBrowser> browser);
|
|
void OnBeforeClose(CefRefPtr<CefBrowser> browser);
|
|
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect);
|
|
void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect);
|
|
bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
|
int viewX,
|
|
int viewY,
|
|
int& screenX,
|
|
int& screenY);
|
|
bool GetScreenInfo(CefRefPtr<CefBrowser> browser, CefScreenInfo& screen_info);
|
|
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show);
|
|
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect);
|
|
void OnPaint(CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::PaintElementType type,
|
|
const CefRenderHandler::RectList& dirtyRects,
|
|
const void* buffer,
|
|
int width,
|
|
int height);
|
|
void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
|
CefCursorHandle cursor,
|
|
CefRenderHandler::CursorType type,
|
|
const CefCursorInfo& custom_cursor_info);
|
|
bool StartDragging(CefRefPtr<CefBrowser> browser,
|
|
CefRefPtr<CefDragData> drag_data,
|
|
CefRenderHandler::DragOperationsMask allowed_ops,
|
|
int x,
|
|
int y);
|
|
void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::DragOperation operation);
|
|
void OnImeCompositionRangeChanged(
|
|
CefRefPtr<CefBrowser> browser,
|
|
const CefRange& selection_range,
|
|
const CefRenderHandler::RectList& character_bounds);
|
|
|
|
void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
|
|
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value);
|
|
|
|
private:
|
|
// Create the NSView.
|
|
void Create(ClientWindowHandle parent_handle, const CefRect& rect);
|
|
|
|
BrowserWindowOsrMac& browser_window_;
|
|
// The below members will only be accessed on the main thread which should be
|
|
// the same as the CEF UI thread.
|
|
OsrRenderer renderer_;
|
|
BrowserOpenGLView* native_browser_view_;
|
|
bool hidden_;
|
|
bool painting_popup_;
|
|
};
|
|
|
|
BrowserWindowOsrMacImpl::BrowserWindowOsrMacImpl(
|
|
BrowserWindow::Delegate* delegate,
|
|
const std::string& startup_url,
|
|
const OsrRendererSettings& settings,
|
|
BrowserWindowOsrMac& browser_window)
|
|
: browser_window_(browser_window),
|
|
renderer_(settings),
|
|
native_browser_view_(nil),
|
|
hidden_(false),
|
|
painting_popup_(false) {}
|
|
|
|
BrowserWindowOsrMacImpl::~BrowserWindowOsrMacImpl() {
|
|
if (native_browser_view_) {
|
|
// Disassociate the view with |this|.
|
|
[native_browser_view_ detach];
|
|
}
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::CreateBrowser(
|
|
ClientWindowHandle parent_handle,
|
|
const CefRect& rect,
|
|
const CefBrowserSettings& settings,
|
|
CefRefPtr<CefRequestContext> request_context) {
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
// Create the native NSView.
|
|
Create(parent_handle, rect);
|
|
|
|
CefWindowInfo window_info;
|
|
window_info.SetAsWindowless(
|
|
CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(native_browser_view_));
|
|
|
|
// Create the browser asynchronously.
|
|
CefBrowserHost::CreateBrowser(window_info, browser_window_.client_handler_,
|
|
browser_window_.client_handler_->startup_url(),
|
|
settings, request_context);
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::GetPopupConfig(CefWindowHandle temp_handle,
|
|
CefWindowInfo& windowInfo,
|
|
CefRefPtr<CefClient>& client,
|
|
CefBrowserSettings& settings) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
windowInfo.SetAsWindowless(temp_handle);
|
|
client = browser_window_.client_handler_;
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::ShowPopup(ClientWindowHandle parent_handle,
|
|
int x,
|
|
int y,
|
|
size_t width,
|
|
size_t height) {
|
|
REQUIRE_MAIN_THREAD();
|
|
DCHECK(browser_window_.browser_.get());
|
|
|
|
// Create the native NSView.
|
|
Create(parent_handle,
|
|
CefRect(x, y, static_cast<int>(width), static_cast<int>(height)));
|
|
|
|
// Send resize notification so the compositor is assigned the correct
|
|
// viewport size and begins rendering.
|
|
browser_window_.browser_->GetHost()->WasResized();
|
|
|
|
Show();
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::Show() {
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (hidden_) {
|
|
// Set the browser as visible.
|
|
browser_window_.browser_->GetHost()->WasHidden(false);
|
|
hidden_ = false;
|
|
}
|
|
|
|
// Give focus to the browser.
|
|
browser_window_.browser_->GetHost()->SendFocusEvent(true);
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::Hide() {
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!browser_window_.browser_.get())
|
|
return;
|
|
|
|
// Remove focus from the browser.
|
|
browser_window_.browser_->GetHost()->SendFocusEvent(false);
|
|
|
|
if (!hidden_) {
|
|
// Set the browser as hidden.
|
|
browser_window_.browser_->GetHost()->WasHidden(true);
|
|
hidden_ = true;
|
|
}
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::SetBounds(int x,
|
|
int y,
|
|
size_t width,
|
|
size_t height) {
|
|
REQUIRE_MAIN_THREAD();
|
|
// Nothing to do here. GTK will take care of positioning in the container.
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::SetFocus(bool focus) {
|
|
REQUIRE_MAIN_THREAD();
|
|
if (native_browser_view_)
|
|
[native_browser_view_.window makeFirstResponder:native_browser_view_];
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::SetDeviceScaleFactor(float device_scale_factor) {
|
|
REQUIRE_MAIN_THREAD();
|
|
if (native_browser_view_)
|
|
[native_browser_view_ setDeviceScaleFactor:device_scale_factor];
|
|
}
|
|
|
|
float BrowserWindowOsrMacImpl::GetDeviceScaleFactor() const {
|
|
REQUIRE_MAIN_THREAD();
|
|
if (native_browser_view_)
|
|
return [native_browser_view_ getDeviceScaleFactor];
|
|
return 1.0f;
|
|
}
|
|
|
|
ClientWindowHandle BrowserWindowOsrMacImpl::GetWindowHandle() const {
|
|
REQUIRE_MAIN_THREAD();
|
|
return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(native_browser_view_);
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
// Detach |this| from the ClientHandlerOsr.
|
|
static_cast<ClientHandlerOsr*>(browser_window_.client_handler_.get())
|
|
->DetachOsrDelegate();
|
|
}
|
|
|
|
bool BrowserWindowOsrMacImpl::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
|
|
CefRect& rect) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
return false;
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::GetViewRect(CefRefPtr<CefBrowser> browser,
|
|
CefRect& rect) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
rect.x = rect.y = 0;
|
|
|
|
if (!native_browser_view_) {
|
|
// Never return an empty rectangle.
|
|
rect.width = rect.height = 1;
|
|
return;
|
|
}
|
|
|
|
const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
|
|
|
// |bounds| is in OS X view coordinates.
|
|
NSRect bounds = native_browser_view_.bounds;
|
|
|
|
// Convert to device coordinates.
|
|
bounds = [native_browser_view_ convertRectToBackingInternal:bounds];
|
|
|
|
// Convert to browser view coordinates.
|
|
rect.width = DeviceToLogical(bounds.size.width, device_scale_factor);
|
|
if (rect.width == 0)
|
|
rect.width = 1;
|
|
rect.height = DeviceToLogical(bounds.size.height, device_scale_factor);
|
|
if (rect.height == 0)
|
|
rect.height = 1;
|
|
}
|
|
|
|
bool BrowserWindowOsrMacImpl::GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
|
int viewX,
|
|
int viewY,
|
|
int& screenX,
|
|
int& screenY) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return false;
|
|
|
|
const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
|
|
|
// (viewX, viewX) is in browser view coordinates.
|
|
// Convert to device coordinates.
|
|
NSPoint view_pt = NSMakePoint(LogicalToDevice(viewX, device_scale_factor),
|
|
LogicalToDevice(viewY, device_scale_factor));
|
|
|
|
// Convert to OS X view coordinates.
|
|
view_pt = [native_browser_view_ convertPointFromBackingInternal:view_pt];
|
|
|
|
// Reverse the Y component.
|
|
const NSRect bounds = native_browser_view_.bounds;
|
|
view_pt.y = bounds.size.height - view_pt.y;
|
|
|
|
// Convert to screen coordinates.
|
|
NSPoint window_pt = [native_browser_view_ convertPoint:view_pt toView:nil];
|
|
NSPoint screen_pt =
|
|
ConvertPointFromWindowToScreen(native_browser_view_.window, window_pt);
|
|
|
|
screenX = screen_pt.x;
|
|
screenY = screen_pt.y;
|
|
return true;
|
|
}
|
|
|
|
bool BrowserWindowOsrMacImpl::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
|
CefScreenInfo& screen_info) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return false;
|
|
|
|
CefRect view_rect;
|
|
GetViewRect(browser, view_rect);
|
|
|
|
screen_info.device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
|
|
|
// The screen info rectangles are used by the renderer to create and position
|
|
// popups. Keep popups inside the view rectangle.
|
|
screen_info.rect = view_rect;
|
|
screen_info.available_rect = view_rect;
|
|
|
|
return true;
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
|
bool show) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return;
|
|
|
|
if (!show) {
|
|
renderer_.ClearPopupRects();
|
|
browser->GetHost()->Invalidate(PET_VIEW);
|
|
}
|
|
renderer_.OnPopupShow(browser, show);
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
|
const CefRect& rect) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return;
|
|
|
|
const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
|
|
|
// |rect| is in browser view coordinates. Convert to device coordinates.
|
|
CefRect device_rect = LogicalToDevice(rect, device_scale_factor);
|
|
|
|
renderer_.OnPopupSize(browser, device_rect);
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnPaint(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::PaintElementType type,
|
|
const CefRenderHandler::RectList& dirtyRects,
|
|
const void* buffer,
|
|
int width,
|
|
int height) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return;
|
|
|
|
if (width <= 2 && height <= 2) {
|
|
// Ignore really small buffer sizes while the widget is starting up.
|
|
return;
|
|
}
|
|
|
|
if (painting_popup_) {
|
|
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
|
return;
|
|
}
|
|
|
|
ScopedGLContext scoped_gl_context(native_browser_view_, true);
|
|
|
|
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
|
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
|
|
painting_popup_ = true;
|
|
browser->GetHost()->Invalidate(PET_POPUP);
|
|
painting_popup_ = false;
|
|
}
|
|
renderer_.Render();
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnCursorChange(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefCursorHandle cursor,
|
|
CefRenderHandler::CursorType type,
|
|
const CefCursorInfo& custom_cursor_info) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
[CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(cursor) set];
|
|
}
|
|
|
|
bool BrowserWindowOsrMacImpl::StartDragging(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefRefPtr<CefDragData> drag_data,
|
|
CefRenderHandler::DragOperationsMask allowed_ops,
|
|
int x,
|
|
int y) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (!native_browser_view_)
|
|
return false;
|
|
|
|
static float device_scale_factor =
|
|
[native_browser_view_ getDeviceScaleFactor];
|
|
|
|
// |point| is in browser view coordinates.
|
|
NSPoint point = NSMakePoint(x, y);
|
|
|
|
// Convert to device coordinates.
|
|
point.x = LogicalToDevice(point.x, device_scale_factor);
|
|
point.y = LogicalToDevice(point.y, device_scale_factor);
|
|
|
|
// Convert to OS X view coordinates.
|
|
point = [native_browser_view_ convertPointFromBackingInternal:point];
|
|
|
|
return [native_browser_view_
|
|
startDragging:drag_data
|
|
allowedOps:static_cast<NSDragOperation>(allowed_ops)
|
|
point:point];
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::UpdateDragCursor(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::DragOperation operation) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
REQUIRE_MAIN_THREAD();
|
|
|
|
if (native_browser_view_)
|
|
[native_browser_view_ setCurrentDragOp:operation];
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::OnImeCompositionRangeChanged(
|
|
CefRefPtr<CefBrowser> browser,
|
|
const CefRange& selection_range,
|
|
const CefRenderHandler::RectList& bounds) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
if (native_browser_view_) {
|
|
[native_browser_view_ ChangeCompositionRange:selection_range
|
|
character_bounds:bounds];
|
|
}
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::UpdateAccessibilityTree(
|
|
CefRefPtr<CefValue> value) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
if (native_browser_view_) {
|
|
[native_browser_view_ UpdateAccessibilityTree:value];
|
|
}
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::UpdateAccessibilityLocation(
|
|
CefRefPtr<CefValue> value) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
if (native_browser_view_) {
|
|
[native_browser_view_ UpdateAccessibilityLocation:value];
|
|
}
|
|
}
|
|
|
|
void BrowserWindowOsrMacImpl::Create(ClientWindowHandle parent_handle,
|
|
const CefRect& rect) {
|
|
REQUIRE_MAIN_THREAD();
|
|
DCHECK(!native_browser_view_);
|
|
|
|
NSRect window_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height);
|
|
native_browser_view_ =
|
|
[[BrowserOpenGLView alloc] initWithFrame:window_rect
|
|
andBrowserWindow:&browser_window_
|
|
andRenderer:&renderer_];
|
|
native_browser_view_.autoresizingMask =
|
|
(NSViewWidthSizable | NSViewHeightSizable);
|
|
native_browser_view_.autoresizesSubviews = YES;
|
|
[CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(parent_handle)
|
|
addSubview:native_browser_view_];
|
|
|
|
// Determine the default scale factor.
|
|
[native_browser_view_ resetDeviceScaleFactor];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
addObserver:native_browser_view_
|
|
selector:@selector(windowDidChangeBackingProperties:)
|
|
name:NSWindowDidChangeBackingPropertiesNotification
|
|
object:native_browser_view_.window];
|
|
}
|
|
|
|
BrowserWindowOsrMac::BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
|
|
const std::string& startup_url,
|
|
const OsrRendererSettings& settings)
|
|
: BrowserWindow(delegate) {
|
|
client_handler_ = new ClientHandlerOsr(this, this, startup_url);
|
|
impl_.reset(
|
|
new BrowserWindowOsrMacImpl(delegate, startup_url, settings, *this));
|
|
}
|
|
|
|
BrowserWindowOsrMac::~BrowserWindowOsrMac() {}
|
|
|
|
void BrowserWindowOsrMac::CreateBrowser(
|
|
ClientWindowHandle parent_handle,
|
|
const CefRect& rect,
|
|
const CefBrowserSettings& settings,
|
|
CefRefPtr<CefRequestContext> request_context) {
|
|
impl_->CreateBrowser(parent_handle, rect, settings, request_context);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::GetPopupConfig(CefWindowHandle temp_handle,
|
|
CefWindowInfo& windowInfo,
|
|
CefRefPtr<CefClient>& client,
|
|
CefBrowserSettings& settings) {
|
|
impl_->GetPopupConfig(temp_handle, windowInfo, client, settings);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::ShowPopup(ClientWindowHandle parent_handle,
|
|
int x,
|
|
int y,
|
|
size_t width,
|
|
size_t height) {
|
|
impl_->ShowPopup(parent_handle, x, y, width, height);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::Show() {
|
|
impl_->Show();
|
|
}
|
|
|
|
void BrowserWindowOsrMac::Hide() {
|
|
impl_->Hide();
|
|
}
|
|
|
|
void BrowserWindowOsrMac::SetBounds(int x, int y, size_t width, size_t height) {
|
|
impl_->SetBounds(x, y, width, height);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::SetFocus(bool focus) {
|
|
impl_->SetFocus(focus);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::SetDeviceScaleFactor(float device_scale_factor) {
|
|
impl_->SetDeviceScaleFactor(device_scale_factor);
|
|
}
|
|
|
|
float BrowserWindowOsrMac::GetDeviceScaleFactor() const {
|
|
return impl_->GetDeviceScaleFactor();
|
|
}
|
|
|
|
ClientWindowHandle BrowserWindowOsrMac::GetWindowHandle() const {
|
|
return impl_->GetWindowHandle();
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
|
impl_->OnAfterCreated(browser);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
|
impl_->OnBeforeClose(browser);
|
|
}
|
|
|
|
bool BrowserWindowOsrMac::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
|
|
CefRect& rect) {
|
|
return impl_->GetRootScreenRect(browser, rect);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::GetViewRect(CefRefPtr<CefBrowser> browser,
|
|
CefRect& rect) {
|
|
impl_->GetViewRect(browser, rect);
|
|
}
|
|
|
|
bool BrowserWindowOsrMac::GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
|
int viewX,
|
|
int viewY,
|
|
int& screenX,
|
|
int& screenY) {
|
|
return impl_->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
|
|
}
|
|
|
|
bool BrowserWindowOsrMac::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
|
CefScreenInfo& screen_info) {
|
|
return impl_->GetScreenInfo(browser, screen_info);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
|
bool show) {
|
|
impl_->OnPopupShow(browser, show);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
|
const CefRect& rect) {
|
|
impl_->OnPopupSize(browser, rect);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnPaint(CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::PaintElementType type,
|
|
const CefRenderHandler::RectList& dirtyRects,
|
|
const void* buffer,
|
|
int width,
|
|
int height) {
|
|
impl_->OnPaint(browser, type, dirtyRects, buffer, width, height);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnCursorChange(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefCursorHandle cursor,
|
|
CefRenderHandler::CursorType type,
|
|
const CefCursorInfo& custom_cursor_info) {
|
|
impl_->OnCursorChange(browser, cursor, type, custom_cursor_info);
|
|
}
|
|
|
|
bool BrowserWindowOsrMac::StartDragging(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefRefPtr<CefDragData> drag_data,
|
|
CefRenderHandler::DragOperationsMask allowed_ops,
|
|
int x,
|
|
int y) {
|
|
return impl_->StartDragging(browser, drag_data, allowed_ops, x, y);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::UpdateDragCursor(
|
|
CefRefPtr<CefBrowser> browser,
|
|
CefRenderHandler::DragOperation operation) {
|
|
impl_->UpdateDragCursor(browser, operation);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::OnImeCompositionRangeChanged(
|
|
CefRefPtr<CefBrowser> browser,
|
|
const CefRange& selection_range,
|
|
const CefRenderHandler::RectList& character_bounds) {
|
|
impl_->OnImeCompositionRangeChanged(browser, selection_range,
|
|
character_bounds);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
|
|
impl_->UpdateAccessibilityTree(value);
|
|
}
|
|
|
|
void BrowserWindowOsrMac::UpdateAccessibilityLocation(
|
|
CefRefPtr<CefValue> value) {
|
|
impl_->UpdateAccessibilityLocation(value);
|
|
}
|
|
|
|
} // namespace client
|