1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011 |
- /*
- * Copyright 2016 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkPath.h"
- #include "include/core/SkRegion.h"
- #include "include/private/SkTemplates.h"
- #include "include/private/SkTo.h"
- #include "src/core/SkAnalyticEdge.h"
- #include "src/core/SkAntiRun.h"
- #include "src/core/SkAutoMalloc.h"
- #include "src/core/SkBlitter.h"
- #include "src/core/SkEdge.h"
- #include "src/core/SkEdgeBuilder.h"
- #include "src/core/SkGeometry.h"
- #include "src/core/SkQuadClipper.h"
- #include "src/core/SkRasterClip.h"
- #include "src/core/SkScan.h"
- #include "src/core/SkScanPriv.h"
- #include "src/core/SkTSort.h"
- #include "src/utils/SkUTF.h"
- #include <utility>
- #if defined(SK_DISABLE_AAA)
- void SkScan::AAAFillPath(const SkPath&, SkBlitter*, const SkIRect&, const SkIRect&, bool) {
- SkDEBUGFAIL("AAA Disabled");
- return;
- }
- #else
- /*
- The following is a high-level overview of our analytic anti-aliasing
- algorithm. We consider a path as a collection of line segments, as
- quadratic/cubic curves are converted to small line segments. Without loss of
- generality, let's assume that the draw region is [0, W] x [0, H].
- Our algorithm is based on horizontal scan lines (y = c_i) as the previous
- sampling-based algorithm did. However, our algorithm uses non-equal-spaced
- scan lines, while the previous method always uses equal-spaced scan lines,
- such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm,
- and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous
- 16-supersampling AA algorithm.
- Our algorithm contains scan lines y = c_i for c_i that is either:
- 1. an integer between [0, H]
- 2. the y value of a line segment endpoint
- 3. the y value of an intersection of two line segments
- For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes
- the coverage of this horizontal strip of our path on each pixel. This can be
- done very efficiently because the strip of our path now only consists of
- trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes
- rectangles and triangles as special cases).
- We now describe how the coverage of single pixel is computed against such a
- trapezoid. That coverage is essentially the intersection area of a rectangle
- (e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection
- could be complicated, as shown in the example region A below:
- +-----------\----+
- | \ C|
- | \ |
- \ \ |
- |\ A \|
- | \ \
- | \ |
- | B \ |
- +----\-----------+
- However, we don't have to compute the area of A directly. Instead, we can
- compute the excluded area, which are B and C, quite easily, because they're
- just triangles. In fact, we can prove that an excluded region (take B as an
- example) is either itself a simple trapezoid (including rectangles, triangles,
- and empty regions), or its opposite (the opposite of B is A + C) is a simple
- trapezoid. In any case, we can compute its area efficiently.
- In summary, our algorithm has a higher quality because it generates ground-
- truth coverages analytically. It is also faster because it has much fewer
- unnessasary horizontal scan lines. For example, given a triangle path, the
- number of scan lines in our algorithm is only about 3 + H while the
- 16-supersampling algorithm has about 4H scan lines.
- */
- static void add_alpha(SkAlpha* alpha, SkAlpha delta) {
- SkASSERT(*alpha + delta <= 256);
- *alpha = SkAlphaRuns::CatchOverflow(*alpha + delta);
- }
- static void safely_add_alpha(SkAlpha* alpha, SkAlpha delta) {
- *alpha = SkTMin(0xFF, *alpha + delta);
- }
- class AdditiveBlitter : public SkBlitter {
- public:
- ~AdditiveBlitter() override {}
- virtual SkBlitter* getRealBlitter(bool forceRealBlitter = false) = 0;
- virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len) = 0;
- virtual void blitAntiH(int x, int y, const SkAlpha alpha) = 0;
- virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha) = 0;
- void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
- SkDEBUGFAIL("Please call real blitter's blitAntiH instead.");
- }
- void blitV(int x, int y, int height, SkAlpha alpha) override {
- SkDEBUGFAIL("Please call real blitter's blitV instead.");
- }
- void blitH(int x, int y, int width) override {
- SkDEBUGFAIL("Please call real blitter's blitH instead.");
- }
- void blitRect(int x, int y, int width, int height) override {
- SkDEBUGFAIL("Please call real blitter's blitRect instead.");
- }
- void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
- override {
- SkDEBUGFAIL("Please call real blitter's blitAntiRect instead.");
- }
- virtual int getWidth() = 0;
- // Flush the additive alpha cache if floor(y) and floor(nextY) is different
- // (i.e., we'll start working on a new pixel row).
- virtual void flush_if_y_changed(SkFixed y, SkFixed nextY) = 0;
- };
- // We need this mask blitter because it significantly accelerates small path filling.
- class MaskAdditiveBlitter : public AdditiveBlitter {
- public:
- MaskAdditiveBlitter(SkBlitter* realBlitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool isInverse);
- ~MaskAdditiveBlitter() override { fRealBlitter->blitMask(fMask, fClipRect); }
- // Most of the time, we still consider this mask blitter as the real blitter
- // so we can accelerate blitRect and others. But sometimes we want to return
- // the absolute real blitter (e.g., when we fall back to the old code path).
- SkBlitter* getRealBlitter(bool forceRealBlitter) override {
- return forceRealBlitter ? fRealBlitter : this;
- }
- // Virtual function is slow. So don't use this. Directly add alpha to the mask instead.
- void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
- // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges
- // Since there aren't many rectangles, we can still bear the slow speed of virtual functions.
- void blitAntiH(int x, int y, const SkAlpha alpha) override;
- void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
- void blitV(int x, int y, int height, SkAlpha alpha) override;
- void blitRect(int x, int y, int width, int height) override;
- void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
- override;
- // The flush is only needed for RLE (RunBasedAdditiveBlitter)
- void flush_if_y_changed(SkFixed y, SkFixed nextY) override {}
- int getWidth() override { return fClipRect.width(); }
- static bool CanHandleRect(const SkIRect& bounds) {
- int width = bounds.width();
- if (width > MaskAdditiveBlitter::kMAX_WIDTH) {
- return false;
- }
- int64_t rb = SkAlign4(width);
- // use 64bits to detect overflow
- int64_t storage = rb * bounds.height();
- return (width <= MaskAdditiveBlitter::kMAX_WIDTH) &&
- (storage <= MaskAdditiveBlitter::kMAX_STORAGE);
- }
- // Return a pointer where pointer[x] corresonds to the alpha of (x, y)
- uint8_t* getRow(int y) {
- if (y != fY) {
- fY = y;
- fRow = fMask.fImage + (y - fMask.fBounds.fTop) * fMask.fRowBytes - fMask.fBounds.fLeft;
- }
- return fRow;
- }
- private:
- // so we don't try to do very wide things, where the RLE blitter would be faster
- static const int kMAX_WIDTH = 32;
- static const int kMAX_STORAGE = 1024;
- SkBlitter* fRealBlitter;
- SkMask fMask;
- SkIRect fClipRect;
- // we add 2 because we can write 1 extra byte at either end due to precision error
- uint32_t fStorage[(kMAX_STORAGE >> 2) + 2];
- uint8_t* fRow;
- int fY;
- };
- MaskAdditiveBlitter::MaskAdditiveBlitter(SkBlitter* realBlitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool isInverse) {
- SkASSERT(CanHandleRect(ir));
- SkASSERT(!isInverse);
- fRealBlitter = realBlitter;
- fMask.fImage = (uint8_t*)fStorage + 1; // There's 1 extra byte at either end of fStorage
- fMask.fBounds = ir;
- fMask.fRowBytes = ir.width();
- fMask.fFormat = SkMask::kA8_Format;
- fY = ir.fTop - 1;
- fRow = nullptr;
- fClipRect = ir;
- if (!fClipRect.intersect(clipBounds)) {
- SkASSERT(0);
- fClipRect.setEmpty();
- }
- memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 2);
- }
- void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
- SK_ABORT("Don't use this; directly add alphas to the mask.");
- }
- void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
- SkASSERT(x >= fMask.fBounds.fLeft - 1);
- add_alpha(&this->getRow(y)[x], alpha);
- }
- void MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
- SkASSERT(x >= fMask.fBounds.fLeft - 1);
- uint8_t* row = this->getRow(y);
- for (int i = 0; i < width; ++i) {
- add_alpha(&row[x + i], alpha);
- }
- }
- void MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
- if (alpha == 0) {
- return;
- }
- SkASSERT(x >= fMask.fBounds.fLeft - 1);
- // This must be called as if this is a real blitter.
- // So we directly set alpha rather than adding it.
- uint8_t* row = this->getRow(y);
- for (int i = 0; i < height; ++i) {
- row[x] = alpha;
- row += fMask.fRowBytes;
- }
- }
- void MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) {
- SkASSERT(x >= fMask.fBounds.fLeft - 1);
- // This must be called as if this is a real blitter.
- // So we directly set alpha rather than adding it.
- uint8_t* row = this->getRow(y);
- for (int i = 0; i < height; ++i) {
- memset(row + x, 0xFF, width);
- row += fMask.fRowBytes;
- }
- }
- void MaskAdditiveBlitter::blitAntiRect(int x,
- int y,
- int width,
- int height,
- SkAlpha leftAlpha,
- SkAlpha rightAlpha) {
- blitV(x, y, height, leftAlpha);
- blitV(x + 1 + width, y, height, rightAlpha);
- blitRect(x + 1, y, width, height);
- }
- class RunBasedAdditiveBlitter : public AdditiveBlitter {
- public:
- RunBasedAdditiveBlitter(SkBlitter* realBlitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool isInverse);
- ~RunBasedAdditiveBlitter() override { this->flush(); }
- SkBlitter* getRealBlitter(bool forceRealBlitter) override { return fRealBlitter; }
- void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
- void blitAntiH(int x, int y, const SkAlpha alpha) override;
- void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
- int getWidth() override { return fWidth; }
- void flush_if_y_changed(SkFixed y, SkFixed nextY) override {
- if (SkFixedFloorToInt(y) != SkFixedFloorToInt(nextY)) {
- this->flush();
- }
- }
- protected:
- SkBlitter* fRealBlitter;
- int fCurrY; // Current y coordinate.
- int fWidth; // Widest row of region to be blitted
- int fLeft; // Leftmost x coordinate in any row
- int fTop; // Initial y coordinate (top of bounds)
- // The next three variables are used to track a circular buffer that
- // contains the values used in SkAlphaRuns. These variables should only
- // ever be updated in advanceRuns(), and fRuns should always point to
- // a valid SkAlphaRuns...
- int fRunsToBuffer;
- void* fRunsBuffer;
- int fCurrentRun;
- SkAlphaRuns fRuns;
- int fOffsetX;
- bool check(int x, int width) const { return x >= 0 && x + width <= fWidth; }
- // extra one to store the zero at the end
- int getRunsSz() const { return (fWidth + 1 + (fWidth + 2) / 2) * sizeof(int16_t); }
- // This function updates the fRuns variable to point to the next buffer space
- // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
- // and resets fRuns to point to an empty scanline.
- void advanceRuns() {
- const size_t kRunsSz = this->getRunsSz();
- fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
- fRuns.fRuns = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(fRunsBuffer) +
- fCurrentRun * kRunsSz);
- fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
- fRuns.reset(fWidth);
- }
- // Blitting 0xFF and 0 is much faster so we snap alphas close to them
- SkAlpha snapAlpha(SkAlpha alpha) { return alpha > 247 ? 0xFF : alpha < 8 ? 0x00 : alpha; }
- void flush() {
- if (fCurrY >= fTop) {
- SkASSERT(fCurrentRun < fRunsToBuffer);
- for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) {
- // It seems that blitting 255 or 0 is much faster than blitting 254 or 1
- fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]);
- }
- if (!fRuns.empty()) {
- // SkDEBUGCODE(fRuns.dump();)
- fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns);
- this->advanceRuns();
- fOffsetX = 0;
- }
- fCurrY = fTop - 1;
- }
- }
- void checkY(int y) {
- if (y != fCurrY) {
- this->flush();
- fCurrY = y;
- }
- }
- };
- RunBasedAdditiveBlitter::RunBasedAdditiveBlitter(SkBlitter* realBlitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool isInverse) {
- fRealBlitter = realBlitter;
- SkIRect sectBounds;
- if (isInverse) {
- // We use the clip bounds instead of the ir, since we may be asked to
- // draw outside of the rect when we're a inverse filltype
- sectBounds = clipBounds;
- } else {
- if (!sectBounds.intersect(ir, clipBounds)) {
- sectBounds.setEmpty();
- }
- }
- const int left = sectBounds.left();
- const int right = sectBounds.right();
- fLeft = left;
- fWidth = right - left;
- fTop = sectBounds.top();
- fCurrY = fTop - 1;
- fRunsToBuffer = realBlitter->requestRowsPreserved();
- fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz());
- fCurrentRun = -1;
- this->advanceRuns();
- fOffsetX = 0;
- }
- void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
- checkY(y);
- x -= fLeft;
- if (x < 0) {
- len += x;
- antialias -= x;
- x = 0;
- }
- len = SkTMin(len, fWidth - x);
- SkASSERT(check(x, len));
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run
- for (int i = 0; i < len; i += fRuns.fRuns[x + i]) {
- for (int j = 1; j < fRuns.fRuns[x + i]; j++) {
- fRuns.fRuns[x + i + j] = 1;
- fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i];
- }
- fRuns.fRuns[x + i] = 1;
- }
- for (int i = 0; i < len; ++i) {
- add_alpha(&fRuns.fAlpha[x + i], antialias[i]);
- }
- }
- void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
- checkY(y);
- x -= fLeft;
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- if (this->check(x, 1)) {
- fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX);
- }
- }
- void RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
- checkY(y);
- x -= fLeft;
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- if (this->check(x, width)) {
- fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX);
- }
- }
- // This exists specifically for concave path filling.
- // In those cases, we can easily accumulate alpha greater than 0xFF.
- class SafeRLEAdditiveBlitter : public RunBasedAdditiveBlitter {
- public:
- SafeRLEAdditiveBlitter(SkBlitter* realBlitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool isInverse)
- : RunBasedAdditiveBlitter(realBlitter, ir, clipBounds, isInverse) {}
- void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
- void blitAntiH(int x, int y, const SkAlpha alpha) override;
- void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
- };
- void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
- checkY(y);
- x -= fLeft;
- if (x < 0) {
- len += x;
- antialias -= x;
- x = 0;
- }
- len = SkTMin(len, fWidth - x);
- SkASSERT(check(x, len));
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run
- for (int i = 0; i < len; i += fRuns.fRuns[x + i]) {
- for (int j = 1; j < fRuns.fRuns[x + i]; j++) {
- fRuns.fRuns[x + i + j] = 1;
- fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i];
- }
- fRuns.fRuns[x + i] = 1;
- }
- for (int i = 0; i < len; ++i) {
- safely_add_alpha(&fRuns.fAlpha[x + i], antialias[i]);
- }
- }
- void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
- checkY(y);
- x -= fLeft;
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- if (check(x, 1)) {
- // Break the run
- fOffsetX = fRuns.add(x, 0, 1, 0, 0, fOffsetX);
- safely_add_alpha(&fRuns.fAlpha[x], alpha);
- }
- }
- void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
- checkY(y);
- x -= fLeft;
- if (x < fOffsetX) {
- fOffsetX = 0;
- }
- if (check(x, width)) {
- // Break the run
- fOffsetX = fRuns.add(x, 0, width, 0, 0, fOffsetX);
- for (int i = x; i < x + width; i += fRuns.fRuns[i]) {
- safely_add_alpha(&fRuns.fAlpha[i], alpha);
- }
- }
- }
- // Return the alpha of a trapezoid whose height is 1
- static SkAlpha trapezoid_to_alpha(SkFixed l1, SkFixed l2) {
- SkASSERT(l1 >= 0 && l2 >= 0);
- SkFixed area = (l1 + l2) / 2;
- return SkTo<SkAlpha>(area >> 8);
- }
- // The alpha of right-triangle (a, a*b)
- static SkAlpha partial_triangle_to_alpha(SkFixed a, SkFixed b) {
- SkASSERT(a <= SK_Fixed1);
- #if 0
- // TODO(mtklein): skia:8877
- SkASSERT(b <= SK_Fixed1);
- #endif
- // Approximating...
- // SkFixed area = SkFixedMul(a, SkFixedMul(a,b)) / 2;
- SkFixed area = (a >> 11) * (a >> 11) * (b >> 11);
- #if 0
- // TODO(mtklein): skia:8877
- return SkTo<SkAlpha>(area >> 8);
- #else
- return SkTo<SkAlpha>((area >> 8) & 0xFF);
- #endif
- }
- static SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight) {
- return SkToU8(SkFixedRoundToInt(alpha * partialHeight));
- }
- static SkAlpha get_partial_alpha(SkAlpha alpha, SkAlpha fullAlpha) {
- return (alpha * fullAlpha) >> 8;
- }
- // For SkFixed that's close to SK_Fixed1, we can't convert it to alpha by just shifting right.
- // For example, when f = SK_Fixed1, right shifting 8 will get 256, but we need 255.
- // This is rarely the problem so we'll only use this for blitting rectangles.
- static SkAlpha fixed_to_alpha(SkFixed f) {
- SkASSERT(f <= SK_Fixed1);
- return get_partial_alpha(0xFF, f);
- }
- // Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1),
- // approximate (very coarsely) the x coordinate of the intersection.
- static SkFixed approximate_intersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2) {
- if (l1 > r1) {
- std::swap(l1, r1);
- }
- if (l2 > r2) {
- std::swap(l2, r2);
- }
- return (SkTMax(l1, l2) + SkTMin(r1, r2)) / 2;
- }
- // Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0]
- static void compute_alpha_above_line(SkAlpha* alphas,
- SkFixed l,
- SkFixed r,
- SkFixed dY,
- SkAlpha fullAlpha) {
- SkASSERT(l <= r);
- SkASSERT(l >> 16 == 0);
- int R = SkFixedCeilToInt(r);
- if (R == 0) {
- return;
- } else if (R == 1) {
- alphas[0] = get_partial_alpha(((R << 17) - l - r) >> 9, fullAlpha);
- } else {
- SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
- SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
- SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle
- alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha
- SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle
- for (int i = 1; i < R - 1; ++i) {
- alphas[i] = alpha16 >> 8;
- alpha16 += dY;
- }
- alphas[R - 1] = fullAlpha - partial_triangle_to_alpha(last, dY);
- }
- }
- // Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0]
- static void compute_alpha_below_line(SkAlpha* alphas,
- SkFixed l,
- SkFixed r,
- SkFixed dY,
- SkAlpha fullAlpha) {
- SkASSERT(l <= r);
- SkASSERT(l >> 16 == 0);
- int R = SkFixedCeilToInt(r);
- if (R == 0) {
- return;
- } else if (R == 1) {
- alphas[0] = get_partial_alpha(trapezoid_to_alpha(l, r), fullAlpha);
- } else {
- SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
- SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
- SkFixed lastH = SkFixedMul(last, dY); // vertical edge of the right-most triangle
- alphas[R - 1] = SkFixedMul(last, lastH) >> 9; // triangle alpha
- SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle
- for (int i = R - 2; i > 0; i--) {
- alphas[i] = (alpha16 >> 8) & 0xFF;
- alpha16 += dY;
- }
- alphas[0] = fullAlpha - partial_triangle_to_alpha(first, dY);
- }
- }
- // Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha
- static SK_ALWAYS_INLINE void blit_single_alpha(AdditiveBlitter* blitter,
- int y,
- int x,
- SkAlpha alpha,
- SkAlpha fullAlpha,
- SkAlpha* maskRow,
- bool isUsingMask,
- bool noRealBlitter,
- bool needSafeCheck) {
- if (isUsingMask) {
- if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths
- maskRow[x] = alpha;
- } else if (needSafeCheck) {
- safely_add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
- } else {
- add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
- }
- } else {
- if (fullAlpha == 0xFF && !noRealBlitter) {
- blitter->getRealBlitter()->blitV(x, y, 1, alpha);
- } else {
- blitter->blitAntiH(x, y, get_partial_alpha(alpha, fullAlpha));
- }
- }
- }
- static SK_ALWAYS_INLINE void blit_two_alphas(AdditiveBlitter* blitter,
- int y,
- int x,
- SkAlpha a1,
- SkAlpha a2,
- SkAlpha fullAlpha,
- SkAlpha* maskRow,
- bool isUsingMask,
- bool noRealBlitter,
- bool needSafeCheck) {
- if (isUsingMask) {
- if (needSafeCheck) {
- safely_add_alpha(&maskRow[x], a1);
- safely_add_alpha(&maskRow[x + 1], a2);
- } else {
- add_alpha(&maskRow[x], a1);
- add_alpha(&maskRow[x + 1], a2);
- }
- } else {
- if (fullAlpha == 0xFF && !noRealBlitter) {
- blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2);
- } else {
- blitter->blitAntiH(x, y, a1);
- blitter->blitAntiH(x + 1, y, a2);
- }
- }
- }
- static SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter,
- int y,
- int x,
- int len,
- SkAlpha fullAlpha,
- SkAlpha* maskRow,
- bool isUsingMask,
- bool noRealBlitter,
- bool needSafeCheck) {
- if (isUsingMask) {
- for (int i = 0; i < len; ++i) {
- if (needSafeCheck) {
- safely_add_alpha(&maskRow[x + i], fullAlpha);
- } else {
- add_alpha(&maskRow[x + i], fullAlpha);
- }
- }
- } else {
- if (fullAlpha == 0xFF && !noRealBlitter) {
- blitter->getRealBlitter()->blitH(x, y, len);
- } else {
- blitter->blitAntiH(x, y, len, fullAlpha);
- }
- }
- }
- 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) {
- int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr);
- int len = R - L;
- if (len == 1) {
- SkAlpha alpha = trapezoid_to_alpha(ur - ul, lr - ll);
- blit_single_alpha(blitter,
- y,
- L,
- alpha,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- return;
- }
- const int kQuickLen = 31;
- char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)];
- SkAlpha* alphas;
- if (len <= kQuickLen) {
- alphas = (SkAlpha*)quickMemory;
- } else {
- alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))];
- }
- SkAlpha* tempAlphas = alphas + len + 1;
- int16_t* runs = (int16_t*)(alphas + (len + 1) * 2);
- for (int i = 0; i < len; ++i) {
- runs[i] = 1;
- alphas[i] = fullAlpha;
- }
- runs[len] = 0;
- int uL = SkFixedFloorToInt(ul);
- int lL = SkFixedCeilToInt(ll);
- if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case
- SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul;
- SkFixed second = ll - ul - first;
- SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, lDY);
- SkAlpha a2 = partial_triangle_to_alpha(second, lDY);
- alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0;
- alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0;
- } else {
- compute_alpha_below_line(
- tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL), lDY, fullAlpha);
- for (int i = uL; i < lL; ++i) {
- if (alphas[i - L] > tempAlphas[i - L]) {
- alphas[i - L] -= tempAlphas[i - L];
- } else {
- alphas[i - L] = 0;
- }
- }
- }
- int uR = SkFixedFloorToInt(ur);
- int lR = SkFixedCeilToInt(lr);
- if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case
- SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur;
- SkFixed second = lr - ur - first;
- SkAlpha a1 = partial_triangle_to_alpha(first, rDY);
- SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, rDY);
- alphas[len - 2] = alphas[len - 2] > a1 ? alphas[len - 2] - a1 : 0;
- alphas[len - 1] = alphas[len - 1] > a2 ? alphas[len - 1] - a2 : 0;
- } else {
- compute_alpha_above_line(
- tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR), rDY, fullAlpha);
- for (int i = uR; i < lR; ++i) {
- if (alphas[i - L] > tempAlphas[i - L]) {
- alphas[i - L] -= tempAlphas[i - L];
- } else {
- alphas[i - L] = 0;
- }
- }
- }
- if (isUsingMask) {
- for (int i = 0; i < len; ++i) {
- if (needSafeCheck) {
- safely_add_alpha(&maskRow[L + i], alphas[i]);
- } else {
- add_alpha(&maskRow[L + i], alphas[i]);
- }
- }
- } else {
- if (fullAlpha == 0xFF && !noRealBlitter) {
- // Real blitter is faster than RunBasedAdditiveBlitter
- blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs);
- } else {
- blitter->blitAntiH(L, y, alphas, len);
- }
- }
- if (len > kQuickLen) {
- delete[] alphas;
- }
- }
- static SK_ALWAYS_INLINE 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) {
- SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value
- if (ul > ur) {
- return;
- }
- // Edge crosses. Approximate it. This should only happend due to precision limit,
- // so the approximation could be very coarse.
- if (ll > lr) {
- ll = lr = approximate_intersection(ul, ll, ur, lr);
- }
- if (ul == ur && ll == lr) {
- return; // empty trapzoid
- }
- // We're going to use the left line ul-ll and the rite line ur-lr
- // to exclude the area that's not covered by the path.
- // Swapping (ul, ll) or (ur, lr) won't affect that exclusion
- // so we'll do that for simplicity.
- if (ul > ll) {
- std::swap(ul, ll);
- }
- if (ur > lr) {
- std::swap(ur, lr);
- }
- SkFixed joinLeft = SkFixedCeilToFixed(ll);
- SkFixed joinRite = SkFixedFloorToFixed(ur);
- if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit
- if (ul < joinLeft) {
- int len = SkFixedCeilToInt(joinLeft - ul);
- if (len == 1) {
- SkAlpha alpha = trapezoid_to_alpha(joinLeft - ul, joinLeft - ll);
- blit_single_alpha(blitter,
- y,
- ul >> 16,
- alpha,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- } else if (len == 2) {
- SkFixed first = joinLeft - SK_Fixed1 - ul;
- SkFixed second = ll - ul - first;
- SkAlpha a1 = partial_triangle_to_alpha(first, lDY);
- SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, lDY);
- blit_two_alphas(blitter,
- y,
- ul >> 16,
- a1,
- a2,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- } else {
- blit_aaa_trapezoid_row(blitter,
- y,
- ul,
- joinLeft,
- ll,
- joinLeft,
- lDY,
- SK_MaxS32,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- }
- }
- // SkAAClip requires that we blit from left to right.
- // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite]
- if (joinLeft < joinRite) {
- blit_full_alpha(blitter,
- y,
- SkFixedFloorToInt(joinLeft),
- SkFixedFloorToInt(joinRite - joinLeft),
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- }
- if (lr > joinRite) {
- int len = SkFixedCeilToInt(lr - joinRite);
- if (len == 1) {
- SkAlpha alpha = trapezoid_to_alpha(ur - joinRite, lr - joinRite);
- blit_single_alpha(blitter,
- y,
- joinRite >> 16,
- alpha,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- } else if (len == 2) {
- SkFixed first = joinRite + SK_Fixed1 - ur;
- SkFixed second = lr - ur - first;
- SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, rDY);
- SkAlpha a2 = partial_triangle_to_alpha(second, rDY);
- blit_two_alphas(blitter,
- y,
- joinRite >> 16,
- a1,
- a2,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- } else {
- blit_aaa_trapezoid_row(blitter,
- y,
- joinRite,
- ur,
- joinRite,
- lr,
- SK_MaxS32,
- rDY,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- }
- }
- } else {
- blit_aaa_trapezoid_row(blitter,
- y,
- ul,
- ur,
- ll,
- lr,
- lDY,
- rDY,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter,
- needSafeCheck);
- }
- }
- static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) {
- int valuea = a.fUpperY;
- int valueb = b.fUpperY;
- if (valuea == valueb) {
- valuea = a.fX;
- valueb = b.fX;
- }
- if (valuea == valueb) {
- valuea = a.fDX;
- valueb = b.fDX;
- }
- return valuea < valueb;
- }
- static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticEdge** last) {
- SkTQSort(list, list + count - 1);
- // now make the edges linked in sorted order
- for (int i = 1; i < count; ++i) {
- list[i - 1]->fNext = list[i];
- list[i]->fPrev = list[i - 1];
- }
- *last = list[count - 1];
- return list[0];
- }
- static void validate_sort(const SkAnalyticEdge* edge) {
- #ifdef SK_DEBUG
- SkFixed y = SkIntToFixed(-32768);
- while (edge->fUpperY != SK_MaxS32) {
- edge->validate();
- SkASSERT(y <= edge->fUpperY);
- y = edge->fUpperY;
- edge = (SkAnalyticEdge*)edge->fNext;
- }
- #endif
- }
- // For an edge, we consider it smooth if the Dx doesn't change much, and Dy is large enough
- // For curves that are updating, the Dx is not changing much if fQDx/fCDx and fQDy/fCDy are
- // relatively large compared to fQDDx/QCDDx and fQDDy/fCDDy
- static bool is_smooth_enough(SkAnalyticEdge* thisEdge, SkAnalyticEdge* nextEdge, int stop_y) {
- if (thisEdge->fCurveCount < 0) {
- const SkCubicEdge& cEdge = static_cast<SkAnalyticCubicEdge*>(thisEdge)->fCEdge;
- int ddshift = cEdge.fCurveShift;
- return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift &&
- SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift &&
- // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift
- (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1;
- } else if (thisEdge->fCurveCount > 0) {
- const SkQuadraticEdge& qEdge = static_cast<SkAnalyticQuadraticEdge*>(thisEdge)->fQEdge;
- return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) &&
- SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) &&
- // current Dy is (fQDy - fQDDy) >> shift
- (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift >= SK_Fixed1;
- }
- return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small
- nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large
- }
- // Check if the leftE and riteE are changing smoothly in terms of fDX.
- // If yes, we can later skip the fractional y and directly jump to integer y.
- static bool is_smooth_enough(SkAnalyticEdge* leftE,
- SkAnalyticEdge* riteE,
- SkAnalyticEdge* currE,
- int stop_y) {
- if (currE->fUpperY >= SkLeftShift(stop_y, 16)) {
- return false; // We're at the end so we won't skip anything
- }
- if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) {
- return is_smooth_enough(leftE, currE, stop_y); // Only leftE is changing
- } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) {
- return is_smooth_enough(riteE, currE, stop_y); // Only riteE is changing
- }
- // Now both edges are changing, find the second next edge
- SkAnalyticEdge* nextCurrE = currE->fNext;
- if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end
- return false;
- }
- // Ensure that currE is the next left edge and nextCurrE is the next right edge. Swap if not.
- if (nextCurrE->fUpperX < currE->fUpperX) {
- std::swap(currE, nextCurrE);
- }
- return is_smooth_enough(leftE, currE, stop_y) && is_smooth_enough(riteE, nextCurrE, stop_y);
- }
- static void aaa_walk_convex_edges(SkAnalyticEdge* prevHead,
- AdditiveBlitter* blitter,
- int start_y,
- int stop_y,
- SkFixed leftBound,
- SkFixed riteBound,
- bool isUsingMask) {
- validate_sort((SkAnalyticEdge*)prevHead->fNext);
- SkAnalyticEdge* leftE = (SkAnalyticEdge*)prevHead->fNext;
- SkAnalyticEdge* riteE = (SkAnalyticEdge*)leftE->fNext;
- SkAnalyticEdge* currE = (SkAnalyticEdge*)riteE->fNext;
- SkFixed y = SkTMax(leftE->fUpperY, riteE->fUpperY);
- for (;;) {
- // We have to check fLowerY first because some edges might be alone (e.g., there's only
- // a left edge but no right edge in a given y scan line) due to precision limit.
- while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
- if (!leftE->update(y)) {
- if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
- goto END_WALK;
- }
- leftE = currE;
- currE = (SkAnalyticEdge*)currE->fNext;
- }
- }
- while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
- if (!riteE->update(y)) {
- if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
- goto END_WALK;
- }
- riteE = currE;
- currE = (SkAnalyticEdge*)currE->fNext;
- }
- }
- SkASSERT(leftE);
- SkASSERT(riteE);
- // check our bottom clip
- if (SkFixedFloorToInt(y) >= stop_y) {
- break;
- }
- SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y);
- SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y);
- leftE->goY(y);
- riteE->goY(y);
- if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && leftE->fDX > riteE->fDX)) {
- std::swap(leftE, riteE);
- }
- SkFixed local_bot_fixed = SkMin32(leftE->fLowerY, riteE->fLowerY);
- if (is_smooth_enough(leftE, riteE, currE, stop_y)) {
- local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed);
- }
- local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y));
- SkFixed left = SkTMax(leftBound, leftE->fX);
- SkFixed dLeft = leftE->fDX;
- SkFixed rite = SkTMin(riteBound, riteE->fX);
- SkFixed dRite = riteE->fDX;
- if (0 == (dLeft | dRite)) {
- int fullLeft = SkFixedCeilToInt(left);
- int fullRite = SkFixedFloorToInt(rite);
- SkFixed partialLeft = SkIntToFixed(fullLeft) - left;
- SkFixed partialRite = rite - SkIntToFixed(fullRite);
- int fullTop = SkFixedCeilToInt(y);
- int fullBot = SkFixedFloorToInt(local_bot_fixed);
- SkFixed partialTop = SkIntToFixed(fullTop) - y;
- SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot);
- if (fullTop > fullBot) { // The rectangle is within one pixel height...
- partialTop -= (SK_Fixed1 - partialBot);
- partialBot = 0;
- }
- if (fullRite >= fullLeft) {
- if (partialTop > 0) { // blit first partial row
- if (partialLeft > 0) {
- blitter->blitAntiH(fullLeft - 1,
- fullTop - 1,
- fixed_to_alpha(SkFixedMul(partialTop, partialLeft)));
- }
- blitter->blitAntiH(
- fullLeft, fullTop - 1, fullRite - fullLeft, fixed_to_alpha(partialTop));
- if (partialRite > 0) {
- blitter->blitAntiH(fullRite,
- fullTop - 1,
- fixed_to_alpha(SkFixedMul(partialTop, partialRite)));
- }
- blitter->flush_if_y_changed(y, y + partialTop);
- }
- // Blit all full-height rows from fullTop to fullBot
- if (fullBot > fullTop &&
- // SkAAClip cannot handle the empty rect so check the non-emptiness here
- // (bug chromium:662800)
- (fullRite > fullLeft || fixed_to_alpha(partialLeft) > 0 ||
- fixed_to_alpha(partialRite) > 0)) {
- blitter->getRealBlitter()->blitAntiRect(fullLeft - 1,
- fullTop,
- fullRite - fullLeft,
- fullBot - fullTop,
- fixed_to_alpha(partialLeft),
- fixed_to_alpha(partialRite));
- }
- if (partialBot > 0) { // blit last partial row
- if (partialLeft > 0) {
- blitter->blitAntiH(fullLeft - 1,
- fullBot,
- fixed_to_alpha(SkFixedMul(partialBot, partialLeft)));
- }
- blitter->blitAntiH(
- fullLeft, fullBot, fullRite - fullLeft, fixed_to_alpha(partialBot));
- if (partialRite > 0) {
- blitter->blitAntiH(fullRite,
- fullBot,
- fixed_to_alpha(SkFixedMul(partialBot, partialRite)));
- }
- }
- } else { // left and rite are within the same pixel
- if (partialTop > 0) {
- blitter->blitAntiH(fullLeft - 1,
- fullTop - 1,
- 1,
- fixed_to_alpha(SkFixedMul(partialTop, rite - left)));
- blitter->flush_if_y_changed(y, y + partialTop);
- }
- if (fullBot > fullTop) {
- blitter->getRealBlitter()->blitV(
- fullLeft - 1, fullTop, fullBot - fullTop, fixed_to_alpha(rite - left));
- }
- if (partialBot > 0) {
- blitter->blitAntiH(fullLeft - 1,
- fullBot,
- 1,
- fixed_to_alpha(SkFixedMul(partialBot, rite - left)));
- }
- }
- y = local_bot_fixed;
- } else {
- // The following constant are used to snap X
- // We snap X mainly for speedup (no tiny triangle) and
- // avoiding edge cases caused by precision errors
- const SkFixed kSnapDigit = SK_Fixed1 >> 4;
- const SkFixed kSnapHalf = kSnapDigit >> 1;
- const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1));
- left += kSnapHalf;
- rite += kSnapHalf; // For fast rounding
- // Number of blit_trapezoid_row calls we'll have
- int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y);
- // If we're using mask blitter, we advance the mask row in this function
- // to save some "if" condition checks.
- SkAlpha* maskRow = nullptr;
- if (isUsingMask) {
- maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
- }
- // Instead of writing one loop that handles both partial-row blit_trapezoid_row
- // and full-row trapezoid_row together, we use the following 3-stage flow to
- // handle partial-row blit and full-row blit separately. It will save us much time
- // on changing y, left, and rite.
- if (count > 1) {
- if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top
- count--;
- SkFixed nextY = SkFixedCeilToFixed(y + 1);
- SkFixed dY = nextY - y;
- SkFixed nextLeft = left + SkFixedMul(dLeft, dY);
- SkFixed nextRite = rite + SkFixedMul(dRite, dY);
- SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
- (nextLeft & kSnapMask) >= leftBound &&
- (nextRite & kSnapMask) <= riteBound);
- blit_trapezoid_row(blitter,
- y >> 16,
- left & kSnapMask,
- rite & kSnapMask,
- nextLeft & kSnapMask,
- nextRite & kSnapMask,
- leftE->fDY,
- riteE->fDY,
- get_partial_alpha(0xFF, dY),
- maskRow,
- isUsingMask);
- blitter->flush_if_y_changed(y, nextY);
- left = nextLeft;
- rite = nextRite;
- y = nextY;
- }
- while (count > 1) { // Full rows in the middle
- count--;
- if (isUsingMask) {
- maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
- }
- SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite;
- SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
- (nextLeft & kSnapMask) >= leftBound &&
- (nextRite & kSnapMask) <= riteBound);
- blit_trapezoid_row(blitter,
- y >> 16,
- left & kSnapMask,
- rite & kSnapMask,
- nextLeft & kSnapMask,
- nextRite & kSnapMask,
- leftE->fDY,
- riteE->fDY,
- 0xFF,
- maskRow,
- isUsingMask);
- blitter->flush_if_y_changed(y, nextY);
- left = nextLeft;
- rite = nextRite;
- y = nextY;
- }
- }
- if (isUsingMask) {
- maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
- }
- SkFixed dY = local_bot_fixed - y; // partial-row on the bottom
- SkASSERT(dY <= SK_Fixed1);
- // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound.
- // Take them back into the bound here.
- // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound
- SkFixed nextLeft = SkTMax(left + SkFixedMul(dLeft, dY), leftBound + kSnapHalf);
- SkFixed nextRite = SkTMin(rite + SkFixedMul(dRite, dY), riteBound + kSnapHalf);
- SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
- (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound);
- blit_trapezoid_row(blitter,
- y >> 16,
- left & kSnapMask,
- rite & kSnapMask,
- nextLeft & kSnapMask,
- nextRite & kSnapMask,
- leftE->fDY,
- riteE->fDY,
- get_partial_alpha(0xFF, dY),
- maskRow,
- isUsingMask);
- blitter->flush_if_y_changed(y, local_bot_fixed);
- left = nextLeft;
- rite = nextRite;
- y = local_bot_fixed;
- left -= kSnapHalf;
- rite -= kSnapHalf;
- }
- leftE->fX = left;
- riteE->fX = rite;
- leftE->fY = riteE->fY = y;
- }
- END_WALK:;
- }
- static void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed* nextNextY) {
- *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY;
- }
- static void check_intersection(const SkAnalyticEdge* edge, SkFixed nextY, SkFixed* nextNextY) {
- if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) {
- *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy);
- }
- }
- static void insert_new_edges(SkAnalyticEdge* newEdge, SkFixed y, SkFixed* nextNextY) {
- if (newEdge->fUpperY > y) {
- update_next_next_y(newEdge->fUpperY, y, nextNextY);
- return;
- }
- SkAnalyticEdge* prev = newEdge->fPrev;
- if (prev->fX <= newEdge->fX) {
- while (newEdge->fUpperY <= y) {
- check_intersection(newEdge, y, nextNextY);
- update_next_next_y(newEdge->fLowerY, y, nextNextY);
- newEdge = newEdge->fNext;
- }
- update_next_next_y(newEdge->fUpperY, y, nextNextY);
- return;
- }
- // find first x pos to insert
- SkAnalyticEdge* start = backward_insert_start(prev, newEdge->fX);
- // insert the lot, fixing up the links as we go
- do {
- SkAnalyticEdge* next = newEdge->fNext;
- do {
- if (start->fNext == newEdge) {
- goto nextEdge;
- }
- SkAnalyticEdge* after = start->fNext;
- if (after->fX >= newEdge->fX) {
- break;
- }
- SkASSERT(start != after);
- start = after;
- } while (true);
- remove_edge(newEdge);
- insert_edge_after(newEdge, start);
- nextEdge:
- check_intersection(newEdge, y, nextNextY);
- update_next_next_y(newEdge->fLowerY, y, nextNextY);
- start = newEdge;
- newEdge = next;
- } while (newEdge->fUpperY <= y);
- update_next_next_y(newEdge->fUpperY, y, nextNextY);
- }
- static void validate_edges_for_y(const SkAnalyticEdge* edge, SkFixed y) {
- #ifdef SK_DEBUG
- while (edge->fUpperY <= y) {
- SkASSERT(edge->fPrev && edge->fNext);
- SkASSERT(edge->fPrev->fNext == edge);
- SkASSERT(edge->fNext->fPrev == edge);
- SkASSERT(edge->fUpperY <= edge->fLowerY);
- SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX);
- edge = edge->fNext;
- }
- #endif
- }
- // Return true if prev->fX, next->fX are too close in the current pixel row.
- static bool edges_too_close(SkAnalyticEdge* prev, SkAnalyticEdge* next, SkFixed lowerY) {
- // When next->fDX == 0, prev->fX >= next->fX - SkAbs32(next->fDX) would be false
- // even if prev->fX and next->fX are close and within one pixel (e.g., prev->fX == 0.1,
- // next->fX == 0.9). Adding SLACK = 1 to the formula would guarantee it to be true if two
- // edges prev and next are within one pixel.
- constexpr SkFixed SLACK = SK_Fixed1;
- // Note that even if the following test failed, the edges might still be very close to each
- // other at some point within the current pixel row because of prev->fDX and next->fDX.
- // However, to handle that case, we have to sacrafice more performance.
- // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg)
- // so I'll ignore fDX for performance tradeoff.
- return next && prev && next->fUpperY < lowerY &&
- prev->fX + SLACK >= next->fX - SkAbs32(next->fDX);
- // The following is more accurate but also slower.
- // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY &&
- // prev->fX + SkAbs32(prev->fDX) + SLACK >= next->fX - SkAbs32(next->fDX));
- }
- // This function exists for the case where the previous rite edge is removed because
- // its fLowerY <= nextY
- static bool edges_too_close(int prevRite, SkFixed ul, SkFixed ll) {
- return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(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) {
- SkAnalyticEdge* riteE = leftE->fRiteE;
- SkASSERT(riteE);
- SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY);
- SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY));
- int y = SkFixedFloorToInt(leftE->fSavedY);
- // Instead of using fixed_to_alpha(lowerY - leftE->fSavedY), we use the following fullAlpha
- // to elimiate cumulative error: if there are many fractional y scan lines within the
- // same row, the former may accumulate the rounding error while the later won't.
- SkAlpha fullAlpha = fixed_to_alpha(lowerY - SkIntToFixed(y)) -
- fixed_to_alpha(leftE->fSavedY - SkIntToFixed(y));
- // We need fSavedDY because the (quad or cubic) edge might be updated
- blit_trapezoid_row(
- blitter,
- y,
- SkTMax(leftE->fSavedX, leftClip),
- SkTMin(riteE->fSavedX, rightClip),
- SkTMax(lowerLeft, leftClip),
- SkTMin(lowerRite, rightClip),
- leftE->fSavedDY,
- riteE->fSavedDY,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter || (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) ||
- edges_too_close(riteE, riteE->fNext, lowerY))),
- true);
- leftE->fRiteE = nullptr;
- }
- static void deferred_blit(SkAnalyticEdge* leftE,
- SkAnalyticEdge* riteE,
- SkFixed left,
- SkFixed leftDY, // don't save leftE->fX/fDY as they may have been updated
- SkFixed y,
- SkFixed nextY,
- bool isIntegralNextY,
- bool leftEnds,
- bool riteEnds,
- AdditiveBlitter* blitter,
- SkAlpha* maskRow,
- bool isUsingMask,
- bool noRealBlitter,
- SkFixed leftClip,
- SkFixed rightClip,
- int yShift) {
- if (leftE->fRiteE && leftE->fRiteE != riteE) {
- // leftE's right edge changed. Blit the saved trapezoid.
- SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y);
- blit_saved_trapezoid(leftE,
- y,
- left,
- leftE->fRiteE->fX,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip);
- }
- if (!leftE->fRiteE) {
- // Save and defer blitting the trapezoid
- SkASSERT(riteE->fRiteE == nullptr);
- SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
- SkASSERT(riteE->fNext == nullptr || riteE->fY == y);
- leftE->saveXY(left, y, leftDY);
- riteE->saveXY(riteE->fX, y, riteE->fDY);
- leftE->fRiteE = riteE;
- }
- SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
- riteE->goY(nextY, yShift);
- // Always blit when edges end or nextY is integral
- if (isIntegralNextY || leftEnds || riteEnds) {
- blit_saved_trapezoid(leftE,
- nextY,
- leftE->fX,
- riteE->fX,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip);
- }
- }
- static void aaa_walk_edges(SkAnalyticEdge* prevHead,
- SkAnalyticEdge* nextTail,
- SkPath::FillType fillType,
- AdditiveBlitter* blitter,
- int start_y,
- int stop_y,
- SkFixed leftClip,
- SkFixed rightClip,
- bool isUsingMask,
- bool forceRLE,
- bool useDeferred,
- bool skipIntersect) {
- prevHead->fX = prevHead->fUpperX = leftClip;
- nextTail->fX = nextTail->fUpperX = rightClip;
- SkFixed y = SkTMax(prevHead->fNext->fUpperY, SkIntToFixed(start_y));
- SkFixed nextNextY = SK_MaxS32;
- {
- SkAnalyticEdge* edge;
- for (edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) {
- edge->goY(y);
- update_next_next_y(edge->fLowerY, y, &nextNextY);
- }
- update_next_next_y(edge->fUpperY, y, &nextNextY);
- }
- // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
- int windingMask = (fillType & 1) ? 1 : -1;
- bool isInverse = SkPath::IsInverseFillType(fillType);
- if (isInverse && SkIntToFixed(start_y) != y) {
- int width = SkFixedFloorToInt(rightClip - leftClip);
- if (SkFixedFloorToInt(y) != start_y) {
- blitter->getRealBlitter()->blitRect(
- SkFixedFloorToInt(leftClip), start_y, width, SkFixedFloorToInt(y) - start_y);
- start_y = SkFixedFloorToInt(y);
- }
- SkAlpha* maskRow =
- isUsingMask ? static_cast<MaskAdditiveBlitter*>(blitter)->getRow(start_y) : nullptr;
- blit_full_alpha(blitter,
- start_y,
- SkFixedFloorToInt(leftClip),
- width,
- fixed_to_alpha(y - SkIntToFixed(start_y)),
- maskRow,
- isUsingMask,
- false,
- false);
- }
- while (true) {
- int w = 0;
- bool in_interval = isInverse;
- SkFixed prevX = prevHead->fX;
- SkFixed nextY = SkTMin(nextNextY, SkFixedCeilToFixed(y + 1));
- bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0;
- SkAnalyticEdge* currE = prevHead->fNext;
- SkAnalyticEdge* leftE = prevHead;
- SkFixed left = leftClip;
- SkFixed leftDY = 0;
- bool leftEnds = false;
- int prevRite = SkFixedFloorToInt(leftClip);
- nextNextY = SK_MaxS32;
- SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0);
- int yShift = 0;
- if ((nextY - y) & (SK_Fixed1 >> 2)) {
- yShift = 2;
- nextY = y + (SK_Fixed1 >> 2);
- } else if ((nextY - y) & (SK_Fixed1 >> 1)) {
- yShift = 1;
- SkASSERT(nextY == y + (SK_Fixed1 >> 1));
- }
- SkAlpha fullAlpha = fixed_to_alpha(nextY - y);
- // If we're using mask blitter, we advance the mask row in this function
- // to save some "if" condition checks.
- SkAlpha* maskRow = nullptr;
- if (isUsingMask) {
- maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(SkFixedFloorToInt(y));
- }
- SkASSERT(currE->fPrev == prevHead);
- validate_edges_for_y(currE, y);
- // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement
- // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges)
- bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1);
- while (currE->fUpperY <= y) {
- SkASSERT(currE->fLowerY >= nextY);
- SkASSERT(currE->fY == y);
- w += currE->fWinding;
- bool prev_in_interval = in_interval;
- in_interval = !(w & windingMask) == isInverse;
- bool isLeft = in_interval && !prev_in_interval;
- bool isRite = !in_interval && prev_in_interval;
- bool currEnds = currE->fLowerY == nextY;
- if (useDeferred) {
- if (currE->fRiteE && !isLeft) {
- // currE is a left edge previously, but now it's not.
- // Blit the trapezoid between fSavedY and y.
- SkASSERT(currE->fRiteE->fY == y);
- blit_saved_trapezoid(currE,
- y,
- currE->fX,
- currE->fRiteE->fX,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip);
- }
- if (leftE->fRiteE == currE && !isRite) {
- // currE is a right edge previously, but now it's not.
- // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it
- // in the previous if clause). Hence we blit the trapezoid.
- blit_saved_trapezoid(leftE,
- y,
- left,
- currE->fX,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip);
- }
- }
- if (isRite) {
- if (useDeferred) {
- deferred_blit(leftE,
- currE,
- left,
- leftDY,
- y,
- nextY,
- isIntegralNextY,
- leftEnds,
- currEnds,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip,
- yShift);
- } else {
- SkFixed rite = currE->fX;
- currE->goY(nextY, yShift);
- SkFixed nextLeft = SkTMax(leftClip, leftE->fX);
- rite = SkTMin(rightClip, rite);
- SkFixed nextRite = SkTMin(rightClip, currE->fX);
- blit_trapezoid_row(
- blitter,
- y >> 16,
- left,
- rite,
- nextLeft,
- nextRite,
- leftDY,
- currE->fDY,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter || (fullAlpha == 0xFF &&
- (edges_too_close(prevRite, left, leftE->fX) ||
- edges_too_close(currE, currE->fNext, nextY))),
- true);
- prevRite = SkFixedCeilToInt(SkTMax(rite, currE->fX));
- }
- } else {
- if (isLeft) {
- left = SkTMax(currE->fX, leftClip);
- leftDY = currE->fDY;
- leftE = currE;
- leftEnds = leftE->fLowerY == nextY;
- }
- currE->goY(nextY, yShift);
- }
- SkAnalyticEdge* next = currE->fNext;
- SkFixed newX;
- while (currE->fLowerY <= nextY) {
- if (currE->fCurveCount < 0) {
- SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE;
- cubicEdge->keepContinuous();
- if (!cubicEdge->updateCubic()) {
- break;
- }
- } else if (currE->fCurveCount > 0) {
- SkAnalyticQuadraticEdge* quadEdge = (SkAnalyticQuadraticEdge*)currE;
- quadEdge->keepContinuous();
- if (!quadEdge->updateQuadratic()) {
- break;
- }
- } else {
- break;
- }
- }
- SkASSERT(currE->fY == nextY);
- if (currE->fLowerY <= nextY) {
- remove_edge(currE);
- } else {
- update_next_next_y(currE->fLowerY, nextY, &nextNextY);
- newX = currE->fX;
- SkASSERT(currE->fLowerY > nextY);
- if (newX < prevX) { // ripple currE backwards until it is x-sorted
- // If the crossing edge is a right edge, blit the saved trapezoid.
- if (leftE->fRiteE == currE && useDeferred) {
- SkASSERT(leftE->fY == nextY && currE->fY == nextY);
- blit_saved_trapezoid(leftE,
- nextY,
- leftE->fX,
- currE->fX,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip);
- }
- backward_insert_edge_based_on_x(currE);
- } else {
- prevX = newX;
- }
- if (!skipIntersect) {
- check_intersection(currE, nextY, &nextNextY);
- }
- }
- currE = next;
- SkASSERT(currE);
- }
- // was our right-edge culled away?
- if (in_interval) {
- if (useDeferred) {
- deferred_blit(leftE,
- nextTail,
- left,
- leftDY,
- y,
- nextY,
- isIntegralNextY,
- leftEnds,
- false,
- blitter,
- maskRow,
- isUsingMask,
- noRealBlitter,
- leftClip,
- rightClip,
- yShift);
- } else {
- blit_trapezoid_row(blitter,
- y >> 16,
- left,
- rightClip,
- SkTMax(leftClip, leftE->fX),
- rightClip,
- leftDY,
- 0,
- fullAlpha,
- maskRow,
- isUsingMask,
- noRealBlitter || (fullAlpha == 0xFF &&
- edges_too_close(leftE->fPrev, leftE, nextY)),
- true);
- }
- }
- if (forceRLE) {
- ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY);
- }
- y = nextY;
- if (y >= SkIntToFixed(stop_y)) {
- break;
- }
- // now currE points to the first edge with a fUpperY larger than the previous y
- insert_new_edges(currE, y, &nextNextY);
- }
- }
- static SK_ALWAYS_INLINE void aaa_fill_path(
- const SkPath& path,
- const SkIRect& clipRect,
- AdditiveBlitter* blitter,
- int start_y,
- int stop_y,
- bool pathContainedInClip,
- bool isUsingMask,
- bool forceRLE) { // forceRLE implies that SkAAClip is calling us
- SkASSERT(blitter);
- SkAnalyticEdgeBuilder builder;
- int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipRect);
- SkAnalyticEdge** list = builder.analyticEdgeList();
- SkIRect rect = clipRect;
- if (0 == count) {
- if (path.isInverseFillType()) {
- /*
- * Since we are in inverse-fill, our caller has already drawn above
- * our top (start_y) and will draw below our bottom (stop_y). Thus
- * we need to restrict our drawing to the intersection of the clip
- * and those two limits.
- */
- if (rect.fTop < start_y) {
- rect.fTop = start_y;
- }
- if (rect.fBottom > stop_y) {
- rect.fBottom = stop_y;
- }
- if (!rect.isEmpty()) {
- blitter->getRealBlitter()->blitRect(
- rect.fLeft, rect.fTop, rect.width(), rect.height());
- }
- }
- return;
- }
- SkAnalyticEdge headEdge, tailEdge, *last;
- // this returns the first and last edge after they're sorted into a dlink list
- SkAnalyticEdge* edge = sort_edges(list, count, &last);
- headEdge.fRiteE = nullptr;
- headEdge.fPrev = nullptr;
- headEdge.fNext = edge;
- headEdge.fUpperY = headEdge.fLowerY = SK_MinS32;
- headEdge.fX = SK_MinS32;
- headEdge.fDX = 0;
- headEdge.fDY = SK_MaxS32;
- headEdge.fUpperX = SK_MinS32;
- edge->fPrev = &headEdge;
- tailEdge.fRiteE = nullptr;
- tailEdge.fPrev = last;
- tailEdge.fNext = nullptr;
- tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32;
- tailEdge.fX = SK_MaxS32;
- tailEdge.fDX = 0;
- tailEdge.fDY = SK_MaxS32;
- tailEdge.fUpperX = SK_MaxS32;
- last->fNext = &tailEdge;
- // now edge is the head of the sorted linklist
- if (!pathContainedInClip && start_y < clipRect.fTop) {
- start_y = clipRect.fTop;
- }
- if (!pathContainedInClip && stop_y > clipRect.fBottom) {
- stop_y = clipRect.fBottom;
- }
- SkFixed leftBound = SkIntToFixed(rect.fLeft);
- SkFixed rightBound = SkIntToFixed(rect.fRight);
- if (isUsingMask) {
- // If we're using mask, then we have to limit the bound within the path bounds.
- // Otherwise, the edge drift may access an invalid address inside the mask.
- SkIRect ir;
- path.getBounds().roundOut(&ir);
- leftBound = SkTMax(leftBound, SkIntToFixed(ir.fLeft));
- rightBound = SkTMin(rightBound, SkIntToFixed(ir.fRight));
- }
- if (!path.isInverseFillType() && path.isConvex() && count >= 2) {
- aaa_walk_convex_edges(
- &headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask);
- } else {
- // Only use deferred blitting if there are many edges.
- bool useDeferred =
- count >
- (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4;
- // We skip intersection computation if there are many points which probably already
- // give us enough fractional scan lines.
- bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2;
- aaa_walk_edges(&headEdge,
- &tailEdge,
- path.getFillType(),
- blitter,
- start_y,
- stop_y,
- leftBound,
- rightBound,
- isUsingMask,
- forceRLE,
- useDeferred,
- skipIntersect);
- }
- }
- void SkScan::AAAFillPath(const SkPath& path,
- SkBlitter* blitter,
- const SkIRect& ir,
- const SkIRect& clipBounds,
- bool forceRLE) {
- bool containedInClip = clipBounds.contains(ir);
- bool isInverse = path.isInverseFillType();
- // The mask blitter (where we store intermediate alpha values directly in a mask, and then call
- // the real blitter once in the end to blit the whole mask) is faster than the RLE blitter when
- // the blit region is small enough (i.e., CanHandleRect(ir)). When isInverse is true, the blit
- // region is no longer the rectangle ir so we won't use the mask blitter. The caller may also
- // use the forceRLE flag to force not using the mask blitter. Also, when the path is a simple
- // rect, preparing a mask and blitting it might have too much overhead. Hence we'll use
- // blitFatAntiRect to avoid the mask and its overhead.
- if (MaskAdditiveBlitter::CanHandleRect(ir) && !isInverse && !forceRLE) {
- // blitFatAntiRect is slower than the normal AAA flow without MaskAdditiveBlitter.
- // Hence only tryBlitFatAntiRect when MaskAdditiveBlitter would have been used.
- if (!TryBlitFatAntiRect(blitter, path, clipBounds)) {
- MaskAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
- aaa_fill_path(path,
- clipBounds,
- &additiveBlitter,
- ir.fTop,
- ir.fBottom,
- containedInClip,
- true,
- forceRLE);
- }
- } else if (!isInverse && path.isConvex()) {
- // If the filling area is convex (i.e., path.isConvex && !isInverse), our simpler
- // aaa_walk_convex_edges won't generate alphas above 255. Hence we don't need
- // SafeRLEAdditiveBlitter (which is slow due to clamping). The basic RLE blitter
- // RunBasedAdditiveBlitter would suffice.
- RunBasedAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
- aaa_fill_path(path,
- clipBounds,
- &additiveBlitter,
- ir.fTop,
- ir.fBottom,
- containedInClip,
- false,
- forceRLE);
- } else {
- // If the filling area might not be convex, the more involved aaa_walk_edges would
- // be called and we have to clamp the alpha downto 255. The SafeRLEAdditiveBlitter
- // does that at a cost of performance.
- SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
- aaa_fill_path(path,
- clipBounds,
- &additiveBlitter,
- ir.fTop,
- ir.fBottom,
- containedInClip,
- false,
- forceRLE);
- }
- }
- #endif // defined(SK_DISABLE_AAA)
|