Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / content / browser / compositor / browser_compositor_view_mac.mm
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.
4
5 #include "content/browser/compositor/browser_compositor_view_mac.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/mac/scoped_cftyperef.h"
9 #include "content/browser/compositor/gpu_process_transport_factory.h"
10 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
11 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
12 #include "content/browser/renderer_host/software_layer_mac.h"
13 #include "content/public/browser/context_factory.h"
14 #include "ui/base/cocoa/animation_utils.h"
15 #include "ui/gl/scoped_cgl.h"
16
17 @interface BrowserCompositorViewMac (Private)
18 - (void)layerDidDrawFrame;
19 - (void)gotAcceleratedLayerError;
20 @end  // BrowserCompositorViewMac (Private)
21
22 namespace content {
23
24 // The CompositingIOSurfaceLayerClient interface needs to be implemented as a
25 // C++ class to operate on, rather than Objective C class. This helper class
26 // provides a bridge between the two.
27 class BrowserCompositorViewMacHelper : public CompositingIOSurfaceLayerClient {
28  public:
29   BrowserCompositorViewMacHelper(BrowserCompositorViewMac* view)
30       : view_(view) {}
31   virtual ~BrowserCompositorViewMacHelper() {}
32
33  private:
34   // CompositingIOSurfaceLayerClient implementation:
35   virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE {
36     [view_ layerDidDrawFrame];
37     if (!succeeded)
38       [view_ gotAcceleratedLayerError];
39   }
40
41   BrowserCompositorViewMac* view_;
42 };
43
44 }  // namespace content
45
46
47 // The default implementation of additions to the NSView interface for browser
48 // compositing should never be called. Log an error if they are.
49 @implementation NSView (BrowserCompositorView)
50
51 - (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
52                  withOutputSurfaceID:(int)surface_id
53                        withPixelSize:(gfx::Size)pixel_size
54                      withScaleFactor:(float)scale_factor {
55   DLOG(ERROR) << "-[NSView gotAcceleratedIOSurfaceFrame] called on "
56               << "non-overriden class.";
57 }
58
59 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
60          withScaleFactor:(float)scale_factor
61               withCanvas:(SkCanvas*)canvas {
62   DLOG(ERROR) << "-[NSView gotSoftwareFrame] called on non-overridden class.";
63 }
64
65 @end  // NSView (BrowserCompositorView)
66
67 @implementation BrowserCompositorViewMac : NSView
68
69 - (id)initWithSuperview:(NSView*)view {
70   if (self = [super init]) {
71     accelerated_layer_output_surface_id_ = 0;
72     helper_.reset(new content::BrowserCompositorViewMacHelper(self));
73
74     // Disable the fade-in animation as the layer and view are added.
75     ScopedCAActionDisabler disabler;
76
77     // Make this view host a transparent layer.
78     background_layer_.reset([[CALayer alloc] init]);
79     [background_layer_ setContentsGravity:kCAGravityTopLeft];
80     [self setLayer:background_layer_];
81     [self setWantsLayer:YES];
82
83     compositor_.reset(new ui::Compositor(self, content::GetContextFactory()));
84     [view addSubview:self];
85   }
86   return self;
87 }
88
89 - (void)gotAcceleratedLayerError {
90   if (!accelerated_layer_)
91     return;
92
93   [accelerated_layer_ context]->PoisonContextAndSharegroup();
94   compositor_->ScheduleFullRedraw();
95 }
96
97 // This function closely mirrors RenderWidgetHostViewMac::LayoutLayers. When
98 // only delegated rendering is supported, only one copy of this code will
99 // need to exist.
100 - (void)layoutLayers {
101   // Disable animation of the layers' resizing or repositioning.
102   ScopedCAActionDisabler disabler;
103
104   NSSize superview_frame_size = [[self superview] frame].size;
105   [self setFrame:NSMakeRect(
106       0, 0, superview_frame_size.width, superview_frame_size.height)];
107
108   CGRect new_background_frame = CGRectMake(
109       0,
110       0,
111       superview_frame_size.width,
112       superview_frame_size.height);
113   [background_layer_ setFrame:new_background_frame];
114
115   // The bounds of the accelerated layer determine the size of the GL surface
116   // that will be drawn to. Make sure that this is big enough to draw the
117   // IOSurface.
118   if (accelerated_layer_) {
119     CGRect layer_bounds = CGRectMake(
120       0,
121       0,
122       [accelerated_layer_ iosurface]->dip_io_surface_size().width(),
123       [accelerated_layer_ iosurface]->dip_io_surface_size().height());
124     CGPoint layer_position = CGPointMake(
125       0,
126       CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
127     bool bounds_changed = !CGRectEqualToRect(
128         layer_bounds, [accelerated_layer_ bounds]);
129     [accelerated_layer_ setBounds:layer_bounds];
130     [accelerated_layer_ setPosition:layer_position];
131     if (bounds_changed) {
132       [accelerated_layer_ setNeedsDisplay];
133       [accelerated_layer_ displayIfNeeded];
134     }
135   }
136
137   // The content area of the software layer is the size of the image provided.
138   // Make the bounds of the layer match the superview's bounds, to ensure that
139   // the visible contents are drawn.
140   [software_layer_ setBounds:new_background_frame];
141 }
142
143 - (void)resetClient {
144   [accelerated_layer_ resetClient];
145 }
146
147 - (ui::Compositor*)compositor {
148   return compositor_.get();
149 }
150
151 - (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
152                  withOutputSurfaceID:(int)surface_id
153                        withPixelSize:(gfx::Size)pixel_size
154                      withScaleFactor:(float)scale_factor {
155   DCHECK(!accelerated_layer_output_surface_id_);
156   accelerated_layer_output_surface_id_ = surface_id;
157
158   ScopedCAActionDisabler disabler;
159
160   // If there is already an accelerated layer, but it has the wrong scale
161   // factor or it was poisoned, remove the old layer and replace it.
162   base::scoped_nsobject<CompositingIOSurfaceLayer> old_accelerated_layer;
163   if (accelerated_layer_ && (
164           [accelerated_layer_ context]->HasBeenPoisoned() ||
165           [accelerated_layer_ iosurface]->scale_factor() != scale_factor)) {
166     old_accelerated_layer = accelerated_layer_;
167     accelerated_layer_.reset();
168   }
169
170   // If there is not a layer for accelerated frames, create one.
171   if (!accelerated_layer_) {
172     // Disable the fade-in animation as the layer is added.
173     ScopedCAActionDisabler disabler;
174     scoped_refptr<content::CompositingIOSurfaceMac> iosurface =
175         content::CompositingIOSurfaceMac::Create();
176     accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc]
177         initWithIOSurface:iosurface
178           withScaleFactor:scale_factor
179                withClient:helper_.get()]);
180     [[self layer] addSublayer:accelerated_layer_];
181   }
182
183   {
184     bool result = true;
185     gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
186         [accelerated_layer_ context]->cgl_context());
187     result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent(
188         [accelerated_layer_ context], surface_handle, pixel_size, scale_factor);
189     if (!result)
190       LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
191   }
192   [accelerated_layer_ gotNewFrame];
193   [self layoutLayers];
194
195   // If there was a software layer or an old accelerated layer, remove it.
196   // Disable the fade-out animation as the layer is removed.
197   {
198     ScopedCAActionDisabler disabler;
199     [software_layer_ removeFromSuperlayer];
200     software_layer_.reset();
201     [old_accelerated_layer resetClient];
202     [old_accelerated_layer removeFromSuperlayer];
203     old_accelerated_layer.reset();
204   }
205 }
206
207 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
208          withScaleFactor:(float)scale_factor
209               withCanvas:(SkCanvas*)canvas {
210   if (!frame_data || !canvas)
211     return;
212
213   // If there is not a layer for software frames, create one.
214   if (!software_layer_) {
215     // Disable the fade-in animation as the layer is added.
216     ScopedCAActionDisabler disabler;
217     software_layer_.reset([[SoftwareLayer alloc] init]);
218     [[self layer] addSublayer:software_layer_];
219   }
220
221   SkImageInfo info;
222   size_t row_bytes;
223   const void* pixels = canvas->peekPixels(&info, &row_bytes);
224   [software_layer_ setContentsToData:pixels
225                         withRowBytes:row_bytes
226                        withPixelSize:gfx::Size(info.fWidth, info.fHeight)
227                      withScaleFactor:scale_factor];
228   [self layoutLayers];
229
230   // If there was an accelerated layer, remove it.
231   // Disable the fade-out animation as the layer is removed.
232   {
233     ScopedCAActionDisabler disabler;
234     [accelerated_layer_ resetClient];
235     [accelerated_layer_ removeFromSuperlayer];
236     accelerated_layer_.reset();
237   }
238
239   // This call can be nested insider ui::Compositor commit calls, and can also
240   // make additional ui::Compositor commit calls. Avoid the potential recursion
241   // by acknowledging the frame asynchronously.
242   [self performSelector:@selector(layerDidDrawFrame)
243              withObject:nil
244              afterDelay:0];
245 }
246
247 - (void)layerDidDrawFrame {
248   if (!accelerated_layer_output_surface_id_)
249     return;
250
251   content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
252       accelerated_layer_output_surface_id_);
253   accelerated_layer_output_surface_id_ = 0;
254 }
255
256 @end  // BrowserCompositorViewMac