| 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 |