void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); if (kReverse_MapDirection == direction) { vec.negate(); } *dst = src; dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); }
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); } }
void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); if (kReverse_MapDirection == direction) { vec.negate(); } *dst = src; dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); #ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS dst->join(src); #endif }
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); }
void SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { *dst = src; SkVector offsetVec = SkVector::Make(fDx, fDy); if (kReverse_MapDirection == direction) { offsetVec.negate(); } ctm.mapVectors(&offsetVec, 1); dst->offset(SkScalarCeilToInt(offsetVec.x()), SkScalarCeilToInt(offsetVec.y())); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctm.mapVectors(&sigma, 1); dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { dst->join(src); } }
SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { SkVector offsetVec = SkVector::Make(fDx, fDy); if (kReverse_MapDirection == direction) { offsetVec.negate(); } ctm.mapVectors(&offsetVec, 1); SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()), SkScalarCeilToInt(offsetVec.y())); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctm.mapVectors(&sigma, 1); dst.outset( SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)), SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { dst.join(src); } return dst; }
static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { SkASSERT(!toDevice == !toSrc); // original quad is specified by tri a,b,c SkPoint a = qpts[0]; SkPoint b = qpts[1]; SkPoint c = qpts[2]; if (toDevice) { toDevice->mapPoints(&a, 1); toDevice->mapPoints(&b, 1); toDevice->mapPoints(&c, 1); } // make a new poly where we replace a and c by a 1-pixel wide edges orthog // to edges ab and bc: // // before | after // | b0 // b | // | // | a0 c0 // a c | a1 c1 // // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, // respectively. BezierVertex& a0 = verts[0]; BezierVertex& a1 = verts[1]; BezierVertex& b0 = verts[2]; BezierVertex& c0 = verts[3]; BezierVertex& c1 = verts[4]; SkVector ab = b; ab -= a; SkVector ac = c; ac -= a; SkVector cb = b; cb -= c; // We should have already handled degenerates SkASSERT(ab.length() > 0 && cb.length() > 0); ab.normalize(); SkVector abN; abN.setOrthog(ab, SkVector::kLeft_Side); if (abN.dot(ac) > 0) { abN.negate(); } cb.normalize(); SkVector cbN; cbN.setOrthog(cb, SkVector::kLeft_Side); if (cbN.dot(ac) < 0) { cbN.negate(); } a0.fPos = a; a0.fPos += abN; a1.fPos = a; a1.fPos -= abN; c0.fPos = c; c0.fPos += cbN; c1.fPos = c; c1.fPos -= cbN; intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); if (toSrc) { toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices); } }
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); }