96 *alpha = std::min(0xFF, *alpha + delta);
110 SkDEBUGFAIL(
"Please call real blitter's blitAntiH instead.");
114 SkDEBUGFAIL(
"Please call real blitter's blitV instead.");
118 SkDEBUGFAIL(
"Please call real blitter's blitH instead.");
122 SkDEBUGFAIL(
"Please call real blitter's blitRect instead.");
127 SkDEBUGFAIL(
"Please call real blitter's blitAntiRect instead.");
150 return forceRealBlitter ? fRealBlitter :
this;
171 int width = bounds.width();
172 if (
width > MaskAdditiveBlitter::kMAX_WIDTH) {
177 int64_t storage = rb * bounds.height();
179 return (
width <= MaskAdditiveBlitter::kMAX_WIDTH) &&
180 (storage <= MaskAdditiveBlitter::kMAX_STORAGE);
194 static const int kMAX_WIDTH = 32;
195 static const int kMAX_STORAGE = 1024;
201 uint32_t fStorage[(kMAX_STORAGE >> 2) + 2];
211 : fRealBlitter(realBlitter)
212 , fMask((uint8_t*)fStorage + 1, ir, ir.
width(),
SkMask::kA8_Format)
229 SK_ABORT(
"Don't use this; directly add alphas to the mask.");
239 uint8_t* row = this->
getRow(y);
240 for (
int i = 0; i <
width; ++i) {
252 uint8_t* row = this->
getRow(y);
253 for (
int i = 0; i <
height; ++i) {
263 uint8_t* row = this->
getRow(y);
264 for (
int i = 0; i <
height; ++i) {
265 memset(row +
x, 0xFF,
width);
332 const size_t kRunsSz = this->
getRunsSz();
378 sectBounds = clipBounds;
380 if (!sectBounds.
intersect(ir, clipBounds)) {
411 len = std::min(len,
fWidth -
x);
419 for (
int i = 0; i < len; i +=
fRuns.
fRuns[
x + i]) {
426 for (
int i = 0; i < len; ++i) {
439 if (this->
check(x, 1)) {
481 len = std::min(len,
fWidth -
x);
489 for (
int i = 0; i < len; i +=
fRuns.
fRuns[
x + i]) {
496 for (
int i = 0; i < len; ++i) {
537 return SkTo<SkAlpha>(area >> 8);
550 SkFixed area = (
a >> 11) * (
a >> 11) * (
b >> 11);
554 return SkTo<SkAlpha>(area >> 8);
556 return SkTo<SkAlpha>((area >> 8) & 0xFF);
565 return (alpha * fullAlpha) >> 8;
585 return (std::max(l1, l2) + std::min(r1, r2)) / 2;
606 SkFixed alpha16 = firstH + (dY >> 1);
607 for (
int i = 1; i <
R - 1; ++i) {
608 alphas[i] = alpha16 >> 8;
633 SkFixed alpha16 = lastH + (dY >> 1);
634 for (
int i =
R - 2; i > 0; i--) {
635 alphas[i] = (alpha16 >> 8) & 0xFF;
651 bool needSafeCheck) {
653 if (fullAlpha == 0xFF && !noRealBlitter) {
655 }
else if (needSafeCheck) {
661 if (fullAlpha == 0xFF && !noRealBlitter) {
678 bool needSafeCheck) {
688 if (fullAlpha == 0xFF && !noRealBlitter) {
705 bool needSafeCheck) {
707 for (
int i = 0; i < len; ++i) {
715 if (fullAlpha == 0xFF && !noRealBlitter) {
735 bool needSafeCheck) {
753 const int kQuickLen = 31;
754 alignas(2)
char quickMemory[(
sizeof(
SkAlpha) * 2 +
sizeof(int16_t)) * (kQuickLen + 1)];
757 if (len <= kQuickLen) {
758 alphas = (
SkAlpha*)quickMemory;
760 alphas =
new SkAlpha[(len + 1) * (
sizeof(
SkAlpha) * 2 +
sizeof(int16_t))];
763 SkAlpha* tempAlphas = alphas + len + 1;
764 int16_t* runs = (int16_t*)(alphas + (len + 1) * 2);
766 for (
int i = 0; i < len; ++i) {
768 alphas[i] = fullAlpha;
776 SkFixed second = ll - ul - first;
779 alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0;
780 alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0;
784 for (
int i = uL; i < lL; ++i) {
785 if (alphas[i - L] > tempAlphas[i - L]) {
786 alphas[i - L] -= tempAlphas[i - L];
797 SkFixed second = lr - ur - first;
800 alphas[len - 2] = alphas[len - 2] > a1 ? alphas[len - 2] - a1 : 0;
801 alphas[len - 1] = alphas[len - 1] > a2 ? alphas[len - 1] - a2 : 0;
805 for (
int i = uR; i < lR; ++i) {
806 if (alphas[i - L] > tempAlphas[i - L]) {
807 alphas[i - L] -= tempAlphas[i - L];
815 for (
int i = 0; i < len; ++i) {
823 if (fullAlpha == 0xFF && !noRealBlitter) {
831 if (len > kQuickLen) {
847 bool noRealBlitter =
false,
848 bool needSafeCheck =
false) {
861 if (ul == ur && ll == lr) {
878 if (joinLeft <= joinRite) {
892 }
else if (len == 2) {
894 SkFixed second = ll - ul - first;
925 if (joinLeft < joinRite) {
949 }
else if (len == 2) {
951 SkFixed second = lr - ur - first;
998 int valuea =
a.fUpperY;
999 int valueb =
b.fUpperY;
1001 if (valuea == valueb) {
1006 if (valuea == valueb) {
1011 return valuea < valueb;
1018 for (
int i = 1; i <
count; ++i) {
1019 list[i - 1]->
fNext = list[i];
1020 list[i]->
fPrev = list[i - 1];
1023 *last = list[
count - 1];
1072 if (leftE->
fLowerY + SK_Fixed1 < riteE->fLowerY) {
1080 if (nextCurrE->
fUpperY >= stop_y << 16) {
1085 std::swap(currE, nextCurrE);
1141 if (leftE->
fX > riteE->
fX || (leftE->
fX == riteE->
fX && leftE->
fDX > riteE->
fDX)) {
1142 std::swap(leftE, riteE);
1149 local_bot_fixed = std::min(local_bot_fixed,
SkIntToFixed(stop_y));
1153 SkFixed rite = std::min(riteBound, riteE->
fX);
1155 if (0 == (dLeft | dRite)) {
1164 if (fullTop > fullBot) {
1169 if (fullRite >= fullLeft) {
1170 if (partialTop > 0) {
1171 if (partialLeft > 0) {
1177 fullLeft, fullTop - 1, fullRite - fullLeft,
fixed_to_alpha(partialTop));
1178 if (partialRite > 0) {
1187 if (fullBot > fullTop &&
1194 fullRite - fullLeft,
1200 if (partialBot > 0) {
1201 if (partialLeft > 0) {
1207 fullLeft, fullBot, fullRite - fullLeft,
fixed_to_alpha(partialBot));
1208 if (partialRite > 0) {
1221 if (partialTop > 0) {
1228 if (fullBot > fullTop) {
1232 if (partialBot > 0) {
1241 y = local_bot_fixed;
1247 const SkFixed kSnapHalf = kSnapDigit >> 1;
1248 const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1));
1267 if ((
int)(
y & 0xFFFF0000) !=
y) {
1273 SkASSERT((
left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1274 (nextLeft & kSnapMask) >= leftBound &&
1275 (nextRite & kSnapMask) <= riteBound);
1280 nextLeft & kSnapMask,
1281 nextRite & kSnapMask,
1299 SkASSERT((
left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1300 (nextLeft & kSnapMask) >= leftBound &&
1301 (nextRite & kSnapMask) <= riteBound);
1306 nextLeft & kSnapMask,
1307 nextRite & kSnapMask,
1330 SkFixed nextRite = std::min(rite +
SkFixedMul(dRite, dY), riteBound + kSnapHalf);
1331 SkASSERT((
left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1332 (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound);
1337 nextLeft & kSnapMask,
1338 nextRite & kSnapMask,
1347 y = local_bot_fixed;
1354 leftE->
fY = riteE->
fY =
y;
1361 *nextNextY =
y > nextY &&
y < *nextNextY ?
y : *nextNextY;
1376 if (
prev->fX <= newEdge->
fX) {
1380 newEdge = newEdge->
fNext;
1391 if (
start->fNext == newEdge) {
1395 if (after->
fX >= newEdge->
fX) {
1475 std::max(leftE->
fSavedX, leftClip),
1476 std::min(riteE->
fSavedX, rightClip),
1477 std::max(lowerLeft, leftClip),
1478 std::min(lowerRite, rightClip),
1496 bool isIntegralNextY,
1530 riteE->
goY(nextY, yShift);
1532 if (isIntegralNextY || leftEnds || riteEnds) {
1557 bool skipIntersect) {
1558 prevHead->
fX = prevHead->
fUpperX = leftClip;
1559 nextTail->
fX = nextTail->
fUpperX = rightClip;
1597 bool in_interval = isInverse;
1600 bool isIntegralNextY = (nextY & (
SK_Fixed1 - 1)) == 0;
1605 bool leftEnds =
false;
1634 bool noRealBlitter = forceRLE;
1641 bool prev_in_interval = in_interval;
1642 in_interval = !(
w & windingMask) == isInverse;
1644 bool isLeft = in_interval && !prev_in_interval;
1645 bool isRite = !in_interval && prev_in_interval;
1646 bool currEnds = currE->
fLowerY == nextY;
1649 if (currE->
fRiteE && !isLeft) {
1664 if (leftE->
fRiteE == currE && !isRite) {
1701 currE->
goY(nextY, yShift);
1702 SkFixed nextLeft = std::max(leftClip, leftE->
fX);
1703 rite = std::min(rightClip, rite);
1704 SkFixed nextRite = std::min(rightClip, currE->
fX);
1717 noRealBlitter || (fullAlpha == 0xFF &&
1725 left = std::max(currE->
fX, leftClip);
1726 leftDY = currE->
fDY;
1728 leftEnds = leftE->
fLowerY == nextY;
1730 currE->
goY(nextY, yShift);
1736 while (currE->
fLowerY <= nextY) {
1755 if (currE->
fLowerY <= nextY) {
1763 if (leftE->
fRiteE == currE && useDeferred) {
1780 if (!skipIntersect) {
1813 std::max(leftClip, leftE->
fX),
1820 noRealBlitter || (fullAlpha == 0xFF &&
1845 bool pathContainedInClip,
1851 int count = builder.buildEdges(path, pathContainedInClip ?
nullptr : &clipRect);
1856 if (path.isInverseFillType()) {
1863 if (rect.fTop < start_y) {
1864 rect.fTop = start_y;
1866 if (rect.fBottom > stop_y) {
1867 rect.fBottom = stop_y;
1869 if (!rect.isEmpty()) {
1871 rect.fLeft, rect.fTop, rect.width(), rect.height());
1881 headEdge.
fRiteE =
nullptr;
1882 headEdge.
fPrev =
nullptr;
1883 headEdge.
fNext = edge;
1889 edge->
fPrev = &headEdge;
1891 tailEdge.
fRiteE =
nullptr;
1892 tailEdge.
fPrev = last;
1893 tailEdge.
fNext =
nullptr;
1899 last->
fNext = &tailEdge;
1903 if (!pathContainedInClip && start_y < clipRect.fTop) {
1904 start_y = clipRect.fTop;
1906 if (!pathContainedInClip && stop_y > clipRect.fBottom) {
1907 stop_y = clipRect.fBottom;
1916 path.getBounds().roundOut(&ir);
1921 if (!path.isInverseFillType() && path.isConvex() &&
count >= 2) {
1923 &headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask);
1932 bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2;
1954 if (!path.isRect(&rect)) {
1960 SkIRect bounds = rect.roundOut();
1961 if (bounds.width() < 3) {
1968void SkScan::AAAFillPath(
const SkPath& path,
1973 bool containedInClip = clipBounds.
contains(ir);
1974 bool isInverse =
path.isInverseFillType();
1997 }
else if (!isInverse &&
path.isConvex()) {
static float next(float f)
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
static constexpr T SkAlign4(T x)
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
#define SkFixedCeilToInt(x)
static SkFixed SkFixedCeilToFixed(SkFixed x)
#define SkFixedFloorToInt(x)
#define SkFixedRoundToInt(x)
static SkFixed SkFixedFloorToFixed(SkFixed x)
static SkFixed SkFixedMul(SkFixed a, SkFixed b)
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
static constexpr int32_t SK_MinS32
static constexpr int32_t SK_MaxS32
static bool SkPathFillType_IsInverse(SkPathFillType ft)
static bool SkPathFillType_IsEvenOdd(SkPathFillType ft)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static int32_t SkAbs32(int32_t value)
static void remove_edge(EdgeType *edge)
void backward_insert_edge_based_on_x(EdgeType *edge)
static void insert_edge_after(EdgeType *edge, EdgeType *afterMe)
EdgeType * backward_insert_start(EdgeType *prev, SkFixed x)
static void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed *nextNextY)
static void check_intersection(const SkAnalyticEdge *edge, SkFixed nextY, SkFixed *nextNextY)
static SkFixed approximate_intersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2)
static void deferred_blit(SkAnalyticEdge *leftE, SkAnalyticEdge *riteE, SkFixed left, SkFixed leftDY, SkFixed y, SkFixed nextY, bool isIntegralNextY, bool leftEnds, bool riteEnds, AdditiveBlitter *blitter, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, SkFixed leftClip, SkFixed rightClip, int yShift)
static SkAlpha trapezoid_to_alpha(SkFixed l1, SkFixed l2)
static SkAlpha partial_triangle_to_alpha(SkFixed a, SkFixed b)
static void blit_single_alpha(AdditiveBlitter *blitter, int y, int x, SkAlpha alpha, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static void blit_two_alphas(AdditiveBlitter *blitter, int y, int x, SkAlpha a1, SkAlpha a2, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static void blit_aaa_trapezoid_row(AdditiveBlitter *blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static bool operator<(const SkAnalyticEdge &a, const SkAnalyticEdge &b)
static void blit_trapezoid_row(AdditiveBlitter *blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter=false, bool needSafeCheck=false)
static void add_alpha(SkAlpha *alpha, SkAlpha delta)
static SkAlpha fixed_to_alpha(SkFixed f)
static void blit_saved_trapezoid(SkAnalyticEdge *leftE, SkFixed lowerY, SkFixed lowerLeft, SkFixed lowerRite, AdditiveBlitter *blitter, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, SkFixed leftClip, SkFixed rightClip)
static bool is_smooth_enough(SkAnalyticEdge *thisEdge, SkAnalyticEdge *nextEdge, int stop_y)
static bool try_blit_fat_anti_rect(SkBlitter *blitter, const SkPath &path, const SkIRect &clip)
static void aaa_walk_convex_edges(SkAnalyticEdge *prevHead, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, bool isUsingMask)
static void safely_add_alpha(SkAlpha *alpha, SkAlpha delta)
static void aaa_fill_path(const SkPath &path, const SkIRect &clipRect, AdditiveBlitter *blitter, int start_y, int stop_y, bool pathContainedInClip, bool isUsingMask, bool forceRLE)
static void compute_alpha_below_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
static void insert_new_edges(SkAnalyticEdge *newEdge, SkFixed y, SkFixed *nextNextY)
static void aaa_walk_edges(SkAnalyticEdge *prevHead, SkAnalyticEdge *nextTail, SkPathFillType fillType, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftClip, SkFixed rightClip, bool isUsingMask, bool forceRLE, bool useDeferred, bool skipIntersect)
static bool edges_too_close(SkAnalyticEdge *prev, SkAnalyticEdge *next, SkFixed lowerY)
static void compute_alpha_above_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
static void blit_full_alpha(AdditiveBlitter *blitter, int y, int x, int len, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight)
static SkAnalyticEdge * sort_edges(SkAnalyticEdge *list[], int count, SkAnalyticEdge **last)
#define validate_edges_for_y(edge, curr_y)
#define validate_sort(edge)
void SkTQSort(T *begin, T *end, const C &lessThan)
constexpr uint8_t SkToU8(S x)
void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override
virtual void blitAntiH(int x, int y, const SkAlpha alpha)=0
virtual void flush_if_y_changed(SkFixed y, SkFixed nextY)=0
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len)=0
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
~AdditiveBlitter() override
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
virtual SkBlitter * getRealBlitter(bool forceRealBlitter=false)=0
virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha)=0
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
static bool CanHandleRect(const SkIRect &bounds)
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
~MaskAdditiveBlitter() override
void flush_if_y_changed(SkFixed y, SkFixed nextY) override
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
SkBlitter * getRealBlitter(bool forceRealBlitter) override
MaskAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
SkAlpha snapAlpha(SkAlpha alpha)
void flush_if_y_changed(SkFixed y, SkFixed nextY) override
RunBasedAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
SkBlitter * getRealBlitter(bool forceRealBlitter) override
bool check(int x, int width) const
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
~RunBasedAdditiveBlitter() override
SafeRLEAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
void reset(int width)
Reinitialize for a new scanline.
SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue, int offsetX)
static SkAlpha CatchOverflow(int alpha)
void blitFatAntiRect(const SkRect &rect)
virtual void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)
virtual int requestRowsPreserved() const
virtual void blitMask(const SkMask &, const SkIRect &clip)
virtual void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
virtual void * allocBlitMemory(size_t sz)
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
virtual void blitV(int x, int y, int height, SkAlpha alpha)
Blit a vertical run of pixels with a constant alpha value.
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
bool updateCubic(bool sortY=true)
static const int kDefaultAccuracy
bool update(SkFixed last_y, bool sortY=true)
void saveXY(SkFixed x, SkFixed y, SkFixed dY)
bool intersect(const SkIRect &r)
int32_t fBottom
larger y-axis bounds
constexpr int32_t top() const
constexpr int32_t height() const
constexpr int32_t right() const
int32_t fTop
smaller y-axis bounds
constexpr int32_t width() const
int32_t fLeft
smaller x-axis bounds
constexpr int32_t left() const
bool contains(int32_t x, int32_t y) const
int32_t fRight
larger x-axis bounds
static SkRect Make(const SkISize &size)