- add sources.
[platform/framework/web/crosswalk.git] / src / skia / ext / platform_device_mac.cc
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.
4
5 #include "skia/ext/platform_device.h"
6 #include "skia/ext/bitmap_platform_device.h"
7
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"
14
15 namespace skia {
16
17 CGContextRef GetBitmapContext(SkBaseDevice* device) {
18   PlatformDevice* platform_device = GetPlatformDevice(device);
19   if (platform_device)
20     return platform_device->GetBitmapContext();
21
22   return NULL;
23 }
24
25 CGContextRef PlatformDevice::BeginPlatformPaint() {
26   return GetBitmapContext();
27 }
28
29 void PlatformDevice::EndPlatformPaint() {
30   // Flushing will be done in onAccessBitmap.
31 }
32
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
36 }
37
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);
44
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;
53       }
54       case SkPath::kLine_Verb: {  // iter.next returns 2 points
55         CGContextAddLineToPoint(context, points[1].fX, points[1].fY);
56         break;
57       }
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;
62       }
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;
68       }
69       case SkPath::kClose_Verb: {  // iter.next returns 1 point (the last point)
70         break;
71       }
72       case SkPath::kDone_Verb:  // iter.next returns 0 points
73       default: {
74         SkASSERT(false);
75         break;
76       }
77     }
78   }
79   CGContextClosePath(context);
80 }
81
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.
88
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);
94
95   // assert that we have indeed returned to the identity Matrix.
96   SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context)));
97
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);
107
108   CGAffineTransform cg_matrix = gfx::SkMatrixToCGAffineTransform(
109       transformed_matrix);
110
111   // Load final transform into context.
112   CGContextConcatCTM(context, cg_matrix);
113 }
114
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);
152   }
153 }
154
155 }  // namespace skia