| // Copyright (c) 2009 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_linux.h" |
| |
| #include <cairo/cairo.h> |
| |
| namespace skia { |
| |
| namespace { |
| |
| 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 |
| |
| // ----------------------------------------------------------------------------- |
| // These objects are reference counted and own a Cairo surface. The surface is |
| // the backing store for a Skia bitmap and we reference count it so that we can |
| // copy BitmapPlatformDevice objects without having to copy all the image |
| // data. |
| // ----------------------------------------------------------------------------- |
| class BitmapPlatformDevice::BitmapPlatformDeviceData |
| : public base::RefCounted<BitmapPlatformDeviceData> { |
| public: |
| explicit BitmapPlatformDeviceData(cairo_surface_t* surface); |
| |
| cairo_t* GetContext(); |
| cairo_surface_t* GetSurface(); |
| |
| // Sets the transform and clip operations. This will not update the Cairo |
| // surface, but will mark the config as dirty. The next call of LoadConfig |
| // will pick up these changes. |
| void SetMatrixClip(const SkMatrix& transform, const SkRegion& region); |
| |
| protected: |
| void LoadConfig(); |
| |
| // The Cairo surface inside this DC. |
| cairo_t* context_; |
| cairo_surface_t *const surface_; |
| |
| // True when there is a transform or clip that has not been set to the |
| // surface. The surface is retrieved for every text operation, and the |
| // transform and clip do not change as much. We can save time by not loading |
| // the clip and transform for every one. |
| bool config_dirty_; |
| |
| // Translation assigned to the DC: we need to keep track of this separately |
| // so it can be updated even if the DC isn't created yet. |
| SkMatrix transform_; |
| |
| // The current clipping |
| SkRegion clip_region_; |
| |
| // Disallow copy & assign. |
| BitmapPlatformDeviceData(const BitmapPlatformDeviceData&); |
| BitmapPlatformDeviceData& operator=( |
| const BitmapPlatformDeviceData&); |
| |
| private: |
| friend class base::RefCounted<BitmapPlatformDeviceData>; |
| |
| ~BitmapPlatformDeviceData(); |
| }; |
| |
| BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData( |
| cairo_surface_t* surface) |
| : surface_(surface), |
| config_dirty_(true) { // Want to load the config next time. |
| context_ = cairo_create(surface); |
| } |
| |
| BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() { |
| cairo_destroy(context_); |
| cairo_surface_destroy(surface_); |
| } |
| |
| cairo_t* BitmapPlatformDevice::BitmapPlatformDeviceData::GetContext() { |
| LoadConfig(); |
| return context_; |
| } |
| |
| void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( |
| const SkMatrix& transform, |
| const SkRegion& region) { |
| transform_ = transform; |
| clip_region_ = region; |
| config_dirty_ = true; |
| } |
| |
| cairo_surface_t* |
| BitmapPlatformDevice::BitmapPlatformDeviceData::GetSurface() { |
| // TODO(brettw) this function should be removed. |
| LoadConfig(); |
| return surface_; |
| } |
| |
| void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() { |
| if (!config_dirty_ || !context_) |
| 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(context_, &cairo_matrix); |
| |
| LoadClipToContext(context_, clip_region_); |
| LoadMatrixToContext(context_, 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) { |
| SkBitmap bitmap; |
| bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, |
| cairo_image_surface_get_stride(surface)); |
| bitmap.setPixels(cairo_image_surface_get_data(surface)); |
| bitmap.setIsOpaque(is_opaque); |
| |
| // The device object will take ownership of the graphics context. |
| return new BitmapPlatformDevice |
| (bitmap, new BitmapPlatformDeviceData(surface)); |
| } |
| |
| BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, |
| bool is_opaque) { |
| cairo_surface_t* surface = |
| cairo_image_surface_create(CAIRO_FORMAT_ARGB32, |
| width, height); |
| |
| BitmapPlatformDevice* device = Create(width, height, is_opaque, surface); |
| |
| #ifndef NDEBUG |
| if (is_opaque) // Fill with bright bluish green |
| device->eraseColor(SkColorSetARGB(255, 0, 255, 128)); |
| #endif |
| |
| return device; |
| } |
| |
| 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); |
| } |
| |
| // The device will own the bitmap, which corresponds to also owning the pixel |
| // data. Therefore, we do not transfer ownership to the SkDevice's bitmap. |
| BitmapPlatformDevice::BitmapPlatformDevice( |
| const SkBitmap& bitmap, |
| BitmapPlatformDeviceData* data) |
| : PlatformDevice(bitmap), |
| data_(data) { |
| } |
| |
| BitmapPlatformDevice::BitmapPlatformDevice( |
| const BitmapPlatformDevice& other) |
| : PlatformDevice(const_cast<BitmapPlatformDevice&>( |
| other).accessBitmap(true)), |
| data_(other.data_) { |
| } |
| |
| BitmapPlatformDevice::~BitmapPlatformDevice() { |
| } |
| |
| cairo_t* BitmapPlatformDevice::beginPlatformPaint() { |
| return data_->GetContext(); |
| } |
| |
| void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, |
| const SkRegion& region) { |
| data_->SetMatrixClip(transform, region); |
| } |
| |
| BitmapPlatformDevice& BitmapPlatformDevice::operator=( |
| const BitmapPlatformDevice& other) { |
| data_ = other.data_; |
| return *this; |
| } |
| |
| } // namespace skia |