summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host
diff options
context:
space:
mode:
authoramanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 18:59:22 +0000
committeramanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 18:59:22 +0000
commitb9471f847796ea07f4a5b3464502c51c2d48cc3f (patch)
tree6ebf50edea23f931fe0582fcef04c77061e685d3 /chrome/browser/renderer_host
parent76b3af422d58822e17523064aca0a3de116a3457 (diff)
downloadchromium_src-b9471f847796ea07f4a5b3464502c51c2d48cc3f.zip
chromium_src-b9471f847796ea07f4a5b3464502c51c2d48cc3f.tar.gz
chromium_src-b9471f847796ea07f4a5b3464502c51c2d48cc3f.tar.bz2
Re-implement BackingStore on the Mac as a CGLayer instead of a Skia canvas,
to get better performance. As a side effect, remove the ugly stopgap scrolling code. Do not close 14823 with this fix, but it should help (primary motivation was improving the plugin drawing path). Paul: review rafael: please check the change to extension_tabs_module.cc John, Rohit: FYI, comments welcome BUG=14823, TEST=scrolling and plugin performance should improve Review URL: http://codereview.chromium.org/171054 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23722 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
-rw-r--r--chrome/browser/renderer_host/backing_store.h10
-rw-r--r--chrome/browser/renderer_host/backing_store_mac.cc140
-rw-r--r--chrome/browser/renderer_host/backing_store_mac.mm103
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm10
4 files changed, 115 insertions, 148 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 49922e78..aea197b 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -15,6 +15,7 @@
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_MACOSX)
+#include "base/scoped_cftyperef.h"
#include "skia/ext/platform_canvas.h"
#elif defined(OS_LINUX)
#include "chrome/common/x11_util.h"
@@ -60,7 +61,12 @@ class BackingStore {
// Returns true if we should convert to the monitor profile when painting.
static bool ColorManagementEnabled();
#elif defined(OS_MACOSX)
- skia::PlatformCanvas* canvas() { return &canvas_; }
+ // A CGLayer that stores the contents of the backing store, cached in GPU
+ // memory if possible.
+ CGLayerRef cg_layer() { return cg_layer_; }
+ // 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);
#elif defined(OS_LINUX)
Display* display() const { return display_; }
XID root_window() const { return root_window_; };
@@ -112,7 +118,7 @@ class BackingStore {
// Number of bits per pixel of the screen.
int color_depth_;
#elif defined(OS_MACOSX)
- skia::PlatformCanvas canvas_;
+ scoped_cftyperef<CGLayerRef> cg_layer_;
#elif defined(OS_LINUX)
// Paints the bitmap from the renderer onto the backing store without
// using Xrender to composite the pixmaps.
diff --git a/chrome/browser/renderer_host/backing_store_mac.cc b/chrome/browser/renderer_host/backing_store_mac.cc
deleted file mode 100644
index d87b292..0000000
--- a/chrome/browser/renderer_host/backing_store_mac.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/renderer_host/backing_store.h"
-
-#include "base/logging.h"
-#include "chrome/common/transport_dib.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-
-BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
- : render_widget_host_(widget),
- size_(size) {
- if (!canvas_.initialize(size.width(), size.height(), true))
- SK_CRASH();
-}
-
-BackingStore::~BackingStore() {
-}
-
-size_t BackingStore::MemorySize() {
- // Always 4 bytes per pixel.
- return size_.GetArea() * 4;
-}
-
-void BackingStore::PaintRect(base::ProcessHandle process,
- TransportDIB* bitmap,
- const gfx::Rect& bitmap_rect) {
- SkBitmap skbitmap;
- skbitmap.setConfig(SkBitmap::kARGB_8888_Config, bitmap_rect.width(),
- bitmap_rect.height(), 4 * bitmap_rect.width());
-
- skbitmap.setPixels(bitmap->memory());
-
- canvas_.drawBitmap(skbitmap, bitmap_rect.x(), bitmap_rect.y());
-}
-
-void BackingStore::ScrollRect(base::ProcessHandle process,
- TransportDIB* bitmap,
- const gfx::Rect& bitmap_rect,
- int dx, int dy,
- const gfx::Rect& clip_rect,
- const gfx::Size& view_size) {
- // WARNING: this is temporary code until a real solution is found for Mac and
- // Linux.
- //
- // On Windows, there's a ScrollDC call which performs horiz and vertical
- // scrolling
- //
- // clip_rect: MSDN says "The only bits that will be painted are the
- // bits that remain inside this rectangle after the scroll operation has been
- // completed."
- //
- // The Windows code always sets the whole backing store as the source of the
- // scroll. Thus, we only have to worry about pixels which will end up inside
- // the clipping rectangle. (Note that the clipping rectangle is not
- // translated by the scroll.)
-
- // We only support scrolling in one direction at a time.
- DCHECK(dx == 0 || dy == 0);
-
- // We assume |clip_rect| is contained within the backing store.
- DCHECK(clip_rect.bottom() <= canvas_.getDevice()->height());
- DCHECK(clip_rect.right() <= canvas_.getDevice()->width());
-
- const SkBitmap &backing_bitmap = canvas_.getDevice()->accessBitmap(true);
- const int stride = backing_bitmap.rowBytes();
- uint8_t* x = static_cast<uint8_t*>(backing_bitmap.getPixels());
-
- if (dx) {
- // Do not memmove any data if the scroll distance (|dx|) is greater
- // than |clip_rect.width()|. If this is true, then none of the
- // previous pixels will still be on the screen after the scroll.
- // The call to PaintRect() below will redraw the entire area.
- if (abs(dx) < clip_rect.width()) {
- // Horizontal scroll. According to msdn, positive values of |dx| scroll
- // left, but in practice this seems reversed. TODO(port): figure this
- // out. For now just reverse the sign.
- dx *= -1;
-
- // This is the number of bytes to move per line at 4 bytes per pixel.
- const int len = (clip_rect.width() - abs(dx)) * 4;
-
- // Move |x| to the first pixel of the first row.
- x += clip_rect.y() * stride;
- x += clip_rect.x() * 4;
-
- // If we are scrolling left, move |x| to the |dx|^th pixel.
- if (dx < 0) {
- x -= dx * 4;
- }
-
- for (int i = clip_rect.y(); i < clip_rect.bottom(); ++i) {
- // Note that overlapping regions requires memmove, not memcpy.
- memmove(x, x + dx * 4, len);
- x += stride;
- }
- }
- } else if (dy) {
- // Vertical scroll. The above warning about not copying data if
- // |dy| > |clip_rect.height()| technically applies here too, but
- // is implicitly taken care of by the termination condition in the
- // for loop, so we do not need to explicitly check against |dy|.
-
- // TODO(port): According to msdn, positive values of |dy| scroll
- // down, but in practice this seems reversed. Figure this
- // out. For now just reverse the sign.
- dy *= -1;
-
- const int len = clip_rect.width() * 4;
-
- // For down scrolls, we copy bottom-up (in screen coordinates).
- // For up scrolls, we copy top-down.
- if (dy > 0) {
- // Move |x| to the first pixel of the first row of the clip rect.
- x += clip_rect.y() * stride;
- x += clip_rect.x() * 4;
-
- for (int i = 0; i < clip_rect.height() - dy; ++i) {
- memcpy(x, x + stride * dy, len);
- x += stride;
- }
- } else {
- // Move |x| to the first pixel of the last row of the clip rect.
- x += (clip_rect.bottom() - 1) * stride;
- x += clip_rect.x() * 4;
-
- for (int i = 0; i < clip_rect.height() + dy; ++i) {
- memcpy(x, x + stride * dy, len);
- x -= stride;
- }
- }
- }
-
- // Now paint the new bitmap data.
- PaintRect(process, bitmap, bitmap_rect);
- return;
-}
diff --git a/chrome/browser/renderer_host/backing_store_mac.mm b/chrome/browser/renderer_host/backing_store_mac.mm
new file mode 100644
index 0000000..e445f7d
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_mac.mm
@@ -0,0 +1,103 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/renderer_host/backing_store.h"
+
+#include "base/logging.h"
+#include "chrome/common/transport_dib.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+// Mac Backing Stores:
+//
+// Since backing stores are only ever written to or drawn into windows, we keep
+// our backing store in a CGLayer that can get cached in GPU memory. This
+// allows acclerated drawing into the layer and lets scrolling and such happen
+// all or mostly on the GPU, which is good for performance.
+
+BackingStore::BackingStore(RenderWidgetHost* widget, const gfx::Size& size)
+ : render_widget_host_(widget),
+ size_(size),
+ cg_layer_(CGLayerCreateWithContext(static_cast<CGContextRef>(
+ [[NSGraphicsContext currentContext] graphicsPort]), size.ToCGSize(),
+ NULL)) {
+ CHECK(cg_layer_.get() != NULL);
+}
+
+BackingStore::~BackingStore() {
+}
+
+size_t BackingStore::MemorySize() {
+ // Estimate memory usage as 4 bytes per pixel.
+ return size_.GetArea() * 4;
+}
+
+// Paint the contents of a TransportDIB into a rectangle of our CGLayer
+void BackingStore::PaintRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect) {
+ 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));
+
+ // 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);
+}
+
+// Scroll the contents of our CGLayer
+void BackingStore::ScrollRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect,
+ int dx, int dy,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ // "Scroll" the contents of the layer by creating a new CGLayer,
+ // copying the contents of the old one into the new one offset by the scroll
+ // amount, swapping in the new CGLayer, and then painting in the new data.
+ //
+ // The Windows code always sets the whole backing store as the source of the
+ // scroll. Thus, we only have to worry about pixels which will end up inside
+ // the clipping rectangle. (Note that the clipping rectangle is not
+ // translated by the scroll.)
+
+ // We assume |clip_rect| is contained within the backing store.
+ CGSize layer_size = CGLayerGetSize(cg_layer());
+ DCHECK(clip_rect.bottom() <= layer_size.height);
+ DCHECK(clip_rect.right() <= layer_size.width);
+
+ 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);
+ }
+ // Now paint the new bitmap data into the CGLayer
+ 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 ae77260..18674bb 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -545,11 +545,11 @@ void RenderWidgetHostViewMac::SetActive(bool active) {
renderWidgetHostView_->about_to_validate_and_paint_ = true;
BackingStore* backing_store =
renderWidgetHostView_->render_widget_host_->GetBackingStore(true);
- skia::PlatformCanvas* canvas = backing_store->canvas();
renderWidgetHostView_->about_to_validate_and_paint_ = false;
dirtyRect = renderWidgetHostView_->invalid_rect_;
if (backing_store) {
+ NSRect view_bounds = [self bounds];
gfx::Rect damaged_rect([self NSRectToRect:dirtyRect]);
gfx::Rect bitmap_rect(0, 0,
@@ -561,11 +561,9 @@ void RenderWidgetHostViewMac::SetActive(bool active) {
CGContextRef context = static_cast<CGContextRef>(
[[NSGraphicsContext currentContext] graphicsPort]);
- CGRect paint_rect_cg = paint_rect.ToCGRect();
- NSRect paint_rect_ns = [self RectToNSRect:paint_rect];
- canvas->getTopPlatformDevice().DrawToContext(
- context, paint_rect_ns.origin.x, paint_rect_ns.origin.y,
- &paint_rect_cg);
+ // TODO: add clipping to dirtyRect if it improves drawing performance.
+ CGContextDrawLayerAtPoint(context, CGPointMake(0.0, 0.0),
+ backing_store->cg_layer());
}
// Fill the remaining portion of the damaged_rect with white