Index: src/gpu/batches/GrAAStrokeRectBatch.cpp |
diff --git a/src/gpu/batches/GrAAStrokeRectBatch.cpp b/src/gpu/batches/GrAAStrokeRectBatch.cpp |
index 0a9601f3102f87f27bdd10eb4057e47f2e0cf055..ea8bc2e46e1aa1ce0149d95094efb4cc4a08cf05 100644 |
--- a/src/gpu/batches/GrAAStrokeRectBatch.cpp |
+++ b/src/gpu/batches/GrAAStrokeRectBatch.cpp |
@@ -53,6 +53,7 @@ public: |
SkRect fDevOutsideAssist; |
SkRect fDevInside; |
GrColor fColor; |
+ bool fDegenerate; |
}; |
static AAStrokeRectBatch* Create(const SkMatrix& viewMatrix, bool miterStroke) { |
@@ -77,17 +78,19 @@ public: |
} |
void append(GrColor color, const SkRect& devOutside, const SkRect& devOutsideAssist, |
- const SkRect& devInside) { |
+ const SkRect& devInside, bool degenerate) { |
Geometry& geometry = fGeoData.push_back(); |
geometry.fColor = color; |
geometry.fDevOutside = devOutside; |
geometry.fDevOutsideAssist = devOutsideAssist; |
geometry.fDevInside = devInside; |
+ geometry.fDegenerate = degenerate; |
} |
void appendAndUpdateBounds(GrColor color, const SkRect& devOutside, |
- const SkRect& devOutsideAssist, const SkRect& devInside) { |
- this->append(color, devOutside, devOutsideAssist, devInside); |
+ const SkRect& devOutsideAssist, const SkRect& devInside, |
+ bool degenerate) { |
+ this->append(color, devOutside, devOutsideAssist, devInside, degenerate); |
SkRect bounds; |
this->updateBounds(&bounds, fGeoData.back()); |
@@ -145,6 +148,7 @@ private: |
const SkRect& devOutsideAssist, |
const SkRect& devInside, |
bool miterStroke, |
+ bool degenerate, |
bool tweakAlphaForCoverage) const; |
struct BatchTracker { |
@@ -226,6 +230,7 @@ void AAStrokeRectBatch::onPrepareDraws(Target* target) { |
args.fDevOutsideAssist, |
args.fDevInside, |
fMiterStroke, |
+ args.fDegenerate, |
canTweakAlphaForCoverage); |
} |
helper.recordDraw(target); |
@@ -356,6 +361,15 @@ bool AAStrokeRectBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { |
return true; |
} |
+static void setup_scale(int* scale, SkScalar inset) { |
+ if (inset < SK_ScalarHalf) { |
+ *scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); |
+ SkASSERT(*scale >= 0 && *scale <= 255); |
+ } else { |
+ *scale = 0xff; |
+ } |
+} |
+ |
void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
size_t offset, |
size_t vertexStride, |
@@ -366,6 +380,7 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
const SkRect& devOutsideAssist, |
const SkRect& devInside, |
bool miterStroke, |
+ bool degenerate, |
bool tweakAlphaForCoverage) const { |
intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset; |
@@ -382,18 +397,34 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX |
// TODO: this only really works if the X & Y margins are the same all around |
// the rect (or if they are all >= 1.0). |
- SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); |
- inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); |
- inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); |
- if (miterStroke) { |
- inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); |
+ SkScalar inset; |
+ if (!degenerate) { |
+ inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); |
+ inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); |
+ inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); |
+ if (miterStroke) { |
+ inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); |
+ } else { |
+ inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - |
+ devInside.fBottom); |
+ } |
+ SkASSERT(inset >= 0); |
} else { |
- inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - |
- devInside.fBottom); |
+ // TODO use real devRect here |
+ inset = SkMinScalar(devOutside.width(), SK_Scalar1); |
+ inset = SK_ScalarHalf * SkMinScalar(inset, SkTMax(devOutside.height(), |
+ devOutsideAssist.height())); |
} |
- SkASSERT(inset >= 0); |
#else |
- SkScalar inset = SK_ScalarHalf; |
+ SkScalar inset; |
+ if (!degenerate) { |
+ inset = SK_ScalarHalf; |
+ } else { |
+ // TODO use real devRect here |
+ inset = SkMinScalar(devOutside.width(), SK_Scalar1); |
+ inset = SK_ScalarHalf * SkMinScalar(inset, SkTMax(devOutside.height(), |
+ devOutsideAssist.height())); |
+ } |
#endif |
if (miterStroke) { |
@@ -401,9 +432,19 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
// inner two |
set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); |
- set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
- // innermost |
- set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); |
+ if (!degenerate) { |
+ set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
+ // innermost |
+ set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); |
+ } else { |
+ // When the interior rect has become degenerate we smoosh to a single point |
+ SkASSERT(devInside.fLeft == devInside.fRight && |
+ devInside.fTop == devInside.fBottom); |
+ fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, |
+ devInside.fRight, devInside.fBottom, vertexStride); |
+ fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, |
+ devInside.fRight, devInside.fBottom, vertexStride); |
+ } |
} else { |
SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride); |
SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + |
@@ -416,10 +457,20 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
// outer one of the inner two |
set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); |
set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset); |
- // inner one of the inner two |
- set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
- // innermost |
- set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); |
+ if (!degenerate) { |
+ // inner one of the inner two |
+ set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
+ // innermost |
+ set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf); |
+ } else { |
+ // When the interior rect has become degenerate we smoosh to a single point |
+ SkASSERT(devInside.fLeft == devInside.fRight && |
+ devInside.fTop == devInside.fBottom); |
+ fan2Pos->setRectFan(devInside.fLeft, devInside.fTop, |
+ devInside.fRight, devInside.fBottom, vertexStride); |
+ fan3Pos->setRectFan(devInside.fLeft, devInside.fTop, |
+ devInside.fRight, devInside.fBottom, vertexStride); |
+ } |
} |
// Make verts point to vertex color and then set all the color and coverage vertex attrs |
@@ -436,12 +487,7 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
// scale is the coverage for the the inner two rects. |
int scale; |
- if (inset < SK_ScalarHalf) { |
- scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); |
- SkASSERT(scale >= 0 && scale <= 255); |
- } else { |
- scale = 0xff; |
- } |
+ setup_scale(&scale, inset); |
float innerCoverage = GrNormalizeByteToFloat(scale); |
GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); |
@@ -452,19 +498,24 @@ void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices, |
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; |
} else { |
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
- *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = |
- innerCoverage; |
+ *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage; |
} |
} |
- // The innermost rect has 0 coverage |
+ // The innermost rect has 0 coverage, unless we are degenerate, in which case we must apply the |
+ // scaled coverage |
verts += (outerVertexNum + innerVertexNum) * vertexStride; |
+ if (!degenerate) { |
+ innerCoverage = 0; |
+ scaledColor = 0; |
+ } |
+ |
for (int i = 0; i < innerVertexNum; ++i) { |
if (tweakAlphaForCoverage) { |
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; |
+ *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; |
} else { |
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
- *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0; |
+ *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage; |
} |
} |
} |
@@ -476,9 +527,10 @@ GrDrawBatch* Create(GrColor color, |
const SkRect& devOutside, |
const SkRect& devOutsideAssist, |
const SkRect& devInside, |
- bool miterStroke) { |
+ bool miterStroke, |
+ bool degenerate) { |
AAStrokeRectBatch* batch = AAStrokeRectBatch::Create(viewMatrix, miterStroke); |
- batch->append(color, devOutside, devOutsideAssist, devInside); |
+ batch->append(color, devOutside, devOutsideAssist, devInside, degenerate); |
batch->init(); |
return batch; |
} |
@@ -489,7 +541,8 @@ bool Append(GrBatch* origBatch, |
const SkRect& devOutside, |
const SkRect& devOutsideAssist, |
const SkRect& devInside, |
- bool miterStroke) { |
+ bool miterStroke, |
+ bool degenerate) { |
AAStrokeRectBatch* batch = origBatch->cast<AAStrokeRectBatch>(); |
// we can't batch across vm changes |
@@ -497,7 +550,7 @@ bool Append(GrBatch* origBatch, |
return false; |
} |
- batch->appendAndUpdateBounds(color, devOutside, devOutsideAssist, devInside); |
+ batch->appendAndUpdateBounds(color, devOutside, devOutsideAssist, devInside, degenerate); |
return true; |
} |
@@ -524,7 +577,7 @@ DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) { |
GrColor color = GrRandomColor(random); |
return GrAAStrokeRectBatch::Create(color, GrTest::TestMatrix(random), outside, outsideAssist, |
- inside, miterStroke); |
+ inside, miterStroke, inside.isFinite() && inside.isEmpty()); |
} |
#endif |