| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 #import <Cocoa/Cocoa.h> | 5 #import <Cocoa/Cocoa.h> |
| 6 | 6 |
| 7 #include "chrome/browser/renderer_host/backing_store.h" | 7 #include "chrome/browser/renderer_host/backing_store.h" |
| 8 #include "chrome/browser/renderer_host/render_widget_host.h" | 8 #include "chrome/browser/renderer_host/render_widget_host.h" |
| 9 #include "chrome/browser/renderer_host/render_widget_host_view.h" | 9 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // all or mostly on the GPU, which is good for performance. | 22 // all or mostly on the GPU, which is good for performance. |
| 23 | 23 |
| 24 BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size) | 24 BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size) |
| 25 : render_widget_host_(widget), | 25 : render_widget_host_(widget), |
| 26 size_(size), | 26 size_(size), |
| 27 cg_layer_(NULL) { | 27 cg_layer_(NULL) { |
| 28 // We want our CGLayer to be optimized for drawing into our containing | 28 // We want our CGLayer to be optimized for drawing into our containing |
| 29 // window, so extract a CGContext corresponding to that window that we can | 29 // window, so extract a CGContext corresponding to that window that we can |
| 30 // pass to CGLayerCreateWithContext. | 30 // pass to CGLayerCreateWithContext. |
| 31 NSWindow* containing_window = [widget->view()->GetNativeView() window]; | 31 NSWindow* containing_window = [widget->view()->GetNativeView() window]; |
| 32 if (!containing_window) // possible in unit tests | 32 if (!containing_window) { |
| 33 return; | 33 // If we are not in a containing window yet, create a CGBitmapContext |
| 34 CGContextRef context = static_cast<CGContextRef>([[containing_window graphicsC
ontext] graphicsPort]); | 34 // to use as a stand-in for the layer. |
| 35 CGLayerRef layer = CGLayerCreateWithContext(context, size.ToCGSize(), NULL); | 35 scoped_cftyperef<CGColorSpaceRef> |
| 36 cg_layer_.reset(layer); | 36 color_space(CGColorSpaceCreateDeviceRGB()); |
| 37 cg_bitmap_.reset(CGBitmapContextCreate(NULL, size.width(), size.height(), |
| 38 8, size.width() * 8, color_space, |
| 39 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); |
| 40 } else { |
| 41 CGContextRef context = static_cast<CGContextRef>( |
| 42 [[containing_window graphicsContext] graphicsPort]); |
| 43 CGLayerRef layer = CGLayerCreateWithContext(context, size.ToCGSize(), NULL); |
| 44 cg_layer_.reset(layer); |
| 45 } |
| 37 } | 46 } |
| 38 | 47 |
| 39 BackingStore::~BackingStore() { | 48 BackingStore::~BackingStore() { |
| 40 } | 49 } |
| 41 | 50 |
| 42 size_t BackingStore::MemorySize() { | 51 size_t BackingStore::MemorySize() { |
| 43 // Estimate memory usage as 4 bytes per pixel. | 52 // Estimate memory usage as 4 bytes per pixel. |
| 44 return size_.GetArea() * 4; | 53 return size_.GetArea() * 4; |
| 45 } | 54 } |
| 46 | 55 |
| 47 // Paint the contents of a TransportDIB into a rectangle of our CGLayer | 56 // Paint the contents of a TransportDIB into a rectangle of our CGLayer |
| 48 void BackingStore::PaintRect(base::ProcessHandle process, | 57 void BackingStore::PaintRect(base::ProcessHandle process, |
| 49 TransportDIB* bitmap, | 58 TransportDIB* bitmap, |
| 50 const gfx::Rect& bitmap_rect) { | 59 const gfx::Rect& bitmap_rect) { |
| 51 if (!cg_layer()) return; | |
| 52 | |
| 53 scoped_cftyperef<CGColorSpaceRef> color_space(CGColorSpaceCreateDeviceRGB()); | 60 scoped_cftyperef<CGColorSpaceRef> color_space(CGColorSpaceCreateDeviceRGB()); |
| 54 scoped_cftyperef<CGDataProviderRef> data_provider( | 61 scoped_cftyperef<CGDataProviderRef> data_provider( |
| 55 CGDataProviderCreateWithData(NULL, bitmap->memory(), | 62 CGDataProviderCreateWithData(NULL, bitmap->memory(), |
| 56 bitmap_rect.width() * bitmap_rect.height() * 4, NULL)); | 63 bitmap_rect.width() * bitmap_rect.height() * 4, NULL)); |
| 57 scoped_cftyperef<CGImageRef> image(CGImageCreate(bitmap_rect.width(), | 64 scoped_cftyperef<CGImageRef> image( |
| 58 bitmap_rect.height(), 8, 32, 4 * bitmap_rect.width(), color_space, | 65 CGImageCreate(bitmap_rect.width(), bitmap_rect.height(), 8, 32, |
| 59 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, data_provider, | 66 4 * bitmap_rect.width(), color_space, |
| 60 NULL, false, kCGRenderingIntentDefault)); | 67 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, |
| 68 data_provider, NULL, false, kCGRenderingIntentDefault)); |
| 61 | 69 |
| 62 // The CGLayer's origin is in the lower left, but flipping the CTM would | 70 if (!cg_layer()) { |
| 63 // cause the image to get drawn upside down. So we move the rectangle | 71 // we don't have a CGLayer yet, so see if we can create one. |
| 64 // to the right position before drawing the image. | 72 NSWindow* containing_window = |
| 65 CGContextRef layer = CGLayerGetContext(cg_layer()); | 73 [render_widget_host()->view()->GetNativeView() window]; |
| 66 gfx::Rect paint_rect = bitmap_rect; | 74 if (containing_window) { |
| 67 paint_rect.set_y(size_.height() - bitmap_rect.bottom()); | 75 CGContextRef context = static_cast<CGContextRef>( |
| 68 CGContextDrawImage(layer, paint_rect.ToCGRect(), image); | 76 [[containing_window graphicsContext] graphicsPort]); |
| 77 CGLayerRef layer = |
| 78 CGLayerCreateWithContext(context, size().ToCGSize(), NULL); |
| 79 cg_layer_.reset(layer); |
| 80 // now that we have a layer, copy the cached image into it |
| 81 scoped_cftyperef<CGImageRef> bitmap_image( |
| 82 CGBitmapContextCreateImage(cg_bitmap_)); |
| 83 CGContextDrawImage(CGLayerGetContext(layer), |
| 84 CGRectMake(0, 0, size().width(), size().height()), |
| 85 bitmap_image); |
| 86 // Discard the cache bitmap, since we no longer need it. |
| 87 cg_bitmap_.reset(NULL); |
| 88 } |
| 89 } |
| 90 |
| 91 if (cg_layer()) { |
| 92 // The CGLayer's origin is in the lower left, but flipping the CTM would |
| 93 // cause the image to get drawn upside down. So we move the rectangle |
| 94 // to the right position before drawing the image. |
| 95 CGContextRef layer = CGLayerGetContext(cg_layer()); |
| 96 gfx::Rect paint_rect = bitmap_rect; |
| 97 paint_rect.set_y(size_.height() - bitmap_rect.bottom()); |
| 98 CGContextDrawImage(layer, paint_rect.ToCGRect(), image); |
| 99 } else { |
| 100 // The layer hasn't been created yet, so draw into the cache bitmap. |
| 101 gfx::Rect paint_rect = bitmap_rect; |
| 102 paint_rect.set_y(size_.height() - bitmap_rect.bottom()); |
| 103 CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image); |
| 104 } |
| 69 } | 105 } |
| 70 | 106 |
| 71 // Scroll the contents of our CGLayer | 107 // Scroll the contents of our CGLayer |
| 72 void BackingStore::ScrollRect(base::ProcessHandle process, | 108 void BackingStore::ScrollRect(base::ProcessHandle process, |
| 73 TransportDIB* bitmap, | 109 TransportDIB* bitmap, |
| 74 const gfx::Rect& bitmap_rect, | 110 const gfx::Rect& bitmap_rect, |
| 75 int dx, int dy, | 111 int dx, int dy, |
| 76 const gfx::Rect& clip_rect, | 112 const gfx::Rect& clip_rect, |
| 77 const gfx::Size& view_size) { | 113 const gfx::Size& view_size) { |
| 78 if (!cg_layer()) return; | 114 if (!cg_layer()) return; |
| 79 | 115 |
| 80 // "Scroll" the contents of the layer by creating a new CGLayer, | 116 // "Scroll" the contents of the layer by creating a new CGLayer, |
| 81 // copying the contents of the old one into the new one offset by the scroll | 117 // copying the contents of the old one into the new one offset by the scroll |
| 82 // amount, swapping in the new CGLayer, and then painting in the new data. | 118 // amount, swapping in the new CGLayer, and then painting in the new data. |
| 83 // | 119 // |
| 84 // The Windows code always sets the whole backing store as the source of the | 120 // The Windows code always sets the whole backing store as the source of the |
| 85 // scroll. Thus, we only have to worry about pixels which will end up inside | 121 // scroll. Thus, we only have to worry about pixels which will end up inside |
| 86 // the clipping rectangle. (Note that the clipping rectangle is not | 122 // the clipping rectangle. (Note that the clipping rectangle is not |
| 87 // translated by the scroll.) | 123 // translated by the scroll.) |
| 88 | 124 |
| 89 // We assume |clip_rect| is contained within the backing store. | 125 // We assume |clip_rect| is contained within the backing store. |
| 90 CGSize layer_size = CGLayerGetSize(cg_layer()); | 126 CGSize layer_size = CGLayerGetSize(cg_layer()); |
| 91 DCHECK(clip_rect.bottom() <= layer_size.height); | 127 DCHECK(clip_rect.bottom() <= layer_size.height); |
| 92 DCHECK(clip_rect.right() <= layer_size.width); | 128 DCHECK(clip_rect.right() <= layer_size.width); |
| 93 | 129 |
| 94 if ((dx && abs(dx) < layer_size.width) || | 130 if ((dx && abs(dx) < layer_size.width) || |
| 95 (dy && abs(dy) < layer_size.height)) { | 131 (dy && abs(dy) < layer_size.height)) { |
| 96 // | 132 if (cg_layer()) { |
| 97 scoped_cftyperef<CGLayerRef> new_layer(CGLayerCreateWithContext( | 133 CGContextRef context = CGLayerGetContext(cg_layer()); |
| 98 CGLayerGetContext(cg_layer()), layer_size, NULL)); | 134 scoped_cftyperef<CGLayerRef> new_layer( |
| 99 CGContextRef layer = CGLayerGetContext(new_layer); | 135 CGLayerCreateWithContext(context, layer_size, NULL)); |
| 100 CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer()); | 136 CGContextRef layer = CGLayerGetContext(new_layer); |
| 101 CGContextSaveGState(layer); | 137 CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer()); |
| 102 CGContextClipToRect(layer, CGRectMake(clip_rect.x(), | 138 CGContextSaveGState(layer); |
| 103 size_.height() - clip_rect.bottom(), | 139 CGContextClipToRect(layer, CGRectMake(clip_rect.x(), |
| 104 clip_rect.width(), | 140 size_.height() - clip_rect.bottom(), |
| 105 clip_rect.height())); | 141 clip_rect.width(), |
| 106 CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer()); | 142 clip_rect.height())); |
| 107 CGContextRestoreGState(layer); | 143 CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer()); |
| 108 cg_layer_.swap(new_layer); | 144 CGContextRestoreGState(layer); |
| 145 cg_layer_.swap(new_layer); |
| 146 } else { |
| 147 // We don't have a layer, so scroll the contents of the CGBitmapContext. |
| 148 scoped_cftyperef<CGColorSpaceRef> |
| 149 color_space(CGColorSpaceCreateDeviceRGB()); |
| 150 scoped_cftyperef<CGContextRef> new_bitmap( |
| 151 CGBitmapContextCreate(NULL, size_.width(), size_.height(), 8, |
| 152 size_.width() * 8, color_space, |
| 153 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); |
| 154 scoped_cftyperef<CGImageRef> bitmap_image( |
| 155 CGBitmapContextCreateImage(cg_bitmap_)); |
| 156 CGContextDrawImage(new_bitmap, |
| 157 CGRectMake(0, 0, size_.width(), size_.height()), |
| 158 bitmap_image); |
| 159 CGContextSaveGState(new_bitmap); |
| 160 CGContextClipToRect(new_bitmap, |
| 161 CGRectMake(clip_rect.x(), |
| 162 size_.height() - clip_rect.bottom(), |
| 163 clip_rect.width(), |
| 164 clip_rect.height())); |
| 165 CGContextDrawImage(new_bitmap, |
| 166 CGRectMake(dx, -dy, size_.width(), size_.height()), |
| 167 bitmap_image); |
| 168 CGContextRestoreGState(new_bitmap); |
| 169 cg_bitmap_.swap(new_bitmap); |
| 170 } |
| 109 } | 171 } |
| 110 // Now paint the new bitmap data into the CGLayer | 172 // Now paint the new bitmap data |
| 111 PaintRect(process, bitmap, bitmap_rect); | 173 PaintRect(process, bitmap, bitmap_rect); |
| 112 return; | 174 return; |
| 113 } | 175 } |
| OLD | NEW |