1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 The Android Open Source Project 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScan.h" 11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlitter.h" 12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkColorPriv.h" 139005874dcc2a962acd88141f7e0ade7ada472babreed@android.com#include "SkLineClipper.h" 1426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#include "SkRasterClip.h" 15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFDot6.h" 16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 17accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com/* Our attempt to compute the worst case "bounds" for the horizontal and 18accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com vertical cases has some numerical bug in it, and we sometimes undervalue 19accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com our extends. The bug is that when this happens, we will set the clip to 20accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com NULL (for speed), and thus draw outside of the clip by a pixel, which might 21accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com only look bad, but it might also access memory outside of the valid range 22accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com allcoated for the device bitmap. 2317f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com 24accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com This define enables our fix to outset our "bounds" by 1, thus avoiding the 25accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com chance of the bug, but at the cost of sometimes taking the rectblitter 26accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com case (i.e. not setting the clip to NULL) when we might not actually need 27accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com to. If we can improve/fix the actual calculations, then we can remove this 28accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com step. 29accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com */ 30accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com#define OUTSET_BEFORE_CLIP_TEST true 31accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define HLINE_STACK_BUFFER 100 33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int SmallDot6Scale(int value, int dot6) { 35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT((int16_t)value == value); 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT((unsigned)dot6 <= 64); 37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return SkMulS16(value, dot6) >> 6; 38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com//#define TEST_GAMMA 41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef TEST_GAMMA 43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com static uint8_t gGammaTable[256]; 44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com #define ApplyGamma(table, alpha) (table)[alpha] 45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 463d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org static void build_gamma_table() { 47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com static bool gInit = false; 48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 493d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (gInit == false) { 503d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org for (int i = 0; i < 256; i++) { 51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed n = i * 257; 52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n += n >> 15; 53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(n >= 0 && n <= SK_Fixed1); 54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n = SkFixedSqrt(n); 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n = n * 255 >> 16; 56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // SkDebugf("morph %d -> %d\n", i, n); 57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gGammaTable[i] = SkToU8(n); 58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gInit = true; 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else 63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com #define ApplyGamma(table, alpha) SkToU8(alpha) 64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/////////////////////////////////////////////////////////////////////////////// 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 683d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, 693d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org U8CPU alpha) { 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(count > 0); 716d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int16_t runs[HLINE_STACK_BUFFER + 1]; 73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com uint8_t aa[HLINE_STACK_BUFFER]; 746d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com aa[0] = ApplyGamma(gGammaTable, alpha); 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do { 77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int n = count; 783d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (n > HLINE_STACK_BUFFER) { 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com n = HLINE_STACK_BUFFER; 803d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com runs[0] = SkToS16(n); 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com runs[n] = 0; 83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitAntiH(x, y, aa, runs); 84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x += n; 85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com count -= n; 86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } while (count > 0); 87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 8937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass SkAntiHairBlitter { 9037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic: 9137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkAntiHairBlitter() : fBlitter(NULL) {} 92c58edf5df3ce86e5ccecab3907ab7db925972c29djsollen@google.com virtual ~SkAntiHairBlitter() {} 93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 9437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkBlitter* getBlitter() const { return fBlitter; } 95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 9637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com void setup(SkBlitter* blitter) { 9737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fBlitter = blitter; 98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 10037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0; 10137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0; 102935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 10337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comprivate: 10437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkBlitter* fBlitter; 10537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com}; 106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 10737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass HLine_SkAntiHairBlitter : public SkAntiHairBlitter { 10837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic: 10937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) SK_OVERRIDE { 11037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fy += SK_Fixed1/2; 1116d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 11237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int y = fy >> 16; 11337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t a = (uint8_t)(fy >> 8); 1146d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 11537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // lower line 11637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com unsigned ma = SmallDot6Scale(a, mod64); 11737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (ma) { 11837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com call_hline_blitter(this->getBlitter(), x, y, 1, ma); 11937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 1206d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 12137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // upper line 12237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com ma = SmallDot6Scale(255 - a, mod64); 12337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (ma) { 12437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma); 12537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 1266d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 12737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fy - SK_Fixed1/2; 12837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 13037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, 13137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkFixed slope) SK_OVERRIDE { 13237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(x < stopx); 13337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int count = stopx - x; 13437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fy += SK_Fixed1/2; 1356d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 13637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int y = fy >> 16; 13737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t a = (uint8_t)(fy >> 8); 1386d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 13937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // lower line 14037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 14137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com call_hline_blitter(this->getBlitter(), x, y, count, a); 14237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 1436d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 14437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // upper line 14537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com a = 255 - a; 14637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 14737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com call_hline_blitter(this->getBlitter(), x, y - 1, count, a); 14837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 1496d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 15037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fy - SK_Fixed1/2; 15137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 15237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com}; 15337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com 15437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass Horish_SkAntiHairBlitter : public SkAntiHairBlitter { 15537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic: 15637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) SK_OVERRIDE { 15737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int16_t runs[2]; 15837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t aa[1]; 1596d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 16037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[0] = 1; 16137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[1] = 0; 1626d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 16337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fy += SK_Fixed1/2; 16437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkBlitter* blitter = this->getBlitter(); 165bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 166bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int lower_y = fy >> 16; 167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com uint8_t a = (uint8_t)(fy >> 8); 168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned ma = SmallDot6Scale(a, mod64); 1693d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (ma) { 170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com aa[0] = ApplyGamma(gamma, ma); 171bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitAntiH(x, lower_y, aa, runs); 172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // the clipping blitters might edit runs, but should not affect us 173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[0] == 1); 174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[1] == 0); 175bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com ma = SmallDot6Scale(255 - a, mod64); 1773d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (ma) { 178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com aa[0] = ApplyGamma(gamma, ma); 179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitAntiH(x, lower_y - 1, aa, runs); 180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // the clipping blitters might edit runs, but should not affect us 181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[0] == 1); 182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[1] == 0); 183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fy += dy; 1856d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 18637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fy - SK_Fixed1/2; 1873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 1886d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 18937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) SK_OVERRIDE { 19037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(x < stopx); 1916d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 19237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int16_t runs[2]; 19337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t aa[1]; 1946d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 19537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[0] = 1; 19637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[1] = 0; 1976d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 19837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fy += SK_Fixed1/2; 19937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkBlitter* blitter = this->getBlitter(); 20037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com do { 20137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int lower_y = fy >> 16; 20237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t a = (uint8_t)(fy >> 8); 20337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 20437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[0] = a; 20537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com blitter->blitAntiH(x, lower_y, aa, runs); 20637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // the clipping blitters might edit runs, but should not affect us 20737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[0] == 1); 20837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[1] == 0); 20937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 21037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com a = 255 - a; 21137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 21237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[0] = a; 21337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com blitter->blitAntiH(x, lower_y - 1, aa, runs); 21437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // the clipping blitters might edit runs, but should not affect us 21537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[0] == 1); 21637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[1] == 0); 21737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 21837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fy += dy; 21937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } while (++x < stopx); 2206d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 22137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fy - SK_Fixed1/2; 22237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 22337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com}; 22437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com 22537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass VLine_SkAntiHairBlitter : public SkAntiHairBlitter { 22637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic: 22737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE { 22837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(0 == dx); 22937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fx += SK_Fixed1/2; 2306d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 23137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int x = fx >> 16; 23237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int a = (uint8_t)(fx >> 8); 2336d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 23437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com unsigned ma = SmallDot6Scale(a, mod64); 23537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (ma) { 23637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitV(x, y, 1, ma); 23737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 23837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com ma = SmallDot6Scale(255 - a, mod64); 23937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (ma) { 24037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitV(x - 1, y, 1, ma); 24137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 2426d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 24337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fx - SK_Fixed1/2; 2443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 245935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 24637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE { 24737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(y < stopy); 24837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(0 == dx); 24937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fx += SK_Fixed1/2; 2506d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 25137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int x = fx >> 16; 25237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int a = (uint8_t)(fx >> 8); 2536d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 25437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 25537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitV(x, y, stopy - y, a); 25637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 25737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com a = 255 - a; 25837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com if (a) { 25937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitV(x - 1, y, stopy - y, a); 26037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 2616d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 26237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fx - SK_Fixed1/2; 26337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 26437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com}; 26537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com 26637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass Vertish_SkAntiHairBlitter : public SkAntiHairBlitter { 26737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic: 26837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE { 26937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int16_t runs[3]; 27037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t aa[2]; 2716d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 27237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[0] = 1; 27337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[2] = 0; 2746d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 27537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fx += SK_Fixed1/2; 276bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int x = fx >> 16; 277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com uint8_t a = (uint8_t)(fx >> 8); 2786d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 27937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[0] = SmallDot6Scale(255 - a, mod64); 28037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[1] = SmallDot6Scale(a, mod64); 281bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // the clippng blitters might overwrite this guy, so we have to reset it each time 282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com runs[1] = 1; 28337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitAntiH(x - 1, y, aa, runs); 284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // the clipping blitters might edit runs, but should not affect us 285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[0] == 1); 286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(runs[2] == 0); 287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fx += dx; 2886d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 28937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fx - SK_Fixed1/2; 29037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 2916d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 29237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE { 29337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(y < stopy); 29437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int16_t runs[3]; 29537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t aa[2]; 2966d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 29737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[0] = 1; 29837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[2] = 0; 2996d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 30037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fx += SK_Fixed1/2; 30137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com do { 30237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com int x = fx >> 16; 30337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com uint8_t a = (uint8_t)(fx >> 8); 3046d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com 30537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[0] = 255 - a; 30637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com aa[1] = a; 30737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // the clippng blitters might overwrite this guy, so we have to reset it each time 30837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com runs[1] = 1; 30937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com this->getBlitter()->blitAntiH(x - 1, y, aa, runs); 31037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com // the clipping blitters might edit runs, but should not affect us 31137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[0] == 1); 31237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(runs[2] == 0); 31337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fx += dx; 31437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } while (++y < stopy); 315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 31637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com return fx - SK_Fixed1/2; 31737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com } 31837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com}; 319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 3203d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { 321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT((a << 16 >> 16) == a); 322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(b != 0); 323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (a << 16) / b; 324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 32690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#define SkBITCOUNT(x) (sizeof(x) << 3) 32790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com 32890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#if 1 32990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com// returns high-bit set iff x==0x8000... 33090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic inline int bad_int(int x) { 33190d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com return x & -x; 33290d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com} 33390d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com 33490d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic int any_bad_ints(int a, int b, int c, int d) { 33590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1); 33690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com} 33790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#else 33890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic inline int good_int(int x) { 33990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com return x ^ (1 << (SkBITCOUNT(x) - 1)); 34090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com} 34190d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com 34290d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic int any_bad_ints(int a, int b, int c, int d) { 34390d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com return !(good_int(a) & good_int(b) & good_int(c) & good_int(d)); 34490d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com} 34590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#endif 34690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com 347afcc161571327871da95761248abefeaafed40a4humper@google.com#ifdef SK_DEBUG 3481562b550f54f1adaf44f2c833a18f63555332e4dreed@google.comstatic bool canConvertFDot6ToFixed(SkFDot6 x) { 3491562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com const int maxDot6 = SK_MaxS32 >> (16 - 6); 3501562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com return SkAbs32(x) <= maxDot6; 3511562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com} 352afcc161571327871da95761248abefeaafed40a4humper@google.com#endif 3531562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com 354821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com/* 355821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com * We want the fractional part of ordinate, but we want multiples of 64 to 356821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com * return 64, not 0, so we can't just say (ordinate & 63). 357821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com * We basically want to compute those bits, and if they're 0, return 64. 358821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com * We can do that w/o a branch with an extra sub and add. 359821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com */ 360821f3ed12741706f95f0b2fc9046139c7644e575reed@google.comstatic int contribution_64(SkFDot6 ordinate) { 361821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#if 0 362821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com int result = ordinate & 63; 363821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com if (0 == result) { 364821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com result = 64; 365821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com } 366821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#else 367821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com int result = ((ordinate - 1) & 63) + 1; 368821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#endif 369821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com SkASSERT(result > 0 && result <= 64); 370821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com return result; 371821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com} 372821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com 373bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, 3743d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org const SkIRect* clip, SkBlitter* blitter) { 37590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com // check for integer NaN (0x80000000) which we can't handle (can't negate it) 37690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com // It appears typically from a huge float (inf or nan) being converted to int. 37790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com // If we see it, just don't draw. 37890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com if (any_bad_ints(x0, y0, x1, y1)) { 37990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com return; 38090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com } 381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 3821562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time 3831562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com // (in dot6 format) 3841562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com SkASSERT(canConvertFDot6ToFixed(x0)); 3851562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com SkASSERT(canConvertFDot6ToFixed(y0)); 3861562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com SkASSERT(canConvertFDot6ToFixed(x1)); 3871562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com SkASSERT(canConvertFDot6ToFixed(y1)); 3881562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com 3893d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) { 390c57897f74f960be3972e615e3a0a297c75e9126breed@android.com /* instead of (x0 + x1) >> 1, we shift each separately. This is less 391c57897f74f960be3972e615e3a0a297c75e9126breed@android.com precise, but avoids overflowing the intermediate result if the 392c57897f74f960be3972e615e3a0a297c75e9126breed@android.com values are huge. A better fix might be to clip the original pts 393c57897f74f960be3972e615e3a0a297c75e9126breed@android.com directly (i.e. do the divide), so we don't spend time subdividing 394c57897f74f960be3972e615e3a0a297c75e9126breed@android.com huge lines at all. 395c57897f74f960be3972e615e3a0a297c75e9126breed@android.com */ 396c57897f74f960be3972e615e3a0a297c75e9126breed@android.com int hx = (x0 >> 1) + (x1 >> 1); 397c57897f74f960be3972e615e3a0a297c75e9126breed@android.com int hy = (y0 >> 1) + (y1 >> 1); 398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_anti_hairline(x0, y0, hx, hy, clip, blitter); 399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_anti_hairline(hx, hy, x1, y1, clip, blitter); 400bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 401bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 402bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 403bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int scaleStart, scaleStop; 404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int istart, istop; 405935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com SkFixed fstart, slope; 40637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com 40737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com HLine_SkAntiHairBlitter hline_blitter; 40837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com Horish_SkAntiHairBlitter horish_blitter; 40937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com VLine_SkAntiHairBlitter vline_blitter; 41037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com Vertish_SkAntiHairBlitter vertish_blitter; 41137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkAntiHairBlitter* hairBlitter = NULL; 412bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 4133d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) { // mostly horizontal 414bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (x0 > x1) { // we want to go left-to-right 415bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkTSwap<SkFDot6>(x0, x1); 416bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkTSwap<SkFDot6>(y0, y1); 417bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 418bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 419bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istart = SkFDot6Floor(x0); 420bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istop = SkFDot6Ceil(x1); 421bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart = SkFDot6ToFixed(y0); 422bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (y0 == y1) { // completely horizontal, take fast case 423bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com slope = 0; 42437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter = &hline_blitter; 425bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com slope = fastfixdiv(y1 - y0, x1 - x0); 427bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1); 428bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart += (slope * (32 - (x0 & 63)) + 32) >> 6; 42937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter = &horish_blitter; 430bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 431935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 432bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(istop > istart); 433bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (istop - istart == 1) { 434821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com // we are within a single pixel 435bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = x1 - x0; 436bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(scaleStart >= 0 && scaleStart <= 64); 437bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStop = 0; 438bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 439bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = 64 - (x0 & 63); 440bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStop = x1 & 63; 441bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 442bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 4433d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip){ 4443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (istart >= clip->fRight || istop <= clip->fLeft) { 445bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 4463d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 4473d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (istart < clip->fLeft) { 448bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart += slope * (clip->fLeft - istart); 449bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istart = clip->fLeft; 450bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = 64; 451821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com if (istop - istart == 1) { 452821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com // we are within a single pixel 453821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com scaleStart = contribution_64(x1); 454821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com scaleStop = 0; 455821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com } 456bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 457731578526ef7f61b1d2acf950c21831a3a2774e6reed@google.com if (istop > clip->fRight) { 458bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istop = clip->fRight; 45967b43262006b7553f44959623813af46e1252edfreed@google.com scaleStop = 0; // so we don't draw this last column 460bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 46173b5d754f5546de3e51e7ed93f9014ed68fa4b3dreed@google.com 462bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(istart <= istop); 4633d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (istart == istop) { 464bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 4653d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 466bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now test if our Y values are completely inside the clip 467bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int top, bottom; 4683d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (slope >= 0) { // T2B 469bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com top = SkFixedFloor(fstart - SK_FixedHalf); 470bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 4713d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } else { // B2T 472bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com bottom = SkFixedCeil(fstart + SK_FixedHalf); 473bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 474bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 47517f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST 47617f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com top -= 1; 47717f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com bottom += 1; 47817f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#endif 4793d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (top >= clip->fBottom || bottom <= clip->fTop) { 480bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 4813d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 4823d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip->fTop <= top && clip->fBottom >= bottom) { 483bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com clip = NULL; 4843d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 485bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 4863d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } else { // mostly vertical 4873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (y0 > y1) { // we want to go top-to-bottom 488bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkTSwap<SkFDot6>(x0, x1); 489bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkTSwap<SkFDot6>(y0, y1); 490bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 491bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 492bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istart = SkFDot6Floor(y0); 493bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istop = SkFDot6Ceil(y1); 494bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart = SkFDot6ToFixed(x0); 4953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (x0 == x1) { 496bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (y0 == y1) { // are we zero length? 497bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; // nothing to do 498bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 499bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com slope = 0; 50037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter = &vline_blitter; 5013d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } else { 502bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com slope = fastfixdiv(x1 - x0, y1 - y0); 503bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1); 504bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart += (slope * (32 - (y0 & 63)) + 32) >> 6; 50537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter = &vertish_blitter; 506bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 507bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 508bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(istop > istart); 509bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (istop - istart == 1) { 510821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com // we are within a single pixel 511bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = y1 - y0; 512bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(scaleStart >= 0 && scaleStart <= 64); 513bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStop = 0; 514bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 515bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = 64 - (y0 & 63); 516bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStop = y1 & 63; 517bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 518935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 5193d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip) { 5203d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (istart >= clip->fBottom || istop <= clip->fTop) { 521bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 5223d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 5233d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (istart < clip->fTop) { 524bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fstart += slope * (clip->fTop - istart); 525bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istart = clip->fTop; 526bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scaleStart = 64; 527821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com if (istop - istart == 1) { 528821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com // we are within a single pixel 529821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com scaleStart = contribution_64(y1); 530821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com scaleStop = 0; 531821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com } 532bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 533731578526ef7f61b1d2acf950c21831a3a2774e6reed@google.com if (istop > clip->fBottom) { 534bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istop = clip->fBottom; 53567b43262006b7553f44959623813af46e1252edfreed@google.com scaleStop = 0; // so we don't draw this last row 536bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 53773b5d754f5546de3e51e7ed93f9014ed68fa4b3dreed@google.com 538bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(istart <= istop); 539bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (istart == istop) 540bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 541bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 542bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now test if our X values are completely inside the clip 543bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int left, right; 5443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (slope >= 0) { // L2R 545bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com left = SkFixedFloor(fstart - SK_FixedHalf); 546bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 5473d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } else { // R2L 548bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com right = SkFixedCeil(fstart + SK_FixedHalf); 549bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 550bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 55117f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST 55217f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com left -= 1; 55317f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com right += 1; 55417f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#endif 5553d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (left >= clip->fRight || right <= clip->fLeft) { 556bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 5573d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 5583d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip->fLeft <= left && clip->fRight >= right) { 559bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com clip = NULL; 5603d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 561bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 562bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 563bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 564bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkRectClipBlitter rectClipper; 5653d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip) { 566bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rectClipper.init(blitter, *clip); 567bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter = &rectClipper; 568bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 569935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 57037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com SkASSERT(hairBlitter); 57137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter->setup(blitter); 57237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com 573821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#ifdef SK_DEBUG 574821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com if (scaleStart > 0 && scaleStop > 0) { 575821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com // be sure we don't draw twice in the same pixel 576821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com SkASSERT(istart < istop - 1); 577821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com } 578821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#endif 579821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com 58037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart); 581bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com istart += 1; 58274c46a2c5c4988c88bf0594977c1f8a0c322682dreed@android.com int fullSpans = istop - istart - (scaleStop > 0); 583bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (fullSpans > 0) { 58437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope); 585bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 586bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (scaleStop > 0) { 58737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop); 588bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 589bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 590bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 59126f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1, 59226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com const SkRegion* clip, SkBlitter* blitter) { 5933d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (clip && clip->isEmpty()) { 594bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 5953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 596bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 597bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(clip == NULL || !clip->getBounds().isEmpty()); 598bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 599bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef TEST_GAMMA 600bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com build_gamma_table(); 601bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 602bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6039005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkPoint pts[2] = { pt0, pt1 }; 604bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6051562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com#ifdef SK_SCALAR_IS_FLOAT 6061562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com // We have to pre-clip the line to fit in a SkFixed, so we just chop 6071562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com // the line. TODO find a way to actually draw beyond that range. 6081562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com { 6091562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com SkRect fixedBounds; 6101562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com const SkScalar max = SkIntToScalar(32767); 6111562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com fixedBounds.set(-max, -max, max, max); 6121562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) { 6131562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com return; 6141562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com } 6151562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com } 6161562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com#endif 6171562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com 6189005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (clip) { 6199005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkRect clipBounds; 6209005874dcc2a962acd88141f7e0ade7ada472babreed@android.com clipBounds.set(clip->getBounds()); 62163faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com /* We perform integral clipping later on, but we do a scalar clip first 62263faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com to ensure that our coordinates are expressible in fixed/integers. 62363faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com 62463faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com antialiased hairlines can draw up to 1/2 of a pixel outside of 62563faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com their bounds, so we need to outset the clip before calling the 62663faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com clipper. To make the numerics safer, we outset by a whole pixel, 62763faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com since the 1/2 pixel boundary is important to the antihair blitter, 62863faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com we don't want to risk numerical fate by chopping on that edge. 62963faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com */ 63063faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com clipBounds.inset(-SK_Scalar1, -SK_Scalar1); 63163faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com 6329005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) { 6339005874dcc2a962acd88141f7e0ade7ada472babreed@android.com return; 6349005874dcc2a962acd88141f7e0ade7ada472babreed@android.com } 6359005874dcc2a962acd88141f7e0ade7ada472babreed@android.com } 636935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 6379005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 x0 = SkScalarToFDot6(pts[0].fX); 6389005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 y0 = SkScalarToFDot6(pts[0].fY); 6399005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 x1 = SkScalarToFDot6(pts[1].fX); 6409005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 y1 = SkScalarToFDot6(pts[1].fY); 6419005874dcc2a962acd88141f7e0ade7ada472babreed@android.com 6429005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (clip) { 6439005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 left = SkMin32(x0, x1); 6449005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 top = SkMin32(y0, y1); 6459005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 right = SkMax32(x0, x1); 6469005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkFDot6 bottom = SkMax32(y0, y1); 6479005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkIRect ir; 648bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 649bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com ir.set( SkFDot6Floor(left) - 1, 650bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFDot6Floor(top) - 1, 651bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFDot6Ceil(right) + 1, 652bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFDot6Ceil(bottom) + 1); 653bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6549005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (clip->quickReject(ir)) { 655bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 6569005874dcc2a962acd88141f7e0ade7ada472babreed@android.com } 6579005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (!clip->quickContains(ir)) { 658bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkRegion::Cliperator iter(*clip, ir); 659bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const SkIRect* r = &iter.rect(); 660bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6619005874dcc2a962acd88141f7e0ade7ada472babreed@android.com while (!iter.done()) { 662bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_anti_hairline(x0, y0, x1, y1, r, blitter); 663bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com iter.next(); 664bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 665bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 666bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 667bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // fall through to no-clip case 668bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 669bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_anti_hairline(x0, y0, x1, y1, NULL, blitter); 670bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 671bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 67226f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip, 6733d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org SkBlitter* blitter) { 674bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkPoint p0, p1; 675bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 676bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com p0.set(rect.fLeft, rect.fTop); 677bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com p1.set(rect.fRight, rect.fTop); 678bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 679bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com p0.set(rect.fRight, rect.fBottom); 680bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 681bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com p1.set(rect.fLeft, rect.fBottom); 682bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 683bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com p0.set(rect.fLeft, rect.fTop); 684bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScan::AntiHairLine(p0, p1, clip, blitter); 685bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 686bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 688bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 689bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comtypedef int FDot8; // 24.8 integer fixed point 690bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 691bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline FDot8 SkFixedToFDot8(SkFixed x) { 692bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (x + 0x80) >> 8; 693bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 694bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 6953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 6963d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org SkBlitter* blitter) { 697bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(L < R); 698935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 6993d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 700bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L)); 701bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 702bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 703935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 704bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int left = L >> 8; 705935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 7063d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (L & 0xFF) { 707bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF))); 708bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com left += 1; 709bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 710bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 711bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int rite = R >> 8; 712bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int width = rite - left; 7133d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (width > 0) { 714bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com call_hline_blitter(blitter, left, top, width, alpha); 7153d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 7163d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (R & 0xFF) { 717bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF)); 7183d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 719bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 720bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 721a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter, 722a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org bool fillInner) { 723bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // check for empty now that we're in our reduced precision space 7243d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (L >= R || T >= B) { 725bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 7263d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 727bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int top = T >> 8; 7283d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (top == ((B - 1) >> 8)) { // just one scanline high 729bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_scanline(L, top, R, B - T - 1, blitter); 730bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return; 731bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 732935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 7333d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (T & 0xFF) { 734bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_scanline(L, top, R, 256 - (T & 0xFF), blitter); 735bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com top += 1; 736bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 737935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 738bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int bot = B >> 8; 739bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int height = bot - top; 7403d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (height > 0) { 741bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int left = L >> 8; 74211a407a3f00f3887d6a933a0cf327a437f054942reed@google.com if (left == ((R - 1) >> 8)) { // just 1-pixel wide 74311a407a3f00f3887d6a933a0cf327a437f054942reed@google.com blitter->blitV(left, top, height, R - L - 1); 74411a407a3f00f3887d6a933a0cf327a437f054942reed@google.com } else { 74511a407a3f00f3887d6a933a0cf327a437f054942reed@google.com if (L & 0xFF) { 74611a407a3f00f3887d6a933a0cf327a437f054942reed@google.com blitter->blitV(left, top, height, 256 - (L & 0xFF)); 74711a407a3f00f3887d6a933a0cf327a437f054942reed@google.com left += 1; 74811a407a3f00f3887d6a933a0cf327a437f054942reed@google.com } 74911a407a3f00f3887d6a933a0cf327a437f054942reed@google.com int rite = R >> 8; 75011a407a3f00f3887d6a933a0cf327a437f054942reed@google.com int width = rite - left; 75111a407a3f00f3887d6a933a0cf327a437f054942reed@google.com if (width > 0 && fillInner) { 75211a407a3f00f3887d6a933a0cf327a437f054942reed@google.com blitter->blitRect(left, top, width, height); 75311a407a3f00f3887d6a933a0cf327a437f054942reed@google.com } 75411a407a3f00f3887d6a933a0cf327a437f054942reed@google.com if (R & 0xFF) { 75511a407a3f00f3887d6a933a0cf327a437f054942reed@google.com blitter->blitV(rite, top, height, R & 0xFF); 75611a407a3f00f3887d6a933a0cf327a437f054942reed@google.com } 7573d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 758bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 759935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 7603d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org if (B & 0xFF) { 761bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do_scanline(L, bot, R, B & 0xFF, blitter); 7623d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org } 763bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 764bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 765a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void antifillrect(const SkXRect& xr, SkBlitter* blitter) { 766a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop), 767a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom), 768a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter, true); 769a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 770a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 771bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/////////////////////////////////////////////////////////////////////////////// 772bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 773d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip, 774bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkBlitter* blitter) { 775d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (NULL == clip) { 776d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com antifillrect(xr, blitter); 777d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } else { 778d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkIRect outerBounds; 779d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com XRect_roundOut(xr, &outerBounds); 780d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com 781d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (clip->isRect()) { 782d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com const SkIRect& clipBounds = clip->getBounds(); 783d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com 784d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (clipBounds.contains(outerBounds)) { 785d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com antifillrect(xr, blitter); 786d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } else { 787d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkXRect tmpR; 788d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com // this keeps our original edges fractional 789d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com XRect_set(&tmpR, clipBounds); 790d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (tmpR.intersect(xr)) { 791d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com antifillrect(tmpR, blitter); 792d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } 793d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } 794bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 795d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkRegion::Cliperator clipper(*clip, outerBounds); 796d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com const SkIRect& rr = clipper.rect(); 797935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 798d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com while (!clipper.done()) { 799d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkXRect tmpR; 800935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 801d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com // this keeps our original edges fractional 802d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com XRect_set(&tmpR, rr); 803d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (tmpR.intersect(xr)) { 804d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com antifillrect(tmpR, blitter); 805d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } 806d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com clipper.next(); 807bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 808bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 809d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } 810d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com} 811d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com 812d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip, 813d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkBlitter* blitter) { 814d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (clip.isBW()) { 815d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com AntiFillXRect(xr, &clip.bwRgn(), blitter); 816bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 817d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkIRect outerBounds; 818d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com XRect_roundOut(xr, &outerBounds); 819d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com 820d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com if (clip.quickContains(outerBounds)) { 821d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com AntiFillXRect(xr, NULL, blitter); 822d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com } else { 823d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com SkAAClipBlitterWrapper wrapper(clip, blitter); 824d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com blitter = wrapper.getBlitter(); 825d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com 826d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter()); 82726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com } 828bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 829bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 830bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 831bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_SCALAR_IS_FLOAT 832bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 833bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/* This guy takes a float-rect, but with the key improvement that it has 834bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com already been clipped, so we know that it is safe to convert it into a 835bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com XRect (fixedpoint), as it won't overflow. 836bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/ 837bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic void antifillrect(const SkRect& r, SkBlitter* blitter) { 838bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkXRect xr; 839935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 840bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com XRect_set(&xr, r); 841bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com antifillrect(xr, blitter); 842bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 843bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 844bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/* We repeat the clipping logic of AntiFillXRect because the float rect might 845bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com overflow if we blindly converted it to an XRect. This sucks that we have to 846bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com repeat the clipping logic, but I don't see how to share the code/logic. 847935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 848bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com We clip r (as needed) into one or more (smaller) float rects, and then pass 849bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com those to our version of antifillrect, which converts it into an XRect and 850bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com then calls the blit. 851bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/ 8529005874dcc2a962acd88141f7e0ade7ada472babreed@android.comvoid SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip, 853bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkBlitter* blitter) { 854bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (clip) { 8559005874dcc2a962acd88141f7e0ade7ada472babreed@android.com SkRect newR; 8569005874dcc2a962acd88141f7e0ade7ada472babreed@android.com newR.set(clip->getBounds()); 8579005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (!newR.intersect(origR)) { 8589005874dcc2a962acd88141f7e0ade7ada472babreed@android.com return; 8599005874dcc2a962acd88141f7e0ade7ada472babreed@android.com } 8609005874dcc2a962acd88141f7e0ade7ada472babreed@android.com 861bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkIRect outerBounds; 8629005874dcc2a962acd88141f7e0ade7ada472babreed@android.com newR.roundOut(&outerBounds); 863935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 864bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (clip->isRect()) { 8659005874dcc2a962acd88141f7e0ade7ada472babreed@android.com antifillrect(newR, blitter); 866bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 867bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkRegion::Cliperator clipper(*clip, outerBounds); 868bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com while (!clipper.done()) { 8699005874dcc2a962acd88141f7e0ade7ada472babreed@android.com newR.set(clipper.rect()); 8709005874dcc2a962acd88141f7e0ade7ada472babreed@android.com if (newR.intersect(origR)) { 8719005874dcc2a962acd88141f7e0ade7ada472babreed@android.com antifillrect(newR, blitter); 872bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 873bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com clipper.next(); 874bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 875bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 876bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 8779005874dcc2a962acd88141f7e0ade7ada472babreed@android.com antifillrect(origR, blitter); 878bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 879bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 880bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 88126f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip, 88226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com SkBlitter* blitter) { 88326f5a398c38318eb7eab44f72e024ef784d247fareed@google.com if (clip.isBW()) { 88426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com AntiFillRect(r, &clip.bwRgn(), blitter); 88526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com } else { 88626f5a398c38318eb7eab44f72e024ef784d247fareed@google.com SkAAClipBlitterWrapper wrap(clip, blitter); 88726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter()); 88826f5a398c38318eb7eab44f72e024ef784d247fareed@google.com } 88926f5a398c38318eb7eab44f72e024ef784d247fareed@google.com} 89026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com 891c4c4538f03a77d218c7c324c24d4472820c7f808epoger@google.com#endif // SK_SCALAR_IS_FLOAT 892c4c4538f03a77d218c7c324c24d4472820c7f808epoger@google.com 893a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 894a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 895353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com#define SkAlphaMulRound(a, b) SkMulDiv255Round(a, b) 896353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com 897a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org// calls blitRect() if the rectangle is non-empty 898a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) { 899a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (L < R && T < B) { 900a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitRect(L, T, R - L, B - T); 901a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 902a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 903a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 904a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline FDot8 SkScalarToFDot8(SkScalar x) { 905a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#ifdef SK_SCALAR_IS_FLOAT 906a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return (int)(x * 256); 907a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#else 908a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return x >> 8; 909a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#endif 910a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 911a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 912a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline int FDot8Floor(FDot8 x) { 913a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return x >> 8; 914a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 915a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 916a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline int FDot8Ceil(FDot8 x) { 917a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return (x + 0xFF) >> 8; 918a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 919a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 920a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org// 1 - (1 - a)*(1 - b) 921a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) { 922353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com // need precise rounding (not just SkAlphaMul) so that values like 923353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com // a=228, b=252 don't overflow the result 924353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com return SkToU8(a + b - SkAlphaMulRound(a, b)); 925a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 926a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 927a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 928a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkBlitter* blitter) { 929a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkASSERT(L < R); 930935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 931a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 932a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L)); 933a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return; 934a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 935935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 936a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int left = L >> 8; 937a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (L & 0xFF) { 938a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF)); 939a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org left += 1; 940a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 941935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 942a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int rite = R >> 8; 943a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int width = rite - left; 944a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (width > 0) { 945a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org call_hline_blitter(blitter, left, top, width, alpha); 946a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 947935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 948a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (R & 0xFF) { 949a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF)); 950a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 951a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 952a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 953a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, 954a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkBlitter* blitter) { 955a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkASSERT(L < R && T < B); 956a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 957a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int top = T >> 8; 958a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (top == ((B - 1) >> 8)) { // just one scanline high 9598e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com // We want the inverse of B-T, since we're the inner-stroke 9608e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com int alpha = 256 - (B - T); 9618e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com if (alpha) { 9628e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com inner_scanline(L, top, R, alpha, blitter); 9638e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com } 964a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return; 965a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 966935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 967a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (T & 0xFF) { 968a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org inner_scanline(L, top, R, T & 0xFF, blitter); 969a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org top += 1; 970a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 971935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 972a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int bot = B >> 8; 973a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org int height = bot - top; 974a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (height > 0) { 975a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (L & 0xFF) { 976a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitV(L >> 8, top, height, L & 0xFF); 977a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 978a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (R & 0xFF) { 979a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter->blitV(R >> 8, top, height, ~R & 0xFF); 980a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 981a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 982935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 983a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (B & 0xFF) { 984a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org inner_scanline(L, bot, R, ~B & 0xFF, blitter); 985a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 986a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 987a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 988f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 989a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org const SkRegion* clip, SkBlitter* blitter) { 990f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 991a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 992f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com SkScalar rx = SkScalarHalf(strokeSize.fX); 993f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com SkScalar ry = SkScalarHalf(strokeSize.fY); 994a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 995a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // outset by the radius 996f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com FDot8 L = SkScalarToFDot8(r.fLeft - rx); 997f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com FDot8 T = SkScalarToFDot8(r.fTop - ry); 998f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com FDot8 R = SkScalarToFDot8(r.fRight + rx); 999f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com FDot8 B = SkScalarToFDot8(r.fBottom + ry); 1000a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1001a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkIRect outer; 1002a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // set outer to the outer rect of the outer section 1003a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); 1004a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1005a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkBlitterClipper clipper; 1006a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (clip) { 1007a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (clip->quickReject(outer)) { 1008a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org return; 1009a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 1010a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (!clip->contains(outer)) { 1011a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter = clipper.apply(blitter, clip, &outer); 1012a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 1013a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // now we can ignore clip for the rest of the function 1014a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 1015935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 1016a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // stroke the outer hull 1017a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org antifilldot8(L, T, R, B, blitter, false); 1018a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1019a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // set outer to the outer rect of the middle section 1020a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B)); 1021a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1022a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // in case we lost a bit with diameter/2 1023f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com rx = strokeSize.fX - rx; 1024f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com ry = strokeSize.fY - ry; 1025a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // inset by the radius 1026f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com L = SkScalarToFDot8(r.fLeft + rx); 1027f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com T = SkScalarToFDot8(r.fTop + ry); 1028f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com R = SkScalarToFDot8(r.fRight - rx); 1029f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com B = SkScalarToFDot8(r.fBottom - ry); 1030a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1031a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org if (L >= R || T >= B) { 1032a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom, 1033a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter); 1034a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } else { 1035a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org SkIRect inner; 1036a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // set inner to the inner rect of the middle section 1037a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); 1038a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1039a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // draw the frame in 4 pieces 1040a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop, 1041a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter); 1042a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom, 1043a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter); 1044a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom, 1045a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter); 1046a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom, 1047a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org blitter); 1048a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org 1049a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // now stroke the inner rect, which is similar to antifilldot8() except that 1050a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // it treats the fractional coordinates with the inverse bias (since its 1051a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org // inner). 1052a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org innerstrokedot8(L, T, R, B, blitter); 1053a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org } 1054a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org} 105526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com 105626f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 105726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com const SkRasterClip& clip, SkBlitter* blitter) { 105826f5a398c38318eb7eab44f72e024ef784d247fareed@google.com if (clip.isBW()) { 105926f5a398c38318eb7eab44f72e024ef784d247fareed@google.com AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter); 106026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com } else { 106126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com SkAAClipBlitterWrapper wrap(clip, blitter); 106226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter()); 106326f5a398c38318eb7eab44f72e024ef784d247fareed@google.com } 106426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com} 1065