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 04051758b6540a2c48e5c62ad6282fb8ce251968..d8ee48152ed56a186637bcfd8ec921b32322cbec 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm |
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm |
@@ -420,6 +420,8 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) |
last_frame_was_accelerated_(false), |
text_input_type_(ui::TEXT_INPUT_TYPE_NONE), |
can_compose_inline_(true), |
+ software_framebuffer_(new SoftwareFramebuffer( |
+ this, RenderWidgetHostImpl::From(widget))), |
allow_overlapping_views_(false), |
use_core_animation_(false), |
is_loading_(false), |
@@ -734,6 +736,7 @@ void RenderWidgetHostViewMac::WasShown() { |
web_contents_switch_paint_time_ = base::TimeTicks::Now(); |
is_hidden_ = false; |
render_widget_host_->WasShown(); |
+ software_framebuffer_->WasShown(); |
// We're messing with the window, so do this to ensure no flashes. |
if (!use_core_animation_) |
@@ -758,6 +761,7 @@ void RenderWidgetHostViewMac::WasHidden() { |
// If we have a renderer, then inform it that we are being hidden so it can |
// reduce its resource utilization. |
render_widget_host_->WasHidden(); |
+ software_framebuffer_->WasHidden(); |
// There can be a transparent flash as this view is removed and the next is |
// added, because of OSX windowing races between displaying the contents of |
@@ -1221,6 +1225,24 @@ void RenderWidgetHostViewMac::EndFrameSubscription() { |
frame_subscriber_.reset(); |
} |
+void RenderWidgetHostViewMac::OnSwapCompositorFrame( |
+ uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) { |
+ // Only software compositor frames are accepted. |
+ if (!frame->software_frame_data) { |
+ render_widget_host_->GetProcess()->ReceivedBadMessage(); |
+ return; |
+ } |
+ |
+ GotSoftwareFrame(); |
+ |
+ software_framebuffer_->SwapToNewFrame( |
+ output_surface_id, |
+ frame->software_frame_data.get(), |
+ frame->metadata.device_scale_factor); |
+ |
+ [cocoa_view_ setNeedsDisplay:YES]; |
+} |
+ |
// Sets whether or not to accept first responder status. |
void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { |
[cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; |
@@ -1657,11 +1679,18 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() { |
bool RenderWidgetHostViewMac::HasAcceleratedSurface( |
const gfx::Size& desired_size) { |
- return last_frame_was_accelerated_ && |
- compositing_iosurface_ && |
- compositing_iosurface_->HasIOSurface() && |
- (desired_size.IsEmpty() || |
- compositing_iosurface_->dip_io_surface_size() == desired_size); |
+ if (last_frame_was_accelerated_) { |
+ return (compositing_iosurface_ && |
+ compositing_iosurface_->HasIOSurface() && |
+ (desired_size.IsEmpty() || |
+ compositing_iosurface_->dip_io_surface_size() == desired_size)); |
+ } else { |
+ return (software_framebuffer_->HasCurrentFrame() && |
+ (desired_size.IsEmpty() || |
+ software_framebuffer_->GetCurrentFrameSizeInDIP() == |
+ desired_size)); |
+ } |
+ return false; |
} |
void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() { |
@@ -1771,6 +1800,9 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() { |
// Delete software backingstore. |
BackingStoreManager::RemoveBackingStore(render_widget_host_); |
+ |
+ // Delete the software compositing frame if one exists. |
+ software_framebuffer_->DiscardCurrentFrame(); |
} |
} |
@@ -2724,29 +2756,63 @@ void RenderWidgetHostViewMac::FrameSwapped() { |
- (void)drawBackingStore:(BackingStoreMac*)backingStore |
dirtyRect:(CGRect)dirtyRect |
inContext:(CGContextRef)context { |
- if (backingStore) { |
+ content::SoftwareFramebuffer* software_framebuffer = |
+ renderWidgetHostView_->software_framebuffer_->HasCurrentFrame() ? |
+ renderWidgetHostView_->software_framebuffer_.get() : NULL; |
+ DCHECK(!backingStore || !software_framebuffer); |
+ |
+ if (backingStore || software_framebuffer) { |
// Note: All coordinates are in view units, not pixels. |
- gfx::Rect bitmapRect(0, 0, |
- backingStore->size().width(), |
- backingStore->size().height()); |
+ gfx::Rect bitmapRect(software_framebuffer ? |
+ software_framebuffer->GetCurrentFrameSizeInDIP() : |
+ backingStore->size()); |
// Specify the proper y offset to ensure that the view is rooted to the |
// upper left corner. This can be negative, if the window was resized |
// smaller and the renderer hasn't yet repainted. |
- int yOffset = NSHeight([self bounds]) - backingStore->size().height(); |
+ int yOffset = NSHeight([self bounds]) - bitmapRect.height(); |
NSRect nsDirtyRect = NSRectFromCGRect(dirtyRect); |
const gfx::Rect damagedRect([self flipNSRectToRect:nsDirtyRect]); |
gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect); |
if (!paintRect.IsEmpty()) { |
- // if we have a CGLayer, draw that into the window |
- if (backingStore->cg_layer()) { |
+ if (software_framebuffer) { |
+ // If a software compositor framebuffer is present, draw using that. |
+ gfx::Size sizeInPixels = |
+ software_framebuffer->GetCurrentFrameSizeInPixels(); |
+ |
+ base::ScopedCFTypeRef<CGDataProviderRef> dataProvider( |
+ CGDataProviderCreateWithData( |
+ NULL, |
+ software_framebuffer->GetCurrentFramePixels(), |
+ 4 * sizeInPixels.width() * sizeInPixels.height(), |
+ NULL)); |
+ |
+ base::ScopedCFTypeRef<CGImageRef> image( |
+ CGImageCreate( |
+ sizeInPixels.width(), |
+ sizeInPixels.height(), |
+ 8, |
+ 32, |
+ 4 * sizeInPixels.width(), |
+ base::mac::GetSystemColorSpace(), |
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, |
+ dataProvider, |
+ NULL, |
+ false, |
+ kCGRenderingIntentDefault)); |
+ |
+ CGRect imageRect = bitmapRect.ToCGRect(); |
+ imageRect.origin.y = yOffset; |
+ CGContextDrawImage(context, imageRect, image); |
+ } else if (backingStore->cg_layer()) { |
+ // If we have a CGLayer, draw that into the window |
// TODO: add clipping to dirtyRect if it improves drawing performance. |
CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset), |
backingStore->cg_layer()); |
} else { |
- // if we haven't created a layer yet, draw the cached bitmap into |
+ // If we haven't created a layer yet, draw the cached bitmap into |
// the window. The CGLayer will be created the next time the renderer |
// paints. |
base::ScopedCFTypeRef<CGImageRef> image( |