| Index: ui/views_core/bridged_view_impl_mac.mm
|
| diff --git a/ui/views_core/bridged_view_impl_mac.mm b/ui/views_core/bridged_view_impl_mac.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f1e73ed558c71e845c81e9729be99892cab9d1a2
|
| --- /dev/null
|
| +++ b/ui/views_core/bridged_view_impl_mac.mm
|
| @@ -0,0 +1,242 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import "ui/views_core/bridged_view_impl_mac.h"
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "ui/accessibility/ax_view_state.h"
|
| +#include "ui/base/layout.h"
|
| +#include "ui/gfx/canvas.h"
|
| +#include "ui/gfx/canvas_paint_mac.h"
|
| +#include "ui/gfx/geometry/vector2d_f.h"
|
| +#include "ui/gfx/image/image.h"
|
| +#include "ui/views/view.h"
|
| +#include "ui/views/widget/root_view.h"
|
| +#include "ui/views/widget/widget.h"
|
| +
|
| +#include "base/debug/stack_trace.h"
|
| +
|
| +namespace {
|
| +
|
| +template <class OSTREAM>
|
| +OSTREAM& operator<<(OSTREAM& out, const NSRect& rect) {
|
| + CGFloat x = rect.origin.x;
|
| + CGFloat y = rect.origin.y;
|
| + out << '[' << rect.size.width << 'x' << rect.size.height
|
| + << (x < 0 ? '-' : '+') << x << (y < 0 ? '-' : '+') << y << ']';
|
| + return out;
|
| +}
|
| +
|
| +template <class OSTREAM>
|
| +OSTREAM& operator<<(OSTREAM& out, const NSPoint& point) {
|
| + out << '(' << point.x << ',' << point.y << ')';
|
| + return out;
|
| +}
|
| +
|
| +}
|
| +
|
| +@interface BridgedViewImpl ()
|
| +
|
| +- (void)handleMouseEvent:(NSEvent*)theEvent;
|
| +
|
| +@end
|
| +
|
| +namespace views {
|
| +
|
| +class NSViewNativeWidget : public internal::NativeWidgetPrivate {
|
| +
|
| +};
|
| +
|
| +class NSViewBridgeWidget : public views::Widget {
|
| + public:
|
| + NSViewBridgeWidget(BridgedViewImpl* parent) : parent_(parent) {}
|
| +
|
| + protected:
|
| + // views::Widget:
|
| + virtual internal::RootView* CreateRootView() OVERRIDE;
|
| +
|
| + private:
|
| + BridgedViewImpl* parent_; // Weak. Owns us.
|
| +};
|
| +
|
| +class NSViewBridge : public internal::RootView {
|
| + public:
|
| + NSViewBridge(views::Widget* widget, BridgedViewImpl* parent)
|
| + : internal::RootView(widget),
|
| + parent_(parent) {
|
| + }
|
| +
|
| + protected:
|
| + // views::View:
|
| + virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
|
| + virtual void ViewHierarchyChanged(
|
| + const ViewHierarchyChangedDetails& details) OVERRIDE;
|
| + virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
|
| + virtual void OnVisibleBoundsChanged() OVERRIDE;
|
| + virtual void SchedulePaintInRect(const gfx::Rect& r) OVERRIDE;
|
| +
|
| + private:
|
| + BridgedViewImpl* parent_; // Weak. Owns us.
|
| +};
|
| +
|
| +internal::RootView* NSViewBridgeWidget::CreateRootView() {
|
| + return new NSViewBridge(this, parent_);
|
| +}
|
| +
|
| +void NSViewBridge::OnBoundsChanged(const gfx::Rect& previous_bounds) {
|
| + [parent_ setFrame:NSRectFromCGRect(bounds().ToCGRect())];
|
| +}
|
| +
|
| +void NSViewBridge::ViewHierarchyChanged(
|
| + const ViewHierarchyChangedDetails& details) {
|
| + if (details.is_add && details.parent == this) {
|
| + DCHECK_EQ(1, child_count());
|
| +
|
| + // This is kinda backwards, but we need notification of bounds changes.
|
| + details.child->AddDescendantToNotify(this);
|
| +
|
| + DLOG(INFO) << "NSViewBridge hosting: " << details.child->GetClassName();
|
| + }
|
| +}
|
| +
|
| +void NSViewBridge::ChildPreferredSizeChanged(View* child) {
|
| + SetBoundsRect(child->bounds());
|
| +}
|
| +
|
| +void NSViewBridge::OnVisibleBoundsChanged() {
|
| + ChildPreferredSizeChanged([parent_ view]);
|
| +}
|
| +
|
| +void NSViewBridge::SchedulePaintInRect(const gfx::Rect& r) {
|
| + [parent_ setNeedsDisplay:YES];
|
| +}
|
| +
|
| +} // namespace views
|
| +
|
| +@implementation BridgedViewImpl
|
| +
|
| +- (id)initWithView:(scoped_ptr<views::View>)viewToHost {
|
| + DCHECK(viewToHost);
|
| + CGRect initialFrame = viewToHost->bounds().ToCGRect();
|
| + if ((self = [super initWithFrame:NSRectFromCGRect(initialFrame)])) {
|
| + widget_.reset(new views::NSViewBridgeWidget(self));
|
| + views::Widget::InitParams initParams;
|
| + initParams.type = views::Widget::InitParams::TYPE_CONTROL;
|
| + widget_->Init(initParams);
|
| +
|
| + widget_->GetRootView()->AddChildView(viewToHost.release());
|
| + hostedView_ = widget_->GetRootView()->child_at(0);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (views::View*)view {
|
| + return hostedView_;
|
| +}
|
| +
|
| +- (void)clearView {
|
| + hostedView_ = NULL;
|
| + bridge_.reset();
|
| +}
|
| +
|
| +// BridgedViewImpl private implementation.
|
| +
|
| +- (void)handleMouseEvent:(NSEvent*)theEvent {
|
| + if (!hostedView_)
|
| + return;
|
| +
|
| + ui::MouseEvent event(theEvent);
|
| +
|
| + NSPoint windowLocation = [theEvent locationInWindow];
|
| + NSPoint viewLocation = [self convertPoint:windowLocation fromView:nil];
|
| + event.set_location(event.location() + gfx::Vector2dF(
|
| + viewLocation.x - windowLocation.x,
|
| + viewLocation.y - windowLocation.y));
|
| +
|
| + {
|
| + gfx::Point uiViewLocation = event.location();
|
| + views::View::ConvertPointFromWidget(hostedView_, &uiViewLocation);
|
| +
|
| + DLOG(INFO) << "Forwarding mouse event in " << [self frame]
|
| + << " " << hostedView_->GetClassName() << ":"
|
| + << " window" << windowLocation
|
| + << " view" << viewLocation
|
| + << " ui.Location: " << event.location_f().ToString()
|
| + << " ui.ViewLocation: " << uiViewLocation.ToString();
|
| + }
|
| +
|
| + widget_->OnMouseEvent(&event);
|
| +}
|
| +
|
| +// NSView implementation.
|
| +
|
| +- (void)drawRect:(NSRect)dirtyRect {
|
| + if (!hostedView_)
|
| + return;
|
| +
|
| + DLOG(INFO) << "Painting.";
|
| + gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */);
|
| + hostedView_->Paint(&canvas);
|
| +}
|
| +
|
| +- (void)mouseDown:(NSEvent*)theEvent {
|
| + [self handleMouseEvent:theEvent];
|
| +}
|
| +
|
| +- (void)mouseDragged:(NSEvent*)theEvent {
|
| + [self handleMouseEvent:theEvent];
|
| +}
|
| +
|
| +- (void)mouseUp:(NSEvent*)theEvent {
|
| + [self handleMouseEvent:theEvent];
|
| +}
|
| +
|
| +// NSAccessibility informal protocol implementation.
|
| +
|
| +- (NSArray*)accessibilityAttributeNames {
|
| + NSMutableArray* attributes =
|
| + [[super accessibilityAttributeNames] mutableCopy];
|
| + if (!hostedView_)
|
| + return [attributes autorelease];
|
| +
|
| + [attributes addObject:NSAccessibilityValueAttribute];
|
| + [attributes addObject:NSAccessibilityDescriptionAttribute];
|
| + return [attributes autorelease];
|
| +}
|
| +
|
| +- (id)accessibilityAttributeValue:(NSString*)attribute {
|
| + if (!hostedView_)
|
| + return [super accessibilityAttributeValue:attribute];
|
| +
|
| + ui::AXViewState state;
|
| + hostedView_->GetAccessibleState(&state);
|
| + switch (state.role) {
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +#if 0
|
| + if ([attribute isEqual:NSAccessibilityRoleAttribute])
|
| + return NSAccessibilityTabGroupRole;
|
| + if ([attribute isEqual:NSAccessibilityTabsAttribute]) {
|
| + NSMutableArray* tabs = [[[NSMutableArray alloc] init] autorelease];
|
| + NSArray* children =
|
| + [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
|
| + for (id child in children) {
|
| + if ([[child accessibilityAttributeValue:NSAccessibilityRoleAttribute]
|
| + isEqual:NSAccessibilityRadioButtonRole]) {
|
| + [tabs addObject:child];
|
| + }
|
| + }
|
| + return tabs;
|
| + }
|
| + if ([attribute isEqual:NSAccessibilityContentsAttribute])
|
| + return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
|
| + if ([attribute isEqual:NSAccessibilityValueAttribute])
|
| + return [controller_ activeTabView];
|
| +#endif
|
| +
|
| + return [super accessibilityAttributeValue:attribute];
|
| +}
|
| +
|
| +@end
|
|
|