bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
    GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
                              "GrAADistanceFieldPathRenderer::onDrawPath");
    SkASSERT(!args.fDrawContext->isUnifiedMultisampled());
    SkASSERT(args.fShape->style().isSimpleFill());

    // we've already bailed on inverse filled paths, so this is safe
    SkASSERT(!args.fShape->isEmpty());
    SkASSERT(args.fShape->hasUnstyledKey());
    if (!fAtlas) {
        fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig,
                                                     ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
                                                     NUM_PLOTS_X, NUM_PLOTS_Y,
                                                     &GrAADistanceFieldPathRenderer::HandleEviction,
                                                     (void*)this);
        if (!fAtlas) {
            return false;
        }
    }

    SkAutoTUnref<GrDrawBatch> batch(new AADistanceFieldPathBatch(args.fPaint->getColor(),
                                                                 *args.fShape,
                                                                 args.fAntiAlias, *args.fViewMatrix,
                                                                 fAtlas, &fShapeCache, &fShapeList,
                                                                 args.fGammaCorrect));

    GrPipelineBuilder pipelineBuilder(*args.fPaint);
    pipelineBuilder.setUserStencil(args.fUserStencilSettings);

    args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch);

    return true;
}
void GrStencilAndCoverTextContext::drawText(GrContext* context, GrDrawContext* dc,
        const GrClip& clip, const GrPaint& paint,
        const SkPaint& skPaint, const SkMatrix& viewMatrix,
        const SkSurfaceProps& props,
        const char text[], size_t byteLength,
        SkScalar x, SkScalar y, const SkIRect& clipBounds) {
    if (context->abandoned()) {
        return;
    } else if (this->canDraw(skPaint, viewMatrix)) {
        TextRun run(skPaint);
        GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip);
        run.setText(text, byteLength, x, y);
        run.draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, props, 0, 0,
                 clipBounds, fFallbackTextContext, skPaint);
        return;
    } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props,
               *context->caps()->shaderCaps())) {
        fFallbackTextContext->drawText(context, dc, clip, paint, skPaint, viewMatrix, props, text,
                                       byteLength, x, y, clipBounds);
        return;
    }

    // fall back to drawing as a path
    GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, byteLength, x, y,
                                clipBounds);
}
void GrStencilAndCoverTextContext::flush() {
    if (fQueuedGlyphCount > 0) {
        SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(),
                                                                 fViewMatrix,
                                                                 fLocalMatrix));

        // We should only be flushing about once every run.  However, if this impacts performance
        // we could move the creation of the GrPipelineBuilder earlier.
        GrPipelineBuilder pipelineBuilder(fPaint, fRenderTarget, fClip);
        SkASSERT(fRenderTarget->isStencilBufferMultisampled() || !fPaint.isAntiAlias());
        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, fPaint.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kZero_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder.stencil() = kStencilPass;

        SkASSERT(0 == fQueuedGlyphCount);
        SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx);

        fDrawContext->drawPaths(&pipelineBuilder, pp, fGlyphs,
                                fGlyphIndices, GrPathRange::kU16_PathIndexType,
                                get_xy_scalar_array(fGlyphPositions),
                                GrPathRendering::kTranslate_PathTransformType,
                                fQueuedGlyphCount, GrPathRendering::kWinding_FillType);

        fQueuedGlyphCount = 0;
    }

    if (fFallbackGlyphsIdx < kGlyphBufferSize) {
        int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx;

        GrPaint paintFallback(fPaint);

        SkPaint skPaintFallback(fSkPaint);
        if (!fUsingDeviceSpaceGlyphs) {
            fStroke.applyToPaint(&skPaintFallback);
        }
        skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
        skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        SkMatrix inverse;
        if (this->mapToFallbackContext(&inverse)) {
            inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyphCount);
        }

        fFallbackTextContext->drawPosText(fRenderTarget, fClip, paintFallback, skPaintFallback,
                                          fViewMatrix, (char*)&fGlyphIndices[fFallbackGlyphsIdx],
                                          2 * fallbackGlyphCount,
                                          get_xy_scalar_array(&fGlyphPositions[fFallbackGlyphsIdx]),
                                          2, SkPoint::Make(0, 0), fRegionClipBounds);

        fFallbackGlyphsIdx = kGlyphBufferSize;
    }
}
Example #4
0
void GrAtlasTextBlob::flushCached(GrContext* context,
                                  GrDrawContext* dc,
                                  const SkTextBlob* blob,
                                  const SkSurfaceProps& props,
                                  const GrDistanceFieldAdjustTable* distanceAdjustTable,
                                  const SkPaint& skPaint,
                                  const GrPaint& grPaint,
                                  SkDrawFilter* drawFilter,
                                  const GrClip& clip,
                                  const SkMatrix& viewMatrix,
                                  const SkIRect& clipBounds,
                                  SkScalar x, SkScalar y) {
    // We loop through the runs of the blob, flushing each.  If any run is too large, then we flush
    // it as paths
    GrPipelineBuilder pipelineBuilder(grPaint,  dc->isUnifiedMultisampled());
    pipelineBuilder.setRenderTarget(dc->accessRenderTarget());

    GrColor color = grPaint.getColor();

    SkTextBlobRunIterator it(blob);
    for (int run = 0; !it.done(); it.next(), run++) {
        if (fRuns[run].fDrawAsPaths) {
            this->flushRunAsPaths(context, dc, props, it, clip, skPaint,
                                  drawFilter, viewMatrix, clipBounds, x, y);
            continue;
        }
        this->flushRun(dc, &pipelineBuilder, clip, run, viewMatrix, x, y, color, skPaint, props,
                       distanceAdjustTable, context->getBatchFontCache());
    }

    // Now flush big glyphs
    this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds);
}
Example #5
0
BSONObj ResolvedViewDefinition::asExpandedViewAggregation(const AggregationRequest& request) {
    BSONObjBuilder aggregationBuilder;

    // Perform the aggregation on the resolved namespace.
    aggregationBuilder.append("aggregate", collectionNss.coll());

    // The new pipeline consists of two parts: first, 'pipeline' in this ResolvedViewDefinition;
    // then, the pipeline in 'request'.
    BSONArrayBuilder pipelineBuilder(aggregationBuilder.subarrayStart("pipeline"));
    for (auto&& item : pipeline) {
        pipelineBuilder.append(item);
    }

    for (auto&& item : request.getPipeline()) {
        pipelineBuilder.append(item);
    }
    pipelineBuilder.doneFast();

    // The cursor option is always specified regardless of the presence of batchSize.
    if (request.getBatchSize()) {
        BSONObjBuilder batchSizeBuilder(aggregationBuilder.subobjStart("cursor"));
        batchSizeBuilder.append(AggregationRequest::kBatchSizeName, *request.getBatchSize());
        batchSizeBuilder.doneFast();
    } else {
        aggregationBuilder.append("cursor", BSONObj());
    }

    if (request.isExplain())
        aggregationBuilder.append("explain", true);

    return aggregationBuilder.obj();
}
bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
    GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
                              "GrDashLinePathRenderer::onDrawPath");
    bool useHWAA = args.fDrawContext->isUnifiedMultisampled();
    GrDashingEffect::AAMode aaMode;
    if (useHWAA) {
        // We ignore args.fAntiAlias here and force anti aliasing when using MSAA. Otherwise,
        // we can wind up with external edges antialiased and internal edges unantialiased.
        aaMode = GrDashingEffect::AAMode::kCoverageWithMSAA;
    } else if (args.fAntiAlias) {
        aaMode = GrDashingEffect::AAMode::kCoverage;
    } else {
        aaMode = GrDashingEffect::AAMode::kNone;
    }
    SkPoint pts[2];
    SkAssertResult(args.fShape->asLine(pts, nullptr));
    SkAutoTUnref<GrDrawBatch> batch(GrDashingEffect::CreateDashLineBatch(args.fColor,
                                                                         *args.fViewMatrix,
                                                                         pts,
                                                                         aaMode,
                                                                         args.fShape->style()));
    if (!batch) {
        return false;
    }

    GrPipelineBuilder pipelineBuilder(*args.fPaint, useHWAA);
    pipelineBuilder.setUserStencil(args.fUserStencilSettings);

    args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch);
    return true;
}
void GrSWMaskHelper::DrawToTargetWithShapeMask(sk_sp<GrTextureProxy> proxy,
                                               GrRenderTargetContext* renderTargetContext,
                                               GrPaint&& paint,
                                               const GrUserStencilSettings& userStencilSettings,
                                               const GrClip& clip,
                                               const SkMatrix& viewMatrix,
                                               const SkIPoint& textureOriginInDeviceSpace,
                                               const SkIRect& deviceSpaceRectToDraw) {
    SkMatrix invert;
    if (!viewMatrix.invert(&invert)) {
        return;
    }

    GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider();

    SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw);

    // We use device coords to compute the texture coordinates. We take the device coords and apply
    // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
    // matrix to normalized coords.
    SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX),
                                              SkIntToScalar(-textureOriginInDeviceSpace.fY));
    maskMatrix.preConcat(viewMatrix);
    std::unique_ptr<GrLegacyMeshDrawOp> op = GrRectOpFactory::MakeNonAAFill(
            paint.getColor(), SkMatrix::I(), dstRect, nullptr, &invert);
    paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
            resourceProvider, std::move(proxy), nullptr, maskMatrix,
            GrSamplerParams::kNone_FilterMode));
    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
    pipelineBuilder.setUserStencil(&userStencilSettings);
    renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
}
Example #8
0
void GrDrawContext::drawPaint(GrRenderTarget* rt,
                              const GrClip& clip,
                              const GrPaint& origPaint,
                              const SkMatrix& viewMatrix) {
    RETURN_IF_ABANDONED
    // set rect to be big enough to fill the space, but not super-huge, so we
    // don't overflow fixed-point implementations
    SkRect r;
    r.setLTRB(0, 0,
              SkIntToScalar(rt->width()),
              SkIntToScalar(rt->height()));
    SkTCopyOnFirstWrite<GrPaint> paint(origPaint);

    // by definition this fills the entire clip, no need for AA
    if (paint->isAntiAlias()) {
        paint.writable()->setAntiAlias(false);
    }

    bool isPerspective = viewMatrix.hasPerspective();

    // We attempt to map r by the inverse matrix and draw that. mapRect will
    // map the four corners and bound them with a new rect. This will not
    // produce a correct result for some perspective matrices.
    if (!isPerspective) {
        SkMatrix inverse;
        if (!viewMatrix.invert(&inverse)) {
            SkDebugf("Could not invert matrix\n");
            return;
        }
        inverse.mapRect(&r);
        this->drawRect(rt, clip, *paint, viewMatrix, r);
    } else {
        SkMatrix localMatrix;
        if (!viewMatrix.invert(&localMatrix)) {
            SkDebugf("Could not invert matrix\n");
            return;
        }

        AutoCheckFlush acf(fContext);
        if (!this->prepareToDraw(rt)) {
            return;
        }

        GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
        fDrawTarget->drawBWRect(pipelineBuilder,
                                paint->getColor(),
                                SkMatrix::I(),
                                r,
                                NULL,
                                &localMatrix);
    }
}
void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) {
    if (fDraw) {
        SkASSERT(fDraw->count());

        // We should only be flushing about once every run.  However, if this impacts performance
        // we could move the creation of the GrPipelineBuilder earlier.
        GrPipelineBuilder pipelineBuilder(fPaint, fRenderTarget, fClip);
        SkASSERT(fRenderTarget->isStencilBufferMultisampled() || !fPaint.isAntiAlias());
        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, fPaint.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kKeep_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder.stencil() = kStencilPass;

        dc->drawPathsFromRange(&pipelineBuilder, fViewMatrix, fLocalMatrix, fPaint.getColor(),
                               fDraw, GrPathRendering::kWinding_FillType);
        fDraw->unref();
        fDraw = nullptr;
    }

    if (fFallbackIndices.count()) {
        SkASSERT(fFallbackPositions.count() == fFallbackIndices.count());
        GrPaint paintFallback(fPaint);

        SkPaint skPaintFallback(fSkPaint);
        if (!fUsingDeviceSpaceGlyphs) {
            fStroke.applyToPaint(&skPaintFallback);
        }
        skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
        skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        SkMatrix inverse;
        if (this->mapToFallbackContext(&inverse)) {
            inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.count());
        }

        fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallback, skPaintFallback,
                                          fViewMatrix, (char*)fFallbackIndices.begin(),
                                          sizeof(uint16_t) * fFallbackIndices.count(),
                                          get_xy_scalar_array(fFallbackPositions.begin()),
                                          2, SkPoint::Make(0, 0), fRegionClipBounds);
        fFallbackIndices.reset();
        fFallbackPositions.reset();
    }
}
Example #10
0
void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt,
                                              const GrClip& clip,
                                              const GrPaint& paint,
                                              const SkPaint& skPaint,
                                              const SkMatrix& viewMatrix,
                                              const char text[],
                                              size_t byteLength,
                                              SkScalar x, SkScalar y,
                                              const SkIRect& clipBounds) {
    TextRun run(skPaint);
    GrPipelineBuilder pipelineBuilder(paint, rt, clip);
    run.setText(text, byteLength, x, y);
    run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds,
             fFallbackTextContext, skPaint);
}
Example #11
0
void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext,
                                           const GrPaint* paint,
                                           const GrUserStencilSettings* userStencilSettings,
                                           const GrClip& clip,
                                           GrColor color,
                                           const SkMatrix& viewMatrix,
                                           const SkRect& rect,
                                           const SkMatrix& localMatrix) {
    SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect,
                                                                        nullptr, &localMatrix));

    GrPipelineBuilder pipelineBuilder(*paint, drawContext->mustUseHWAA(*paint));
    pipelineBuilder.setUserStencil(userStencilSettings);

    drawContext->drawBatch(pipelineBuilder, clip, batch);
}
Example #12
0
void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarget* rt,
                                                 const GrClip& clip,
                                                 const GrPaint& paint,
                                                 const SkPaint& skPaint,
                                                 const SkMatrix& viewMatrix,
                                                 const char text[],
                                                 size_t byteLength,
                                                 const SkScalar pos[],
                                                 int scalarsPerPosition,
                                                 const SkPoint& offset,
                                                 const SkIRect& clipBounds) {
    TextRun run(skPaint);
    GrPipelineBuilder pipelineBuilder(paint, rt, clip);
    run.setPosText(text, byteLength, pos, scalarsPerPosition, offset);
    run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds,
             fFallbackTextContext, skPaint);
}
Example #13
0
void GrAtlasTextBlob::flushThrowaway(GrContext* context,
                                     GrDrawContext* dc,
                                     const SkSurfaceProps& props,
                                     const GrDistanceFieldAdjustTable* distanceAdjustTable,
                                     const SkPaint& skPaint,
                                     const GrPaint& grPaint,
                                     const GrClip& clip,
                                     const SkIRect& clipBounds) {
    GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip);

    GrColor color = grPaint.getColor();
    for (int run = 0; run < fRunCount; run++) {
        this->flushRun(dc, &pipelineBuilder, run, color, 0, 0, skPaint, props,
                       distanceAdjustTable, context->getBatchFontCache());
    }

    // Now flush big glyphs
    this->flushBigGlyphs(context, dc, clip, skPaint, 0, 0, clipBounds);
}
Example #14
0
void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
                                              GrDrawContext* drawContext,
                                              const GrPaint* paint,
                                              const GrUserStencilSettings* userStencilSettings,
                                              const GrClip& clip,
                                              GrColor color,
                                              const SkMatrix& viewMatrix,
                                              const SkIRect& rect) {
    SkMatrix invert;
    if (!viewMatrix.invert(&invert)) {
        return;
    }

    SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
                                      SK_Scalar1 * rect.fTop,
                                      SK_Scalar1 * rect.fRight,
                                      SK_Scalar1 * rect.fBottom);

    // We use device coords to compute the texture coordinates. We take the device coords and apply
    // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
    // matrix to normalized coords.
    SkMatrix maskMatrix;
    maskMatrix.setIDiv(texture->width(), texture->height());
    maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));

    GrPipelineBuilder pipelineBuilder(*paint, drawContext->isUnifiedMultisampled());
    pipelineBuilder.setRenderTarget(drawContext->accessRenderTarget());
    pipelineBuilder.setUserStencil(userStencilSettings);

    pipelineBuilder.addCoverageFragmentProcessor(
                         GrSimpleTextureEffect::Create(texture,
                                                       maskMatrix,
                                                       GrTextureParams::kNone_FilterMode,
                                                       kDevice_GrCoordSet))->unref();

    SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(),
                                                                        dstRect, nullptr, &invert));
    drawContext->drawBatch(pipelineBuilder, clip, batch);
}
Example #15
0
void GrAtlasTextBlob::flushThrowaway(GrContext* context,
                                     GrDrawContext* dc,
                                     const SkSurfaceProps& props,
                                     const GrDistanceFieldAdjustTable* distanceAdjustTable,
                                     const SkPaint& skPaint,
                                     const GrPaint& grPaint,
                                     const GrClip& clip,
                                     const SkMatrix& viewMatrix,
                                     const SkIRect& clipBounds,
                                     SkScalar x, SkScalar y) {
    GrPipelineBuilder pipelineBuilder(grPaint,  dc->isUnifiedMultisampled());
    pipelineBuilder.setRenderTarget(dc->accessRenderTarget());

    GrColor color = grPaint.getColor();
    for (int run = 0; run < fRunCount; run++) {
        this->flushRun(dc, &pipelineBuilder, clip, run, viewMatrix, x, y, color, skPaint, props,
                       distanceAdjustTable, context->getBatchFontCache());
    }

    // Now flush big glyphs
    this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds);
}
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc,
        const GrClip& clip, const SkPaint& skPaint,
        const SkMatrix& viewMatrix,
        const SkSurfaceProps& props,
        const SkTextBlob* skBlob, SkScalar x, SkScalar y,
        SkDrawFilter* drawFilter,
        const SkIRect& clipBounds) {
    if (context->abandoned()) {
        return;
    }

    if (!this->internalCanDraw(skPaint)) {
        fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob,
                                           x, y, drawFilter, clipBounds);
        return;
    }

    if (drawFilter || skPaint.getPathEffect()) {
        // This draw can't be cached.
        this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y,
                                   drawFilter, clipBounds);
        return;
    }

    GrPaint paint;
    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &paint)) {
        return;
    }

    const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint);
    GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip);

    TextBlob::Iter iter(blob);
    for (TextRun* run = iter.get(); run; run = iter.next()) {
        run->draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, props,  x, y,
                  clipBounds, fFallbackTextContext, skPaint);
        run->releaseGlyphCache();
    }
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrDrawContext* drawContext,
                                                 const GrPaint& grPaint,
                                                 const GrClip& clip,
                                                 const SkMatrix& viewMatrix,
                                                 const SkSurfaceProps& props,
                                                 SkScalar x, SkScalar y,
                                                 const SkIRect& clipBounds,
                                                 GrAtlasTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);
    SkASSERT(drawContext->isStencilBufferMultisampled() || !grPaint.isAntiAlias());

    if (fInstanceData->count()) {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->uniqueID();
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt batching.
        const SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());

        SkAutoTUnref<GrDrawBatch> batch(
            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
                                         fTextInverseRatio * y, grPaint.getColor(),
                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                         bounds));

        GrPipelineBuilder pipelineBuilder(grPaint);
        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, grPaint.isAntiAlias());
        pipelineBuilder.setUserStencil(&kCoverPass);

        drawContext->drawBatch(pipelineBuilder, clip, batch);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
        if (!fStyle.isSimpleFill()) {
            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, drawContext, clip, fallbackSkPaint, viewMatrix,
                                          props, fFallbackTextBlob.get(), x, y, nullptr,
                                          clipBounds);
    }
}
Example #18
0
StatusWith<BSONObj> ParsedDistinct::asAggregationCommand() const {
    BSONObjBuilder aggregationBuilder;

    invariant(_query);
    const QueryRequest& qr = _query->getQueryRequest();
    aggregationBuilder.append("aggregate", qr.nss().coll());

    // Build a pipeline that accomplishes the distinct request. The building code constructs a
    // pipeline that looks like this, assuming the distinct is on the key "a.b.c"
    //
    //      [
    //          { $match: { ... } },
    //          { $unwind: { path: "a", preserveNullAndEmptyArrays: true } },
    //          { $unwind: { path: "a.b", preserveNullAndEmptyArrays: true } },
    //          { $unwind: { path: "a.b.c", preserveNullAndEmptyArrays: true } },
    //          { $match: {"a": {$_internalSchemaType: "object"},
    //                     "a.b": {$_internalSchemaType: "object"}}}
    //          { $group: { _id: null, distinct: { $addToSet: "$<key>" } } }
    //      ]
    //
    // The purpose of the intermediate $unwind stages is to deal with cases where there is an array
    // along the distinct path. For example, if we're distincting on "a.b" and have a document like
    // {a: [{b: 1}, {b: 2}]}, distinct() should produce two values: 1 and 2. If we were to only
    // unwind on "a.b", the document would pass through the $unwind unmodified, and the $group
    // stage would treat the entire array as a key, rather than each element.
    //
    // The reason for the $match with $_internalSchemaType is to deal with cases of nested
    // arrays. The distinct command will not traverse paths inside of nested arrays. For example, a
    // distinct on "a.b" with the following document will produce no results:
    // {a: [[{b: 1}]]
    //
    // Any arrays remaining after the $unwinds must have been nested arrays, so in order to match
    // the behavior of the distinct() command, we filter them out before the $group.
    BSONArrayBuilder pipelineBuilder(aggregationBuilder.subarrayStart("pipeline"));
    if (!qr.getFilter().isEmpty()) {
        BSONObjBuilder matchStageBuilder(pipelineBuilder.subobjStart());
        matchStageBuilder.append("$match", qr.getFilter());
        matchStageBuilder.doneFast();
    }

    FieldPath path(_key);
    addNestedUnwind(&pipelineBuilder, path);
    addMatchRemovingNestedArrays(&pipelineBuilder, path);

    BSONObjBuilder groupStageBuilder(pipelineBuilder.subobjStart());
    {
        BSONObjBuilder groupBuilder(groupStageBuilder.subobjStart("$group"));
        groupBuilder.appendNull("_id");
        {
            BSONObjBuilder distinctBuilder(groupBuilder.subobjStart("distinct"));
            distinctBuilder.append("$addToSet", str::stream() << "$" << _key);
            distinctBuilder.doneFast();
        }
        groupBuilder.doneFast();
    }
    groupStageBuilder.doneFast();
    pipelineBuilder.doneFast();

    aggregationBuilder.append(kCollationField, qr.getCollation());

    if (qr.getMaxTimeMS() > 0) {
        aggregationBuilder.append(QueryRequest::cmdOptionMaxTimeMS, qr.getMaxTimeMS());
    }

    if (!qr.getReadConcern().isEmpty()) {
        aggregationBuilder.append(repl::ReadConcernArgs::kReadConcernFieldName,
                                  qr.getReadConcern());
    }

    if (!qr.getUnwrappedReadPref().isEmpty()) {
        aggregationBuilder.append(QueryRequest::kUnwrappedReadPrefField, qr.getUnwrappedReadPref());
    }

    if (!qr.getComment().empty()) {
        aggregationBuilder.append(kCommentField, qr.getComment());
    }

    // Specify the 'cursor' option so that aggregation uses the cursor interface.
    aggregationBuilder.append("cursor", BSONObj());

    return aggregationBuilder.obj();
}
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
    GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
                              "GrStencilAndCoverPathRenderer::onDrawPath");
    SkASSERT(!args.fPaint->isAntiAlias() || args.fDrawContext->isStencilBufferMultisampled());
    SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());

    const SkMatrix& viewMatrix = *args.fViewMatrix;

    SkPath path;
    args.fShape->asPath(&path);

    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, args.fShape->style()));

    if (path.isInverseFillType()) {
        static constexpr GrUserStencilSettings kInvertedCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                // We know our rect will hit pixels outside the clip and the user bits will be 0
                // outside the clip. So we can't just fill where the user bits are 0. We also need
                // to check that the clip bit is set.
                GrUserStencilTest::kEqualIfInClip,
                0xffff,
                GrUserStencilOp::kKeep,
                GrUserStencilOp::kZero,
                0xffff>()
        );

        // fake inverse with a stencil and cover
        args.fDrawContext->drawContextPriv().stencilPath(*args.fClip,
                                                         &kInvertedCoverPass,
                                                         args.fPaint->isAntiAlias(),
                                                         viewMatrix, p);

        SkMatrix invert = SkMatrix::I();
        SkRect bounds =
            SkRect::MakeLTRB(0, 0,
                             SkIntToScalar(args.fDrawContext->width()),
                             SkIntToScalar(args.fDrawContext->height()));
        SkMatrix vmi;
        // mapRect through persp matrix may not be correct
        if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
            vmi.mapRect(&bounds);
            // theoretically could set bloat = 0, instead leave it because of matrix inversion
            // precision.
            SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
            bounds.outset(bloat, bloat);
        } else {
            if (!viewMatrix.invert(&invert)) {
                return false;
            }
        }
        const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;

        SkAutoTUnref<GrDrawBatch> coverBatch(
                GrRectBatchFactory::CreateNonAAFill(args.fPaint->getColor(), viewM, bounds,
                                                    nullptr, &invert));

        {
            GrPipelineBuilder pipelineBuilder(*args.fPaint,
                                              args.fPaint->isAntiAlias() &&
                                              !args.fDrawContext->hasMixedSamples());
            pipelineBuilder.setUserStencil(&kInvertedCoverPass);

            args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, coverBatch);
        }
    } else {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual,
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        SkAutoTUnref<GrDrawBatch> batch(
                GrDrawPathBatch::Create(viewMatrix, args.fPaint->getColor(), p->getFillType(), p));

        GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fPaint->isAntiAlias());
        pipelineBuilder.setUserStencil(&kCoverPass);
        if (args.fAntiAlias) {
            SkASSERT(args.fDrawContext->isStencilBufferMultisampled());
            pipelineBuilder.enableState(GrPipelineBuilder::kHWAntialias_Flag);
        }

        args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch);
    }

    return true;
}