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.
64 bool PlatformDevice::LoadPathToDC(HDC context
, const SkPath
& path
) {
65 switch (path
.getFillType()) {
66 case SkPath::kWinding_FillType
: {
67 int res
= SetPolyFillMode(context
, WINDING
);
71 case SkPath::kEvenOdd_FillType
: {
72 int res
= SetPolyFillMode(context
, ALTERNATE
);
81 BOOL res
= BeginPath(context
);
87 if (!SkPathToCubicPaths(&paths
, path
))
90 std::vector
<POINT
> points
;
91 for (CubicPaths::const_iterator
path(paths
.begin()); path
!= paths
.end();
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();
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()));
117 // Make sure the path is discarded.
120 res
= EndPath(context
);
127 void PlatformDevice::LoadTransformToDC(HDC dc
, const SkMatrix
& matrix
) {
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
);
139 bool PlatformDevice::SkPathToCubicPaths(CubicPaths
* paths
,
140 const SkPath
& skpath
) {
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
)) {
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.
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];
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];
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];
179 case SkPath::kClose_Verb
: { // iter.next returns 1 point (the last point)
180 paths
->push_back(CubicPath());
181 current_path
= &paths
->back();
186 // Will return false.
190 SkASSERT(current_path
);
195 current_path
->push_back(points_to_add
);
201 void PlatformDevice::LoadClippingRegionToDC(HDC context
,
202 const SkRegion
& region
,
203 const SkMatrix
& transformation
) {
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
211 hrgn
= CreateRectRgnIndirect(&SkIRectToRECT(region
.getBounds()));
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());
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);