Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_host_view_mac.mm
index 2138a3b..f807fa2 100644 (file)
@@ -380,6 +380,13 @@ blink::WebScreenInfo GetWebScreenInfo(NSView* view) {
   return results;
 }
 
+void RemoveLayerFromSuperlayer(
+    base::scoped_nsobject<CompositingIOSurfaceLayer> layer) {
+  // Disable the fade-out animation as the layer is removed.
+  ScopedCAActionDisabler disabler;
+  [layer removeFromSuperlayer];
+}
+
 }  // namespace
 
 namespace content {
@@ -573,13 +580,16 @@ void RenderWidgetHostViewMac::EnsureCompositedIOSurfaceLayer() {
   [background_layer_ addSublayer:compositing_iosurface_layer_];
 }
 
-void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceLayer() {
+void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceLayer(
+    DestroyCompositedIOSurfaceLayerBehavior destroy_layer_behavior) {
   if (!compositing_iosurface_layer_)
     return;
 
-  // Disable the fade-out animation as the layer is removed.
-  ScopedCAActionDisabler disabler;
-  [compositing_iosurface_layer_ removeFromSuperlayer];
+  if (destroy_layer_behavior == kRemoveLayerFromHierarchy) {
+    // Disable the fade-out animation as the layer is removed.
+    ScopedCAActionDisabler disabler;
+    [compositing_iosurface_layer_ removeFromSuperlayer];
+  }
   [compositing_iosurface_layer_ disableCompositing];
   compositing_iosurface_layer_.reset();
 }
@@ -589,7 +599,7 @@ void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer(
   // Any pending frames will not be displayed, so ack them now.
   SendPendingSwapAck();
 
-  DestroyCompositedIOSurfaceLayer();
+  DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
   compositing_iosurface_.reset();
 
   switch (destroy_context_behavior) {
@@ -1354,6 +1364,19 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
 
   AddPendingLatencyInfo(latency_info);
 
+  // If compositing_iosurface_ exists and has been poisoned, destroy it
+  // and allow EnsureCompositedIOSurface to recreate it below. Keep a
+  // reference to the destroyed layer around until after the below call
+  // to LayoutLayers, to avoid flickers.
+  base::ScopedClosureRunner scoped_layer_remover;
+  if (compositing_iosurface_context_ &&
+      compositing_iosurface_context_->HasBeenPoisoned()) {
+    scoped_layer_remover.Reset(
+        base::Bind(RemoveLayerFromSuperlayer, compositing_iosurface_layer_));
+    DestroyCompositedIOSurfaceLayer(kLeaveLayerInHierarchy);
+    DestroyCompositedIOSurfaceAndLayer(kDestroyContext);
+  }
+
   // Ensure compositing_iosurface_ and compositing_iosurface_context_ be
   // allocated.
   if (!EnsureCompositedIOSurface()) {
@@ -1363,13 +1386,15 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
 
   // Make the context current and update the IOSurface with the handle
   // passed in by the swap command.
-  gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
-      compositing_iosurface_context_->cgl_context());
-  if (!compositing_iosurface_->SetIOSurfaceWithContextCurrent(
-          compositing_iosurface_context_, surface_handle, size,
-          surface_scale_factor)) {
-    LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
-    return;
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        compositing_iosurface_context_->cgl_context());
+    if (!compositing_iosurface_->SetIOSurfaceWithContextCurrent(
+            compositing_iosurface_context_, surface_handle, size,
+            surface_scale_factor)) {
+      LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
+      return;
+    }
   }
 
   // Grab video frames now that the IOSurface has been set up. Note that this
@@ -1384,12 +1409,14 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
                                               &frame, &callback)) {
       // Flush the context that updated the IOSurface, to ensure that the
       // context that does the copy picks up the correct version.
-      glFlush();
+      {
+        gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+            compositing_iosurface_context_->cgl_context());
+        glFlush();
+      }
       compositing_iosurface_->CopyToVideoFrame(
           gfx::Rect(size), frame,
           base::Bind(callback, present_time));
-      DCHECK_EQ(CGLGetCurrentContext(),
-                compositing_iosurface_context_->cgl_context());
       frame_was_captured = true;
     }
   }
@@ -1447,9 +1474,15 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers(
     compositing_iosurface_layer_async_timer_.Reset();
     [compositing_iosurface_layer_ gotNewFrame];
   } else {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        compositing_iosurface_context_->cgl_context());
     DrawIOSurfaceWithoutCoreAnimation();
   }
 
+  // Try to finish previous copy requests after draw to get better pipelining.
+  if (compositing_iosurface_)
+    compositing_iosurface_->CheckIfAllCopiesAreFinished(false);
+
   // The IOSurface's size may have changed, so re-layout the layers to take
   // this into account. This may force an immediate draw.
   LayoutLayers();
@@ -1557,15 +1590,15 @@ void RenderWidgetHostViewMac::DestroyCompositingStateOnError() {
 
 void RenderWidgetHostViewMac::SetOverlayView(
     RenderWidgetHostViewMac* overlay, const gfx::Point& offset) {
-  if (use_core_animation_)
-    return;
-
   if (overlay_view_)
     overlay_view_->underlay_view_.reset();
 
   overlay_view_ = overlay->overlay_view_weak_factory_.GetWeakPtr();
-  overlay_view_offset_ = offset;
   overlay_view_->underlay_view_ = overlay_view_weak_factory_.GetWeakPtr();
+  if (use_core_animation_)
+    return;
+
+  overlay_view_offset_ = offset;
   overlay_view_->underlay_view_has_drawn_ = false;
 
   [cocoa_view_ setNeedsDisplay:YES];
@@ -1573,13 +1606,13 @@ void RenderWidgetHostViewMac::SetOverlayView(
 }
 
 void RenderWidgetHostViewMac::RemoveOverlayView() {
-  if (use_core_animation_)
-    return;
-
   if (overlay_view_) {
     overlay_view_->underlay_view_.reset();
     overlay_view_.reset();
   }
+  if (use_core_animation_)
+    return;
+
   [cocoa_view_ setNeedsDisplay:YES];
   [[cocoa_view_ window] disableScreenUpdatesUntilFlush];
 }
@@ -2028,7 +2061,7 @@ void RenderWidgetHostViewMac::WindowFrameChanged() {
         GetViewBounds()));
   }
 
-  if (compositing_iosurface_) {
+  if (compositing_iosurface_ && !use_core_animation_) {
     // This will migrate the context to the appropriate window.
     if (!EnsureCompositedIOSurface())
       GotAcceleratedCompositingError();
@@ -2188,6 +2221,16 @@ void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() {
   if (!render_widget_host_ || render_widget_host_->is_hidden())
     return;
 
+  // Pausing for the overlay view prevents the underlay from receiving
+  // frames. This may lead to large delays, causing overlaps. If both
+  // overlay and underlay resize at the same time, let them both to have
+  // some time waiting. See crbug.com/352020.
+  if (underlay_view_ &&
+      underlay_view_->render_widget_host_ &&
+      !underlay_view_->render_widget_host_->
+          CanPauseForPendingResizeOrRepaints())
+    return;
+
   // Ensure that all frames are acked before waiting for a frame to come in.
   // Note that we will draw a frame at the end of this function, so it is safe
   // to ack a never-drawn frame here.
@@ -2221,11 +2264,13 @@ void RenderWidgetHostViewMac::LayoutLayers() {
           respondsToSelector:(@selector(contentsScale))]) {
     if (compositing_iosurface_->scale_factor() !=
         [compositing_iosurface_layer_ contentsScale]) {
-      DestroyCompositedIOSurfaceLayer();
+      DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
       EnsureCompositedIOSurfaceLayer();
     }
   }
-  if (compositing_iosurface_ && compositing_iosurface_layer_) {
+  if (compositing_iosurface_ &&
+      compositing_iosurface_->HasIOSurface() &&
+      compositing_iosurface_layer_) {
     CGRect layer_bounds = CGRectMake(
       0,
       0,
@@ -2267,7 +2312,12 @@ void RenderWidgetHostViewMac::LayoutLayers() {
   // in the layer being anchored to the top-left. Set the layer's frame
   // explicitly, since this is more reliable in practice.
   if (software_layer_) {
-    [software_layer_ setFrame:new_background_frame];
+    bool frame_changed = !CGRectEqualToRect(
+        new_background_frame, [software_layer_ frame]);
+    if (frame_changed) {
+      [software_layer_ setFrame:new_background_frame];
+      [software_layer_ setNeedsDisplay];
+    }
   }
 }