| Index: skia/sgl/SkStrokerPriv.cpp
|
| ===================================================================
|
| --- skia/sgl/SkStrokerPriv.cpp (revision 16859)
|
| +++ skia/sgl/SkStrokerPriv.cpp (working copy)
|
| @@ -1,275 +0,0 @@
|
| -/* libs/graphics/sgl/SkStrokerPriv.cpp
|
| -**
|
| -** Copyright 2006, The Android Open Source Project
|
| -**
|
| -** Licensed under the Apache License, Version 2.0 (the "License");
|
| -** you may not use this file except in compliance with the License.
|
| -** You may obtain a copy of the License at
|
| -**
|
| -** http://www.apache.org/licenses/LICENSE-2.0
|
| -**
|
| -** Unless required by applicable law or agreed to in writing, software
|
| -** distributed under the License is distributed on an "AS IS" BASIS,
|
| -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -** See the License for the specific language governing permissions and
|
| -** limitations under the License.
|
| -*/
|
| -
|
| -#include "SkStrokerPriv.h"
|
| -#include "SkGeometry.h"
|
| -#include "SkPath.h"
|
| -
|
| -static void ButtCapper(SkPath* path, const SkPoint& pivot,
|
| - const SkVector& normal, const SkPoint& stop,
|
| - SkPath*)
|
| -{
|
| - path->lineTo(stop.fX, stop.fY);
|
| -}
|
| -
|
| -static void RoundCapper(SkPath* path, const SkPoint& pivot,
|
| - const SkVector& normal, const SkPoint& stop,
|
| - SkPath*)
|
| -{
|
| - SkScalar px = pivot.fX;
|
| - SkScalar py = pivot.fY;
|
| - SkScalar nx = normal.fX;
|
| - SkScalar ny = normal.fY;
|
| - SkScalar sx = SkScalarMul(nx, CUBIC_ARC_FACTOR);
|
| - SkScalar sy = SkScalarMul(ny, CUBIC_ARC_FACTOR);
|
| -
|
| - path->cubicTo(px + nx + CWX(sx, sy), py + ny + CWY(sx, sy),
|
| - px + CWX(nx, ny) + sx, py + CWY(nx, ny) + sy,
|
| - px + CWX(nx, ny), py + CWY(nx, ny));
|
| - path->cubicTo(px + CWX(nx, ny) - sx, py + CWY(nx, ny) - sy,
|
| - px - nx + CWX(sx, sy), py - ny + CWY(sx, sy),
|
| - stop.fX, stop.fY);
|
| -}
|
| -
|
| -static void SquareCapper(SkPath* path, const SkPoint& pivot,
|
| - const SkVector& normal, const SkPoint& stop,
|
| - SkPath* otherPath)
|
| -{
|
| - SkVector parallel;
|
| - normal.rotateCW(¶llel);
|
| -
|
| - if (otherPath)
|
| - {
|
| - path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
|
| - path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
|
| - }
|
| - else
|
| - {
|
| - path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
|
| - path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
|
| - path->lineTo(stop.fX, stop.fY);
|
| - }
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////////////////
|
| -
|
| -static bool is_clockwise(const SkVector& before, const SkVector& after)
|
| -{
|
| - return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) > 0;
|
| -}
|
| -
|
| -enum AngleType {
|
| - kNearly180_AngleType,
|
| - kSharp_AngleType,
|
| - kShallow_AngleType,
|
| - kNearlyLine_AngleType
|
| -};
|
| -
|
| -static AngleType Dot2AngleType(SkScalar dot)
|
| -{
|
| -// need more precise fixed normalization
|
| -// SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero);
|
| -
|
| - if (dot >= 0) // shallow or line
|
| - return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType;
|
| - else // sharp or 180
|
| - return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType;
|
| -}
|
| -
|
| -static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector& after)
|
| -{
|
| -#if 1
|
| - /* In the degenerate case that the stroke radius is larger than our segments
|
| - just connecting the two inner segments may "show through" as a funny
|
| - diagonal. To pseudo-fix this, we go through the pivot point. This adds
|
| - an extra point/edge, but I can't see a cheap way to know when this is
|
| - not needed :(
|
| - */
|
| - inner->lineTo(pivot.fX, pivot.fY);
|
| -#endif
|
| -
|
| - inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
|
| -}
|
| -
|
| -static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
|
| - const SkPoint& pivot, const SkVector& afterUnitNormal,
|
| - SkScalar radius, SkScalar invMiterLimit, bool, bool)
|
| -{
|
| - SkVector after;
|
| - afterUnitNormal.scale(radius, &after);
|
| -
|
| - if (!is_clockwise(beforeUnitNormal, afterUnitNormal))
|
| - {
|
| - SkTSwap<SkPath*>(outer, inner);
|
| - after.negate();
|
| - }
|
| -
|
| - outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
|
| - HandleInnerJoin(inner, pivot, after);
|
| -}
|
| -
|
| -static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
|
| - const SkPoint& pivot, const SkVector& afterUnitNormal,
|
| - SkScalar radius, SkScalar invMiterLimit, bool, bool)
|
| -{
|
| - SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
|
| - AngleType angleType = Dot2AngleType(dotProd);
|
| -
|
| - if (angleType == kNearlyLine_AngleType)
|
| - return;
|
| -
|
| - SkVector before = beforeUnitNormal;
|
| - SkVector after = afterUnitNormal;
|
| - SkRotationDirection dir = kCW_SkRotationDirection;
|
| -
|
| - if (!is_clockwise(before, after))
|
| - {
|
| - SkTSwap<SkPath*>(outer, inner);
|
| - before.negate();
|
| - after.negate();
|
| - dir = kCCW_SkRotationDirection;
|
| - }
|
| -
|
| - SkPoint pts[kSkBuildQuadArcStorage];
|
| - SkMatrix matrix;
|
| - matrix.setScale(radius, radius);
|
| - matrix.postTranslate(pivot.fX, pivot.fY);
|
| - int count = SkBuildQuadArc(before, after, dir, &matrix, pts);
|
| - SkASSERT((count & 1) == 1);
|
| -
|
| - if (count > 1)
|
| - {
|
| - for (int i = 1; i < count; i += 2)
|
| - outer->quadTo(pts[i].fX, pts[i].fY, pts[i+1].fX, pts[i+1].fY);
|
| -
|
| - after.scale(radius);
|
| - HandleInnerJoin(inner, pivot, after);
|
| - }
|
| -}
|
| -
|
| -#ifdef SK_SCALAR_IS_FLOAT
|
| - #define kOneOverSqrt2 (0.707106781f)
|
| -#else
|
| - #define kOneOverSqrt2 (46341)
|
| -#endif
|
| -
|
| -static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
|
| - const SkPoint& pivot, const SkVector& afterUnitNormal,
|
| - SkScalar radius, SkScalar invMiterLimit,
|
| - bool prevIsLine, bool currIsLine)
|
| -{
|
| - // negate the dot since we're using normals instead of tangents
|
| - SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
|
| - AngleType angleType = Dot2AngleType(dotProd);
|
| - SkVector before = beforeUnitNormal;
|
| - SkVector after = afterUnitNormal;
|
| - SkVector mid;
|
| - SkScalar sinHalfAngle;
|
| - bool ccw;
|
| -
|
| - if (angleType == kNearlyLine_AngleType)
|
| - return;
|
| - if (angleType == kNearly180_AngleType)
|
| - {
|
| - currIsLine = false;
|
| - goto DO_BLUNT;
|
| - }
|
| -
|
| - ccw = !is_clockwise(before, after);
|
| - if (ccw)
|
| - {
|
| - SkTSwap<SkPath*>(outer, inner);
|
| - before.negate();
|
| - after.negate();
|
| - }
|
| -
|
| - /* Before we enter the world of square-roots and divides,
|
| - check if we're trying to join an upright right angle
|
| - (common case for stroking rectangles). If so, special case
|
| - that (for speed an accuracy).
|
| - Note: we only need to check one normal if dot==0
|
| - */
|
| - if (0 == dotProd && invMiterLimit <= kOneOverSqrt2)
|
| - {
|
| - mid.set(SkScalarMul(before.fX + after.fX, radius),
|
| - SkScalarMul(before.fY + after.fY, radius));
|
| - goto DO_MITER;
|
| - }
|
| -
|
| - /* midLength = radius / sinHalfAngle
|
| - if (midLength > miterLimit * radius) abort
|
| - if (radius / sinHalf > miterLimit * radius) abort
|
| - if (1 / sinHalf > miterLimit) abort
|
| - if (1 / miterLimit > sinHalf) abort
|
| - My dotProd is opposite sign, since it is built from normals and not tangents
|
| - hence 1 + dot instead of 1 - dot in the formula
|
| - */
|
| - sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd));
|
| - if (sinHalfAngle < invMiterLimit)
|
| - {
|
| - currIsLine = false;
|
| - goto DO_BLUNT;
|
| - }
|
| -
|
| - // choose the most accurate way to form the initial mid-vector
|
| - if (angleType == kSharp_AngleType)
|
| - {
|
| - mid.set(after.fY - before.fY, before.fX - after.fX);
|
| - if (ccw)
|
| - mid.negate();
|
| - }
|
| - else
|
| - mid.set(before.fX + after.fX, before.fY + after.fY);
|
| -
|
| - mid.setLength(SkScalarDiv(radius, sinHalfAngle));
|
| -DO_MITER:
|
| - if (prevIsLine)
|
| - outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY);
|
| - else
|
| - outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY);
|
| -
|
| -DO_BLUNT:
|
| - after.scale(radius);
|
| - if (!currIsLine)
|
| - outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
|
| - HandleInnerJoin(inner, pivot, after);
|
| -}
|
| -
|
| -/////////////////////////////////////////////////////////////////////////////
|
| -
|
| -SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap)
|
| -{
|
| - static const SkStrokerPriv::CapProc gCappers[] = {
|
| - ButtCapper, RoundCapper, SquareCapper
|
| - };
|
| -
|
| - SkASSERT((unsigned)cap < SkPaint::kCapCount);
|
| - return gCappers[cap];
|
| -}
|
| -
|
| -SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join)
|
| -{
|
| - static const SkStrokerPriv::JoinProc gJoiners[] = {
|
| - MiterJoiner, RoundJoiner, BluntJoiner
|
| - };
|
| -
|
| - SkASSERT((unsigned)join < SkPaint::kJoinCount);
|
| - return gJoiners[join];
|
| -}
|
| -
|
| -
|
| -
|
|
|