gfx/skia/trunk/src/core/SkStrokerPriv.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial