SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) { if (branches->count() == 1) { // Only one branch. It will be the root. return (*branches)[0]; } // We might sort our branches here, but we expect Blink gives us a reasonable x,y order. // Skipping a call to sort (in Y) here resulted in a 17% win for recording with negligible // difference in playback speed. int numBranches = branches->count() / kMaxChildren; int remainder = branches->count() % kMaxChildren; int newBranches = 0; if (remainder > 0) { ++numBranches; // If the remainder isn't enough to fill a node, we'll add fewer nodes to other branches. if (remainder >= kMinChildren) { remainder = 0; } else { remainder = kMinChildren - remainder; } } int numStrips = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(numBranches) / fAspectRatio)); int numTiles = SkScalarCeilToInt(SkIntToScalar(numBranches) / SkIntToScalar(numStrips)); int currentBranch = 0; for (int i = 0; i < numStrips; ++i) { // Might be worth sorting by X here too. for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) { int incrementBy = kMaxChildren; if (remainder != 0) { // if need be, omit some nodes to make up for remainder if (remainder <= kMaxChildren - kMinChildren) { incrementBy -= remainder; remainder = 0; } else { incrementBy = kMinChildren; remainder -= kMaxChildren - kMinChildren; } } Node* n = allocateNodeAtLevel(level); n->fNumChildren = 1; n->fChildren[0] = (*branches)[currentBranch]; Branch b; b.fBounds = (*branches)[currentBranch].fBounds; b.fSubtree = n; ++currentBranch; for (int k = 1; k < incrementBy && currentBranch < branches->count(); ++k) { b.fBounds.join((*branches)[currentBranch].fBounds); n->fChildren[k] = (*branches)[currentBranch]; ++n->fNumChildren; ++currentBranch; } (*branches)[newBranches] = b; ++newBranches; } } branches->setCount(newBranches); return this->bulkLoad(branches, level + 1); }
bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { SkBitmap srcBM; if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &srcBM, offset)) { return false; } GrTexture* srcTexture = srcBM.getTexture(); GrContext* context = srcTexture->getContext(); SkRect dstRect = SkRect::MakeWH(srcBM.width() * fScale.fWidth, srcBM.height() * fScale.fHeight); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = SkScalarCeilToInt(dstRect.width()); desc.fHeight = SkScalarCeilToInt(dstRect.height()); desc.fConfig = kSkia8888_GrPixelConfig; GrAutoScratchTexture ast(context, desc); SkAutoTUnref<GrTexture> dst(ast.detach()); if (!dst) { return false; } GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); GrPaint paint; paint.addColorEffect(GrBicubicEffect::Create(srcTexture, fCoefficients))->unref(); SkRect srcRect; srcBM.getBounds(&srcRect); context->drawRectToRect(paint, dstRect, srcRect); return SkImageFilterUtils::WrapTexture(dst, desc.fWidth, desc.fHeight, result); }
bool PipePictureRenderer::render(SkBitmap** out) { SkASSERT(fCanvas.get() != NULL); SkASSERT(fPicture != NULL); if (NULL == fCanvas.get() || NULL == fPicture) { return false; } PipeController pipeController(fCanvas.get()); SkGPipeWriter writer; SkCanvas* pipeCanvas = writer.startRecording(&pipeController); pipeCanvas->drawPicture(fPicture); writer.endRecording(); fCanvas->flush(); if (out) { *out = SkNEW(SkBitmap); setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), SkScalarCeilToInt(fPicture->cullRect().height())); fCanvas->readPixels(*out, 0, 0); } if (fEnableWrites) { return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr, fUseChecksumBasedFilenames); } else { return true; } }
bool SimplePictureRenderer::render(SkBitmap** out) { SkASSERT(fCanvas.get() != NULL); SkASSERT(fPicture); if (NULL == fCanvas.get() || NULL == fPicture) { return false; } if (fUseMultiPictureDraw) { SkMultiPictureDraw mpd; mpd.add(fCanvas, fPicture); mpd.draw(); } else { fCanvas->drawPicture(fPicture); } fCanvas->flush(); if (out) { *out = SkNEW(SkBitmap); setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), SkScalarCeilToInt(fPicture->cullRect().height())); fCanvas->readPixels(*out, 0, 0); } if (fEnableWrites) { return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr, fUseChecksumBasedFilenames); } else { return true; } }
void GpuGMTask::draw(GrContextFactory* grFactory) { SkImageInfo info = SkImageInfo::Make(SkScalarCeilToInt(fGM->width()), SkScalarCeilToInt(fGM->height()), kN32_SkColorType, kPremul_SkAlphaType); SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, fGpuAPI, info, fSampleCount)); if (!surface) { if (!gAlreadyWarned[fContextType][fGpuAPI]) { SkDebugf("FYI: couldn't create GPU context, type %d API %d. Will skip.\n", fContextType, fGpuAPI); gAlreadyWarned[fContextType][fGpuAPI] = true; } return; } SkCanvas* canvas = surface->getCanvas(); CanvasPreflight(canvas); canvas->concat(fGM->getInitialTransform()); fGM->draw(canvas); canvas->flush(); #if GR_CACHE_STATS && SK_SUPPORT_GPU if (FLAGS_veryVerbose) { grFactory->get(fContextType)->printCacheStats(); } #endif SkBitmap bitmap; bitmap.setInfo(info); canvas->readPixels(&bitmap, 0, 0); this->spawnChild(SkNEW_ARGS(WriteTask, (*this, "GM", bitmap))); }
SkIRect SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection) const { SkVector scale = SkVector::Make(fScale, fScale); ctm.mapVectors(&scale, 1); return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf), SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf)); }
void SKPBench::onPerCanvasPreDraw(SkCanvas* canvas) { if (!fUseMultiPictureDraw) { return; } SkIRect bounds; SkAssertResult(canvas->getClipDeviceBounds(&bounds)); int xTiles = SkScalarCeilToInt(bounds.width() / SkIntToScalar(FLAGS_benchTile)); int yTiles = SkScalarCeilToInt(bounds.height() / SkIntToScalar(FLAGS_benchTile)); fSurfaces.setReserve(xTiles * yTiles); fTileRects.setReserve(xTiles * yTiles); SkImageInfo ii = canvas->imageInfo().makeWH(FLAGS_benchTile, FLAGS_benchTile); for (int y = bounds.fTop; y < bounds.fBottom; y += FLAGS_benchTile) { for (int x = bounds.fLeft; x < bounds.fRight; x += FLAGS_benchTile) { const SkIRect tileRect = SkIRect::MakeXYWH(x, y, FLAGS_benchTile, FLAGS_benchTile); *fTileRects.append() = tileRect; *fSurfaces.push() = canvas->newSurface(ii); // Never want the contents of a tile to include stuff the parent // canvas clips out SkRect clip = SkRect::Make(bounds); clip.offset(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop)); fSurfaces.top()->getCanvas()->clipRect(clip); fSurfaces.top()->getCanvas()->setMatrix(canvas->getTotalMatrix()); fSurfaces.top()->getCanvas()->scale(fScale, fScale); } } }
SkIRect SkMorphologyImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection) const { SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), SkIntToScalar(this->radius().height())); ctm.mapVectors(&radius, 1); return src.makeOutset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y())); }
void SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection) const { *dst = src; SkVector sigma = mapSigma(fSigma, ctm); dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); }
static SkBitmap draw_picture(SkPicture& picture) { SkBitmap bitmap; bitmap.allocN32Pixels(SkScalarCeilToInt(picture.cullRect().width()), SkScalarCeilToInt(picture.cullRect().height())); SkCanvas canvas(bitmap); picture.playback(&canvas); return bitmap; }
void SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection) const { *dst = src; SkVector scale = SkVector::Make(fScale, fScale); ctm.mapVectors(&scale, 1); dst->outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf), SkScalarCeilToInt(scale.fY * SK_ScalarHalf)); }
int tool_main(int argc, char** argv) { SkCommandLineFlags::Parse(argc, argv); for (int i = 0; i < FLAGS_skps.count(); i++) { if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) { continue; } SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(FLAGS_skps[i])); if (!stream) { SkDebugf("Could not read %s.\n", FLAGS_skps[i]); return 1; } sk_sp<SkPicture> src(SkPicture::MakeFromStream(stream)); if (!src) { SkDebugf("Could not read %s as an SkPicture.\n", FLAGS_skps[i]); return 1; } if (FLAGS_defer) { SkPictureRecorder recorder; SkDeferredCanvas deferred(recorder.beginRecording(src->cullRect())); src->playback(&deferred); src = recorder.finishRecordingAsPicture(); } const int w = SkScalarCeilToInt(src->cullRect().width()); const int h = SkScalarCeilToInt(src->cullRect().height()); SkRecord record; SkRecorder canvas(&record, w, h); src->playback(&canvas); if (FLAGS_optimize) { SkRecordOptimize(&record); } if (FLAGS_optimize2) { SkRecordOptimize2(&record); } dump(FLAGS_skps[i], w, h, record); if (FLAGS_write.count() > 0) { SkPictureRecorder r; SkRecordDraw(record, r.beginRecording(SkRect::MakeIWH(w, h)), nullptr, nullptr, 0, nullptr, nullptr); sk_sp<SkPicture> dst(r.finishRecordingAsPicture()); SkFILEWStream ostream(FLAGS_write[0]); dst->serialize(&ostream); } } return 0; }
void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); if (kReverse_MapDirection == direction) { vec.negate(); } *dst = src; dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); }
// Create a mask of 'devPath' and place the result in 'mask'. static GrTexture* create_mask_GPU(GrContext* context, SkRect* maskRect, const SkPath& devPath, const GrStrokeInfo& strokeInfo, bool doAA, int sampleCnt) { // This mask will ultimately be drawn as a non-AA rect (see draw_mask). // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here // so the mask draws in a reproducible manner. *maskRect = SkRect::Make(maskRect->roundOut()); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = SkScalarCeilToInt(maskRect->width()); desc.fHeight = SkScalarCeilToInt(maskRect->height()); desc.fSampleCnt = doAA ? sampleCnt : 0; // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 desc.fConfig = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) { desc.fConfig = kAlpha_8_GrPixelConfig; } GrTexture* mask = context->textureProvider()->createApproxTexture(desc); if (nullptr == mask) { return nullptr; } SkRect clipRect = SkRect::MakeWH(maskRect->width(), maskRect->height()); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(mask->asRenderTarget())); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip GrClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-maskRect->fLeft, -maskRect->fTop); drawContext->drawPath(clip, tempPaint, translate, devPath, strokeInfo); return mask; }
void onOnceBeforeDraw() override { // Build the picture. SkPictureRecorder recorder; SkCanvas* pictureCanvas = recorder.beginRecording(fTileSize, fTileSize, NULL, 0); this->drawTile(pictureCanvas); fPicture.reset(recorder.endRecording()); // Build a reference bitmap. fBitmap.allocN32Pixels(SkScalarCeilToInt(fTileSize), SkScalarCeilToInt(fTileSize)); fBitmap.eraseColor(SK_ColorTRANSPARENT); SkCanvas bitmapCanvas(fBitmap); this->drawTile(&bitmapCanvas); }
bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkIRect bounds = src; if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) { return false; } SkVector sigma = SkVector::Make(fSigma.width(), fSigma.height()); ctm.mapVectors(&sigma, 1); bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); *dst = bounds; return true; }
bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkIRect bounds = src; SkVector scale = SkVector::Make(fScale, fScale); ctm.mapVectors(&scale, 1); bounds.outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf), SkScalarCeilToInt(scale.fY * SK_ScalarHalf)); if (getColorInput()) { return getColorInput()->filterBounds(bounds, ctm, dst); } *dst = bounds; return true; }
bool SkMorphologyImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkIRect bounds = src; SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), SkIntToScalar(this->radius().height())); ctm.mapVectors(&radius, 1); bounds.outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y())); if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { return false; } *dst = bounds; return true; }
TiledPictureRenderer::TiledPictureRenderer(const GrContextOptions& opts) : INHERITED(opts) , fTileWidth(kDefaultTileWidth) #else TiledPictureRenderer::TiledPictureRenderer() : fTileWidth(kDefaultTileWidth) #endif , fTileHeight(kDefaultTileHeight) , fTileWidthPercentage(0.0) , fTileHeightPercentage(0.0) , fTileMinPowerOf2Width(0) , fCurrentTileOffset(-1) , fTilesX(0) , fTilesY(0) { } void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath, const SkString* mismatchPath, const SkString* inputFilename, bool useChecksumBasedFilenames, bool useMultiPictureDraw) { SkASSERT(pict); SkASSERT(0 == fTileRects.count()); if (NULL == pict || fTileRects.count() != 0) { return; } // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not // used by bench_pictures. fPicture.reset(pict)->ref(); this->CopyString(&fWritePath, writePath); this->CopyString(&fMismatchPath, mismatchPath); this->CopyString(&fInputFilename, inputFilename); fUseChecksumBasedFilenames = useChecksumBasedFilenames; fUseMultiPictureDraw = useMultiPictureDraw; this->buildBBoxHierarchy(); if (fTileWidthPercentage > 0) { fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100)); } if (fTileHeightPercentage > 0) { fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100)); } if (fTileMinPowerOf2Width > 0) { this->setupPowerOf2Tiles(); } else { this->setupTiles(); } fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight)); // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the // first call to drawCurrentTile. fCurrentTileOffset = -1; }
bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) const { SkScalar sigma = matrix.mapRadius(fBlurSigma); if (!SkBlurMask::BoxBlur(dst, src, sigma, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality)) { return false; } dst->fFormat = SkMask::k3D_Format; if (margin) { margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma)); } if (src.fImage == NULL) { return true; } // create a larger buffer for the other two channels (should force fBlur to do this for us) { uint8_t* alphaPlane = dst->fImage; size_t planeSize = dst->computeImageSize(); if (0 == planeSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(planeSize * 3); memcpy(dst->fImage, alphaPlane, planeSize); SkMask::FreeImage(alphaPlane); } // run the light direction through the matrix... Light light = fLight; matrix.mapVectors((SkVector*)(void*)light.fDirection, (SkVector*)(void*)fLight.fDirection, 1); // now restore the length of the XY component // cast to SkVector so we can call setLength (this double cast silences alias warnings) SkVector* vec = (SkVector*)(void*)light.fDirection; vec->setLength(light.fDirection[0], light.fDirection[1], SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); SkEmbossMask::Emboss(dst, light); // restore original alpha memcpy(dst->fImage, src.fImage, src.computeImageSize()); return true; }
void check_save_state(skiatest::Reporter* reporter, SkPicture* picture, unsigned int numSaves, unsigned int numSaveLayers, unsigned int numRestores) { SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()), SkScalarCeilToInt(picture->cullRect().height())); picture->playback(&canvas); // Optimizations may have removed these, // so expect to have seen no more than num{Saves,SaveLayers,Restores}. REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount()); REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount()); REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount()); }
void SkPictureUtils::GatherPixelRefsAndRects(SkPicture* pict, SkPictureUtils::SkPixelRefContainer* prCont) { if (pict->cullRect().isEmpty()) { return ; } SkGatherPixelRefsAndRectsDevice device(SkScalarCeilToInt(pict->cullRect().width()), SkScalarCeilToInt(pict->cullRect().height()), prCont); SkNoSaveLayerCanvas canvas(&device); canvas.clipRect(pict->cullRect(), SkRegion::kIntersect_Op, false); canvas.drawPicture(pict); }
void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); if (kReverse_MapDirection == direction) { vec.negate(); } *dst = src; dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); #ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS dst->join(src); #endif }
static inline void compute_profile_offset_and_size(float halfWH, float sigma, float* offset, int* size) { if (3*sigma <= halfWH) { // The circle is bigger than the Gaussian. In this case we know the interior of the // blurred circle is solid. *offset = halfWH - 3 * sigma; // This location maps to 0.5f in the weights texture. // It should always be 255. *size = SkScalarCeilToInt(6*sigma); } else { // The Gaussian is bigger than the circle. *offset = 0.0f; *size = SkScalarCeilToInt(halfWH + 3*sigma); } }
bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeMethod method, int destWidth, int destHeight, SkBitmap::Allocator* allocator) { if (nullptr == source.addr() || source.colorType() != kN32_SkColorType || source.width() < 1 || source.height() < 1) { return false; } if (destWidth < 1 || destHeight < 1) { return false; } SkConvolutionProcs convolveProcs= { 0, nullptr, nullptr, nullptr, nullptr }; PlatformConvolutionProcs(&convolveProcs); SkRect destSubset = SkRect::MakeIWH(destWidth, destHeight); SkResizeFilter filter(method, source.width(), source.height(), destWidth, destHeight, destSubset, convolveProcs); // Get a subset encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while // referring to the old data. const uint8_t* sourceSubset = reinterpret_cast<const uint8_t*>(source.addr()); // Convolve into the result. SkBitmap result; result.setInfo(SkImageInfo::MakeN32(SkScalarCeilToInt(destSubset.width()), SkScalarCeilToInt(destSubset.height()), source.alphaType())); result.allocPixels(allocator, nullptr); if (!result.readyToDraw()) { return false; } if (!BGRAConvolve2D(sourceSubset, static_cast<int>(source.rowBytes()), !source.isOpaque(), filter.xFilter(), filter.yFilter(), static_cast<int>(result.rowBytes()), static_cast<unsigned char*>(result.getPixels()), convolveProcs, true)) { return false; } *resultPtr = result; resultPtr->lockPixels(); SkASSERT(resultPtr->getPixels()); return true; }
// This function creates a profile of a blurred circle. It does this by computing a kernel for // half the Gaussian and a matching summed area table. The summed area table is used to compute // an array of vertical applications of the half kernel to the circle along the x axis. The // table of y evaluations has 2 * k + n entries where k is the size of the half kernel and n is // the size of the profile being computed. Then for each of the n profile entries we walk out k // steps in each horizontal direction multiplying the corresponding y evaluation by the half // kernel entry and sum these values to compute the profile entry. static uint8_t* create_circle_profile(float sigma, float circleR, int profileTextureWidth) { const int numSteps = profileTextureWidth; uint8_t* weights = new uint8_t[numSteps]; // The full kernel is 6 sigmas wide. int halfKernelSize = SkScalarCeilToInt(6.0f * sigma); // round up to next multiple of 2 and then divide by 2 halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1; // Number of x steps at which to apply kernel in y to cover all the profile samples in x. int numYSteps = numSteps + 2 * halfKernelSize; SkAutoTArray<float> bulkAlloc(halfKernelSize + halfKernelSize + numYSteps); float* halfKernel = bulkAlloc.get(); float* summedKernel = bulkAlloc.get() + halfKernelSize; float* yEvals = bulkAlloc.get() + 2 * halfKernelSize; make_half_kernel_and_summed_table(halfKernel, summedKernel, halfKernelSize, sigma); float firstX = -halfKernelSize + 0.5f; apply_kernel_in_y(yEvals, numYSteps, firstX, circleR, halfKernelSize, summedKernel); for (int i = 0; i < numSteps - 1; ++i) { float evalX = i + 0.5f; weights[i] = eval_at(evalX, circleR, halfKernel, halfKernelSize, yEvals + i); } // Ensure the tail of the Gaussian goes to zero. weights[numSteps - 1] = 0; return weights; }
uint32_t GrPathUtils::quadraticPointCount(const SkPoint points[], SkScalar tol) { if (tol < gMinCurveTol) { tol = gMinCurveTol; } SkASSERT(tol > 0); SkScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]); if (!SkScalarIsFinite(d)) { return MAX_POINTS_PER_CURVE; } else if (d <= tol) { return 1; } else { // Each time we subdivide, d should be cut in 4. So we need to // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x) // points. // 2^(log4(x)) = sqrt(x); SkScalar divSqrt = SkScalarSqrt(d / tol); if (((SkScalar)SK_MaxS32) <= divSqrt) { return MAX_POINTS_PER_CURVE; } else { int temp = SkScalarCeilToInt(divSqrt); int pow2 = GrNextPow2(temp); // Because of NaNs & INFs we can wind up with a degenerate temp // such that pow2 comes out negative. Also, our point generator // will always output at least one pt. if (pow2 < 1) { pow2 = 1; } return SkTMin(pow2, MAX_POINTS_PER_CURVE); } } }
static void get_adjusted_radii(SkScalar passRadius, int *loRadius, int *hiRadius) { *loRadius = *hiRadius = SkScalarCeilToInt(passRadius); if (SkIntToScalar(*hiRadius) - passRadius > 0.5f) { *loRadius = *hiRadius - 1; } }
static float* create_2d_kernel(float sigma, int* filterSize) { // We will actually take 2*halfFilterSize+1 samples (i.e., our filter kernel // sizes are always odd) int halfFilterSize = SkScalarCeilToInt(6*sigma)/2; int wh = *filterSize = 2*halfFilterSize + 1; float* temp = new float[wh*wh]; float filterTot = 0.0f; for (int yOff = 0; yOff < wh; ++yOff) { for (int xOff = 0; xOff < wh; ++xOff) { temp[yOff*wh+xOff] = gaussian2d_value(xOff-halfFilterSize, yOff-halfFilterSize, sigma); filterTot += temp[yOff*wh+xOff]; } } // normalize the kernel for (int yOff = 0; yOff < wh; ++yOff) { for (int xOff = 0; xOff < wh; ++xOff) { temp[yOff*wh+xOff] /= filterTot; } } return temp; }
uint32_t GrPathUtils::cubicPointCount(const SkPoint points[], SkScalar tol) { if (tol < gMinCurveTol) { tol = gMinCurveTol; } SkASSERT(tol > 0); SkScalar d = SkTMax( points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]), points[2].distanceToLineSegmentBetweenSqd(points[0], points[3])); d = SkScalarSqrt(d); if (!SkScalarIsFinite(d)) { return MAX_POINTS_PER_CURVE; } else if (d <= tol) { return 1; } else { SkScalar divSqrt = SkScalarSqrt(d / tol); if (((SkScalar)SK_MaxS32) <= divSqrt) { return MAX_POINTS_PER_CURVE; } else { int temp = SkScalarCeilToInt(SkScalarSqrt(d / tol)); int pow2 = GrNextPow2(temp); // Because of NaNs & INFs we can wind up with a degenerate temp // such that pow2 comes out negative. Also, our point generator // will always output at least one pt. if (pow2 < 1) { pow2 = 1; } return SkTMin(pow2, MAX_POINTS_PER_CURVE); } } }