Use a separate NSView to draw browser composited content
[chromium-blink-merge.git] / content / browser / compositor / browser_compositor_view_mac.mm
blob5ebeddd077511dd59c7cb0ad3199f0bb22c4d9b9
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
3 // found in the LICENSE file.
5 #include "content/browser/compositor/browser_compositor_view_mac.h"
7 #include "base/debug/trace_event.h"
8 #include "base/mac/scoped_cftyperef.h"
9 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
10 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
11 #include "content/browser/renderer_host/software_layer_mac.h"
12 #include "ui/base/cocoa/animation_utils.h"
13 #include "ui/gl/scoped_cgl.h"
15 // The default implementation of additions to the NSView interface for browser
16 // compositing should never be called. Log an error if they are.
17 @implementation NSView (BrowserCompositorView)
19 - (void)gotAcceleratedIOSurfaceFrame:(uint64)surface_handle
20                        withPixelSize:(gfx::Size)pixel_size
21                      withScaleFactor:(float)scale_factor {
22   DLOG(ERROR) << "-[NSView gotAcceleratedIOSurfaceFrame] called on "
23               << "non-overriden class.";
26 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
27          withScaleFactor:(float)scale_factor
28               withCanvas:(SkCanvas*)canvas {
29   DLOG(ERROR) << "-[NSView gotSoftwareFrame] called on non-overridden class.";
32 @end  // NSView (BrowserCompositorView)
34 @implementation BrowserCompositorViewMac : NSView
36 - (id)initWithSuperview:(NSView*)view {
37   if (self = [super init]) {
38     // Disable the fade-in animation as the layer and view are added.
39     ScopedCAActionDisabler disabler;
41     // Make this view host a transparent layer.
42     background_layer_.reset([[CALayer alloc] init]);
43     [background_layer_ setContentsGravity:kCAGravityTopLeft];
44     [self setLayer:background_layer_];
45     [self setWantsLayer:YES];
47     compositor_.reset(new ui::Compositor(self));
48     [view addSubview:self];
49   }
50   return self;
53 // This function closely mirrors RenderWidgetHostViewMac::LayoutLayers. When
54 // only delegated rendering is supported, only one copy of this code will
55 // need to exist.
56 - (void)layoutLayers {
57   // Disable animation of the layers' resizing or repositioning.
58   ScopedCAActionDisabler disabler;
60   NSSize superview_frame_size = [[self superview] frame].size;
61   [self setFrame:NSMakeRect(
62       0, 0, superview_frame_size.width, superview_frame_size.height)];
64   CGRect new_background_frame = CGRectMake(
65       0,
66       0,
67       superview_frame_size.width,
68       superview_frame_size.height);
69   [background_layer_ setFrame:new_background_frame];
71   // The bounds of the accelerated layer determine the size of the GL surface
72   // that will be drawn to. Make sure that this is big enough to draw the
73   // IOSurface.
74   if (accelerated_layer_) {
75     CGRect layer_bounds = CGRectMake(
76       0,
77       0,
78       [accelerated_layer_ iosurface]->dip_io_surface_size().width(),
79       [accelerated_layer_ iosurface]->dip_io_surface_size().height());
80     CGPoint layer_position = CGPointMake(
81       0,
82       CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
83     bool bounds_changed = !CGRectEqualToRect(
84         layer_bounds, [accelerated_layer_ bounds]);
85     [accelerated_layer_ setBounds:layer_bounds];
86     [accelerated_layer_ setPosition:layer_position];
87     if (bounds_changed) {
88       [accelerated_layer_ setNeedsDisplay];
89       [accelerated_layer_ displayIfNeeded];
90     }
91   }
93   // The content area of the software layer is the size of the image provided.
94   // Make the bounds of the layer match the superview's bounds, to ensure that
95   // the visible contents are drawn.
96   [software_layer_ setBounds:new_background_frame];
99 - (ui::Compositor*)compositor {
100   return compositor_.get();
103 - (void)gotAcceleratedIOSurfaceFrame:(uint64)surface_handle
104                        withPixelSize:(gfx::Size)pixel_size
105                      withScaleFactor:(float)scale_factor {
106   ScopedCAActionDisabler disabler;
108   // If there is not a layer for accelerated frames, create one.
109   if (!accelerated_layer_) {
110     // Disable the fade-in animation as the layer is added.
111     ScopedCAActionDisabler disabler;
112     scoped_refptr<content::CompositingIOSurfaceMac> iosurface =
113         content::CompositingIOSurfaceMac::Create();
114     accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc]
115         initWithIOSurface:iosurface
116                withClient:NULL]);
117     [[self layer] addSublayer:accelerated_layer_];
118   }
120   {
121     bool result = true;
122     gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
123         [accelerated_layer_ context]->cgl_context());
124     result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent(
125         [accelerated_layer_ context], surface_handle, pixel_size, scale_factor);
126     // TODO(ccameron): On failure, poison the GL context, tear down the layers,
127     // and request a new frame.
128     ignore_result(result);
129   }
130   [accelerated_layer_ gotNewFrame];
131   [self layoutLayers];
133   // If there was a software layer, remove it.
134   if (software_layer_) {
135     // Disable the fade-out animation as the layer is removed.
136     ScopedCAActionDisabler disabler;
137     [software_layer_ removeFromSuperlayer];
138     software_layer_.reset();
139   }
142 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
143          withScaleFactor:(float)scale_factor
144               withCanvas:(SkCanvas*)canvas {
145   if (!frame_data || !canvas)
146     return;
148   // If there is not a layer for software frames, create one.
149   if (!software_layer_) {
150     // Disable the fade-in animation as the layer is added.
151     ScopedCAActionDisabler disabler;
152     software_layer_.reset([[SoftwareLayer alloc] init]);
153     [[self layer] addSublayer:software_layer_];
154   }
156   SkImageInfo info;
157   size_t row_bytes;
158   const void* pixels = canvas->peekPixels(&info, &row_bytes);
159   [software_layer_ setContentsToData:pixels
160                         withRowBytes:row_bytes
161                        withPixelSize:gfx::Size(info.fWidth, info.fHeight)
162                      withScaleFactor:scale_factor];
163   [self layoutLayers];
165   // If there was an accelerated layer, remove it.
166   if (accelerated_layer_) {
167     // Disable the fade-out animation as the layer is removed.
168     ScopedCAActionDisabler disabler;
169     [accelerated_layer_ removeFromSuperlayer];
170     accelerated_layer_.reset();
171   }
174 @end  // BrowserCompositorViewMac