1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScanPriv.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMatrix.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h" 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkAntiRun.h" 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SHIFT 2 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SCALE (1 << SHIFT) 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MASK (SCALE - 1) 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/** @file 222f3567c0003b948ad90528e597ea1e8326f644aereed@google.com We have two techniques for capturing the output of the supersampler: 232f3567c0003b948ad90528e597ea1e8326f644aereed@google.com - SUPERMASK, which records a large mask-bitmap 242f3567c0003b948ad90528e597ea1e8326f644aereed@google.com this is often faster for small, complex objects 252f3567c0003b948ad90528e597ea1e8326f644aereed@google.com - RLE, which records a rle-encoded scanline 262f3567c0003b948ad90528e597ea1e8326f644aereed@google.com this is often faster for large objects with big spans 272f3567c0003b948ad90528e597ea1e8326f644aereed@google.com 2805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com These blitters use two coordinate systems: 2905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com - destination coordinates, scale equal to the output - often 3005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com abbreviated with 'i' or 'I' in variable names 3105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com - supersampled coordinates, scale equal to the output * SCALE 322f3567c0003b948ad90528e597ea1e8326f644aereed@google.com */ 335b7d603e179a38735056db5f9092d18c187e76a0reed@google.com 349f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_SUPERMASK 359f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_RLE 369f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 379f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com/////////////////////////////////////////////////////////////////////////////// 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Base class for a single-pass supersampled blitter. 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass BaseSuperBlitter : public SkBlitter { 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, 43bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed const SkRegion& clip, bool isInverse); 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Must be explicitly defined on subclasses. 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual void blitAntiH(int x, int y, const SkAlpha antialias[], 4736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein const int16_t runs[]) override { 480c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("How did I get here?"); 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// May not be called on BaseSuperBlitter because it blits out of order. 5136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void blitV(int x, int y, int height, SkAlpha alpha) override { 520c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("How did I get here?"); 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected: 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* fRealBlitter; 5705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Current y coordinate, in destination coordinates. 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int fCurrIY; 5905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Widest row of region to be blitted, in destination coordinates. 6005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fWidth; 6105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Leftmost x coordinate in any row, in destination coordinates. 6205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fLeft; 6305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Leftmost x coordinate in any row, in supersampled coordinates. 6405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fSuperLeft; 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(int fCurrX;) 6705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Current y coordinate in supersampled coordinates. 68fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com int fCurrY; 6905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Initial y coordinate (top of bounds). 70045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com int fTop; 71bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed 72bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed SkIRect fSectBounds; 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 75bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedBaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlit, const SkIRect& ir, const SkRegion& clip, 76bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed bool isInverse) { 77bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed fRealBlitter = realBlit; 78bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed 79bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed SkIRect sectBounds; 80bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 81c553b7a7172bab052eed8432856c85fd01601b27reed // We use the clip bounds instead of the ir, since we may be asked to 82c553b7a7172bab052eed8432856c85fd01601b27reed //draw outside of the rect when we're a inverse filltype 83bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed sectBounds = clip.getBounds(); 84bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed } else { 85bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (!sectBounds.intersect(ir, clip.getBounds())) { 86bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed sectBounds.setEmpty(); 87bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed } 88bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed } 8955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 90bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed const int left = sectBounds.left(); 91bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed const int right = sectBounds.right(); 92fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLeft = left; 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSuperLeft = left << SHIFT; 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fWidth = right - left; 96bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed fTop = sectBounds.top(); 97bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed fCurrIY = fTop - 1; 98bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed fCurrY = (fTop << SHIFT) - 1; 99bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed 10034e52a0392f146b62f46cfe6714d9bddbb8d9e77reed@google.com SkDEBUGCODE(fCurrX = -1;) 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Run-length-encoded supersampling antialiased blitter. 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SuperBlitter : public BaseSuperBlitter { 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 106bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse); 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual ~SuperBlitter() { 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->flush(); 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Once fRuns contains a complete supersampled row, flush() blits 11305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// it out through the wrapped blitter. 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com void flush(); 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11605fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Blits a row of pixels, with location and width specified 11705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// in supersampled coordinates. 11836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void blitH(int x, int y, int width) override; 11905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// Blits a rectangle of pixels, with location and size specified 12005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com /// in supersampled coordinates. 12136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void blitRect(int x, int y, int width, int height) override; 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate: 1242ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // The next three variables are used to track a circular buffer that 1252ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // contains the values used in SkAlphaRuns. These variables should only 1262ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // ever be updated in advanceRuns(), and fRuns should always point to 1272ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // a valid SkAlphaRuns... 1282ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski int fRunsToBuffer; 1292ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski void* fRunsBuffer; 1302ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski int fCurrentRun; 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkAlphaRuns fRuns; 1322ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski 1332ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // extra one to store the zero at the end 1342ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); } 1352ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski 1362ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // This function updates the fRuns variable to point to the next buffer space 1372ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun 1382ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // and resets fRuns to point to an empty scanline. 1392ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski void advanceRuns() { 1402ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski const size_t kRunsSz = this->getRunsSz(); 1412ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer; 1422ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fRuns.fRuns = reinterpret_cast<int16_t*>( 1432ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz); 1442ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1); 1452ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fRuns.reset(fWidth); 1462ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski } 1472ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski 148fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com int fOffsetX; 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 151bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedSuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, 152bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed bool isInverse) 153bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed : BaseSuperBlitter(realBlitter, ir, clip, isInverse) 154bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed{ 1552ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fRunsToBuffer = realBlitter->requestRowsPreserved(); 15675f88512a1b74ebb1bbb4f0046e43f1a5a234320krajcevski fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz()); 1572ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski fCurrentRun = -1; 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1592ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski this->advanceRuns(); 160fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com 161fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com fOffsetX = 0; 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1649f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid SuperBlitter::flush() { 165045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fCurrIY >= fTop) { 1662ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski 1672ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski SkASSERT(fCurrentRun < fRunsToBuffer); 1689f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (!fRuns.empty()) { 1692ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski // SkDEBUGCODE(fRuns.dump();) 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns); 1712ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski this->advanceRuns(); 172fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com fOffsetX = 0; 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1742ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski 175045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fCurrIY = fTop - 1; 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(fCurrX = -1;) 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 180ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com/** coverage_to_partial_alpha() is being used by SkAlphaRuns, which 181ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com *accumulates* SCALE pixels worth of "alpha" in [0,(256/SCALE)] 182ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com to produce a final value in [0, 255] and handles clamping 256->255 183ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com itself, with the same (alpha - (alpha >> 8)) correction as 184ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com coverage_to_exact_alpha(). 185ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com*/ 186ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.comstatic inline int coverage_to_partial_alpha(int aa) { 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa <<= 8 - 2*SHIFT; 1885b7d603e179a38735056db5f9092d18c187e76a0reed@google.com return aa; 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 191ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com/** coverage_to_exact_alpha() is being used by our blitter, which wants 192ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com a final value in [0, 255]. 193ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com*/ 19449eac192faa35159752525b23345563252721c64tomhudson@google.comstatic inline int coverage_to_exact_alpha(int aa) { 19531bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com int alpha = (256 >> SHIFT) * aa; 19631bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com // clamp 256->255 19731bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com return alpha - (alpha >> 8); 19849eac192faa35159752525b23345563252721c64tomhudson@google.com} 19949eac192faa35159752525b23345563252721c64tomhudson@google.com 2009f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid SuperBlitter::blitH(int x, int y, int width) { 201967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com SkASSERT(width > 0); 202967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int iy = y >> SHIFT; 2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(iy >= fCurrIY); 2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x -= fSuperLeft; 2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // hack, until I figure out why my cubics (I think) go beyond the bounds 2089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (x < 0) { 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com width += x; 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x = 0; 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(y != fCurrY || x >= fCurrX); 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 216fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com SkASSERT(y >= fCurrY); 217fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com if (fCurrY != y) { 218fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com fOffsetX = 0; 219fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com fCurrY = y; 220fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com } 221fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2229f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (iy != fCurrIY) { // new scanline 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->flush(); 2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurrIY = iy; 2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2275a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com int start = x; 2285a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com int stop = x + width; 2295a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com 2305a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com SkASSERT(start >= 0 && stop > start); 23105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com // integer-pixel-aligned ends of blit, rounded out 23205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fb = start & MASK; 23305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fe = stop & MASK; 2345a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com int n = (stop >> SHIFT) - (start >> SHIFT) - 1; 2355a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com 2365a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com if (n < 0) { 2375a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com fb = fe - fb; 2385a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com n = 0; 2395a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com fe = 0; 2405a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com } else { 2415a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com if (fb == 0) { 2425a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com n += 1; 2439f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } else { 24449eac192faa35159752525b23345563252721c64tomhudson@google.com fb = SCALE - fb; 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 247fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com 248ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb), 249ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com n, coverage_to_partial_alpha(fe), 250fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT), 251fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com fOffsetX); 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRuns.assertValid(y & MASK, (1 << (8 - SHIFT))); 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurrX = x + width; 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 259803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#if 0 // UNUSED 260a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.comstatic void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA, 261a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com int n, U8CPU riteA) { 262a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com SkASSERT(leftA <= 0xFF); 263a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com SkASSERT(riteA <= 0xFF); 264a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 265a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com int16_t* run = runs.fRuns; 266a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com uint8_t* aa = runs.fAlpha; 267a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 268a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com if (ileft > 0) { 269a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com run[0] = ileft; 270a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com aa[0] = 0; 271a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com run += ileft; 272a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com aa += ileft; 273a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com } 274a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 275a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com SkASSERT(leftA < 0xFF); 276a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com if (leftA > 0) { 277a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com *run++ = 1; 278a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com *aa++ = leftA; 279a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com } 280a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 281a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com if (n > 0) { 282a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com run[0] = n; 283a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com aa[0] = 0xFF; 284a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com run += n; 285a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com aa += n; 286a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com } 287a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 288a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com SkASSERT(riteA < 0xFF); 289a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com if (riteA > 0) { 290a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com *run++ = 1; 291a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com *aa++ = riteA; 292a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com } 293a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com run[0] = 0; 294a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com} 295803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#endif 296a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com 297967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.comvoid SuperBlitter::blitRect(int x, int y, int width, int height) { 298967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com SkASSERT(width > 0); 299967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com SkASSERT(height > 0); 300967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 30105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com // blit leading rows 30205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com while ((y & MASK)) { 303967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com this->blitH(x, y++, width); 304967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com if (--height <= 0) { 305967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com return; 306967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } 307967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } 308967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com SkASSERT(height > 0); 309967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 31005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com // Since this is a rect, instead of blitting supersampled rows one at a 31105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com // time and then resolving to the destination canvas, we can blit 31205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com // directly to the destintion canvas one row per SCALE supersampled rows. 313967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int start_y = y >> SHIFT; 314967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int stop_y = (y + height) >> SHIFT; 315967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int count = stop_y - start_y; 316967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com if (count > 0) { 317967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com y += count << SHIFT; 318967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com height -= count << SHIFT; 319967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 320967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com // save original X for our tail blitH() loop at the bottom 321967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int origX = x; 322967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 323967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com x -= fSuperLeft; 324967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com // hack, until I figure out why my cubics (I think) go beyond the bounds 325967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com if (x < 0) { 326967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com width += x; 327967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com x = 0; 328967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } 329967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 33049eac192faa35159752525b23345563252721c64tomhudson@google.com // There is always a left column, a middle, and a right column. 33149eac192faa35159752525b23345563252721c64tomhudson@google.com // ileft is the destination x of the first pixel of the entire rect. 33249eac192faa35159752525b23345563252721c64tomhudson@google.com // xleft is (SCALE - # of covered supersampled pixels) in that 33349eac192faa35159752525b23345563252721c64tomhudson@google.com // destination pixel. 334967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int ileft = x >> SHIFT; 33505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int xleft = x & MASK; 33649eac192faa35159752525b23345563252721c64tomhudson@google.com // irite is the destination x of the last pixel of the OPAQUE section. 33749eac192faa35159752525b23345563252721c64tomhudson@google.com // xrite is the number of supersampled pixels extending beyond irite; 33849eac192faa35159752525b23345563252721c64tomhudson@google.com // xrite/SCALE should give us alpha. 339967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int irite = (x + width) >> SHIFT; 34005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int xrite = (x + width) & MASK; 34149eac192faa35159752525b23345563252721c64tomhudson@google.com if (!xrite) { 34249eac192faa35159752525b23345563252721c64tomhudson@google.com xrite = SCALE; 34349eac192faa35159752525b23345563252721c64tomhudson@google.com irite--; 34449eac192faa35159752525b23345563252721c64tomhudson@google.com } 34549eac192faa35159752525b23345563252721c64tomhudson@google.com 3464714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // Need to call flush() to clean up pending draws before we 3474714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // even consider blitV(), since otherwise it can look nonmonotonic. 3484714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com SkASSERT(start_y > fCurrIY); 3494714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com this->flush(); 3504714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com 351967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com int n = irite - ileft - 1; 352967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com if (n < 0) { 3534714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // If n < 0, we'll only have a single partially-transparent column 3544714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // of pixels to render. 355967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com xleft = xrite - xleft; 35649eac192faa35159752525b23345563252721c64tomhudson@google.com SkASSERT(xleft <= SCALE); 35749eac192faa35159752525b23345563252721c64tomhudson@google.com SkASSERT(xleft > 0); 358967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com xrite = 0; 35949eac192faa35159752525b23345563252721c64tomhudson@google.com fRealBlitter->blitV(ileft + fLeft, start_y, count, 36049eac192faa35159752525b23345563252721c64tomhudson@google.com coverage_to_exact_alpha(xleft)); 361967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } else { 3624714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // With n = 0, we have two possibly-transparent columns of pixels 3634714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // to render; with n > 0, we have opaque columns between them. 3644714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com 36549eac192faa35159752525b23345563252721c64tomhudson@google.com xleft = SCALE - xleft; 366967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 3674714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com // Using coverage_to_exact_alpha is not consistent with blitH() 3684714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com const int coverageL = coverage_to_exact_alpha(xleft); 3694714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com const int coverageR = coverage_to_exact_alpha(xrite); 37049eac192faa35159752525b23345563252721c64tomhudson@google.com 3714714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com SkASSERT(coverageL > 0 || n > 0 || coverageR > 0); 3724714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth); 373967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 3744714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count, 3754714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com coverageL, coverageR); 3764714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com } 377967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 378967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com // preamble for our next call to blitH() 379967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com fCurrIY = stop_y - 1; 380967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com fOffsetX = 0; 381967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com fCurrY = y - 1; 382967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com fRuns.reset(fWidth); 383967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com x = origX; 384967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } 385967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 38649eac192faa35159752525b23345563252721c64tomhudson@google.com // catch any remaining few rows 38705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com SkASSERT(height <= MASK); 388967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com while (--height >= 0) { 389967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com this->blitH(x, y++, width); 390967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com } 391967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com} 392967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 39505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Masked supersampling antialiased blitter. 3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass MaskSuperBlitter : public BaseSuperBlitter { 3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 398bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion&, bool isInverse); 3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual ~MaskSuperBlitter() { 4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRealBlitter->blitMask(fMask, fClipRect); 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 40336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void blitH(int x, int y, int width) override; 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com static bool CanHandleRect(const SkIRect& bounds) { 4069f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_RLE 4079f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com return false; 4089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width = bounds.width(); 410f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com int64_t rb = SkAlign4(width); 411f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com // use 64bits to detect overflow 412f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com int64_t storage = rb * bounds.height(); 41355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (width <= MaskSuperBlitter::kMAX_WIDTH) && 415f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com (storage <= MaskSuperBlitter::kMAX_STORAGE); 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 41755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate: 4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com enum { 4209f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_SUPERMASK 4219f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com kMAX_WIDTH = 2048, 4229f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com kMAX_STORAGE = 1024 * 1024 * 2 4239f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#else 4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster 4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com kMAX_STORAGE = 1024 4269f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com }; 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask fMask; 4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect fClipRect; 4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // perform a test to see if stopAlpha != 0 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t fStorage[(kMAX_STORAGE >> 2) + 1]; 4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 436bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedMaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, 437bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed bool isInverse) 438bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed : BaseSuperBlitter(realBlitter, ir, clip, isInverse) 439bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed{ 4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(CanHandleRect(ir)); 441bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed SkASSERT(!isInverse); 4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMask.fImage = (uint8_t*)fStorage; 4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMask.fBounds = ir; 4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMask.fRowBytes = ir.width(); 4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMask.fFormat = SkMask::kA8_Format; 447fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fClipRect = ir; 449f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips if (!fClipRect.intersect(clip.getBounds())) { 450f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips SkASSERT(0); 451f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips fClipRect.setEmpty(); 452f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips } 45355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // For valgrind, write 1 extra byte at the end so we don't read 4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // uninitialized memory. See comment in add_aa_span and fStorage[]. 4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1); 4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4599f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha) { 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* I should be able to just add alpha[x] + startAlpha. 4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com However, if the trailing edge of the previous span and the leading 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com edge of the current span round to the same super-sampled x value, 4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com I might overflow to 256 with this add, hence the funny subtract. 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned tmp = *alpha + startAlpha; 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(tmp <= 256); 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *alpha = SkToU8(tmp - (tmp >> 8)); 4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4709f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic inline uint32_t quadplicate_byte(U8CPU value) { 4719f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com uint32_t pair = (value << 8) | value; 4729f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com return (pair << 16) | pair; 4739f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com} 4749f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 4756997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// Perform this tricky subtract, to avoid overflowing to 256. Our caller should 4766997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// only ever call us with at most enough to hit 256 (never larger), so it is 4776997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// enough to just subtract the high-bit. Actually clamping with a branch would 4786997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// be slower (e.g. if (tmp > 255) tmp = 255;) 4796997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// 4806997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.comstatic inline void saturated_add(uint8_t* ptr, U8CPU add) { 4816997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com unsigned tmp = *ptr + add; 4826997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com SkASSERT(tmp <= 256); 4836997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com *ptr = SkToU8(tmp - (tmp >> 8)); 4846997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com} 4856997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com 4869f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com// minimum count before we want to setup an inner loop, adding 4-at-a-time 4879f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#define MIN_COUNT_FOR_QUAD_LOOP 16 4889f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 4899f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, 4909f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com U8CPU stopAlpha, U8CPU maxValue) { 4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(middleCount >= 0); 4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4936997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com saturated_add(alpha, startAlpha); 4946997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com alpha += 1; 4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4969f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) { 4979f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com // loop until we're quad-byte aligned 4989f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com while (SkTCast<intptr_t>(alpha) & 0x3) { 4999f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com alpha[0] = SkToU8(alpha[0] + maxValue); 5009f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com alpha += 1; 5019f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com middleCount -= 1; 5029f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } 5039f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 5049f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com int bigCount = middleCount >> 2; 5059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha); 5069f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com uint32_t qval = quadplicate_byte(maxValue); 5079f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com do { 5089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com *qptr++ += qval; 5099f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } while (--bigCount > 0); 5109f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 5119f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com middleCount &= 3; 5129f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com alpha = reinterpret_cast<uint8_t*> (qptr); 5139f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com // fall through to the following while-loop 5149f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } 5159f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com 5169f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com while (--middleCount >= 0) { 5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com alpha[0] = SkToU8(alpha[0] + maxValue); 5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com alpha += 1; 5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // potentially this can be off the end of our "legal" alpha values, but that 5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0 5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // every time (slow), we just do it, and ensure that we've allocated extra space 5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // (see the + 1 comment in fStorage[] 5256997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com saturated_add(alpha, stopAlpha); 5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5289f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid MaskSuperBlitter::blitH(int x, int y, int width) { 5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int iy = (y >> SHIFT); 53055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom); 5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com iy -= fMask.fBounds.fTop; // make it relative to 0 5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 534c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org // This should never happen, but it does. Until the true cause is 535c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org // discovered, let's skip this span instead of crashing. 536c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org // See http://crbug.com/17569. 537c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org if (iy < 0) { 538c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org return; 539c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org } 540c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org 5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int ix = x >> SHIFT; 5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight); 5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 54755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x -= (fMask.fBounds.fLeft << SHIFT); 5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // hack, until I figure out why my cubics (I think) go beyond the bounds 5519f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (x < 0) { 5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com width += x; 5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x = 0; 5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT); 5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int start = x; 5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int stop = x + width; 5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(start >= 0 && stop > start); 56205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fb = start & MASK; 56305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com int fe = stop & MASK; 5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int n = (stop >> SHIFT) - (start >> SHIFT) - 1; 5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5679f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (n < 0) { 568feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org SkASSERT(row >= fMask.fImage); 569feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1); 570ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com add_aa_span(row, coverage_to_partial_alpha(fe - fb)); 5719f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } else { 57249eac192faa35159752525b23345563252721c64tomhudson@google.com fb = SCALE - fb; 573feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org SkASSERT(row >= fMask.fImage); 574feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1); 575ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com add_aa_span(row, coverage_to_partial_alpha(fb), 576ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com n, coverage_to_partial_alpha(fe), 5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT)); 5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCurrX = x + width; 5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 58707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool fitsInsideLimit(const SkRect& r, SkScalar max) { 58807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com const SkScalar min = -max; 58907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com return r.fLeft > min && r.fTop > min && 59007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com r.fRight < max && r.fBottom < max; 59107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com} 59207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com 59317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int overflows_short_shift(int value, int shift) { 59417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com const int s = 16 + shift; 59517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com return (value << s >> s) - value; 59617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com} 59717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com 59817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com/** 59917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com Would any of the coordinates of this rectangle not fit in a short, 60017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com when left-shifted by shift? 60117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com*/ 60217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int rect_overflows_short_shift(SkIRect rect, int shift) { 60317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkASSERT(!overflows_short_shift(8191, SHIFT)); 60417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkASSERT(overflows_short_shift(8192, SHIFT)); 60517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkASSERT(!overflows_short_shift(32767, 0)); 60617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkASSERT(overflows_short_shift(32768, 0)); 60717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com 60817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // Since we expect these to succeed, we bit-or together 60917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // for a tiny extra bit of speed. 61017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com return overflows_short_shift(rect.fLeft, SHIFT) | 61117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com overflows_short_shift(rect.fRight, SHIFT) | 61217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com overflows_short_shift(rect.fTop, SHIFT) | 61317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com overflows_short_shift(rect.fBottom, SHIFT); 61417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com} 61517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com 61607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) { 61707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com const SkScalar maxScalar = SkIntToScalar(maxInt); 6188f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com 61907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com if (fitsInsideLimit(src, maxScalar)) { 62007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com src.roundOut(dst); 62107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com return true; 62207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com } 62307db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com return false; 6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6265546ef2dd9edad601383b85907f677118f857332reed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, 6272c508f2dc22027d61437b79326297ba055041561reed@google.com SkBlitter* blitter, bool forceRLE) { 6285546ef2dd9edad601383b85907f677118f857332reed@google.com if (origClip.isEmpty()) { 6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 632bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed const bool isInverse = path.isInverseFillType(); 633d252db03d9650013b545ef9781fe993c07f8f314reed@android.com SkIRect ir; 63407db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com 63507db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) { 63607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#if 0 63707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com const SkRect& r = path.getBounds(); 63807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com SkDebugf("--- bounds can't fit in SkIRect\n", r.fLeft, r.fTop, r.fRight, r.fBottom); 63907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#endif 64007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com return; 64107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com } 6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (ir.isEmpty()) { 643bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 6445546ef2dd9edad601383b85907f677118f857332reed@google.com blitter->blitRegion(origClip); 645ee068aae552e8cfb3e23f9c972a377e75a07e822reed@google.com } 6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 64917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // If the intersection of the path bounds and the clip bounds 65017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // will overflow 32767 when << by SHIFT, we can't supersample, 65117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // so draw without antialiasing. 65217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkIRect clippedIR; 653bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 65417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // If the path is an inverse fill, it's going to fill the entire 65517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // clip, and we care whether the entire clip exceeds our limits. 65617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com clippedIR = origClip.getBounds(); 65717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com } else { 65817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com if (!clippedIR.intersect(ir, origClip.getBounds())) { 65917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com return; 66017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com } 66117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com } 66217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com if (rect_overflows_short_shift(clippedIR, SHIFT)) { 66317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com SkScan::FillPath(path, origClip, blitter); 66417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com return; 66517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com } 66617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com 6675546ef2dd9edad601383b85907f677118f857332reed@google.com // Our antialiasing can't handle a clip larger than 32767, so we restrict 6685546ef2dd9edad601383b85907f677118f857332reed@google.com // the clip to that limit here. (the runs[] uses int16_t for its index). 6695546ef2dd9edad601383b85907f677118f857332reed@google.com // 67017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // A more general solution (one that could also eliminate the need to 67117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // disable aa based on ir bounds (see overflows_short_shift) would be 67217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com // to tile the clip/target... 6735546ef2dd9edad601383b85907f677118f857332reed@google.com SkRegion tmpClipStorage; 6745546ef2dd9edad601383b85907f677118f857332reed@google.com const SkRegion* clipRgn = &origClip; 6755546ef2dd9edad601383b85907f677118f857332reed@google.com { 6765546ef2dd9edad601383b85907f677118f857332reed@google.com static const int32_t kMaxClipCoord = 32767; 6775546ef2dd9edad601383b85907f677118f857332reed@google.com const SkIRect& bounds = origClip.getBounds(); 6785546ef2dd9edad601383b85907f677118f857332reed@google.com if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { 6795546ef2dd9edad601383b85907f677118f857332reed@google.com SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; 6805546ef2dd9edad601383b85907f677118f857332reed@google.com tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); 6815546ef2dd9edad601383b85907f677118f857332reed@google.com clipRgn = &tmpClipStorage; 6825546ef2dd9edad601383b85907f677118f857332reed@google.com } 6835546ef2dd9edad601383b85907f677118f857332reed@google.com } 6845546ef2dd9edad601383b85907f677118f857332reed@google.com // for here down, use clipRgn, not origClip 6855546ef2dd9edad601383b85907f677118f857332reed@google.com 6865546ef2dd9edad601383b85907f677118f857332reed@google.com SkScanClipper clipper(blitter, clipRgn, ir); 6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkIRect* clipRect = clipper.getClipRect(); 6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clipper.getBlitter() == NULL) { // clipped out 690bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 6915546ef2dd9edad601383b85907f677118f857332reed@google.com blitter->blitRegion(*clipRgn); 6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 69555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now use the (possibly wrapped) blitter 6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter = clipper.getBlitter(); 6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 699bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 7005546ef2dd9edad601383b85907f677118f857332reed@google.com sk_blit_above(blitter, ir, *clipRgn); 7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect superRect, *superClipRect = NULL; 7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com if (clipRect) { 7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT, 7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT); 7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com superClipRect = &superRect; 7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 711c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); 712c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org 7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it 7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // if we're an inverse filltype 715bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (!isInverse && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) { 716bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed MaskSuperBlitter superBlit(blitter, ir, *clipRgn, isInverse); 717c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); 7185546ef2dd9edad601383b85907f677118f857332reed@google.com sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); 7199f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com } else { 720bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed SuperBlitter superBlit(blitter, ir, *clipRgn, isInverse); 7215546ef2dd9edad601383b85907f677118f857332reed@google.com sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); 7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 72355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com 724bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed if (isInverse) { 7255546ef2dd9edad601383b85907f677118f857332reed@google.com sk_blit_below(blitter, ir, *clipRgn); 72655b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com } 7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7281ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7291ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com/////////////////////////////////////////////////////////////////////////////// 7301ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7311ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com#include "SkRasterClip.h" 7321ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7331ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, 7341ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkBlitter* blitter) { 7351ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com if (clip.isEmpty()) { 7361ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com return; 7371ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } 738fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7391ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com if (clip.isBW()) { 7401ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com FillPath(path, clip.bwRgn(), blitter); 7411ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } else { 7421ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkRegion tmp; 7431ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkAAClipBlitter aaBlitter; 744fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7451ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com tmp.setRect(clip.getBounds()); 7461ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com aaBlitter.init(blitter, &clip.aaRgn()); 7471ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkScan::FillPath(path, tmp, &aaBlitter); 7481ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } 7491ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com} 7501ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7511ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip, 7521ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkBlitter* blitter) { 7531ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com if (clip.isEmpty()) { 7541ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com return; 7551ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } 7561ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7571ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com if (clip.isBW()) { 7581ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com AntiFillPath(path, clip.bwRgn(), blitter); 7591ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } else { 7601ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkRegion tmp; 7611ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkAAClipBlitter aaBlitter; 7621ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com 7631ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com tmp.setRect(clip.getBounds()); 7641ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com aaBlitter.init(blitter, &clip.aaRgn()); 7651ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com SkScan::AntiFillPath(path, tmp, &aaBlitter, true); 7661ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com } 7671ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com} 768