Flutter Engine
The Flutter Engine
SkBlurMask.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
13#include "include/core/SkRect.h"
19#include "src/base/SkMathPriv.h"
21
22#include <cmath>
23#include <cstring>
24#include <utility>
25
26class SkRRect;
27
28using namespace skia_private;
29
30// This constant approximates the scaling done in the software path's
31// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
32// IMHO, it actually should be 1: we blur "less" than we should do
33// according to the CSS and canvas specs, simply because Safari does the same.
34// Firefox used to do the same too, until 4.0 where they fixed it. So at some
35// point we should probably get rid of these scaling constants and rebaseline
36// all the blur tests.
37static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f;
38
40 return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
41}
42
44 return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f;
45}
46
47
48template <typename AlphaIter>
49static void merge_src_with_blur(uint8_t dst[], int dstRB,
50 AlphaIter src, int srcRB,
51 const uint8_t blur[], int blurRB,
52 int sw, int sh) {
53 dstRB -= sw;
54 blurRB -= sw;
55 while (--sh >= 0) {
56 AlphaIter rowSrc(src);
57 for (int x = sw - 1; x >= 0; --x) {
58 *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*rowSrc)));
59 ++dst;
60 ++rowSrc;
61 ++blur;
62 }
63 dst += dstRB;
64 src >>= srcRB;
65 blur += blurRB;
66 }
67}
68
69template <typename AlphaIter>
70static void clamp_solid_with_orig(uint8_t dst[], int dstRowBytes,
71 AlphaIter src, int srcRowBytes,
72 int sw, int sh) {
73 int x;
74 while (--sh >= 0) {
75 AlphaIter rowSrc(src);
76 for (x = sw - 1; x >= 0; --x) {
77 int s = *rowSrc;
78 int d = *dst;
79 *dst = SkToU8(s + d - SkMulDiv255Round(s, d));
80 ++dst;
81 ++rowSrc;
82 }
83 dst += dstRowBytes - sw;
84 src >>= srcRowBytes;
85 }
86}
87
88template <typename AlphaIter>
89static void clamp_outer_with_orig(uint8_t dst[], int dstRowBytes,
90 AlphaIter src, int srcRowBytes,
91 int sw, int sh) {
92 int x;
93 while (--sh >= 0) {
94 AlphaIter rowSrc(src);
95 for (x = sw - 1; x >= 0; --x) {
96 int srcValue = *rowSrc;
97 if (srcValue) {
98 *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - srcValue)));
99 }
100 ++dst;
101 ++rowSrc;
102 }
103 dst += dstRowBytes - sw;
104 src >>= srcRowBytes;
105 }
106}
107///////////////////////////////////////////////////////////////////////////////
108
109// we use a local function to wrap the class static method to work around
110// a bug in gcc98
111void SkMask_FreeImage(uint8_t* image);
112void SkMask_FreeImage(uint8_t* image) {
114}
115
117 SkIPoint* margin) {
118 if (src.fFormat != SkMask::kBW_Format &&
119 src.fFormat != SkMask::kA8_Format &&
120 src.fFormat != SkMask::kARGB32_Format &&
121 src.fFormat != SkMask::kLCD16_Format)
122 {
123 return false;
124 }
125
126 SkMaskBlurFilter blurFilter{sigma, sigma};
127 if (blurFilter.hasNoBlur()) {
128 // If there is no effective blur most styles will just produce the original mask.
129 // However, kOuter_SkBlurStyle will produce an empty mask.
130 if (style == kOuter_SkBlurStyle) {
131 dst->image() = nullptr;
132 dst->bounds() = SkIRect::MakeEmpty();
133 dst->rowBytes() = dst->fBounds.width();
134 dst->format() = SkMask::kA8_Format;
135 if (margin != nullptr) {
136 // This filter will disregard the src.fImage completely.
137 // The margin is actually {-(src.fBounds.width() / 2), -(src.fBounds.height() / 2)}
138 // but it is not clear if callers will fall over with negative margins.
139 *margin = SkIPoint{0,0};
140 }
141 return true;
142 }
143 return false;
144 }
145 const SkIPoint border = blurFilter.blur(src, dst);
146 // If src.fImage is null, then this call is only to calculate the border.
147 if (src.fImage != nullptr && dst->fImage == nullptr) {
148 return false;
149 }
150
151 if (margin != nullptr) {
152 *margin = border;
153 }
154
155 if (src.fImage == nullptr) {
156 if (style == kInner_SkBlurStyle) {
157 dst->bounds() = src.fBounds; // restore trimmed bounds
158 dst->rowBytes() = dst->fBounds.width();
159 }
160 return true;
161 }
162
163 switch (style) {
165 break;
166 case kSolid_SkBlurStyle: {
167 auto dstStart = &dst->image()[border.x() + border.y() * dst->fRowBytes];
168 switch (src.fFormat) {
171 dstStart, dst->fRowBytes,
172 SkMask::AlphaIter<SkMask::kBW_Format>(src.fImage, 0), src.fRowBytes,
173 src.fBounds.width(), src.fBounds.height());
174 break;
177 dstStart, dst->fRowBytes,
179 src.fBounds.width(), src.fBounds.height());
180 break;
182 const uint32_t* srcARGB = reinterpret_cast<const uint32_t*>(src.fImage);
184 dstStart, dst->fRowBytes,
186 src.fBounds.width(), src.fBounds.height());
187 } break;
189 const uint16_t* srcLCD = reinterpret_cast<const uint16_t*>(src.fImage);
191 dstStart, dst->fRowBytes,
193 src.fBounds.width(), src.fBounds.height());
194 } break;
195 default:
196 SK_ABORT("Unhandled format.");
197 }
198 } break;
199 case kOuter_SkBlurStyle: {
200 auto dstStart = &dst->image()[border.x() + border.y() * dst->fRowBytes];
201 switch (src.fFormat) {
204 dstStart, dst->fRowBytes,
205 SkMask::AlphaIter<SkMask::kBW_Format>(src.fImage, 0), src.fRowBytes,
206 src.fBounds.width(), src.fBounds.height());
207 break;
210 dstStart, dst->fRowBytes,
212 src.fBounds.width(), src.fBounds.height());
213 break;
215 const uint32_t* srcARGB = reinterpret_cast<const uint32_t*>(src.fImage);
217 dstStart, dst->fRowBytes,
219 src.fBounds.width(), src.fBounds.height());
220 } break;
222 const uint16_t* srcLCD = reinterpret_cast<const uint16_t*>(src.fImage);
224 dstStart, dst->fRowBytes,
226 src.fBounds.width(), src.fBounds.height());
227 } break;
228 default:
229 SK_ABORT("Unhandled format.");
230 }
231 } break;
232 case kInner_SkBlurStyle: {
233 // now we allocate the "real" dst, mirror the size of src
234 SkMaskBuilder blur = std::move(*dst);
235 SkAutoMaskFreeImage autoFreeBlurMask(blur.image());
236
237 *dst = SkMaskBuilder(nullptr, src.fBounds, src.fBounds.width(), blur.format());
238 size_t dstSize = dst->computeImageSize();
239 if (0 == dstSize) {
240 return false; // too big to allocate, abort
241 }
242 dst->image() = SkMaskBuilder::AllocImage(dstSize);
243
244 auto blurStart = &blur.image()[border.x() + border.y() * blur.fRowBytes];
245 switch (src.fFormat) {
248 dst->image(), dst->fRowBytes,
249 SkMask::AlphaIter<SkMask::kBW_Format>(src.fImage, 0), src.fRowBytes,
250 blurStart, blur.fRowBytes,
251 src.fBounds.width(), src.fBounds.height());
252 break;
255 dst->image(), dst->fRowBytes,
257 blurStart, blur.fRowBytes,
258 src.fBounds.width(), src.fBounds.height());
259 break;
261 const uint32_t* srcARGB = reinterpret_cast<const uint32_t*>(src.fImage);
263 dst->image(), dst->fRowBytes,
265 blurStart, blur.fRowBytes,
266 src.fBounds.width(), src.fBounds.height());
267 } break;
269 const uint16_t* srcLCD = reinterpret_cast<const uint16_t*>(src.fImage);
271 dst->image(), dst->fRowBytes,
273 blurStart, blur.fRowBytes,
274 src.fBounds.width(), src.fBounds.height());
275 } break;
276 default:
277 SK_ABORT("Unhandled format.");
278 }
279 } break;
280 }
281
282 return true;
283}
284
285/* Convolving a box with itself three times results in a piecewise
286 quadratic function:
287
288 0 x <= -1.5
289 9/8 + 3/2 x + 1/2 x^2 -1.5 < x <= -.5
290 3/4 - x^2 -.5 < x <= .5
291 9/8 - 3/2 x + 1/2 x^2 0.5 < x <= 1.5
292 0 1.5 < x
293
294 Mathematica:
295
296 g[x_] := Piecewise [ {
297 {9/8 + 3/2 x + 1/2 x^2 , -1.5 < x <= -.5},
298 {3/4 - x^2 , -.5 < x <= .5},
299 {9/8 - 3/2 x + 1/2 x^2 , 0.5 < x <= 1.5}
300 }, 0]
301
302 To get the profile curve of the blurred step function at the rectangle
303 edge, we evaluate the indefinite integral, which is piecewise cubic:
304
305 0 x <= -1.5
306 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3 -1.5 < x <= -0.5
307 1/2 + 3/4 x - 1/3 x^3 -.5 < x <= .5
308 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3 .5 < x <= 1.5
309 1 1.5 < x
310
311 in Mathematica code:
312
313 gi[x_] := Piecewise[ {
314 { 0 , x <= -1.5 },
315 { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 },
316 { 1/2 + 3/4 x - 1/3 x^3 , -.5 < x <= .5},
317 { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3, .5 < x <= 1.5}
318 },1]
319*/
320
321static float gaussianIntegral(float x) {
322 if (x > 1.5f) {
323 return 0.0f;
324 }
325 if (x < -1.5f) {
326 return 1.0f;
327 }
328
329 float x2 = x*x;
330 float x3 = x2*x;
331
332 if ( x > 0.5f ) {
333 return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x);
334 }
335 if ( x > -0.5f ) {
336 return 0.5f - (0.75f * x - x3 / 3.0f);
337 }
338 return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
339}
340
341/* ComputeBlurProfile fills in an array of floating
342 point values between 0 and 255 for the profile signature of
343 a blurred half-plane with the given blur radius. Since we're
344 going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
345 all the time, we actually fill in the profile pre-inverted
346 (already done 255-x).
347*/
348
350 SkASSERT(SkScalarCeilToInt(6*sigma) == size);
351
352 int center = size >> 1;
353
354 float invr = 1.f/(2*sigma);
355
356 profile[0] = 255;
357 for (int x = 1 ; x < size ; ++x) {
358 float scaled_x = (center - x - .5f) * invr;
359 float gi = gaussianIntegral(scaled_x);
360 profile[x] = 255 - (uint8_t) (255.f * gi);
361 }
362}
363
364// TODO MAYBE: Maintain a profile cache to avoid recomputing this for
365// commonly used radii. Consider baking some of the most common blur radii
366// directly in as static data?
367
368// Implementation adapted from Michael Herf's approach:
369// http://stereopsis.com/shadowrect/
370
371uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc,
372 int blurredWidth, int sharpWidth) {
373 // how far are we from the original edge?
374 int dx = SkAbs32(((loc << 1) + 1) - blurredWidth) - sharpWidth;
375 int ox = dx >> 1;
376 if (ox < 0) {
377 ox = 0;
378 }
379
380 return profile[ox];
381}
382
383void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile,
384 unsigned int width, SkScalar sigma) {
385
386 unsigned int profile_size = SkScalarCeilToInt(6*sigma);
387 skia_private::AutoTMalloc<uint8_t> horizontalScanline(width);
388
389 unsigned int sw = width - profile_size;
390 // nearest odd number less than the profile size represents the center
391 // of the (2x scaled) profile
392 int center = ( profile_size & ~1 ) - 1;
393
394 int w = sw - center;
395
396 for (unsigned int x = 0 ; x < width ; ++x) {
397 if (profile_size <= sw) {
398 pixels[x] = ProfileLookup(profile, x, width, w);
399 } else {
400 float span = float(sw)/(2*sigma);
401 float giX = 1.5f - (x+.5f)/(2*sigma);
402 pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
403 }
404 }
405}
406
408 const SkRect &src, SkBlurStyle style,
409 SkIPoint *margin, SkMaskBuilder::CreateMode createMode) {
410 int profileSize = SkScalarCeilToInt(6*sigma);
411 if (profileSize <= 0) {
412 return false; // no blur to compute
413 }
414
415 int pad = profileSize/2;
416 if (margin) {
417 margin->set( pad, pad );
418 }
419
420 dst->bounds().setLTRB(SkScalarRoundToInt(src.fLeft - pad),
421 SkScalarRoundToInt(src.fTop - pad),
422 SkScalarRoundToInt(src.fRight + pad),
423 SkScalarRoundToInt(src.fBottom + pad));
424
425 dst->rowBytes() = dst->fBounds.width();
426 dst->format() = SkMask::kA8_Format;
427 dst->image() = nullptr;
428
429 int sw = SkScalarFloorToInt(src.width());
430 int sh = SkScalarFloorToInt(src.height());
431
433 if (style == kInner_SkBlurStyle) {
434 dst->bounds() = src.round(); // restore trimmed bounds
435 dst->rowBytes() = sw;
436 }
437 return true;
438 }
439
440 AutoTMalloc<uint8_t> profile(profileSize);
441
442 ComputeBlurProfile(profile, profileSize, sigma);
443
444 size_t dstSize = dst->computeImageSize();
445 if (0 == dstSize) {
446 return false; // too big to allocate, abort
447 }
448
449 uint8_t* dp = SkMaskBuilder::AllocImage(dstSize);
450 dst->image() = dp;
451
452 int dstHeight = dst->fBounds.height();
453 int dstWidth = dst->fBounds.width();
454
455 uint8_t *outptr = dp;
456
457 AutoTMalloc<uint8_t> horizontalScanline(dstWidth);
458 AutoTMalloc<uint8_t> verticalScanline(dstHeight);
459
460 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma);
461 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma);
462
463 for (int y = 0 ; y < dstHeight ; ++y) {
464 for (int x = 0 ; x < dstWidth ; x++) {
465 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]);
466 *(outptr++) = maskval;
467 }
468 }
469
470 if (style == kInner_SkBlurStyle) {
471 // now we allocate the "real" dst, mirror the size of src
472 size_t srcSize = (size_t)(src.width() * src.height());
473 if (0 == srcSize) {
474 return false; // too big to allocate, abort
475 }
476 dst->image() = SkMaskBuilder::AllocImage(srcSize);
477 for (int y = 0 ; y < sh ; y++) {
478 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
479 uint8_t *inner_scanline = dst->image() + y*sw;
480 memcpy(inner_scanline, blur_scanline, sw);
481 }
483
484 dst->bounds() = src.round(); // restore trimmed bounds
485 dst->rowBytes() = sw;
486
487 } else if (style == kOuter_SkBlurStyle) {
488 for (int y = pad ; y < dstHeight-pad ; y++) {
489 uint8_t *dst_scanline = dp + y*dstWidth + pad;
490 memset(dst_scanline, 0, sw);
491 }
492 } else if (style == kSolid_SkBlurStyle) {
493 for (int y = pad ; y < dstHeight-pad ; y++) {
494 uint8_t *dst_scanline = dp + y*dstWidth + pad;
495 memset(dst_scanline, 0xff, sw);
496 }
497 }
498 // normal and solid styles are the same for analytic rect blurs, so don't
499 // need to handle solid specially.
500
501 return true;
502}
503
505 const SkRRect &src, SkBlurStyle style,
506 SkIPoint *margin, SkMaskBuilder::CreateMode createMode) {
507 // Temporary for now -- always fail, should cause caller to fall back
508 // to old path. Plumbing just to land API and parallelize effort.
509
510 return false;
511}
512
513// The "simple" blur is a direct implementation of separable convolution with a discrete
514// gaussian kernel. It's "ground truth" in a sense; too slow to be used, but very
515// useful for correctness comparisons.
516
518 SkBlurStyle style, SkIPoint* margin) {
519
520 if (src.fFormat != SkMask::kA8_Format) {
521 return false;
522 }
523
524 float variance = sigma * sigma;
525
526 int windowSize = SkScalarCeilToInt(sigma*6);
527 // round window size up to nearest odd number
528 windowSize |= 1;
529
530 AutoTMalloc<float> gaussWindow(windowSize);
531
532 int halfWindow = windowSize >> 1;
533
534 gaussWindow[halfWindow] = 1;
535
536 float windowSum = 1;
537 for (int x = 1 ; x <= halfWindow ; ++x) {
538 float gaussian = expf(-x*x / (2*variance));
539 gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian;
540 windowSum += 2*gaussian;
541 }
542
543 // leave the filter un-normalized for now; we will divide by the normalization
544 // sum later;
545
546 int pad = halfWindow;
547 if (margin) {
548 margin->set( pad, pad );
549 }
550
551 dst->bounds() = src.fBounds;
552 dst->bounds().outset(pad, pad);
553
554 dst->rowBytes() = dst->fBounds.width();
555 dst->format() = SkMask::kA8_Format;
556 dst->image() = nullptr;
557
558 if (src.fImage) {
559
560 size_t dstSize = dst->computeImageSize();
561 if (0 == dstSize) {
562 return false; // too big to allocate, abort
563 }
564
565 int srcWidth = src.fBounds.width();
566 int srcHeight = src.fBounds.height();
567 int dstWidth = dst->fBounds.width();
568
569 const uint8_t* srcPixels = src.fImage;
570 uint8_t* dstPixels = SkMaskBuilder::AllocImage(dstSize);
571 SkAutoMaskFreeImage autoFreeDstPixels(dstPixels);
572
573 // do the actual blur. First, make a padded copy of the source.
574 // use double pad so we never have to check if we're outside anything
575
576 int padWidth = srcWidth + 4*pad;
577 int padHeight = srcHeight;
578 int padSize = padWidth * padHeight;
579
580 AutoTMalloc<uint8_t> padPixels(padSize);
581 memset(padPixels, 0, padSize);
582
583 for (int y = 0 ; y < srcHeight; ++y) {
584 uint8_t* padptr = padPixels + y * padWidth + 2*pad;
585 const uint8_t* srcptr = srcPixels + y * srcWidth;
586 memcpy(padptr, srcptr, srcWidth);
587 }
588
589 // blur in X, transposing the result into a temporary floating point buffer.
590 // also double-pad the intermediate result so that the second blur doesn't
591 // have to do extra conditionals.
592
593 int tmpWidth = padHeight + 4*pad;
594 int tmpHeight = padWidth - 2*pad;
595 int tmpSize = tmpWidth * tmpHeight;
596
597 AutoTMalloc<float> tmpImage(tmpSize);
598 memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0]));
599
600 for (int y = 0 ; y < padHeight ; ++y) {
601 uint8_t *srcScanline = padPixels + y*padWidth;
602 for (int x = pad ; x < padWidth - pad ; ++x) {
603 float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output
604 uint8_t *windowCenter = srcScanline + x;
605 for (int i = -pad ; i <= pad ; ++i) {
606 *outPixel += gaussWindow[pad+i]*windowCenter[i];
607 }
608 *outPixel /= windowSum;
609 }
610 }
611
612 // blur in Y; now filling in the actual desired destination. We have to do
613 // the transpose again; these transposes guarantee that we read memory in
614 // linear order.
615
616 for (int y = 0 ; y < tmpHeight ; ++y) {
617 float *srcScanline = tmpImage + y*tmpWidth;
618 for (int x = pad ; x < tmpWidth - pad ; ++x) {
619 float *windowCenter = srcScanline + x;
620 float finalValue = 0;
621 for (int i = -pad ; i <= pad ; ++i) {
622 finalValue += gaussWindow[pad+i]*windowCenter[i];
623 }
624 finalValue /= windowSum;
625 uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output
626 int integerPixel = int(finalValue + 0.5f);
627 *outPixel = SkTPin(SkClampPos(integerPixel), 0, 255);
628 }
629 }
630
631 dst->image() = dstPixels;
632 switch (style) {
634 break;
635 case kSolid_SkBlurStyle: {
637 dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes,
638 SkMask::AlphaIter<SkMask::kA8_Format>(srcPixels), src.fRowBytes,
639 srcWidth, srcHeight);
640 } break;
641 case kOuter_SkBlurStyle: {
643 dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes,
644 SkMask::AlphaIter<SkMask::kA8_Format>(srcPixels), src.fRowBytes,
645 srcWidth, srcHeight);
646 } break;
647 case kInner_SkBlurStyle: {
648 // now we allocate the "real" dst, mirror the size of src
649 size_t srcSize = src.computeImageSize();
650 if (0 == srcSize) {
651 return false; // too big to allocate, abort
652 }
653 dst->image() = SkMaskBuilder::AllocImage(srcSize);
654 merge_src_with_blur(dst->image(), src.fRowBytes,
655 SkMask::AlphaIter<SkMask::kA8_Format>(srcPixels), src.fRowBytes,
656 dstPixels + pad*dst->fRowBytes + pad,
657 dst->fRowBytes, srcWidth, srcHeight);
658 SkMaskBuilder::FreeImage(dstPixels);
659 } break;
660 }
661 autoFreeDstPixels.release();
662 }
663
664 if (style == kInner_SkBlurStyle) {
665 dst->bounds() = src.fBounds; // restore trimmed bounds
666 dst->rowBytes() = src.fRowBytes;
667 }
668
669 return true;
670}
static float gaussian(int x, SkScalar sigma)
Definition: BlurTest.cpp:223
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
static void merge_src_with_blur(uint8_t dst[], int dstRB, AlphaIter src, int srcRB, const uint8_t blur[], int blurRB, int sw, int sh)
Definition: SkBlurMask.cpp:49
static const SkScalar kBLUR_SIGMA_SCALE
Definition: SkBlurMask.cpp:37
static void clamp_solid_with_orig(uint8_t dst[], int dstRowBytes, AlphaIter src, int srcRowBytes, int sw, int sh)
Definition: SkBlurMask.cpp:70
static void clamp_outer_with_orig(uint8_t dst[], int dstRowBytes, AlphaIter src, int srcRowBytes, int sw, int sh)
Definition: SkBlurMask.cpp:89
static float gaussianIntegral(float x)
Definition: SkBlurMask.cpp:321
void SkMask_FreeImage(uint8_t *image)
Definition: SkBlurMask.cpp:112
SkBlurStyle
Definition: SkBlurTypes.h:11
@ kOuter_SkBlurStyle
nothing inside, fuzzy outside
Definition: SkBlurTypes.h:14
@ kSolid_SkBlurStyle
solid inside, fuzzy outside
Definition: SkBlurTypes.h:13
@ kInner_SkBlurStyle
fuzzy inside, nothing outside
Definition: SkBlurTypes.h:15
@ kNormal_SkBlurStyle
fuzzy inside and outside
Definition: SkBlurTypes.h:12
#define SkAlphaMul(value, alpha256)
Definition: SkColorPriv.h:34
static unsigned SkAlpha255To256(U8CPU alpha)
Definition: SkColorPriv.h:24
std::unique_ptr< uint8_t, SkFunctionObject< SkMaskBuilder::FreeImage > > SkAutoMaskFreeImage
Definition: SkMask.h:316
static int SkClampPos(int value)
Definition: SkMathPriv.h:30
static U8CPU SkMulDiv255Round(U16CPU a, U16CPU b)
Definition: SkMath.h:73
static int32_t SkAbs32(int32_t value)
Definition: SkSafe32.h:41
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
#define SkScalarCeilToInt(x)
Definition: SkScalar.h:36
#define SkScalarFloorToInt(x)
Definition: SkScalar.h:35
static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter *blitter)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
constexpr uint8_t SkToU8(S x)
Definition: SkTo.h:22
static SkScalar center(float pos0, float pos1)
static void ComputeBlurProfile(uint8_t *profile, int size, SkScalar sigma)
Definition: SkBlurMask.cpp:349
static void ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, unsigned int width, SkScalar sigma)
Definition: SkBlurMask.cpp:383
static bool BlurRect(SkScalar sigma, SkMaskBuilder *dst, const SkRect &src, SkBlurStyle, SkIPoint *margin=nullptr, SkMaskBuilder::CreateMode createMode=SkMaskBuilder::kComputeBoundsAndRenderImage_CreateMode)
Definition: SkBlurMask.cpp:407
static bool BlurRRect(SkScalar sigma, SkMaskBuilder *dst, const SkRRect &src, SkBlurStyle, SkIPoint *margin=nullptr, SkMaskBuilder::CreateMode createMode=SkMaskBuilder::kComputeBoundsAndRenderImage_CreateMode)
Definition: SkBlurMask.cpp:504
static SkScalar SK_SPI ConvertSigmaToRadius(SkScalar sigma)
Definition: SkBlurMask.cpp:43
static SkScalar SK_SPI ConvertRadiusToSigma(SkScalar radius)
Definition: SkBlurMask.cpp:39
static bool BlurGroundTruth(SkScalar sigma, SkMaskBuilder *dst, const SkMask &src, SkBlurStyle, SkIPoint *margin=nullptr)
Definition: SkBlurMask.cpp:517
static bool BoxBlur(SkMaskBuilder *dst, const SkMask &src, SkScalar sigma, SkBlurStyle style, SkIPoint *margin=nullptr)
Definition: SkBlurMask.cpp:116
static uint8_t ProfileLookup(const uint8_t *profile, int loc, int blurredWidth, int sharpWidth)
Definition: SkBlurMask.cpp:371
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
float SkScalar
Definition: extension.cpp:12
struct MyStruct s
double y
double x
sk_sp< const SkImage > image
Definition: SkRecords.h:269
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
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
Definition: switches.h:259
dst
Definition: cp.py:12
sh
Definition: run_sh.py:10
SkScalar w
int32_t width
constexpr int32_t y() const
Definition: SkPoint_impl.h:52
void set(int32_t x, int32_t y)
Definition: SkPoint_impl.h:65
constexpr int32_t x() const
Definition: SkPoint_impl.h:46
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
static void FreeImage(void *image)
Definition: SkMask.cpp:57
@ kJustComputeBounds_CreateMode
compute bounds and return
Definition: SkMask.h:299
Format & format()
Definition: SkMask.h:239
static uint8_t * AllocImage(size_t bytes, AllocType=kUninit_Alloc)
Definition: SkMask.cpp:45
uint8_t *& image()
Definition: SkMask.h:236
Definition: SkMask.h:25
const uint32_t fRowBytes
Definition: SkMask.h:43
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition: SkMask.h:28
@ kLCD16_Format
565 alpha for r/g/b
Definition: SkMask.h:31
@ kARGB32_Format
SkPMColor.
Definition: SkMask.h:30
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition: SkMask.h:27