Move action_runner.py out of actions folder prior to moving actions to internal.
[chromium-blink-merge.git] / skia / ext / platform_device_win.cc
blobef48fbd3a38cf2ceb5a854cbeb2fe9562eb28f17
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
3 // found in the LICENSE file.
5 #include "skia/ext/platform_device.h"
7 #include "skia/ext/skia_utils_win.h"
8 #include "third_party/skia/include/core/SkMatrix.h"
9 #include "third_party/skia/include/core/SkPath.h"
10 #include "third_party/skia/include/core/SkRegion.h"
11 #include "third_party/skia/include/core/SkUtils.h"
13 namespace skia {
15 void InitializeDC(HDC context) {
16 // Enables world transformation.
17 // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
18 // counterclockwise direction in logical space. This is equivalent to the
19 // statement that, in the GM_ADVANCED graphics mode, both arc control points
20 // and arcs themselves fully respect the device context's world-to-device
21 // transformation.
22 BOOL res = SetGraphicsMode(context, GM_ADVANCED);
23 SkASSERT(res != 0);
25 // Enables dithering.
26 res = SetStretchBltMode(context, HALFTONE);
27 SkASSERT(res != 0);
28 // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
29 // right after.
30 res = SetBrushOrgEx(context, 0, 0, NULL);
31 SkASSERT(res != 0);
33 // Sets up default orientation.
34 res = SetArcDirection(context, AD_CLOCKWISE);
35 SkASSERT(res != 0);
37 // Sets up default colors.
38 res = SetBkColor(context, RGB(255, 255, 255));
39 SkASSERT(res != CLR_INVALID);
40 res = SetTextColor(context, RGB(0, 0, 0));
41 SkASSERT(res != CLR_INVALID);
42 res = SetDCBrushColor(context, RGB(255, 255, 255));
43 SkASSERT(res != CLR_INVALID);
44 res = SetDCPenColor(context, RGB(0, 0, 0));
45 SkASSERT(res != CLR_INVALID);
47 // Sets up default transparency.
48 res = SetBkMode(context, OPAQUE);
49 SkASSERT(res != 0);
50 res = SetROP2(context, R2_COPYPEN);
51 SkASSERT(res != 0);
54 PlatformSurface PlatformDevice::BeginPlatformPaint() {
55 return 0;
58 void PlatformDevice::EndPlatformPaint() {
59 // We don't clear the DC here since it will be likely to be used again.
60 // Flushing will be done in onAccessBitmap.
63 // static
64 bool PlatformDevice::LoadPathToDC(HDC context, const SkPath& path) {
65 switch (path.getFillType()) {
66 case SkPath::kWinding_FillType: {
67 int res = SetPolyFillMode(context, WINDING);
68 SkASSERT(res != 0);
69 break;
71 case SkPath::kEvenOdd_FillType: {
72 int res = SetPolyFillMode(context, ALTERNATE);
73 SkASSERT(res != 0);
74 break;
76 default: {
77 SkASSERT(false);
78 break;
81 BOOL res = BeginPath(context);
82 if (!res) {
83 return false;
86 CubicPaths paths;
87 if (!SkPathToCubicPaths(&paths, path))
88 return false;
90 std::vector<POINT> points;
91 for (CubicPaths::const_iterator path(paths.begin()); path != paths.end();
92 ++path) {
93 if (!path->size())
94 continue;
95 points.resize(0);
96 points.reserve(path->size() * 3 / 4 + 1);
97 points.push_back(SkPointToPOINT(path->front().p[0]));
98 for (CubicPath::const_iterator point(path->begin()); point != path->end();
99 ++point) {
100 // Never add point->p[0]
101 points.push_back(SkPointToPOINT(point->p[1]));
102 points.push_back(SkPointToPOINT(point->p[2]));
103 points.push_back(SkPointToPOINT(point->p[3]));
105 SkASSERT((points.size() - 1) % 3 == 0);
106 // This is slightly inefficient since all straight line and quadratic lines
107 // are "upgraded" to a cubic line.
108 // TODO(maruel): http://b/1147346 We should use
109 // PolyDraw/PolyBezier/Polyline whenever possible.
110 res = PolyBezier(context, &points.front(),
111 static_cast<DWORD>(points.size()));
112 SkASSERT(res != 0);
113 if (res == 0)
114 break;
116 if (res == 0) {
117 // Make sure the path is discarded.
118 AbortPath(context);
119 } else {
120 res = EndPath(context);
121 SkASSERT(res != 0);
123 return true;
126 // static
127 void PlatformDevice::LoadTransformToDC(HDC dc, const SkMatrix& matrix) {
128 XFORM xf;
129 xf.eM11 = matrix[SkMatrix::kMScaleX];
130 xf.eM21 = matrix[SkMatrix::kMSkewX];
131 xf.eDx = matrix[SkMatrix::kMTransX];
132 xf.eM12 = matrix[SkMatrix::kMSkewY];
133 xf.eM22 = matrix[SkMatrix::kMScaleY];
134 xf.eDy = matrix[SkMatrix::kMTransY];
135 SetWorldTransform(dc, &xf);
138 // static
139 bool PlatformDevice::SkPathToCubicPaths(CubicPaths* paths,
140 const SkPath& skpath) {
141 paths->clear();
142 CubicPath* current_path = NULL;
143 SkPoint current_points[4];
144 CubicPoints points_to_add;
145 SkPath::Iter iter(skpath, false);
146 for (SkPath::Verb verb = iter.next(current_points);
147 verb != SkPath::kDone_Verb;
148 verb = iter.next(current_points)) {
149 switch (verb) {
150 case SkPath::kMove_Verb: { // iter.next returns 1 point
151 // Ignores it since the point is copied in the next operation. See
152 // SkPath::Iter::next() for reference.
153 paths->push_back(CubicPath());
154 current_path = &paths->back();
155 // Skip point addition.
156 continue;
158 case SkPath::kLine_Verb: { // iter.next returns 2 points
159 points_to_add.p[0] = current_points[0];
160 points_to_add.p[1] = current_points[0];
161 points_to_add.p[2] = current_points[1];
162 points_to_add.p[3] = current_points[1];
163 break;
165 case SkPath::kQuad_Verb: { // iter.next returns 3 points
166 points_to_add.p[0] = current_points[0];
167 points_to_add.p[1] = current_points[1];
168 points_to_add.p[2] = current_points[2];
169 points_to_add.p[3] = current_points[2];
170 break;
172 case SkPath::kCubic_Verb: { // iter.next returns 4 points
173 points_to_add.p[0] = current_points[0];
174 points_to_add.p[1] = current_points[1];
175 points_to_add.p[2] = current_points[2];
176 points_to_add.p[3] = current_points[3];
177 break;
179 case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
180 paths->push_back(CubicPath());
181 current_path = &paths->back();
182 continue;
184 default: {
185 current_path = NULL;
186 // Will return false.
187 break;
190 SkASSERT(current_path);
191 if (!current_path) {
192 paths->clear();
193 return false;
195 current_path->push_back(points_to_add);
197 return true;
200 // static
201 void PlatformDevice::LoadClippingRegionToDC(HDC context,
202 const SkRegion& region,
203 const SkMatrix& transformation) {
204 HRGN hrgn;
205 if (region.isEmpty()) {
206 // region can be empty, in which case everything will be clipped.
207 hrgn = CreateRectRgn(0, 0, 0, 0);
208 } else if (region.isRect()) {
209 // We don't apply transformation, because the translation is already applied
210 // to the region.
211 hrgn = CreateRectRgnIndirect(&SkIRectToRECT(region.getBounds()));
212 } else {
213 // It is complex.
214 SkPath path;
215 region.getBoundaryPath(&path);
216 // Clip. Note that windows clipping regions are not affected by the
217 // transform so apply it manually.
218 // Since the transform is given as the original translation of canvas, we
219 // should apply it in reverse.
220 SkMatrix t(transformation);
221 t.setTranslateX(-t.getTranslateX());
222 t.setTranslateY(-t.getTranslateY());
223 path.transform(t);
224 LoadPathToDC(context, path);
225 hrgn = PathToRegion(context);
227 int result = SelectClipRgn(context, hrgn);
228 SkASSERT(result != ERROR);
229 result = DeleteObject(hrgn);
230 SkASSERT(result != 0);
233 } // namespace skia