| 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 #import "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "ui/base/ime/input_method.h" | 8 #include "ui/base/ime/input_method.h" |
| 9 #include "ui/base/ime/input_method_factory.h" | 9 #include "ui/base/ime/input_method_factory.h" |
| 10 #include "ui/base/ui_base_switches_util.h" | 10 #include "ui/base/ui_base_switches_util.h" |
| 11 #include "ui/gfx/display.h" |
| 12 #import "ui/gfx/mac/coordinate_conversion.h" |
| 13 #include "ui/gfx/screen.h" |
| 11 #import "ui/views/cocoa/bridged_content_view.h" | 14 #import "ui/views/cocoa/bridged_content_view.h" |
| 12 #import "ui/views/cocoa/views_nswindow_delegate.h" | 15 #import "ui/views/cocoa/views_nswindow_delegate.h" |
| 13 #include "ui/views/widget/native_widget_mac.h" | 16 #include "ui/views/widget/native_widget_mac.h" |
| 14 #include "ui/views/ime/input_method_bridge.h" | 17 #include "ui/views/ime/input_method_bridge.h" |
| 15 #include "ui/views/ime/null_input_method.h" | 18 #include "ui/views/ime/null_input_method.h" |
| 16 #include "ui/views/view.h" | 19 #include "ui/views/view.h" |
| 17 #include "ui/views/widget/widget.h" | 20 #include "ui/views/widget/widget.h" |
| 18 | 21 |
| 22 #include "cc/output/copy_output_request.h" |
| 23 #include "cc/output/copy_output_result.h" |
| 24 |
| 25 #include "third_party/skia/include/core/SkBitmap.h" |
| 26 #include "ui/gfx/codec/png_codec.h" |
| 27 #include "ui/gfx/image/image_skia_rep.h" |
| 28 #include "ui/gfx/canvas.h" |
| 29 |
| 30 namespace { |
| 31 |
| 32 float GetDeviceScaleFactorFromDisplay(NSView* view) { |
| 33 gfx::Display display = gfx::Screen::GetScreenFor(view)-> |
| 34 GetDisplayNearestWindow(view); |
| 35 DCHECK(display.is_valid()); |
| 36 return display.device_scale_factor(); |
| 37 } |
| 38 |
| 39 } // namespace |
| 40 |
| 19 namespace views { | 41 namespace views { |
| 20 | 42 |
| 21 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) | 43 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) |
| 22 : native_widget_mac_(parent), focus_manager_(NULL) { | 44 : native_widget_mac_(parent), focus_manager_(NULL) { |
| 23 DCHECK(parent); | 45 DCHECK(parent); |
| 24 window_delegate_.reset( | 46 window_delegate_.reset( |
| 25 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); | 47 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); |
| 26 } | 48 } |
| 27 | 49 |
| 28 BridgedNativeWidget::~BridgedNativeWidget() { | 50 BridgedNativeWidget::~BridgedNativeWidget() { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 57 | 79 |
| 58 if (focus_manager_) | 80 if (focus_manager_) |
| 59 focus_manager_->RemoveFocusChangeListener(this); | 81 focus_manager_->RemoveFocusChangeListener(this); |
| 60 | 82 |
| 61 if (focus_manager) | 83 if (focus_manager) |
| 62 focus_manager->AddFocusChangeListener(this); | 84 focus_manager->AddFocusChangeListener(this); |
| 63 | 85 |
| 64 focus_manager_ = focus_manager; | 86 focus_manager_ = focus_manager; |
| 65 } | 87 } |
| 66 | 88 |
| 89 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { |
| 90 [window_ setFrame:gfx::ScreenRectToNSRect(new_bounds) |
| 91 display:YES |
| 92 animate:NO]; |
| 93 if (layer()) |
| 94 SetLayerSize(new_bounds.size()); |
| 95 } |
| 96 |
| 67 void BridgedNativeWidget::SetRootView(views::View* view) { | 97 void BridgedNativeWidget::SetRootView(views::View* view) { |
| 68 if (view == [bridged_view_ hostedView]) | 98 if (view == [bridged_view_ hostedView]) |
| 69 return; | 99 return; |
| 70 | 100 |
| 101 // If this is ever false, the compositor will need to be properly torn down |
| 102 // and replaced, pointing at the new view. |
| 103 DCHECK(!view || !compositor_view_); |
| 104 |
| 71 [bridged_view_ clearView]; | 105 [bridged_view_ clearView]; |
| 72 bridged_view_.reset(); | 106 bridged_view_.reset(); |
| 73 // Note that there can still be references to the old |bridged_view_| | 107 // Note that there can still be references to the old |bridged_view_| |
| 74 // floating around in Cocoa libraries at this point. However, references to | 108 // floating around in Cocoa libraries at this point. However, references to |
| 75 // the old views::View will be gone, so any method calls will become no-ops. | 109 // the old views::View will be gone, so any method calls will become no-ops. |
| 76 | 110 |
| 77 if (view) { | 111 if (view) { |
| 78 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]); | 112 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]); |
| 79 // Objective C initializers can return nil. However, if |view| is non-NULL | 113 // Objective C initializers can return nil. However, if |view| is non-NULL |
| 80 // this should be treated as an error and caught early. | 114 // this should be treated as an error and caught early. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 98 | 132 |
| 99 ui::InputMethod* BridgedNativeWidget::GetHostInputMethod() { | 133 ui::InputMethod* BridgedNativeWidget::GetHostInputMethod() { |
| 100 if (!input_method_) { | 134 if (!input_method_) { |
| 101 // Delegate is NULL because Mac IME does not need DispatchKeyEventPostIME | 135 // Delegate is NULL because Mac IME does not need DispatchKeyEventPostIME |
| 102 // callbacks. | 136 // callbacks. |
| 103 input_method_ = ui::CreateInputMethod(NULL, nil); | 137 input_method_ = ui::CreateInputMethod(NULL, nil); |
| 104 } | 138 } |
| 105 return input_method_.get(); | 139 return input_method_.get(); |
| 106 } | 140 } |
| 107 | 141 |
| 142 ui::Layer* BridgedNativeWidget::GetOrCreateLayer() { |
| 143 if (!bridged_view_) |
| 144 return NULL; |
| 145 |
| 146 if (layer()) |
| 147 return layer(); |
| 148 |
| 149 [bridged_view_ setWantsLayer:YES]; |
| 150 // Next line does nothing. |
| 151 [[bridged_view_ layer] |
| 152 setBackgroundColor:CGColorGetConstantColor(kCGColorClear)]; |
| 153 |
| 154 SetLayer(new ui::Layer()); |
| 155 layer()->set_delegate(this); |
| 156 DCHECK_EQ(0u, [[bridged_view_ subviews] count]); |
| 157 compositor_view_.reset(new content::BrowserCompositorViewMac(this)); |
| 158 |
| 159 DCHECK(compositor_view_->GetCompositor()); |
| 160 DCHECK_EQ(compositor_view_->GetCompositor(), layer()->GetCompositor()); |
| 161 |
| 162 [window_ setOpaque:NO]; |
| 163 layer()->GetCompositor()->SetHostHasTransparentBackground(true); |
| 164 layer()->SetFillsBoundsCompletely(true); |
| 165 |
| 166 SetLayerSize(native_widget_mac_->GetWindowBoundsInScreen().size()); |
| 167 return layer(); |
| 168 } |
| 169 |
| 108 //////////////////////////////////////////////////////////////////////////////// | 170 //////////////////////////////////////////////////////////////////////////////// |
| 109 // BridgedNativeWidget, internal::InputMethodDelegate: | 171 // BridgedNativeWidget, internal::InputMethodDelegate: |
| 110 | 172 |
| 111 void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) { | 173 void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) { |
| 112 // Mac key events don't go through this, but some unit tests that use | 174 // Mac key events don't go through this, but some unit tests that use |
| 113 // MockInputMethod do. | 175 // MockInputMethod do. |
| 114 DCHECK(focus_manager_); | 176 DCHECK(focus_manager_); |
| 115 native_widget_mac_->GetWidget()->OnKeyEvent(const_cast<ui::KeyEvent*>(&key)); | 177 native_widget_mac_->GetWidget()->OnKeyEvent(const_cast<ui::KeyEvent*>(&key)); |
| 116 if (!key.handled()) | 178 if (!key.handled()) |
| 117 focus_manager_->OnKeyEvent(key); | 179 focus_manager_->OnKeyEvent(key); |
| 118 } | 180 } |
| 119 | 181 |
| 182 //////////////////////////////////////////////////////////////////////////////// |
| 183 // BridgedNativeWidget, content::BrowserCompositorViewMacClient: |
| 184 |
| 185 void BridgedNativeWidget::BrowserCompositorViewFrameSwapped( |
| 186 const std::vector<ui::LatencyInfo>& latency_info) { |
| 187 } |
| 188 |
| 189 NSView* BridgedNativeWidget::BrowserCompositorSuperview() { |
| 190 return bridged_view_; |
| 191 } |
| 192 |
| 193 ui::Layer* BridgedNativeWidget::BrowserCompositorRootLayer() { |
| 194 return layer(); |
| 195 } |
| 196 |
| 197 //////////////////////////////////////////////////////////////////////////////// |
| 198 // BridgedNativeWidget, FocusChangeListener: |
| 199 |
| 120 void BridgedNativeWidget::OnWillChangeFocus(View* focused_before, | 200 void BridgedNativeWidget::OnWillChangeFocus(View* focused_before, |
| 121 View* focused_now) { | 201 View* focused_now) { |
| 122 } | 202 } |
| 123 | 203 |
| 124 void BridgedNativeWidget::OnDidChangeFocus(View* focused_before, | 204 void BridgedNativeWidget::OnDidChangeFocus(View* focused_before, |
| 125 View* focused_now) { | 205 View* focused_now) { |
| 126 ui::TextInputClient* input_client = | 206 ui::TextInputClient* input_client = |
| 127 focused_now ? focused_now->GetTextInputClient() : NULL; | 207 focused_now ? focused_now->GetTextInputClient() : NULL; |
| 128 [bridged_view_ setTextInputClient:input_client]; | 208 [bridged_view_ setTextInputClient:input_client]; |
| 129 } | 209 } |
| 130 | 210 |
| 131 //////////////////////////////////////////////////////////////////////////////// | 211 //////////////////////////////////////////////////////////////////////////////// |
| 212 // BridgedNativeWidget, LayerDelegate: |
| 213 |
| 214 static bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path
, |
| 215 bool discard_transparency) { |
| 216 std::vector<unsigned char> png_data; |
| 217 if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, |
| 218 discard_transparency, |
| 219 &png_data) && |
| 220 base::CreateDirectory(file_path.DirName())) { |
| 221 char* data = reinterpret_cast<char*>(&png_data[0]); |
| 222 int size = static_cast<int>(png_data.size()); |
| 223 bool result = base::WriteFile(file_path, data, size) == size; |
| 224 return result; |
| 225 } |
| 226 return false; |
| 227 } |
| 228 |
| 229 static void ReadbackResult(scoped_ptr<cc::CopyOutputResult> result) { |
| 230 DLOG(INFO) << "result!"; |
| 231 scoped_ptr<SkBitmap> result_bitmap = result->TakeBitmap().Pass(); |
| 232 static int filectr = 0; |
| 233 std::ostringstream oss; |
| 234 oss << "file" << filectr++ << ".png"; |
| 235 WritePNGFile(*result_bitmap, base::FilePath().AppendASCII(oss.str().c_str()),
false); |
| 236 } |
| 237 |
| 238 void BridgedNativeWidget::OnPaintLayer(gfx::Canvas* canvas) { |
| 239 layer()->RequestCopyOfOutput(cc::CopyOutputRequest::CreateBitmapRequest(base::
Bind(&ReadbackResult))); |
| 240 native_widget_mac_->GetWidget()->OnNativeWidgetPaint(canvas); |
| 241 |
| 242 gfx::ImageSkiaRep image = canvas->ExtractImageRep(); |
| 243 static int filectr = 0; |
| 244 std::ostringstream oss; |
| 245 oss << "bpass" << filectr++ << ".png"; |
| 246 WritePNGFile(image.sk_bitmap(), base::FilePath().AppendASCII(oss.str().c_str()
), false); |
| 247 |
| 248 } |
| 249 |
| 250 void BridgedNativeWidget::OnDeviceScaleFactorChanged( |
| 251 float device_scale_factor) { |
| 252 } |
| 253 |
| 254 base::Closure BridgedNativeWidget::PrepareForLayerBoundsChange() { |
| 255 return base::Bind(&BridgedNativeWidget::OnWindowBoundsChanged, |
| 256 base::Unretained(this)); |
| 257 } |
| 258 |
| 259 //////////////////////////////////////////////////////////////////////////////// |
| 132 // BridgedNativeWidget, private: | 260 // BridgedNativeWidget, private: |
| 133 | 261 |
| 134 void BridgedNativeWidget::RemoveOrDestroyChildren() { | 262 void BridgedNativeWidget::RemoveOrDestroyChildren() { |
| 135 // TODO(tapted): Implement unowned child windows if required. | 263 // TODO(tapted): Implement unowned child windows if required. |
| 136 base::scoped_nsobject<NSArray> child_windows( | 264 base::scoped_nsobject<NSArray> child_windows( |
| 137 [[NSArray alloc] initWithArray:[window_ childWindows]]); | 265 [[NSArray alloc] initWithArray:[window_ childWindows]]); |
| 138 [child_windows makeObjectsPerformSelector:@selector(close)]; | 266 [child_windows makeObjectsPerformSelector:@selector(close)]; |
| 139 } | 267 } |
| 140 | 268 |
| 269 void BridgedNativeWidget::SetLayerSize(const gfx::Size& size_in_dip) { |
| 270 DCHECK(layer()); |
| 271 |
| 272 layer()->SetBounds(gfx::Rect(size_in_dip)); |
| 273 |
| 274 float scale_factor = GetDeviceScaleFactorFromDisplay(bridged_view_); |
| 275 gfx::Size size_in_pixels(size_in_dip.width() * scale_factor, |
| 276 size_in_dip.height() * scale_factor); |
| 277 compositor_view_->GetCompositor()->SetScaleAndSize(scale_factor, |
| 278 size_in_pixels); |
| 279 } |
| 280 |
| 281 void BridgedNativeWidget::OnWindowBoundsChanged() { |
| 282 } |
| 283 |
| 141 } // namespace views | 284 } // namespace views |
| OLD | NEW |