bool onQuery(Event* evt) override { if (Sample::TitleQ(*evt)) { Sample::TitleR(evt, "SGPong"); return true; } SkUnichar uni; if (Sample::CharQ(*evt, &uni)) { switch (uni) { case '[': fTimeScale = SkTPin(fTimeScale - 0.1f, kTimeScaleMin, kTimeScaleMax); return true; case ']': fTimeScale = SkTPin(fTimeScale + 0.1f, kTimeScaleMin, kTimeScaleMax); return true; case 'I': fShowInval = !fShowInval; fScene->setShowInval(fShowInval); return true; default: break; } } return this->INHERITED::onQuery(evt); }
SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& v) { // best effort to turn this into a color const auto r = v.size() > 0 ? v[0] : 0, g = v.size() > 1 ? v[1] : 0, b = v.size() > 2 ? v[2] : 0, a = v.size() > 3 ? v[3] : 1; return SkColorSetARGB(SkScalarRoundToInt(SkTPin(a, 0.0f, 1.0f) * 255), SkScalarRoundToInt(SkTPin(r, 0.0f, 1.0f) * 255), SkScalarRoundToInt(SkTPin(g, 0.0f, 1.0f) * 255), SkScalarRoundToInt(SkTPin(b, 0.0f, 1.0f) * 255)); }
// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementHrefAttribute void SkSVGLinearGradient::collectColorStops(const SkSVGRenderContext& ctx, SkSTArray<2, SkScalar, true>* pos, SkSTArray<2, SkColor, true>* colors) const { // Used to resolve percentage offsets. const SkSVGLengthContext ltx(SkSize::Make(1, 1)); for (const auto& child : fChildren) { if (child->tag() != SkSVGTag::kStop) { continue; } const auto& stop = static_cast<const SkSVGStop&>(*child); colors->push_back(SkColorSetA(stop.stopColor(), SkScalarRoundToInt(stop.stopOpacity() * 255))); pos->push_back(SkTPin(ltx.resolve(stop.offset(), SkSVGLengthContext::LengthType::kOther), 0.f, 1.f)); } SkASSERT(colors->count() == pos->count()); if (pos->empty() && !fHref.value().isEmpty()) { const auto* ref = ctx.findNodeById(fHref); if (ref && ref->tag() == SkSVGTag::kLinearGradient) { static_cast<const SkSVGLinearGradient*>(ref)->collectColorStops(ctx, pos, colors); } } }
SkScalar fuzzBallSpeed(SkScalar spd) { // The speed limits are absolute values. const SkScalar sign = spd >= 0 ? 1.0f : -1.0f; const SkScalar fuzzed = fabs(spd) + fRand.nextRangeScalar(-kBallSpeedFuzz, kBallSpeedFuzz); return sign * SkTPin(fuzzed, kBallSpeedMin, kBallSpeedMax); }
GrColor4f GrColorSpaceXform::clampedXform(const GrColor4f& srcColor) { GrColor4f result = this->unclampedXform(srcColor); for (int i = 0; i < 4; ++i) { // We always operate on unpremul colors, so clamp to [0,1]. result.fRGBA[i] = SkTPin(result.fRGBA[i], 0.0f, 1.0f); } return result; }
sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) { if (!SkScalarsAreFinite(startT, stopT)) { return nullptr; } if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) { return nullptr; } startT = SkTPin(startT, 0.f, 1.f); stopT = SkTPin(stopT, 0.f, 1.f); if (startT >= stopT && mode == Mode::kInverted) { return nullptr; } return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode)); }
bool onQuery(SkEvent* evt) override { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "SVGPong"); return true; } SkUnichar uni; if (SampleCode::CharQ(*evt, &uni)) { switch (uni) { case '[': fTimeScale = SkTPin(fTimeScale - 0.1f, kTimeScaleMin, kTimeScaleMax); return true; case ']': fTimeScale = SkTPin(fTimeScale + 0.1f, kTimeScaleMin, kTimeScaleMax); return true; default: break; } } return this->INHERITED::onQuery(evt); }
void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawContext* drawContext, const GrClip& clip, GrDrawBatch* batch) { // Setup clip GrAppliedClip appliedClip; if (!clip.apply(fContext, pipelineBuilder, drawContext, &batch->bounds(), &appliedClip)) { return; } // TODO: this is the only remaining usage of the AutoRestoreFragmentProcessorState - remove it GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps; if (appliedClip.getClipCoverageFragmentProcessor()) { arfps.set(&pipelineBuilder); arfps.addCoverageFragmentProcessor(sk_ref_sp(appliedClip.getClipCoverageFragmentProcessor())); } GrPipeline::CreateArgs args; args.fPipelineBuilder = &pipelineBuilder; args.fDrawContext = drawContext; args.fCaps = this->caps(); args.fScissor = &appliedClip.scissorState(); args.fHasStencilClip = appliedClip.hasStencilClip(); if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) { if (!fResourceProvider->attachStencilAttachment(drawContext->accessRenderTarget())) { SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); return; } } batch->getPipelineOptimizations(&args.fOpts); GrScissorState finalScissor; if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) { GrGLIRect viewport; viewport.fLeft = 0; viewport.fBottom = 0; viewport.fWidth = drawContext->width(); viewport.fHeight = drawContext->height(); SkIRect ibounds; ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft, viewport.fWidth); ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom, viewport.fHeight); ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft, viewport.fWidth); ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom, viewport.fHeight); if (appliedClip.scissorState().enabled()) { const SkIRect& scissorRect = appliedClip.scissorState().rect(); if (!ibounds.intersect(scissorRect)) { return; } } finalScissor.set(ibounds); args.fScissor = &finalScissor; } args.fOpts.fColorPOI.completeCalculations( sk_sp_address_as_pointer_address(pipelineBuilder.fColorFragmentProcessors.begin()), pipelineBuilder.numColorFragmentProcessors()); args.fOpts.fCoveragePOI.completeCalculations( sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()), pipelineBuilder.numCoverageFragmentProcessors()); if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(), clip, args.fOpts, &args.fDstTexture, batch->bounds())) { return; } if (!batch->installPipeline(args)) { return; } #ifdef ENABLE_MDB SkASSERT(fRenderTarget); batch->pipeline()->addDependenciesTo(fRenderTarget); #endif this->recordBatch(batch); }
sk_sp<SkSpecialImage> SkMagnifierImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), input->width(), input->height()); SkIRect bounds; if (!this->applyCropRect(ctx, inputBounds, &bounds)) { return nullptr; } SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; SkScalar invXZoom = fSrcRect.width() / bounds.width(); SkScalar invYZoom = fSrcRect.height() / bounds.height(); #if SK_SUPPORT_GPU if (source->isTextureBacked()) { GrContext* context = source->getContext(); sk_sp<GrTexture> inputTexture(input->asTextureRef(context)); SkASSERT(inputTexture); offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-inputOffset); SkScalar yOffset = inputTexture->origin() == kTopLeft_GrSurfaceOrigin ? fSrcRect.y() : inputTexture->height() - fSrcRect.height() * inputTexture->height() / bounds.height() - fSrcRect.y(); int boundsY = inputTexture->origin() == kTopLeft_GrSurfaceOrigin ? bounds.y() : inputTexture->height() - bounds.height(); SkRect effectBounds = SkRect::MakeXYWH( SkIntToScalar(bounds.x()) / inputTexture->width(), SkIntToScalar(boundsY) / inputTexture->height(), SkIntToScalar(inputTexture->width()) / bounds.width(), SkIntToScalar(inputTexture->height()) / bounds.height()); // SRGBTODO: Handle sRGB here sk_sp<GrFragmentProcessor> fp(GrMagnifierEffect::Create( inputTexture.get(), effectBounds, fSrcRect.x() / inputTexture->width(), yOffset / inputTexture->height(), invXZoom, invYZoom, bounds.width() * invInset, bounds.height() * invInset)); if (!fp) { return nullptr; } return DrawWithFP(context, std::move(fp), bounds); } #endif SkBitmap inputBM; if (!input->getROPixels(&inputBM)) { return nullptr; } if ((inputBM.colorType() != kN32_SkColorType) || (fSrcRect.width() >= inputBM.width()) || (fSrcRect.height() >= inputBM.height())) { return nullptr; } SkAutoLockPixels alp(inputBM); SkASSERT(inputBM.getPixels()); if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) { return nullptr; } const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()); SkBitmap dst; if (!dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels dstLock(dst); SkColor* dptr = dst.getAddr32(0, 0); int dstWidth = dst.width(), dstHeight = dst.height(); for (int y = 0; y < dstHeight; ++y) { for (int x = 0; x < dstWidth; ++x) { SkScalar x_dist = SkMin32(x, dstWidth - x - 1) * invInset; SkScalar y_dist = SkMin32(y, dstHeight - y - 1) * invInset; SkScalar weight = 0; static const SkScalar kScalar2 = SkScalar(2); // To create a smooth curve at the corners, we need to work on // a square twice the size of the inset. if (x_dist < kScalar2 && y_dist < kScalar2) { x_dist = kScalar2 - x_dist; y_dist = kScalar2 - y_dist; SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + SkScalarSquare(y_dist)); dist = SkMaxScalar(kScalar2 - dist, 0); weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); } else { SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), SkScalarSquare(y_dist)); weight = SkMinScalar(sqDist, SK_Scalar1); } SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * invXZoom)) + (SK_Scalar1 - weight) * x; SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * invYZoom)) + (SK_Scalar1 - weight) * y; int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1); int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1); *dptr = *inputBM.getAddr32(x_val, y_val); dptr++; } } offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst); }
bool SkMagnifierImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context&, SkBitmap* dst, SkIPoint* offset) const { if ((src.colorType() != kN32_SkColorType) || (fSrcRect.width() >= src.width()) || (fSrcRect.height() >= src.height())) { return false; } SkAutoLockPixels alp(src); SkASSERT(src.getPixels()); if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height())); if (!device) { return false; } *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; SkScalar inv_x_zoom = fSrcRect.width() / src.width(); SkScalar inv_y_zoom = fSrcRect.height() / src.height(); SkColor* sptr = src.getAddr32(0, 0); SkColor* dptr = dst->getAddr32(0, 0); int width = src.width(), height = src.height(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset; SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset; SkScalar weight = 0; static const SkScalar kScalar2 = SkScalar(2); // To create a smooth curve at the corners, we need to work on // a square twice the size of the inset. if (x_dist < kScalar2 && y_dist < kScalar2) { x_dist = kScalar2 - x_dist; y_dist = kScalar2 - y_dist; SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + SkScalarSquare(y_dist)); dist = SkMaxScalar(kScalar2 - dist, 0); weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); } else { SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), SkScalarSquare(y_dist)); weight = SkMinScalar(sqDist, SK_Scalar1); } SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) + (SK_Scalar1 - weight) * x; SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) + (SK_Scalar1 - weight) * y; int x_val = SkTPin(SkScalarFloorToInt(x_interp), 0, width - 1); int y_val = SkTPin(SkScalarFloorToInt(y_interp), 0, height - 1); *dptr = sptr[y_val * width + x_val]; dptr++; } } return true; }
int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) { #ifdef SK_DEBUG // create a string mathematica understands // GDB set print repe 15 # if repeated digits is a bother // set print elements 400 # if line doesn't fit char str[1024]; sk_bzero(str, sizeof(str)); SK_SNPRINTF(str, sizeof(str), "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]", A, B, C, D); SkPathOpsDebug::MathematicaIze(str, sizeof(str)); #if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA SkDebugf("%s\n", str); #endif #endif if (approximately_zero(A) && approximately_zero_when_compared_to(A, B) && approximately_zero_when_compared_to(A, C) && approximately_zero_when_compared_to(A, D)) { // we're just a quadratic return SkDQuad::RootsReal(B, C, D, s); } if (approximately_zero_when_compared_to(D, A) && approximately_zero_when_compared_to(D, B) && approximately_zero_when_compared_to(D, C)) { // 0 is one root int num = SkDQuad::RootsReal(A, B, C, s); for (int i = 0; i < num; ++i) { if (approximately_zero(s[i])) { return num; } } s[num++] = 0; return num; } if (approximately_zero(A + B + C + D)) { // 1 is one root int num = SkDQuad::RootsReal(A, A + B, -D, s); for (int i = 0; i < num; ++i) { if (AlmostDequalUlps(s[i], 1)) { return num; } } s[num++] = 1; return num; } double a, b, c; { double invA = 1 / A; a = B * invA; b = C * invA; c = D * invA; } double a2 = a * a; double Q = (a2 - b * 3) / 9; double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54; double R2 = R * R; double Q3 = Q * Q * Q; double R2MinusQ3 = R2 - Q3; double adiv3 = a / 3; double r; double* roots = s; if (R2MinusQ3 < 0) { // we have 3 real roots // the divide/root can, due to finite precisions, be slightly outside of -1...1 double theta = acos(SkTPin(R / sqrt(Q3), -1., 1.)); double neg2RootQ = -2 * sqrt(Q); r = neg2RootQ * cos(theta / 3) - adiv3; *roots++ = r; r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3; if (!AlmostDequalUlps(s[0], r)) { *roots++ = r; } r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3; if (!AlmostDequalUlps(s[0], r) && (roots - s == 1 || !AlmostDequalUlps(s[1], r))) { *roots++ = r; } } else { // we have 1 real root double sqrtR2MinusQ3 = sqrt(R2MinusQ3); double A = fabs(R) + sqrtR2MinusQ3; A = SkDCubeRoot(A); if (R > 0) { A = -A; } if (A != 0) { A += Q / A; } r = A - adiv3; *roots++ = r; if (AlmostDequalUlps((double) R2, (double) Q3)) { r = -A / 2 - adiv3; if (!AlmostDequalUlps(s[0], r)) { *roots++ = r; } } } return static_cast<int>(roots - s); }
static inline SkPMColor fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { x = SkTPin(x, bounds.fLeft, bounds.fRight - 1); y = SkTPin(y, bounds.fTop, bounds.fBottom - 1); return *src.getAddr32(x, y); }