bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target, bool antiAlias) { GrDrawState* drawState = target->drawState(); SkScalar hairlineCoverage; if (IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), &hairlineCoverage)) { uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * target->getDrawState().getCoverage()); target->drawState()->setCoverage(newCoverage); } SkIRect devClipBounds; target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); int lineCnt; int quadCnt; int conicCnt; PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; PREALLOC_PTARRAY(128) conics; IntArray qSubdivs; FloatArray cWeights; quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClipBounds, &lines, &quads, &conics, &qSubdivs, &cWeights); lineCnt = lines.count() / 2; conicCnt = conics.count() / 3; // do lines first if (lineCnt) { GrDrawTarget::AutoReleaseGeometry arg; SkRect devBounds; if (!this->createLineGeom(path, target, lines, lineCnt, &arg, &devBounds)) { return false; } GrDrawTarget::AutoStateRestore asr; // createLineGeom transforms the geometry to device space when the matrix does not have // perspective. if (target->getDrawState().getViewMatrix().hasPerspective()) { asr.set(target, GrDrawTarget::kPreserve_ASRInit); } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { return false; } GrDrawState* drawState = target->drawState(); // Check devBounds SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), kVertsPerLineSeg * lineCnt)); { GrDrawState::AutoRestoreEffects are(drawState); target->setIndexSourceToBuffer(fLinesIndexBuffer); int lines = 0; while (lines < lineCnt) { int n = SkTMin(lineCnt - lines, kNumLineSegsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerLineSeg*lines, // startV 0, // startI kVertsPerLineSeg*n, // vCount kIdxsPerLineSeg*n, // iCount &devBounds); lines += n; } } } // then quadratics/conics if (quadCnt || conicCnt) { GrDrawTarget::AutoReleaseGeometry arg; SkRect devBounds; if (!this->createBezierGeom(path, target, quads, quadCnt, conics, conicCnt, qSubdivs, cWeights, &arg, &devBounds)) { return false; } GrDrawTarget::AutoStateRestore asr; // createGeom transforms the geometry to device space when the matrix does not have // perspective. if (target->getDrawState().getViewMatrix().hasPerspective()) { asr.set(target, GrDrawTarget::kPreserve_ASRInit); } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { return false; } GrDrawState* drawState = target->drawState(); static const int kEdgeAttrIndex = 1; // Check devBounds SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(), kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt)); if (quadCnt > 0) { GrEffect* hairQuadEffect = GrQuadEffect::Create(kHairlineAA_GrEffectEdgeType, *target->caps()); SkASSERT(hairQuadEffect); GrDrawState::AutoRestoreEffects are(drawState); target->setIndexSourceToBuffer(fQuadsIndexBuffer); drawState->setGeometryProcessor(hairQuadEffect, kEdgeAttrIndex)->unref(); int quads = 0; while (quads < quadCnt) { int n = SkTMin(quadCnt - quads, kNumQuadsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerQuad*quads, // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n, // iCount &devBounds); quads += n; } } if (conicCnt > 0) { GrDrawState::AutoRestoreEffects are(drawState); GrEffect* hairConicEffect = GrConicEffect::Create(kHairlineAA_GrEffectEdgeType, *target->caps()); SkASSERT(hairConicEffect); drawState->setGeometryProcessor(hairConicEffect, 1, 2)->unref(); int conics = 0; while (conics < conicCnt) { int n = SkTMin(conicCnt - conics, kNumQuadsInIdxBuffer); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerQuad*(quadCnt + conics), // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n, // iCount &devBounds); conics += n; } } } target->resetIndexSource(); return true; }
void GrDistanceFieldTextContext::flush() { if (NULL == fDrawTarget) { return; } if (fCurrVertex > 0) { GrDrawState drawState; drawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget()); bool useColorVerts = !fUseLCDText; set_vertex_attributes(&drawState, useColorVerts); // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); // get our current color SkColor filteredColor; SkColorFilter* colorFilter = fSkPaint.getColorFilter(); if (colorFilter) { filteredColor = colorFilter->filterColor(fSkPaint.getColor()); } else { filteredColor = fSkPaint.getColor(); } this->setupCoverageEffect(filteredColor); // Effects could be stored with one of the cache objects (atlas?) drawState.setGeometryProcessor(fCachedGeometryProcessor.get()); // Set draw state if (fUseLCDText) { GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || fPaint.numColorStages()) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState.hasColorVertexAttribute()); // We don't use the GrPaint's color in this case because it's been premultiplied by // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by // the mask texture color. The end result is that we get // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor int a = SkColorGetA(fSkPaint.getColor()); // paintAlpha drawState.setColor(SkColorSetARGB(a, a, a, a)); // paintColor drawState.setBlendConstant(colorNoPreMul); drawState.setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); } else { if (0xFF == GrColorUnpackA(fPaint.getColor())) { drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true); } // set back to normal in case we took LCD path previously. drawState.setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); // We're using per-vertex color. SkASSERT(drawState.hasColorVertexAttribute()); } int nGlyphs = fCurrVertex / kVerticesPerGlyph; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(&drawState, kTriangles_GrPrimitiveType, nGlyphs, kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds); fDrawTarget->resetVertexSource(); fVertices = NULL; fTotalVertexCount -= fCurrVertex; fCurrVertex = 0; SkSafeSetNull(fCurrTexture); fVertexBounds.setLargestInverted(); } }