| OLD | NEW |
| (Empty) |
| 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 "PlatformDeviceWin.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/gfx/skia_utils.h" | |
| 9 #include "SkMatrix.h" | |
| 10 #include "SkPath.h" | |
| 11 #include "SkRegion.h" | |
| 12 #include "SkUtils.h" | |
| 13 | |
| 14 namespace gfx { | |
| 15 | |
| 16 PlatformDeviceWin::PlatformDeviceWin(const SkBitmap& bitmap) | |
| 17 : SkDevice(bitmap) { | |
| 18 } | |
| 19 | |
| 20 // static | |
| 21 void PlatformDeviceWin::InitializeDC(HDC context) { | |
| 22 // Enables world transformation. | |
| 23 // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the | |
| 24 // counterclockwise direction in logical space. This is equivalent to the | |
| 25 // statement that, in the GM_ADVANCED graphics mode, both arc control points | |
| 26 // and arcs themselves fully respect the device context's world-to-device | |
| 27 // transformation. | |
| 28 BOOL res = SetGraphicsMode(context, GM_ADVANCED); | |
| 29 DCHECK_NE(res, 0); | |
| 30 | |
| 31 // Enables dithering. | |
| 32 res = SetStretchBltMode(context, HALFTONE); | |
| 33 DCHECK_NE(res, 0); | |
| 34 // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called | |
| 35 // right after. | |
| 36 res = SetBrushOrgEx(context, 0, 0, NULL); | |
| 37 DCHECK_NE(res, 0); | |
| 38 | |
| 39 // Sets up default orientation. | |
| 40 res = SetArcDirection(context, AD_CLOCKWISE); | |
| 41 DCHECK_NE(res, 0); | |
| 42 | |
| 43 // Sets up default colors. | |
| 44 res = SetBkColor(context, RGB(255, 255, 255)); | |
| 45 DCHECK_NE(res, CLR_INVALID); | |
| 46 res = SetTextColor(context, RGB(0, 0, 0)); | |
| 47 DCHECK_NE(res, CLR_INVALID); | |
| 48 res = SetDCBrushColor(context, RGB(255, 255, 255)); | |
| 49 DCHECK_NE(res, CLR_INVALID); | |
| 50 res = SetDCPenColor(context, RGB(0, 0, 0)); | |
| 51 DCHECK_NE(res, CLR_INVALID); | |
| 52 | |
| 53 // Sets up default transparency. | |
| 54 res = SetBkMode(context, OPAQUE); | |
| 55 DCHECK_NE(res, 0); | |
| 56 res = SetROP2(context, R2_COPYPEN); | |
| 57 DCHECK_NE(res, 0); | |
| 58 } | |
| 59 | |
| 60 // static | |
| 61 void PlatformDeviceWin::LoadPathToDC(HDC context, const SkPath& path) { | |
| 62 switch (path.getFillType()) { | |
| 63 case SkPath::kWinding_FillType: { | |
| 64 int res = SetPolyFillMode(context, WINDING); | |
| 65 DCHECK(res != 0); | |
| 66 break; | |
| 67 } | |
| 68 case SkPath::kEvenOdd_FillType: { | |
| 69 int res = SetPolyFillMode(context, ALTERNATE); | |
| 70 DCHECK(res != 0); | |
| 71 break; | |
| 72 } | |
| 73 default: { | |
| 74 NOTREACHED(); | |
| 75 break; | |
| 76 } | |
| 77 } | |
| 78 BOOL res = BeginPath(context); | |
| 79 DCHECK(res != 0); | |
| 80 | |
| 81 CubicPaths paths; | |
| 82 if (!SkPathToCubicPaths(&paths, path)) | |
| 83 return; | |
| 84 | |
| 85 std::vector<POINT> points; | |
| 86 for (CubicPaths::const_iterator path(paths.begin()); path != paths.end(); | |
| 87 ++path) { | |
| 88 if (!path->size()) | |
| 89 continue; | |
| 90 // DCHECK_EQ(points.size() % 4, 0); | |
| 91 points.resize(0); | |
| 92 points.reserve(path->size() * 3 / 4 + 1); | |
| 93 points.push_back(SkPointToPOINT(path->front().p[0])); | |
| 94 for (CubicPath::const_iterator point(path->begin()); point != path->end(); | |
| 95 ++point) { | |
| 96 // Never add point->p[0] | |
| 97 points.push_back(SkPointToPOINT(point->p[1])); | |
| 98 points.push_back(SkPointToPOINT(point->p[2])); | |
| 99 points.push_back(SkPointToPOINT(point->p[3])); | |
| 100 } | |
| 101 DCHECK_EQ((points.size() - 1) % 3, 0); | |
| 102 // This is slightly inefficient since all straight line and quadratic lines | |
| 103 // are "upgraded" to a cubic line. | |
| 104 // TODO(maruel): http://b/1147346 We should use | |
| 105 // PolyDraw/PolyBezier/Polyline whenever possible. | |
| 106 res = PolyBezier(context, &points.front(), | |
| 107 static_cast<DWORD>(points.size())); | |
| 108 DCHECK_NE(res, 0); | |
| 109 if (res == 0) | |
| 110 break; | |
| 111 } | |
| 112 if (res == 0) { | |
| 113 // Make sure the path is discarded. | |
| 114 AbortPath(context); | |
| 115 } else { | |
| 116 res = EndPath(context); | |
| 117 DCHECK(res != 0); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 // static | |
| 122 void PlatformDeviceWin::LoadTransformToDC(HDC dc, const SkMatrix& matrix) { | |
| 123 XFORM xf; | |
| 124 xf.eM11 = matrix[SkMatrix::kMScaleX]; | |
| 125 xf.eM21 = matrix[SkMatrix::kMSkewX]; | |
| 126 xf.eDx = matrix[SkMatrix::kMTransX]; | |
| 127 xf.eM12 = matrix[SkMatrix::kMSkewY]; | |
| 128 xf.eM22 = matrix[SkMatrix::kMScaleY]; | |
| 129 xf.eDy = matrix[SkMatrix::kMTransY]; | |
| 130 SetWorldTransform(dc, &xf); | |
| 131 } | |
| 132 | |
| 133 // static | |
| 134 bool PlatformDeviceWin::SkPathToCubicPaths(CubicPaths* paths, | |
| 135 const SkPath& skpath) { | |
| 136 paths->clear(); | |
| 137 CubicPath* current_path = NULL; | |
| 138 SkPoint current_points[4]; | |
| 139 CubicPoints points_to_add; | |
| 140 SkPath::Iter iter(skpath, false); | |
| 141 for (SkPath::Verb verb = iter.next(current_points); | |
| 142 verb != SkPath::kDone_Verb; | |
| 143 verb = iter.next(current_points)) { | |
| 144 switch (verb) { | |
| 145 case SkPath::kMove_Verb: { // iter.next returns 1 point | |
| 146 // Ignores it since the point is copied in the next operation. See | |
| 147 // SkPath::Iter::next() for reference. | |
| 148 paths->push_back(CubicPath()); | |
| 149 current_path = &paths->back(); | |
| 150 // Skip point addition. | |
| 151 continue; | |
| 152 } | |
| 153 case SkPath::kLine_Verb: { // iter.next returns 2 points | |
| 154 points_to_add.p[0] = current_points[0]; | |
| 155 points_to_add.p[1] = current_points[0]; | |
| 156 points_to_add.p[2] = current_points[1]; | |
| 157 points_to_add.p[3] = current_points[1]; | |
| 158 break; | |
| 159 } | |
| 160 case SkPath::kQuad_Verb: { // iter.next returns 3 points | |
| 161 points_to_add.p[0] = current_points[0]; | |
| 162 points_to_add.p[1] = current_points[1]; | |
| 163 points_to_add.p[2] = current_points[2]; | |
| 164 points_to_add.p[3] = current_points[2]; | |
| 165 break; | |
| 166 } | |
| 167 case SkPath::kCubic_Verb: { // iter.next returns 4 points | |
| 168 points_to_add.p[0] = current_points[0]; | |
| 169 points_to_add.p[1] = current_points[1]; | |
| 170 points_to_add.p[2] = current_points[2]; | |
| 171 points_to_add.p[3] = current_points[3]; | |
| 172 break; | |
| 173 } | |
| 174 case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point) | |
| 175 paths->push_back(CubicPath()); | |
| 176 current_path = &paths->back(); | |
| 177 continue; | |
| 178 } | |
| 179 case SkPath::kDone_Verb: // iter.next returns 0 points | |
| 180 default: { | |
| 181 current_path = NULL; | |
| 182 // Will return false. | |
| 183 break; | |
| 184 } | |
| 185 } | |
| 186 DCHECK(current_path); | |
| 187 if (!current_path) { | |
| 188 paths->clear(); | |
| 189 return false; | |
| 190 } | |
| 191 current_path->push_back(points_to_add); | |
| 192 } | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 // static | |
| 197 void PlatformDeviceWin::LoadClippingRegionToDC(HDC context, | |
| 198 const SkRegion& region, | |
| 199 const SkMatrix& transformation) { | |
| 200 HRGN hrgn; | |
| 201 if (region.isEmpty()) { | |
| 202 // region can be empty, in which case everything will be clipped. | |
| 203 hrgn = CreateRectRgn(0, 0, 0, 0); | |
| 204 } else if (region.isRect()) { | |
| 205 // Do the transformation. | |
| 206 SkRect rect; | |
| 207 rect.set(region.getBounds()); | |
| 208 transformation.mapRect(&rect); | |
| 209 SkIRect irect; | |
| 210 rect.round(&irect); | |
| 211 hrgn = CreateRectRgnIndirect(&SkIRectToRECT(irect)); | |
| 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 path.transform(transformation); | |
| 219 LoadPathToDC(context, path); | |
| 220 hrgn = PathToRegion(context); | |
| 221 } | |
| 222 int result = SelectClipRgn(context, hrgn); | |
| 223 DCHECK_NE(result, ERROR); | |
| 224 result = DeleteObject(hrgn); | |
| 225 DCHECK_NE(result, 0); | |
| 226 } | |
| 227 | |
| 228 } // namespace gfx | |
| 229 | |
| OLD | NEW |