42 ShaderMode
fShaderModes[2] = {ShaderMode::kNone, ShaderMode::kNone};
51 const float border[4],
52 bool alwaysUseShaderTileMode,
54 SkVector linearFilterInset = {0.5f, 0.5f});
62 const float border[4],
63 bool alwaysUseShaderTileMode,
67 float fA = 0.f, fB = 0.f;
69 Span makeInset(
float o)
const {
70 Span r = {fA + o, fB - o};
72 r.fA = r.fB = (r.fA + r.fB) / 2;
77 bool contains(Span r)
const {
return fA <= r.fA && fB >= r.fB; }
80 ShaderMode fShaderMode = ShaderMode::kNone;
87 auto filter = sampler.
filter();
90 auto canDoWrapInHW = [&](
int size,
Wrap wrap) {
91 if (alwaysUseShaderTileMode) {
116 bool aniso = sampler.
isAniso();
120 (!domain || !subset.
contains(*domain));
121 bool needsShaderWrap = !canDoWrapInHW(dim.
width(), sampler.
wrapModeX()) ||
123 if (needsShaderWrap || anisoSubset) {
135 auto resolve = [&](
int size,
Wrap wrap, Span subset, Span domain,
float linearFilterInset) {
137 bool canDoModeInHW = canDoWrapInHW(
size, wrap);
138 if (canDoModeInHW &&
size > 0 && subset.fA <= 0 && subset.fB >=
size) {
139 r.fShaderMode = ShaderMode::kNone;
141 r.fShaderSubset = r.fShaderClamp = {0, 0};
145 r.fShaderSubset = subset;
146 bool domainIsSafe =
false;
149 if (domain.fA > isubset.fA && domain.fB < isubset.fB) {
158 if (r.fShaderClamp.contains(domain)) {
162 if (!alwaysUseShaderTileMode && domainIsSafe) {
166 r.fShaderMode = ShaderMode::kNone;
168 r.fShaderSubset = r.fShaderClamp = {0, 0};
171 r.fShaderMode = GetShaderMode(wrap, filter, mm);
179 auto domainX = domain ? Span{domain->
fLeft, domain->
fRight}
181 x = resolve(dim.
width(), sampler.
wrapModeX(), subsetX, domainX, linearFilterInset.
fX);
184 auto domainY = domain ? Span{domain->
fTop, domain->
fBottom}
186 y = resolve(dim.
height(), sampler.
wrapModeY(), subsetY, domainY, linearFilterInset.
fY);
200 x.fShaderSubset.fB,
y.fShaderSubset.fB};
202 x.fShaderClamp.fB,
y.fShaderClamp.fB};
203 std::copy_n(border, 4,
fBorder);
211 if (ShaderModeIsClampToBorder(fShaderModes[0]) || ShaderModeIsClampToBorder(fShaderModes[1])) {
212 return fBorder[3] < 1.f;
234 const float border[4]) {
254 const float border[4],
255 bool alwaysUseShaderTileMode) {
261 alwaysUseShaderTileMode,
276 const float border[4]) {
294 const float border[4]) {
307 if (this->matrixEffectShouldNormalize()) {
309 m.setScaleTranslate(1.f /
d.width(), -1.f /
d.height(), 0, 1);
311 m.setScale(1.f /
d.width(), 1.f /
d.height());
315 m.setScaleTranslate(1.f, -1.f, 0,
d.height());
321GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(
Wrap wrap,
326 return ShaderMode::kMirrorRepeat;
328 return ShaderMode::kClamp;
348 : ShaderMode::kClampToBorder_Filter;
353inline bool GrTextureEffect::ShaderModeIsClampToBorder(ShaderMode
m) {
354 return m == ShaderMode::kClampToBorder_Nearest ||
m == ShaderMode::kClampToBorder_Filter;
357bool GrTextureEffect::ShaderModeRequiresUnormCoord(ShaderMode
m) {
359 case ShaderMode::kNone:
return false;
360 case ShaderMode::kClamp:
return false;
361 case ShaderMode::kRepeat_Nearest_None:
return false;
362 case ShaderMode::kRepeat_Linear_None:
return true;
363 case ShaderMode::kRepeat_Nearest_Mipmap:
return true;
364 case ShaderMode::kRepeat_Linear_Mipmap:
return true;
365 case ShaderMode::kMirrorRepeat:
return false;
366 case ShaderMode::kClampToBorder_Nearest:
return true;
367 case ShaderMode::kClampToBorder_Filter:
return true;
373 using ShaderMode = GrTextureEffect::ShaderMode;
376 auto* fb =
args.fFragBuilder;
378 if (te.fShaderModes[0] == ShaderMode::kNone &&
379 te.fShaderModes[1] == ShaderMode::kNone) {
380 fb->codeAppendf(
"return ");
381 fb->appendTextureLookup(fSamplerHandle,
args.fSampleCoord);
382 fb->codeAppendf(
";");
403 fb->codeAppendf(
"float2 inCoord = %s;",
args.fSampleCoord);
405 const auto&
m = te.fShaderModes;
407 const char* borderName =
nullptr;
408 if (te.hasClampToBorderShaderMode()) {
409 fBorderUni =
args.fUniformHandler->addUniform(
412 auto modeUsesSubset = [](ShaderMode
m) {
414 case ShaderMode::kNone:
return false;
415 case ShaderMode::kClamp:
return false;
416 case ShaderMode::kRepeat_Nearest_None:
return true;
417 case ShaderMode::kRepeat_Linear_None:
return true;
418 case ShaderMode::kRepeat_Nearest_Mipmap:
return true;
419 case ShaderMode::kRepeat_Linear_Mipmap:
return true;
420 case ShaderMode::kMirrorRepeat:
return true;
421 case ShaderMode::kClampToBorder_Nearest:
return true;
422 case ShaderMode::kClampToBorder_Filter:
return true;
427 auto modeUsesClamp = [](ShaderMode
m) {
429 case ShaderMode::kNone:
return false;
430 case ShaderMode::kClamp:
return true;
431 case ShaderMode::kRepeat_Nearest_None:
return true;
432 case ShaderMode::kRepeat_Linear_None:
return true;
433 case ShaderMode::kRepeat_Nearest_Mipmap:
return true;
434 case ShaderMode::kRepeat_Linear_Mipmap:
return true;
435 case ShaderMode::kMirrorRepeat:
return true;
436 case ShaderMode::kClampToBorder_Nearest:
return false;
437 case ShaderMode::kClampToBorder_Filter:
return true;
442 bool useSubset[2] = {modeUsesSubset(
m[0]), modeUsesSubset(
m[1])};
443 bool useClamp [2] = {modeUsesClamp (
m[0]), modeUsesClamp (
m[1])};
445 const char* subsetName =
nullptr;
446 if (useSubset[0] || useSubset[1]) {
447 fSubsetUni =
args.fUniformHandler->addUniform(
451 const char* clampName =
nullptr;
452 if (useClamp[0] || useClamp[1]) {
453 fClampUni =
args.fUniformHandler->addUniform(
457 bool unormCoordsRequiredForShaderMode = ShaderModeRequiresUnormCoord(
m[0]) ||
458 ShaderModeRequiresUnormCoord(
m[1]);
461 SkASSERT(!(unormCoordsRequiredForShaderMode && te.matrixEffectShouldNormalize()));
462 bool sampleCoordsMustBeNormalized =
465 const char* idims =
nullptr;
466 if (unormCoordsRequiredForShaderMode && sampleCoordsMustBeNormalized) {
474 auto read = [&](
const char* coord) {
478 normCoord.
printf(
"(%s) * %s", coord, idims);
482 fb->appendTextureLookup(&
result, fSamplerHandle, normCoord.
c_str());
487 auto subsetCoord = [&](ShaderMode
mode,
488 const char* coordSwizzle,
489 const char* subsetStartSwizzle,
490 const char* subsetStopSwizzle,
491 const char* extraCoord,
492 const char* coordWeight) {
496 case ShaderMode::kNone:
497 case ShaderMode::kClampToBorder_Nearest:
498 case ShaderMode::kClampToBorder_Filter:
499 case ShaderMode::kClamp:
500 fb->codeAppendf(
"subsetCoord.%s = inCoord.%s;", coordSwizzle, coordSwizzle);
502 case ShaderMode::kRepeat_Nearest_None:
503 case ShaderMode::kRepeat_Linear_None:
505 "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + %s.%s;",
506 coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle, subsetName,
507 subsetStopSwizzle, subsetName, subsetStartSwizzle, subsetName,
510 case ShaderMode::kRepeat_Nearest_Mipmap:
511 case ShaderMode::kRepeat_Linear_Mipmap:
524 fb->codeAppendf(
"float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
525 subsetName, subsetStartSwizzle);
526 fb->codeAppendf(
"float w2 = 2 * w;");
527 fb->codeAppendf(
"float d = inCoord.%s - %s.%s;", coordSwizzle, subsetName,
529 fb->codeAppend(
"float m = mod(d, w2);");
530 fb->codeAppend(
"float o = mix(m, w2 - m, step(w, m));");
531 fb->codeAppendf(
"subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName,
533 fb->codeAppendf(
"%s = w - o + %s.%s;", extraCoord, subsetName,
537 fb->codeAppend(
"float hw = w/2;");
538 fb->codeAppend(
"float n = mod(d - hw, w2);");
539 fb->codeAppendf(
"%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + 0.5));",
543 case ShaderMode::kMirrorRepeat:
545 fb->codeAppendf(
"float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
546 subsetName, subsetStartSwizzle);
547 fb->codeAppendf(
"float w2 = 2 * w;");
548 fb->codeAppendf(
"float m = mod(inCoord.%s - %s.%s, w2);", coordSwizzle,
549 subsetName, subsetStartSwizzle);
550 fb->codeAppendf(
"subsetCoord.%s = mix(m, w2 - m, step(w, m)) + %s.%s;",
551 coordSwizzle, subsetName, subsetStartSwizzle);
557 auto clampCoord = [&](
bool clamp,
558 const char* coordSwizzle,
559 const char* clampStartSwizzle,
560 const char* clampStopSwizzle) {
562 fb->codeAppendf(
"clampedCoord%s = clamp(subsetCoord%s, %s%s, %s%s);",
563 coordSwizzle, coordSwizzle,
564 clampName, clampStartSwizzle,
565 clampName, clampStopSwizzle);
567 fb->codeAppendf(
"clampedCoord%s = subsetCoord%s;", coordSwizzle, coordSwizzle);
572 const char* extraRepeatCoordX =
nullptr;
573 const char* repeatCoordWeightX =
nullptr;
574 const char* extraRepeatCoordY =
nullptr;
575 const char* repeatCoordWeightY =
nullptr;
577 bool mipmapRepeatX =
m[0] == ShaderMode::kRepeat_Nearest_Mipmap ||
578 m[0] == ShaderMode::kRepeat_Linear_Mipmap;
579 bool mipmapRepeatY =
m[1] == ShaderMode::kRepeat_Nearest_Mipmap ||
580 m[1] == ShaderMode::kRepeat_Linear_Mipmap;
582 if (mipmapRepeatX || mipmapRepeatY) {
583 fb->codeAppend(
"float2 extraRepeatCoord;");
586 fb->codeAppend(
"half repeatCoordWeightX;");
587 extraRepeatCoordX =
"extraRepeatCoord.x";
588 repeatCoordWeightX =
"repeatCoordWeightX";
591 fb->codeAppend(
"half repeatCoordWeightY;");
592 extraRepeatCoordY =
"extraRepeatCoord.y";
593 repeatCoordWeightY =
"repeatCoordWeightY";
597 fb->codeAppend(
"float2 subsetCoord;");
598 subsetCoord(te.fShaderModes[0],
"x",
"x",
"z", extraRepeatCoordX, repeatCoordWeightX);
599 subsetCoord(te.fShaderModes[1],
"y",
"y",
"w", extraRepeatCoordY, repeatCoordWeightY);
600 fb->codeAppend(
"float2 clampedCoord;");
601 if (useClamp[0] == useClamp[1]) {
602 clampCoord(useClamp[0],
"",
".xy",
".zw");
604 clampCoord(useClamp[0],
".x",
".x",
".z");
605 clampCoord(useClamp[1],
".y",
".y",
".w");
608 if (mipmapRepeatX && mipmapRepeatY) {
609 fb->codeAppendf(
"extraRepeatCoord = clamp(extraRepeatCoord, %s.xy, %s.zw);",
610 clampName, clampName);
611 }
else if (mipmapRepeatX) {
612 fb->codeAppendf(
"extraRepeatCoord.x = clamp(extraRepeatCoord.x, %s.x, %s.z);",
613 clampName, clampName);
614 }
else if (mipmapRepeatY) {
615 fb->codeAppendf(
"extraRepeatCoord.y = clamp(extraRepeatCoord.y, %s.y, %s.w);",
616 clampName, clampName);
622 if (mipmapRepeatX && mipmapRepeatY) {
624 "half4 textureColor ="
625 " mix(mix(%s, %s, repeatCoordWeightX),"
626 " mix(%s, %s, repeatCoordWeightX),"
627 " repeatCoordWeightY);",
628 read(
"clampedCoord").c_str(),
629 read(
"float2(extraRepeatCoord.x, clampedCoord.y)").c_str(),
630 read(
"float2(clampedCoord.x, extraRepeatCoord.y)").c_str(),
631 read(
"float2(extraRepeatCoord.x, extraRepeatCoord.y)").c_str());
633 }
else if (mipmapRepeatX) {
634 fb->codeAppendf(
"half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
635 read(
"clampedCoord").c_str(),
636 read(
"float2(extraRepeatCoord.x, clampedCoord.y)").c_str());
637 }
else if (mipmapRepeatY) {
638 fb->codeAppendf(
"half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
639 read(
"clampedCoord").c_str(),
640 read(
"float2(clampedCoord.x, extraRepeatCoord.y)").c_str());
642 fb->codeAppendf(
"half4 textureColor = %s;",
read(
"clampedCoord").c_str());
651 bool repeatLinearFilterX =
m[0] == ShaderMode::kRepeat_Linear_None ||
652 m[0] == ShaderMode::kRepeat_Linear_Mipmap;
653 bool repeatLinearFilterY =
m[1] == ShaderMode::kRepeat_Linear_None ||
654 m[1] == ShaderMode::kRepeat_Linear_Mipmap;
655 if (repeatLinearFilterX ||
m[0] == ShaderMode::kClampToBorder_Filter) {
656 fb->codeAppend(
"half errX = half(subsetCoord.x - clampedCoord.x);");
657 if (repeatLinearFilterX) {
658 fb->codeAppendf(
"float repeatCoordX = errX > 0 ? %s.x : %s.z;",
659 clampName, clampName);
660 repeatLinearReadX =
read(
"float2(repeatCoordX, clampedCoord.y)");
663 if (repeatLinearFilterY ||
m[1] == ShaderMode::kClampToBorder_Filter) {
664 fb->codeAppend(
"half errY = half(subsetCoord.y - clampedCoord.y);");
665 if (repeatLinearFilterY) {
666 fb->codeAppendf(
"float repeatCoordY = errY > 0 ? %s.y : %s.w;",
667 clampName, clampName);
668 repeatLinearReadY =
read(
"float2(clampedCoord.x, repeatCoordY)");
676 const char* ifStr =
"if";
677 if (repeatLinearFilterX && repeatLinearFilterY) {
678 auto repeatLinearReadXY =
read(
"float2(repeatCoordX, repeatCoordY)");
680 "if (errX != 0 && errY != 0) {"
682 " textureColor = mix(mix(textureColor, %s, errX),"
683 " mix(%s, %s, errX),"
686 repeatLinearReadX.
c_str(), repeatLinearReadY.
c_str(),
687 repeatLinearReadXY.c_str());
690 if (repeatLinearFilterX) {
693 " textureColor = mix(textureColor, %s, abs(errX));"
695 ifStr, repeatLinearReadX.
c_str());
697 if (repeatLinearFilterY) {
700 " textureColor = mix(textureColor, %s, abs(errY));"
702 ifStr, repeatLinearReadY.
c_str());
707 if (
m[0] == ShaderMode::kClampToBorder_Filter) {
708 fb->codeAppendf(
"textureColor = mix(textureColor, %s, min(abs(errX), 1));", borderName);
710 if (
m[1] == ShaderMode::kClampToBorder_Filter) {
711 fb->codeAppendf(
"textureColor = mix(textureColor, %s, min(abs(errY), 1));", borderName);
717 if (
m[0] == ShaderMode::kClampToBorder_Nearest) {
719 "float snappedX = floor(inCoord.x + 0.001) + 0.5;"
720 "if (snappedX < %s.x || snappedX > %s.z) {"
721 " textureColor = %s;"
723 subsetName, subsetName, borderName);
725 if (
m[1] == ShaderMode::kClampToBorder_Nearest) {
727 "float snappedY = floor(inCoord.y + 0.001) + 0.5;"
728 "if (snappedY < %s.y || snappedY > %s.w) {"
729 " textureColor = %s;"
731 subsetName, subsetName, borderName);
733 fb->codeAppendf(
"return textureColor;");
741 const float w = te.texture()->width();
742 const float h = te.texture()->height();
743 const auto&
s = te.fSubset;
744 const auto& c = te.fClamp;
746 auto type = te.texture()->textureType();
748 float idims[2] = {1.f/
w, 1.f/
h};
750 if (fIDimsUni.isValid()) {
751 pdm.
set2fv(fIDimsUni, 1, idims);
755 auto pushRect = [&](
float rect[4], UniformHandle uni) {
770 if (fSubsetUni.isValid()) {
771 float subset[] = {
s.fLeft,
s.fTop,
s.fRight,
s.fBottom};
772 pushRect(subset, fSubsetUni);
774 if (fClampUni.isValid()) {
775 float subset[] = {c.fLeft, c.fTop, c.fRight, c.fBottom};
776 pushRect(subset, fClampUni);
778 if (fBorderUni.isValid()) {
779 pdm.
set4fv(fBorderUni, 1, te.fBorder);
783std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrTextureEffect::onMakeProgramImpl()
const {
784 return std::make_unique<Impl>();
788 auto m0 =
static_cast<uint32_t
>(fShaderModes[0]);
789 b->addBits(8, m0,
"shaderMode0");
791 auto m1 =
static_cast<uint32_t
>(fShaderModes[1]);
792 b->addBits(8, m1,
"shaderMode1");
797 if (fView != that.fView) {
800 if (fSamplerState != that.fSamplerState) {
803 if (fShaderModes[0] != that.fShaderModes[0] || fShaderModes[1] != that.fShaderModes[1]) {
806 if (fSubset != that.fSubset) {
809 if (this->hasClampToBorderShaderMode() && !
std::equal(fBorder, fBorder + 4, that.fBorder)) {
815bool GrTextureEffect::matrixEffectShouldNormalize()
const {
817 !ShaderModeRequiresUnormCoord(fShaderModes[0]) &&
818 !ShaderModeRequiresUnormCoord(fShaderModes[1]);
827 , fSamplerState(
sampling.fHWSampler)
833 SkASSERT(fShaderModes[0] != ShaderMode::kNone || (fSubset.fLeft == 0 && fSubset.fRight == 0));
834 SkASSERT(fShaderModes[1] != ShaderMode::kNone || (fSubset.fTop == 0 && fSubset.fBottom == 0));
836 std::copy_n(
sampling.fBorder, 4, fBorder);
842 , fSamplerState(
src.fSamplerState)
843 , fSubset(
src.fSubset)
845 , fShaderModes{
src.fShaderModes[0],
src.fShaderModes[1]} {
846 std::copy_n(
src.fBorder, 4, fBorder);
851 return std::unique_ptr<GrFragmentProcessor>(
new GrTextureEffect(*
this));
855#if defined(GR_TEST_UTILS)
856std::unique_ptr<GrFragmentProcessor> GrTextureEffect::TestCreate(GrProcessorTestData* testData) {
857 auto [
view, ct, at] = testData->randomView();
859 GrTest::TestWrapModes(testData->fRandom, wrapModes);
#define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(...)
@ kBottomLeft_GrSurfaceOrigin
static bool equal(const SkBitmap &a, const SkBitmap &b)
static unsigned clamp(SkFixed fx, int max)
constexpr float SK_FloatInfinity
constexpr float SK_FloatNegativeInfinity
static bool read(SkStream *stream, void *buffer, size_t amount)
constexpr bool SkIsPow2(T value)
void swap(sk_sp< T > &a, sk_sp< T > &b)
bool anisoSupport() const
bool clampToBorderSupport() const
bool npotTextureTileSupport() const
OptimizationFlags optimizationFlags() const
void setUsesSampleCoordsDirectly()
static OptimizationFlags ModulateForSamplerOptFlags(SkAlphaType alphaType, bool samplingDecal)
virtual void set4fv(UniformHandle, int arrayCount, const float v[]) const =0
virtual void set2fv(UniformHandle, int arrayCount, const float v[]) const =0
static std::unique_ptr< GrFragmentProcessor > Make(const SkMatrix &matrix, std::unique_ptr< GrFragmentProcessor > child)
@ kGrTextureEffect_ClassID
static constexpr GrSamplerState Aniso(WrapMode wrapX, WrapMode wrapY, int maxAniso, skgpu::Mipmapped viewIsMipped)
constexpr WrapMode wrapModeX() const
constexpr Filter filter() const
constexpr MipmapMode mipmapMode() const
constexpr WrapMode wrapModeY() const
GrTextureProxy * asTextureProxy() const
GrSurfaceOrigin origin() const
GrSurfaceProxy * proxy() const
SkISize backingStoreDimensions() const
SkRect backingStoreBoundsRect() const
SkISize dimensions() const
virtual GrTextureProxy * asTextureProxy()
SkISize dimensions() const
void emitCode(EmitArgs &) override
static constexpr float kInsetEpsilon
static std::unique_ptr< GrFragmentProcessor > MakeCustomLinearFilterInset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wy, const SkRect &subset, const SkRect *domain, SkVector inset, const GrCaps &caps, const float border[4]=kDefaultBorder)
const GrSurfaceProxyView & view() const
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState, const SkRect &subset, const GrCaps &caps, const float border[4]=kDefaultBorder, bool alwaysUseShaderTileMode=false)
SkMatrix coordAdjustmentMatrix() const
GrTexture * texture() const
std::unique_ptr< GrFragmentProcessor > clone() const override
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
GrTextureType textureType() const
skgpu::Mipmapped mipmapped() const
void printf(const char format[],...) SK_PRINTF_LIKE(2
const char * c_str() const
const EmbeddedViewParams * params
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
unsigned useCenter Optional< SkMatrix > matrix
sk_sp< SkBlender > blender SkRect rect
SkSamplingOptions sampling
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
constexpr bool contains(std::string_view str, std::string_view needle)
SIN Vec< N, float > floor(const Vec< N, float > &x)
SIN Vec< N, float > ceil(const Vec< N, float > &x)
static SkRect inset(const SkRect &r)
bool hasBorderAlpha() const
Sampling(Filter filter, MipmapMode mm)
GrSamplerState fHWSampler
ShaderMode fShaderModes[2]
constexpr int32_t width() const
constexpr int32_t height() const
static SkRect Make(const SkISize &size)
SkScalar fBottom
larger y-axis bounds
SkScalar fLeft
smaller x-axis bounds
SkRect makeInset(float dx, float dy) const
SkScalar fRight
larger x-axis bounds
bool contains(SkScalar x, SkScalar y) const
SkScalar fTop
smaller y-axis bounds