Пример #1
0
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
                                         GrDrawContext* drawContext,
                                         const GrClip& clip,
                                         const SkPath& origPath,
                                         GrPaint* paint,
                                         const SkMatrix& viewMatrix,
                                         const SkMaskFilter* mf,
                                         const SkPathEffect* pathEffect,
                                         const GrStrokeInfo& origStrokeInfo,
                                         bool pathIsMutable) {
    SkPath* pathPtr = const_cast<SkPath*>(&origPath);

    SkTLazy<SkPath> tmpPath;
    GrStrokeInfo strokeInfo(origStrokeInfo);

    if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(tmpPath.init(), *pathPtr,
                                                                       &strokeInfo, nullptr)) {
        pathPtr = tmpPath.get();
        pathPtr->setIsVolatile(true);
        pathIsMutable = true;
        pathEffect = nullptr;
    }

    draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf, pathEffect,
                               strokeInfo, pathPtr, pathIsMutable);
}
Пример #2
0
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
                                         GrDrawContext* drawContext,
                                         const GrClip& clip,
                                         const SkPath& origSrcPath,
                                         const SkPaint& paint,
                                         const SkMatrix& origViewMatrix,
                                         const SkMatrix* prePathMatrix,
                                         const SkIRect& clipBounds,
                                         bool pathIsMutable) {
    SkASSERT(!pathIsMutable || origSrcPath.isVolatile());

    GrStrokeInfo strokeInfo(paint);
    // comment out the line below to determine if it is the reason that the chrome mac perf bot
    // has begun crashing
    // strokeInfo.setResScale(SkDraw::ComputeResScaleForStroking(origViewMatrix));

    // 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).
    SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
    SkTLazy<SkPath> tmpPath;
    SkTLazy<SkPath> effectPath;
    SkPathEffect* pathEffect = paint.getPathEffect();

    SkMatrix viewMatrix = origViewMatrix;

    if (prePathMatrix) {
        // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix.
        // The pre-path-matrix also should not affect shading.
        if (!paint.getMaskFilter() && !pathEffect && !paint.getShader() &&
            (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) {
            viewMatrix.preConcat(*prePathMatrix);
        } else {
            SkPath* result = pathPtr;

            if (!pathIsMutable) {
                result = tmpPath.init();
                result->setIsVolatile(true);
                pathIsMutable = true;
            }
            // should I push prePathMatrix on our MV stack temporarily, instead
            // of applying it here? See SkDraw.cpp
            pathPtr->transform(*prePathMatrix, result);
            pathPtr = result;
        }
    }
    // at this point we're done with prePathMatrix
    SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
Пример #3
0
GrStrokeInfo TestStrokeInfo(SkRandom* random) {
    SkStrokeRec::InitStyle style =
            SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
    GrStrokeInfo strokeInfo(style);
    randomize_stroke_rec(&strokeInfo, random);
    SkPathEffect::DashInfo dashInfo;
    dashInfo.fCount = random->nextRangeU(1, 50) * 2;
    SkAutoTDeleteArray<SkScalar> intervals(SkNEW_ARRAY(SkScalar, dashInfo.fCount));
    dashInfo.fIntervals = intervals.get();
    SkScalar sum = 0;
    for (int i = 0; i < dashInfo.fCount; i++) {
        dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
                                                         SkDoubleToScalar(10.0));
        sum += dashInfo.fIntervals[i];
    }
    dashInfo.fPhase = random->nextRangeScalar(0, sum);
    strokeInfo.setDashInfo(dashInfo);
    return strokeInfo;
}
Пример #4
0
static void draw_path_with_mask_filter(GrContext* context,
                                       GrDrawContext* drawContext,
                                       const GrClip& clip,
                                       GrPaint* paint,
                                       const SkMatrix& viewMatrix,
                                       const SkMaskFilter* maskFilter,
                                       const SkPathEffect* pathEffect,
                                       const GrStrokeInfo& origStrokeInfo,
                                       SkPath* pathPtr,
                                       bool pathIsMutable) {
    SkASSERT(maskFilter);

    SkIRect clipBounds;
    clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds);
    SkTLazy<SkPath> tmpPath;
    GrStrokeInfo strokeInfo(origStrokeInfo);

    static const SkRect* cullRect = nullptr;  // TODO: what is our bounds?

    SkASSERT(strokeInfo.isDashed() || !pathEffect);

    if (!strokeInfo.isHairlineStyle()) {
        SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
        if (strokeInfo.isDashed()) {
            if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) {
                pathPtr = strokedPath;
                pathPtr->setIsVolatile(true);
                pathIsMutable = true;
            }
            strokeInfo.removeDash();
        }
        if (strokeInfo.applyToPath(strokedPath, *pathPtr)) {
            // Apply the stroke to the path if there is one
            pathPtr = strokedPath;
            pathPtr->setIsVolatile(true);
            pathIsMutable = true;
            strokeInfo.setFillStyle();
        }
    }

    // avoid possibly allocating a new path in transform if we can
    SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
    if (!pathIsMutable) {
        devPathPtr->setIsVolatile(true);
    }

    // transform the path into device space
    pathPtr->transform(viewMatrix, devPathPtr);

    SkRect maskRect;
    if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()),
                                     clipBounds,
                                     viewMatrix,
                                     &maskRect)) {
        SkIRect finalIRect;
        maskRect.roundOut(&finalIRect);
        if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
            // clipped out
            return;
        }

        if (maskFilter->directFilterMaskGPU(context->textureProvider(),
                                            drawContext,
                                            paint,
                                            clip,
                                            viewMatrix,
                                            strokeInfo,
                                            *devPathPtr)) {
            // the mask filter was able to draw itself directly, so there's nothing
            // left to do.
            return;
        }

        SkAutoTUnref<GrTexture> mask(create_mask_GPU(context,
                                                     &maskRect,
                                                     *devPathPtr,
                                                     strokeInfo,
                                                     paint->isAntiAlias(),
                                                     drawContext->numColorSamples()));
        if (mask) {
            GrTexture* filtered;

            if (maskFilter->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) {
                // filterMaskGPU gives us ownership of a ref to the result
                SkAutoTUnref<GrTexture> atu(filtered);
                if (draw_mask(drawContext, clip, viewMatrix, maskRect, paint, filtered)) {
                    // This path is completely drawn
                    return;
                }
            }
        }
    }

    // draw the mask on the CPU - this is a fallthrough path in case the
    // GPU path fails
    SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_Style :
                                                          SkPaint::kFill_Style;
    sw_draw_with_mask_filter(drawContext, context->textureProvider(),
                             clip, viewMatrix, *devPathPtr,
                             maskFilter, clipBounds, paint, style);
}
Пример #5
0
// Returns true if this method handled the glyph, false if needs to be passed to fallback
//
bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
                                             SkScalar sx, SkScalar sy,
                                             GrFontScaler* scaler) {
    if (NULL == fDrawTarget) {
        return true;
    }

    if (NULL == fStrike) {
        fStrike = fContext->getFontCache()->getStrike(scaler, true);
    }

    GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
    if (NULL == glyph || glyph->fBounds.isEmpty()) {
        return true;
    }

    // fallback to color glyph support
    if (kA8_GrMaskFormat != glyph->fMaskFormat) {
        return false;
    }

    SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
    SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
    SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    SkScalar scale = fTextRatio;
    dx *= scale;
    dy *= scale;
    sx += dx;
    sy += dy;
    width *= scale;
    height *= scale;
    SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);

    // check if we clipped out
    SkRect dstRect;
    const SkMatrix& ctm = fViewMatrix;
    (void) ctm.mapRect(&dstRect, glyphRect);
    if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
                              SkScalarTruncToInt(dstRect.top()),
                              SkScalarTruncToInt(dstRect.right()),
                              SkScalarTruncToInt(dstRect.bottom()))) {
        return true;
    }

    if (NULL == glyph->fPlot) {
        // needs to be a separate conditional to avoid over-optimization
        // on Nexus 7 and Nexus 10

        // If the glyph is too large we fall back to paths
        if (!uploadGlyph(glyph, scaler)) {
            if (NULL == glyph->fPath) {
                SkPath* path = SkNEW(SkPath);
                if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                    // flag the glyph as being dead?
                    delete path;
                    return true;
                }
                glyph->fPath = path;
            }

            // flush any accumulated draws before drawing this glyph as a path.
            this->flush();

            SkMatrix ctm;
            ctm.setScale(fTextRatio, fTextRatio);
            ctm.postTranslate(sx - dx, sy - dy);

            SkPath tmpPath(*glyph->fPath);
            tmpPath.transform(ctm);

            GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
            fContext->drawPath(fRenderTarget, fClip, fPaint, fViewMatrix, tmpPath, strokeInfo);

            // remove this glyph from the vertices we need to allocate
            fTotalVertexCount -= kVerticesPerGlyph;
            return true;
        }
    }

    SkASSERT(glyph->fPlot);
    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
    glyph->fPlot->setDrawToken(drawToken);

    GrTexture* texture = glyph->fPlot->texture();
    SkASSERT(texture);

    if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }

    bool useColorVerts = !fUseLCDText;

    if (NULL == fVertices) {
        int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
        fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
        fVertices = alloc_vertices(fDrawTarget,
                                   fAllocVertexCount,
                                   useColorVerts);
    }

    fVertexBounds.joinNonEmptyArg(glyphRect);

    int u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
    int v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
    int u1 = u0 + glyph->fBounds.width() - 2*SK_DistanceFieldInset;
    int v1 = v0 + glyph->fBounds.height() - 2*SK_DistanceFieldInset;

    size_t vertSize = get_vertex_stride(useColorVerts);
    intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex;

    // V0
    SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fLeft, glyphRect.fTop);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize -
                                                              sizeof(SkIPoint16));
    textureCoords->set(u0, v0);
    vertex += vertSize;

    // V1
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fLeft, glyphRect.fBottom);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u0, v1);
    vertex += vertSize;

    // V2
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fRight, glyphRect.fBottom);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u1, v1);
    vertex += vertSize;

    // V3
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fRight, glyphRect.fTop);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u1, v0);

    fCurrVertex += 4;
    
    return true;
}
Пример #6
0
// Returns true if this method handled the glyph, false if needs to be passed to fallback
//
bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
                                             SkScalar sx, SkScalar sy,
                                             GrFontScaler* scaler) {
    if (NULL == fDrawTarget) {
        return true;
    }

    if (NULL == fStrike) {
        fStrike = fContext->getFontCache()->getStrike(scaler, true);
    }

    GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
    if (NULL == glyph || glyph->fBounds.isEmpty()) {
        return true;
    }

    // fallback to color glyph support
    if (kA8_GrMaskFormat != glyph->fMaskFormat) {
        return false;
    }

    SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
    SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
    SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    SkScalar scale = fTextRatio;
    dx *= scale;
    dy *= scale;
    sx += dx;
    sy += dy;
    width *= scale;
    height *= scale;
    SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);

    // check if we clipped out
    SkRect dstRect;
    const SkMatrix& ctm = fContext->getMatrix();
    (void) ctm.mapRect(&dstRect, glyphRect);
    if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
                              SkScalarTruncToInt(dstRect.top()),
                              SkScalarTruncToInt(dstRect.right()),
                              SkScalarTruncToInt(dstRect.bottom()))) {
//            SkCLZ(3);    // so we can set a break-point in the debugger
        return true;
    }

    if (NULL == glyph->fPlot) {
        if (!fStrike->glyphTooLargeForAtlas(glyph)) {
            if (fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }

            // try to clear out an unused plot before we flush
            if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
                fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }

            if (c_DumpFontCache) {
#ifdef SK_DEVELOPER
                fContext->getFontCache()->dump();
#endif
            }

            // before we purge the cache, we must flush any accumulated draws
            this->flush();
            fContext->flush();

            // we should have an unused plot now
            if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
                fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }
        }

        if (NULL == glyph->fPath) {
            SkPath* path = SkNEW(SkPath);
            if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                // flag the glyph as being dead?
                delete path;
                return true;
            }
            glyph->fPath = path;
        }

        // flush any accumulated draws before drawing this glyph as a path.
        this->flush();

        GrContext::AutoMatrix am;
        SkMatrix ctm;
        ctm.setScale(fTextRatio, fTextRatio);
        ctm.postTranslate(sx - dx, sy - dy);
        GrPaint tmpPaint(fPaint);
        am.setPreConcat(fContext, ctm, &tmpPaint);
        GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
        fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);

        // remove this glyph from the vertices we need to allocate
        fTotalVertexCount -= kVerticesPerGlyph;
        return true;
    }

HAS_ATLAS:
    SkASSERT(glyph->fPlot);
    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
    glyph->fPlot->setDrawToken(drawToken);

    GrTexture* texture = glyph->fPlot->texture();
    SkASSERT(texture);

    if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }

    bool useColorVerts = !fUseLCDText;

    if (NULL == fVertices) {
        int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
        fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
        fVertices = alloc_vertices(fDrawTarget,
                                   fAllocVertexCount,
                                   useColorVerts);
    }

    SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
    SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
    SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    fVertexBounds.joinNonEmptyArg(glyphRect);

    size_t vertSize = get_vertex_stride(useColorVerts);

    SkPoint* positions = reinterpret_cast<SkPoint*>(
                               reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
    positions->setRectFan(glyphRect.fLeft, glyphRect.fTop, glyphRect.fRight, glyphRect.fBottom,
                          vertSize);

    // The texture coords are last in both the with and without color vertex layouts.
    SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
                               reinterpret_cast<intptr_t>(positions) + vertSize  - sizeof(SkPoint));
    textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
                              vertSize);
    if (useColorVerts) {
        // color comes after position.
        GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
        for (int i = 0; i < 4; ++i) {
            *colors = fPaint.getColor();
            colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
        }
    }

    fCurrVertex += 4;
    
    return true;
}