OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "skia/ext/platform_device.h" | |
6 | |
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" | |
12 | |
13 namespace skia { | |
14 | |
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); | |
24 | |
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); | |
32 | |
33 // Sets up default orientation. | |
34 res = SetArcDirection(context, AD_CLOCKWISE); | |
35 SkASSERT(res != 0); | |
36 | |
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); | |
46 | |
47 // Sets up default transparency. | |
48 res = SetBkMode(context, OPAQUE); | |
49 SkASSERT(res != 0); | |
50 res = SetROP2(context, R2_COPYPEN); | |
51 SkASSERT(res != 0); | |
52 } | |
53 | |
54 PlatformSurface PlatformDevice::BeginPlatformPaint() { | |
55 return 0; | |
56 } | |
57 | |
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. | |
61 } | |
62 | |
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; | |
70 } | |
71 case SkPath::kEvenOdd_FillType: { | |
72 int res = SetPolyFillMode(context, ALTERNATE); | |
73 SkASSERT(res != 0); | |
74 break; | |
75 } | |
76 default: { | |
77 SkASSERT(false); | |
78 break; | |
79 } | |
80 } | |
81 BOOL res = BeginPath(context); | |
82 if (!res) { | |
83 return false; | |
84 } | |
85 | |
86 CubicPaths paths; | |
87 if (!SkPathToCubicPaths(&paths, path)) | |
88 return false; | |
89 | |
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])); | |
104 } | |
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; | |
115 } | |
116 if (res == 0) { | |
117 // Make sure the path is discarded. | |
118 AbortPath(context); | |
119 } else { | |
120 res = EndPath(context); | |
121 SkASSERT(res != 0); | |
122 } | |
123 return true; | |
124 } | |
125 | |
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); | |
136 } | |
137 | |
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; | |
157 } | |
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; | |
164 } | |
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; | |
171 } | |
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; | |
178 } | |
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; | |
183 } | |
184 default: { | |
185 current_path = NULL; | |
186 // Will return false. | |
187 break; | |
188 } | |
189 } | |
190 SkASSERT(current_path); | |
191 if (!current_path) { | |
192 paths->clear(); | |
193 return false; | |
194 } | |
195 current_path->push_back(points_to_add); | |
196 } | |
197 return true; | |
198 } | |
199 | |
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); | |
226 } | |
227 int result = SelectClipRgn(context, hrgn); | |
228 SkASSERT(result != ERROR); | |
229 result = DeleteObject(hrgn); | |
230 SkASSERT(result != 0); | |
231 } | |
232 | |
233 } // namespace skia | |
OLD | NEW |