27std::optional<Rect> outset_bounds(
const SkMatrix& localToDevice,
30 float outsetX = 3.0f * devSigma;
31 float outsetY = 3.0f * devSigma;
33 outsetX /= std::fabs(localToDevice.
getScaleX());
34 outsetY /= std::fabs(localToDevice.
getScaleY());
40 outsetX /=
scale.width();
41 outsetY /=
scale.height();
53 SkMatrix localToDevice = localToDeviceTransform;
56 return MakeRect(recorder, localToDevice, deviceSigma, srcRRect.
rect());
60 const bool devRRectIsValid = srcRRect.
transform(localToDevice, &devRRect);
62 return MakeCircle(recorder, localToDevice, deviceSigma, srcRRect.
rect(), devRRect.
rect());
70 const float devRadius = localToDevice.
mapVector(0.0f, srcRect.
width() / 2.0f).length();
71 const SkRect devRect = {devCenter.
x() - devRadius,
72 devCenter.
y() - devRadius,
73 devCenter.
x() + devRadius,
74 devCenter.
y() + devRadius};
75 return MakeCircle(recorder, localToDevice, deviceSigma, srcRect, devRect);
80 return MakeRRect(recorder, localToDevice, deviceSigma, srcRRect, devRRect);
86std::optional<AnalyticBlurMask> AnalyticBlurMask::MakeRect(
Recorder* recorder,
110 if (!
m.invert(&devToScaledShape)) {
113 devRect = {srcRect.
left() *
scale.width(),
123 if (std::fabs(devRect.
left()) > 16000.0f || std::fabs(devRect.
top()) > 16000.0f ||
124 std::fabs(devRect.
right()) > 16000.0f || std::fabs(devRect.
bottom()) > 16000.0f) {
129 const float sixSigma = 6.0f * devSigma;
138 recorder,
key, &tableWidth,
139 [](
const void* context) {
140 int tableWidth = *
static_cast<const int*
>(context);
152 const float threeSigma = 3.0f * devSigma;
154 devRect.
top() + threeSigma,
155 devRect.
right() - threeSigma,
156 devRect.
bottom() - threeSigma);
164 const float invSixSigma = 1.0f / sixSigma;
167 std::optional<Rect>
drawBounds = outset_bounds(localToDevice, devSigma, srcRect);
173 SkM44(devToScaledShape),
176 {
static_cast<float>(isFast), invSixSigma},
186std::optional<AnalyticBlurMask> AnalyticBlurMask::MakeCircle(
Recorder* recorder,
191 const float radius = devRect.
width() / 2.0f;
198 struct DerivedParams {
199 float fQuantizedRadius;
200 float fQuantizedDevSigma;
203 float fTextureRadius;
205 bool fUseHalfPlaneApprox;
207 DerivedParams(
float devSigma,
float radius)
208 : fQuantizedRadius(
quantize(radius))
209 , fQuantizedDevSigma(
quantize(devSigma)) {
216 constexpr float kHalfPlaneThreshold = 0.1f;
217 const float sigmaToRadiusRatio =
std::min(fQuantizedDevSigma / fQuantizedRadius, 8.0f);
218 if (sigmaToRadiusRatio <= kHalfPlaneThreshold) {
219 fUseHalfPlaneApprox =
true;
220 fSolidRadius = fQuantizedRadius - 3.0f * fQuantizedDevSigma;
221 fTextureRadius = 6.0f * fQuantizedDevSigma;
223 fUseHalfPlaneApprox =
false;
224 fQuantizedDevSigma = fQuantizedRadius * sigmaToRadiusRatio;
226 fTextureRadius = fQuantizedRadius + 3.0f * fQuantizedDevSigma;
229 }
params{devSigma, radius};
235 if (
params.fUseHalfPlaneApprox) {
247 [](
const void* context) {
248 constexpr int kProfileTextureWidth = 512;
249 const DerivedParams*
params =
static_cast<const DerivedParams*
>(context);
250 if (
params->fUseHalfPlaneApprox) {
254 const float scale = kProfileTextureWidth /
params->fTextureRadius;
257 kProfileTextureWidth);
273 1.0f /
params.fTextureRadius,
277 std::optional<Rect>
drawBounds = outset_bounds(localToDevice,
278 params.fQuantizedDevSigma,
284 constexpr float kUnusedBlurData = 0.0f;
289 {kUnusedBlurData, kUnusedBlurData},
293std::optional<AnalyticBlurMask> AnalyticBlurMask::MakeRRect(
Recorder* recorder,
312 if (devOrig.
fLeft + devLeft + devBlurRadius >= devOrig.
fRight - devRight - devBlurRadius ||
313 devOrig.
fTop + devTop + devBlurRadius >= devOrig.
fBottom - devBot - devBlurRadius) {
317 const int newRRWidth = 2 * devBlurRadius + devLeft + devRight + 1;
318 const int newRRHeight = 2 * devBlurRadius + devTop + devBot + 1;
334 struct DerivedParams {
341 params.fRRectToDraw.setRectRadii(newRect, newRadii);
343 SkISize::Make(newRRWidth + 2 * devBlurRadius, newRRHeight + 2 * devBlurRadius);
344 params.fDevSigma = devSigma;
354 static constexpr int kKeySize =
sizeof(DerivedParams) /
sizeof(uint32_t);
355 static_assert(
SkIsAlign4(
sizeof(DerivedParams)));
363 [](
const void* context) {
364 const DerivedParams*
params =
static_cast<const DerivedParams*
>(context);
379 std::optional<Rect>
drawBounds = outset_bounds(localToDevice, devSigma, srcRRect.
rect());
384 constexpr float kUnusedBlurData = 0.0f;
389 {edgeSize, kUnusedBlurData},
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
static constexpr bool SkIsAlign4(T x)
static uint32_t SkFloat2Bits(float value)
static bool SkIsFinite(T x, Pack... values)
#define SK_BEGIN_REQUIRE_DENSE
#define SK_END_REQUIRE_DENSE
#define SkScalarRoundToInt(x)
#define SkScalarCeilToInt(x)
#define SK_ScalarNearlyZero
#define SkScalarCeilToScalar(x)
bool preservesRightAngles(SkScalar tol=SK_ScalarNearlyZero) const
SkPoint mapPoint(SkPoint pt) const
bool rectStaysRect() const
SkScalar getScaleX() const
bool decomposeScale(SkSize *scale, SkMatrix *remaining=nullptr) const
SkScalar getScaleY() const
bool isScaleTranslate() const
bool isSimilarity(SkScalar tol=SK_ScalarNearlyZero) const
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
void mapVector(SkScalar dx, SkScalar dy, SkVector *result) const
static bool IsSimpleCircular(const SkRRect &rr)
static SkVector GetSimpleRadii(const SkRRect &rr)
static bool IsCircle(const SkRRect &rr)
const SkRect & rect() const
SkVector radii(Corner corner) const
@ kUpperLeft_Corner
index of top-left corner radii
@ kLowerRight_Corner
index of bottom-right corner radii
@ kUpperRight_Corner
index of top-right corner radii
@ kLowerLeft_Corner
index of bottom-left corner radii
bool transform(const SkMatrix &matrix, SkRRect *dst) const
const SkRect & getBounds() const
static Domain GenerateDomain()
const Rect & shapeData() const
AnalyticBlurMask()=delete
static std::optional< AnalyticBlurMask > Make(Recorder *, const Transform &localToDevice, float deviceSigma, const SkRRect &srcRRect)
const Rect & drawBounds() const
const SkSL::ShaderCaps * shaderCaps() const
sk_sp< TextureProxy > findOrCreateCachedProxy(Recorder *, const SkBitmap &, std::string_view label)
const Caps * caps() const
ProxyCache * proxyCache()
const EmbeddedViewParams * params
static float min(float r, float g, float b)
DlVertices::Builder Builder
static float quantize(float deviceSpaceFloat)
SkBitmap CreateRRectBlurMask(const SkRRect &rrectToDraw, const SkISize &dimensions, float sigma)
int ComputeIntegralTableWidth(float sixSigma)
SkBitmap CreateCircleProfile(float sigma, float radius, int profileWidth)
SkBitmap CreateHalfPlaneProfile(int profileWidth)
SkBitmap CreateIntegralTable(int width)
static constexpr SkISize Make(int32_t w, int32_t h)
constexpr float y() const
constexpr float x() const
SkScalar fBottom
larger y-axis bounds
constexpr float left() const
constexpr float top() const
SkScalar fLeft
smaller x-axis bounds
SkRect makeOutset(float dx, float dy) const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
SkScalar fRight
larger x-axis bounds
constexpr float centerX() const
constexpr float right() const
constexpr float centerY() const
constexpr float width() const
constexpr SkPoint center() const
constexpr float bottom() const
SkScalar fTop
smaller y-axis bounds