| Index: ui/views/cocoa/bridged_native_widget.mm
|
| diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
|
| index 560f533009df6cd8efb4132130a2ed2640e7074a..9ad0ffeda8afae70ba847ce2b95d392568aa8191 100644
|
| --- a/ui/views/cocoa/bridged_native_widget.mm
|
| +++ b/ui/views/cocoa/bridged_native_widget.mm
|
| @@ -10,7 +10,9 @@
|
| #include "ui/base/ime/input_method.h"
|
| #include "ui/base/ime/input_method_factory.h"
|
| #include "ui/base/ui_base_switches_util.h"
|
| +#include "ui/gfx/display.h"
|
| #import "ui/gfx/mac/coordinate_conversion.h"
|
| +#include "ui/gfx/screen.h"
|
| #import "ui/views/cocoa/bridged_content_view.h"
|
| #import "ui/views/cocoa/views_nswindow_delegate.h"
|
| #include "ui/views/widget/native_widget_mac.h"
|
| @@ -19,13 +21,35 @@
|
| #include "ui/views/view.h"
|
| #include "ui/views/widget/widget.h"
|
|
|
| +#include "base/bind.h"
|
| +
|
| +#include "cc/output/copy_output_request.h"
|
| +#include "cc/output/copy_output_result.h"
|
| +
|
| +#include "third_party/skia/include/core/SkBitmap.h"
|
| +#include "ui/gfx/codec/png_codec.h"
|
| +#include "ui/gfx/image/image_skia_rep.h"
|
| +#include "ui/gfx/canvas.h"
|
| +
|
| +namespace {
|
| +
|
| +float GetDeviceScaleFactorFromDisplay(NSView* view) {
|
| + gfx::Display display = gfx::Screen::GetScreenFor(view)->
|
| + GetDisplayNearestWindow(view);
|
| + DCHECK(display.is_valid());
|
| + return display.device_scale_factor();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace views {
|
|
|
| BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
|
| : native_widget_mac_(parent),
|
| focus_manager_(NULL),
|
| target_fullscreen_state_(false),
|
| - in_fullscreen_transition_(false) {
|
| + in_fullscreen_transition_(false),
|
| + window_visible_(false) {
|
| DCHECK(parent);
|
| window_delegate_.reset(
|
| [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
|
| @@ -50,6 +74,18 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
|
| window_.swap(window);
|
| [window_ setDelegate:window_delegate_];
|
|
|
| + // Register for application hide notifications so that visibility can be
|
| + // properly tracked. This is not done in the delegate so that the lifetime is
|
| + // tied to the C++ object, rather than the delegate (which may be reference
|
| + // counted). This is required since the application hides do not send an
|
| + // orderOut: to individual windows. Unhide, however, does send an order
|
| + // message.
|
| + [[NSNotificationCenter defaultCenter]
|
| + addObserver:window_delegate_
|
| + selector:@selector(onWindowOrderChanged:)
|
| + name:NSApplicationDidHideNotification
|
| + object:nil];
|
| +
|
| // Validate the window's initial state, otherwise the bridge's initial
|
| // tracking state will be incorrect.
|
| DCHECK(![window_ isVisible]);
|
| @@ -59,6 +95,13 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
|
| // Use NSWindow to manage child windows. This won't automatically close them
|
| // but it will maintain relative positioning of the window layer and origin.
|
| [[params.parent window] addChildWindow:window_ ordered:NSWindowAbove];
|
| +
|
| + // Windows with a parent that are not explicitly child windows are transient
|
| + // children.
|
| + if (!params.child) {
|
| + [window setExcludedFromWindowsMenu:YES];
|
| + [window_delegate_ setTransientChild:YES];
|
| + }
|
| }
|
| }
|
|
|
| @@ -75,10 +118,24 @@ void BridgedNativeWidget::SetFocusManager(FocusManager* focus_manager) {
|
| focus_manager_ = focus_manager;
|
| }
|
|
|
| +void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
|
| + [window_ setFrame:gfx::ScreenRectToNSRect(new_bounds)
|
| + display:YES
|
| + animate:NO];
|
| +
|
| + // If not visible, -[NSWindowDelegate windowDidResize:] is not triggered.
|
| + if (![window_ isVisible])
|
| + OnSizeChanged();
|
| +}
|
| +
|
| void BridgedNativeWidget::SetRootView(views::View* view) {
|
| if (view == [bridged_view_ hostedView])
|
| return;
|
|
|
| + // If this is ever false, the compositor will need to be properly torn down
|
| + // and replaced, pointing at the new view.
|
| + DCHECK(!view || !compositor_view_);
|
| +
|
| [bridged_view_ clearView];
|
| bridged_view_.reset();
|
| // Note that there can still be references to the old |bridged_view_|
|
| @@ -97,6 +154,7 @@ void BridgedNativeWidget::SetRootView(views::View* view) {
|
| void BridgedNativeWidget::OnWindowWillClose() {
|
| [[window_ parentWindow] removeChildWindow:window_];
|
| [window_ setDelegate:nil];
|
| + [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
|
| native_widget_mac_->OnWindowWillClose();
|
| }
|
|
|
| @@ -155,6 +213,28 @@ void BridgedNativeWidget::ToggleDesiredFullscreenState() {
|
| [window_ setCollectionBehavior:behavior];
|
| }
|
|
|
| +void BridgedNativeWidget::OnSizeChanged() {
|
| + NSSize new_size = [window_ frame].size;
|
| + native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(
|
| + gfx::Size(new_size.width, new_size.height));
|
| + if (layer())
|
| + SetLayerSize(native_widget_mac_->GetClientAreaBoundsInScreen().size());
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnVisibilityChanged() {
|
| + OnSizeChanged();
|
| + if (window_visible_ == [window_ isVisible])
|
| + return;
|
| +
|
| + window_visible_ = [window_ isVisible];
|
| + native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
|
| + window_visible_);
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnDisplayChanged() {
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| InputMethod* BridgedNativeWidget::CreateInputMethod() {
|
| if (switches::IsTextInputFocusManagerEnabled())
|
| return new NullInputMethod();
|
| @@ -178,6 +258,35 @@ gfx::Rect BridgedNativeWidget::GetRestoredBounds() const {
|
| return gfx::ScreenRectFromNSRect([window_ frame]);
|
| }
|
|
|
| +ui::Layer* BridgedNativeWidget::GetOrCreateLayer() {
|
| + if (!bridged_view_)
|
| + return NULL;
|
| +
|
| + if (layer())
|
| + return layer();
|
| +
|
| + NSView* host_view = BrowserCompositorSuperview();
|
| + [host_view setWantsLayer:YES];
|
| + // Next line does nothing.
|
| + [[host_view layer] setBackgroundColor:CGColorGetConstantColor(kCGColorClear)];
|
| +
|
| + SetLayer(new ui::Layer());
|
| + layer()->set_delegate(this);
|
| + // DCHECK_EQ(0u, [[bridged_view_ subviews] count]);
|
| + compositor_view_.reset(new content::BrowserCompositorViewMac(this));
|
| +
|
| + DCHECK(compositor_view_->GetCompositor());
|
| + DCHECK_EQ(compositor_view_->GetCompositor(), layer()->GetCompositor());
|
| +
|
| + [window_ setOpaque:NO];
|
| + layer()->GetCompositor()->SetHostHasTransparentBackground(true);
|
| + layer()->SetFillsBoundsCompletely(true);
|
| +
|
| + SetLayerSize(native_widget_mac_->GetClientAreaBoundsInScreen().size());
|
| +
|
| + return layer();
|
| +}
|
| +
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // BridgedNativeWidget, internal::InputMethodDelegate:
|
|
|
| @@ -190,6 +299,38 @@ void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
|
| focus_manager_->OnKeyEvent(key);
|
| }
|
|
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// BridgedNativeWidget, content::BrowserCompositorViewMacClient:
|
| +
|
| +bool BridgedNativeWidget::BrowserCompositorViewShouldAckImmediately() const {
|
| + return false;
|
| +}
|
| +
|
| +void BridgedNativeWidget::BrowserCompositorViewFrameSwapped(
|
| + const std::vector<ui::LatencyInfo>& latency_info) {
|
| +}
|
| +
|
| +NSView* BridgedNativeWidget::BrowserCompositorSuperview() {
|
| + if (!compositor_superview_) {
|
| + compositor_superview_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
|
| + if ([[bridged_view_ subviews] count] == 0) {
|
| + [bridged_view_ addSubview:compositor_superview_];
|
| + } else {
|
| + [bridged_view_ addSubview:compositor_superview_
|
| + positioned:NSWindowBelow
|
| + relativeTo:[[bridged_view_ subviews] objectAtIndex:0]];
|
| + }
|
| + }
|
| + return compositor_superview_;
|
| +}
|
| +
|
| +ui::Layer* BridgedNativeWidget::BrowserCompositorRootLayer() {
|
| + return layer();
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// BridgedNativeWidget, FocusChangeListener:
|
| +
|
| void BridgedNativeWidget::OnWillChangeFocus(View* focused_before,
|
| View* focused_now) {
|
| }
|
| @@ -202,6 +343,61 @@ void BridgedNativeWidget::OnDidChangeFocus(View* focused_before,
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| +// BridgedNativeWidget, LayerDelegate:
|
| +
|
| +static bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path,
|
| + bool discard_transparency) {
|
| + std::vector<unsigned char> png_data;
|
| + if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
|
| + discard_transparency,
|
| + &png_data) &&
|
| + base::CreateDirectory(file_path.DirName())) {
|
| + char* data = reinterpret_cast<char*>(&png_data[0]);
|
| + int size = static_cast<int>(png_data.size());
|
| + bool result = base::WriteFile(file_path, data, size) == size;
|
| + return result;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +static void ReadbackResult(scoped_ptr<cc::CopyOutputResult> result) {
|
| + return;
|
| + DLOG(INFO) << "result!";
|
| + scoped_ptr<SkBitmap> result_bitmap = result->TakeBitmap().Pass();
|
| + static int filectr = 0;
|
| + std::ostringstream oss;
|
| + oss << "file" << filectr++ << ".png";
|
| + WritePNGFile(*result_bitmap, base::FilePath().AppendASCII(oss.str().c_str()), false);
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnPaintLayer(gfx::Canvas* canvas) {
|
| + native_widget_mac_->GetWidget()->OnNativeWidgetPaint(canvas);
|
| +return;
|
| + layer()->RequestCopyOfOutput(cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(&ReadbackResult)));
|
| + native_widget_mac_->GetWidget()->OnNativeWidgetPaint(canvas);
|
| + gfx::ImageSkiaRep image = canvas->ExtractImageRep();
|
| + static int filectr = 0;
|
| + std::ostringstream oss;
|
| + oss << "bpass" << filectr++ << ".png";
|
| + WritePNGFile(image.sk_bitmap(), base::FilePath().AppendASCII(oss.str().c_str()), false);
|
| +
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnDelegatedFrameDamage(
|
| + const gfx::Rect& damage_rect_in_dip) {
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnDeviceScaleFactorChanged(
|
| + float device_scale_factor) {
|
| +}
|
| +
|
| +base::Closure BridgedNativeWidget::PrepareForLayerBoundsChange() {
|
| + return base::Bind(&BridgedNativeWidget::OnWindowBoundsChanged,
|
| + base::Unretained(this));
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| // BridgedNativeWidget, private:
|
|
|
| void BridgedNativeWidget::RemoveOrDestroyChildren() {
|
| @@ -211,4 +407,25 @@ void BridgedNativeWidget::RemoveOrDestroyChildren() {
|
| [child_windows makeObjectsPerformSelector:@selector(close)];
|
| }
|
|
|
| +void BridgedNativeWidget::SetLayerSize(const gfx::Size& size_in_dip) {
|
| + DLOG(INFO) << "SetLayerSize: " << size_in_dip.ToString();
|
| + DCHECK(layer());
|
| + DCHECK(compositor_superview_);
|
| +
|
| + layer()->SetBounds(gfx::Rect(size_in_dip));
|
| + NSRect view_frame = [compositor_superview_ frame];
|
| + view_frame.size.width = size_in_dip.width();
|
| + view_frame.size.height = size_in_dip.height();
|
| + [compositor_superview_ setFrame:view_frame];
|
| +
|
| + float scale_factor = GetDeviceScaleFactorFromDisplay(compositor_superview_);
|
| + gfx::Size size_in_pixels(size_in_dip.width() * scale_factor,
|
| + size_in_dip.height() * scale_factor);
|
| + compositor_view_->GetCompositor()->SetScaleAndSize(scale_factor,
|
| + size_in_pixels);
|
| +}
|
| +
|
| +void BridgedNativeWidget::OnWindowBoundsChanged() {
|
| +}
|
| +
|
| } // namespace views
|
|
|