| Index: chrome/browser/renderer_host/backing_store_mac.mm
|
| ===================================================================
|
| --- chrome/browser/renderer_host/backing_store_mac.mm (revision 75488)
|
| +++ chrome/browser/renderer_host/backing_store_mac.mm (working copy)
|
| @@ -1,242 +0,0 @@
|
| -// Copyright (c) 2010 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_mac.h"
|
| -
|
| -#include "app/surface/transport_dib.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/mac_util.h"
|
| -#include "base/mac/scoped_cftyperef.h"
|
| -#include "base/sys_info.h"
|
| -#include "chrome/browser/renderer_host/render_process_host.h"
|
| -#include "chrome/browser/renderer_host/render_widget_host.h"
|
| -#include "chrome/browser/renderer_host/render_widget_host_view.h"
|
| -#include "skia/ext/platform_canvas.h"
|
| -#include "third_party/skia/include/core/SkBitmap.h"
|
| -#include "third_party/skia/include/core/SkCanvas.h"
|
| -#include "ui/gfx/rect.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.
|
| -
|
| -namespace {
|
| -
|
| -// Returns whether this version of OS X has broken CGLayers, see
|
| -// http://crbug.com/45553 , comments 5 and 6.
|
| -bool NeedsLayerWorkaround() {
|
| - int32 os_major, os_minor, os_bugfix;
|
| - base::SysInfo::OperatingSystemVersionNumbers(
|
| - &os_major, &os_minor, &os_bugfix);
|
| - return os_major == 10 && os_minor == 5;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -BackingStoreMac::BackingStoreMac(RenderWidgetHost* widget,
|
| - const gfx::Size& size)
|
| - : BackingStore(widget, size) {
|
| - cg_layer_.reset(CreateCGLayer());
|
| - if (!cg_layer_) {
|
| - // The view isn't in a window yet. Use a CGBitmapContext for now.
|
| - cg_bitmap_.reset(CreateCGBitmapContext());
|
| - }
|
| -}
|
| -
|
| -BackingStoreMac::~BackingStoreMac() {
|
| -}
|
| -
|
| -void BackingStoreMac::PaintToBackingStore(
|
| - RenderProcessHost* process,
|
| - TransportDIB::Id bitmap,
|
| - const gfx::Rect& bitmap_rect,
|
| - const std::vector<gfx::Rect>& copy_rects) {
|
| - DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
|
| -
|
| - TransportDIB* dib = process->GetTransportDIB(bitmap);
|
| - if (!dib)
|
| - return;
|
| -
|
| - base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider(
|
| - CGDataProviderCreateWithData(NULL, dib->memory(),
|
| - bitmap_rect.width() * bitmap_rect.height() * 4, NULL));
|
| -
|
| - base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
|
| - CGImageCreate(bitmap_rect.width(), bitmap_rect.height(), 8, 32,
|
| - 4 * bitmap_rect.width(), base::mac::GetSystemColorSpace(),
|
| - kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
|
| - data_provider, NULL, false, kCGRenderingIntentDefault));
|
| -
|
| - for (size_t i = 0; i < copy_rects.size(); i++) {
|
| - const gfx::Rect& copy_rect = copy_rects[i];
|
| -
|
| - // Only the subpixels given by copy_rect have pixels to copy.
|
| - base::mac::ScopedCFTypeRef<CGImageRef> image(
|
| - CGImageCreateWithImageInRect(bitmap_image, CGRectMake(
|
| - copy_rect.x() - bitmap_rect.x(),
|
| - copy_rect.y() - bitmap_rect.y(),
|
| - copy_rect.width(),
|
| - copy_rect.height())));
|
| -
|
| - if (!cg_layer()) {
|
| - // The view may have moved to a window. Try to get a CGLayer.
|
| - cg_layer_.reset(CreateCGLayer());
|
| - if (cg_layer()) {
|
| - // now that we have a layer, copy the cached image into it
|
| - base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
|
| - CGBitmapContextCreateImage(cg_bitmap_));
|
| - CGContextDrawImage(CGLayerGetContext(cg_layer()),
|
| - CGRectMake(0, 0, size().width(), size().height()),
|
| - bitmap_image);
|
| - // Discard the cache bitmap, since we no longer need it.
|
| - cg_bitmap_.reset(NULL);
|
| - }
|
| - }
|
| -
|
| - DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
|
| -
|
| - 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 = copy_rect;
|
| - paint_rect.set_y(size().height() - copy_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 = copy_rect;
|
| - paint_rect.set_y(size().height() - copy_rect.bottom());
|
| - CGContextDrawImage(cg_bitmap_, paint_rect.ToCGRect(), image);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool BackingStoreMac::CopyFromBackingStore(const gfx::Rect& rect,
|
| - skia::PlatformCanvas* output) {
|
| - if (!output->initialize(rect.width(), rect.height(), true))
|
| - return false;
|
| -
|
| - CGContextRef temp_context = output->beginPlatformPaint();
|
| - CGContextSaveGState(temp_context);
|
| - CGContextTranslateCTM(temp_context, 0.0, size().height());
|
| - CGContextScaleCTM(temp_context, 1.0, -1.0);
|
| - CGContextDrawLayerAtPoint(temp_context, CGPointMake(rect.x(), rect.y()),
|
| - cg_layer());
|
| - CGContextRestoreGState(temp_context);
|
| - output->endPlatformPaint();
|
| - return true;
|
| -}
|
| -
|
| -// Scroll the contents of our CGLayer
|
| -void BackingStoreMac::ScrollBackingStore(int dx, int dy,
|
| - const gfx::Rect& clip_rect,
|
| - const gfx::Size& view_size) {
|
| - DCHECK_NE(static_cast<bool>(cg_layer()), static_cast<bool>(cg_bitmap()));
|
| -
|
| - // "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.
|
| - DCHECK(clip_rect.bottom() <= size().height());
|
| - DCHECK(clip_rect.right() <= size().width());
|
| -
|
| - if ((dx || dy) && abs(dx) < size().width() && abs(dy) < size().height()) {
|
| - if (cg_layer()) {
|
| - // See http://crbug.com/45553 , comments 5 and 6.
|
| - static bool needs_layer_workaround = NeedsLayerWorkaround();
|
| -
|
| - base::mac::ScopedCFTypeRef<CGLayerRef> new_layer;
|
| - CGContextRef layer;
|
| -
|
| - if (needs_layer_workaround) {
|
| - new_layer.reset(CreateCGLayer());
|
| - // If the current view is in a window, the replacement must be too.
|
| - DCHECK(new_layer);
|
| -
|
| - layer = CGLayerGetContext(new_layer);
|
| - CGContextDrawLayerAtPoint(layer, CGPointMake(0, 0), cg_layer());
|
| - } else {
|
| - layer = CGLayerGetContext(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);
|
| -
|
| - if (needs_layer_workaround)
|
| - cg_layer_.swap(new_layer);
|
| - } else {
|
| - // We don't have a layer, so scroll the contents of the CGBitmapContext.
|
| - base::mac::ScopedCFTypeRef<CGImageRef> bitmap_image(
|
| - CGBitmapContextCreateImage(cg_bitmap_));
|
| - CGContextSaveGState(cg_bitmap_);
|
| - CGContextClipToRect(cg_bitmap_,
|
| - CGRectMake(clip_rect.x(),
|
| - size().height() - clip_rect.bottom(),
|
| - clip_rect.width(),
|
| - clip_rect.height()));
|
| - CGContextDrawImage(cg_bitmap_,
|
| - CGRectMake(dx, -dy, size().width(), size().height()),
|
| - bitmap_image);
|
| - CGContextRestoreGState(cg_bitmap_);
|
| - }
|
| - }
|
| -}
|
| -
|
| -CGLayerRef BackingStoreMac::CreateCGLayer() {
|
| - // The CGLayer should be optimized for drawing into the containing window,
|
| - // so extract a CGContext corresponding to the window to be passed to
|
| - // CGLayerCreateWithContext.
|
| - NSWindow* window = [render_widget_host()->view()->GetNativeView() window];
|
| - if ([window windowNumber] <= 0) {
|
| - // This catches a nil |window|, as well as windows that exist but that
|
| - // aren't yet connected to WindowServer.
|
| - return NULL;
|
| - }
|
| -
|
| - NSGraphicsContext* ns_context = [window graphicsContext];
|
| - DCHECK(ns_context);
|
| -
|
| - CGContextRef cg_context = static_cast<CGContextRef>(
|
| - [ns_context graphicsPort]);
|
| - DCHECK(cg_context);
|
| -
|
| - CGLayerRef layer = CGLayerCreateWithContext(cg_context,
|
| - size().ToCGSize(),
|
| - NULL);
|
| - DCHECK(layer);
|
| -
|
| - return layer;
|
| -}
|
| -
|
| -CGContextRef BackingStoreMac::CreateCGBitmapContext() {
|
| - // A CGBitmapContext serves as a stand-in for the layer before the view is
|
| - // in a containing window.
|
| - CGContextRef context = CGBitmapContextCreate(NULL,
|
| - size().width(), size().height(),
|
| - 8, size().width() * 4,
|
| - base::mac::GetSystemColorSpace(),
|
| - kCGImageAlphaPremultipliedFirst |
|
| - kCGBitmapByteOrder32Host);
|
| - DCHECK(context);
|
| -
|
| - return context;
|
| -}
|
|
|