1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkScan.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 12cb93a386Sopenharmony_ci#include "src/core/SkBlitter.h" 13cb93a386Sopenharmony_ci#include "src/core/SkFDot6.h" 14cb93a386Sopenharmony_ci#include "src/core/SkLineClipper.h" 15cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include <utility> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci/* Our attempt to compute the worst case "bounds" for the horizontal and 20cb93a386Sopenharmony_ci vertical cases has some numerical bug in it, and we sometimes undervalue 21cb93a386Sopenharmony_ci our extends. The bug is that when this happens, we will set the clip to 22cb93a386Sopenharmony_ci nullptr (for speed), and thus draw outside of the clip by a pixel, which might 23cb93a386Sopenharmony_ci only look bad, but it might also access memory outside of the valid range 24cb93a386Sopenharmony_ci allcoated for the device bitmap. 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci This define enables our fix to outset our "bounds" by 1, thus avoiding the 27cb93a386Sopenharmony_ci chance of the bug, but at the cost of sometimes taking the rectblitter 28cb93a386Sopenharmony_ci case (i.e. not setting the clip to nullptr) when we might not actually need 29cb93a386Sopenharmony_ci to. If we can improve/fix the actual calculations, then we can remove this 30cb93a386Sopenharmony_ci step. 31cb93a386Sopenharmony_ci */ 32cb93a386Sopenharmony_ci#define OUTSET_BEFORE_CLIP_TEST true 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci#define HLINE_STACK_BUFFER 100 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cistatic inline int SmallDot6Scale(int value, int dot6) { 37cb93a386Sopenharmony_ci SkASSERT((int16_t)value == value); 38cb93a386Sopenharmony_ci SkASSERT((unsigned)dot6 <= 64); 39cb93a386Sopenharmony_ci return (value * dot6) >> 6; 40cb93a386Sopenharmony_ci} 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci//#define TEST_GAMMA 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci#ifdef TEST_GAMMA 45cb93a386Sopenharmony_ci static uint8_t gGammaTable[256]; 46cb93a386Sopenharmony_ci #define ApplyGamma(table, alpha) (table)[alpha] 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci static void build_gamma_table() { 49cb93a386Sopenharmony_ci static bool gInit = false; 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci if (gInit == false) { 52cb93a386Sopenharmony_ci for (int i = 0; i < 256; i++) { 53cb93a386Sopenharmony_ci SkFixed n = i * 257; 54cb93a386Sopenharmony_ci n += n >> 15; 55cb93a386Sopenharmony_ci SkASSERT(n >= 0 && n <= SK_Fixed1); 56cb93a386Sopenharmony_ci n = SkFixedSqrt(n); 57cb93a386Sopenharmony_ci n = n * 255 >> 16; 58cb93a386Sopenharmony_ci // SkDebugf("morph %d -> %d\n", i, n); 59cb93a386Sopenharmony_ci gGammaTable[i] = SkToU8(n); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci gInit = true; 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci#else 65cb93a386Sopenharmony_ci #define ApplyGamma(table, alpha) SkToU8(alpha) 66cb93a386Sopenharmony_ci#endif 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_cistatic void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, 71cb93a386Sopenharmony_ci U8CPU alpha) { 72cb93a386Sopenharmony_ci SkASSERT(count > 0); 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci int16_t runs[HLINE_STACK_BUFFER + 1]; 75cb93a386Sopenharmony_ci uint8_t aa[HLINE_STACK_BUFFER]; 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci do { 78cb93a386Sopenharmony_ci // In theory, we should be able to just do this once (outside of the loop), 79cb93a386Sopenharmony_ci // since aa[] and runs[] are supposed" to be const when we call the blitter. 80cb93a386Sopenharmony_ci // In reality, some wrapper-blitters (e.g. SkRgnClipBlitter) cast away that 81cb93a386Sopenharmony_ci // constness, and modify the buffers in-place. Hence the need to be defensive 82cb93a386Sopenharmony_ci // here and reseed the aa value. 83cb93a386Sopenharmony_ci aa[0] = ApplyGamma(gGammaTable, alpha); 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci int n = count; 86cb93a386Sopenharmony_ci if (n > HLINE_STACK_BUFFER) { 87cb93a386Sopenharmony_ci n = HLINE_STACK_BUFFER; 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci runs[0] = SkToS16(n); 90cb93a386Sopenharmony_ci runs[n] = 0; 91cb93a386Sopenharmony_ci blitter->blitAntiH(x, y, aa, runs); 92cb93a386Sopenharmony_ci x += n; 93cb93a386Sopenharmony_ci count -= n; 94cb93a386Sopenharmony_ci } while (count > 0); 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ciclass SkAntiHairBlitter { 98cb93a386Sopenharmony_cipublic: 99cb93a386Sopenharmony_ci SkAntiHairBlitter() : fBlitter(nullptr) {} 100cb93a386Sopenharmony_ci virtual ~SkAntiHairBlitter() {} 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci SkBlitter* getBlitter() const { return fBlitter; } 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci void setup(SkBlitter* blitter) { 105cb93a386Sopenharmony_ci fBlitter = blitter; 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0; 109cb93a386Sopenharmony_ci virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0; 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ciprivate: 112cb93a386Sopenharmony_ci SkBlitter* fBlitter; 113cb93a386Sopenharmony_ci}; 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ciclass HLine_SkAntiHairBlitter : public SkAntiHairBlitter { 116cb93a386Sopenharmony_cipublic: 117cb93a386Sopenharmony_ci SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) override { 118cb93a386Sopenharmony_ci fy += SK_Fixed1/2; 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci int y = fy >> 16; 121cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fy >> 8) & 0xFF); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci // lower line 124cb93a386Sopenharmony_ci unsigned ma = SmallDot6Scale(a, mod64); 125cb93a386Sopenharmony_ci if (ma) { 126cb93a386Sopenharmony_ci call_hline_blitter(this->getBlitter(), x, y, 1, ma); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci // upper line 130cb93a386Sopenharmony_ci ma = SmallDot6Scale(255 - a, mod64); 131cb93a386Sopenharmony_ci if (ma) { 132cb93a386Sopenharmony_ci call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma); 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci return fy - SK_Fixed1/2; 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) override { 139cb93a386Sopenharmony_ci SkASSERT(x < stopx); 140cb93a386Sopenharmony_ci int count = stopx - x; 141cb93a386Sopenharmony_ci fy += SK_Fixed1/2; 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci int y = fy >> 16; 144cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fy >> 8) & 0xFF); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci // lower line 147cb93a386Sopenharmony_ci if (a) { 148cb93a386Sopenharmony_ci call_hline_blitter(this->getBlitter(), x, y, count, a); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci // upper line 152cb93a386Sopenharmony_ci a = 255 - a; 153cb93a386Sopenharmony_ci if (a) { 154cb93a386Sopenharmony_ci call_hline_blitter(this->getBlitter(), x, y - 1, count, a); 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci return fy - SK_Fixed1/2; 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci}; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ciclass Horish_SkAntiHairBlitter : public SkAntiHairBlitter { 162cb93a386Sopenharmony_cipublic: 163cb93a386Sopenharmony_ci SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) override { 164cb93a386Sopenharmony_ci fy += SK_Fixed1/2; 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci int lower_y = fy >> 16; 167cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fy >> 8) & 0xFF); 168cb93a386Sopenharmony_ci unsigned a0 = SmallDot6Scale(255 - a, mod64); 169cb93a386Sopenharmony_ci unsigned a1 = SmallDot6Scale(a, mod64); 170cb93a386Sopenharmony_ci this->getBlitter()->blitAntiV2(x, lower_y - 1, a0, a1); 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci return fy + dy - SK_Fixed1/2; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) override { 176cb93a386Sopenharmony_ci SkASSERT(x < stopx); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci fy += SK_Fixed1/2; 179cb93a386Sopenharmony_ci SkBlitter* blitter = this->getBlitter(); 180cb93a386Sopenharmony_ci do { 181cb93a386Sopenharmony_ci int lower_y = fy >> 16; 182cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fy >> 8) & 0xFF); 183cb93a386Sopenharmony_ci blitter->blitAntiV2(x, lower_y - 1, 255 - a, a); 184cb93a386Sopenharmony_ci fy += dy; 185cb93a386Sopenharmony_ci } while (++x < stopx); 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci return fy - SK_Fixed1/2; 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci}; 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ciclass VLine_SkAntiHairBlitter : public SkAntiHairBlitter { 192cb93a386Sopenharmony_cipublic: 193cb93a386Sopenharmony_ci SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) override { 194cb93a386Sopenharmony_ci SkASSERT(0 == dx); 195cb93a386Sopenharmony_ci fx += SK_Fixed1/2; 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci int x = fx >> 16; 198cb93a386Sopenharmony_ci int a = (uint8_t)((fx >> 8) & 0xFF); 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci unsigned ma = SmallDot6Scale(a, mod64); 201cb93a386Sopenharmony_ci if (ma) { 202cb93a386Sopenharmony_ci this->getBlitter()->blitV(x, y, 1, ma); 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci ma = SmallDot6Scale(255 - a, mod64); 205cb93a386Sopenharmony_ci if (ma) { 206cb93a386Sopenharmony_ci this->getBlitter()->blitV(x - 1, y, 1, ma); 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci return fx - SK_Fixed1/2; 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) override { 213cb93a386Sopenharmony_ci SkASSERT(y < stopy); 214cb93a386Sopenharmony_ci SkASSERT(0 == dx); 215cb93a386Sopenharmony_ci fx += SK_Fixed1/2; 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci int x = fx >> 16; 218cb93a386Sopenharmony_ci int a = (uint8_t)((fx >> 8) & 0xFF); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci if (a) { 221cb93a386Sopenharmony_ci this->getBlitter()->blitV(x, y, stopy - y, a); 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci a = 255 - a; 224cb93a386Sopenharmony_ci if (a) { 225cb93a386Sopenharmony_ci this->getBlitter()->blitV(x - 1, y, stopy - y, a); 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci return fx - SK_Fixed1/2; 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci}; 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ciclass Vertish_SkAntiHairBlitter : public SkAntiHairBlitter { 233cb93a386Sopenharmony_cipublic: 234cb93a386Sopenharmony_ci SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) override { 235cb93a386Sopenharmony_ci fx += SK_Fixed1/2; 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci int x = fx >> 16; 238cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fx >> 8) & 0xFF); 239cb93a386Sopenharmony_ci this->getBlitter()->blitAntiH2(x - 1, y, 240cb93a386Sopenharmony_ci SmallDot6Scale(255 - a, mod64), SmallDot6Scale(a, mod64)); 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci return fx + dx - SK_Fixed1/2; 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) override { 246cb93a386Sopenharmony_ci SkASSERT(y < stopy); 247cb93a386Sopenharmony_ci fx += SK_Fixed1/2; 248cb93a386Sopenharmony_ci do { 249cb93a386Sopenharmony_ci int x = fx >> 16; 250cb93a386Sopenharmony_ci uint8_t a = (uint8_t)((fx >> 8) & 0xFF); 251cb93a386Sopenharmony_ci this->getBlitter()->blitAntiH2(x - 1, y, 255 - a, a); 252cb93a386Sopenharmony_ci fx += dx; 253cb93a386Sopenharmony_ci } while (++y < stopy); 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci return fx - SK_Fixed1/2; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci}; 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_cistatic inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { 260cb93a386Sopenharmony_ci SkASSERT((SkLeftShift(a, 16) >> 16) == a); 261cb93a386Sopenharmony_ci SkASSERT(b != 0); 262cb93a386Sopenharmony_ci return SkLeftShift(a, 16) / b; 263cb93a386Sopenharmony_ci} 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci#define SkBITCOUNT(x) (sizeof(x) << 3) 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci#if 1 268cb93a386Sopenharmony_ci// returns high-bit set iff x==0x8000... 269cb93a386Sopenharmony_cistatic inline int bad_int(int x) { 270cb93a386Sopenharmony_ci return x & -x; 271cb93a386Sopenharmony_ci} 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_cistatic int any_bad_ints(int a, int b, int c, int d) { 274cb93a386Sopenharmony_ci return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1); 275cb93a386Sopenharmony_ci} 276cb93a386Sopenharmony_ci#else 277cb93a386Sopenharmony_cistatic inline int good_int(int x) { 278cb93a386Sopenharmony_ci return x ^ (1 << (SkBITCOUNT(x) - 1)); 279cb93a386Sopenharmony_ci} 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_cistatic int any_bad_ints(int a, int b, int c, int d) { 282cb93a386Sopenharmony_ci return !(good_int(a) & good_int(b) & good_int(c) & good_int(d)); 283cb93a386Sopenharmony_ci} 284cb93a386Sopenharmony_ci#endif 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci#ifdef SK_DEBUG 287cb93a386Sopenharmony_cistatic bool canConvertFDot6ToFixed(SkFDot6 x) { 288cb93a386Sopenharmony_ci const int maxDot6 = SK_MaxS32 >> (16 - 6); 289cb93a386Sopenharmony_ci return SkAbs32(x) <= maxDot6; 290cb93a386Sopenharmony_ci} 291cb93a386Sopenharmony_ci#endif 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci/* 294cb93a386Sopenharmony_ci * We want the fractional part of ordinate, but we want multiples of 64 to 295cb93a386Sopenharmony_ci * return 64, not 0, so we can't just say (ordinate & 63). 296cb93a386Sopenharmony_ci * We basically want to compute those bits, and if they're 0, return 64. 297cb93a386Sopenharmony_ci * We can do that w/o a branch with an extra sub and add. 298cb93a386Sopenharmony_ci */ 299cb93a386Sopenharmony_cistatic int contribution_64(SkFDot6 ordinate) { 300cb93a386Sopenharmony_ci#if 0 301cb93a386Sopenharmony_ci int result = ordinate & 63; 302cb93a386Sopenharmony_ci if (0 == result) { 303cb93a386Sopenharmony_ci result = 64; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci#else 306cb93a386Sopenharmony_ci int result = ((ordinate - 1) & 63) + 1; 307cb93a386Sopenharmony_ci#endif 308cb93a386Sopenharmony_ci SkASSERT(result > 0 && result <= 64); 309cb93a386Sopenharmony_ci return result; 310cb93a386Sopenharmony_ci} 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_cistatic void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, 313cb93a386Sopenharmony_ci const SkIRect* clip, SkBlitter* blitter) { 314cb93a386Sopenharmony_ci // check for integer NaN (0x80000000) which we can't handle (can't negate it) 315cb93a386Sopenharmony_ci // It appears typically from a huge float (inf or nan) being converted to int. 316cb93a386Sopenharmony_ci // If we see it, just don't draw. 317cb93a386Sopenharmony_ci if (any_bad_ints(x0, y0, x1, y1)) { 318cb93a386Sopenharmony_ci return; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time 322cb93a386Sopenharmony_ci // (in dot6 format) 323cb93a386Sopenharmony_ci SkASSERT(canConvertFDot6ToFixed(x0)); 324cb93a386Sopenharmony_ci SkASSERT(canConvertFDot6ToFixed(y0)); 325cb93a386Sopenharmony_ci SkASSERT(canConvertFDot6ToFixed(x1)); 326cb93a386Sopenharmony_ci SkASSERT(canConvertFDot6ToFixed(y1)); 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) { 329cb93a386Sopenharmony_ci /* instead of (x0 + x1) >> 1, we shift each separately. This is less 330cb93a386Sopenharmony_ci precise, but avoids overflowing the intermediate result if the 331cb93a386Sopenharmony_ci values are huge. A better fix might be to clip the original pts 332cb93a386Sopenharmony_ci directly (i.e. do the divide), so we don't spend time subdividing 333cb93a386Sopenharmony_ci huge lines at all. 334cb93a386Sopenharmony_ci */ 335cb93a386Sopenharmony_ci int hx = (x0 >> 1) + (x1 >> 1); 336cb93a386Sopenharmony_ci int hy = (y0 >> 1) + (y1 >> 1); 337cb93a386Sopenharmony_ci do_anti_hairline(x0, y0, hx, hy, clip, blitter); 338cb93a386Sopenharmony_ci do_anti_hairline(hx, hy, x1, y1, clip, blitter); 339cb93a386Sopenharmony_ci return; 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci int scaleStart, scaleStop; 343cb93a386Sopenharmony_ci int istart, istop; 344cb93a386Sopenharmony_ci SkFixed fstart, slope; 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci HLine_SkAntiHairBlitter hline_blitter; 347cb93a386Sopenharmony_ci Horish_SkAntiHairBlitter horish_blitter; 348cb93a386Sopenharmony_ci VLine_SkAntiHairBlitter vline_blitter; 349cb93a386Sopenharmony_ci Vertish_SkAntiHairBlitter vertish_blitter; 350cb93a386Sopenharmony_ci SkAntiHairBlitter* hairBlitter = nullptr; 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) { // mostly horizontal 353cb93a386Sopenharmony_ci if (x0 > x1) { // we want to go left-to-right 354cb93a386Sopenharmony_ci using std::swap; 355cb93a386Sopenharmony_ci swap(x0, x1); 356cb93a386Sopenharmony_ci swap(y0, y1); 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci istart = SkFDot6Floor(x0); 360cb93a386Sopenharmony_ci istop = SkFDot6Ceil(x1); 361cb93a386Sopenharmony_ci fstart = SkFDot6ToFixed(y0); 362cb93a386Sopenharmony_ci if (y0 == y1) { // completely horizontal, take fast case 363cb93a386Sopenharmony_ci slope = 0; 364cb93a386Sopenharmony_ci hairBlitter = &hline_blitter; 365cb93a386Sopenharmony_ci } else { 366cb93a386Sopenharmony_ci slope = fastfixdiv(y1 - y0, x1 - x0); 367cb93a386Sopenharmony_ci SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1); 368cb93a386Sopenharmony_ci fstart += (slope * (32 - (x0 & 63)) + 32) >> 6; 369cb93a386Sopenharmony_ci hairBlitter = &horish_blitter; 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci SkASSERT(istop > istart); 373cb93a386Sopenharmony_ci if (istop - istart == 1) { 374cb93a386Sopenharmony_ci // we are within a single pixel 375cb93a386Sopenharmony_ci scaleStart = x1 - x0; 376cb93a386Sopenharmony_ci SkASSERT(scaleStart >= 0 && scaleStart <= 64); 377cb93a386Sopenharmony_ci scaleStop = 0; 378cb93a386Sopenharmony_ci } else { 379cb93a386Sopenharmony_ci scaleStart = 64 - (x0 & 63); 380cb93a386Sopenharmony_ci scaleStop = x1 & 63; 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci if (clip){ 384cb93a386Sopenharmony_ci if (istart >= clip->fRight || istop <= clip->fLeft) { 385cb93a386Sopenharmony_ci return; 386cb93a386Sopenharmony_ci } 387cb93a386Sopenharmony_ci if (istart < clip->fLeft) { 388cb93a386Sopenharmony_ci fstart += slope * (clip->fLeft - istart); 389cb93a386Sopenharmony_ci istart = clip->fLeft; 390cb93a386Sopenharmony_ci scaleStart = 64; 391cb93a386Sopenharmony_ci if (istop - istart == 1) { 392cb93a386Sopenharmony_ci // we are within a single pixel 393cb93a386Sopenharmony_ci scaleStart = contribution_64(x1); 394cb93a386Sopenharmony_ci scaleStop = 0; 395cb93a386Sopenharmony_ci } 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci if (istop > clip->fRight) { 398cb93a386Sopenharmony_ci istop = clip->fRight; 399cb93a386Sopenharmony_ci scaleStop = 0; // so we don't draw this last column 400cb93a386Sopenharmony_ci } 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci SkASSERT(istart <= istop); 403cb93a386Sopenharmony_ci if (istart == istop) { 404cb93a386Sopenharmony_ci return; 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci // now test if our Y values are completely inside the clip 407cb93a386Sopenharmony_ci int top, bottom; 408cb93a386Sopenharmony_ci if (slope >= 0) { // T2B 409cb93a386Sopenharmony_ci top = SkFixedFloorToInt(fstart - SK_FixedHalf); 410cb93a386Sopenharmony_ci bottom = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 411cb93a386Sopenharmony_ci } else { // B2T 412cb93a386Sopenharmony_ci bottom = SkFixedCeilToInt(fstart + SK_FixedHalf); 413cb93a386Sopenharmony_ci top = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 414cb93a386Sopenharmony_ci } 415cb93a386Sopenharmony_ci#ifdef OUTSET_BEFORE_CLIP_TEST 416cb93a386Sopenharmony_ci top -= 1; 417cb93a386Sopenharmony_ci bottom += 1; 418cb93a386Sopenharmony_ci#endif 419cb93a386Sopenharmony_ci if (top >= clip->fBottom || bottom <= clip->fTop) { 420cb93a386Sopenharmony_ci return; 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci if (clip->fTop <= top && clip->fBottom >= bottom) { 423cb93a386Sopenharmony_ci clip = nullptr; 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci } 426cb93a386Sopenharmony_ci } else { // mostly vertical 427cb93a386Sopenharmony_ci if (y0 > y1) { // we want to go top-to-bottom 428cb93a386Sopenharmony_ci using std::swap; 429cb93a386Sopenharmony_ci swap(x0, x1); 430cb93a386Sopenharmony_ci swap(y0, y1); 431cb93a386Sopenharmony_ci } 432cb93a386Sopenharmony_ci 433cb93a386Sopenharmony_ci istart = SkFDot6Floor(y0); 434cb93a386Sopenharmony_ci istop = SkFDot6Ceil(y1); 435cb93a386Sopenharmony_ci fstart = SkFDot6ToFixed(x0); 436cb93a386Sopenharmony_ci if (x0 == x1) { 437cb93a386Sopenharmony_ci if (y0 == y1) { // are we zero length? 438cb93a386Sopenharmony_ci return; // nothing to do 439cb93a386Sopenharmony_ci } 440cb93a386Sopenharmony_ci slope = 0; 441cb93a386Sopenharmony_ci hairBlitter = &vline_blitter; 442cb93a386Sopenharmony_ci } else { 443cb93a386Sopenharmony_ci slope = fastfixdiv(x1 - x0, y1 - y0); 444cb93a386Sopenharmony_ci SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1); 445cb93a386Sopenharmony_ci fstart += (slope * (32 - (y0 & 63)) + 32) >> 6; 446cb93a386Sopenharmony_ci hairBlitter = &vertish_blitter; 447cb93a386Sopenharmony_ci } 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci SkASSERT(istop > istart); 450cb93a386Sopenharmony_ci if (istop - istart == 1) { 451cb93a386Sopenharmony_ci // we are within a single pixel 452cb93a386Sopenharmony_ci scaleStart = y1 - y0; 453cb93a386Sopenharmony_ci SkASSERT(scaleStart >= 0 && scaleStart <= 64); 454cb93a386Sopenharmony_ci scaleStop = 0; 455cb93a386Sopenharmony_ci } else { 456cb93a386Sopenharmony_ci scaleStart = 64 - (y0 & 63); 457cb93a386Sopenharmony_ci scaleStop = y1 & 63; 458cb93a386Sopenharmony_ci } 459cb93a386Sopenharmony_ci 460cb93a386Sopenharmony_ci if (clip) { 461cb93a386Sopenharmony_ci if (istart >= clip->fBottom || istop <= clip->fTop) { 462cb93a386Sopenharmony_ci return; 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci if (istart < clip->fTop) { 465cb93a386Sopenharmony_ci fstart += slope * (clip->fTop - istart); 466cb93a386Sopenharmony_ci istart = clip->fTop; 467cb93a386Sopenharmony_ci scaleStart = 64; 468cb93a386Sopenharmony_ci if (istop - istart == 1) { 469cb93a386Sopenharmony_ci // we are within a single pixel 470cb93a386Sopenharmony_ci scaleStart = contribution_64(y1); 471cb93a386Sopenharmony_ci scaleStop = 0; 472cb93a386Sopenharmony_ci } 473cb93a386Sopenharmony_ci } 474cb93a386Sopenharmony_ci if (istop > clip->fBottom) { 475cb93a386Sopenharmony_ci istop = clip->fBottom; 476cb93a386Sopenharmony_ci scaleStop = 0; // so we don't draw this last row 477cb93a386Sopenharmony_ci } 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_ci SkASSERT(istart <= istop); 480cb93a386Sopenharmony_ci if (istart == istop) 481cb93a386Sopenharmony_ci return; 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci // now test if our X values are completely inside the clip 484cb93a386Sopenharmony_ci int left, right; 485cb93a386Sopenharmony_ci if (slope >= 0) { // L2R 486cb93a386Sopenharmony_ci left = SkFixedFloorToInt(fstart - SK_FixedHalf); 487cb93a386Sopenharmony_ci right = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf); 488cb93a386Sopenharmony_ci } else { // R2L 489cb93a386Sopenharmony_ci right = SkFixedCeilToInt(fstart + SK_FixedHalf); 490cb93a386Sopenharmony_ci left = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf); 491cb93a386Sopenharmony_ci } 492cb93a386Sopenharmony_ci#ifdef OUTSET_BEFORE_CLIP_TEST 493cb93a386Sopenharmony_ci left -= 1; 494cb93a386Sopenharmony_ci right += 1; 495cb93a386Sopenharmony_ci#endif 496cb93a386Sopenharmony_ci if (left >= clip->fRight || right <= clip->fLeft) { 497cb93a386Sopenharmony_ci return; 498cb93a386Sopenharmony_ci } 499cb93a386Sopenharmony_ci if (clip->fLeft <= left && clip->fRight >= right) { 500cb93a386Sopenharmony_ci clip = nullptr; 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci } 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci SkRectClipBlitter rectClipper; 506cb93a386Sopenharmony_ci if (clip) { 507cb93a386Sopenharmony_ci rectClipper.init(blitter, *clip); 508cb93a386Sopenharmony_ci blitter = &rectClipper; 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci SkASSERT(hairBlitter); 512cb93a386Sopenharmony_ci hairBlitter->setup(blitter); 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci#ifdef SK_DEBUG 515cb93a386Sopenharmony_ci if (scaleStart > 0 && scaleStop > 0) { 516cb93a386Sopenharmony_ci // be sure we don't draw twice in the same pixel 517cb93a386Sopenharmony_ci SkASSERT(istart < istop - 1); 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci#endif 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_ci fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart); 522cb93a386Sopenharmony_ci istart += 1; 523cb93a386Sopenharmony_ci int fullSpans = istop - istart - (scaleStop > 0); 524cb93a386Sopenharmony_ci if (fullSpans > 0) { 525cb93a386Sopenharmony_ci fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope); 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci if (scaleStop > 0) { 528cb93a386Sopenharmony_ci hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop); 529cb93a386Sopenharmony_ci } 530cb93a386Sopenharmony_ci} 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_civoid SkScan::AntiHairLineRgn(const SkPoint array[], int arrayCount, const SkRegion* clip, 533cb93a386Sopenharmony_ci SkBlitter* blitter) { 534cb93a386Sopenharmony_ci if (clip && clip->isEmpty()) { 535cb93a386Sopenharmony_ci return; 536cb93a386Sopenharmony_ci } 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_ci SkASSERT(clip == nullptr || !clip->getBounds().isEmpty()); 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci#ifdef TEST_GAMMA 541cb93a386Sopenharmony_ci build_gamma_table(); 542cb93a386Sopenharmony_ci#endif 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci const SkScalar max = SkIntToScalar(32767); 545cb93a386Sopenharmony_ci const SkRect fixedBounds = SkRect::MakeLTRB(-max, -max, max, max); 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci SkRect clipBounds; 548cb93a386Sopenharmony_ci if (clip) { 549cb93a386Sopenharmony_ci clipBounds.set(clip->getBounds()); 550cb93a386Sopenharmony_ci /* We perform integral clipping later on, but we do a scalar clip first 551cb93a386Sopenharmony_ci to ensure that our coordinates are expressible in fixed/integers. 552cb93a386Sopenharmony_ci 553cb93a386Sopenharmony_ci antialiased hairlines can draw up to 1/2 of a pixel outside of 554cb93a386Sopenharmony_ci their bounds, so we need to outset the clip before calling the 555cb93a386Sopenharmony_ci clipper. To make the numerics safer, we outset by a whole pixel, 556cb93a386Sopenharmony_ci since the 1/2 pixel boundary is important to the antihair blitter, 557cb93a386Sopenharmony_ci we don't want to risk numerical fate by chopping on that edge. 558cb93a386Sopenharmony_ci */ 559cb93a386Sopenharmony_ci clipBounds.outset(SK_Scalar1, SK_Scalar1); 560cb93a386Sopenharmony_ci } 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci for (int i = 0; i < arrayCount - 1; ++i) { 563cb93a386Sopenharmony_ci SkPoint pts[2]; 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci // We have to pre-clip the line to fit in a SkFixed, so we just chop 566cb93a386Sopenharmony_ci // the line. TODO find a way to actually draw beyond that range. 567cb93a386Sopenharmony_ci if (!SkLineClipper::IntersectLine(&array[i], fixedBounds, pts)) { 568cb93a386Sopenharmony_ci continue; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci if (clip && !SkLineClipper::IntersectLine(pts, clipBounds, pts)) { 572cb93a386Sopenharmony_ci continue; 573cb93a386Sopenharmony_ci } 574cb93a386Sopenharmony_ci 575cb93a386Sopenharmony_ci SkFDot6 x0 = SkScalarToFDot6(pts[0].fX); 576cb93a386Sopenharmony_ci SkFDot6 y0 = SkScalarToFDot6(pts[0].fY); 577cb93a386Sopenharmony_ci SkFDot6 x1 = SkScalarToFDot6(pts[1].fX); 578cb93a386Sopenharmony_ci SkFDot6 y1 = SkScalarToFDot6(pts[1].fY); 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci if (clip) { 581cb93a386Sopenharmony_ci SkFDot6 left = std::min(x0, x1); 582cb93a386Sopenharmony_ci SkFDot6 top = std::min(y0, y1); 583cb93a386Sopenharmony_ci SkFDot6 right = std::max(x0, x1); 584cb93a386Sopenharmony_ci SkFDot6 bottom = std::max(y0, y1); 585cb93a386Sopenharmony_ci SkIRect ir; 586cb93a386Sopenharmony_ci 587cb93a386Sopenharmony_ci ir.setLTRB(SkFDot6Floor(left) - 1, 588cb93a386Sopenharmony_ci SkFDot6Floor(top) - 1, 589cb93a386Sopenharmony_ci SkFDot6Ceil(right) + 1, 590cb93a386Sopenharmony_ci SkFDot6Ceil(bottom) + 1); 591cb93a386Sopenharmony_ci 592cb93a386Sopenharmony_ci if (clip->quickReject(ir)) { 593cb93a386Sopenharmony_ci continue; 594cb93a386Sopenharmony_ci } 595cb93a386Sopenharmony_ci if (!clip->quickContains(ir)) { 596cb93a386Sopenharmony_ci SkRegion::Cliperator iter(*clip, ir); 597cb93a386Sopenharmony_ci const SkIRect* r = &iter.rect(); 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci while (!iter.done()) { 600cb93a386Sopenharmony_ci do_anti_hairline(x0, y0, x1, y1, r, blitter); 601cb93a386Sopenharmony_ci iter.next(); 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci continue; 604cb93a386Sopenharmony_ci } 605cb93a386Sopenharmony_ci // fall through to no-clip case 606cb93a386Sopenharmony_ci } 607cb93a386Sopenharmony_ci do_anti_hairline(x0, y0, x1, y1, nullptr, blitter); 608cb93a386Sopenharmony_ci } 609cb93a386Sopenharmony_ci} 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_civoid SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip, 612cb93a386Sopenharmony_ci SkBlitter* blitter) { 613cb93a386Sopenharmony_ci SkPoint pts[5]; 614cb93a386Sopenharmony_ci 615cb93a386Sopenharmony_ci pts[0].set(rect.fLeft, rect.fTop); 616cb93a386Sopenharmony_ci pts[1].set(rect.fRight, rect.fTop); 617cb93a386Sopenharmony_ci pts[2].set(rect.fRight, rect.fBottom); 618cb93a386Sopenharmony_ci pts[3].set(rect.fLeft, rect.fBottom); 619cb93a386Sopenharmony_ci pts[4] = pts[0]; 620cb93a386Sopenharmony_ci SkScan::AntiHairLine(pts, 5, clip, blitter); 621cb93a386Sopenharmony_ci} 622cb93a386Sopenharmony_ci 623cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 624cb93a386Sopenharmony_ci 625cb93a386Sopenharmony_citypedef int FDot8; // 24.8 integer fixed point 626cb93a386Sopenharmony_ci 627cb93a386Sopenharmony_cistatic inline FDot8 SkFixedToFDot8(SkFixed x) { 628cb93a386Sopenharmony_ci return (x + 0x80) >> 8; 629cb93a386Sopenharmony_ci} 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_cistatic void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 632cb93a386Sopenharmony_ci SkBlitter* blitter) { 633cb93a386Sopenharmony_ci SkASSERT(L < R); 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_ci if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 636cb93a386Sopenharmony_ci blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L)); 637cb93a386Sopenharmony_ci return; 638cb93a386Sopenharmony_ci } 639cb93a386Sopenharmony_ci 640cb93a386Sopenharmony_ci int left = L >> 8; 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci if (L & 0xFF) { 643cb93a386Sopenharmony_ci blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF))); 644cb93a386Sopenharmony_ci left += 1; 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci int rite = R >> 8; 648cb93a386Sopenharmony_ci int width = rite - left; 649cb93a386Sopenharmony_ci if (width > 0) { 650cb93a386Sopenharmony_ci call_hline_blitter(blitter, left, top, width, alpha); 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci if (R & 0xFF) { 653cb93a386Sopenharmony_ci blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF)); 654cb93a386Sopenharmony_ci } 655cb93a386Sopenharmony_ci} 656cb93a386Sopenharmony_ci 657cb93a386Sopenharmony_cistatic void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter, 658cb93a386Sopenharmony_ci bool fillInner) { 659cb93a386Sopenharmony_ci // check for empty now that we're in our reduced precision space 660cb93a386Sopenharmony_ci if (L >= R || T >= B) { 661cb93a386Sopenharmony_ci return; 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci int top = T >> 8; 664cb93a386Sopenharmony_ci if (top == ((B - 1) >> 8)) { // just one scanline high 665cb93a386Sopenharmony_ci do_scanline(L, top, R, B - T - 1, blitter); 666cb93a386Sopenharmony_ci return; 667cb93a386Sopenharmony_ci } 668cb93a386Sopenharmony_ci 669cb93a386Sopenharmony_ci if (T & 0xFF) { 670cb93a386Sopenharmony_ci do_scanline(L, top, R, 256 - (T & 0xFF), blitter); 671cb93a386Sopenharmony_ci top += 1; 672cb93a386Sopenharmony_ci } 673cb93a386Sopenharmony_ci 674cb93a386Sopenharmony_ci int bot = B >> 8; 675cb93a386Sopenharmony_ci int height = bot - top; 676cb93a386Sopenharmony_ci if (height > 0) { 677cb93a386Sopenharmony_ci int left = L >> 8; 678cb93a386Sopenharmony_ci if (left == ((R - 1) >> 8)) { // just 1-pixel wide 679cb93a386Sopenharmony_ci blitter->blitV(left, top, height, R - L - 1); 680cb93a386Sopenharmony_ci } else { 681cb93a386Sopenharmony_ci if (L & 0xFF) { 682cb93a386Sopenharmony_ci blitter->blitV(left, top, height, 256 - (L & 0xFF)); 683cb93a386Sopenharmony_ci left += 1; 684cb93a386Sopenharmony_ci } 685cb93a386Sopenharmony_ci int rite = R >> 8; 686cb93a386Sopenharmony_ci int width = rite - left; 687cb93a386Sopenharmony_ci if (width > 0 && fillInner) { 688cb93a386Sopenharmony_ci blitter->blitRect(left, top, width, height); 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci if (R & 0xFF) { 691cb93a386Sopenharmony_ci blitter->blitV(rite, top, height, R & 0xFF); 692cb93a386Sopenharmony_ci } 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci } 695cb93a386Sopenharmony_ci 696cb93a386Sopenharmony_ci if (B & 0xFF) { 697cb93a386Sopenharmony_ci do_scanline(L, bot, R, B & 0xFF, blitter); 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci} 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_cistatic void antifillrect(const SkXRect& xr, SkBlitter* blitter) { 702cb93a386Sopenharmony_ci antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop), 703cb93a386Sopenharmony_ci SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom), 704cb93a386Sopenharmony_ci blitter, true); 705cb93a386Sopenharmony_ci} 706cb93a386Sopenharmony_ci 707cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 708cb93a386Sopenharmony_ci 709cb93a386Sopenharmony_civoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip, 710cb93a386Sopenharmony_ci SkBlitter* blitter) { 711cb93a386Sopenharmony_ci if (nullptr == clip) { 712cb93a386Sopenharmony_ci antifillrect(xr, blitter); 713cb93a386Sopenharmony_ci } else { 714cb93a386Sopenharmony_ci SkIRect outerBounds; 715cb93a386Sopenharmony_ci XRect_roundOut(xr, &outerBounds); 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci if (clip->isRect()) { 718cb93a386Sopenharmony_ci const SkIRect& clipBounds = clip->getBounds(); 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci if (clipBounds.contains(outerBounds)) { 721cb93a386Sopenharmony_ci antifillrect(xr, blitter); 722cb93a386Sopenharmony_ci } else { 723cb93a386Sopenharmony_ci SkXRect tmpR; 724cb93a386Sopenharmony_ci // this keeps our original edges fractional 725cb93a386Sopenharmony_ci XRect_set(&tmpR, clipBounds); 726cb93a386Sopenharmony_ci if (tmpR.intersect(xr)) { 727cb93a386Sopenharmony_ci antifillrect(tmpR, blitter); 728cb93a386Sopenharmony_ci } 729cb93a386Sopenharmony_ci } 730cb93a386Sopenharmony_ci } else { 731cb93a386Sopenharmony_ci SkRegion::Cliperator clipper(*clip, outerBounds); 732cb93a386Sopenharmony_ci const SkIRect& rr = clipper.rect(); 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci while (!clipper.done()) { 735cb93a386Sopenharmony_ci SkXRect tmpR; 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci // this keeps our original edges fractional 738cb93a386Sopenharmony_ci XRect_set(&tmpR, rr); 739cb93a386Sopenharmony_ci if (tmpR.intersect(xr)) { 740cb93a386Sopenharmony_ci antifillrect(tmpR, blitter); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci clipper.next(); 743cb93a386Sopenharmony_ci } 744cb93a386Sopenharmony_ci } 745cb93a386Sopenharmony_ci } 746cb93a386Sopenharmony_ci} 747cb93a386Sopenharmony_ci 748cb93a386Sopenharmony_civoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip, 749cb93a386Sopenharmony_ci SkBlitter* blitter) { 750cb93a386Sopenharmony_ci if (clip.isBW()) { 751cb93a386Sopenharmony_ci AntiFillXRect(xr, &clip.bwRgn(), blitter); 752cb93a386Sopenharmony_ci } else { 753cb93a386Sopenharmony_ci SkIRect outerBounds; 754cb93a386Sopenharmony_ci XRect_roundOut(xr, &outerBounds); 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci if (clip.quickContains(outerBounds)) { 757cb93a386Sopenharmony_ci AntiFillXRect(xr, nullptr, blitter); 758cb93a386Sopenharmony_ci } else { 759cb93a386Sopenharmony_ci SkAAClipBlitterWrapper wrapper(clip, blitter); 760cb93a386Sopenharmony_ci AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter()); 761cb93a386Sopenharmony_ci } 762cb93a386Sopenharmony_ci } 763cb93a386Sopenharmony_ci} 764cb93a386Sopenharmony_ci 765cb93a386Sopenharmony_ci/* This takes a float-rect, but with the key improvement that it has 766cb93a386Sopenharmony_ci already been clipped, so we know that it is safe to convert it into a 767cb93a386Sopenharmony_ci XRect (fixedpoint), as it won't overflow. 768cb93a386Sopenharmony_ci*/ 769cb93a386Sopenharmony_cistatic void antifillrect(const SkRect& r, SkBlitter* blitter) { 770cb93a386Sopenharmony_ci SkXRect xr; 771cb93a386Sopenharmony_ci 772cb93a386Sopenharmony_ci XRect_set(&xr, r); 773cb93a386Sopenharmony_ci antifillrect(xr, blitter); 774cb93a386Sopenharmony_ci} 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci/* We repeat the clipping logic of AntiFillXRect because the float rect might 777cb93a386Sopenharmony_ci overflow if we blindly converted it to an XRect. This sucks that we have to 778cb93a386Sopenharmony_ci repeat the clipping logic, but I don't see how to share the code/logic. 779cb93a386Sopenharmony_ci 780cb93a386Sopenharmony_ci We clip r (as needed) into one or more (smaller) float rects, and then pass 781cb93a386Sopenharmony_ci those to our version of antifillrect, which converts it into an XRect and 782cb93a386Sopenharmony_ci then calls the blit. 783cb93a386Sopenharmony_ci*/ 784cb93a386Sopenharmony_civoid SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip, 785cb93a386Sopenharmony_ci SkBlitter* blitter) { 786cb93a386Sopenharmony_ci if (clip) { 787cb93a386Sopenharmony_ci SkRect newR; 788cb93a386Sopenharmony_ci newR.set(clip->getBounds()); 789cb93a386Sopenharmony_ci if (!newR.intersect(origR)) { 790cb93a386Sopenharmony_ci return; 791cb93a386Sopenharmony_ci } 792cb93a386Sopenharmony_ci 793cb93a386Sopenharmony_ci const SkIRect outerBounds = newR.roundOut(); 794cb93a386Sopenharmony_ci 795cb93a386Sopenharmony_ci if (clip->isRect()) { 796cb93a386Sopenharmony_ci antifillrect(newR, blitter); 797cb93a386Sopenharmony_ci } else { 798cb93a386Sopenharmony_ci SkRegion::Cliperator clipper(*clip, outerBounds); 799cb93a386Sopenharmony_ci while (!clipper.done()) { 800cb93a386Sopenharmony_ci newR.set(clipper.rect()); 801cb93a386Sopenharmony_ci if (newR.intersect(origR)) { 802cb93a386Sopenharmony_ci antifillrect(newR, blitter); 803cb93a386Sopenharmony_ci } 804cb93a386Sopenharmony_ci clipper.next(); 805cb93a386Sopenharmony_ci } 806cb93a386Sopenharmony_ci } 807cb93a386Sopenharmony_ci } else { 808cb93a386Sopenharmony_ci antifillrect(origR, blitter); 809cb93a386Sopenharmony_ci } 810cb93a386Sopenharmony_ci} 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_civoid SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip, 813cb93a386Sopenharmony_ci SkBlitter* blitter) { 814cb93a386Sopenharmony_ci if (clip.isBW()) { 815cb93a386Sopenharmony_ci AntiFillRect(r, &clip.bwRgn(), blitter); 816cb93a386Sopenharmony_ci } else { 817cb93a386Sopenharmony_ci SkAAClipBlitterWrapper wrap(clip, blitter); 818cb93a386Sopenharmony_ci AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter()); 819cb93a386Sopenharmony_ci } 820cb93a386Sopenharmony_ci} 821cb93a386Sopenharmony_ci 822cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 823cb93a386Sopenharmony_ci 824cb93a386Sopenharmony_ci#define SkAlphaMulRound(a, b) SkMulDiv255Round(a, b) 825cb93a386Sopenharmony_ci 826cb93a386Sopenharmony_ci// calls blitRect() if the rectangle is non-empty 827cb93a386Sopenharmony_cistatic void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) { 828cb93a386Sopenharmony_ci if (L < R && T < B) { 829cb93a386Sopenharmony_ci blitter->blitRect(L, T, R - L, B - T); 830cb93a386Sopenharmony_ci } 831cb93a386Sopenharmony_ci} 832cb93a386Sopenharmony_ci 833cb93a386Sopenharmony_cistatic inline FDot8 SkScalarToFDot8(SkScalar x) { 834cb93a386Sopenharmony_ci return (int)(x * 256); 835cb93a386Sopenharmony_ci} 836cb93a386Sopenharmony_ci 837cb93a386Sopenharmony_cistatic inline int FDot8Floor(FDot8 x) { 838cb93a386Sopenharmony_ci return x >> 8; 839cb93a386Sopenharmony_ci} 840cb93a386Sopenharmony_ci 841cb93a386Sopenharmony_cistatic inline int FDot8Ceil(FDot8 x) { 842cb93a386Sopenharmony_ci return (x + 0xFF) >> 8; 843cb93a386Sopenharmony_ci} 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_ci// 1 - (1 - a)*(1 - b) 846cb93a386Sopenharmony_cistatic inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) { 847cb93a386Sopenharmony_ci // need precise rounding (not just SkAlphaMul) so that values like 848cb93a386Sopenharmony_ci // a=228, b=252 don't overflow the result 849cb93a386Sopenharmony_ci return SkToU8(a + b - SkAlphaMulRound(a, b)); 850cb93a386Sopenharmony_ci} 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_cistatic void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, 853cb93a386Sopenharmony_ci SkBlitter* blitter) { 854cb93a386Sopenharmony_ci SkASSERT(L < R); 855cb93a386Sopenharmony_ci 856cb93a386Sopenharmony_ci if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel 857cb93a386Sopenharmony_ci FDot8 widClamp = R - L; 858cb93a386Sopenharmony_ci // border case clamp 256 to 255 instead of going through call_hline_blitter 859cb93a386Sopenharmony_ci // see skbug/4406 860cb93a386Sopenharmony_ci widClamp = widClamp - (widClamp >> 8); 861cb93a386Sopenharmony_ci blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, widClamp)); 862cb93a386Sopenharmony_ci return; 863cb93a386Sopenharmony_ci } 864cb93a386Sopenharmony_ci 865cb93a386Sopenharmony_ci int left = L >> 8; 866cb93a386Sopenharmony_ci if (L & 0xFF) { 867cb93a386Sopenharmony_ci blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF)); 868cb93a386Sopenharmony_ci left += 1; 869cb93a386Sopenharmony_ci } 870cb93a386Sopenharmony_ci 871cb93a386Sopenharmony_ci int rite = R >> 8; 872cb93a386Sopenharmony_ci int width = rite - left; 873cb93a386Sopenharmony_ci if (width > 0) { 874cb93a386Sopenharmony_ci call_hline_blitter(blitter, left, top, width, alpha); 875cb93a386Sopenharmony_ci } 876cb93a386Sopenharmony_ci 877cb93a386Sopenharmony_ci if (R & 0xFF) { 878cb93a386Sopenharmony_ci blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF)); 879cb93a386Sopenharmony_ci } 880cb93a386Sopenharmony_ci} 881cb93a386Sopenharmony_ci 882cb93a386Sopenharmony_cistatic void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, 883cb93a386Sopenharmony_ci SkBlitter* blitter) { 884cb93a386Sopenharmony_ci SkASSERT(L < R && T < B); 885cb93a386Sopenharmony_ci 886cb93a386Sopenharmony_ci int top = T >> 8; 887cb93a386Sopenharmony_ci if (top == ((B - 1) >> 8)) { // just one scanline high 888cb93a386Sopenharmony_ci // We want the inverse of B-T, since we're the inner-stroke 889cb93a386Sopenharmony_ci int alpha = 256 - (B - T); 890cb93a386Sopenharmony_ci if (alpha) { 891cb93a386Sopenharmony_ci inner_scanline(L, top, R, alpha, blitter); 892cb93a386Sopenharmony_ci } 893cb93a386Sopenharmony_ci return; 894cb93a386Sopenharmony_ci } 895cb93a386Sopenharmony_ci 896cb93a386Sopenharmony_ci if (T & 0xFF) { 897cb93a386Sopenharmony_ci inner_scanline(L, top, R, T & 0xFF, blitter); 898cb93a386Sopenharmony_ci top += 1; 899cb93a386Sopenharmony_ci } 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci int bot = B >> 8; 902cb93a386Sopenharmony_ci int height = bot - top; 903cb93a386Sopenharmony_ci if (height > 0) { 904cb93a386Sopenharmony_ci if (L & 0xFF) { 905cb93a386Sopenharmony_ci blitter->blitV(L >> 8, top, height, L & 0xFF); 906cb93a386Sopenharmony_ci } 907cb93a386Sopenharmony_ci if (R & 0xFF) { 908cb93a386Sopenharmony_ci blitter->blitV(R >> 8, top, height, ~R & 0xFF); 909cb93a386Sopenharmony_ci } 910cb93a386Sopenharmony_ci } 911cb93a386Sopenharmony_ci 912cb93a386Sopenharmony_ci if (B & 0xFF) { 913cb93a386Sopenharmony_ci inner_scanline(L, bot, R, ~B & 0xFF, blitter); 914cb93a386Sopenharmony_ci } 915cb93a386Sopenharmony_ci} 916cb93a386Sopenharmony_ci 917cb93a386Sopenharmony_cistatic inline void align_thin_stroke(FDot8& edge1, FDot8& edge2) { 918cb93a386Sopenharmony_ci SkASSERT(edge1 <= edge2); 919cb93a386Sopenharmony_ci 920cb93a386Sopenharmony_ci if (FDot8Floor(edge1) == FDot8Floor(edge2)) { 921cb93a386Sopenharmony_ci edge2 -= (edge1 & 0xFF); 922cb93a386Sopenharmony_ci edge1 &= ~0xFF; 923cb93a386Sopenharmony_ci } 924cb93a386Sopenharmony_ci} 925cb93a386Sopenharmony_ci 926cb93a386Sopenharmony_civoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 927cb93a386Sopenharmony_ci const SkRegion* clip, SkBlitter* blitter) { 928cb93a386Sopenharmony_ci SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 929cb93a386Sopenharmony_ci 930cb93a386Sopenharmony_ci SkScalar rx = SkScalarHalf(strokeSize.fX); 931cb93a386Sopenharmony_ci SkScalar ry = SkScalarHalf(strokeSize.fY); 932cb93a386Sopenharmony_ci 933cb93a386Sopenharmony_ci // outset by the radius 934cb93a386Sopenharmony_ci FDot8 outerL = SkScalarToFDot8(r.fLeft - rx); 935cb93a386Sopenharmony_ci FDot8 outerT = SkScalarToFDot8(r.fTop - ry); 936cb93a386Sopenharmony_ci FDot8 outerR = SkScalarToFDot8(r.fRight + rx); 937cb93a386Sopenharmony_ci FDot8 outerB = SkScalarToFDot8(r.fBottom + ry); 938cb93a386Sopenharmony_ci 939cb93a386Sopenharmony_ci SkIRect outer; 940cb93a386Sopenharmony_ci // set outer to the outer rect of the outer section 941cb93a386Sopenharmony_ci outer.setLTRB(FDot8Floor(outerL), FDot8Floor(outerT), FDot8Ceil(outerR), FDot8Ceil(outerB)); 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ci SkBlitterClipper clipper; 944cb93a386Sopenharmony_ci if (clip) { 945cb93a386Sopenharmony_ci if (clip->quickReject(outer)) { 946cb93a386Sopenharmony_ci return; 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci if (!clip->contains(outer)) { 949cb93a386Sopenharmony_ci blitter = clipper.apply(blitter, clip, &outer); 950cb93a386Sopenharmony_ci } 951cb93a386Sopenharmony_ci // now we can ignore clip for the rest of the function 952cb93a386Sopenharmony_ci } 953cb93a386Sopenharmony_ci 954cb93a386Sopenharmony_ci // in case we lost a bit with diameter/2 955cb93a386Sopenharmony_ci rx = strokeSize.fX - rx; 956cb93a386Sopenharmony_ci ry = strokeSize.fY - ry; 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ci // inset by the radius 959cb93a386Sopenharmony_ci FDot8 innerL = SkScalarToFDot8(r.fLeft + rx); 960cb93a386Sopenharmony_ci FDot8 innerT = SkScalarToFDot8(r.fTop + ry); 961cb93a386Sopenharmony_ci FDot8 innerR = SkScalarToFDot8(r.fRight - rx); 962cb93a386Sopenharmony_ci FDot8 innerB = SkScalarToFDot8(r.fBottom - ry); 963cb93a386Sopenharmony_ci 964cb93a386Sopenharmony_ci // For sub-unit strokes, tweak the hulls such that one of the edges coincides with the pixel 965cb93a386Sopenharmony_ci // edge. This ensures that the general rect stroking logic below 966cb93a386Sopenharmony_ci // a) doesn't blit the same scanline twice 967cb93a386Sopenharmony_ci // b) computes the correct coverage when both edges fall within the same pixel 968cb93a386Sopenharmony_ci if (strokeSize.fX < 1 || strokeSize.fY < 1) { 969cb93a386Sopenharmony_ci align_thin_stroke(outerL, innerL); 970cb93a386Sopenharmony_ci align_thin_stroke(outerT, innerT); 971cb93a386Sopenharmony_ci align_thin_stroke(innerR, outerR); 972cb93a386Sopenharmony_ci align_thin_stroke(innerB, outerB); 973cb93a386Sopenharmony_ci } 974cb93a386Sopenharmony_ci 975cb93a386Sopenharmony_ci // stroke the outer hull 976cb93a386Sopenharmony_ci antifilldot8(outerL, outerT, outerR, outerB, blitter, false); 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_ci // set outer to the outer rect of the middle section 979cb93a386Sopenharmony_ci outer.setLTRB(FDot8Ceil(outerL), FDot8Ceil(outerT), FDot8Floor(outerR), FDot8Floor(outerB)); 980cb93a386Sopenharmony_ci 981cb93a386Sopenharmony_ci if (innerL >= innerR || innerT >= innerB) { 982cb93a386Sopenharmony_ci fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom, 983cb93a386Sopenharmony_ci blitter); 984cb93a386Sopenharmony_ci } else { 985cb93a386Sopenharmony_ci SkIRect inner; 986cb93a386Sopenharmony_ci // set inner to the inner rect of the middle section 987cb93a386Sopenharmony_ci inner.setLTRB(FDot8Floor(innerL), FDot8Floor(innerT), FDot8Ceil(innerR), FDot8Ceil(innerB)); 988cb93a386Sopenharmony_ci 989cb93a386Sopenharmony_ci // draw the frame in 4 pieces 990cb93a386Sopenharmony_ci fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop, 991cb93a386Sopenharmony_ci blitter); 992cb93a386Sopenharmony_ci fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom, 993cb93a386Sopenharmony_ci blitter); 994cb93a386Sopenharmony_ci fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom, 995cb93a386Sopenharmony_ci blitter); 996cb93a386Sopenharmony_ci fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom, 997cb93a386Sopenharmony_ci blitter); 998cb93a386Sopenharmony_ci 999cb93a386Sopenharmony_ci // now stroke the inner rect, which is similar to antifilldot8() except that 1000cb93a386Sopenharmony_ci // it treats the fractional coordinates with the inverse bias (since its 1001cb93a386Sopenharmony_ci // inner). 1002cb93a386Sopenharmony_ci innerstrokedot8(innerL, innerT, innerR, innerB, blitter); 1003cb93a386Sopenharmony_ci } 1004cb93a386Sopenharmony_ci} 1005cb93a386Sopenharmony_ci 1006cb93a386Sopenharmony_civoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, 1007cb93a386Sopenharmony_ci const SkRasterClip& clip, SkBlitter* blitter) { 1008cb93a386Sopenharmony_ci if (clip.isBW()) { 1009cb93a386Sopenharmony_ci AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter); 1010cb93a386Sopenharmony_ci } else { 1011cb93a386Sopenharmony_ci SkAAClipBlitterWrapper wrap(clip, blitter); 1012cb93a386Sopenharmony_ci AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter()); 1013cb93a386Sopenharmony_ci } 1014cb93a386Sopenharmony_ci} 1015