OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" | 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" |
6 | 6 |
7 #import <objc/runtime.h> | 7 #import <objc/runtime.h> |
8 #include <QuartzCore/QuartzCore.h> | 8 #include <QuartzCore/QuartzCore.h> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 /////////////////////////////////////////////////////////////////////////////// | 413 /////////////////////////////////////////////////////////////////////////////// |
414 // RenderWidgetHostViewMac, public: | 414 // RenderWidgetHostViewMac, public: |
415 | 415 |
416 RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) | 416 RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) |
417 : render_widget_host_(RenderWidgetHostImpl::From(widget)), | 417 : render_widget_host_(RenderWidgetHostImpl::From(widget)), |
418 about_to_validate_and_paint_(false), | 418 about_to_validate_and_paint_(false), |
419 call_set_needs_display_in_rect_pending_(false), | 419 call_set_needs_display_in_rect_pending_(false), |
420 last_frame_was_accelerated_(false), | 420 last_frame_was_accelerated_(false), |
421 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), | 421 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), |
422 can_compose_inline_(true), | 422 can_compose_inline_(true), |
| 423 software_framebuffer_(new SoftwareFramebuffer( |
| 424 this, RenderWidgetHostImpl::From(widget))), |
423 allow_overlapping_views_(false), | 425 allow_overlapping_views_(false), |
424 use_core_animation_(false), | 426 use_core_animation_(false), |
425 is_loading_(false), | 427 is_loading_(false), |
426 is_hidden_(false), | 428 is_hidden_(false), |
427 weak_factory_(this), | 429 weak_factory_(this), |
428 fullscreen_parent_host_view_(NULL), | 430 fullscreen_parent_host_view_(NULL), |
429 pending_swap_buffers_acks_weak_factory_(this), | 431 pending_swap_buffers_acks_weak_factory_(this), |
430 next_swap_ack_time_(base::Time::Now()) { | 432 next_swap_ack_time_(base::Time::Now()) { |
431 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_| | 433 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_| |
432 // goes away. Since we autorelease it, our caller must put | 434 // goes away. Since we autorelease it, our caller must put |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } | 729 } |
728 | 730 |
729 void RenderWidgetHostViewMac::WasShown() { | 731 void RenderWidgetHostViewMac::WasShown() { |
730 if (!is_hidden_) | 732 if (!is_hidden_) |
731 return; | 733 return; |
732 | 734 |
733 if (web_contents_switch_paint_time_.is_null()) | 735 if (web_contents_switch_paint_time_.is_null()) |
734 web_contents_switch_paint_time_ = base::TimeTicks::Now(); | 736 web_contents_switch_paint_time_ = base::TimeTicks::Now(); |
735 is_hidden_ = false; | 737 is_hidden_ = false; |
736 render_widget_host_->WasShown(); | 738 render_widget_host_->WasShown(); |
| 739 software_framebuffer_->WasShown(); |
737 | 740 |
738 // We're messing with the window, so do this to ensure no flashes. | 741 // We're messing with the window, so do this to ensure no flashes. |
739 if (!use_core_animation_) | 742 if (!use_core_animation_) |
740 [[cocoa_view_ window] disableScreenUpdatesUntilFlush]; | 743 [[cocoa_view_ window] disableScreenUpdatesUntilFlush]; |
741 | 744 |
742 [compositing_iosurface_layer_ setNeedsDisplay]; | 745 [compositing_iosurface_layer_ setNeedsDisplay]; |
743 } | 746 } |
744 | 747 |
745 void RenderWidgetHostViewMac::WasHidden() { | 748 void RenderWidgetHostViewMac::WasHidden() { |
746 if (is_hidden_) | 749 if (is_hidden_) |
747 return; | 750 return; |
748 | 751 |
749 // Send ACKs for any pending SwapBuffers (if any) since we won't be displaying | 752 // Send ACKs for any pending SwapBuffers (if any) since we won't be displaying |
750 // them and the GPU process is waiting. | 753 // them and the GPU process is waiting. |
751 AckPendingSwapBuffers(); | 754 AckPendingSwapBuffers(); |
752 | 755 |
753 // If we receive any more paint messages while we are hidden, we want to | 756 // If we receive any more paint messages while we are hidden, we want to |
754 // ignore them so we don't re-allocate the backing store. We will paint | 757 // ignore them so we don't re-allocate the backing store. We will paint |
755 // everything again when we become selected again. | 758 // everything again when we become selected again. |
756 is_hidden_ = true; | 759 is_hidden_ = true; |
757 | 760 |
758 // If we have a renderer, then inform it that we are being hidden so it can | 761 // If we have a renderer, then inform it that we are being hidden so it can |
759 // reduce its resource utilization. | 762 // reduce its resource utilization. |
760 render_widget_host_->WasHidden(); | 763 render_widget_host_->WasHidden(); |
| 764 software_framebuffer_->WasHidden(); |
761 | 765 |
762 // There can be a transparent flash as this view is removed and the next is | 766 // There can be a transparent flash as this view is removed and the next is |
763 // added, because of OSX windowing races between displaying the contents of | 767 // added, because of OSX windowing races between displaying the contents of |
764 // the NSView and its corresponding OpenGL context. | 768 // the NSView and its corresponding OpenGL context. |
765 // disableScreenUpdatesUntilFlush prevents the transparent flash by avoiding | 769 // disableScreenUpdatesUntilFlush prevents the transparent flash by avoiding |
766 // screen updates until the next tab draws. | 770 // screen updates until the next tab draws. |
767 if (!use_core_animation_) | 771 if (!use_core_animation_) |
768 [[cocoa_view_ window] disableScreenUpdatesUntilFlush]; | 772 [[cocoa_view_ window] disableScreenUpdatesUntilFlush]; |
769 | 773 |
770 web_contents_switch_paint_time_ = base::TimeTicks(); | 774 web_contents_switch_paint_time_ = base::TimeTicks(); |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 | 1218 |
1215 void RenderWidgetHostViewMac::BeginFrameSubscription( | 1219 void RenderWidgetHostViewMac::BeginFrameSubscription( |
1216 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) { | 1220 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) { |
1217 frame_subscriber_ = subscriber.Pass(); | 1221 frame_subscriber_ = subscriber.Pass(); |
1218 } | 1222 } |
1219 | 1223 |
1220 void RenderWidgetHostViewMac::EndFrameSubscription() { | 1224 void RenderWidgetHostViewMac::EndFrameSubscription() { |
1221 frame_subscriber_.reset(); | 1225 frame_subscriber_.reset(); |
1222 } | 1226 } |
1223 | 1227 |
| 1228 void RenderWidgetHostViewMac::OnSwapCompositorFrame( |
| 1229 uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) { |
| 1230 // Only software compositor frames are accepted. |
| 1231 if (!frame->software_frame_data) { |
| 1232 render_widget_host_->GetProcess()->ReceivedBadMessage(); |
| 1233 return; |
| 1234 } |
| 1235 |
| 1236 GotSoftwareFrame(); |
| 1237 |
| 1238 software_framebuffer_->SwapToNewFrame( |
| 1239 output_surface_id, |
| 1240 frame->software_frame_data.get(), |
| 1241 frame->metadata.device_scale_factor); |
| 1242 |
| 1243 [cocoa_view_ setNeedsDisplay:YES]; |
| 1244 } |
| 1245 |
1224 // Sets whether or not to accept first responder status. | 1246 // Sets whether or not to accept first responder status. |
1225 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { | 1247 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { |
1226 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; | 1248 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; |
1227 } | 1249 } |
1228 | 1250 |
1229 void RenderWidgetHostViewMac::ForwardMouseEvent(const WebMouseEvent& event) { | 1251 void RenderWidgetHostViewMac::ForwardMouseEvent(const WebMouseEvent& event) { |
1230 if (render_widget_host_) | 1252 if (render_widget_host_) |
1231 render_widget_host_->ForwardMouseEvent(event); | 1253 render_widget_host_->ForwardMouseEvent(event); |
1232 | 1254 |
1233 if (event.type == WebInputEvent::MouseLeave) { | 1255 if (event.type == WebInputEvent::MouseLeave) { |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 if (compositing_iosurface_) | 1672 if (compositing_iosurface_) |
1651 compositing_iosurface_->UnrefIOSurface(); | 1673 compositing_iosurface_->UnrefIOSurface(); |
1652 } | 1674 } |
1653 | 1675 |
1654 void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() { | 1676 void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() { |
1655 DestroyCompositedIOSurfaceAndLayer(kDestroyContext); | 1677 DestroyCompositedIOSurfaceAndLayer(kDestroyContext); |
1656 } | 1678 } |
1657 | 1679 |
1658 bool RenderWidgetHostViewMac::HasAcceleratedSurface( | 1680 bool RenderWidgetHostViewMac::HasAcceleratedSurface( |
1659 const gfx::Size& desired_size) { | 1681 const gfx::Size& desired_size) { |
1660 return last_frame_was_accelerated_ && | 1682 if (last_frame_was_accelerated_) { |
1661 compositing_iosurface_ && | 1683 return (compositing_iosurface_ && |
1662 compositing_iosurface_->HasIOSurface() && | 1684 compositing_iosurface_->HasIOSurface() && |
1663 (desired_size.IsEmpty() || | 1685 (desired_size.IsEmpty() || |
1664 compositing_iosurface_->dip_io_surface_size() == desired_size); | 1686 compositing_iosurface_->dip_io_surface_size() == desired_size)); |
| 1687 } else { |
| 1688 return (software_framebuffer_->HasCurrentFrame() && |
| 1689 (desired_size.IsEmpty() || |
| 1690 software_framebuffer_->GetCurrentFrameSizeInDIP() == |
| 1691 desired_size)); |
| 1692 } |
| 1693 return false; |
1665 } | 1694 } |
1666 | 1695 |
1667 void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() { | 1696 void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() { |
1668 AckPendingSwapBuffers(); | 1697 AckPendingSwapBuffers(); |
1669 } | 1698 } |
1670 | 1699 |
1671 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() { | 1700 void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() { |
1672 } | 1701 } |
1673 | 1702 |
1674 void RenderWidgetHostViewMac::GetScreenInfo(WebKit::WebScreenInfo* results) { | 1703 void RenderWidgetHostViewMac::GetScreenInfo(WebKit::WebScreenInfo* results) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1764 last_frame_was_accelerated_ = true; | 1793 last_frame_was_accelerated_ = true; |
1765 | 1794 |
1766 if (!use_core_animation_) { | 1795 if (!use_core_animation_) { |
1767 // Need to wipe the software view with transparency to expose the GL | 1796 // Need to wipe the software view with transparency to expose the GL |
1768 // underlay. Invalidate the whole window to do that. | 1797 // underlay. Invalidate the whole window to do that. |
1769 [cocoa_view_ setNeedsDisplay:YES]; | 1798 [cocoa_view_ setNeedsDisplay:YES]; |
1770 } | 1799 } |
1771 | 1800 |
1772 // Delete software backingstore. | 1801 // Delete software backingstore. |
1773 BackingStoreManager::RemoveBackingStore(render_widget_host_); | 1802 BackingStoreManager::RemoveBackingStore(render_widget_host_); |
| 1803 |
| 1804 // Delete the software compositing frame if one exists. |
| 1805 software_framebuffer_->DiscardCurrentFrame(); |
1774 } | 1806 } |
1775 } | 1807 } |
1776 | 1808 |
1777 void RenderWidgetHostViewMac::GotSoftwareFrame() { | 1809 void RenderWidgetHostViewMac::GotSoftwareFrame() { |
1778 if (last_frame_was_accelerated_) { | 1810 if (last_frame_was_accelerated_) { |
1779 last_frame_was_accelerated_ = false; | 1811 last_frame_was_accelerated_ = false; |
1780 | 1812 |
1781 AckPendingSwapBuffers(); | 1813 AckPendingSwapBuffers(); |
1782 | 1814 |
1783 // If overlapping views are allowed, then don't unbind the context | 1815 // If overlapping views are allowed, then don't unbind the context |
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2717 CGContextRef context = static_cast<CGContextRef>( | 2749 CGContextRef context = static_cast<CGContextRef>( |
2718 [[NSGraphicsContext currentContext] graphicsPort]); | 2750 [[NSGraphicsContext currentContext] graphicsPort]); |
2719 [self drawBackingStore:backingStore | 2751 [self drawBackingStore:backingStore |
2720 dirtyRect:NSRectToCGRect(dirtyRect) | 2752 dirtyRect:NSRectToCGRect(dirtyRect) |
2721 inContext:context]; | 2753 inContext:context]; |
2722 } | 2754 } |
2723 | 2755 |
2724 - (void)drawBackingStore:(BackingStoreMac*)backingStore | 2756 - (void)drawBackingStore:(BackingStoreMac*)backingStore |
2725 dirtyRect:(CGRect)dirtyRect | 2757 dirtyRect:(CGRect)dirtyRect |
2726 inContext:(CGContextRef)context { | 2758 inContext:(CGContextRef)context { |
2727 if (backingStore) { | 2759 content::SoftwareFramebuffer* software_framebuffer = |
| 2760 renderWidgetHostView_->software_framebuffer_->HasCurrentFrame() ? |
| 2761 renderWidgetHostView_->software_framebuffer_.get() : NULL; |
| 2762 DCHECK(!backingStore || !software_framebuffer); |
| 2763 |
| 2764 if (backingStore || software_framebuffer) { |
2728 // Note: All coordinates are in view units, not pixels. | 2765 // Note: All coordinates are in view units, not pixels. |
2729 gfx::Rect bitmapRect(0, 0, | 2766 gfx::Rect bitmapRect(software_framebuffer ? |
2730 backingStore->size().width(), | 2767 software_framebuffer->GetCurrentFrameSizeInDIP() : |
2731 backingStore->size().height()); | 2768 backingStore->size()); |
2732 | 2769 |
2733 // Specify the proper y offset to ensure that the view is rooted to the | 2770 // Specify the proper y offset to ensure that the view is rooted to the |
2734 // upper left corner. This can be negative, if the window was resized | 2771 // upper left corner. This can be negative, if the window was resized |
2735 // smaller and the renderer hasn't yet repainted. | 2772 // smaller and the renderer hasn't yet repainted. |
2736 int yOffset = NSHeight([self bounds]) - backingStore->size().height(); | 2773 int yOffset = NSHeight([self bounds]) - bitmapRect.height(); |
2737 | 2774 |
2738 NSRect nsDirtyRect = NSRectFromCGRect(dirtyRect); | 2775 NSRect nsDirtyRect = NSRectFromCGRect(dirtyRect); |
2739 const gfx::Rect damagedRect([self flipNSRectToRect:nsDirtyRect]); | 2776 const gfx::Rect damagedRect([self flipNSRectToRect:nsDirtyRect]); |
2740 | 2777 |
2741 gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect); | 2778 gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect); |
2742 if (!paintRect.IsEmpty()) { | 2779 if (!paintRect.IsEmpty()) { |
2743 // if we have a CGLayer, draw that into the window | 2780 if (software_framebuffer) { |
2744 if (backingStore->cg_layer()) { | 2781 // If a software compositor framebuffer is present, draw using that. |
| 2782 gfx::Size sizeInPixels = |
| 2783 software_framebuffer->GetCurrentFrameSizeInPixels(); |
| 2784 |
| 2785 base::ScopedCFTypeRef<CGDataProviderRef> dataProvider( |
| 2786 CGDataProviderCreateWithData( |
| 2787 NULL, |
| 2788 software_framebuffer->GetCurrentFramePixels(), |
| 2789 4 * sizeInPixels.width() * sizeInPixels.height(), |
| 2790 NULL)); |
| 2791 |
| 2792 base::ScopedCFTypeRef<CGImageRef> image( |
| 2793 CGImageCreate( |
| 2794 sizeInPixels.width(), |
| 2795 sizeInPixels.height(), |
| 2796 8, |
| 2797 32, |
| 2798 4 * sizeInPixels.width(), |
| 2799 base::mac::GetSystemColorSpace(), |
| 2800 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, |
| 2801 dataProvider, |
| 2802 NULL, |
| 2803 false, |
| 2804 kCGRenderingIntentDefault)); |
| 2805 |
| 2806 CGRect imageRect = bitmapRect.ToCGRect(); |
| 2807 imageRect.origin.y = yOffset; |
| 2808 CGContextDrawImage(context, imageRect, image); |
| 2809 } else if (backingStore->cg_layer()) { |
| 2810 // If we have a CGLayer, draw that into the window |
2745 // TODO: add clipping to dirtyRect if it improves drawing performance. | 2811 // TODO: add clipping to dirtyRect if it improves drawing performance. |
2746 CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset), | 2812 CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset), |
2747 backingStore->cg_layer()); | 2813 backingStore->cg_layer()); |
2748 } else { | 2814 } else { |
2749 // if we haven't created a layer yet, draw the cached bitmap into | 2815 // If we haven't created a layer yet, draw the cached bitmap into |
2750 // the window. The CGLayer will be created the next time the renderer | 2816 // the window. The CGLayer will be created the next time the renderer |
2751 // paints. | 2817 // paints. |
2752 base::ScopedCFTypeRef<CGImageRef> image( | 2818 base::ScopedCFTypeRef<CGImageRef> image( |
2753 CGBitmapContextCreateImage(backingStore->cg_bitmap())); | 2819 CGBitmapContextCreateImage(backingStore->cg_bitmap())); |
2754 CGRect imageRect = bitmapRect.ToCGRect(); | 2820 CGRect imageRect = bitmapRect.ToCGRect(); |
2755 imageRect.origin.y = yOffset; | 2821 imageRect.origin.y = yOffset; |
2756 CGContextDrawImage(context, imageRect, image); | 2822 CGContextDrawImage(context, imageRect, image); |
2757 } | 2823 } |
2758 } | 2824 } |
2759 | 2825 |
(...skipping 1088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3848 return YES; | 3914 return YES; |
3849 } | 3915 } |
3850 | 3916 |
3851 - (BOOL)isOpaque { | 3917 - (BOOL)isOpaque { |
3852 if (renderWidgetHostView_->use_core_animation_) | 3918 if (renderWidgetHostView_->use_core_animation_) |
3853 return YES; | 3919 return YES; |
3854 return [super isOpaque]; | 3920 return [super isOpaque]; |
3855 } | 3921 } |
3856 | 3922 |
3857 @end | 3923 @end |
OLD | NEW |