diff options
-rw-r--r-- | src/core/SkPoint.cpp | 10 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 66 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 1 | ||||
-rw-r--r-- | src/gpu/batches/GrAAFillRectBatch.cpp | 13 |
4 files changed, 81 insertions, 9 deletions
diff --git a/src/core/SkPoint.cpp b/src/core/SkPoint.cpp index 490e4a2d2d..162c62acad 100644 --- a/src/core/SkPoint.cpp +++ b/src/core/SkPoint.cpp @@ -88,8 +88,8 @@ static inline float getLengthSquared(float dx, float dy) { // This logic is encapsulated in a helper method to make it explicit that we // always perform this check in the same manner, to avoid inconsistencies // (see http://code.google.com/p/skia/issues/detail?id=560 ). -static inline bool isLengthNearlyZero(float dx, float dy, - float *lengthSquared) { +static inline bool is_length_nearly_zero(float dx, float dy, + float *lengthSquared) { *lengthSquared = getLengthSquared(dx, dy); return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); } @@ -98,7 +98,7 @@ SkScalar SkPoint::Normalize(SkPoint* pt) { float x = pt->fX; float y = pt->fY; float mag2; - if (isLengthNearlyZero(x, y, &mag2)) { + if (is_length_nearly_zero(x, y, &mag2)) { pt->set(0, 0); return 0; } @@ -146,7 +146,7 @@ SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { */ bool SkPoint::setLength(float x, float y, float length) { float mag2; - if (isLengthNearlyZero(x, y, &mag2)) { + if (is_length_nearly_zero(x, y, &mag2)) { this->set(0, 0); return false; } @@ -183,7 +183,7 @@ bool SkPoint::setLengthFast(float length) { bool SkPoint::setLengthFast(float x, float y, float length) { float mag2; - if (isLengthNearlyZero(x, y, &mag2)) { + if (is_length_nearly_zero(x, y, &mag2)) { this->set(0, 0); return false; } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 10bcecf2ba..20afada017 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -692,12 +692,78 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint #include "SkMaskFilter.h" /////////////////////////////////////////////////////////////////////////////// +void SkGpuDevice::drawStrokedLine(const SkPoint points[2], + const SkDraw& draw, + const SkPaint& origPaint) { + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext); + CHECK_SHOULD_DRAW(draw); + + // Adding support for round capping would require a GrDrawContext::fillRRectWithLocalMatrix + // entry point + SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap()); + SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle()); + SkASSERT(!origPaint.getPathEffect()); + SkASSERT(!origPaint.getMaskFilter()); + + const SkScalar halfWidth = 0.5f * origPaint.getStrokeWidth(); + SkASSERT(halfWidth > 0); + + SkVector v = points[1] - points[0]; + + SkScalar length = SkPoint::Normalize(&v); + if (!length) { + v.fX = 1.0f; + v.fY = 0.0f; + } + + SkPaint newPaint(origPaint); + newPaint.setStyle(SkPaint::kFill_Style); + + SkScalar xtraLength = 0.0f; + if (SkPaint::kButt_Cap != origPaint.getStrokeCap()) { + xtraLength = halfWidth; + } + + SkPoint mid = points[0] + points[1]; + mid.scale(0.5f); + + SkRect rect = SkRect::MakeLTRB(mid.fX-halfWidth, mid.fY - 0.5f*length - xtraLength, + mid.fX+halfWidth, mid.fY + 0.5f*length + xtraLength); + SkMatrix m; + m.setSinCos(v.fX, -v.fY, mid.fX, mid.fY); + + SkMatrix local = m; + + m.postConcat(*draw.fMatrix); + + GrPaint grPaint; + if (!SkPaintToGrPaint(this->context(), newPaint, m, + this->surfaceProps().isGammaCorrect(), &grPaint)) { + return; + } + + fDrawContext->fillRectWithLocalMatrix(fClip, grPaint, m, rect, local); +} void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { ASSERT_SINGLE_OWNER if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) { + SkPoint points[2]; + if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 && + !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() && + draw.fMatrix->preservesRightAngles() && origSrcPath.isLine(points)) { + // Path-based stroking looks better for thin rects + SkScalar strokeWidth = draw.fMatrix->getMaxScale() * paint.getStrokeWidth(); + if (strokeWidth > 0.9f) { + // Round capping support is currently disabled b.c. it would require + // a RRect batch that takes a localMatrix. + this->drawStrokedLine(points, draw, paint); + return; + } + } bool isClosed; SkRect rect; if (origSrcPath.isRect(&rect, &isClosed) && isClosed) { diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 474a030ef5..4c6a0f37ab 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -252,6 +252,7 @@ private: const SkRect& dst, const SkPaint&); bool drawDashLine(const SkPoint pts[2], const SkPaint& paint); + void drawStrokedLine(const SkPoint pts[2], const SkDraw&, const SkPaint&); static sk_sp<GrDrawContext> CreateDrawContext(GrContext*, SkBudgeted, diff --git a/src/gpu/batches/GrAAFillRectBatch.cpp b/src/gpu/batches/GrAAFillRectBatch.cpp index 859328af3b..2c90b8bcf2 100644 --- a/src/gpu/batches/GrAAFillRectBatch.cpp +++ b/src/gpu/batches/GrAAFillRectBatch.cpp @@ -84,10 +84,12 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); - SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); - inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); + SkScalar inset; if (viewMatrix.rectStaysRect()) { + inset = SkMinScalar(devRect.width(), SK_Scalar1); + inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); + set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf); set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset); } else { @@ -97,11 +99,14 @@ static void generate_aa_fill_rect_geometry(intptr_t verts, { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] } }; - vec[0].normalize(); + SkScalar len1 = SkPoint::Normalize(&vec[0]); vec[0].scale(SK_ScalarHalf); - vec[1].normalize(); + SkScalar len2 = SkPoint::Normalize(&vec[1]); vec[1].scale(SK_ScalarHalf); + inset = SkMinScalar(len1 * rect.width(), SK_Scalar1); + inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height()); + // create the rotated rect fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); |