Flutter Engine
The Flutter Engine
Classes | Macros | Typedefs | Functions
SkScan_Antihair.cpp File Reference
#include "include/core/SkColorPriv.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRegion.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkCPUTypes.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkSafe32.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkBlitter.h"
#include "src/core/SkFDot6.h"
#include "src/core/SkLineClipper.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkScan.h"
#include <algorithm>
#include <cstdint>

Go to the source code of this file.

Classes

class  SkAntiHairBlitter
 
class  HLine_SkAntiHairBlitter
 
class  Horish_SkAntiHairBlitter
 
class  VLine_SkAntiHairBlitter
 
class  Vertish_SkAntiHairBlitter
 

Macros

#define OUTSET_BEFORE_CLIP_TEST   true
 
#define HLINE_STACK_BUFFER   100
 
#define ApplyGamma(table, alpha)   SkToU8(alpha)
 
#define SkBITCOUNT(x)   (sizeof(x) << 3)
 
#define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
 

Typedefs

typedef int FDot8
 

Functions

static int SmallDot6Scale (int value, int dot6)
 
static void call_hline_blitter (SkBlitter *blitter, int x, int y, int count, U8CPU alpha)
 
static SkFixed fastfixdiv (SkFDot6 a, SkFDot6 b)
 
static int bad_int (int x)
 
static int any_bad_ints (int a, int b, int c, int d)
 
static int contribution_64 (SkFDot6 ordinate)
 
static void do_anti_hairline (SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, const SkIRect *clip, SkBlitter *blitter)
 
static FDot8 SkFixedToFDot8 (SkFixed x)
 
static void do_scanline (FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter *blitter)
 
static void antifilldot8 (FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter *blitter, bool fillInner)
 
static void antifillrect (const SkXRect &xr, SkBlitter *blitter)
 
static void antifillrect (const SkRect &r, SkBlitter *blitter)
 
static void fillcheckrect (int L, int T, int R, int B, SkBlitter *blitter)
 
static FDot8 SkScalarToFDot8 (SkScalar x)
 
static int FDot8Floor (FDot8 x)
 
static int FDot8Ceil (FDot8 x)
 
static U8CPU InvAlphaMul (U8CPU a, U8CPU b)
 
static void inner_scanline (FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter *blitter)
 
static void innerstrokedot8 (FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter *blitter)
 
static void align_thin_stroke (FDot8 &edge1, FDot8 &edge2)
 

Macro Definition Documentation

◆ ApplyGamma

#define ApplyGamma (   table,
  alpha 
)    SkToU8(alpha)

Definition at line 75 of file SkScan_Antihair.cpp.

◆ HLINE_STACK_BUFFER

#define HLINE_STACK_BUFFER   100

Definition at line 44 of file SkScan_Antihair.cpp.

◆ OUTSET_BEFORE_CLIP_TEST

#define OUTSET_BEFORE_CLIP_TEST   true

Definition at line 42 of file SkScan_Antihair.cpp.

◆ SkAlphaMulRound

#define SkAlphaMulRound (   a,
  b 
)    SkMulDiv255Round(a, b)

Definition at line 834 of file SkScan_Antihair.cpp.

◆ SkBITCOUNT

#define SkBITCOUNT (   x)    (sizeof(x) << 3)

Definition at line 275 of file SkScan_Antihair.cpp.

Typedef Documentation

◆ FDot8

typedef int FDot8

Definition at line 635 of file SkScan_Antihair.cpp.

Function Documentation

◆ align_thin_stroke()

static void align_thin_stroke ( FDot8 edge1,
FDot8 edge2 
)
inlinestatic

Definition at line 927 of file SkScan_Antihair.cpp.

927 {
928 SkASSERT(edge1 <= edge2);
929
930 if (FDot8Floor(edge1) == FDot8Floor(edge2)) {
931 edge2 -= (edge1 & 0xFF);
932 edge1 &= ~0xFF;
933 }
934}
#define SkASSERT(cond)
Definition: SkAssert.h:116
static int FDot8Floor(FDot8 x)

◆ antifilldot8()

static void antifilldot8 ( FDot8  L,
FDot8  T,
FDot8  R,
FDot8  B,
SkBlitter blitter,
bool  fillInner 
)
static

Definition at line 667 of file SkScan_Antihair.cpp.

668 {
669 // check for empty now that we're in our reduced precision space
670 if (L >= R || T >= B) {
671 return;
672 }
673 int top = T >> 8;
674 if (top == ((B - 1) >> 8)) { // just one scanline high
675 do_scanline(L, top, R, B - T - 1, blitter);
676 return;
677 }
678
679 if (T & 0xFF) {
680 do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
681 top += 1;
682 }
683
684 int bot = B >> 8;
685 int height = bot - top;
686 if (height > 0) {
687 int left = L >> 8;
688 if (left == ((R - 1) >> 8)) { // just 1-pixel wide
689 blitter->blitV(left, top, height, R - L - 1);
690 } else {
691 if (L & 0xFF) {
692 blitter->blitV(left, top, height, 256 - (L & 0xFF));
693 left += 1;
694 }
695 int rite = R >> 8;
696 int width = rite - left;
697 if (width > 0 && fillInner) {
698 blitter->blitRect(left, top, width, height);
699 }
700 if (R & 0xFF) {
701 blitter->blitV(rite, top, height, R & 0xFF);
702 }
703 }
704 }
705
706 if (B & 0xFF) {
707 do_scanline(L, bot, R, B & 0xFF, blitter);
708 }
709}
static bool left(const SkPoint &p0, const SkPoint &p1)
static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter *blitter)
virtual void blitV(int x, int y, int height, SkAlpha alpha)
Blit a vertical run of pixels with a constant alpha value.
Definition: SkBlitter.cpp:119
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
Definition: SkBlitter.cpp:133
#define R(r)
#define T
Definition: precompiler.cc:65
int32_t height
int32_t width

◆ antifillrect() [1/2]

static void antifillrect ( const SkRect r,
SkBlitter blitter 
)
static

Definition at line 779 of file SkScan_Antihair.cpp.

779 {
780 SkXRect xr;
781
782 XRect_set(&xr, r);
783 antifillrect(xr, blitter);
784}
static void XRect_set(SkXRect *xr, const SkIRect &src)
Definition: SkScan.h:98
static void antifillrect(const SkXRect &xr, SkBlitter *blitter)
Definition: SkRect.h:32

◆ antifillrect() [2/2]

static void antifillrect ( const SkXRect xr,
SkBlitter blitter 
)
static

Definition at line 711 of file SkScan_Antihair.cpp.

711 {
714 blitter, true);
715}
static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter *blitter, bool fillInner)
static FDot8 SkFixedToFDot8(SkFixed x)
int32_t fBottom
larger y-axis bounds
Definition: SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
int32_t fRight
larger x-axis bounds
Definition: SkRect.h:35

◆ any_bad_ints()

static int any_bad_ints ( int  a,
int  b,
int  c,
int  d 
)
static

Definition at line 283 of file SkScan_Antihair.cpp.

283 {
284 return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1);
285}
static int bad_int(int x)
#define SkBITCOUNT(x)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
static bool b
struct MyStruct a[10]

◆ bad_int()

static int bad_int ( int  x)
inlinestatic

Definition at line 279 of file SkScan_Antihair.cpp.

279 {
280 return x & -x;
281}
double x

◆ call_hline_blitter()

static void call_hline_blitter ( SkBlitter blitter,
int  x,
int  y,
int  count,
U8CPU  alpha 
)
static

Definition at line 80 of file SkScan_Antihair.cpp.

81 {
82 SkASSERT(count > 0);
83
84 int16_t runs[HLINE_STACK_BUFFER + 1];
85 uint8_t aa[HLINE_STACK_BUFFER];
86
87 do {
88 // In theory, we should be able to just do this once (outside of the loop),
89 // since aa[] and runs[] are supposed" to be const when we call the blitter.
90 // In reality, some wrapper-blitters (e.g. SkRgnClipBlitter) cast away that
91 // constness, and modify the buffers in-place. Hence the need to be defensive
92 // here and reseed the aa value.
93 aa[0] = ApplyGamma(gGammaTable, alpha);
94
95 int n = count;
96 if (n > HLINE_STACK_BUFFER) {
98 }
99 runs[0] = SkToS16(n);
100 runs[n] = 0;
101 blitter->blitAntiH(x, y, aa, runs);
102 x += n;
103 count -= n;
104 } while (count > 0);
105}
int count
Definition: FontMgrTest.cpp:50
#define ApplyGamma(table, alpha)
#define HLINE_STACK_BUFFER
constexpr int16_t SkToS16(S x)
Definition: SkTo.h:23
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
double y

◆ contribution_64()

static int contribution_64 ( SkFDot6  ordinate)
static

Definition at line 309 of file SkScan_Antihair.cpp.

309 {
310#if 0
311 int result = ordinate & 63;
312 if (0 == result) {
313 result = 64;
314 }
315#else
316 int result = ((ordinate - 1) & 63) + 1;
317#endif
318 SkASSERT(result > 0 && result <= 64);
319 return result;
320}
GAsyncResult * result

◆ do_anti_hairline()

static void do_anti_hairline ( SkFDot6  x0,
SkFDot6  y0,
SkFDot6  x1,
SkFDot6  y1,
const SkIRect clip,
SkBlitter blitter 
)
static

Definition at line 322 of file SkScan_Antihair.cpp.

323 {
324 // check for integer NaN (0x80000000) which we can't handle (can't negate it)
325 // It appears typically from a huge float (inf or nan) being converted to int.
326 // If we see it, just don't draw.
327 if (any_bad_ints(x0, y0, x1, y1)) {
328 return;
329 }
330
331 // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time
332 // (in dot6 format)
333 SkASSERT(canConvertFDot6ToFixed(x0));
334 SkASSERT(canConvertFDot6ToFixed(y0));
335 SkASSERT(canConvertFDot6ToFixed(x1));
336 SkASSERT(canConvertFDot6ToFixed(y1));
337
338 if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
339 /* instead of (x0 + x1) >> 1, we shift each separately. This is less
340 precise, but avoids overflowing the intermediate result if the
341 values are huge. A better fix might be to clip the original pts
342 directly (i.e. do the divide), so we don't spend time subdividing
343 huge lines at all.
344 */
345 int hx = (x0 >> 1) + (x1 >> 1);
346 int hy = (y0 >> 1) + (y1 >> 1);
347 do_anti_hairline(x0, y0, hx, hy, clip, blitter);
348 do_anti_hairline(hx, hy, x1, y1, clip, blitter);
349 return;
350 }
351
352 int scaleStart, scaleStop;
353 int istart, istop;
354 SkFixed fstart, slope;
355
356 HLine_SkAntiHairBlitter hline_blitter;
357 Horish_SkAntiHairBlitter horish_blitter;
358 VLine_SkAntiHairBlitter vline_blitter;
359 Vertish_SkAntiHairBlitter vertish_blitter;
360 SkAntiHairBlitter* hairBlitter = nullptr;
361
362 if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) { // mostly horizontal
363 if (x0 > x1) { // we want to go left-to-right
364 using std::swap;
365 swap(x0, x1);
366 swap(y0, y1);
367 }
368
369 istart = SkFDot6Floor(x0);
370 istop = SkFDot6Ceil(x1);
371 fstart = SkFDot6ToFixed(y0);
372 if (y0 == y1) { // completely horizontal, take fast case
373 slope = 0;
374 hairBlitter = &hline_blitter;
375 } else {
376 slope = fastfixdiv(y1 - y0, x1 - x0);
377 SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
378 fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
379 hairBlitter = &horish_blitter;
380 }
381
382 SkASSERT(istop > istart);
383 if (istop - istart == 1) {
384 // we are within a single pixel
385 scaleStart = x1 - x0;
386 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
387 scaleStop = 0;
388 } else {
389 scaleStart = 64 - (x0 & 63);
390 scaleStop = x1 & 63;
391 }
392
393 if (clip){
394 if (istart >= clip->fRight || istop <= clip->fLeft) {
395 return;
396 }
397 if (istart < clip->fLeft) {
398 fstart += slope * (clip->fLeft - istart);
399 istart = clip->fLeft;
400 scaleStart = 64;
401 if (istop - istart == 1) {
402 // we are within a single pixel
403 scaleStart = contribution_64(x1);
404 scaleStop = 0;
405 }
406 }
407 if (istop > clip->fRight) {
408 istop = clip->fRight;
409 scaleStop = 0; // so we don't draw this last column
410 }
411
412 SkASSERT(istart <= istop);
413 if (istart == istop) {
414 return;
415 }
416 // now test if our Y values are completely inside the clip
417 int top, bottom;
418 if (slope >= 0) { // T2B
419 top = SkFixedFloorToInt(fstart - SK_FixedHalf);
420 bottom = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
421 } else { // B2T
422 bottom = SkFixedCeilToInt(fstart + SK_FixedHalf);
423 top = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
424 }
425#ifdef OUTSET_BEFORE_CLIP_TEST
426 top -= 1;
427 bottom += 1;
428#endif
429 if (top >= clip->fBottom || bottom <= clip->fTop) {
430 return;
431 }
432 if (clip->fTop <= top && clip->fBottom >= bottom) {
433 clip = nullptr;
434 }
435 }
436 } else { // mostly vertical
437 if (y0 > y1) { // we want to go top-to-bottom
438 using std::swap;
439 swap(x0, x1);
440 swap(y0, y1);
441 }
442
443 istart = SkFDot6Floor(y0);
444 istop = SkFDot6Ceil(y1);
445 fstart = SkFDot6ToFixed(x0);
446 if (x0 == x1) {
447 if (y0 == y1) { // are we zero length?
448 return; // nothing to do
449 }
450 slope = 0;
451 hairBlitter = &vline_blitter;
452 } else {
453 slope = fastfixdiv(x1 - x0, y1 - y0);
454 SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
455 fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
456 hairBlitter = &vertish_blitter;
457 }
458
459 SkASSERT(istop > istart);
460 if (istop - istart == 1) {
461 // we are within a single pixel
462 scaleStart = y1 - y0;
463 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
464 scaleStop = 0;
465 } else {
466 scaleStart = 64 - (y0 & 63);
467 scaleStop = y1 & 63;
468 }
469
470 if (clip) {
471 if (istart >= clip->fBottom || istop <= clip->fTop) {
472 return;
473 }
474 if (istart < clip->fTop) {
475 fstart += slope * (clip->fTop - istart);
476 istart = clip->fTop;
477 scaleStart = 64;
478 if (istop - istart == 1) {
479 // we are within a single pixel
480 scaleStart = contribution_64(y1);
481 scaleStop = 0;
482 }
483 }
484 if (istop > clip->fBottom) {
485 istop = clip->fBottom;
486 scaleStop = 0; // so we don't draw this last row
487 }
488
489 SkASSERT(istart <= istop);
490 if (istart == istop)
491 return;
492
493 // now test if our X values are completely inside the clip
494 int left, right;
495 if (slope >= 0) { // L2R
497 right = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
498 } else { // R2L
500 left = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
501 }
502#ifdef OUTSET_BEFORE_CLIP_TEST
503 left -= 1;
504 right += 1;
505#endif
506 if (left >= clip->fRight || right <= clip->fLeft) {
507 return;
508 }
509 if (clip->fLeft <= left && clip->fRight >= right) {
510 clip = nullptr;
511 }
512 }
513 }
514
515 SkRectClipBlitter rectClipper;
516 if (clip) {
517 rectClipper.init(blitter, *clip);
518 blitter = &rectClipper;
519 }
520
521 SkASSERT(hairBlitter);
522 hairBlitter->setup(blitter);
523
524#ifdef SK_DEBUG
525 if (scaleStart > 0 && scaleStop > 0) {
526 // be sure we don't draw twice in the same pixel
527 SkASSERT(istart < istop - 1);
528 }
529#endif
530
531 fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart);
532 istart += 1;
533 int fullSpans = istop - istart - (scaleStop > 0);
534 if (fullSpans > 0) {
535 fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope);
536 }
537 if (scaleStop > 0) {
538 hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop);
539 }
540}
#define SkFDot6Ceil(x)
Definition: SkFDot6.h:53
#define SkFDot6Floor(x)
Definition: SkFDot6.h:52
SkFixed SkFDot6ToFixed(SkFDot6 x)
Definition: SkFDot6.h:58
#define SkIntToFDot6(x)
Definition: SkFDot6.h:49
#define SkFixedCeilToInt(x)
Definition: SkFixed.h:77
int32_t SkFixed
Definition: SkFixed.h:25
#define SK_Fixed1
Definition: SkFixed.h:26
#define SK_FixedHalf
Definition: SkFixed.h:27
#define SkFixedFloorToInt(x)
Definition: SkFixed.h:78
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
static bool right(const SkPoint &p0, const SkPoint &p1)
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
static int32_t SkAbs32(int32_t value)
Definition: SkSafe32.h:41
static int any_bad_ints(int a, int b, int c, int d)
static SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b)
static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, const SkIRect *clip, SkBlitter *blitter)
static int contribution_64(SkFDot6 ordinate)
virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64)=0
void setup(SkBlitter *blitter)
virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope)=0
void init(SkBlitter *blitter, const SkIRect &clipRect)
Definition: SkBlitter.h:184

◆ do_scanline()

static void do_scanline ( FDot8  L,
int  top,
FDot8  R,
U8CPU  alpha,
SkBlitter blitter 
)
static

Definition at line 641 of file SkScan_Antihair.cpp.

642 {
643 SkASSERT(L < R);
644
645 if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel
646 blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
647 return;
648 }
649
650 int left = L >> 8;
651
652 if (L & 0xFF) {
653 blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
654 left += 1;
655 }
656
657 int rite = R >> 8;
658 int width = rite - left;
659 if (width > 0) {
660 call_hline_blitter(blitter, left, top, width, alpha);
661 }
662 if (R & 0xFF) {
663 blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
664 }
665}
#define SkAlphaMul(value, alpha256)
Definition: SkColorPriv.h:34
static void call_hline_blitter(SkBlitter *blitter, int x, int y, int count, U8CPU alpha)

◆ fastfixdiv()

static SkFixed fastfixdiv ( SkFDot6  a,
SkFDot6  b 
)
inlinestatic

Definition at line 269 of file SkScan_Antihair.cpp.

269 {
270 SkASSERT((SkLeftShift(a, 16) >> 16) == a);
271 SkASSERT(b != 0);
272 return SkLeftShift(a, 16) / b;
273}
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition: SkMath.h:37

◆ FDot8Ceil()

static int FDot8Ceil ( FDot8  x)
inlinestatic

Definition at line 851 of file SkScan_Antihair.cpp.

851 {
852 return (x + 0xFF) >> 8;
853}

◆ FDot8Floor()

static int FDot8Floor ( FDot8  x)
inlinestatic

Definition at line 847 of file SkScan_Antihair.cpp.

847 {
848 return x >> 8;
849}

◆ fillcheckrect()

static void fillcheckrect ( int  L,
int  T,
int  R,
int  B,
SkBlitter blitter 
)
static

Definition at line 837 of file SkScan_Antihair.cpp.

837 {
838 if (L < R && T < B) {
839 blitter->blitRect(L, T, R - L, B - T);
840 }
841}

◆ inner_scanline()

static void inner_scanline ( FDot8  L,
int  top,
FDot8  R,
U8CPU  alpha,
SkBlitter blitter 
)
static

Definition at line 862 of file SkScan_Antihair.cpp.

863 {
864 SkASSERT(L < R);
865
866 if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel
867 FDot8 widClamp = R - L;
868 // border case clamp 256 to 255 instead of going through call_hline_blitter
869 // see skbug/4406
870 widClamp = widClamp - (widClamp >> 8);
871 blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, widClamp));
872 return;
873 }
874
875 int left = L >> 8;
876 if (L & 0xFF) {
877 blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
878 left += 1;
879 }
880
881 int rite = R >> 8;
882 int width = rite - left;
883 if (width > 0) {
884 call_hline_blitter(blitter, left, top, width, alpha);
885 }
886
887 if (R & 0xFF) {
888 blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
889 }
890}
int FDot8
static U8CPU InvAlphaMul(U8CPU a, U8CPU b)

◆ innerstrokedot8()

static void innerstrokedot8 ( FDot8  L,
FDot8  T,
FDot8  R,
FDot8  B,
SkBlitter blitter 
)
static

Definition at line 892 of file SkScan_Antihair.cpp.

893 {
894 SkASSERT(L < R && T < B);
895
896 int top = T >> 8;
897 if (top == ((B - 1) >> 8)) { // just one scanline high
898 // We want the inverse of B-T, since we're the inner-stroke
899 int alpha = 256 - (B - T);
900 if (alpha) {
901 inner_scanline(L, top, R, alpha, blitter);
902 }
903 return;
904 }
905
906 if (T & 0xFF) {
907 inner_scanline(L, top, R, T & 0xFF, blitter);
908 top += 1;
909 }
910
911 int bot = B >> 8;
912 int height = bot - top;
913 if (height > 0) {
914 if (L & 0xFF) {
915 blitter->blitV(L >> 8, top, height, L & 0xFF);
916 }
917 if (R & 0xFF) {
918 blitter->blitV(R >> 8, top, height, ~R & 0xFF);
919 }
920 }
921
922 if (B & 0xFF) {
923 inner_scanline(L, bot, R, ~B & 0xFF, blitter);
924 }
925}
static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter *blitter)

◆ InvAlphaMul()

static U8CPU InvAlphaMul ( U8CPU  a,
U8CPU  b 
)
inlinestatic

Definition at line 856 of file SkScan_Antihair.cpp.

856 {
857 // need precise rounding (not just SkAlphaMul) so that values like
858 // a=228, b=252 don't overflow the result
859 return SkToU8(a + b - SkAlphaMulRound(a, b));
860}
#define SkAlphaMulRound(a, b)
constexpr uint8_t SkToU8(S x)
Definition: SkTo.h:22

◆ SkFixedToFDot8()

static FDot8 SkFixedToFDot8 ( SkFixed  x)
inlinestatic

Definition at line 637 of file SkScan_Antihair.cpp.

637 {
638 return (x + 0x80) >> 8;
639}

◆ SkScalarToFDot8()

static FDot8 SkScalarToFDot8 ( SkScalar  x)
inlinestatic

Definition at line 843 of file SkScan_Antihair.cpp.

843 {
844 return (int)(x * 256);
845}

◆ SmallDot6Scale()

static int SmallDot6Scale ( int  value,
int  dot6 
)
inlinestatic

Definition at line 46 of file SkScan_Antihair.cpp.

46 {
47 SkASSERT((int16_t)value == value);
48 SkASSERT((unsigned)dot6 <= 64);
49 return (value * dot6) >> 6;
50}
uint8_t value