| 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 |