diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-31 21:39:22 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-31 21:39:22 +0000 |
commit | a72c6bb647954c92109a57b3edbb789195edda57 (patch) | |
tree | 7d7666fb98785b9bcfc784f61532abd7a485fad1 /chrome | |
parent | 3771f9bcce1d418162656f6b802f86784c998353 (diff) | |
download | chromium_src-a72c6bb647954c92109a57b3edbb789195edda57.zip chromium_src-a72c6bb647954c92109a57b3edbb789195edda57.tar.gz chromium_src-a72c6bb647954c92109a57b3edbb789195edda57.tar.bz2 |
Update BackingStore to handle the case where our Cocoa view has
not been inserted into a window yet.
BUG=20009
TEST=tabs opened in the background should not be blank when you switch to them.
Review URL: http://codereview.chromium.org/175027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24941 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/renderer_host/backing_store.h | 5 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_mac.mm | 128 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.mm | 26 |
3 files changed, 119 insertions, 40 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h index aea197b..df34eee 100644 --- a/chrome/browser/renderer_host/backing_store.h +++ b/chrome/browser/renderer_host/backing_store.h @@ -64,6 +64,10 @@ class BackingStore { // A CGLayer that stores the contents of the backing store, cached in GPU // memory if possible. CGLayerRef cg_layer() { return cg_layer_; } + // A CGBitmapContext that stores the contents of the backing store if the + // corresponding Cocoa view has not been inserted into an NSWindow yet. + CGContextRef cg_bitmap() { return cg_bitmap_; } + // Paint the layer into a graphics context--if the target is a window, // this should be a GPU->GPU copy (and therefore very fast). void PaintToRect(const gfx::Rect& dest_rect, CGContextRef target); @@ -118,6 +122,7 @@ class BackingStore { // Number of bits per pixel of the screen. int color_depth_; #elif defined(OS_MACOSX) + scoped_cftyperef<CGContextRef> cg_bitmap_; scoped_cftyperef<CGLayerRef> cg_layer_; #elif defined(OS_LINUX) // Paints the bitmap from the renderer onto the backing store without diff --git a/chrome/browser/renderer_host/backing_store_mac.mm b/chrome/browser/renderer_host/backing_store_mac.mm index b1f2b92..c877a52 100644 --- a/chrome/browser/renderer_host/backing_store_mac.mm +++ b/chrome/browser/renderer_host/backing_store_mac.mm @@ -29,11 +29,20 @@ BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size) // window, so extract a CGContext corresponding to that window that we can // pass to CGLayerCreateWithContext. NSWindow* containing_window = [widget->view()->GetNativeView() window]; - if (!containing_window) // possible in unit tests - return; - CGContextRef context = static_cast<CGContextRef>([[containing_window graphicsContext] graphicsPort]); - CGLayerRef layer = CGLayerCreateWithContext(context, size.ToCGSize(), NULL); - cg_layer_.reset(layer); + if (!containing_window) { + // If we are not in a containing window yet, create a CGBitmapContext + // to use as a stand-in for the layer. + scoped_cftyperef<CGColorSpaceRef> + color_space(CGColorSpaceCreateDeviceRGB()); + cg_bitmap_.reset(CGBitmapContextCreate(NULL, size.width(), size.height(), + 8, size.width() * 8, color_space, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + } else { + CGContextRef context = static_cast<CGContextRef>( + [[containing_window graphicsContext] graphicsPort]); + CGLayerRef layer = CGLayerCreateWithContext(context, size.ToCGSize(), NULL); + cg_layer_.reset(layer); + } } BackingStore::~BackingStore() { @@ -48,24 +57,51 @@ size_t BackingStore::MemorySize() { void BackingStore::PaintRect(base::ProcessHandle process, TransportDIB* bitmap, const gfx::Rect& bitmap_rect) { - if (!cg_layer()) return; - scoped_cftyperef<CGColorSpaceRef> color_space(CGColorSpaceCreateDeviceRGB()); scoped_cftyperef<CGDataProviderRef> data_provider( CGDataProviderCreateWithData(NULL, bitmap->memory(), - bitmap_rect.width() * bitmap_rect.height() * 4, NULL)); - scoped_cftyperef<CGImageRef> image(CGImageCreate(bitmap_rect.width(), - bitmap_rect.height(), 8, 32, 4 * bitmap_rect.width(), color_space, - kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, data_provider, - NULL, false, kCGRenderingIntentDefault)); + bitmap_rect.width() * bitmap_rect.height() * 4, NULL)); + scoped_cftyperef<CGImageRef> image( + CGImageCreate(bitmap_rect.width(), bitmap_rect.height(), 8, 32, + 4 * bitmap_rect.width(), color_space, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + data_provider, NULL, false, kCGRenderingIntentDefault)); - // The CGLayer's origin is in the lower left, but flipping the CTM would - // cause the image to get drawn upside down. So we move the rectangle - // to the right position before drawing the image. - CGContextRef layer = CGLayerGetContext(cg_layer()); - gfx::Rect paint_rect = bitmap_rect; - paint_rect.set_y(size_.height() - bitmap_rect.bottom()); - CGContextDrawImage(layer, paint_rect.ToCGRect(), image); + if (!cg_layer()) { + // we don't have a CGLayer yet, so see if we can create one. + NSWindow* containing_window = + [render_widget_host()->view()->GetNativeView() window]; + if (containing_window) { + CGContextRef context = static_cast<CGContextRef>( + [[containing_window graphicsContext] graphicsPort]); + CGLayerRef layer = + CGLayerCreateWithContext(context, size().ToCGSize(), NULL); + cg_layer_.reset(layer); + // now that we have a layer, copy the cached image into it + scoped_cftyperef<CGImageRef> bitmap_image( + CGBitmapContextCreateImage(cg_bitmap_)); + CGContextDrawImage(CGLayerGetContext(layer), + CGRectMake(0, 0, size().width(), size().height()), + bitmap_image); + // Discard the cache bitmap, since we no longer need it. + cg_bitmap_.reset(NULL); + } + } + + if (cg_layer()) { + // The CGLayer's origin is in the lower left, but flipping the CTM would + // cause the image to get drawn upside down. So we move the rectangle + // to the right position before drawing the image. + CGContextRef layer = CGLayerGetContext(cg_layer()); + gfx::Rect paint_rect = bitmap_rect; + paint_rect.set_y(size_.height() - bitmap_rect.bottom()); + CGContextDrawImage(layer, paint_rect.ToCGRect(), image); + } else { + // The layer hasn't been created yet, so draw into the cache bitmap. + gfx::Rect paint_rect = bitmap_rect; + paint_rect.set_y(size_.height() - bitmap_rect.bottom()); + CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image); + } } // Scroll the contents of our CGLayer @@ -93,21 +129,47 @@ void BackingStore::ScrollRect(base::ProcessHandle process, if ((dx && abs(dx) < layer_size.width) || (dy && abs(dy) < layer_size.height)) { - // - scoped_cftyperef<CGLayerRef> new_layer(CGLayerCreateWithContext( - CGLayerGetContext(cg_layer()), layer_size, NULL)); - CGContextRef layer = CGLayerGetContext(new_layer); - CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer()); - CGContextSaveGState(layer); - CGContextClipToRect(layer, CGRectMake(clip_rect.x(), - size_.height() - clip_rect.bottom(), - clip_rect.width(), - clip_rect.height())); - CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer()); - CGContextRestoreGState(layer); - cg_layer_.swap(new_layer); + if (cg_layer()) { + CGContextRef context = CGLayerGetContext(cg_layer()); + scoped_cftyperef<CGLayerRef> new_layer( + CGLayerCreateWithContext(context, layer_size, NULL)); + CGContextRef layer = CGLayerGetContext(new_layer); + CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer()); + CGContextSaveGState(layer); + CGContextClipToRect(layer, CGRectMake(clip_rect.x(), + size_.height() - clip_rect.bottom(), + clip_rect.width(), + clip_rect.height())); + CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer()); + CGContextRestoreGState(layer); + cg_layer_.swap(new_layer); + } else { + // We don't have a layer, so scroll the contents of the CGBitmapContext. + scoped_cftyperef<CGColorSpaceRef> + color_space(CGColorSpaceCreateDeviceRGB()); + scoped_cftyperef<CGContextRef> new_bitmap( + CGBitmapContextCreate(NULL, size_.width(), size_.height(), 8, + size_.width() * 8, color_space, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + scoped_cftyperef<CGImageRef> bitmap_image( + CGBitmapContextCreateImage(cg_bitmap_)); + CGContextDrawImage(new_bitmap, + CGRectMake(0, 0, size_.width(), size_.height()), + bitmap_image); + CGContextSaveGState(new_bitmap); + CGContextClipToRect(new_bitmap, + CGRectMake(clip_rect.x(), + size_.height() - clip_rect.bottom(), + clip_rect.width(), + clip_rect.height())); + CGContextDrawImage(new_bitmap, + CGRectMake(dx, -dy, size_.width(), size_.height()), + bitmap_image); + CGContextRestoreGState(new_bitmap); + cg_bitmap_.swap(new_bitmap); + } } - // Now paint the new bitmap data into the CGLayer + // Now paint the new bitmap data PaintRect(process, bitmap, bitmap_rect); return; } diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index af3ce8a..1010475 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -549,7 +549,7 @@ void RenderWidgetHostViewMac::SetActive(bool active) { renderWidgetHostView_->about_to_validate_and_paint_ = false; dirtyRect = renderWidgetHostView_->invalid_rect_; - if (backing_store && backing_store->cg_layer()) { + if (backing_store) { NSRect view_bounds = [self bounds]; gfx::Rect damaged_rect([self NSRectToRect:dirtyRect]); @@ -559,12 +559,24 @@ void RenderWidgetHostViewMac::SetActive(bool active) { gfx::Rect paint_rect = bitmap_rect.Intersect(damaged_rect); if (!paint_rect.IsEmpty()) { - CGContextRef context = static_cast<CGContextRef>( - [[NSGraphicsContext currentContext] graphicsPort]); - - // TODO: add clipping to dirtyRect if it improves drawing performance. - CGContextDrawLayerAtPoint(context, CGPointMake(0.0, 0.0), - backing_store->cg_layer()); + // if we have a CGLayer, draw that into the window + if (backing_store->cg_layer()) { + CGContextRef context = static_cast<CGContextRef>( + [[NSGraphicsContext currentContext] graphicsPort]); + + // TODO: add clipping to dirtyRect if it improves drawing performance. + CGContextDrawLayerAtPoint(context, CGPointMake(0.0, 0.0), + backing_store->cg_layer()); + } else { + // 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. + CGContextRef context = static_cast<CGContextRef>( + [[NSGraphicsContext currentContext] graphicsPort]); + scoped_cftyperef<CGImageRef> image( + CGBitmapContextCreateImage(backing_store->cg_bitmap())); + CGContextDrawImage(context, bitmap_rect.ToCGRect(), image); + } } // Fill the remaining portion of the damaged_rect with white |