| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/native/native_view_host_mac.h" | 5 #include "ui/views/controls/native/native_view_host_mac.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
| 10 #import "ui/views/cocoa/bridged_native_widget.h" | 10 #import "ui/views/cocoa/bridged_native_widget.h" |
| 11 #include "ui/views/controls/native/native_view_host.h" | 11 #include "ui/views/controls/native/native_view_host.h" |
| 12 #include "ui/views/widget/native_widget_mac.h" | 12 #include "ui/views/widget/native_widget_mac.h" |
| 13 #include "ui/views/widget/widget.h" | 13 #include "ui/views/widget/widget.h" |
| 14 | 14 |
| 15 // An NSView that allows the rendering size of its child subview to be different |
| 16 // than its own frame size, which will result in showing a scaled version of the |
| 17 // child. |
| 18 @interface NativeViewHostMacScalingView : NSView { |
| 19 } |
| 20 |
| 21 - (id)init; |
| 22 - (void)attach:(NSView*)subview; |
| 23 - (BOOL)hasAttachedSubview:(NSView*)subview; |
| 24 - (void)showWithFrame:(NSRect)frame andSize:(NSSize)size; |
| 25 @end |
| 26 |
| 27 @implementation NativeViewHostMacScalingView |
| 28 |
| 29 - (id)init { |
| 30 if (self = [super initWithFrame:NSZeroRect]) { |
| 31 // NativeViewHostMac::ShowWidget() provides manual layout. |
| 32 [self setAutoresizingMask:NSViewNotSizable]; |
| 33 } |
| 34 return self; |
| 35 } |
| 36 |
| 37 - (void)attach:(NSView*)subview { |
| 38 if ([[self subviews] count] == 0) { |
| 39 [self addSubview:subview]; |
| 40 } else if ([[self subviews] objectAtIndex:0] != subview) { |
| 41 [self replaceSubview:[[self subviews] objectAtIndex:0] with:subview]; |
| 42 } |
| 43 } |
| 44 |
| 45 - (BOOL)hasAttachedSubview:(NSView*)subview { |
| 46 if ([[self subviews] count] > 0 && |
| 47 [[self subviews] objectAtIndex:0] == subview) { |
| 48 return YES; |
| 49 } |
| 50 return NO; |
| 51 } |
| 52 |
| 53 - (void)showWithFrame:(NSRect)frame andSize:(NSSize)size { |
| 54 [self setFrame:frame]; |
| 55 const NSRect bounds = NSMakeRect(0, 0, size.width, size.height); |
| 56 [self setBounds:bounds]; |
| 57 DCHECK([[self subviews] count] > 0); |
| 58 [[[self subviews] objectAtIndex:0] setFrame:bounds]; |
| 59 } |
| 60 |
| 61 @end // @implementation NativeViewHostMacScalingView |
| 62 |
| 15 namespace views { | 63 namespace views { |
| 16 namespace { | 64 namespace { |
| 17 | 65 |
| 18 void EnsureNativeViewHasNoChildWidgets(NSView* native_view) { | 66 void EnsureNativeViewHasNoChildWidgets(NSView* native_view) { |
| 19 DCHECK(native_view); | 67 DCHECK(native_view); |
| 20 // Mac's NativeViewHost has no support for hosting its own child widgets. | 68 // Mac's NativeViewHost has no support for hosting its own child widgets. |
| 21 // This check is probably overly restrictive, since the Widget containing the | 69 // This check is probably overly restrictive, since the Widget containing the |
| 22 // NativeViewHost _is_ allowed child Widgets. However, we don't know yet | 70 // NativeViewHost _is_ allowed child Widgets. However, we don't know yet |
| 23 // whether those child Widgets need to be distinguished from Widgets that code | 71 // whether those child Widgets need to be distinguished from Widgets that code |
| 24 // might want to associate with the hosted NSView instead. | 72 // might want to associate with the hosted NSView instead. |
| 25 { | 73 { |
| 26 Widget::Widgets child_widgets; | 74 Widget::Widgets child_widgets; |
| 27 Widget::GetAllChildWidgets(native_view, &child_widgets); | 75 Widget::GetAllChildWidgets(native_view, &child_widgets); |
| 28 CHECK_GE(1u, child_widgets.size()); // 1 (itself) or 0 if detached. | 76 CHECK_GE(1u, child_widgets.size()); // 1 (itself) or 0 if detached. |
| 29 } | 77 } |
| 30 } | 78 } |
| 31 | 79 |
| 32 } // namespace | 80 } // namespace |
| 33 | 81 |
| 34 NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) { | 82 NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) { |
| 35 } | 83 } |
| 36 | 84 |
| 37 NativeViewHostMac::~NativeViewHostMac() { | 85 NativeViewHostMac::~NativeViewHostMac() { |
| 38 } | 86 } |
| 39 | 87 |
| 40 //////////////////////////////////////////////////////////////////////////////// | 88 //////////////////////////////////////////////////////////////////////////////// |
| 41 // NativeViewHostMac, NativeViewHostWrapper implementation: | 89 // NativeViewHostMac, NativeViewHostWrapper implementation: |
| 42 | 90 |
| 43 void NativeViewHostMac::AttachNativeView() { | 91 void NativeViewHostMac::AttachNativeView() { |
| 44 DCHECK(host_->native_view()); | 92 NSView* const native_view = host_->native_view(); |
| 45 DCHECK(!native_view_); | 93 DCHECK(native_view); |
| 46 native_view_.reset([host_->native_view() retain]); | 94 DCHECK(!scaling_view_); |
| 95 scaling_view_.reset([[NativeViewHostMacScalingView alloc] init]); |
| 96 [scaling_view_ attach:native_view]; |
| 47 | 97 |
| 48 EnsureNativeViewHasNoChildWidgets(native_view_); | 98 EnsureNativeViewHasNoChildWidgets(native_view); |
| 49 BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow( | 99 BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow( |
| 50 host_->GetWidget()->GetNativeWindow()); | 100 host_->GetWidget()->GetNativeWindow()); |
| 51 DCHECK(bridge); | 101 DCHECK(bridge); |
| 52 [bridge->ns_view() addSubview:native_view_]; | 102 [bridge->ns_view() addSubview:scaling_view_]; |
| 53 bridge->SetAssociationForView(host_, native_view_); | 103 bridge->SetAssociationForView(host_, scaling_view_); |
| 54 } | 104 } |
| 55 | 105 |
| 56 void NativeViewHostMac::NativeViewDetaching(bool destroyed) { | 106 void NativeViewHostMac::NativeViewDetaching(bool destroyed) { |
| 57 // |destroyed| is only true if this class calls host_->NativeViewDestroyed(). | 107 // |destroyed| is only true if this class calls host_->NativeViewDestroyed(). |
| 58 // Aura does this after observing an aura OnWindowDestroying, but NSViews | 108 // Aura does this after observing an aura OnWindowDestroying, but NSViews |
| 59 // are reference counted so there isn't a reliable signal. Instead, a | 109 // are reference counted so there isn't a reliable signal. Instead, a |
| 60 // reference is retained until the NativeViewHost is detached. | 110 // reference is retained until the NativeViewHost is detached. |
| 61 DCHECK(!destroyed); | 111 DCHECK(!destroyed); |
| 62 | 112 |
| 63 // |native_view_| can be nil here if RemovedFromWidget() is called before | 113 // |scaling_view_| can be nil here if RemovedFromWidget() is called before |
| 64 // NativeViewHost::Detach(). | 114 // NativeViewHost::Detach(). |
| 65 if (!native_view_) { | 115 if (!scaling_view_) { |
| 66 DCHECK(![host_->native_view() superview]); | 116 DCHECK(![host_->native_view() superview]); |
| 67 return; | 117 return; |
| 68 } | 118 } |
| 69 | 119 |
| 70 DCHECK(native_view_ == host_->native_view()); | 120 DCHECK([scaling_view_ hasAttachedSubview:host_->native_view()]); |
| 71 [host_->native_view() setHidden:YES]; | 121 [host_->native_view() setHidden:YES]; |
| 122 // Retain the native view for the remainder of this scope, since removing it |
| 123 // from its superview could cause it to be released. |
| 124 const base::scoped_nsobject<NSView> retained_native_view( |
| 125 [host_->native_view() retain]); |
| 72 [host_->native_view() removeFromSuperview]; | 126 [host_->native_view() removeFromSuperview]; |
| 127 [scaling_view_ removeFromSuperview]; |
| 73 | 128 |
| 74 EnsureNativeViewHasNoChildWidgets(host_->native_view()); | 129 EnsureNativeViewHasNoChildWidgets(host_->native_view()); |
| 75 BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow( | 130 BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow( |
| 76 host_->GetWidget()->GetNativeWindow()); | 131 host_->GetWidget()->GetNativeWindow()); |
| 77 // BridgedNativeWidget can be null when Widget is closing. | 132 // BridgedNativeWidget can be null when Widget is closing. |
| 78 if (bridge) | 133 if (bridge) |
| 79 bridge->ClearAssociationForView(host_); | 134 bridge->ClearAssociationForView(host_); |
| 80 | 135 |
| 81 native_view_.reset(); | 136 scaling_view_.reset(); |
| 82 } | 137 } |
| 83 | 138 |
| 84 void NativeViewHostMac::AddedToWidget() { | 139 void NativeViewHostMac::AddedToWidget() { |
| 85 if (!host_->native_view()) | 140 if (!host_->native_view()) |
| 86 return; | 141 return; |
| 87 | 142 |
| 88 AttachNativeView(); | 143 AttachNativeView(); |
| 89 host_->Layout(); | 144 host_->Layout(); |
| 90 } | 145 } |
| 91 | 146 |
| 92 void NativeViewHostMac::RemovedFromWidget() { | 147 void NativeViewHostMac::RemovedFromWidget() { |
| 93 if (!host_->native_view()) | 148 if (!host_->native_view()) |
| 94 return; | 149 return; |
| 95 | 150 |
| 96 NativeViewDetaching(false); | 151 NativeViewDetaching(false); |
| 97 } | 152 } |
| 98 | 153 |
| 99 void NativeViewHostMac::InstallClip(int x, int y, int w, int h) { | 154 void NativeViewHostMac::InstallClip(int x, int y, int w, int h) { |
| 100 NOTIMPLEMENTED(); | 155 NOTIMPLEMENTED(); |
| 101 } | 156 } |
| 102 | 157 |
| 103 bool NativeViewHostMac::HasInstalledClip() { | 158 bool NativeViewHostMac::HasInstalledClip() { |
| 104 return false; | 159 return false; |
| 105 } | 160 } |
| 106 | 161 |
| 107 void NativeViewHostMac::UninstallClip() { | 162 void NativeViewHostMac::UninstallClip() { |
| 108 NOTIMPLEMENTED(); | 163 NOTIMPLEMENTED(); |
| 109 } | 164 } |
| 110 | 165 |
| 111 void NativeViewHostMac::ShowWidget(int x, int y, int w, int h) { | 166 void NativeViewHostMac::ShowWidget(int x, |
| 167 int y, |
| 168 int w, |
| 169 int h, |
| 170 int render_w, |
| 171 int render_h) { |
| 172 DCHECK(scaling_view_); // AttachNativeView() should have been called. |
| 173 |
| 112 if (host_->fast_resize()) | 174 if (host_->fast_resize()) |
| 113 NOTIMPLEMENTED(); | 175 NOTIMPLEMENTED(); |
| 114 | 176 |
| 115 // Coordinates will be from the top left of the parent Widget. The NativeView | 177 // Coordinates will be from the top left of the parent Widget. The NativeView |
| 116 // is already in the same NSWindow, so just flip to get Cooca coordinates and | 178 // is already in the same NSWindow, so just flip to get Cooca coordinates and |
| 117 // then convert to the containing view. | 179 // then convert to the containing view. |
| 118 NSRect window_rect = NSMakeRect( | 180 NSRect window_rect = NSMakeRect( |
| 119 x, | 181 x, |
| 120 host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h, | 182 host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h, |
| 121 w, | 183 w, |
| 122 h); | 184 h); |
| 123 | 185 |
| 124 // Convert window coordinates to the hosted view's superview, since that's how | 186 // Convert window coordinates to the hosted view's superview, since that's how |
| 125 // coordinates of the hosted view's frame is based. | 187 // coordinates of the hosted view's frame is based. |
| 126 NSRect container_rect = | 188 NSRect container_rect = |
| 127 [[host_->native_view() superview] convertRect:window_rect fromView:nil]; | 189 [[scaling_view_ superview] convertRect:window_rect fromView:nil]; |
| 128 [host_->native_view() setFrame:container_rect]; | 190 [scaling_view_ showWithFrame:container_rect |
| 191 andSize:NSMakeSize(render_w, render_h)]; |
| 129 [host_->native_view() setHidden:NO]; | 192 [host_->native_view() setHidden:NO]; |
| 130 } | 193 } |
| 131 | 194 |
| 132 void NativeViewHostMac::HideWidget() { | 195 void NativeViewHostMac::HideWidget() { |
| 133 [host_->native_view() setHidden:YES]; | 196 [host_->native_view() setHidden:YES]; |
| 134 } | 197 } |
| 135 | 198 |
| 136 void NativeViewHostMac::SetFocus() { | 199 void NativeViewHostMac::SetFocus() { |
| 137 if ([host_->native_view() acceptsFirstResponder]) | 200 if ([host_->native_view() acceptsFirstResponder]) |
| 138 [[host_->native_view() window] makeFirstResponder:host_->native_view()]; | 201 [[host_->native_view() window] makeFirstResponder:host_->native_view()]; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 156 return gfx::kNullCursor; | 219 return gfx::kNullCursor; |
| 157 } | 220 } |
| 158 | 221 |
| 159 // static | 222 // static |
| 160 NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper( | 223 NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper( |
| 161 NativeViewHost* host) { | 224 NativeViewHost* host) { |
| 162 return new NativeViewHostMac(host); | 225 return new NativeViewHostMac(host); |
| 163 } | 226 } |
| 164 | 227 |
| 165 } // namespace views | 228 } // namespace views |
| OLD | NEW |