OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 #import "ui/gfx/path_mac.h" | |
6 | |
7 #import <Cocoa/Cocoa.h> | |
8 | |
9 #include "third_party/skia/include/core/SkRegion.h" | |
10 #include "ui/gfx/path.h" | |
11 | |
12 namespace { | |
13 | |
14 // Convert an SkPoint to an NSPoint. | |
15 NSPoint GetNSPointFromSkPoint(const SkPoint& point) { | |
16 return NSMakePoint(point.x(), point.y()); | |
17 } | |
18 | |
19 // Convert a quadratic bezier curve to a cubic bezier curve. | |
tapted
2016/02/10 02:28:02
nit: mention that this is based on the implementat
karandeepb
2016/02/11 00:30:09
Done.
| |
20 void ConvertQuadToCubicBezier(NSPoint quad[3], NSPoint cubic[4]) { | |
21 // The resultant cubic will have the same endpoints. | |
22 cubic[0] = quad[0]; | |
23 cubic[3] = quad[2]; | |
24 | |
25 const double scale = 2.0 / 3.0; | |
26 | |
27 cubic[1].x = quad[0].x + scale * (quad[1].x - quad[0].x); | |
28 cubic[1].y = quad[0].y + scale * (quad[1].y - quad[0].y); | |
29 | |
30 cubic[2].x = quad[2].x + scale * (quad[1].x - quad[2].x); | |
31 cubic[2].y = quad[2].y + scale * (quad[1].y - quad[2].y); | |
32 } | |
33 | |
34 } // namespace | |
35 | |
36 namespace gfx { | |
37 | |
38 NSBezierPath* CreateNSBezierPathFromSkRegion(const SkRegion& region) { | |
39 NSBezierPath* result = [NSBezierPath bezierPath]; | |
40 for (SkRegion::Iterator i(region); !i.done(); i.next()) { | |
41 const SkIRect& rect = i.rect(); | |
42 [result appendBezierPathWithRect:NSMakeRect(rect.x(), rect.y(), | |
43 rect.width(), rect.height())]; | |
44 } | |
45 return result; | |
46 } | |
47 | |
48 NSBezierPath* CreateNSBezierPathFromSkPath(const SkPath& path) { | |
49 NSBezierPath* result = [NSBezierPath bezierPath]; | |
50 SkPath::RawIter iter(path); | |
51 SkPoint points[4]; | |
52 SkPath::Verb verb; | |
53 while ((verb = iter.next(points)) != SkPath::kDone_Verb) { | |
54 NSPoint ns_points[4]; | |
55 for (size_t i = 0; i < 4; i++) | |
56 ns_points[i] = GetNSPointFromSkPoint(points[i]); | |
tapted
2016/02/10 02:28:01
I think this can read from uninitialized memory in
karandeepb
2016/02/11 00:30:09
Done.
| |
57 | |
58 switch (verb) { | |
59 case SkPath::kMove_Verb: { | |
60 [result moveToPoint:ns_points[0]]; | |
61 break; | |
62 } | |
63 case SkPath::kLine_Verb: { | |
64 DCHECK(NSEqualPoints([result currentPoint], ns_points[0])); | |
65 [result lineToPoint:ns_points[1]]; | |
66 break; | |
67 } | |
68 case SkPath::kQuad_Verb: { | |
69 DCHECK(NSEqualPoints([result currentPoint], ns_points[0])); | |
70 NSPoint quad[] = {ns_points[0], ns_points[1], ns_points[2]}; | |
71 // NSBezierPath does not support quadratic bezier curves. Hence convert | |
72 // to cubic bezier curve. | |
73 ConvertQuadToCubicBezier(quad, ns_points); | |
74 [result curveToPoint:ns_points[3] | |
75 controlPoint1:ns_points[1] | |
76 controlPoint2:ns_points[2]]; | |
77 break; | |
78 } | |
79 case SkPath::kCubic_Verb: { | |
80 DCHECK(NSEqualPoints([result currentPoint], ns_points[0])); | |
81 [result curveToPoint:ns_points[3] | |
82 controlPoint1:ns_points[1] | |
83 controlPoint2:ns_points[2]]; | |
84 break; | |
85 } | |
86 case SkPath::kConic_Verb: { | |
87 DCHECK(NSEqualPoints([result currentPoint], ns_points[0])); | |
88 // Approximate with quads. Use two for now, increase if more precision | |
89 // is needed. | |
90 const size_t kSubdivisionLevels = 1; | |
91 const size_t kQuadCount = 1 << kSubdivisionLevels; | |
92 // The quads will share endpoints, so we need one more point than twice | |
93 // the number of quads. | |
94 const size_t kPointCount = 1 + 2 * kQuadCount; | |
95 SkPoint quads[kPointCount]; | |
96 SkPath::ConvertConicToQuads(points[0], points[1], points[2], | |
97 iter.conicWeight(), quads, | |
98 kSubdivisionLevels); | |
99 NSPoint ns_quads[kPointCount]; | |
100 for (size_t i = 0; i < kPointCount; i++) | |
101 ns_quads[i] = GetNSPointFromSkPoint(quads[i]); | |
102 | |
103 for (size_t i = 0; i < kQuadCount; i++) { | |
104 NSPoint quad[] = {ns_quads[2 * i], ns_quads[2 * i + 1], | |
105 ns_quads[2 * i + 2]}; | |
106 ConvertQuadToCubicBezier(quad, ns_points); | |
107 [result curveToPoint:ns_points[3] | |
108 controlPoint1:ns_points[1] | |
109 controlPoint2:ns_points[2]]; | |
110 } | |
111 break; | |
112 } | |
113 case SkPath::kClose_Verb: { | |
114 [result closePath]; | |
115 break; | |
116 } | |
117 default: { NOTREACHED(); } | |
118 } | |
119 } | |
120 | |
121 // Set up the fill type. | |
122 switch (path.getFillType()) { | |
123 case SkPath::kWinding_FillType: | |
124 [result setWindingRule:NSNonZeroWindingRule]; | |
125 break; | |
126 case SkPath::kEvenOdd_FillType: | |
127 [result setWindingRule:NSEvenOddWindingRule]; | |
128 break; | |
129 case SkPath::kInverseWinding_FillType: | |
130 case SkPath::kInverseEvenOdd_FillType: | |
131 NOTREACHED() << "NSBezierCurve does not support inverse fill types."; | |
132 break; | |
133 default: | |
134 NOTREACHED(); | |
135 } | |
136 | |
137 return result; | |
138 } | |
139 | |
140 } // namespace gfx | |
OLD | NEW |