| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "skia/ext/bitmap_platform_device_mac.h" | 5 #include "skia/ext/bitmap_platform_device_mac.h" |
| 6 | 6 |
| 7 #import <ApplicationServices/ApplicationServices.h> | 7 #import <ApplicationServices/ApplicationServices.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <time.h> | 9 #include <time.h> |
| 10 | 10 |
| 11 #include "base/mac/mac_util.h" | 11 #include "base/mac/mac_util.h" |
| 12 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
| 13 #include "skia/ext/bitmap_platform_device.h" | 13 #include "skia/ext/bitmap_platform_device.h" |
| 14 #include "skia/ext/platform_canvas.h" | 14 #include "skia/ext/platform_canvas.h" |
| 15 #include "skia/ext/skia_utils_mac.h" | 15 #include "skia/ext/skia_utils_mac.h" |
| 16 #include "third_party/skia/include/core/SkMatrix.h" | 16 #include "third_party/skia/include/core/SkMatrix.h" |
| 17 #include "third_party/skia/include/core/SkPath.h" | 17 #include "third_party/skia/include/core/SkPath.h" |
| 18 #include "third_party/skia/include/core/SkRegion.h" | 18 #include "third_party/skia/include/core/SkRect.h" |
| 19 #include "third_party/skia/include/core/SkTypes.h" | 19 #include "third_party/skia/include/core/SkTypes.h" |
| 20 | 20 |
| 21 namespace skia { | 21 namespace skia { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 // Returns true if it is unsafe to attempt to allocate an offscreen buffer | 25 // Returns true if it is unsafe to attempt to allocate an offscreen buffer |
| 26 // given these dimensions. | 26 // given these dimensions. |
| 27 bool RasterDeviceTooBigToAllocate(int width, int height) { | 27 bool RasterDeviceTooBigToAllocate(int width, int height) { |
| 28 | 28 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 } | 70 } |
| 71 | 71 |
| 72 } // namespace | 72 } // namespace |
| 73 | 73 |
| 74 void BitmapPlatformDevice::ReleaseBitmapContext() { | 74 void BitmapPlatformDevice::ReleaseBitmapContext() { |
| 75 SkASSERT(bitmap_context_); | 75 SkASSERT(bitmap_context_); |
| 76 CGContextRelease(bitmap_context_); | 76 CGContextRelease(bitmap_context_); |
| 77 bitmap_context_ = NULL; | 77 bitmap_context_ = NULL; |
| 78 } | 78 } |
| 79 | 79 |
| 80 void BitmapPlatformDevice::SetMatrixClip( | |
| 81 const SkMatrix& transform, | |
| 82 const SkRegion& region) { | |
| 83 transform_ = transform; | |
| 84 clip_region_ = region; | |
| 85 config_dirty_ = true; | |
| 86 } | |
| 87 | |
| 88 // Loads the specified Skia transform into the device context | 80 // Loads the specified Skia transform into the device context |
| 89 static void LoadTransformToCGContext(CGContextRef context, | 81 static void LoadTransformToCGContext(CGContextRef context, |
| 90 const SkMatrix& matrix) { | 82 const SkMatrix& matrix) { |
| 91 // CoreGraphics can concatenate transforms, but not reset the current one. | 83 // CoreGraphics can concatenate transforms, but not reset the current one. |
| 92 // So in order to get the required behavior here, we need to first make | 84 // So in order to get the required behavior here, we need to first make |
| 93 // the current transformation matrix identity and only then load the new one. | 85 // the current transformation matrix identity and only then load the new one. |
| 94 | 86 |
| 95 // Reset matrix to identity. | 87 // Reset matrix to identity. |
| 96 CGAffineTransform orig_cg_matrix = CGContextGetCTM(context); | 88 CGAffineTransform orig_cg_matrix = CGContextGetCTM(context); |
| 97 CGAffineTransform orig_cg_matrix_inv = | 89 CGAffineTransform orig_cg_matrix_inv = |
| (...skipping 13 matching lines...) Expand all Loading... |
| 111 SkScalar ty = -matrix.getTranslateY(); // y axis is flipped. | 103 SkScalar ty = -matrix.getTranslateY(); // y axis is flipped. |
| 112 transformed_matrix.setTranslateY(ty + (SkScalar)height); | 104 transformed_matrix.setTranslateY(ty + (SkScalar)height); |
| 113 | 105 |
| 114 CGAffineTransform cg_matrix = | 106 CGAffineTransform cg_matrix = |
| 115 skia::SkMatrixToCGAffineTransform(transformed_matrix); | 107 skia::SkMatrixToCGAffineTransform(transformed_matrix); |
| 116 | 108 |
| 117 // Load final transform into context. | 109 // Load final transform into context. |
| 118 CGContextConcatCTM(context, cg_matrix); | 110 CGContextConcatCTM(context, cg_matrix); |
| 119 } | 111 } |
| 120 | 112 |
| 121 // Loads a SkRegion into the CG context. | |
| 122 static void LoadClippingRegionToCGContext(CGContextRef context, | 113 static void LoadClippingRegionToCGContext(CGContextRef context, |
| 123 const SkRegion& region, | 114 const SkIRect& clip_bounds, |
| 124 const SkMatrix& transformation) { | 115 const SkMatrix& transformation) { |
| 125 if (region.isEmpty()) { | 116 // CoreGraphics applies the current transform to clip rects, which is |
| 126 // region can be empty, in which case everything will be clipped. | 117 // unwanted. Inverse-transform the rect before sending it to CG. This only |
| 127 SkRect rect; | 118 // works for translations and scaling, but not for rotations (but the |
| 128 rect.setEmpty(); | 119 // viewport is never rotated anyway). |
| 129 CGContextClipToRect(context, skia::SkRectToCGRect(rect)); | 120 SkMatrix t; |
| 130 } else if (region.isRect()) { | 121 bool did_invert = transformation.invert(&t); |
| 131 // CoreGraphics applies the current transform to clip rects, which is | 122 if (!did_invert) |
| 132 // unwanted. Inverse-transform the rect before sending it to CG. This only | 123 t.reset(); |
| 133 // works for translations and scaling, but not for rotations (but the | 124 |
| 134 // viewport is never rotated anyway). | 125 SkRect rect = SkRect::Make(clip_bounds); |
| 135 SkMatrix t; | 126 t.mapRect(&rect); |
| 136 bool did_invert = transformation.invert(&t); | 127 SkIRect irect; |
| 137 if (!did_invert) | 128 rect.round(&irect); |
| 138 t.reset(); | 129 CGContextClipToRect(context, skia::SkIRectToCGRect(irect)); |
| 139 // Do the transformation. | |
| 140 SkRect rect; | |
| 141 rect.set(region.getBounds()); | |
| 142 t.mapRect(&rect); | |
| 143 SkIRect irect; | |
| 144 rect.round(&irect); | |
| 145 CGContextClipToRect(context, skia::SkIRectToCGRect(irect)); | |
| 146 } else { | |
| 147 // It is complex. | |
| 148 SkPath path; | |
| 149 region.getBoundaryPath(&path); | |
| 150 // Clip. Note that windows clipping regions are not affected by the | |
| 151 // transform so apply it manually. | |
| 152 path.transform(transformation); | |
| 153 // TODO(playmobil): Implement. | |
| 154 SkASSERT(false); | |
| 155 // LoadPathToDC(context, path); | |
| 156 // hrgn = PathToRegion(context); | |
| 157 } | |
| 158 } | 130 } |
| 159 | 131 |
| 160 void BitmapPlatformDevice::LoadConfig() { | 132 void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, |
| 161 if (!config_dirty_ || !bitmap_context_) | 133 const SkIRect& clip_bounds) { |
| 134 if (!bitmap_context_) |
| 162 return; // Nothing to do. | 135 return; // Nothing to do. |
| 163 config_dirty_ = false; | |
| 164 | 136 |
| 165 // We must restore and then save the state of the graphics context since the | 137 // We must restore and then save the state of the graphics context since the |
| 166 // calls to Load the clipping region to the context are strictly cummulative, | 138 // calls to Load the clipping region to the context are strictly cummulative, |
| 167 // i.e., you can't replace a clip rect, other than with a save/restore. | 139 // i.e., you can't replace a clip rect, other than with a save/restore. |
| 168 // But this implies that no other changes to the state are done elsewhere. | 140 // But this implies that no other changes to the state are done elsewhere. |
| 169 // If we ever get to need to change this, then we must replace the clip rect | 141 // If we ever get to need to change this, then we must replace the clip rect |
| 170 // calls in LoadClippingRegionToCGContext() with an image mask instead. | 142 // calls in LoadClippingRegionToCGContext() with an image mask instead. |
| 171 CGContextRestoreGState(bitmap_context_); | 143 CGContextRestoreGState(bitmap_context_); |
| 172 CGContextSaveGState(bitmap_context_); | 144 CGContextSaveGState(bitmap_context_); |
| 173 LoadTransformToCGContext(bitmap_context_, transform_); | 145 LoadTransformToCGContext(bitmap_context_, transform); |
| 174 LoadClippingRegionToCGContext(bitmap_context_, clip_region_, transform_); | 146 LoadClippingRegionToCGContext(bitmap_context_, clip_bounds, transform); |
| 175 } | 147 } |
| 176 | 148 |
| 177 | 149 |
| 178 // We use this static factory function instead of the regular constructor so | 150 // We use this static factory function instead of the regular constructor so |
| 179 // that we can create the pixel data before calling the constructor. This is | 151 // that we can create the pixel data before calling the constructor. This is |
| 180 // required so that we can call the base class' constructor with the pixel | 152 // required so that we can call the base class' constructor with the pixel |
| 181 // data. | 153 // data. |
| 182 BitmapPlatformDevice* BitmapPlatformDevice::Create(CGContextRef context, | 154 BitmapPlatformDevice* BitmapPlatformDevice::Create(CGContextRef context, |
| 183 int width, | 155 int width, |
| 184 int height, | 156 int height, |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 CGContextRelease(context); | 217 CGContextRelease(context); |
| 246 | 218 |
| 247 return rv; | 219 return rv; |
| 248 } | 220 } |
| 249 | 221 |
| 250 // The device will own the bitmap, which corresponds to also owning the pixel | 222 // The device will own the bitmap, which corresponds to also owning the pixel |
| 251 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. | 223 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. |
| 252 BitmapPlatformDevice::BitmapPlatformDevice( | 224 BitmapPlatformDevice::BitmapPlatformDevice( |
| 253 CGContextRef context, const SkBitmap& bitmap) | 225 CGContextRef context, const SkBitmap& bitmap) |
| 254 : SkBitmapDevice(bitmap), | 226 : SkBitmapDevice(bitmap), |
| 255 bitmap_context_(context), | 227 bitmap_context_(context) { |
| 256 config_dirty_(true), // Want to load the config next time. | |
| 257 transform_(SkMatrix::I()) { | |
| 258 SetPlatformDevice(this, this); | 228 SetPlatformDevice(this, this); |
| 259 SkASSERT(bitmap_context_); | 229 SkASSERT(bitmap_context_); |
| 260 // Initialize the clip region to the entire bitmap. | 230 // Initialize the clip region to the entire bitmap. |
| 261 | 231 |
| 262 SkIRect rect; | 232 SkIRect rect; |
| 263 rect.set(0, 0, | 233 rect.set(0, 0, |
| 264 CGBitmapContextGetWidth(bitmap_context_), | 234 CGBitmapContextGetWidth(bitmap_context_), |
| 265 CGBitmapContextGetHeight(bitmap_context_)); | 235 CGBitmapContextGetHeight(bitmap_context_)); |
| 266 clip_region_ = SkRegion(rect); | |
| 267 CGContextRetain(bitmap_context_); | 236 CGContextRetain(bitmap_context_); |
| 268 // We must save the state once so that we can use the restore/save trick | 237 // We must save the state once so that we can use the restore/save trick |
| 269 // in LoadConfig(). | 238 // in LoadConfig(). |
| 270 CGContextSaveGState(bitmap_context_); | 239 CGContextSaveGState(bitmap_context_); |
| 271 } | 240 } |
| 272 | 241 |
| 273 BitmapPlatformDevice::~BitmapPlatformDevice() { | 242 BitmapPlatformDevice::~BitmapPlatformDevice() { |
| 274 if (bitmap_context_) | 243 if (bitmap_context_) |
| 275 CGContextRelease(bitmap_context_); | 244 CGContextRelease(bitmap_context_); |
| 276 } | 245 } |
| 277 | 246 |
| 278 CGContextRef BitmapPlatformDevice::GetBitmapContext() { | 247 CGContextRef BitmapPlatformDevice::GetBitmapContext(const SkMatrix& transform, |
| 279 LoadConfig(); | 248 const SkIRect& clip_bounds)
{ |
| 249 LoadConfig(transform, clip_bounds); |
| 280 return bitmap_context_; | 250 return bitmap_context_; |
| 281 } | 251 } |
| 282 | 252 |
| 283 void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, | |
| 284 const SkRegion& region, | |
| 285 const SkClipStack&) { | |
| 286 SetMatrixClip(transform, region); | |
| 287 } | |
| 288 | |
| 289 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, | 253 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, |
| 290 const SkPaint*) { | 254 const SkPaint*) { |
| 291 const SkImageInfo& info = cinfo.fInfo; | 255 const SkImageInfo& info = cinfo.fInfo; |
| 292 const bool do_clear = !info.isOpaque(); | 256 const bool do_clear = !info.isOpaque(); |
| 293 SkASSERT(info.colorType() == kN32_SkColorType); | 257 SkASSERT(info.colorType() == kN32_SkColorType); |
| 294 return Create(NULL, info.width(), info.height(), info.isOpaque(), do_clear); | 258 return Create(NULL, info.width(), info.height(), info.isOpaque(), do_clear); |
| 295 } | 259 } |
| 296 | 260 |
| 297 // PlatformCanvas impl | 261 // PlatformCanvas impl |
| 298 | 262 |
| 299 SkCanvas* CreatePlatformCanvas(CGContextRef ctx, int width, int height, | 263 SkCanvas* CreatePlatformCanvas(CGContextRef ctx, int width, int height, |
| 300 bool is_opaque, OnFailureType failureType) { | 264 bool is_opaque, OnFailureType failureType) { |
| 301 const bool do_clear = false; | 265 const bool do_clear = false; |
| 302 sk_sp<SkBaseDevice> dev( | 266 sk_sp<SkBaseDevice> dev( |
| 303 BitmapPlatformDevice::Create(ctx, width, height, is_opaque, do_clear)); | 267 BitmapPlatformDevice::Create(ctx, width, height, is_opaque, do_clear)); |
| 304 return CreateCanvas(dev, failureType); | 268 return CreateCanvas(dev, failureType); |
| 305 } | 269 } |
| 306 | 270 |
| 307 SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque, | 271 SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque, |
| 308 uint8_t* data, OnFailureType failureType) { | 272 uint8_t* data, OnFailureType failureType) { |
| 309 sk_sp<SkBaseDevice> dev( | 273 sk_sp<SkBaseDevice> dev( |
| 310 BitmapPlatformDevice::CreateWithData(data, width, height, is_opaque)); | 274 BitmapPlatformDevice::CreateWithData(data, width, height, is_opaque)); |
| 311 return CreateCanvas(dev, failureType); | 275 return CreateCanvas(dev, failureType); |
| 312 } | 276 } |
| 313 | 277 |
| 314 } // namespace skia | 278 } // namespace skia |
| OLD | NEW |