bool fColorMatrixEnabled;
GrColor fColor;
+ uint8_t fCoverage;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
fDither = paint.fDither;
fColor = paint.fColor;
+ fCoverage = paint.fCoverage;
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
this->resetBlend();
this->resetOptions();
this->resetColor();
+ this->resetCoverage();
this->resetTextures();
this->resetColorFilter();
this->resetMasks();
fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
}
+ void resetCoverage() {
+ fCoverage = 0xff;
+ }
+
void resetTextures() {
for (int i = 0; i < kMaxTextures; ++i) {
this->setTexture(i, NULL);
}
bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
- SkAlpha* newAlpha) {
- SkASSERT(newAlpha);
+ SkScalar* coverage) {
+ SkASSERT(coverage);
if (SkPaint::kStroke_Style != paint.getStyle()) {
return false;
}
SkScalar strokeWidth = paint.getStrokeWidth();
if (0 == strokeWidth) {
- *newAlpha = paint.getAlpha();
+ *coverage = SK_Scalar1;
return true;
}
if (!paint.isAntiAlias()) {
return false;
}
- if (!xfermodeSupportsCoverageAsAlpha(paint.getXfermode())) {
- return false;
- }
if (matrix.hasPerspective()) {
return false;
}
SkScalar len0 = fast_len(dst[0]);
SkScalar len1 = fast_len(dst[1]);
if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
- SkScalar modulate = SkScalarAve(len0, len1);
-#if 0
- *newAlpha = SkToU8(SkScalarRoundToInt(modulate * paint.getAlpha()));
-#else
- // this is the old technique, which we preserve for now so we don't
- // change previous results (testing)
- // the new way seems fine, its just (a tiny bit) different
- int scale = (int)SkScalarMul(modulate, 256);
- *newAlpha = paint.getAlpha() * scale >> 8;
-#endif
+ *coverage = SkScalarAve(len0, len1);
return true;
}
return false;
SkTLazy<SkPaint> lazyPaint;
{
- SkAlpha newAlpha;
- if (SkDrawTreatAsHairline(origPaint, *matrix, &newAlpha)) {
- lazyPaint.set(origPaint);
- lazyPaint.get()->setAlpha(newAlpha);
- lazyPaint.get()->setStrokeWidth(0);
- paint = lazyPaint.get();
+ SkScalar coverage;
+ if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
+ if (SK_Scalar1 == coverage) {
+ lazyPaint.set(origPaint);
+ lazyPaint.get()->setStrokeWidth(0);
+ paint = lazyPaint.get();
+ } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) {
+ U8CPU newAlpha;
+#if 0
+ newAlpha = SkToU8(SkScalarRoundToInt(coverage *
+ origPaint.getAlpha()));
+#else
+ // this is the old technique, which we preserve for now so
+ // we don't change previous results (testing)
+ // the new way seems fine, its just (a tiny bit) different
+ int scale = (int)SkScalarMul(coverage, 256);
+ newAlpha = origPaint.getAlpha() * scale >> 8;
+#endif
+ lazyPaint.set(origPaint);
+ lazyPaint.get()->setStrokeWidth(0);
+ lazyPaint.get()->setAlpha(newAlpha);
+ paint = lazyPaint.get();
+ }
}
}
};
/**
- * If the current paint is set to stroke, has a compatible xfermode, and the
- * stroke-width when applied to the matrix is <= 1.0, then this returns true,
- * and sets newAlpha (simulating a stroke by drawing a hairline + newAlpha).
- * If any of these conditions are false, then this returns false and modulate
- * is ignored.
+ * If the current paint is set to stroke and the stroke-width when applied to
+ * the matrix is <= 1.0, then this returns true, and sets coverage (simulating
+ * a stroke by drawing a hairline with partial coverage). If any of these
+ * conditions are false, then this returns false and coverage is ignored.
*/
-bool SkDrawTreatAsHairline(const SkPaint&, const SkMatrix&, SkAlpha* newAlpha);
+bool SkDrawTreatAsHairline(const SkPaint&, const SkMatrix&, SkScalar* coverage);
#endif
drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
drawState->setColorMatrix(paint.fColorMatrix);
+ drawState->setCoverage(paint.fCoverage);
if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
GrDrawTarget::AutoStateRestore asr(fGpu);
GrDrawState* drawState = fGpu->drawState();
+ GrRenderTarget* target = drawState->getRenderTarget();
+ drawState->reset();
+ drawState->setRenderTarget(target);
GrMatrix sampleM;
sampleM.setIDiv(texture->width(), texture->height());
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
kernel,
imageIncrement);
- drawState->setViewMatrix(GrMatrix::I());
drawState->setTexture(0, texture);
- drawState->setAlpha(0xFF);
- drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
fGpu->drawSimpleRect(rect, NULL, 1 << 0);
}
grPaint->fDither = skPaint.isDither();
grPaint->fAntiAlias = skPaint.isAntiAlias();
+ grPaint->fCoverage = 0xFF;
SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
}
void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
- const SkPaint& origPaint, const SkMatrix* prePathMatrix,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
CHECK_SHOULD_DRAW(draw);
bool doFill = true;
- SkTLazy<SkPaint> lazyPaint;
- const SkPaint* paint = &origPaint;
-
- // can we cheat, and threat a thin stroke as a hairline (w/ modulated alpha)
+
+ SkScalar coverage = SK_Scalar1;
+ // can we cheat, and threat a thin stroke as a hairline w/ coverage
// if we can, we draw lots faster (raster device does this same test)
- {
- SkAlpha newAlpha;
- if (SkDrawTreatAsHairline(*paint, *draw.fMatrix, &newAlpha)) {
- lazyPaint.set(*paint);
- lazyPaint.get()->setAlpha(newAlpha);
- lazyPaint.get()->setStrokeWidth(0);
- paint = lazyPaint.get();
- doFill = false;
- }
+ if (SkDrawTreatAsHairline(paint, *draw.fMatrix, &coverage)) {
+ doFill = false;
}
- // must reference paint from here down, and not origPaint
- // since we may have change the paint (using lazyPaint for storage)
GrPaint grPaint;
SkAutoCachedTexture act;
- if (!this->skPaint2GrPaintShader(*paint,
+ if (!this->skPaint2GrPaintShader(paint,
&act,
*draw.fMatrix,
&grPaint,
return;
}
+ grPaint.fCoverage = SkScalarRoundToInt(coverage * grPaint.fCoverage);
+
// If we have a prematrix, apply it to the path, optimizing for the case
// where the original path can in fact be modified in place (even though
// its parameter type is const).
// at this point we're done with prePathMatrix
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
- if (doFill && (paint->getPathEffect() ||
- paint->getStyle() != SkPaint::kFill_Style)) {
+ if (doFill && (paint.getPathEffect() ||
+ paint.getStyle() != SkPaint::kFill_Style)) {
// it is safe to use tmpPath here, even if we already used it for the
// prepathmatrix, since getFillPath can take the same object for its
// input and output safely.
- doFill = paint->getFillPath(*pathPtr, &tmpPath);
+ doFill = paint.getFillPath(*pathPtr, &tmpPath);
pathPtr = &tmpPath;
}
- if (paint->getMaskFilter()) {
+ if (paint.getMaskFilter()) {
// avoid possibly allocating a new path in transform if we can
SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
// transform the path into device space
pathPtr->transform(*draw.fMatrix, devPathPtr);
- if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
+ if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
*draw.fMatrix, *draw.fClip, draw.fBounder,
&grPaint)) {
- drawWithMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
+ drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
*draw.fMatrix, *draw.fClip, draw.fBounder,
&grPaint);
}