Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: chrome/browser/renderer_host/backing_store_mac.mm

Issue 6532073: Move core pieces of browser\renderer_host to src\content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <Cocoa/Cocoa.h>
6
7 #include "chrome/browser/renderer_host/backing_store_mac.h"
8
9 #include "app/surface/transport_dib.h"
10 #include "base/logging.h"
11 #include "base/mac/mac_util.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/sys_info.h"
14 #include "chrome/browser/renderer_host/render_process_host.h"
15 #include "chrome/browser/renderer_host/render_widget_host.h"
16 #include "chrome/browser/renderer_host/render_widget_host_view.h"
17 #include "skia/ext/platform_canvas.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "ui/gfx/rect.h"
21
22 // Mac Backing Stores:
23 //
24 // Since backing stores are only ever written to or drawn into windows, we keep
25 // our backing store in a CGLayer that can get cached in GPU memory. This
26 // allows acclerated drawing into the layer and lets scrolling and such happen
27 // all or mostly on the GPU, which is good for performance.
28
29 namespace {
30
31 // Returns whether this version of OS X has broken CGLayers, see
32 // http://crbug.com/45553 , comments 5 and 6.
33 bool NeedsLayerWorkaround() {
34 int32 os_major, os_minor, os_bugfix;
35 base::SysInfo::OperatingSystemVersionNumbers(
36 &os_major, &os_minor, &os_bugfix);
37 return os_major == 10 && os_minor == 5;
38 }
39
40 } // namespace
41
42 BackingStoreMac::BackingStoreMac(RenderWidgetHost* widget,
43 const gfx::Size& size)
44 : BackingStore(widget, size) {
45 cg_layer_.reset(CreateCGLayer());
46 if (!cg_layer_) {
47 // The view isn't in a window yet. Use a CGBitmapContext for now.
48 cg_bitmap_.reset(CreateCGBitmapContext());
49 }
50 }
51
52 BackingStoreMac::~BackingStoreMac() {
53 }
54
55 void BackingStoreMac::PaintToBackingStore(
56 RenderProcessHost* process,
57 TransportDIB::Id bitmap,
58 const gfx::Rect& bitmap_rect,
59 const std::vector<gfx::Rect>& copy_rects) {
60 DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
61
62 TransportDIB* dib = process->GetTransportDIB(bitmap);
63 if (!dib)
64 return;
65
66 base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider(
67 CGDataProviderCreateWithData(NULL, dib->memory(),
68 bitmap_rect.width() * bitmap_rect.height() * 4, NULL));
69
70 base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
71 CGImageCreate(bitmap_rect.width(), bitmap_rect.height(), 8, 32,
72 4 * bitmap_rect.width(), base::mac::GetSystemColorSpace(),
73 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
74 data_provider, NULL, false, kCGRenderingIntentDefault));
75
76 for (size_t i = 0; i < copy_rects.size(); i++) {
77 const gfx::Rect& copy_rect = copy_rects[i];
78
79 // Only the subpixels given by copy_rect have pixels to copy.
80 base::mac::ScopedCFTypeRef<CGImageRef> image(
81 CGImageCreateWithImageInRect(bitmap_image, CGRectMake(
82 copy_rect.x() - bitmap_rect.x(),
83 copy_rect.y() - bitmap_rect.y(),
84 copy_rect.width(),
85 copy_rect.height())));
86
87 if (!cg_layer()) {
88 // The view may have moved to a window. Try to get a CGLayer.
89 cg_layer_.reset(CreateCGLayer());
90 if (cg_layer()) {
91 // now that we have a layer, copy the cached image into it
92 base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
93 CGBitmapContextCreateImage(cg_bitmap_));
94 CGContextDrawImage(CGLayerGetContext(cg_layer()),
95 CGRectMake(0, 0, size().width(), size().height()),
96 bitmap_image);
97 // Discard the cache bitmap, since we no longer need it.
98 cg_bitmap_.reset(NULL);
99 }
100 }
101
102 DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
103
104 if (cg_layer()) {
105 // The CGLayer's origin is in the lower left, but flipping the CTM would
106 // cause the image to get drawn upside down. So we move the rectangle
107 // to the right position before drawing the image.
108 CGContextRef layer = CGLayerGetContext(cg_layer());
109 gfx::Rect paint_rect = copy_rect;
110 paint_rect.set_y(size().height() - copy_rect.bottom());
111 CGContextDrawImage(layer, paint_rect.ToCGRect(), image);
112 } else {
113 // The layer hasn't been created yet, so draw into the cache bitmap.
114 gfx::Rect paint_rect = copy_rect;
115 paint_rect.set_y(size().height() - copy_rect.bottom());
116 CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image);
117 }
118 }
119 }
120
121 bool BackingStoreMac::CopyFromBackingStore(const gfx::Rect& rect,
122 skia::PlatformCanvas* output) {
123 if (!output->initialize(rect.width(), rect.height(), true))
124 return false;
125
126 CGContextRef temp_context = output->beginPlatformPaint();
127 CGContextSaveGState(temp_context);
128 CGContextTranslateCTM(temp_context, 0.0, size().height());
129 CGContextScaleCTM(temp_context, 1.0, -1.0);
130 CGContextDrawLayerAtPoint(temp_context, CGPointMake(rect.x(), rect.y()),
131 cg_layer());
132 CGContextRestoreGState(temp_context);
133 output->endPlatformPaint();
134 return true;
135 }
136
137 // Scroll the contents of our CGLayer
138 void BackingStoreMac::ScrollBackingStore(int dx, int dy,
139 const gfx::Rect& clip_rect,
140 const gfx::Size& view_size) {
141 DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
142
143 // "Scroll" the contents of the layer by creating a new CGLayer,
144 // copying the contents of the old one into the new one offset by the scroll
145 // amount, swapping in the new CGLayer, and then painting in the new data.
146 //
147 // The Windows code always sets the whole backing store as the source of the
148 // scroll. Thus, we only have to worry about pixels which will end up inside
149 // the clipping rectangle. (Note that the clipping rectangle is not
150 // translated by the scroll.)
151
152 // We assume |clip_rect| is contained within the backing store.
153 DCHECK(clip_rect.bottom() <= size().height());
154 DCHECK(clip_rect.right() <= size().width());
155
156 if ((dx || dy) && abs(dx) < size().width() && abs(dy) < size().height()) {
157 if (cg_layer()) {
158 // See http://crbug.com/45553 , comments 5 and 6.
159 static bool needs_layer_workaround = NeedsLayerWorkaround();
160
161 base::mac::ScopedCFTypeRef<CGLayerRef> new_layer;
162 CGContextRef layer;
163
164 if (needs_layer_workaround) {
165 new_layer.reset(CreateCGLayer());
166 // If the current view is in a window, the replacement must be too.
167 DCHECK(new_layer);
168
169 layer = CGLayerGetContext(new_layer);
170 CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer());
171 } else {
172 layer = CGLayerGetContext(cg_layer());
173 }
174
175 CGContextSaveGState(layer);
176 CGContextClipToRect(layer,
177 CGRectMake(clip_rect.x(),
178 size().height() - clip_rect.bottom(),
179 clip_rect.width(),
180 clip_rect.height()));
181 CGContextDrawLayerAtPoint(layer, CGPointMake(dx, -dy), cg_layer());
182 CGContextRestoreGState(layer);
183
184 if (needs_layer_workaround)
185 cg_layer_.swap(new_layer);
186 } else {
187 // We don't have a layer, so scroll the contents of the CGBitmapContext.
188 base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
189 CGBitmapContextCreateImage(cg_bitmap_));
190 CGContextSaveGState(cg_bitmap_);
191 CGContextClipToRect(cg_bitmap_,
192 CGRectMake(clip_rect.x(),
193 size().height() - clip_rect.bottom(),
194 clip_rect.width(),
195 clip_rect.height()));
196 CGContextDrawImage(cg_bitmap_,
197 CGRectMake(dx, -dy, size().width(), size().height()),
198 bitmap_image);
199 CGContextRestoreGState(cg_bitmap_);
200 }
201 }
202 }
203
204 CGLayerRef BackingStoreMac::CreateCGLayer() {
205 // The CGLayer should be optimized for drawing into the containing window,
206 // so extract a CGContext corresponding to the window to be passed to
207 // CGLayerCreateWithContext.
208 NSWindow* window = [render_widget_host()->view()->GetNativeView() window];
209 if ([window windowNumber] <= 0) {
210 // This catches a nil |window|, as well as windows that exist but that
211 // aren't yet connected to WindowServer.
212 return NULL;
213 }
214
215 NSGraphicsContext* ns_context = [window graphicsContext];
216 DCHECK(ns_context);
217
218 CGContextRef cg_context = static_cast<CGContextRef>(
219 [ns_context graphicsPort]);
220 DCHECK(cg_context);
221
222 CGLayerRef layer = CGLayerCreateWithContext(cg_context,
223 size().ToCGSize(),
224 NULL);
225 DCHECK(layer);
226
227 return layer;
228 }
229
230 CGContextRef BackingStoreMac::CreateCGBitmapContext() {
231 // A CGBitmapContext serves as a stand-in for the layer before the view is
232 // in a containing window.
233 CGContextRef context = CGBitmapContextCreate(NULL,
234 size().width(), size().height(),
235 8, size().width() * 4,
236 base::mac::GetSystemColorSpace(),
237 kCGImageAlphaPremultipliedFirst |
238 kCGBitmapByteOrder32Host);
239 DCHECK(context);
240
241 return context;
242 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698