Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
10 #include "SkStrokerPriv.h"
11 #include "SkGeometry.h"
12 #include "SkPath.h"
14 static void ButtCapper(SkPath* path, const SkPoint& pivot,
15 const SkVector& normal, const SkPoint& stop,
16 SkPath*)
17 {
18 path->lineTo(stop.fX, stop.fY);
19 }
21 static void RoundCapper(SkPath* path, const SkPoint& pivot,
22 const SkVector& normal, const SkPoint& stop,
23 SkPath*)
24 {
25 SkScalar px = pivot.fX;
26 SkScalar py = pivot.fY;
27 SkScalar nx = normal.fX;
28 SkScalar ny = normal.fY;
29 SkScalar sx = SkScalarMul(nx, CUBIC_ARC_FACTOR);
30 SkScalar sy = SkScalarMul(ny, CUBIC_ARC_FACTOR);
32 path->cubicTo(px + nx + CWX(sx, sy), py + ny + CWY(sx, sy),
33 px + CWX(nx, ny) + sx, py + CWY(nx, ny) + sy,
34 px + CWX(nx, ny), py + CWY(nx, ny));
35 path->cubicTo(px + CWX(nx, ny) - sx, py + CWY(nx, ny) - sy,
36 px - nx + CWX(sx, sy), py - ny + CWY(sx, sy),
37 stop.fX, stop.fY);
38 }
40 static void SquareCapper(SkPath* path, const SkPoint& pivot,
41 const SkVector& normal, const SkPoint& stop,
42 SkPath* otherPath)
43 {
44 SkVector parallel;
45 normal.rotateCW(¶llel);
47 if (otherPath)
48 {
49 path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
50 path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
51 }
52 else
53 {
54 path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
55 path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
56 path->lineTo(stop.fX, stop.fY);
57 }
58 }
60 /////////////////////////////////////////////////////////////////////////////
62 static bool is_clockwise(const SkVector& before, const SkVector& after)
63 {
64 return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) > 0;
65 }
67 enum AngleType {
68 kNearly180_AngleType,
69 kSharp_AngleType,
70 kShallow_AngleType,
71 kNearlyLine_AngleType
72 };
74 static AngleType Dot2AngleType(SkScalar dot)
75 {
76 // need more precise fixed normalization
77 // SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero);
79 if (dot >= 0) // shallow or line
80 return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType;
81 else // sharp or 180
82 return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType;
83 }
85 static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after)
86 {
87 #if 1
88 /* In the degenerate case that the stroke radius is larger than our segments
89 just connecting the two inner segments may "show through" as a funny
90 diagonal. To pseudo-fix this, we go through the pivot point. This adds
91 an extra point/edge, but I can't see a cheap way to know when this is
92 not needed :(
93 */
94 inner->lineTo(pivot.fX, pivot.fY);
95 #endif
97 inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
98 }
100 static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
101 const SkPoint& pivot, const SkVector& afterUnitNormal,
102 SkScalar radius, SkScalar invMiterLimit, bool, bool)
103 {
104 SkVector after;
105 afterUnitNormal.scale(radius, &after);
107 if (!is_clockwise(beforeUnitNormal, afterUnitNormal))
108 {
109 SkTSwap<SkPath*>(outer, inner);
110 after.negate();
111 }
113 outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
114 HandleInnerJoin(inner, pivot, after);
115 }
117 static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
118 const SkPoint& pivot, const SkVector& afterUnitNormal,
119 SkScalar radius, SkScalar invMiterLimit, bool, bool)
120 {
121 SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
122 AngleType angleType = Dot2AngleType(dotProd);
124 if (angleType == kNearlyLine_AngleType)
125 return;
127 SkVector before = beforeUnitNormal;
128 SkVector after = afterUnitNormal;
129 SkRotationDirection dir = kCW_SkRotationDirection;
131 if (!is_clockwise(before, after))
132 {
133 SkTSwap<SkPath*>(outer, inner);
134 before.negate();
135 after.negate();
136 dir = kCCW_SkRotationDirection;
137 }
139 SkPoint pts[kSkBuildQuadArcStorage];
140 SkMatrix matrix;
141 matrix.setScale(radius, radius);
142 matrix.postTranslate(pivot.fX, pivot.fY);
143 int count = SkBuildQuadArc(before, after, dir, &matrix, pts);
144 SkASSERT((count & 1) == 1);
146 if (count > 1)
147 {
148 for (int i = 1; i < count; i += 2)
149 outer->quadTo(pts[i].fX, pts[i].fY, pts[i+1].fX, pts[i+1].fY);
151 after.scale(radius);
152 HandleInnerJoin(inner, pivot, after);
153 }
154 }
156 #define kOneOverSqrt2 (0.707106781f)
158 static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
159 const SkPoint& pivot, const SkVector& afterUnitNormal,
160 SkScalar radius, SkScalar invMiterLimit,
161 bool prevIsLine, bool currIsLine)
162 {
163 // negate the dot since we're using normals instead of tangents
164 SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
165 AngleType angleType = Dot2AngleType(dotProd);
166 SkVector before = beforeUnitNormal;
167 SkVector after = afterUnitNormal;
168 SkVector mid;
169 SkScalar sinHalfAngle;
170 bool ccw;
172 if (angleType == kNearlyLine_AngleType)
173 return;
174 if (angleType == kNearly180_AngleType)
175 {
176 currIsLine = false;
177 goto DO_BLUNT;
178 }
180 ccw = !is_clockwise(before, after);
181 if (ccw)
182 {
183 SkTSwap<SkPath*>(outer, inner);
184 before.negate();
185 after.negate();
186 }
188 /* Before we enter the world of square-roots and divides,
189 check if we're trying to join an upright right angle
190 (common case for stroking rectangles). If so, special case
191 that (for speed an accuracy).
192 Note: we only need to check one normal if dot==0
193 */
194 if (0 == dotProd && invMiterLimit <= kOneOverSqrt2)
195 {
196 mid.set(SkScalarMul(before.fX + after.fX, radius),
197 SkScalarMul(before.fY + after.fY, radius));
198 goto DO_MITER;
199 }
201 /* midLength = radius / sinHalfAngle
202 if (midLength > miterLimit * radius) abort
203 if (radius / sinHalf > miterLimit * radius) abort
204 if (1 / sinHalf > miterLimit) abort
205 if (1 / miterLimit > sinHalf) abort
206 My dotProd is opposite sign, since it is built from normals and not tangents
207 hence 1 + dot instead of 1 - dot in the formula
208 */
209 sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd));
210 if (sinHalfAngle < invMiterLimit)
211 {
212 currIsLine = false;
213 goto DO_BLUNT;
214 }
216 // choose the most accurate way to form the initial mid-vector
217 if (angleType == kSharp_AngleType)
218 {
219 mid.set(after.fY - before.fY, before.fX - after.fX);
220 if (ccw)
221 mid.negate();
222 }
223 else
224 mid.set(before.fX + after.fX, before.fY + after.fY);
226 mid.setLength(SkScalarDiv(radius, sinHalfAngle));
227 DO_MITER:
228 if (prevIsLine)
229 outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY);
230 else
231 outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY);
233 DO_BLUNT:
234 after.scale(radius);
235 if (!currIsLine)
236 outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
237 HandleInnerJoin(inner, pivot, after);
238 }
240 /////////////////////////////////////////////////////////////////////////////
242 SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap)
243 {
244 static const SkStrokerPriv::CapProc gCappers[] = {
245 ButtCapper, RoundCapper, SquareCapper
246 };
248 SkASSERT((unsigned)cap < SkPaint::kCapCount);
249 return gCappers[cap];
250 }
252 SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join)
253 {
254 static const SkStrokerPriv::JoinProc gJoiners[] = {
255 MiterJoiner, RoundJoiner, BluntJoiner
256 };
258 SkASSERT((unsigned)join < SkPaint::kJoinCount);
259 return gJoiners[join];
260 }