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"
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
22 BOOL res
= SetGraphicsMode(context
, GM_ADVANCED
);
26 res
= SetStretchBltMode(context
, HALFTONE
);
28 // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
30 res
= SetBrushOrgEx(context
, 0, 0, NULL
);
33 // Sets up default orientation.
34 res
= SetArcDirection(context
, AD_CLOCKWISE
);
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
);
50 res
= SetROP2(context
, R2_COPYPEN
);
54 PlatformSurface
PlatformDevice::BeginPlatformPaint() {
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 void PlatformDevice::DrawToNativeContext(PlatformSurface surface
, int x
, int y
,
64 const PlatformRect
* src_rect
) {
68 bool PlatformDevice::LoadPathToDC(HDC context
, const SkPath
& path
) {
69 switch (path
.getFillType()) {
70 case SkPath::kWinding_FillType
: {
71 int res
= SetPolyFillMode(context
, WINDING
);
75 case SkPath::kEvenOdd_FillType
: {
76 int res
= SetPolyFillMode(context
, ALTERNATE
);
85 BOOL res
= BeginPath(context
);
91 if (!SkPathToCubicPaths(&paths
, path
))
94 std::vector
<POINT
> points
;
95 for (CubicPaths::const_iterator
path(paths
.begin()); path
!= paths
.end();
100 points
.reserve(path
->size() * 3 / 4 + 1);
101 points
.push_back(SkPointToPOINT(path
->front().p
[0]));
102 for (CubicPath::const_iterator
point(path
->begin()); point
!= path
->end();
104 // Never add point->p[0]
105 points
.push_back(SkPointToPOINT(point
->p
[1]));
106 points
.push_back(SkPointToPOINT(point
->p
[2]));
107 points
.push_back(SkPointToPOINT(point
->p
[3]));
109 SkASSERT((points
.size() - 1) % 3 == 0);
110 // This is slightly inefficient since all straight line and quadratic lines
111 // are "upgraded" to a cubic line.
112 // TODO(maruel): http://b/1147346 We should use
113 // PolyDraw/PolyBezier/Polyline whenever possible.
114 res
= PolyBezier(context
, &points
.front(),
115 static_cast<DWORD
>(points
.size()));
121 // Make sure the path is discarded.
124 res
= EndPath(context
);
131 void PlatformDevice::LoadTransformToDC(HDC dc
, const SkMatrix
& matrix
) {
133 xf
.eM11
= matrix
[SkMatrix::kMScaleX
];
134 xf
.eM21
= matrix
[SkMatrix::kMSkewX
];
135 xf
.eDx
= matrix
[SkMatrix::kMTransX
];
136 xf
.eM12
= matrix
[SkMatrix::kMSkewY
];
137 xf
.eM22
= matrix
[SkMatrix::kMScaleY
];
138 xf
.eDy
= matrix
[SkMatrix::kMTransY
];
139 SetWorldTransform(dc
, &xf
);
143 bool PlatformDevice::SkPathToCubicPaths(CubicPaths
* paths
,
144 const SkPath
& skpath
) {
146 CubicPath
* current_path
= NULL
;
147 SkPoint current_points
[4];
148 CubicPoints points_to_add
;
149 SkPath::Iter
iter(skpath
, false);
150 for (SkPath::Verb verb
= iter
.next(current_points
);
151 verb
!= SkPath::kDone_Verb
;
152 verb
= iter
.next(current_points
)) {
154 case SkPath::kMove_Verb
: { // iter.next returns 1 point
155 // Ignores it since the point is copied in the next operation. See
156 // SkPath::Iter::next() for reference.
157 paths
->push_back(CubicPath());
158 current_path
= &paths
->back();
159 // Skip point addition.
162 case SkPath::kLine_Verb
: { // iter.next returns 2 points
163 points_to_add
.p
[0] = current_points
[0];
164 points_to_add
.p
[1] = current_points
[0];
165 points_to_add
.p
[2] = current_points
[1];
166 points_to_add
.p
[3] = current_points
[1];
169 case SkPath::kQuad_Verb
: { // iter.next returns 3 points
170 points_to_add
.p
[0] = current_points
[0];
171 points_to_add
.p
[1] = current_points
[1];
172 points_to_add
.p
[2] = current_points
[2];
173 points_to_add
.p
[3] = current_points
[2];
176 case SkPath::kCubic_Verb
: { // iter.next returns 4 points
177 points_to_add
.p
[0] = current_points
[0];
178 points_to_add
.p
[1] = current_points
[1];
179 points_to_add
.p
[2] = current_points
[2];
180 points_to_add
.p
[3] = current_points
[3];
183 case SkPath::kClose_Verb
: { // iter.next returns 1 point (the last point)
184 paths
->push_back(CubicPath());
185 current_path
= &paths
->back();
190 // Will return false.
194 SkASSERT(current_path
);
199 current_path
->push_back(points_to_add
);
205 void PlatformDevice::LoadClippingRegionToDC(HDC context
,
206 const SkRegion
& region
,
207 const SkMatrix
& transformation
) {
209 if (region
.isEmpty()) {
210 // region can be empty, in which case everything will be clipped.
211 hrgn
= CreateRectRgn(0, 0, 0, 0);
212 } else if (region
.isRect()) {
213 // We don't apply transformation, because the translation is already applied
215 hrgn
= CreateRectRgnIndirect(&SkIRectToRECT(region
.getBounds()));
219 region
.getBoundaryPath(&path
);
220 // Clip. Note that windows clipping regions are not affected by the
221 // transform so apply it manually.
222 // Since the transform is given as the original translation of canvas, we
223 // should apply it in reverse.
224 SkMatrix
t(transformation
);
225 t
.setTranslateX(-t
.getTranslateX());
226 t
.setTranslateY(-t
.getTranslateY());
228 LoadPathToDC(context
, path
);
229 hrgn
= PathToRegion(context
);
231 int result
= SelectClipRgn(context
, hrgn
);
232 SkASSERT(result
!= ERROR
);
233 result
= DeleteObject(hrgn
);
234 SkASSERT(result
!= 0);