Index: content/browser/renderer_host/render_widget_host_view_mac.mm |
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm |
index df7b9217c9cdb9b61f6cabc2bd1852dedd85f6c8..709e60ece16d83a59b91be3a576936de8b72ed0d 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm |
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm |
@@ -607,8 +607,7 @@ void RenderWidgetHostViewMac::EnsureSoftwareLayer() { |
if (software_layer_ || !use_core_animation_) |
return; |
- software_layer_.reset([[SoftwareLayer alloc] |
- initWithRenderWidgetHostViewMac:this]); |
+ software_layer_.reset([[SoftwareLayer alloc] init]); |
DCHECK(software_layer_); |
// Disable the fade-in animation as the layer is added. |
@@ -868,7 +867,6 @@ void RenderWidgetHostViewMac::WasShown() { |
// Call setNeedsDisplay before pausing for new frames to come in -- if any |
// do, and are drawn, then the needsDisplay bit will be cleared. |
- [software_layer_ setNeedsDisplay]; |
[compositing_iosurface_layer_ setNeedsDisplay]; |
PauseForPendingResizeOrRepaintsAndDraw(); |
@@ -1570,6 +1568,27 @@ void RenderWidgetHostViewMac::CompositorSwapBuffers( |
LayoutLayers(); |
} |
+void RenderWidgetHostViewMac::GotBrowserCompositorSoftwareFrame( |
+ cc::SoftwareFrameData* frame_data, |
+ float scale_factor, |
+ SkCanvas* canvas) { |
+ if (!frame_data || !canvas) |
+ return; |
+ |
+ SkImageInfo info; |
+ size_t row_bytes; |
+ const void* pixels = canvas->peekPixels(&info, &row_bytes); |
+ |
+ EnsureSoftwareLayer(); |
+ [software_layer_ setContentsToData:pixels |
+ withRowBytes:row_bytes |
+ withPixelSize:gfx::Size(info.fWidth, info.fHeight) |
+ withScaleFactor:scale_factor]; |
+ |
+ LayoutLayers(); |
+ DestroyCompositedIOSurfaceAndLayer(kDestroyContext); |
+} |
+ |
void RenderWidgetHostViewMac::DrawIOSurfaceWithoutCoreAnimation() { |
CHECK(!use_core_animation_); |
CHECK(compositing_iosurface_); |
@@ -1893,6 +1912,8 @@ bool RenderWidgetHostViewMac::HasAcceleratedSurface( |
void RenderWidgetHostViewMac::OnSwapCompositorFrame( |
uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) { |
+ TRACE_EVENT0("browser", "RenderWidgetHostViewMac::OnSwapCompositorFrame"); |
+ |
if (frame->delegated_frame_data) { |
if (!compositor_) { |
compositor_.reset(new ui::Compositor(cocoa_view_)); |
@@ -1930,6 +1951,23 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame( |
// Add latency info to report when the frame finishes drawing. |
AddPendingLatencyInfo(frame->metadata.latency_info); |
+ |
+ if (use_core_animation_) { |
+ const void* pixels = software_frame_manager_->GetCurrentFramePixels(); |
+ gfx::Size size_in_pixels = |
+ software_frame_manager_->GetCurrentFrameSizeInPixels(); |
+ |
+ EnsureSoftwareLayer(); |
+ [software_layer_ setContentsToData:pixels |
+ withRowBytes:4 * size_in_pixels.width() |
+ withPixelSize:size_in_pixels |
+ withScaleFactor:frame->metadata.device_scale_factor]; |
+ |
+ // Send latency information to the host immediately, as there will be no |
+ // subsequent draw call in which to do so. |
+ SendPendingLatencyInfoToHost(); |
+ } |
+ |
GotSoftwareFrame(); |
cc::CompositorFrameAck ack; |
@@ -2073,6 +2111,8 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() { |
} |
void RenderWidgetHostViewMac::GotSoftwareFrame() { |
+ TRACE_EVENT0("browser", "RenderWidgetHostViewMac::GotSoftwareFrame"); |
+ |
if (!render_widget_host_) |
return; |
@@ -2084,7 +2124,6 @@ void RenderWidgetHostViewMac::GotSoftwareFrame() { |
// happen before the frame be acked, otherwise the new frame will likely be |
// ready before the drawing is complete, thrashing the browser main thread. |
if (use_core_animation_) { |
- [software_layer_ setNeedsDisplay]; |
[software_layer_ displayIfNeeded]; |
} else { |
[cocoa_view_ setNeedsDisplay:YES]; |
@@ -2329,15 +2368,14 @@ void RenderWidgetHostViewMac::TickPendingLatencyInfoDelay() { |
[compositing_iosurface_layer_ gotNewFrame]; |
} |
if (software_layer_) { |
- // In software mode, setNeedsDisplay will almost immediately result in the |
- // layer's draw function being called, so manually insert a pretend-vsync |
- // at 60 Hz. |
+ // In software mode there is not an explicit setNeedsDisplay/display loop, |
+ // so just wait a pretend-vsync at 60 Hz. |
base::MessageLoop::current()->PostDelayedTask( |
FROM_HERE, |
base::Bind(&RenderWidgetHostViewMac::TickPendingLatencyInfoDelay, |
pending_latency_info_delay_weak_ptr_factory_.GetWeakPtr()), |
base::TimeDelta::FromMilliseconds(1000/60)); |
- [software_layer_ setNeedsDisplay]; |
+ SendPendingLatencyInfoToHost(); |
} |
} |
@@ -2443,17 +2481,6 @@ void RenderWidgetHostViewMac::LayoutLayers() { |
} |
} |
- // Dynamically update the software layer's contents scale to match the |
- // software frame. |
- if (software_frame_manager_->HasCurrentFrame() && |
- [software_layer_ respondsToSelector:(@selector(contentsScale))] && |
- [software_layer_ respondsToSelector:(@selector(setContentsScale:))]) { |
- if (software_frame_manager_->GetCurrentFrameDeviceScaleFactor() != |
- [software_layer_ contentsScale]) { |
- [software_layer_ setContentsScale: |
- software_frame_manager_->GetCurrentFrameDeviceScaleFactor()]; |
- } |
- } |
// Changing the software layer's bounds and position doesn't always result |
// in the layer being anchored to the top-left. Set the layer's frame |
// explicitly, since this is more reliable in practice. |
@@ -2462,7 +2489,6 @@ void RenderWidgetHostViewMac::LayoutLayers() { |
new_background_frame, [software_layer_ frame]); |
if (frame_changed) { |
[software_layer_ setFrame:new_background_frame]; |
- [software_layer_ setNeedsDisplay]; |
} |
} |
} |
@@ -3315,6 +3341,13 @@ SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() { |
params.latency_info); |
} |
+- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data |
+ withScaleFactor:(float)scale_factor |
+ withCanvas:(SkCanvas*)canvas { |
+ renderWidgetHostView_->GotBrowserCompositorSoftwareFrame( |
+ frame_data, scale_factor, canvas); |
+} |
+ |
- (void)drawRect:(NSRect)dirtyRect { |
TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::drawRect"); |
DCHECK(!renderWidgetHostView_->use_core_animation_); |
@@ -4385,38 +4418,54 @@ extern NSString *NSTextInputReplacementRangeAttributeName; |
@implementation SoftwareLayer |
-- (id)initWithRenderWidgetHostViewMac:(content::RenderWidgetHostViewMac*)r { |
+- (id)init { |
if (self = [super init]) { |
- renderWidgetHostView_ = r; |
- |
[self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; |
[self setAnchorPoint:CGPointMake(0, 0)]; |
// Setting contents gravity is necessary to prevent the layer from being |
// scaled during dyanmic resizes (especially with devtools open). |
[self setContentsGravity:kCAGravityTopLeft]; |
- if (renderWidgetHostView_->software_frame_manager_->HasCurrentFrame() && |
- [self respondsToSelector:(@selector(setContentsScale:))]) { |
- [self setContentsScale:renderWidgetHostView_->software_frame_manager_-> |
- GetCurrentFrameDeviceScaleFactor()]; |
- } |
- |
- // Ensure that the transition between frames not be animated. |
- [self setActions:@{ @"contents" : [NSNull null] }]; |
} |
return self; |
} |
-- (void)drawInContext:(CGContextRef)context { |
- TRACE_EVENT0("browser", "SoftwareLayer::drawInContext"); |
+- (void)setContentsToData:(const void *)data |
+ withRowBytes:(size_t)rowBytes |
+ withPixelSize:(gfx::Size)pixelSize |
+ withScaleFactor:(float)scaleFactor { |
+ TRACE_EVENT0("browser", "-[SoftwareLayer setContentsToData]"); |
- CGRect clipRect = CGContextGetClipBoundingBox(context); |
- if (renderWidgetHostView_) { |
- [renderWidgetHostView_->cocoa_view() drawWithDirtyRect:clipRect |
- inContext:context]; |
- } else { |
- CGContextSetFillColorWithColor(context, |
- CGColorGetConstantColor(kCGColorWhite)); |
- CGContextFillRect(context, clipRect); |
+ // Disable animating the contents change or the scale factor change. |
+ ScopedCAActionDisabler disabler; |
+ |
+ // Set the contents of the software CALayer to be a CGImage with the provided |
+ // pixel data. Make a copy of the data before backing the image with them, |
+ // because the same buffer will be reused for the next frame. |
+ base::ScopedCFTypeRef<CFDataRef> dataCopy( |
+ CFDataCreate(NULL, |
+ static_cast<const UInt8 *>(data), |
+ rowBytes * pixelSize.height())); |
+ base::ScopedCFTypeRef<CGDataProviderRef> dataProvider( |
+ CGDataProviderCreateWithCFData(dataCopy)); |
+ base::ScopedCFTypeRef<CGImageRef> image( |
+ CGImageCreate(pixelSize.width(), |
+ pixelSize.height(), |
+ 8, |
+ 32, |
+ rowBytes, |
+ base::mac::GetSystemColorSpace(), |
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, |
+ dataProvider, |
+ NULL, |
+ false, |
+ kCGRenderingIntentDefault)); |
+ [self setContents:(id)image.get()]; |
+ |
+ // Set the contents scale of the software CALayer. |
+ if ([self respondsToSelector:(@selector(contentsScale))] && |
+ [self respondsToSelector:(@selector(setContentsScale:))] && |
+ [self contentsScale] != scaleFactor) { |
+ [self setContentsScale:scaleFactor]; |
} |
} |
@@ -4424,7 +4473,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName; |
// Disable the fade-out animation as the layer is removed. |
ScopedCAActionDisabler disabler; |
[self removeFromSuperlayer]; |
- renderWidgetHostView_ = nil; |
} |
@end // implementation SoftwareLayer |