gfx/skia/trunk/src/core/SkScan_Antihair.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial