Roll leveldb from r73 to r75.
[chromium-blink-merge.git] / skia / ext / platform_device_mac.cc
blob6ff017d5cd7d258ae4aa034dac7078f286bc819d
1 // Copyright (c) 2006-2008 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.
5 #include "skia/ext/platform_device.h"
6 #include "skia/ext/bitmap_platform_device.h"
8 #import <ApplicationServices/ApplicationServices.h>
9 #include "skia/ext/skia_utils_mac.h"
10 #include "third_party/skia/include/core/SkMatrix.h"
11 #include "third_party/skia/include/core/SkPath.h"
12 #include "third_party/skia/include/core/SkTypes.h"
13 #include "third_party/skia/include/core/SkUtils.h"
15 namespace skia {
17 CGContextRef GetBitmapContext(SkDevice* device) {
18 PlatformDevice* platform_device = GetPlatformDevice(device);
19 if (platform_device)
20 return platform_device->GetBitmapContext();
22 return NULL;
25 CGContextRef PlatformDevice::BeginPlatformPaint() {
26 return GetBitmapContext();
29 void PlatformDevice::EndPlatformPaint() {
30 // Flushing will be done in onAccessBitmap.
33 // Set up the CGContextRef for peaceful coexistence with Skia
34 void PlatformDevice::InitializeCGContext(CGContextRef context) {
35 // CG defaults to the same settings as Skia
38 // static
39 void PlatformDevice::LoadPathToCGContext(CGContextRef context,
40 const SkPath& path) {
41 // instead of a persistent attribute of the context, CG specifies the fill
42 // type per call, so we just have to load up the geometry.
43 CGContextBeginPath(context);
45 SkPoint points[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
46 SkPath::Iter iter(path, false);
47 for (SkPath::Verb verb = iter.next(points); verb != SkPath::kDone_Verb;
48 verb = iter.next(points)) {
49 switch (verb) {
50 case SkPath::kMove_Verb: { // iter.next returns 1 point
51 CGContextMoveToPoint(context, points[0].fX, points[0].fY);
52 break;
54 case SkPath::kLine_Verb: { // iter.next returns 2 points
55 CGContextAddLineToPoint(context, points[1].fX, points[1].fY);
56 break;
58 case SkPath::kQuad_Verb: { // iter.next returns 3 points
59 CGContextAddQuadCurveToPoint(context, points[1].fX, points[1].fY,
60 points[2].fX, points[2].fY);
61 break;
63 case SkPath::kCubic_Verb: { // iter.next returns 4 points
64 CGContextAddCurveToPoint(context, points[1].fX, points[1].fY,
65 points[2].fX, points[2].fY,
66 points[3].fX, points[3].fY);
67 break;
69 case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
70 break;
72 case SkPath::kDone_Verb: // iter.next returns 0 points
73 default: {
74 SkASSERT(false);
75 break;
79 CGContextClosePath(context);
82 // static
83 void PlatformDevice::LoadTransformToCGContext(CGContextRef context,
84 const SkMatrix& matrix) {
85 // CoreGraphics can concatenate transforms, but not reset the current one.
86 // So in order to get the required behavior here, we need to first make
87 // the current transformation matrix identity and only then load the new one.
89 // Reset matrix to identity.
90 CGAffineTransform orig_cg_matrix = CGContextGetCTM(context);
91 CGAffineTransform orig_cg_matrix_inv = CGAffineTransformInvert(
92 orig_cg_matrix);
93 CGContextConcatCTM(context, orig_cg_matrix_inv);
95 // assert that we have indeed returned to the identity Matrix.
96 SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context)));
98 // Convert xform to CG-land.
99 // Our coordinate system is flipped to match WebKit's so we need to modify
100 // the xform to match that.
101 SkMatrix transformed_matrix = matrix;
102 SkScalar sy = matrix.getScaleY() * (SkScalar)-1;
103 transformed_matrix.setScaleY(sy);
104 size_t height = CGBitmapContextGetHeight(context);
105 SkScalar ty = -matrix.getTranslateY(); // y axis is flipped.
106 transformed_matrix.setTranslateY(ty + (SkScalar)height);
108 CGAffineTransform cg_matrix = gfx::SkMatrixToCGAffineTransform(
109 transformed_matrix);
111 // Load final transform into context.
112 CGContextConcatCTM(context, cg_matrix);
115 // static
116 void PlatformDevice::LoadClippingRegionToCGContext(
117 CGContextRef context,
118 const SkRegion& region,
119 const SkMatrix& transformation) {
120 if (region.isEmpty()) {
121 // region can be empty, in which case everything will be clipped.
122 SkRect rect;
123 rect.setEmpty();
124 CGContextClipToRect(context, gfx::SkRectToCGRect(rect));
125 } else if (region.isRect()) {
126 // CoreGraphics applies the current transform to clip rects, which is
127 // unwanted. Inverse-transform the rect before sending it to CG. This only
128 // works for translations and scaling, but not for rotations (but the
129 // viewport is never rotated anyway).
130 SkMatrix t;
131 bool did_invert = transformation.invert(&t);
132 if (!did_invert)
133 t.reset();
134 // Do the transformation.
135 SkRect rect;
136 rect.set(region.getBounds());
137 t.mapRect(&rect);
138 SkIRect irect;
139 rect.round(&irect);
140 CGContextClipToRect(context, gfx::SkIRectToCGRect(irect));
141 } else {
142 // It is complex.
143 SkPath path;
144 region.getBoundaryPath(&path);
145 // Clip. Note that windows clipping regions are not affected by the
146 // transform so apply it manually.
147 path.transform(transformation);
148 // TODO(playmobil): Implement.
149 SkASSERT(false);
150 // LoadPathToDC(context, path);
151 // hrgn = PathToRegion(context);
155 } // namespace skia