| 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(
|
|
|