| Index: skia/ext/bitmap_platform_device_cairo.cc
|
| diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a331bed0612ede805a9037976aeedaa8daceffd9
|
| --- /dev/null
|
| +++ b/skia/ext/bitmap_platform_device_cairo.cc
|
| @@ -0,0 +1,225 @@
|
| +// Copyright 2013 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 "skia/ext/bitmap_platform_device_cairo.h"
|
| +#include "skia/ext/platform_canvas.h"
|
| +
|
| +#if defined(OS_OPENBSD)
|
| +#include <cairo.h>
|
| +#else
|
| +#include <cairo/cairo.h>
|
| +#endif
|
| +
|
| +namespace skia {
|
| +
|
| +namespace {
|
| +
|
| +void CairoSurfaceReleaseProc(void*, void* context) {
|
| + SkASSERT(context);
|
| + cairo_surface_destroy(static_cast<cairo_surface_t*>(context));
|
| +}
|
| +
|
| +// Back the destination bitmap by a Cairo surface. The bitmap's
|
| +// pixelRef takes ownership of the passed-in surface and will call
|
| +// cairo_surface_destroy() upon destruction.
|
| +//
|
| +// Note: it may immediately destroy the surface, if it fails to create a bitmap
|
| +// with pixels, thus the caller must either ref() the surface before hand, or
|
| +// it must not refer to the surface after this call.
|
| +bool InstallCairoSurfacePixels(SkBitmap* dst,
|
| + cairo_surface_t* surface,
|
| + bool is_opaque) {
|
| + SkASSERT(dst);
|
| + if (!surface) {
|
| + return false;
|
| + }
|
| + SkImageInfo info
|
| + = SkImageInfo::MakeN32Premul(cairo_image_surface_get_width(surface),
|
| + cairo_image_surface_get_height(surface));
|
| + return dst->installPixels(info,
|
| + cairo_image_surface_get_data(surface),
|
| + cairo_image_surface_get_stride(surface),
|
| + NULL,
|
| + &CairoSurfaceReleaseProc,
|
| + static_cast<void*>(surface));
|
| +}
|
| +
|
| +void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) {
|
| + cairo_matrix_t cairo_matrix;
|
| + cairo_matrix_init(&cairo_matrix,
|
| + SkScalarToFloat(matrix.getScaleX()),
|
| + SkScalarToFloat(matrix.getSkewY()),
|
| + SkScalarToFloat(matrix.getSkewX()),
|
| + SkScalarToFloat(matrix.getScaleY()),
|
| + SkScalarToFloat(matrix.getTranslateX()),
|
| + SkScalarToFloat(matrix.getTranslateY()));
|
| + cairo_set_matrix(context, &cairo_matrix);
|
| +}
|
| +
|
| +void LoadClipToContext(cairo_t* context, const SkRegion& clip) {
|
| + cairo_reset_clip(context);
|
| +
|
| + // TODO(brettw) support non-rect clips.
|
| + SkIRect bounding = clip.getBounds();
|
| + cairo_rectangle(context, bounding.fLeft, bounding.fTop,
|
| + bounding.fRight - bounding.fLeft,
|
| + bounding.fBottom - bounding.fTop);
|
| + cairo_clip(context);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void BitmapPlatformDevice::SetMatrixClip(
|
| + const SkMatrix& transform,
|
| + const SkRegion& region) {
|
| + transform_ = transform;
|
| + clip_region_ = region;
|
| + config_dirty_ = true;
|
| +}
|
| +
|
| +void BitmapPlatformDevice::LoadConfig() {
|
| + if (!config_dirty_ || !cairo_)
|
| + return; // Nothing to do.
|
| + config_dirty_ = false;
|
| +
|
| + // Load the identity matrix since this is what our clip is relative to.
|
| + cairo_matrix_t cairo_matrix;
|
| + cairo_matrix_init_identity(&cairo_matrix);
|
| + cairo_set_matrix(cairo_, &cairo_matrix);
|
| +
|
| + LoadClipToContext(cairo_, clip_region_);
|
| + LoadMatrixToContext(cairo_, transform_);
|
| +}
|
| +
|
| +// We use this static factory function instead of the regular constructor so
|
| +// that we can create the pixel data before calling the constructor. This is
|
| +// required so that we can call the base class' constructor with the pixel
|
| +// data.
|
| +BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
|
| + bool is_opaque,
|
| + cairo_surface_t* surface) {
|
| + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
|
| + cairo_surface_destroy(surface);
|
| + return NULL;
|
| + }
|
| +
|
| + // must call this before trying to install the surface, since that may result
|
| + // in the surface being destroyed.
|
| + cairo_t* cairo = cairo_create(surface);
|
| +
|
| + SkBitmap bitmap;
|
| + if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) {
|
| + cairo_destroy(cairo);
|
| + return NULL;
|
| + }
|
| +
|
| + // The device object will take ownership of the graphics context.
|
| + return new BitmapPlatformDevice(bitmap, cairo);
|
| +}
|
| +
|
| +BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
|
| + bool is_opaque) {
|
| + // This initializes the bitmap to all zeros.
|
| + cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
| + width, height);
|
| +
|
| + BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
|
| +
|
| +#ifndef NDEBUG
|
| + if (device && is_opaque) // Fill with bright bluish green
|
| + SkCanvas(device).drawColor(0xFF00FF80);
|
| +#endif
|
| +
|
| + return device;
|
| +}
|
| +
|
| +BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
|
| + int height,
|
| + bool is_opaque) {
|
| + // The Linux port always constructs initialized bitmaps, so there is no extra
|
| + // work to perform here.
|
| + return Create(width, height, is_opaque);
|
| +}
|
| +
|
| +BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
|
| + bool is_opaque,
|
| + uint8_t* data) {
|
| + cairo_surface_t* surface = cairo_image_surface_create_for_data(
|
| + data, CAIRO_FORMAT_ARGB32, width, height,
|
| + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
|
| +
|
| + return Create(width, height, is_opaque, surface);
|
| +}
|
| +
|
| +// Ownership of the cairo object is transferred.
|
| +BitmapPlatformDevice::BitmapPlatformDevice(
|
| + const SkBitmap& bitmap,
|
| + cairo_t* cairo)
|
| + : SkBitmapDevice(bitmap),
|
| + cairo_(cairo),
|
| + config_dirty_(true),
|
| + transform_(SkMatrix::I()) { // Want to load the config next time.
|
| + SetPlatformDevice(this, this);
|
| +}
|
| +
|
| +BitmapPlatformDevice::~BitmapPlatformDevice() {
|
| + cairo_destroy(cairo_);
|
| +}
|
| +
|
| +SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
|
| + const CreateInfo& info) {
|
| + SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
|
| + return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
|
| + info.fInfo.isOpaque());
|
| +}
|
| +
|
| +cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
|
| + LoadConfig();
|
| + cairo_surface_t* surface = cairo_get_target(cairo_);
|
| + // Tell cairo to flush anything it has pending.
|
| + cairo_surface_flush(surface);
|
| + // Tell Cairo that we (probably) modified (actually, will modify) its pixel
|
| + // buffer directly.
|
| + cairo_surface_mark_dirty(surface);
|
| + return cairo_;
|
| +}
|
| +
|
| +void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
|
| + const SkRegion& region,
|
| + const SkClipStack&) {
|
| + SetMatrixClip(transform, region);
|
| +}
|
| +
|
| +// PlatformCanvas impl
|
| +
|
| +SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque,
|
| + uint8_t* data, OnFailureType failureType) {
|
| + skia::RefPtr<SkBaseDevice> dev = skia::AdoptRef(
|
| + BitmapPlatformDevice::Create(width, height, is_opaque, data));
|
| + return CreateCanvas(dev, failureType);
|
| +}
|
| +
|
| +// Port of PlatformBitmap to linux
|
| +PlatformBitmap::~PlatformBitmap() {
|
| + cairo_destroy(surface_);
|
| +}
|
| +
|
| +bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) {
|
| + // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
|
| + // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
|
| + // outlive the PlatformBitmap if additional copies are made.
|
| + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
| +
|
| + cairo_surface_t* surf = cairo_image_surface_create(
|
| + CAIRO_FORMAT_ARGB32,
|
| + width,
|
| + height);
|
| + if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
|
| + cairo_surface_destroy(surf);
|
| + return false;
|
| + }
|
| + return InstallCairoSurfacePixels(&bitmap_, surf, is_opaque);
|
| +}
|
| +
|
| +} // namespace skia
|
|
|