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 |