1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 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 "SkScan.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h" 13e28ff55d980d2992618b6b721c848aba96cf759areed@android.com#include "SkLineClipper.h" 14045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFDot6.h" 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com/* Our attempt to compute the worst case "bounds" for the horizontal and 188898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com vertical cases has some numerical bug in it, and we sometimes undervalue 198898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com our extends. The bug is that when this happens, we will set the clip to 208898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com NULL (for speed), and thus draw outside of the clip by a pixel, which might 218898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com only look bad, but it might also access memory outside of the valid range 228898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com allcoated for the device bitmap. 236c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com 248898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com This define enables our fix to outset our "bounds" by 1, thus avoiding the 258898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com chance of the bug, but at the cost of sometimes taking the rectblitter 268898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com case (i.e. not setting the clip to NULL) when we might not actually need 278898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com to. If we can improve/fix the actual calculations, then we can remove this 288898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com step. 298898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com */ 308898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com#define OUTSET_BEFORE_CLIP_TEST true 318898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define HLINE_STACK_BUFFER 100 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int SmallDot6Scale(int value, int dot6) { 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((int16_t)value == value); 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)dot6 <= 64); 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return SkMulS16(value, dot6) >> 6; 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//#define TEST_GAMMA 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef TEST_GAMMA 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static uint8_t gGammaTable[256]; 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com #define ApplyGamma(table, alpha) (table)[alpha] 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 46bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org static void build_gamma_table() { 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static bool gInit = false; 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 49bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (gInit == false) { 50bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org for (int i = 0; i < 256; i++) { 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed n = i * 257; 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n += n >> 15; 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(n >= 0 && n <= SK_Fixed1); 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n = SkFixedSqrt(n); 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n = n * 255 >> 16; 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // SkDebugf("morph %d -> %d\n", i, n); 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com gGammaTable[i] = SkToU8(n); 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com gInit = true; 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com #define ApplyGamma(table, alpha) SkToU8(alpha) 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 68bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, 69bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org U8CPU alpha) { 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(count > 0); 7127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int16_t runs[HLINE_STACK_BUFFER + 1]; 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t aa[HLINE_STACK_BUFFER]; 7427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa[0] = ApplyGamma(gGammaTable, alpha); 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int n = count; 78bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (n > HLINE_STACK_BUFFER) { 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n = HLINE_STACK_BUFFER; 80bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com runs[0] = SkToS16(n); 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com runs[n] = 0; 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitAntiH(x, y, aa, runs); 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com x += n; 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count -= n; 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (count > 0); 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 89b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass SkAntiHairBlitter { 90b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic: 91b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkAntiHairBlitter() : fBlitter(NULL) {} 92ade109f57c64f4fbc048cd77abaf4c539e010557djsollen@google.com virtual ~SkAntiHairBlitter() {} 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 94b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkBlitter* getBlitter() const { return fBlitter; } 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 96b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com void setup(SkBlitter* blitter) { 97b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fBlitter = blitter; 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 100b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0; 101b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0; 102fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 103b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comprivate: 104b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkBlitter* fBlitter; 105b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com}; 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 107b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass HLine_SkAntiHairBlitter : public SkAntiHairBlitter { 108b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic: 109b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) SK_OVERRIDE { 110b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fy += SK_Fixed1/2; 11127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 112b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int y = fy >> 16; 113b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t a = (uint8_t)(fy >> 8); 11427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 115b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // lower line 116b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com unsigned ma = SmallDot6Scale(a, mod64); 117b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (ma) { 118b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com call_hline_blitter(this->getBlitter(), x, y, 1, ma); 119b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 12027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 121b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // upper line 122b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com ma = SmallDot6Scale(255 - a, mod64); 123b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (ma) { 124b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma); 125b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 12627b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 127b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fy - SK_Fixed1/2; 128b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 130b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, 131b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkFixed slope) SK_OVERRIDE { 132b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(x < stopx); 133b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int count = stopx - x; 134b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fy += SK_Fixed1/2; 13527b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 136b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int y = fy >> 16; 137b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t a = (uint8_t)(fy >> 8); 13827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 139b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // lower line 140b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 141b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com call_hline_blitter(this->getBlitter(), x, y, count, a); 142b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 14327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 144b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // upper line 145b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com a = 255 - a; 146b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 147b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com call_hline_blitter(this->getBlitter(), x, y - 1, count, a); 148b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 14927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 150b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fy - SK_Fixed1/2; 151b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 152b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com}; 153b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com 154b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass Horish_SkAntiHairBlitter : public SkAntiHairBlitter { 155b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic: 156b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) SK_OVERRIDE { 157b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int16_t runs[2]; 158b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t aa[1]; 15927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 160b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[0] = 1; 161b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[1] = 0; 16227b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 163b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fy += SK_Fixed1/2; 164b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkBlitter* blitter = this->getBlitter(); 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int lower_y = fy >> 16; 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t a = (uint8_t)(fy >> 8); 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned ma = SmallDot6Scale(a, mod64); 169bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (ma) { 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa[0] = ApplyGamma(gamma, ma); 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitAntiH(x, lower_y, aa, runs); 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // the clipping blitters might edit runs, but should not affect us 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[0] == 1); 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[1] == 0); 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ma = SmallDot6Scale(255 - a, mod64); 177bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (ma) { 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa[0] = ApplyGamma(gamma, ma); 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitAntiH(x, lower_y - 1, aa, runs); 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // the clipping blitters might edit runs, but should not affect us 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[0] == 1); 1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[1] == 0); 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fy += dy; 18527b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 186b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fy - SK_Fixed1/2; 187bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 18827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 189b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) SK_OVERRIDE { 190b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(x < stopx); 19127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 192b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int16_t runs[2]; 193b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t aa[1]; 19427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 195b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[0] = 1; 196b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[1] = 0; 19727b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 198b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fy += SK_Fixed1/2; 199b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkBlitter* blitter = this->getBlitter(); 200b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com do { 201b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int lower_y = fy >> 16; 202b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t a = (uint8_t)(fy >> 8); 203b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 204b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[0] = a; 205b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com blitter->blitAntiH(x, lower_y, aa, runs); 206b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // the clipping blitters might edit runs, but should not affect us 207b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[0] == 1); 208b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[1] == 0); 209b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 210b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com a = 255 - a; 211b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 212b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[0] = a; 213b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com blitter->blitAntiH(x, lower_y - 1, aa, runs); 214b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // the clipping blitters might edit runs, but should not affect us 215b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[0] == 1); 216b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[1] == 0); 217b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 218b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fy += dy; 219b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } while (++x < stopx); 22027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 221b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fy - SK_Fixed1/2; 222b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 223b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com}; 224b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com 225b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass VLine_SkAntiHairBlitter : public SkAntiHairBlitter { 226b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic: 227b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE { 228b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(0 == dx); 229b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fx += SK_Fixed1/2; 23027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 231b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int x = fx >> 16; 232b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int a = (uint8_t)(fx >> 8); 23327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 234b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com unsigned ma = SmallDot6Scale(a, mod64); 235b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (ma) { 236b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitV(x, y, 1, ma); 237b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 238b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com ma = SmallDot6Scale(255 - a, mod64); 239b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (ma) { 240b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitV(x - 1, y, 1, ma); 241b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 24227b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 243b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fx - SK_Fixed1/2; 244bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 245fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 246b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE { 247b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(y < stopy); 248b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(0 == dx); 249b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fx += SK_Fixed1/2; 25027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 251b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int x = fx >> 16; 252b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int a = (uint8_t)(fx >> 8); 25327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 254b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 255b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitV(x, y, stopy - y, a); 256b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 257b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com a = 255 - a; 258b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com if (a) { 259b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitV(x - 1, y, stopy - y, a); 260b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 26127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 262b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fx - SK_Fixed1/2; 263b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 264b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com}; 265b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com 266b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass Vertish_SkAntiHairBlitter : public SkAntiHairBlitter { 267b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic: 268b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE { 269b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int16_t runs[3]; 270b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t aa[2]; 27127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 272b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[0] = 1; 273b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[2] = 0; 27427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 275b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fx += SK_Fixed1/2; 2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int x = fx >> 16; 2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t a = (uint8_t)(fx >> 8); 27827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 279b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[0] = SmallDot6Scale(255 - a, mod64); 280b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[1] = SmallDot6Scale(a, mod64); 2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // the clippng blitters might overwrite this guy, so we have to reset it each time 2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com runs[1] = 1; 283b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitAntiH(x - 1, y, aa, runs); 2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // the clipping blitters might edit runs, but should not affect us 2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[0] == 1); 2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(runs[2] == 0); 2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fx += dx; 28827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 289b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fx - SK_Fixed1/2; 290b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 29127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 292b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE { 293b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(y < stopy); 294b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int16_t runs[3]; 295b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t aa[2]; 29627b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 297b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[0] = 1; 298b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[2] = 0; 29927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 300b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fx += SK_Fixed1/2; 301b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com do { 302b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com int x = fx >> 16; 303b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com uint8_t a = (uint8_t)(fx >> 8); 30427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com 305b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[0] = 255 - a; 306b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com aa[1] = a; 307b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // the clippng blitters might overwrite this guy, so we have to reset it each time 308b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com runs[1] = 1; 309b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com this->getBlitter()->blitAntiH(x - 1, y, aa, runs); 310b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com // the clipping blitters might edit runs, but should not affect us 311b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[0] == 1); 312b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(runs[2] == 0); 313b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fx += dx; 314b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } while (++y < stopy); 3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 316b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com return fx - SK_Fixed1/2; 317b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com } 318b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com}; 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 320bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { 3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((a << 16 >> 16) == a); 3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(b != 0); 3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (a << 16) / b; 3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3268a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#define SkBITCOUNT(x) (sizeof(x) << 3) 3278a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com 3288a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#if 1 3298a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com// returns high-bit set iff x==0x8000... 3308a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic inline int bad_int(int x) { 3318a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com return x & -x; 3328a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com} 3338a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com 3348a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic int any_bad_ints(int a, int b, int c, int d) { 3358a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1); 3368a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com} 3378a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#else 3388a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic inline int good_int(int x) { 3398a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com return x ^ (1 << (SkBITCOUNT(x) - 1)); 3408a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com} 3418a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com 3428a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic int any_bad_ints(int a, int b, int c, int d) { 3438a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com return !(good_int(a) & good_int(b) & good_int(c) & good_int(d)); 3448a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com} 3458a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#endif 3468a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com 3470e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#ifdef SK_DEBUG 34899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.comstatic bool canConvertFDot6ToFixed(SkFDot6 x) { 34999b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com const int maxDot6 = SK_MaxS32 >> (16 - 6); 35099b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com return SkAbs32(x) <= maxDot6; 35199b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com} 3520e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#endif 35399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com 354c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com/* 355c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com * We want the fractional part of ordinate, but we want multiples of 64 to 356c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com * return 64, not 0, so we can't just say (ordinate & 63). 357c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com * We basically want to compute those bits, and if they're 0, return 64. 358c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com * We can do that w/o a branch with an extra sub and add. 359c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com */ 360c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.comstatic int contribution_64(SkFDot6 ordinate) { 361c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#if 0 362c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com int result = ordinate & 63; 363c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com if (0 == result) { 364c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com result = 64; 365c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com } 366c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#else 367c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com int result = ((ordinate - 1) & 63) + 1; 368c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#endif 369c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com SkASSERT(result > 0 && result <= 64); 370c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com return result; 371c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com} 372c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com 3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, 374bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org const SkIRect* clip, SkBlitter* blitter) { 3758a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com // check for integer NaN (0x80000000) which we can't handle (can't negate it) 3768a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com // It appears typically from a huge float (inf or nan) being converted to int. 3778a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com // If we see it, just don't draw. 3788a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com if (any_bad_ints(x0, y0, x1, y1)) { 3798a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com return; 3808a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com } 3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 38299b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time 38399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com // (in dot6 format) 38499b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com SkASSERT(canConvertFDot6ToFixed(x0)); 38599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com SkASSERT(canConvertFDot6ToFixed(y0)); 38699b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com SkASSERT(canConvertFDot6ToFixed(x1)); 38799b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com SkASSERT(canConvertFDot6ToFixed(y1)); 38899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com 389bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) { 3903555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com /* instead of (x0 + x1) >> 1, we shift each separately. This is less 3913555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com precise, but avoids overflowing the intermediate result if the 3923555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com values are huge. A better fix might be to clip the original pts 3933555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com directly (i.e. do the divide), so we don't spend time subdividing 3943555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com huge lines at all. 3953555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com */ 3963555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com int hx = (x0 >> 1) + (x1 >> 1); 3973555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com int hy = (y0 >> 1) + (y1 >> 1); 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_anti_hairline(x0, y0, hx, hy, clip, blitter); 3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_anti_hairline(hx, hy, x1, y1, clip, blitter); 4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int scaleStart, scaleStop; 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int istart, istop; 405fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkFixed fstart, slope; 406b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com 407b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com HLine_SkAntiHairBlitter hline_blitter; 408b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com Horish_SkAntiHairBlitter horish_blitter; 409b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com VLine_SkAntiHairBlitter vline_blitter; 410b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com Vertish_SkAntiHairBlitter vertish_blitter; 411b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkAntiHairBlitter* hairBlitter = NULL; 4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 413bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) { // mostly horizontal 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (x0 > x1) { // we want to go left-to-right 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap<SkFDot6>(x0, x1); 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap<SkFDot6>(y0, y1); 4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istart = SkFDot6Floor(x0); 4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istop = SkFDot6Ceil(x1); 4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart = SkFDot6ToFixed(y0); 4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (y0 == y1) { // completely horizontal, take fast case 4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com slope = 0; 424b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter = &hline_blitter; 4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com slope = fastfixdiv(y1 - y0, x1 - x0); 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1); 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart += (slope * (32 - (x0 & 63)) + 32) >> 6; 429b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter = &horish_blitter; 4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 431fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(istop > istart); 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (istop - istart == 1) { 434c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com // we are within a single pixel 4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = x1 - x0; 4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(scaleStart >= 0 && scaleStart <= 64); 4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStop = 0; 4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = 64 - (x0 & 63); 4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStop = x1 & 63; 4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 443bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip){ 444bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (istart >= clip->fRight || istop <= clip->fLeft) { 4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 446bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 447bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (istart < clip->fLeft) { 4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart += slope * (clip->fLeft - istart); 4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istart = clip->fLeft; 4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = 64; 451c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com if (istop - istart == 1) { 452c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com // we are within a single pixel 453c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com scaleStart = contribution_64(x1); 454c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com scaleStop = 0; 455c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com } 4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4570724f4320d4f8c67d26c77594cca7fd030f4be1dreed@google.com if (istop > clip->fRight) { 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istop = clip->fRight; 459adb2e240188ecd3deef2b31f3836f44968d71d65reed@google.com scaleStop = 0; // so we don't draw this last column 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 461bbbe9ed59ee1d3077fa4e6368a4a7294240a5ec6reed@google.com 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(istart <= istop); 463bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (istart == istop) { 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 465bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now test if our Y values are completely inside the clip 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top, bottom; 468bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (slope >= 0) { // T2B 4699fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org top = SkFixedFloorToInt(fstart - SK_FixedHalf); 4709fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org bottom = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 471bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } else { // B2T 4729fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org bottom = SkFixedCeilToInt(fstart + SK_FixedHalf); 4739fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org top = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4756c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST 4766c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com top -= 1; 4776c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com bottom += 1; 4786c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#endif 479bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (top >= clip->fBottom || bottom <= clip->fTop) { 4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 481bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 482bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip->fTop <= top && clip->fBottom >= bottom) { 4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com clip = NULL; 484bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 486bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } else { // mostly vertical 487bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (y0 > y1) { // we want to go top-to-bottom 4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap<SkFDot6>(x0, x1); 4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkTSwap<SkFDot6>(y0, y1); 4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istart = SkFDot6Floor(y0); 4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istop = SkFDot6Ceil(y1); 4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart = SkFDot6ToFixed(x0); 495bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (x0 == x1) { 4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (y0 == y1) { // are we zero length? 4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; // nothing to do 4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com slope = 0; 500b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter = &vline_blitter; 501bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } else { 5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com slope = fastfixdiv(x1 - x0, y1 - y0); 5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1); 5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart += (slope * (32 - (y0 & 63)) + 32) >> 6; 505b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter = &vertish_blitter; 5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(istop > istart); 5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (istop - istart == 1) { 510c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com // we are within a single pixel 5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = y1 - y0; 5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(scaleStart >= 0 && scaleStart <= 64); 5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStop = 0; 5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = 64 - (y0 & 63); 5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStop = y1 & 63; 5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 518fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 519bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip) { 520bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (istart >= clip->fBottom || istop <= clip->fTop) { 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 522bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 523bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (istart < clip->fTop) { 5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fstart += slope * (clip->fTop - istart); 5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istart = clip->fTop; 5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com scaleStart = 64; 527c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com if (istop - istart == 1) { 528c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com // we are within a single pixel 529c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com scaleStart = contribution_64(y1); 530c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com scaleStop = 0; 531c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com } 5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5330724f4320d4f8c67d26c77594cca7fd030f4be1dreed@google.com if (istop > clip->fBottom) { 5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istop = clip->fBottom; 535adb2e240188ecd3deef2b31f3836f44968d71d65reed@google.com scaleStop = 0; // so we don't draw this last row 5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 537bbbe9ed59ee1d3077fa4e6368a4a7294240a5ec6reed@google.com 5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(istart <= istop); 5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (istart == istop) 5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now test if our X values are completely inside the clip 5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int left, right; 544bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (slope >= 0) { // L2R 5459fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org left = SkFixedFloorToInt(fstart - SK_FixedHalf); 5469fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org right = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 547bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } else { // R2L 5489fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org right = SkFixedCeilToInt(fstart + SK_FixedHalf); 5499fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org left = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5516c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST 5526c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com left -= 1; 5536c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com right += 1; 5546c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#endif 555bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (left >= clip->fRight || right <= clip->fLeft) { 5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 557bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 558bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip->fLeft <= left && clip->fRight >= right) { 5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com clip = NULL; 560bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRectClipBlitter rectClipper; 565bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip) { 5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rectClipper.init(blitter, *clip); 5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter = &rectClipper; 5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 569fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 570b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com SkASSERT(hairBlitter); 571b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter->setup(blitter); 572b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com 573c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#ifdef SK_DEBUG 574c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com if (scaleStart > 0 && scaleStop > 0) { 575c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com // be sure we don't draw twice in the same pixel 576c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com SkASSERT(istart < istop - 1); 577c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com } 578c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#endif 579c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com 580b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart); 5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com istart += 1; 58228937283e16928a562b3f9e19908db51bbb89ff9reed@android.com int fullSpans = istop - istart - (scaleStop > 0); 5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fullSpans > 0) { 584b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope); 5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (scaleStop > 0) { 587b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop); 5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 591045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1, 592045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRegion* clip, SkBlitter* blitter) { 593bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (clip && clip->isEmpty()) { 5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 595bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(clip == NULL || !clip->getBounds().isEmpty()); 5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef TEST_GAMMA 6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com build_gamma_table(); 6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 603e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkPoint pts[2] = { pt0, pt1 }; 6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 60599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com // We have to pre-clip the line to fit in a SkFixed, so we just chop 60699b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com // the line. TODO find a way to actually draw beyond that range. 60799b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com { 60899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com SkRect fixedBounds; 60999b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com const SkScalar max = SkIntToScalar(32767); 61099b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com fixedBounds.set(-max, -max, max, max); 61199b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) { 61299b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com return; 61399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com } 61499b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com } 61599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com 616e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (clip) { 617e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkRect clipBounds; 618e28ff55d980d2992618b6b721c848aba96cf759areed@android.com clipBounds.set(clip->getBounds()); 619a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com /* We perform integral clipping later on, but we do a scalar clip first 620a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com to ensure that our coordinates are expressible in fixed/integers. 621a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 622a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com antialiased hairlines can draw up to 1/2 of a pixel outside of 623a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com their bounds, so we need to outset the clip before calling the 624a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com clipper. To make the numerics safer, we outset by a whole pixel, 625a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com since the 1/2 pixel boundary is important to the antihair blitter, 626a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com we don't want to risk numerical fate by chopping on that edge. 627a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com */ 628a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com clipBounds.inset(-SK_Scalar1, -SK_Scalar1); 629a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 630e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) { 631e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return; 632e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 633e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 634fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 635e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 x0 = SkScalarToFDot6(pts[0].fX); 636e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 y0 = SkScalarToFDot6(pts[0].fY); 637e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 x1 = SkScalarToFDot6(pts[1].fX); 638e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 y1 = SkScalarToFDot6(pts[1].fY); 639e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 640e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (clip) { 641e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 left = SkMin32(x0, x1); 642e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 top = SkMin32(y0, y1); 643e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 right = SkMax32(x0, x1); 644e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkFDot6 bottom = SkMax32(y0, y1); 645e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkIRect ir; 6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ir.set( SkFDot6Floor(left) - 1, 6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6Floor(top) - 1, 6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6Ceil(right) + 1, 6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFDot6Ceil(bottom) + 1); 6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 652e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (clip->quickReject(ir)) { 6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 654e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 655e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (!clip->quickContains(ir)) { 6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRegion::Cliperator iter(*clip, ir); 6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkIRect* r = &iter.rect(); 6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 659e28ff55d980d2992618b6b721c848aba96cf759areed@android.com while (!iter.done()) { 6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_anti_hairline(x0, y0, x1, y1, r, blitter); 6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com iter.next(); 6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // fall through to no-clip case 6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_anti_hairline(x0, y0, x1, y1, NULL, blitter); 6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 670045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip, 671bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org SkBlitter* blitter) { 6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint p0, p1; 6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p0.set(rect.fLeft, rect.fTop); 6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p1.set(rect.fRight, rect.fTop); 6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p0.set(rect.fRight, rect.fBottom); 6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p1.set(rect.fLeft, rect.fBottom); 6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p0.set(rect.fLeft, rect.fTop); 6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 685bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef int FDot8; // 24.8 integer fixed point 6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline FDot8 SkFixedToFDot8(SkFixed x) { 6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (x + 0x80) >> 8; 6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 693bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 694bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org SkBlitter* blitter) { 6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(L < R); 696fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 697bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L)); 6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 701fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int left = L >> 8; 703fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 704bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (L & 0xFF) { 7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF))); 7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com left += 1; 7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int rite = R >> 8; 7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width = rite - left; 711bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (width > 0) { 7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com call_hline_blitter(blitter, left, top, width, alpha); 713bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 714bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (R & 0xFF) { 7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF)); 716bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7197ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter, 7207ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org bool fillInner) { 7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // check for empty now that we're in our reduced precision space 722bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (L >= R || T >= B) { 7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 724bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int top = T >> 8; 726bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (top == ((B - 1) >> 8)) { // just one scanline high 7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_scanline(L, top, R, B - T - 1, blitter); 7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 730fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 731bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (T & 0xFF) { 7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_scanline(L, top, R, 256 - (T & 0xFF), blitter); 7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com top += 1; 7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 735fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int bot = B >> 8; 7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int height = bot - top; 738bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (height > 0) { 7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int left = L >> 8; 740f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com if (left == ((R - 1) >> 8)) { // just 1-pixel wide 741f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com blitter->blitV(left, top, height, R - L - 1); 742f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com } else { 743f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com if (L & 0xFF) { 744f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com blitter->blitV(left, top, height, 256 - (L & 0xFF)); 745f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com left += 1; 746f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com } 747f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com int rite = R >> 8; 748f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com int width = rite - left; 749f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com if (width > 0 && fillInner) { 750f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com blitter->blitRect(left, top, width, height); 751f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com } 752f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com if (R & 0xFF) { 753f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com blitter->blitV(rite, top, height, R & 0xFF); 754f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com } 755bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 757fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 758bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org if (B & 0xFF) { 7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do_scanline(L, bot, R, B & 0xFF, blitter); 760bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org } 7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7637ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void antifillrect(const SkXRect& xr, SkBlitter* blitter) { 7647ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop), 7657ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom), 7667ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter, true); 7677ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 7687ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 77167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip, 7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* blitter) { 77367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (NULL == clip) { 77467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com antifillrect(xr, blitter); 77567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } else { 77667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkIRect outerBounds; 77767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com XRect_roundOut(xr, &outerBounds); 77867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com 77967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (clip->isRect()) { 78067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com const SkIRect& clipBounds = clip->getBounds(); 78167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com 78267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (clipBounds.contains(outerBounds)) { 78367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com antifillrect(xr, blitter); 78467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } else { 78567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkXRect tmpR; 78667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com // this keeps our original edges fractional 78767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com XRect_set(&tmpR, clipBounds); 78867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (tmpR.intersect(xr)) { 78967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com antifillrect(tmpR, blitter); 79067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } 79167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } 7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 79367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkRegion::Cliperator clipper(*clip, outerBounds); 79467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com const SkIRect& rr = clipper.rect(); 795fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 79667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com while (!clipper.done()) { 79767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkXRect tmpR; 798fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 79967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com // this keeps our original edges fractional 80067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com XRect_set(&tmpR, rr); 80167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (tmpR.intersect(xr)) { 80267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com antifillrect(tmpR, blitter); 80367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } 80467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com clipper.next(); 8058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 80767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } 80867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com} 80967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com 81067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip, 81167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkBlitter* blitter) { 81267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (clip.isBW()) { 81367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com AntiFillXRect(xr, &clip.bwRgn(), blitter); 8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 81567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkIRect outerBounds; 81667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com XRect_roundOut(xr, &outerBounds); 81767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com 81867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com if (clip.quickContains(outerBounds)) { 81967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com AntiFillXRect(xr, NULL, blitter); 82067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com } else { 82167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com SkAAClipBlitterWrapper wrapper(clip, blitter); 82267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com blitter = wrapper.getBlitter(); 82367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com 82467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter()); 825045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 8268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* This guy takes a float-rect, but with the key improvement that it has 8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com already been clipped, so we know that it is safe to convert it into a 8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com XRect (fixedpoint), as it won't overflow. 8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void antifillrect(const SkRect& r, SkBlitter* blitter) { 8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXRect xr; 835fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com XRect_set(&xr, r); 8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com antifillrect(xr, blitter); 8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* We repeat the clipping logic of AntiFillXRect because the float rect might 8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com overflow if we blindly converted it to an XRect. This sucks that we have to 8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com repeat the clipping logic, but I don't see how to share the code/logic. 843fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com We clip r (as needed) into one or more (smaller) float rects, and then pass 8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com those to our version of antifillrect, which converts it into an XRect and 8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com then calls the blit. 8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 848e28ff55d980d2992618b6b721c848aba96cf759areed@android.comvoid SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip, 8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* blitter) { 8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clip) { 851e28ff55d980d2992618b6b721c848aba96cf759areed@android.com SkRect newR; 852e28ff55d980d2992618b6b721c848aba96cf759areed@android.com newR.set(clip->getBounds()); 853e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (!newR.intersect(origR)) { 854e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return; 855e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 856e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect outerBounds; 858e28ff55d980d2992618b6b721c848aba96cf759areed@android.com newR.roundOut(&outerBounds); 859fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (clip->isRect()) { 861e28ff55d980d2992618b6b721c848aba96cf759areed@android.com antifillrect(newR, blitter); 8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRegion::Cliperator clipper(*clip, outerBounds); 8648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (!clipper.done()) { 865e28ff55d980d2992618b6b721c848aba96cf759areed@android.com newR.set(clipper.rect()); 866e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (newR.intersect(origR)) { 867e28ff55d980d2992618b6b721c848aba96cf759areed@android.com antifillrect(newR, blitter); 8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com clipper.next(); 8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 873e28ff55d980d2992618b6b721c848aba96cf759areed@android.com antifillrect(origR, blitter); 8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 877045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip, 878045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkBlitter* blitter) { 879045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (clip.isBW()) { 880045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com AntiFillRect(r, &clip.bwRgn(), blitter); 881045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 882045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper wrap(clip, blitter); 883045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter()); 884045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 885045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com} 886045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 8877ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 8887ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 8893a968750b29b3bb15452a4d4ed040c382727a297reed@google.com#define SkAlphaMulRound(a, b) SkMulDiv255Round(a, b) 8903a968750b29b3bb15452a4d4ed040c382727a297reed@google.com 8917ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org// calls blitRect() if the rectangle is non-empty 8927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) { 8937ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (L < R && T < B) { 8947ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitRect(L, T, R - L, B - T); 8957ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 8967ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 8977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 8987ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline FDot8 SkScalarToFDot8(SkScalar x) { 8997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return (int)(x * 256); 9007ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9017ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9027ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline int FDot8Floor(FDot8 x) { 9037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return x >> 8; 9047ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9057ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9067ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline int FDot8Ceil(FDot8 x) { 9077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return (x + 0xFF) >> 8; 9087ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9097ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org// 1 - (1 - a)*(1 - b) 9117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) { 9123a968750b29b3bb15452a4d4ed040c382727a297reed@google.com // need precise rounding (not just SkAlphaMul) so that values like 9133a968750b29b3bb15452a4d4ed040c382727a297reed@google.com // a=228, b=252 don't overflow the result 9143a968750b29b3bb15452a4d4ed040c382727a297reed@google.com return SkToU8(a + b - SkAlphaMulRound(a, b)); 9157ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9167ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9177ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 9187ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkBlitter* blitter) { 9197ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkASSERT(L < R); 920fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9217ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 9227ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L)); 9237ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return; 9247ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 925fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9267ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int left = L >> 8; 9277ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (L & 0xFF) { 9287ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF)); 9297ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org left += 1; 9307ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 931fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9327ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int rite = R >> 8; 9337ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int width = rite - left; 9347ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (width > 0) { 9357ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org call_hline_blitter(blitter, left, top, width, alpha); 9367ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 937fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9387ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (R & 0xFF) { 9397ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF)); 9407ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 9417ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9427ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9437ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, 9447ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkBlitter* blitter) { 9457ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkASSERT(L < R && T < B); 9467ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9477ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int top = T >> 8; 9487ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (top == ((B - 1) >> 8)) { // just one scanline high 94910d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com // We want the inverse of B-T, since we're the inner-stroke 95010d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com int alpha = 256 - (B - T); 95110d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com if (alpha) { 95210d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com inner_scanline(L, top, R, alpha, blitter); 95310d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com } 9547ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return; 9557ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 956fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9577ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (T & 0xFF) { 9587ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org inner_scanline(L, top, R, T & 0xFF, blitter); 9597ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org top += 1; 9607ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 961fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9627ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int bot = B >> 8; 9637ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org int height = bot - top; 9647ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (height > 0) { 9657ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (L & 0xFF) { 9667ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitV(L >> 8, top, height, L & 0xFF); 9677ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 9687ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (R & 0xFF) { 9697ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter->blitV(R >> 8, top, height, ~R & 0xFF); 9707ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 9717ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 972fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 9737ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (B & 0xFF) { 9747ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org inner_scanline(L, bot, R, ~B & 0xFF, blitter); 9757ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 9767ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 9777ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 978761fb62b0eb174783316d2a8b933fba896ca6355reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 9797ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org const SkRegion* clip, SkBlitter* blitter) { 980761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 9817ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 982761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com SkScalar rx = SkScalarHalf(strokeSize.fX); 983761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com SkScalar ry = SkScalarHalf(strokeSize.fY); 9847ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9857ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // outset by the radius 986761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com FDot8 L = SkScalarToFDot8(r.fLeft - rx); 987761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com FDot8 T = SkScalarToFDot8(r.fTop - ry); 988761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com FDot8 R = SkScalarToFDot8(r.fRight + rx); 989761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com FDot8 B = SkScalarToFDot8(r.fBottom + ry); 9907ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9917ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkIRect outer; 9927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // set outer to the outer rect of the outer section 9937ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); 9947ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 9957ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkBlitterClipper clipper; 9967ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (clip) { 9977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (clip->quickReject(outer)) { 9987ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org return; 9997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 10007ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (!clip->contains(outer)) { 10017ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter = clipper.apply(blitter, clip, &outer); 10027ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 10037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // now we can ignore clip for the rest of the function 10047ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 1005fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 10067ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // stroke the outer hull 10077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org antifilldot8(L, T, R, B, blitter, false); 10087ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 10097ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // set outer to the outer rect of the middle section 10107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B)); 10117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 10127ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // in case we lost a bit with diameter/2 1013761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com rx = strokeSize.fX - rx; 1014761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com ry = strokeSize.fY - ry; 10157ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // inset by the radius 1016761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com L = SkScalarToFDot8(r.fLeft + rx); 1017761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com T = SkScalarToFDot8(r.fTop + ry); 1018761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com R = SkScalarToFDot8(r.fRight - rx); 1019761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com B = SkScalarToFDot8(r.fBottom - ry); 10207ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 10217ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (L >= R || T >= B) { 10227ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom, 10237ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter); 10247ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } else { 10257ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkIRect inner; 10267ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // set inner to the inner rect of the middle section 10277ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); 10287ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 10297ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // draw the frame in 4 pieces 10307ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop, 10317ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter); 10327ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom, 10337ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter); 10347ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom, 10357ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter); 10367ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom, 10377ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org blitter); 10387ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 10397ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // now stroke the inner rect, which is similar to antifilldot8() except that 10407ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // it treats the fractional coordinates with the inverse bias (since its 10417ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org // inner). 10427ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org innerstrokedot8(L, T, R, B, blitter); 10437ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 10447ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 1045045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 1046045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 1047045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRasterClip& clip, SkBlitter* blitter) { 1048045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (clip.isBW()) { 1049045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter); 1050045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 1051045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper wrap(clip, blitter); 1052045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter()); 1053045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 1054045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com} 1055