Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: skia/sgl/SkScan_Antihair.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/sgl/SkScan_AntiPath.cpp ('k') | skia/sgl/SkScan_Hairline.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* libs/graphics/sgl/SkScan_Antihair.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkScan.h"
19 #include "SkBlitter.h"
20 #include "SkColorPriv.h"
21 #include "SkRegion.h"
22 #include "SkFDot6.h"
23
24 /* Our attempt to compute the worst case "bounds" for the horizontal and
25 vertical cases has some numerical bug in it, and we sometimes undervalue
26 our extends. The bug is that when this happens, we will set the clip to
27 NULL (for speed), and thus draw outside of the clip by a pixel, which might
28 only look bad, but it might also access memory outside of the valid range
29 allcoated for the device bitmap.
30
31 This define enables our fix to outset our "bounds" by 1, thus avoiding the
32 chance of the bug, but at the cost of sometimes taking the rectblitter
33 case (i.e. not setting the clip to NULL) when we might not actually need
34 to. If we can improve/fix the actual calculations, then we can remove this
35 step.
36 */
37 #define OUTSET_BEFORE_CLIP_TEST true
38
39
40 #define HLINE_STACK_BUFFER 100
41
42 static inline int SmallDot6Scale(int value, int dot6) {
43 SkASSERT((int16_t)value == value);
44 SkASSERT((unsigned)dot6 <= 64);
45 return SkMulS16(value, dot6) >> 6;
46 }
47
48 //#define TEST_GAMMA
49
50 #ifdef TEST_GAMMA
51 static uint8_t gGammaTable[256];
52 #define ApplyGamma(table, alpha) (table)[alpha]
53
54 static void build_gamma_table()
55 {
56 static bool gInit = false;
57
58 if (gInit == false)
59 {
60 for (int i = 0; i < 256; i++)
61 {
62 SkFixed n = i * 257;
63 n += n >> 15;
64 SkASSERT(n >= 0 && n <= SK_Fixed1);
65 n = SkFixedSqrt(n);
66 n = n * 255 >> 16;
67 // SkDebugf("morph %d -> %d\n", i, n);
68 gGammaTable[i] = SkToU8(n);
69 }
70 gInit = true;
71 }
72 }
73 #else
74 #define ApplyGamma(table, alpha) SkToU8(alpha)
75 #endif
76
77 ///////////////////////////////////////////////////////////////////////////////
78
79 static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, U8CP U alpha)
80 {
81 SkASSERT(count > 0);
82
83 int16_t runs[HLINE_STACK_BUFFER + 1];
84 uint8_t aa[HLINE_STACK_BUFFER];
85
86 aa[0] = ApplyGamma(gGammaTable, alpha);
87 do {
88 int n = count;
89 if (n > HLINE_STACK_BUFFER)
90 n = HLINE_STACK_BUFFER;
91
92 runs[0] = SkToS16(n);
93 runs[n] = 0;
94 blitter->blitAntiH(x, y, aa, runs);
95 x += n;
96 count -= n;
97 } while (count > 0);
98 }
99
100 static SkFixed hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter, int mod64)
101 {
102 SkASSERT(x < stopx);
103 int count = stopx - x;
104 fy += SK_Fixed1/2;
105
106 int y = fy >> 16;
107 uint8_t a = (uint8_t)(fy >> 8);
108
109 // lower line
110 unsigned ma = SmallDot6Scale(a, mod64);
111 if (ma) {
112 call_hline_blitter(blitter, x, y, count, ma);
113 }
114
115 // upper line
116 ma = SmallDot6Scale(255 - a, mod64);
117 if (ma) {
118 call_hline_blitter(blitter, x, y - 1, count, ma);
119 }
120
121 return fy - SK_Fixed1/2;
122 }
123
124 static SkFixed horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitt er, int mod64)
125 {
126 SkASSERT(x < stopx);
127
128 #ifdef TEST_GAMMA
129 const uint8_t* gamma = gGammaTable;
130 #endif
131 int16_t runs[2];
132 uint8_t aa[1];
133
134 runs[0] = 1;
135 runs[1] = 0;
136
137 fy += SK_Fixed1/2;
138 do {
139 int lower_y = fy >> 16;
140 uint8_t a = (uint8_t)(fy >> 8);
141 unsigned ma = SmallDot6Scale(a, mod64);
142 if (ma)
143 {
144 aa[0] = ApplyGamma(gamma, ma);
145 blitter->blitAntiH(x, lower_y, aa, runs);
146 // the clipping blitters might edit runs, but should not affect us
147 SkASSERT(runs[0] == 1);
148 SkASSERT(runs[1] == 0);
149 }
150 ma = SmallDot6Scale(255 - a, mod64);
151 if (ma)
152 {
153 aa[0] = ApplyGamma(gamma, ma);
154 blitter->blitAntiH(x, lower_y - 1, aa, runs);
155 // the clipping blitters might edit runs, but should not affect us
156 SkASSERT(runs[0] == 1);
157 SkASSERT(runs[1] == 0);
158 }
159 fy += dy;
160 } while (++x < stopx);
161
162 return fy - SK_Fixed1/2;
163 }
164
165 static SkFixed vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter, int mod64)
166 {
167 SkASSERT(y < stopy);
168 fx += SK_Fixed1/2;
169
170 int x = fx >> 16;
171 int a = (uint8_t)(fx >> 8);
172
173 unsigned ma = SmallDot6Scale(a, mod64);
174 if (ma)
175 blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, ma));
176 ma = SmallDot6Scale(255 - a, mod64);
177 if (ma)
178 blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, ma));
179
180 return fx - SK_Fixed1/2;
181 }
182
183 static SkFixed vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blit ter, int mod64)
184 {
185 SkASSERT(y < stopy);
186 #ifdef TEST_GAMMA
187 const uint8_t* gamma = gGammaTable;
188 #endif
189 int16_t runs[3];
190 uint8_t aa[2];
191
192 runs[0] = 1;
193 runs[2] = 0;
194
195 fx += SK_Fixed1/2;
196 do {
197 int x = fx >> 16;
198 uint8_t a = (uint8_t)(fx >> 8);
199
200 aa[0] = ApplyGamma(gamma, SmallDot6Scale(255 - a, mod64));
201 aa[1] = ApplyGamma(gamma, SmallDot6Scale(a, mod64));
202 // the clippng blitters might overwrite this guy, so we have to reset it each time
203 runs[1] = 1;
204 blitter->blitAntiH(x - 1, y, aa, runs);
205 // the clipping blitters might edit runs, but should not affect us
206 SkASSERT(runs[0] == 1);
207 SkASSERT(runs[2] == 0);
208 fx += dx;
209 } while (++y < stopy);
210
211 return fx - SK_Fixed1/2;
212 }
213
214 typedef SkFixed (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope , SkBlitter*, int);
215
216 static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b)
217 {
218 SkASSERT((a << 16 >> 16) == a);
219 SkASSERT(b != 0);
220 return (a << 16) / b;
221 }
222
223 static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
224 const SkIRect* clip, SkBlitter* blitter)
225 {
226 // check that we're no larger than 511 pixels (so we can do a faster div).
227 // if we are, subdivide and call again
228
229 if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6( 511))
230 {
231 int hx = (x0 + x1) >> 1;
232 int hy = (y0 + y1) >> 1;
233 do_anti_hairline(x0, y0, hx, hy, clip, blitter);
234 do_anti_hairline(hx, hy, x1, y1, clip, blitter);
235 return;
236 }
237
238 int scaleStart, scaleStop;
239 int istart, istop;
240 SkFixed fstart, slope;
241 LineProc proc;
242
243 if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) // mostly horizontal
244 {
245 if (x0 > x1) { // we want to go left-to-right
246 SkTSwap<SkFDot6>(x0, x1);
247 SkTSwap<SkFDot6>(y0, y1);
248 }
249
250 istart = SkFDot6Floor(x0);
251 istop = SkFDot6Ceil(x1);
252 fstart = SkFDot6ToFixed(y0);
253 if (y0 == y1) { // completely horizontal, take fast case
254 slope = 0;
255 proc = hline;
256 } else {
257 slope = fastfixdiv(y1 - y0, x1 - x0);
258 SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
259 fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
260 proc = horish;
261 }
262
263 SkASSERT(istop > istart);
264 if (istop - istart == 1) {
265 scaleStart = x1 - x0;
266 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
267 scaleStop = 0;
268 } else {
269 scaleStart = 64 - (x0 & 63);
270 scaleStop = x1 & 63;
271 }
272
273 if (clip)
274 {
275 if (istart >= clip->fRight || istop <= clip->fLeft)
276 return;
277 if (istart < clip->fLeft)
278 {
279 fstart += slope * (clip->fLeft - istart);
280 istart = clip->fLeft;
281 scaleStart = 64;
282 }
283 if (istop > clip->fRight) {
284 istop = clip->fRight;
285 scaleStop = 64;
286 }
287 SkASSERT(istart <= istop);
288 if (istart == istop)
289 return;
290
291 // now test if our Y values are completely inside the clip
292 int top, bottom;
293 if (slope >= 0) // T2B
294 {
295 top = SkFixedFloor(fstart - SK_FixedHalf);
296 bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_ FixedHalf);
297 }
298 else // B2T
299 {
300 bottom = SkFixedCeil(fstart + SK_FixedHalf);
301 top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_Fi xedHalf);
302 }
303 if (OUTSET_BEFORE_CLIP_TEST) {
304 top -= 1;
305 bottom += 1;
306 }
307 if (top >= clip->fBottom || bottom <= clip->fTop)
308 return;
309 if (clip->fTop <= top && clip->fBottom >= bottom)
310 clip = NULL;
311 }
312 }
313 else // mostly vertical
314 {
315 if (y0 > y1) // we want to go top-to-bottom
316 {
317 SkTSwap<SkFDot6>(x0, x1);
318 SkTSwap<SkFDot6>(y0, y1);
319 }
320
321 istart = SkFDot6Floor(y0);
322 istop = SkFDot6Ceil(y1);
323 fstart = SkFDot6ToFixed(x0);
324 if (x0 == x1)
325 {
326 if (y0 == y1) { // are we zero length?
327 return; // nothing to do
328 }
329 slope = 0;
330 proc = vline;
331 }
332 else
333 {
334 slope = fastfixdiv(x1 - x0, y1 - y0);
335 SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
336 fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
337 proc = vertish;
338 }
339
340 SkASSERT(istop > istart);
341 if (istop - istart == 1) {
342 scaleStart = y1 - y0;
343 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
344 scaleStop = 0;
345 } else {
346 scaleStart = 64 - (y0 & 63);
347 scaleStop = y1 & 63;
348 }
349
350 if (clip)
351 {
352 if (istart >= clip->fBottom || istop <= clip->fTop)
353 return;
354 if (istart < clip->fTop)
355 {
356 fstart += slope * (clip->fTop - istart);
357 istart = clip->fTop;
358 scaleStart = 64;
359 }
360 if (istop > clip->fBottom) {
361 istop = clip->fBottom;
362 scaleStop = 64;
363 }
364 SkASSERT(istart <= istop);
365 if (istart == istop)
366 return;
367
368 // now test if our X values are completely inside the clip
369 int left, right;
370 if (slope >= 0) // L2R
371 {
372 left = SkFixedFloor(fstart - SK_FixedHalf);
373 right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_F ixedHalf);
374 }
375 else // R2L
376 {
377 right = SkFixedCeil(fstart + SK_FixedHalf);
378 left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_F ixedHalf);
379 }
380 if (OUTSET_BEFORE_CLIP_TEST) {
381 left -= 1;
382 right += 1;
383 }
384 if (left >= clip->fRight || right <= clip->fLeft)
385 return;
386 if (clip->fLeft <= left && clip->fRight >= right)
387 clip = NULL;
388 }
389 }
390
391 SkRectClipBlitter rectClipper;
392 if (clip)
393 {
394 rectClipper.init(blitter, *clip);
395 blitter = &rectClipper;
396 }
397
398 fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart);
399 istart += 1;
400 int fullSpans = istop - istart - 1;
401 if (fullSpans > 0) {
402 fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64);
403 }
404 if (scaleStop > 0) {
405 proc(istop - 1, istop, fstart, slope, blitter, scaleStop);
406 }
407 }
408
409 void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
410 const SkRegion* clip, SkBlitter* blitter)
411 {
412 if (clip && clip->isEmpty())
413 return;
414
415 SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
416
417 #ifdef TEST_GAMMA
418 build_gamma_table();
419 #endif
420
421 SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
422 SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
423 SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
424 SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
425
426 if (clip)
427 {
428 SkFDot6 left = SkMin32(x0, x1);
429 SkFDot6 top = SkMin32(y0, y1);
430 SkFDot6 right = SkMax32(x0, x1);
431 SkFDot6 bottom = SkMax32(y0, y1);
432 SkIRect ir;
433
434 ir.set( SkFDot6Floor(left) - 1,
435 SkFDot6Floor(top) - 1,
436 SkFDot6Ceil(right) + 1,
437 SkFDot6Ceil(bottom) + 1);
438
439 if (clip->quickReject(ir))
440 return;
441 if (!clip->quickContains(ir))
442 {
443 SkRegion::Cliperator iter(*clip, ir);
444 const SkIRect* r = &iter.rect();
445
446 while (!iter.done())
447 {
448 do_anti_hairline(x0, y0, x1, y1, r, blitter);
449 iter.next();
450 }
451 return;
452 }
453 // fall through to no-clip case
454 }
455 do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
456 }
457
458 void SkScan::AntiHairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* b litter)
459 {
460 if (clip)
461 {
462 SkIRect ir;
463 SkRect r = rect;
464
465 r.inset(-SK_Scalar1/2, -SK_Scalar1/2);
466 r.roundOut(&ir);
467 if (clip->quickReject(ir))
468 return;
469 if (clip->quickContains(ir))
470 clip = NULL;
471 }
472
473 SkPoint p0, p1;
474
475 p0.set(rect.fLeft, rect.fTop);
476 p1.set(rect.fRight, rect.fTop);
477 SkScan::AntiHairLine(p0, p1, clip, blitter);
478 p0.set(rect.fRight, rect.fBottom);
479 SkScan::AntiHairLine(p0, p1, clip, blitter);
480 p1.set(rect.fLeft, rect.fBottom);
481 SkScan::AntiHairLine(p0, p1, clip, blitter);
482 p0.set(rect.fLeft, rect.fTop);
483 SkScan::AntiHairLine(p0, p1, clip, blitter);
484 }
485
486 //////////////////////////////////////////////////////////////////////////////// //////////
487
488 typedef int FDot8; // 24.8 integer fixed point
489
490 static inline FDot8 SkFixedToFDot8(SkFixed x) {
491 return (x + 0x80) >> 8;
492 }
493
494 static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter* blitt er)
495 {
496 SkASSERT(L < R);
497
498 if ((L >> 8) == ((R - 1) >> 8)) // 1x1 pixel
499 {
500 blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
501 return;
502 }
503
504 int left = L >> 8;
505
506 if (L & 0xFF)
507 {
508 blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
509 left += 1;
510 }
511
512 int rite = R >> 8;
513 int width = rite - left;
514 if (width > 0)
515 call_hline_blitter(blitter, left, top, width, alpha);
516
517 if (R & 0xFF)
518 blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
519 }
520
521 static void antifillrect(const SkXRect& xr, SkBlitter* blitter)
522 {
523 FDot8 L = SkFixedToFDot8(xr.fLeft);
524 FDot8 T = SkFixedToFDot8(xr.fTop);
525 FDot8 R = SkFixedToFDot8(xr.fRight);
526 FDot8 B = SkFixedToFDot8(xr.fBottom);
527
528 // check for empty now that we're in our reduced precision space
529 if (L >= R || T >= B)
530 return;
531
532 int top = T >> 8;
533 if (top == ((B - 1) >> 8)) // just one scanline high
534 {
535 do_scanline(L, top, R, B - T - 1, blitter);
536 return;
537 }
538
539 if (T & 0xFF)
540 {
541 do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
542 top += 1;
543 }
544
545 int bot = B >> 8;
546 int height = bot - top;
547 if (height > 0)
548 {
549 int left = L >> 8;
550 if (L & 0xFF)
551 {
552 blitter->blitV(left, top, height, 256 - (L & 0xFF));
553 left += 1;
554 }
555 int rite = R >> 8;
556 int width = rite - left;
557 if (width > 0)
558 blitter->blitRect(left, top, width, height);
559 if (R & 0xFF)
560 blitter->blitV(rite, top, height, R & 0xFF);
561 }
562
563 if (B & 0xFF)
564 do_scanline(L, bot, R, B & 0xFF, blitter);
565 }
566
567 ///////////////////////////////////////////////////////////////////////////////
568
569 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
570 SkBlitter* blitter) {
571 if (clip) {
572 SkIRect outerBounds;
573 XRect_roundOut(xr, &outerBounds);
574
575 if (clip->isRect()) {
576 const SkIRect& clipBounds = clip->getBounds();
577
578 if (clipBounds.contains(outerBounds)) {
579 antifillrect(xr, blitter);
580 } else {
581 SkXRect tmpR;
582 // this keeps our original edges fractional
583 XRect_set(&tmpR, clipBounds);
584 if (tmpR.intersect(xr)) {
585 antifillrect(tmpR, blitter);
586 }
587 }
588 } else {
589 SkRegion::Cliperator clipper(*clip, outerBounds);
590 const SkIRect& rr = clipper.rect();
591
592 while (!clipper.done()) {
593 SkXRect tmpR;
594
595 // this keeps our original edges fractional
596 XRect_set(&tmpR, rr);
597 if (tmpR.intersect(xr)) {
598 antifillrect(tmpR, blitter);
599 }
600 clipper.next();
601 }
602 }
603 } else {
604 antifillrect(xr, blitter);
605 }
606 }
607
608 #ifdef SK_SCALAR_IS_FLOAT
609
610 /* This guy takes a float-rect, but with the key improvement that it has
611 already been clipped, so we know that it is safe to convert it into a
612 XRect (fixedpoint), as it won't overflow.
613 */
614 static void antifillrect(const SkRect& r, SkBlitter* blitter) {
615 SkXRect xr;
616
617 XRect_set(&xr, r);
618 antifillrect(xr, blitter);
619 }
620
621 /* We repeat the clipping logic of AntiFillXRect because the float rect might
622 overflow if we blindly converted it to an XRect. This sucks that we have to
623 repeat the clipping logic, but I don't see how to share the code/logic.
624
625 We clip r (as needed) into one or more (smaller) float rects, and then pass
626 those to our version of antifillrect, which converts it into an XRect and
627 then calls the blit.
628 */
629 void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip,
630 SkBlitter* blitter) {
631 if (clip) {
632 SkIRect outerBounds;
633 r.roundOut(&outerBounds);
634
635 if (clip->isRect()) {
636 const SkIRect& clipBounds = clip->getBounds();
637
638 if (clipBounds.contains(outerBounds)) {
639 antifillrect(r, blitter);
640 } else {
641 SkRect tmpR;
642 // this keeps our original edges fractional
643 tmpR.set(clipBounds);
644 if (tmpR.intersect(r)) {
645 antifillrect(tmpR, blitter);
646 }
647 }
648 } else {
649 SkRegion::Cliperator clipper(*clip, outerBounds);
650 const SkIRect& rr = clipper.rect();
651
652 while (!clipper.done()) {
653 SkRect tmpR;
654 // this keeps our original edges fractional
655 tmpR.set(rr);
656 if (tmpR.intersect(r)) {
657 antifillrect(tmpR, blitter);
658 }
659 clipper.next();
660 }
661 }
662 } else {
663 antifillrect(r, blitter);
664 }
665 }
666
667 #endif
668
669
OLDNEW
« no previous file with comments | « skia/sgl/SkScan_AntiPath.cpp ('k') | skia/sgl/SkScan_Hairline.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698