Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Functions
SkScan_AAAPath.cpp File Reference
#include "include/core/SkColor.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkRect.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkAssert.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/base/SkTSort.h"
#include "src/core/SkAlphaRuns.h"
#include "src/core/SkAnalyticEdge.h"
#include "src/core/SkBlitter.h"
#include "src/core/SkEdge.h"
#include "src/core/SkEdgeBuilder.h"
#include "src/core/SkMask.h"
#include "src/core/SkScan.h"
#include "src/core/SkScanPriv.h"
#include <algorithm>
#include <cstdint>
#include <cstring>

Go to the source code of this file.

Classes

class  AdditiveBlitter
 
class  MaskAdditiveBlitter
 
class  RunBasedAdditiveBlitter
 
class  SafeRLEAdditiveBlitter
 

Functions

static void add_alpha (SkAlpha *alpha, SkAlpha delta)
 
static void safely_add_alpha (SkAlpha *alpha, SkAlpha delta)
 
static SkAlpha trapezoid_to_alpha (SkFixed l1, SkFixed l2)
 
static SkAlpha partial_triangle_to_alpha (SkFixed a, SkFixed b)
 
static SkAlpha get_partial_alpha (SkAlpha alpha, SkFixed partialHeight)
 
static SkAlpha get_partial_alpha (SkAlpha alpha, SkAlpha fullAlpha)
 
static SkAlpha fixed_to_alpha (SkFixed f)
 
static SkFixed approximate_intersection (SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2)
 
static void compute_alpha_above_line (SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
 
static void compute_alpha_below_line (SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
 
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_full_alpha (AdditiveBlitter *blitter, int y, int x, int len, 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 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 bool operator< (const SkAnalyticEdge &a, const SkAnalyticEdge &b)
 
static SkAnalyticEdgesort_edges (SkAnalyticEdge *list[], int count, SkAnalyticEdge **last)
 
static void validate_sort (const SkAnalyticEdge *edge)
 
static bool is_smooth_enough (SkAnalyticEdge *thisEdge, SkAnalyticEdge *nextEdge, int stop_y)
 
static bool is_smooth_enough (SkAnalyticEdge *leftE, SkAnalyticEdge *riteE, SkAnalyticEdge *currE, int stop_y)
 
static void aaa_walk_convex_edges (SkAnalyticEdge *prevHead, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, bool isUsingMask)
 
static void update_next_next_y (SkFixed y, SkFixed nextY, SkFixed *nextNextY)
 
static void check_intersection (const SkAnalyticEdge *edge, SkFixed nextY, SkFixed *nextNextY)
 
static void insert_new_edges (SkAnalyticEdge *newEdge, SkFixed y, SkFixed *nextNextY)
 
static void validate_edges_for_y (const SkAnalyticEdge *edge, SkFixed y)
 
static bool edges_too_close (SkAnalyticEdge *prev, SkAnalyticEdge *next, SkFixed lowerY)
 
static bool edges_too_close (int prevRite, SkFixed ul, SkFixed ll)
 
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 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 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 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 bool try_blit_fat_anti_rect (SkBlitter *blitter, const SkPath &path, const SkIRect &clip)
 

Function Documentation

◆ aaa_fill_path()

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

Definition at line 1840 of file SkScan_AAAPath.cpp.

1847 { // forceRLE implies that SkAAClip is calling us
1848 SkASSERT(blitter);
1849
1851 int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipRect);
1852 SkAnalyticEdge** list = builder.analyticEdgeList();
1853
1855 if (0 == count) {
1856 if (path.isInverseFillType()) {
1857 /*
1858 * Since we are in inverse-fill, our caller has already drawn above
1859 * our top (start_y) and will draw below our bottom (stop_y). Thus
1860 * we need to restrict our drawing to the intersection of the clip
1861 * and those two limits.
1862 */
1863 if (rect.fTop < start_y) {
1864 rect.fTop = start_y;
1865 }
1866 if (rect.fBottom > stop_y) {
1867 rect.fBottom = stop_y;
1868 }
1869 if (!rect.isEmpty()) {
1870 blitter->getRealBlitter()->blitRect(
1871 rect.fLeft, rect.fTop, rect.width(), rect.height());
1872 }
1873 }
1874 return;
1875 }
1876
1877 SkAnalyticEdge headEdge, tailEdge, *last;
1878 // this returns the first and last edge after they're sorted into a dlink list
1879 SkAnalyticEdge* edge = sort_edges(list, count, &last);
1880
1881 headEdge.fRiteE = nullptr;
1882 headEdge.fPrev = nullptr;
1883 headEdge.fNext = edge;
1884 headEdge.fUpperY = headEdge.fLowerY = SK_MinS32;
1885 headEdge.fX = SK_MinS32;
1886 headEdge.fDX = 0;
1887 headEdge.fDY = SK_MaxS32;
1888 headEdge.fUpperX = SK_MinS32;
1889 edge->fPrev = &headEdge;
1890
1891 tailEdge.fRiteE = nullptr;
1892 tailEdge.fPrev = last;
1893 tailEdge.fNext = nullptr;
1894 tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32;
1895 tailEdge.fX = SK_MaxS32;
1896 tailEdge.fDX = 0;
1897 tailEdge.fDY = SK_MaxS32;
1898 tailEdge.fUpperX = SK_MaxS32;
1899 last->fNext = &tailEdge;
1900
1901 // now edge is the head of the sorted linklist
1902
1903 if (!pathContainedInClip && start_y < clipRect.fTop) {
1904 start_y = clipRect.fTop;
1905 }
1906 if (!pathContainedInClip && stop_y > clipRect.fBottom) {
1907 stop_y = clipRect.fBottom;
1908 }
1909
1910 SkFixed leftBound = SkIntToFixed(rect.fLeft);
1911 SkFixed rightBound = SkIntToFixed(rect.fRight);
1912 if (isUsingMask) {
1913 // If we're using mask, then we have to limit the bound within the path bounds.
1914 // Otherwise, the edge drift may access an invalid address inside the mask.
1915 SkIRect ir;
1916 path.getBounds().roundOut(&ir);
1917 leftBound = std::max(leftBound, SkIntToFixed(ir.fLeft));
1918 rightBound = std::min(rightBound, SkIntToFixed(ir.fRight));
1919 }
1920
1921 if (!path.isInverseFillType() && path.isConvex() && count >= 2) {
1923 &headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask);
1924 } else {
1925 // Only use deferred blitting if there are many edges.
1926 bool useDeferred =
1927 count >
1928 (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4;
1929
1930 // We skip intersection computation if there are many points which probably already
1931 // give us enough fractional scan lines.
1932 bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2;
1933
1934 aaa_walk_edges(&headEdge,
1935 &tailEdge,
1936 path.getFillType(),
1937 blitter,
1938 start_y,
1939 stop_y,
1940 leftBound,
1941 rightBound,
1942 isUsingMask,
1943 forceRLE,
1944 useDeferred,
1945 skipIntersect);
1946 }
1947}
int count
#define SkASSERT(cond)
Definition SkAssert.h:116
int32_t SkFixed
Definition SkFixed.h:25
#define SkIntToFixed(n)
Definition SkFixed.h:73
#define SkFixedFloorToInt(x)
Definition SkFixed.h:78
static constexpr int32_t SK_MinS32
Definition SkMath.h:22
static constexpr int32_t SK_MaxS32
Definition SkMath.h:21
static void aaa_walk_convex_edges(SkAnalyticEdge *prevHead, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, bool isUsingMask)
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 SkAnalyticEdge * sort_edges(SkAnalyticEdge *list[], int count, SkAnalyticEdge **last)
virtual SkBlitter * getRealBlitter(bool forceRealBlitter=false)=0
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
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
Definition switches.h:57
SkAnalyticEdge * fRiteE
SkAnalyticEdge * fNext
SkAnalyticEdge * fPrev
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35

◆ aaa_walk_convex_edges()

static void aaa_walk_convex_edges ( SkAnalyticEdge prevHead,
AdditiveBlitter blitter,
int  start_y,
int  stop_y,
SkFixed  leftBound,
SkFixed  riteBound,
bool  isUsingMask 
)
static

Definition at line 1090 of file SkScan_AAAPath.cpp.

1096 {
1097 validate_sort((SkAnalyticEdge*)prevHead->fNext);
1098
1099 SkAnalyticEdge* leftE = (SkAnalyticEdge*)prevHead->fNext;
1100 SkAnalyticEdge* riteE = (SkAnalyticEdge*)leftE->fNext;
1101 SkAnalyticEdge* currE = (SkAnalyticEdge*)riteE->fNext;
1102
1103 SkFixed y = std::max(leftE->fUpperY, riteE->fUpperY);
1104
1105 for (;;) {
1106 // We have to check fLowerY first because some edges might be alone (e.g., there's only
1107 // a left edge but no right edge in a given y scan line) due to precision limit.
1108 while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
1109 if (!leftE->update(y)) {
1110 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
1111 goto END_WALK;
1112 }
1113 leftE = currE;
1114 currE = (SkAnalyticEdge*)currE->fNext;
1115 }
1116 }
1117 while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
1118 if (!riteE->update(y)) {
1119 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
1120 goto END_WALK;
1121 }
1122 riteE = currE;
1123 currE = (SkAnalyticEdge*)currE->fNext;
1124 }
1125 }
1126
1127 SkASSERT(leftE);
1128 SkASSERT(riteE);
1129
1130 // check our bottom clip
1131 if (SkFixedFloorToInt(y) >= stop_y) {
1132 break;
1133 }
1134
1135 SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y);
1136 SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y);
1137
1138 leftE->goY(y);
1139 riteE->goY(y);
1140
1141 if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && leftE->fDX > riteE->fDX)) {
1142 std::swap(leftE, riteE);
1143 }
1144
1145 SkFixed local_bot_fixed = std::min(leftE->fLowerY, riteE->fLowerY);
1146 if (is_smooth_enough(leftE, riteE, currE, stop_y)) {
1147 local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed);
1148 }
1149 local_bot_fixed = std::min(local_bot_fixed, SkIntToFixed(stop_y));
1150
1151 SkFixed left = std::max(leftBound, leftE->fX);
1152 SkFixed dLeft = leftE->fDX;
1153 SkFixed rite = std::min(riteBound, riteE->fX);
1154 SkFixed dRite = riteE->fDX;
1155 if (0 == (dLeft | dRite)) {
1156 int fullLeft = SkFixedCeilToInt(left);
1157 int fullRite = SkFixedFloorToInt(rite);
1158 SkFixed partialLeft = SkIntToFixed(fullLeft) - left;
1159 SkFixed partialRite = rite - SkIntToFixed(fullRite);
1160 int fullTop = SkFixedCeilToInt(y);
1161 int fullBot = SkFixedFloorToInt(local_bot_fixed);
1162 SkFixed partialTop = SkIntToFixed(fullTop) - y;
1163 SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot);
1164 if (fullTop > fullBot) { // The rectangle is within one pixel height...
1165 partialTop -= (SK_Fixed1 - partialBot);
1166 partialBot = 0;
1167 }
1168
1169 if (fullRite >= fullLeft) {
1170 if (partialTop > 0) { // blit first partial row
1171 if (partialLeft > 0) {
1172 blitter->blitAntiH(fullLeft - 1,
1173 fullTop - 1,
1174 fixed_to_alpha(SkFixedMul(partialTop, partialLeft)));
1175 }
1176 blitter->blitAntiH(
1177 fullLeft, fullTop - 1, fullRite - fullLeft, fixed_to_alpha(partialTop));
1178 if (partialRite > 0) {
1179 blitter->blitAntiH(fullRite,
1180 fullTop - 1,
1181 fixed_to_alpha(SkFixedMul(partialTop, partialRite)));
1182 }
1183 blitter->flush_if_y_changed(y, y + partialTop);
1184 }
1185
1186 // Blit all full-height rows from fullTop to fullBot
1187 if (fullBot > fullTop &&
1188 // SkAAClip cannot handle the empty rect so check the non-emptiness here
1189 // (bug chromium:662800)
1190 (fullRite > fullLeft || fixed_to_alpha(partialLeft) > 0 ||
1191 fixed_to_alpha(partialRite) > 0)) {
1192 blitter->getRealBlitter()->blitAntiRect(fullLeft - 1,
1193 fullTop,
1194 fullRite - fullLeft,
1195 fullBot - fullTop,
1196 fixed_to_alpha(partialLeft),
1197 fixed_to_alpha(partialRite));
1198 }
1199
1200 if (partialBot > 0) { // blit last partial row
1201 if (partialLeft > 0) {
1202 blitter->blitAntiH(fullLeft - 1,
1203 fullBot,
1204 fixed_to_alpha(SkFixedMul(partialBot, partialLeft)));
1205 }
1206 blitter->blitAntiH(
1207 fullLeft, fullBot, fullRite - fullLeft, fixed_to_alpha(partialBot));
1208 if (partialRite > 0) {
1209 blitter->blitAntiH(fullRite,
1210 fullBot,
1211 fixed_to_alpha(SkFixedMul(partialBot, partialRite)));
1212 }
1213 }
1214 } else {
1215 // Normal conditions, this means left and rite are within the same pixel, but if
1216 // both left and rite were < leftBounds or > rightBounds, both edges are clipped and
1217 // we should not do any blitting (particularly since the negative width saturates to
1218 // full alpha).
1219 SkFixed width = rite - left;
1220 if (width > 0) {
1221 if (partialTop > 0) {
1222 blitter->blitAntiH(fullLeft - 1,
1223 fullTop - 1,
1224 1,
1225 fixed_to_alpha(SkFixedMul(partialTop, width)));
1226 blitter->flush_if_y_changed(y, y + partialTop);
1227 }
1228 if (fullBot > fullTop) {
1229 blitter->getRealBlitter()->blitV(
1230 fullLeft - 1, fullTop, fullBot - fullTop, fixed_to_alpha(width));
1231 }
1232 if (partialBot > 0) {
1233 blitter->blitAntiH(fullLeft - 1,
1234 fullBot,
1235 1,
1236 fixed_to_alpha(SkFixedMul(partialBot, width)));
1237 }
1238 }
1239 }
1240
1241 y = local_bot_fixed;
1242 } else {
1243 // The following constant are used to snap X
1244 // We snap X mainly for speedup (no tiny triangle) and
1245 // avoiding edge cases caused by precision errors
1246 const SkFixed kSnapDigit = SK_Fixed1 >> 4;
1247 const SkFixed kSnapHalf = kSnapDigit >> 1;
1248 const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1));
1249 left += kSnapHalf;
1250 rite += kSnapHalf; // For fast rounding
1251
1252 // Number of blit_trapezoid_row calls we'll have
1253 int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y);
1254
1255 // If we're using mask blitter, we advance the mask row in this function
1256 // to save some "if" condition checks.
1257 SkAlpha* maskRow = nullptr;
1258 if (isUsingMask) {
1259 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1260 }
1261
1262 // Instead of writing one loop that handles both partial-row blit_trapezoid_row
1263 // and full-row trapezoid_row together, we use the following 3-stage flow to
1264 // handle partial-row blit and full-row blit separately. It will save us much time
1265 // on changing y, left, and rite.
1266 if (count > 1) {
1267 if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top
1268 count--;
1269 SkFixed nextY = SkFixedCeilToFixed(y + 1);
1270 SkFixed dY = nextY - y;
1271 SkFixed nextLeft = left + SkFixedMul(dLeft, dY);
1272 SkFixed nextRite = rite + SkFixedMul(dRite, dY);
1273 SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1274 (nextLeft & kSnapMask) >= leftBound &&
1275 (nextRite & kSnapMask) <= riteBound);
1276 blit_trapezoid_row(blitter,
1277 y >> 16,
1278 left & kSnapMask,
1279 rite & kSnapMask,
1280 nextLeft & kSnapMask,
1281 nextRite & kSnapMask,
1282 leftE->fDY,
1283 riteE->fDY,
1284 get_partial_alpha(0xFF, dY),
1285 maskRow,
1286 isUsingMask);
1287 blitter->flush_if_y_changed(y, nextY);
1288 left = nextLeft;
1289 rite = nextRite;
1290 y = nextY;
1291 }
1292
1293 while (count > 1) { // Full rows in the middle
1294 count--;
1295 if (isUsingMask) {
1296 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1297 }
1298 SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite;
1299 SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1300 (nextLeft & kSnapMask) >= leftBound &&
1301 (nextRite & kSnapMask) <= riteBound);
1302 blit_trapezoid_row(blitter,
1303 y >> 16,
1304 left & kSnapMask,
1305 rite & kSnapMask,
1306 nextLeft & kSnapMask,
1307 nextRite & kSnapMask,
1308 leftE->fDY,
1309 riteE->fDY,
1310 0xFF,
1311 maskRow,
1312 isUsingMask);
1313 blitter->flush_if_y_changed(y, nextY);
1314 left = nextLeft;
1315 rite = nextRite;
1316 y = nextY;
1317 }
1318 }
1319
1320 if (isUsingMask) {
1321 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1322 }
1323
1324 SkFixed dY = local_bot_fixed - y; // partial-row on the bottom
1325 SkASSERT(dY <= SK_Fixed1);
1326 // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound.
1327 // Take them back into the bound here.
1328 // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound
1329 SkFixed nextLeft = std::max(left + SkFixedMul(dLeft, dY), leftBound + kSnapHalf);
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);
1333 blit_trapezoid_row(blitter,
1334 y >> 16,
1335 left & kSnapMask,
1336 rite & kSnapMask,
1337 nextLeft & kSnapMask,
1338 nextRite & kSnapMask,
1339 leftE->fDY,
1340 riteE->fDY,
1341 get_partial_alpha(0xFF, dY),
1342 maskRow,
1343 isUsingMask);
1344 blitter->flush_if_y_changed(y, local_bot_fixed);
1345 left = nextLeft;
1346 rite = nextRite;
1347 y = local_bot_fixed;
1348 left -= kSnapHalf;
1349 rite -= kSnapHalf;
1350 }
1351
1352 leftE->fX = left;
1353 riteE->fX = rite;
1354 leftE->fY = riteE->fY = y;
1355 }
1356
1357END_WALK:;
1358}
uint8_t SkAlpha
Definition SkColor.h:26
#define SkFixedCeilToInt(x)
Definition SkFixed.h:77
#define SK_Fixed1
Definition SkFixed.h:26
static SkFixed SkFixedCeilToFixed(SkFixed x)
Definition SkFixed.h:83
static SkFixed SkFixedMul(SkFixed a, SkFixed b)
Definition SkFixed.h:96
static bool left(const SkPoint &p0, const SkPoint &p1)
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 SkAlpha fixed_to_alpha(SkFixed f)
static bool is_smooth_enough(SkAnalyticEdge *thisEdge, SkAnalyticEdge *nextEdge, int stop_y)
static SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight)
#define validate_sort(edge)
virtual void flush_if_y_changed(SkFixed y, SkFixed nextY)=0
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len)=0
virtual void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
virtual void blitV(int x, int y, int height, SkAlpha alpha)
Blit a vertical run of pixels with a constant alpha value.
double y
int32_t width

◆ aaa_walk_edges()

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

Definition at line 1546 of file SkScan_AAAPath.cpp.

1557 {
1558 prevHead->fX = prevHead->fUpperX = leftClip;
1559 nextTail->fX = nextTail->fUpperX = rightClip;
1560 SkFixed y = std::max(prevHead->fNext->fUpperY, SkIntToFixed(start_y));
1561 SkFixed nextNextY = SK_MaxS32;
1562
1563 {
1564 SkAnalyticEdge* edge;
1565 for (edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) {
1566 edge->goY(y);
1567 update_next_next_y(edge->fLowerY, y, &nextNextY);
1568 }
1569 update_next_next_y(edge->fUpperY, y, &nextNextY);
1570 }
1571
1572 int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1;
1573 bool isInverse = SkPathFillType_IsInverse(fillType);
1574
1575 if (isInverse && SkIntToFixed(start_y) != y) {
1576 int width = SkFixedFloorToInt(rightClip - leftClip);
1577 if (SkFixedFloorToInt(y) != start_y) {
1578 blitter->getRealBlitter()->blitRect(
1579 SkFixedFloorToInt(leftClip), start_y, width, SkFixedFloorToInt(y) - start_y);
1580 start_y = SkFixedFloorToInt(y);
1581 }
1582 SkAlpha* maskRow =
1583 isUsingMask ? static_cast<MaskAdditiveBlitter*>(blitter)->getRow(start_y) : nullptr;
1584 blit_full_alpha(blitter,
1585 start_y,
1586 SkFixedFloorToInt(leftClip),
1587 width,
1588 fixed_to_alpha(y - SkIntToFixed(start_y)),
1589 maskRow,
1590 isUsingMask,
1591 false,
1592 false);
1593 }
1594
1595 while (true) {
1596 int w = 0;
1597 bool in_interval = isInverse;
1598 SkFixed prevX = prevHead->fX;
1599 SkFixed nextY = std::min(nextNextY, SkFixedCeilToFixed(y + 1));
1600 bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0;
1601 SkAnalyticEdge* currE = prevHead->fNext;
1602 SkAnalyticEdge* leftE = prevHead;
1603 SkFixed left = leftClip;
1604 SkFixed leftDY = 0;
1605 bool leftEnds = false;
1606 int prevRite = SkFixedFloorToInt(leftClip);
1607
1608 nextNextY = SK_MaxS32;
1609
1610 SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0);
1611 int yShift = 0;
1612 if ((nextY - y) & (SK_Fixed1 >> 2)) {
1613 yShift = 2;
1614 nextY = y + (SK_Fixed1 >> 2);
1615 } else if ((nextY - y) & (SK_Fixed1 >> 1)) {
1616 yShift = 1;
1617 SkASSERT(nextY == y + (SK_Fixed1 >> 1));
1618 }
1619
1620 SkAlpha fullAlpha = fixed_to_alpha(nextY - y);
1621
1622 // If we're using mask blitter, we advance the mask row in this function
1623 // to save some "if" condition checks.
1624 SkAlpha* maskRow = nullptr;
1625 if (isUsingMask) {
1626 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(SkFixedFloorToInt(y));
1627 }
1628
1629 SkASSERT(currE->fPrev == prevHead);
1630 validate_edges_for_y(currE, y);
1631
1632 // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement
1633 // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges)
1634 bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1);
1635
1636 while (currE->fUpperY <= y) {
1637 SkASSERT(currE->fLowerY >= nextY);
1638 SkASSERT(currE->fY == y);
1639
1640 w += currE->fWinding;
1641 bool prev_in_interval = in_interval;
1642 in_interval = !(w & windingMask) == isInverse;
1643
1644 bool isLeft = in_interval && !prev_in_interval;
1645 bool isRite = !in_interval && prev_in_interval;
1646 bool currEnds = currE->fLowerY == nextY;
1647
1648 if (useDeferred) {
1649 if (currE->fRiteE && !isLeft) {
1650 // currE is a left edge previously, but now it's not.
1651 // Blit the trapezoid between fSavedY and y.
1652 SkASSERT(currE->fRiteE->fY == y);
1654 y,
1655 currE->fX,
1656 currE->fRiteE->fX,
1657 blitter,
1658 maskRow,
1659 isUsingMask,
1660 noRealBlitter,
1661 leftClip,
1662 rightClip);
1663 }
1664 if (leftE->fRiteE == currE && !isRite) {
1665 // currE is a right edge previously, but now it's not.
1666 // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it
1667 // in the previous if clause). Hence we blit the trapezoid.
1669 y,
1670 left,
1671 currE->fX,
1672 blitter,
1673 maskRow,
1674 isUsingMask,
1675 noRealBlitter,
1676 leftClip,
1677 rightClip);
1678 }
1679 }
1680
1681 if (isRite) {
1682 if (useDeferred) {
1683 deferred_blit(leftE,
1684 currE,
1685 left,
1686 leftDY,
1687 y,
1688 nextY,
1689 isIntegralNextY,
1690 leftEnds,
1691 currEnds,
1692 blitter,
1693 maskRow,
1694 isUsingMask,
1695 noRealBlitter,
1696 leftClip,
1697 rightClip,
1698 yShift);
1699 } else {
1700 SkFixed rite = currE->fX;
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);
1706 blitter,
1707 y >> 16,
1708 left,
1709 rite,
1710 nextLeft,
1711 nextRite,
1712 leftDY,
1713 currE->fDY,
1714 fullAlpha,
1715 maskRow,
1716 isUsingMask,
1717 noRealBlitter || (fullAlpha == 0xFF &&
1718 (edges_too_close(prevRite, left, leftE->fX) ||
1719 edges_too_close(currE, currE->fNext, nextY))),
1720 true);
1721 prevRite = SkFixedCeilToInt(std::max(rite, currE->fX));
1722 }
1723 } else {
1724 if (isLeft) {
1725 left = std::max(currE->fX, leftClip);
1726 leftDY = currE->fDY;
1727 leftE = currE;
1728 leftEnds = leftE->fLowerY == nextY;
1729 }
1730 currE->goY(nextY, yShift);
1731 }
1732
1733 SkAnalyticEdge* next = currE->fNext;
1734 SkFixed newX;
1735
1736 while (currE->fLowerY <= nextY) {
1737 if (currE->fCurveCount < 0) {
1738 SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE;
1739 cubicEdge->keepContinuous();
1740 if (!cubicEdge->updateCubic()) {
1741 break;
1742 }
1743 } else if (currE->fCurveCount > 0) {
1745 quadEdge->keepContinuous();
1746 if (!quadEdge->updateQuadratic()) {
1747 break;
1748 }
1749 } else {
1750 break;
1751 }
1752 }
1753 SkASSERT(currE->fY == nextY);
1754
1755 if (currE->fLowerY <= nextY) {
1756 remove_edge(currE);
1757 } else {
1758 update_next_next_y(currE->fLowerY, nextY, &nextNextY);
1759 newX = currE->fX;
1760 SkASSERT(currE->fLowerY > nextY);
1761 if (newX < prevX) { // ripple currE backwards until it is x-sorted
1762 // If the crossing edge is a right edge, blit the saved trapezoid.
1763 if (leftE->fRiteE == currE && useDeferred) {
1764 SkASSERT(leftE->fY == nextY && currE->fY == nextY);
1766 nextY,
1767 leftE->fX,
1768 currE->fX,
1769 blitter,
1770 maskRow,
1771 isUsingMask,
1772 noRealBlitter,
1773 leftClip,
1774 rightClip);
1775 }
1777 } else {
1778 prevX = newX;
1779 }
1780 if (!skipIntersect) {
1781 check_intersection(currE, nextY, &nextNextY);
1782 }
1783 }
1784
1785 currE = next;
1786 SkASSERT(currE);
1787 }
1788
1789 // was our right-edge culled away?
1790 if (in_interval) {
1791 if (useDeferred) {
1792 deferred_blit(leftE,
1793 nextTail,
1794 left,
1795 leftDY,
1796 y,
1797 nextY,
1798 isIntegralNextY,
1799 leftEnds,
1800 false,
1801 blitter,
1802 maskRow,
1803 isUsingMask,
1804 noRealBlitter,
1805 leftClip,
1806 rightClip,
1807 yShift);
1808 } else {
1809 blit_trapezoid_row(blitter,
1810 y >> 16,
1811 left,
1812 rightClip,
1813 std::max(leftClip, leftE->fX),
1814 rightClip,
1815 leftDY,
1816 0,
1817 fullAlpha,
1818 maskRow,
1819 isUsingMask,
1820 noRealBlitter || (fullAlpha == 0xFF &&
1821 edges_too_close(leftE->fPrev, leftE, nextY)),
1822 true);
1823 }
1824 }
1825
1826 if (forceRLE) {
1827 ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY);
1828 }
1829
1830 y = nextY;
1831 if (y >= SkIntToFixed(stop_y)) {
1832 break;
1833 }
1834
1835 // now currE points to the first edge with a fUpperY larger than the previous y
1836 insert_new_edges(currE, y, &nextNextY);
1837 }
1838}
static float next(float f)
static bool SkPathFillType_IsInverse(SkPathFillType ft)
Definition SkPathTypes.h:26
static bool SkPathFillType_IsEvenOdd(SkPathFillType ft)
Definition SkPathTypes.h:22
static void remove_edge(EdgeType *edge)
Definition SkScanPriv.h:45
void backward_insert_edge_based_on_x(EdgeType *edge)
Definition SkScanPriv.h:59
static void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed *nextNextY)
static void check_intersection(const SkAnalyticEdge *edge, SkFixed nextY, SkFixed *nextNextY)
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 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 void insert_new_edges(SkAnalyticEdge *newEdge, SkFixed y, SkFixed *nextNextY)
static bool edges_too_close(SkAnalyticEdge *prev, SkAnalyticEdge *next, SkFixed lowerY)
static void blit_full_alpha(AdditiveBlitter *blitter, int y, int x, int len, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
#define validate_edges_for_y(edge, curr_y)
SkScalar w
bool updateCubic(bool sortY=true)
void goY(SkFixed y)

◆ add_alpha()

static void add_alpha ( SkAlpha alpha,
SkAlpha  delta 
)
static

Definition at line 90 of file SkScan_AAAPath.cpp.

90 {
91 SkASSERT(*alpha + delta <= 256);
92 *alpha = SkAlphaRuns::CatchOverflow(*alpha + delta);
93}
static SkAlpha CatchOverflow(int alpha)
Definition SkAlphaRuns.h:30

◆ approximate_intersection()

static SkFixed approximate_intersection ( SkFixed  l1,
SkFixed  r1,
SkFixed  l2,
SkFixed  r2 
)
static

Definition at line 578 of file SkScan_AAAPath.cpp.

578 {
579 if (l1 > r1) {
580 std::swap(l1, r1);
581 }
582 if (l2 > r2) {
583 std::swap(l2, r2);
584 }
585 return (std::max(l1, l2) + std::min(r1, r2)) / 2;
586}

◆ blit_aaa_trapezoid_row()

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

Definition at line 723 of file SkScan_AAAPath.cpp.

735 {
736 int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr);
737 int len = R - L;
738
739 if (len == 1) {
740 SkAlpha alpha = trapezoid_to_alpha(ur - ul, lr - ll);
741 blit_single_alpha(blitter,
742 y,
743 L,
744 alpha,
745 fullAlpha,
746 maskRow,
747 isUsingMask,
748 noRealBlitter,
749 needSafeCheck);
750 return;
751 }
752
753 const int kQuickLen = 31;
754 alignas(2) char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)];
755 SkAlpha* alphas;
756
757 if (len <= kQuickLen) {
758 alphas = (SkAlpha*)quickMemory;
759 } else {
760 alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))];
761 }
762
763 SkAlpha* tempAlphas = alphas + len + 1;
764 int16_t* runs = (int16_t*)(alphas + (len + 1) * 2);
765
766 for (int i = 0; i < len; ++i) {
767 runs[i] = 1;
768 alphas[i] = fullAlpha;
769 }
770 runs[len] = 0;
771
772 int uL = SkFixedFloorToInt(ul);
773 int lL = SkFixedCeilToInt(ll);
774 if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case
775 SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul;
776 SkFixed second = ll - ul - first;
777 SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, lDY);
778 SkAlpha a2 = partial_triangle_to_alpha(second, lDY);
779 alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0;
780 alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0;
781 } else {
783 tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL), lDY, fullAlpha);
784 for (int i = uL; i < lL; ++i) {
785 if (alphas[i - L] > tempAlphas[i - L]) {
786 alphas[i - L] -= tempAlphas[i - L];
787 } else {
788 alphas[i - L] = 0;
789 }
790 }
791 }
792
793 int uR = SkFixedFloorToInt(ur);
794 int lR = SkFixedCeilToInt(lr);
795 if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case
796 SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur;
797 SkFixed second = lr - ur - first;
798 SkAlpha a1 = partial_triangle_to_alpha(first, rDY);
799 SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, rDY);
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;
802 } else {
804 tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR), rDY, fullAlpha);
805 for (int i = uR; i < lR; ++i) {
806 if (alphas[i - L] > tempAlphas[i - L]) {
807 alphas[i - L] -= tempAlphas[i - L];
808 } else {
809 alphas[i - L] = 0;
810 }
811 }
812 }
813
814 if (isUsingMask) {
815 for (int i = 0; i < len; ++i) {
816 if (needSafeCheck) {
817 safely_add_alpha(&maskRow[L + i], alphas[i]);
818 } else {
819 add_alpha(&maskRow[L + i], alphas[i]);
820 }
821 }
822 } else {
823 if (fullAlpha == 0xFF && !noRealBlitter) {
824 // Real blitter is faster than RunBasedAdditiveBlitter
825 blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs);
826 } else {
827 blitter->blitAntiH(L, y, alphas, len);
828 }
829 }
830
831 if (len > kQuickLen) {
832 delete[] alphas;
833 }
834}
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 add_alpha(SkAlpha *alpha, SkAlpha delta)
static void safely_add_alpha(SkAlpha *alpha, SkAlpha delta)
static void compute_alpha_below_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
static void compute_alpha_above_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
#define R(r)

◆ blit_full_alpha()

static void blit_full_alpha ( AdditiveBlitter blitter,
int  y,
int  x,
int  len,
SkAlpha  fullAlpha,
SkAlpha maskRow,
bool  isUsingMask,
bool  noRealBlitter,
bool  needSafeCheck 
)
static

Definition at line 697 of file SkScan_AAAPath.cpp.

705 {
706 if (isUsingMask) {
707 for (int i = 0; i < len; ++i) {
708 if (needSafeCheck) {
709 safely_add_alpha(&maskRow[x + i], fullAlpha);
710 } else {
711 add_alpha(&maskRow[x + i], fullAlpha);
712 }
713 }
714 } else {
715 if (fullAlpha == 0xFF && !noRealBlitter) {
716 blitter->getRealBlitter()->blitH(x, y, len);
717 } else {
718 blitter->blitAntiH(x, y, len, fullAlpha);
719 }
720 }
721}
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
double x

◆ blit_saved_trapezoid()

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

Definition at line 1451 of file SkScan_AAAPath.cpp.

1460 {
1461 SkAnalyticEdge* riteE = leftE->fRiteE;
1462 SkASSERT(riteE);
1463 SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY);
1464 SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY));
1465 int y = SkFixedFloorToInt(leftE->fSavedY);
1466 // Instead of using fixed_to_alpha(lowerY - leftE->fSavedY), we use the following fullAlpha
1467 // to elimiate cumulative error: if there are many fractional y scan lines within the
1468 // same row, the former may accumulate the rounding error while the later won't.
1469 SkAlpha fullAlpha = fixed_to_alpha(lowerY - SkIntToFixed(y)) -
1471 // We need fSavedDY because the (quad or cubic) edge might be updated
1473 blitter,
1474 y,
1475 std::max(leftE->fSavedX, leftClip),
1476 std::min(riteE->fSavedX, rightClip),
1477 std::max(lowerLeft, leftClip),
1478 std::min(lowerRite, rightClip),
1479 leftE->fSavedDY,
1480 riteE->fSavedDY,
1481 fullAlpha,
1482 maskRow,
1483 isUsingMask,
1484 noRealBlitter || (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) ||
1485 edges_too_close(riteE, riteE->fNext, lowerY))),
1486 true);
1487 leftE->fRiteE = nullptr;
1488}

◆ blit_single_alpha()

static void blit_single_alpha ( AdditiveBlitter blitter,
int  y,
int  x,
SkAlpha  alpha,
SkAlpha  fullAlpha,
SkAlpha maskRow,
bool  isUsingMask,
bool  noRealBlitter,
bool  needSafeCheck 
)
static

Definition at line 643 of file SkScan_AAAPath.cpp.

651 {
652 if (isUsingMask) {
653 if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths
654 maskRow[x] = alpha;
655 } else if (needSafeCheck) {
656 safely_add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
657 } else {
658 add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
659 }
660 } else {
661 if (fullAlpha == 0xFF && !noRealBlitter) {
662 blitter->getRealBlitter()->blitV(x, y, 1, alpha);
663 } else {
664 blitter->blitAntiH(x, y, get_partial_alpha(alpha, fullAlpha));
665 }
666 }
667}

◆ blit_trapezoid_row()

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

Definition at line 836 of file SkScan_AAAPath.cpp.

848 {
849 SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value
850
851 if (ul > ur) {
852 return;
853 }
854
855 // Edge crosses. Approximate it. This should only happend due to precision limit,
856 // so the approximation could be very coarse.
857 if (ll > lr) {
858 ll = lr = approximate_intersection(ul, ll, ur, lr);
859 }
860
861 if (ul == ur && ll == lr) {
862 return; // empty trapzoid
863 }
864
865 // We're going to use the left line ul-ll and the rite line ur-lr
866 // to exclude the area that's not covered by the path.
867 // Swapping (ul, ll) or (ur, lr) won't affect that exclusion
868 // so we'll do that for simplicity.
869 if (ul > ll) {
870 std::swap(ul, ll);
871 }
872 if (ur > lr) {
873 std::swap(ur, lr);
874 }
875
876 SkFixed joinLeft = SkFixedCeilToFixed(ll);
877 SkFixed joinRite = SkFixedFloorToFixed(ur);
878 if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit
879 if (ul < joinLeft) {
880 int len = SkFixedCeilToInt(joinLeft - ul);
881 if (len == 1) {
882 SkAlpha alpha = trapezoid_to_alpha(joinLeft - ul, joinLeft - ll);
883 blit_single_alpha(blitter,
884 y,
885 ul >> 16,
886 alpha,
887 fullAlpha,
888 maskRow,
889 isUsingMask,
890 noRealBlitter,
891 needSafeCheck);
892 } else if (len == 2) {
893 SkFixed first = joinLeft - SK_Fixed1 - ul;
894 SkFixed second = ll - ul - first;
895 SkAlpha a1 = partial_triangle_to_alpha(first, lDY);
896 SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, lDY);
897 blit_two_alphas(blitter,
898 y,
899 ul >> 16,
900 a1,
901 a2,
902 fullAlpha,
903 maskRow,
904 isUsingMask,
905 noRealBlitter,
906 needSafeCheck);
907 } else {
909 y,
910 ul,
911 joinLeft,
912 ll,
913 joinLeft,
914 lDY,
915 SK_MaxS32,
916 fullAlpha,
917 maskRow,
918 isUsingMask,
919 noRealBlitter,
920 needSafeCheck);
921 }
922 }
923 // SkAAClip requires that we blit from left to right.
924 // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite]
925 if (joinLeft < joinRite) {
926 blit_full_alpha(blitter,
927 y,
928 SkFixedFloorToInt(joinLeft),
929 SkFixedFloorToInt(joinRite - joinLeft),
930 fullAlpha,
931 maskRow,
932 isUsingMask,
933 noRealBlitter,
934 needSafeCheck);
935 }
936 if (lr > joinRite) {
937 int len = SkFixedCeilToInt(lr - joinRite);
938 if (len == 1) {
939 SkAlpha alpha = trapezoid_to_alpha(ur - joinRite, lr - joinRite);
940 blit_single_alpha(blitter,
941 y,
942 joinRite >> 16,
943 alpha,
944 fullAlpha,
945 maskRow,
946 isUsingMask,
947 noRealBlitter,
948 needSafeCheck);
949 } else if (len == 2) {
950 SkFixed first = joinRite + SK_Fixed1 - ur;
951 SkFixed second = lr - ur - first;
952 SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, rDY);
953 SkAlpha a2 = partial_triangle_to_alpha(second, rDY);
954 blit_two_alphas(blitter,
955 y,
956 joinRite >> 16,
957 a1,
958 a2,
959 fullAlpha,
960 maskRow,
961 isUsingMask,
962 noRealBlitter,
963 needSafeCheck);
964 } else {
966 y,
967 joinRite,
968 ur,
969 joinRite,
970 lr,
971 SK_MaxS32,
972 rDY,
973 fullAlpha,
974 maskRow,
975 isUsingMask,
976 noRealBlitter,
977 needSafeCheck);
978 }
979 }
980 } else {
982 y,
983 ul,
984 ur,
985 ll,
986 lr,
987 lDY,
988 rDY,
989 fullAlpha,
990 maskRow,
991 isUsingMask,
992 noRealBlitter,
993 needSafeCheck);
994 }
995}
static SkFixed SkFixedFloorToFixed(SkFixed x)
Definition SkFixed.h:86
static SkFixed approximate_intersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2)
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)

◆ blit_two_alphas()

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

Definition at line 669 of file SkScan_AAAPath.cpp.

678 {
679 if (isUsingMask) {
680 if (needSafeCheck) {
681 safely_add_alpha(&maskRow[x], a1);
682 safely_add_alpha(&maskRow[x + 1], a2);
683 } else {
684 add_alpha(&maskRow[x], a1);
685 add_alpha(&maskRow[x + 1], a2);
686 }
687 } else {
688 if (fullAlpha == 0xFF && !noRealBlitter) {
689 blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2);
690 } else {
691 blitter->blitAntiH(x, y, a1);
692 blitter->blitAntiH(x + 1, y, a2);
693 }
694 }
695}
virtual void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)
Definition SkBlitter.h:80

◆ check_intersection()

static void check_intersection ( const SkAnalyticEdge edge,
SkFixed  nextY,
SkFixed nextNextY 
)
static

Definition at line 1364 of file SkScan_AAAPath.cpp.

1364 {
1365 if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) {
1366 *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy);
1367 }
1368}
static const int kDefaultAccuracy

◆ compute_alpha_above_line()

static void compute_alpha_above_line ( SkAlpha alphas,
SkFixed  l,
SkFixed  r,
SkFixed  dY,
SkAlpha  fullAlpha 
)
static

Definition at line 589 of file SkScan_AAAPath.cpp.

593 {
594 SkASSERT(l <= r);
595 SkASSERT(l >> 16 == 0);
596 int R = SkFixedCeilToInt(r);
597 if (R == 0) {
598 return;
599 } else if (R == 1) {
600 alphas[0] = get_partial_alpha(((R << 17) - l - r) >> 9, fullAlpha);
601 } else {
602 SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
603 SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
604 SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle
605 alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha
606 SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle
607 for (int i = 1; i < R - 1; ++i) {
608 alphas[i] = alpha16 >> 8;
609 alpha16 += dY;
610 }
611 alphas[R - 1] = fullAlpha - partial_triangle_to_alpha(last, dY);
612 }
613}

◆ compute_alpha_below_line()

static void compute_alpha_below_line ( SkAlpha alphas,
SkFixed  l,
SkFixed  r,
SkFixed  dY,
SkAlpha  fullAlpha 
)
static

Definition at line 616 of file SkScan_AAAPath.cpp.

620 {
621 SkASSERT(l <= r);
622 SkASSERT(l >> 16 == 0);
623 int R = SkFixedCeilToInt(r);
624 if (R == 0) {
625 return;
626 } else if (R == 1) {
627 alphas[0] = get_partial_alpha(trapezoid_to_alpha(l, r), fullAlpha);
628 } else {
629 SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
630 SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
631 SkFixed lastH = SkFixedMul(last, dY); // vertical edge of the right-most triangle
632 alphas[R - 1] = SkFixedMul(last, lastH) >> 9; // triangle alpha
633 SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle
634 for (int i = R - 2; i > 0; i--) {
635 alphas[i] = (alpha16 >> 8) & 0xFF;
636 alpha16 += dY;
637 }
638 alphas[0] = fullAlpha - partial_triangle_to_alpha(first, dY);
639 }
640}

◆ deferred_blit()

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

Definition at line 1490 of file SkScan_AAAPath.cpp.

1505 {
1506 if (leftE->fRiteE && leftE->fRiteE != riteE) {
1507 // leftE's right edge changed. Blit the saved trapezoid.
1508 SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y);
1510 y,
1511 left,
1512 leftE->fRiteE->fX,
1513 blitter,
1514 maskRow,
1515 isUsingMask,
1516 noRealBlitter,
1517 leftClip,
1518 rightClip);
1519 }
1520 if (!leftE->fRiteE) {
1521 // Save and defer blitting the trapezoid
1522 SkASSERT(riteE->fRiteE == nullptr);
1523 SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
1524 SkASSERT(riteE->fNext == nullptr || riteE->fY == y);
1525 leftE->saveXY(left, y, leftDY);
1526 riteE->saveXY(riteE->fX, y, riteE->fDY);
1527 leftE->fRiteE = riteE;
1528 }
1529 SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
1530 riteE->goY(nextY, yShift);
1531 // Always blit when edges end or nextY is integral
1532 if (isIntegralNextY || leftEnds || riteEnds) {
1534 nextY,
1535 leftE->fX,
1536 riteE->fX,
1537 blitter,
1538 maskRow,
1539 isUsingMask,
1540 noRealBlitter,
1541 leftClip,
1542 rightClip);
1543 }
1544}
void saveXY(SkFixed x, SkFixed y, SkFixed dY)

◆ edges_too_close() [1/2]

static bool edges_too_close ( int  prevRite,
SkFixed  ul,
SkFixed  ll 
)
static

Definition at line 1447 of file SkScan_AAAPath.cpp.

1447 {
1448 return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(ll);
1449}

◆ edges_too_close() [2/2]

static bool edges_too_close ( SkAnalyticEdge prev,
SkAnalyticEdge next,
SkFixed  lowerY 
)
static

Definition at line 1426 of file SkScan_AAAPath.cpp.

1426 {
1427 // When next->fDX == 0, prev->fX >= next->fX - SkAbs32(next->fDX) would be false
1428 // even if prev->fX and next->fX are close and within one pixel (e.g., prev->fX == 0.1,
1429 // next->fX == 0.9). Adding SLACK = 1 to the formula would guarantee it to be true if two
1430 // edges prev and next are within one pixel.
1431 constexpr SkFixed SLACK = SK_Fixed1;
1432
1433 // Note that even if the following test failed, the edges might still be very close to each
1434 // other at some point within the current pixel row because of prev->fDX and next->fDX.
1435 // However, to handle that case, we have to sacrafice more performance.
1436 // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg)
1437 // so I'll ignore fDX for performance tradeoff.
1438 return next && prev && next->fUpperY < lowerY &&
1439 prev->fX + SLACK >= next->fX - SkAbs32(next->fDX);
1440 // The following is more accurate but also slower.
1441 // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY &&
1442 // prev->fX + SkAbs32(prev->fDX) + SLACK >= next->fX - SkAbs32(next->fDX));
1443}
static float prev(float f)
static int32_t SkAbs32(int32_t value)
Definition SkSafe32.h:41

◆ fixed_to_alpha()

static SkAlpha fixed_to_alpha ( SkFixed  f)
static

Definition at line 571 of file SkScan_AAAPath.cpp.

571 {
572 SkASSERT(f <= SK_Fixed1);
573 return get_partial_alpha(0xFF, f);
574}

◆ get_partial_alpha() [1/2]

static SkAlpha get_partial_alpha ( SkAlpha  alpha,
SkAlpha  fullAlpha 
)
static

Definition at line 564 of file SkScan_AAAPath.cpp.

564 {
565 return (alpha * fullAlpha) >> 8;
566}

◆ get_partial_alpha() [2/2]

static SkAlpha get_partial_alpha ( SkAlpha  alpha,
SkFixed  partialHeight 
)
static

Definition at line 560 of file SkScan_AAAPath.cpp.

560 {
561 return SkToU8(SkFixedRoundToInt(alpha * partialHeight));
562}
#define SkFixedRoundToInt(x)
Definition SkFixed.h:76
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22

◆ insert_new_edges()

static void insert_new_edges ( SkAnalyticEdge newEdge,
SkFixed  y,
SkFixed nextNextY 
)
static

Definition at line 1370 of file SkScan_AAAPath.cpp.

1370 {
1371 if (newEdge->fUpperY > y) {
1372 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1373 return;
1374 }
1375 SkAnalyticEdge* prev = newEdge->fPrev;
1376 if (prev->fX <= newEdge->fX) {
1377 while (newEdge->fUpperY <= y) {
1378 check_intersection(newEdge, y, nextNextY);
1379 update_next_next_y(newEdge->fLowerY, y, nextNextY);
1380 newEdge = newEdge->fNext;
1381 }
1382 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1383 return;
1384 }
1385 // find first x pos to insert
1387 // insert the lot, fixing up the links as we go
1388 do {
1389 SkAnalyticEdge* next = newEdge->fNext;
1390 do {
1391 if (start->fNext == newEdge) {
1392 goto nextEdge;
1393 }
1394 SkAnalyticEdge* after = start->fNext;
1395 if (after->fX >= newEdge->fX) {
1396 break;
1397 }
1398 SkASSERT(start != after);
1399 start = after;
1400 } while (true);
1401 remove_edge(newEdge);
1402 insert_edge_after(newEdge, start);
1403 nextEdge:
1404 check_intersection(newEdge, y, nextNextY);
1405 update_next_next_y(newEdge->fLowerY, y, nextNextY);
1406 start = newEdge;
1407 newEdge = next;
1408 } while (newEdge->fUpperY <= y);
1409 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1410}
static void insert_edge_after(EdgeType *edge, EdgeType *afterMe)
Definition SkScanPriv.h:51
EdgeType * backward_insert_start(EdgeType *prev, SkFixed x)
Definition SkScanPriv.h:76

◆ is_smooth_enough() [1/2]

static bool is_smooth_enough ( SkAnalyticEdge leftE,
SkAnalyticEdge riteE,
SkAnalyticEdge currE,
int  stop_y 
)
static

Definition at line 1065 of file SkScan_AAAPath.cpp.

1068 {
1069 if (currE->fUpperY >= SkLeftShift(stop_y, 16)) {
1070 return false; // We're at the end so we won't skip anything
1071 }
1072 if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) {
1073 return is_smooth_enough(leftE, currE, stop_y); // Only leftE is changing
1074 } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) {
1075 return is_smooth_enough(riteE, currE, stop_y); // Only riteE is changing
1076 }
1077
1078 // Now both edges are changing, find the second next edge
1079 SkAnalyticEdge* nextCurrE = currE->fNext;
1080 if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end
1081 return false;
1082 }
1083 // Ensure that currE is the next left edge and nextCurrE is the next right edge. Swap if not.
1084 if (nextCurrE->fUpperX < currE->fUpperX) {
1085 std::swap(currE, nextCurrE);
1086 }
1087 return is_smooth_enough(leftE, currE, stop_y) && is_smooth_enough(riteE, nextCurrE, stop_y);
1088}
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition SkMath.h:37

◆ is_smooth_enough() [2/2]

static bool is_smooth_enough ( SkAnalyticEdge thisEdge,
SkAnalyticEdge nextEdge,
int  stop_y 
)
static

Definition at line 1044 of file SkScan_AAAPath.cpp.

1044 {
1045 if (thisEdge->fCurveCount < 0) {
1046 const SkCubicEdge& cEdge = static_cast<SkAnalyticCubicEdge*>(thisEdge)->fCEdge;
1047 int ddshift = cEdge.fCurveShift;
1048 return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift &&
1049 SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift &&
1050 // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift
1051 (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1;
1052 } else if (thisEdge->fCurveCount > 0) {
1053 const SkQuadraticEdge& qEdge = static_cast<SkAnalyticQuadraticEdge*>(thisEdge)->fQEdge;
1054 return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) &&
1055 SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) &&
1056 // current Dy is (fQDy - fQDDy) >> shift
1057 (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift >= SK_Fixed1;
1058 }
1059 return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small
1060 nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large
1061}
SkFixed fCDDy
Definition SkEdge.h:84
SkFixed fCDx
Definition SkEdge.h:83
SkFixed fCDy
Definition SkEdge.h:83
SkFixed fCDDx
Definition SkEdge.h:84
uint8_t fCurveShift
Definition SkEdge.h:42
SkFixed fQDx
Definition SkEdge.h:72
SkFixed fQDDx
Definition SkEdge.h:73
SkFixed fQDy
Definition SkEdge.h:72
SkFixed fQDDy
Definition SkEdge.h:73

◆ operator<()

static bool operator< ( const SkAnalyticEdge a,
const SkAnalyticEdge b 
)
static

Definition at line 997 of file SkScan_AAAPath.cpp.

997 {
998 int valuea = a.fUpperY;
999 int valueb = b.fUpperY;
1000
1001 if (valuea == valueb) {
1002 valuea = a.fX;
1003 valueb = b.fX;
1004 }
1005
1006 if (valuea == valueb) {
1007 valuea = a.fDX;
1008 valueb = b.fDX;
1009 }
1010
1011 return valuea < valueb;
1012}
static bool b
struct MyStruct a[10]

◆ partial_triangle_to_alpha()

static SkAlpha partial_triangle_to_alpha ( SkFixed  a,
SkFixed  b 
)
static

Definition at line 541 of file SkScan_AAAPath.cpp.

541 {
542 SkASSERT(a <= SK_Fixed1);
543#if 0
544 // TODO(mtklein): skia:8877
545 SkASSERT(b <= SK_Fixed1);
546#endif
547
548 // Approximating...
549 // SkFixed area = SkFixedMul(a, SkFixedMul(a,b)) / 2;
550 SkFixed area = (a >> 11) * (a >> 11) * (b >> 11);
551
552#if 0
553 // TODO(mtklein): skia:8877
554 return SkTo<SkAlpha>(area >> 8);
555#else
556 return SkTo<SkAlpha>((area >> 8) & 0xFF);
557#endif
558}

◆ safely_add_alpha()

static void safely_add_alpha ( SkAlpha alpha,
SkAlpha  delta 
)
static

Definition at line 95 of file SkScan_AAAPath.cpp.

95 {
96 *alpha = std::min(0xFF, *alpha + delta);
97}

◆ sort_edges()

static SkAnalyticEdge * sort_edges ( SkAnalyticEdge list[],
int  count,
SkAnalyticEdge **  last 
)
static

Definition at line 1014 of file SkScan_AAAPath.cpp.

1014 {
1015 SkTQSort(list, list + count);
1016
1017 // now make the edges linked in sorted order
1018 for (int i = 1; i < count; ++i) {
1019 list[i - 1]->fNext = list[i];
1020 list[i]->fPrev = list[i - 1];
1021 }
1022
1023 *last = list[count - 1];
1024 return list[0];
1025}
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194

◆ trapezoid_to_alpha()

static SkAlpha trapezoid_to_alpha ( SkFixed  l1,
SkFixed  l2 
)
static

Definition at line 534 of file SkScan_AAAPath.cpp.

534 {
535 SkASSERT(l1 >= 0 && l2 >= 0);
536 SkFixed area = (l1 + l2) / 2;
537 return SkTo<SkAlpha>(area >> 8);
538}

◆ try_blit_fat_anti_rect()

static bool try_blit_fat_anti_rect ( SkBlitter blitter,
const SkPath path,
const SkIRect clip 
)
inlinestatic

Definition at line 1950 of file SkScan_AAAPath.cpp.

1952 {
1953 SkRect rect;
1954 if (!path.isRect(&rect)) {
1955 return false; // not rect
1956 }
1957 if (!rect.intersect(SkRect::Make(clip))) {
1958 return true; // The intersection is empty. Hence consider it done.
1959 }
1960 SkIRect bounds = rect.roundOut();
1961 if (bounds.width() < 3) {
1962 return false; // not fat
1963 }
1964 blitter->blitFatAntiRect(rect);
1965 return true;
1966}
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
void blitFatAntiRect(const SkRect &rect)
Definition SkBlitter.cpp:67
Optional< SkRect > bounds
Definition SkRecords.h:189
static SkRect Make(const SkISize &size)
Definition SkRect.h:669

◆ update_next_next_y()

static void update_next_next_y ( SkFixed  y,
SkFixed  nextY,
SkFixed nextNextY 
)
static

Definition at line 1360 of file SkScan_AAAPath.cpp.

1360 {
1361 *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY;
1362}

◆ validate_edges_for_y()

static void validate_edges_for_y ( const SkAnalyticEdge edge,
SkFixed  y 
)
static

Definition at line 1412 of file SkScan_AAAPath.cpp.

1412 {
1413#ifdef SK_DEBUG
1414 while (edge->fUpperY <= y) {
1415 SkASSERT(edge->fPrev && edge->fNext);
1416 SkASSERT(edge->fPrev->fNext == edge);
1417 SkASSERT(edge->fNext->fPrev == edge);
1418 SkASSERT(edge->fUpperY <= edge->fLowerY);
1419 SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX);
1420 edge = edge->fNext;
1421 }
1422#endif
1423}

◆ validate_sort()

static void validate_sort ( const SkAnalyticEdge edge)
static

Definition at line 1027 of file SkScan_AAAPath.cpp.

1027 {
1028#ifdef SK_DEBUG
1029 SkFixed y = SkIntToFixed(-32768);
1030
1031 while (edge->fUpperY != SK_MaxS32) {
1032 edge->validate();
1033 SkASSERT(y <= edge->fUpperY);
1034
1035 y = edge->fUpperY;
1036 edge = (SkAnalyticEdge*)edge->fNext;
1037 }
1038#endif
1039}