OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 #include "build/build_config.h" |
| 6 #include "skia/ext/bitmap_platform_device_cairo.h" |
| 7 #include "skia/ext/platform_canvas.h" |
| 8 |
| 9 #if defined(OS_OPENBSD) |
| 10 #include <cairo.h> |
| 11 #else |
| 12 #include <cairo/cairo.h> |
| 13 #endif |
| 14 |
| 15 namespace skia { |
| 16 |
| 17 namespace { |
| 18 |
| 19 void CairoSurfaceReleaseProc(void*, void* context) { |
| 20 SkASSERT(context); |
| 21 cairo_surface_destroy(static_cast<cairo_surface_t*>(context)); |
| 22 } |
| 23 |
| 24 // Back the destination bitmap by a Cairo surface. The bitmap's |
| 25 // pixelRef takes ownership of the passed-in surface and will call |
| 26 // cairo_surface_destroy() upon destruction. |
| 27 // |
| 28 // Note: it may immediately destroy the surface, if it fails to create a bitmap |
| 29 // with pixels, thus the caller must either ref() the surface before hand, or |
| 30 // it must not refer to the surface after this call. |
| 31 bool InstallCairoSurfacePixels(SkBitmap* dst, |
| 32 cairo_surface_t* surface, |
| 33 bool is_opaque) { |
| 34 SkASSERT(dst); |
| 35 if (!surface) { |
| 36 return false; |
| 37 } |
| 38 SkImageInfo info |
| 39 = SkImageInfo::MakeN32(cairo_image_surface_get_width(surface), |
| 40 cairo_image_surface_get_height(surface), |
| 41 is_opaque ? kOpaque_SkAlphaType |
| 42 : kPremul_SkAlphaType); |
| 43 return dst->installPixels(info, |
| 44 cairo_image_surface_get_data(surface), |
| 45 cairo_image_surface_get_stride(surface), |
| 46 NULL, |
| 47 &CairoSurfaceReleaseProc, |
| 48 static_cast<void*>(surface)); |
| 49 } |
| 50 |
| 51 void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) { |
| 52 cairo_matrix_t cairo_matrix; |
| 53 cairo_matrix_init(&cairo_matrix, |
| 54 SkScalarToFloat(matrix.getScaleX()), |
| 55 SkScalarToFloat(matrix.getSkewY()), |
| 56 SkScalarToFloat(matrix.getSkewX()), |
| 57 SkScalarToFloat(matrix.getScaleY()), |
| 58 SkScalarToFloat(matrix.getTranslateX()), |
| 59 SkScalarToFloat(matrix.getTranslateY())); |
| 60 cairo_set_matrix(context, &cairo_matrix); |
| 61 } |
| 62 |
| 63 void LoadClipToContext(cairo_t* context, const SkIRect& clip_bounds) { |
| 64 cairo_reset_clip(context); |
| 65 |
| 66 cairo_rectangle(context, clip_bounds.fLeft, clip_bounds.fTop, |
| 67 clip_bounds.width(), clip_bounds.height()); |
| 68 cairo_clip(context); |
| 69 } |
| 70 |
| 71 } // namespace |
| 72 |
| 73 void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, |
| 74 const SkIRect& clip_bounds) { |
| 75 if (!cairo_) |
| 76 return; // Nothing to do. |
| 77 |
| 78 LoadClipToContext(cairo_, clip_bounds); |
| 79 LoadMatrixToContext(cairo_, transform); |
| 80 } |
| 81 |
| 82 // We use this static factory function instead of the regular constructor so |
| 83 // that we can create the pixel data before calling the constructor. This is |
| 84 // required so that we can call the base class' constructor with the pixel |
| 85 // data. |
| 86 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, |
| 87 bool is_opaque, |
| 88 cairo_surface_t* surface) { |
| 89 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { |
| 90 cairo_surface_destroy(surface); |
| 91 return NULL; |
| 92 } |
| 93 |
| 94 // must call this before trying to install the surface, since that may result |
| 95 // in the surface being destroyed. |
| 96 cairo_t* cairo = cairo_create(surface); |
| 97 |
| 98 SkBitmap bitmap; |
| 99 if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) { |
| 100 cairo_destroy(cairo); |
| 101 return NULL; |
| 102 } |
| 103 |
| 104 // The device object will take ownership of the graphics context. |
| 105 return new BitmapPlatformDevice(bitmap, cairo); |
| 106 } |
| 107 |
| 108 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, |
| 109 bool is_opaque) { |
| 110 // This initializes the bitmap to all zeros. |
| 111 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, |
| 112 width, height); |
| 113 |
| 114 BitmapPlatformDevice* device = Create(width, height, is_opaque, surface); |
| 115 |
| 116 #ifndef NDEBUG |
| 117 if (device && is_opaque) // Fill with bright bluish green |
| 118 SkCanvas(device).drawColor(0xFF00FF80); |
| 119 #endif |
| 120 |
| 121 return device; |
| 122 } |
| 123 |
| 124 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, |
| 125 bool is_opaque, |
| 126 uint8_t* data) { |
| 127 cairo_surface_t* surface = cairo_image_surface_create_for_data( |
| 128 data, CAIRO_FORMAT_ARGB32, width, height, |
| 129 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); |
| 130 |
| 131 return Create(width, height, is_opaque, surface); |
| 132 } |
| 133 |
| 134 // Ownership of the cairo object is transferred. |
| 135 BitmapPlatformDevice::BitmapPlatformDevice( |
| 136 const SkBitmap& bitmap, |
| 137 cairo_t* cairo) |
| 138 : SkBitmapDevice(bitmap), |
| 139 cairo_(cairo) { |
| 140 SetPlatformDevice(this, this); |
| 141 } |
| 142 |
| 143 BitmapPlatformDevice::~BitmapPlatformDevice() { |
| 144 cairo_destroy(cairo_); |
| 145 } |
| 146 |
| 147 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& info, |
| 148 const SkPaint*) { |
| 149 SkASSERT(info.fInfo.colorType() == kN32_SkColorType); |
| 150 return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(), |
| 151 info.fInfo.isOpaque()); |
| 152 } |
| 153 |
| 154 cairo_t* BitmapPlatformDevice::BeginPlatformPaint( |
| 155 const SkMatrix& transform, |
| 156 const SkIRect& clip_bounds) { |
| 157 LoadConfig(transform, clip_bounds); |
| 158 cairo_surface_t* surface = cairo_get_target(cairo_); |
| 159 // Tell cairo to flush anything it has pending. |
| 160 cairo_surface_flush(surface); |
| 161 // Tell Cairo that we (probably) modified (actually, will modify) its pixel |
| 162 // buffer directly. |
| 163 cairo_surface_mark_dirty(surface); |
| 164 return cairo_; |
| 165 } |
| 166 |
| 167 // PlatformCanvas impl |
| 168 |
| 169 std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels( |
| 170 int width, |
| 171 int height, |
| 172 bool is_opaque, |
| 173 uint8_t* data, |
| 174 OnFailureType failureType) { |
| 175 sk_sp<SkBaseDevice> dev( |
| 176 BitmapPlatformDevice::Create(width, height, is_opaque, data)); |
| 177 return CreateCanvas(dev, failureType); |
| 178 } |
| 179 |
| 180 } // namespace skia |
OLD | NEW |