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; } }
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); }
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)); }
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(); } }
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); }
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); }
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); }
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); }
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); }
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); } }
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; }