11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkScan.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkBlitter.h"
121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#include "SkRasterClip.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkFDot6.h"
148e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed#include "SkLineClipper.h"
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic void horiline(int x, int stopx, SkFixed fy, SkFixed dy,
1735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                     SkBlitter* blitter) {
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(x < stopx);
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        blitter->blitH(x, fy >> 16, 1);
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fy += dy;
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (++x < stopx);
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic void vertline(int y, int stopy, SkFixed fx, SkFixed dx,
2735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                     SkBlitter* blitter) {
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(y < stopy);
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        blitter->blitH(fx >> 16, y, 1);
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fx += dx;
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (++y < stopy);
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::HairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         const SkRegion* clip, SkBlitter* blitter) {
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkBlitterClipper    clipper;
398e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkRect  r;
408e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkIRect clipR, ptsR;
418e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkPoint pts[2] = { pt0, pt1 };
428e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed
438e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    if (clip) {
448e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // Perform a clip in scalar space, so we catch huge values which might
458e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // be missed after we convert to SkFDot6 (overflow)
468e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        r.set(clip->getBounds());
478e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        if (!SkLineClipper::IntersectLine(pts, r, pts)) {
488e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed            return;
498e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        }
508e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    }
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
528e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
538e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
548e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
558e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
568e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed
578e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed    if (clip) {
588e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // now perform clipping again, as the rounding to dot6 can wiggle us
598e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // our rects are really dot6 rects, but since we've already used
608e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // lineclipper, we know they will fit in 32bits (26.6)
618e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        const SkIRect& bounds = clip->getBounds();
628e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed
638e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
648e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed                  SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom));
658e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        ptsR.set(x0, y0, x1, y1);
668e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        ptsR.sort();
678e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed
688e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // outset the right and bottom, to account for how hairlines are
698e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // actually drawn, which may hit the pixel to the right or below of
708e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        // the coordinate
7187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger        ptsR.fRight += SK_FDot6One;
7287b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger        ptsR.fBottom += SK_FDot6One;
738e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed
748e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        if (!SkIRect::Intersects(ptsR, clipR)) {
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return;
768e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        }
778e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        if (clip->isRect() && clipR.contains(ptsR)) {
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            clip = NULL;
798e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed        } else {
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            blitter = clipper.apply(blitter, clip);
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFDot6 dx = x1 - x0;
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFDot6 dy = y1 - y0;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
8835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (x0 > x1) {   // we want to go left-to-right
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkTSwap<SkFDot6>(x0, x1);
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkTSwap<SkFDot6>(y0, y1);
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int ix0 = SkFDot6Round(x0);
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int ix1 = SkFDot6Round(x1);
9435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (ix0 == ix1) {// too short to draw
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return;
9635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed slope = SkFixedDiv(dy, dx);
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6);
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        horiline(ix0, ix1, startY, slope, blitter);
10235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } else {              // mostly vertical
10335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (y0 > y1) {   // we want to go top-to-bottom
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkTSwap<SkFDot6>(x0, x1);
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkTSwap<SkFDot6>(y0, y1);
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int iy0 = SkFDot6Round(y0);
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int iy1 = SkFDot6Round(y1);
10935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (iy0 == iy1) { // too short to draw
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return;
11135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed slope = SkFixedDiv(dx, dy);
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6);
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        vertline(iy0, iy1, startX, slope, blitter);
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// and double-hit the top-left.
1228e048c19870a898cecdde3b3c0d2d512e6f372c0Mike Reed// TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
1231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
12435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                      SkBlitter* blitter) {
1251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkAAClipBlitterWrapper wrapper;
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkBlitterClipper    clipper;
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkIRect             r;
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    r.set(SkScalarToFixed(rect.fLeft) >> 16,
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project          SkScalarToFixed(rect.fTop) >> 16,
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project          (SkScalarToFixed(rect.fRight) >> 16) + 1,
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project          (SkScalarToFixed(rect.fBottom) >> 16) + 1);
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (clip.quickReject(r)) {
1351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return;
1361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
1371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (!clip.quickContains(r)) {
1381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkRegion* clipRgn;
1391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (clip.isBW()) {
1401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            clipRgn = &clip.bwRgn();
1411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else {
1421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            wrapper.init(clip, blitter);
1431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            clipRgn = &wrapper.getRgn();
1441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            blitter = wrapper.getBlitter();
14535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
1461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        blitter = clipper.apply(blitter, clipRgn);
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int width = r.width();
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int height = r.height();
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if ((width | height) == 0) {
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
15435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
15535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (width <= 2 || height <= 2) {
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        blitter->blitRect(r.fLeft, r.fTop, width, height);
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // if we get here, we know we have 4 segments to draw
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    blitter->blitH(r.fLeft, r.fTop, width);                     // top
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2);      // left
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    blitter->blitH(r.fLeft, r.fBottom - 1, width);              // bottom
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
16635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPath.h"
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGeometry.h"
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
17135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic bool quad_too_curvy(const SkPoint pts[3]) {
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int compute_int_quad_dist(const SkPoint pts[3]) {
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // compute the vector between the control point ([1]) and the middle of the
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // line connecting the start and end ([0] and [2])
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX;
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY;
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we want everyone to be positive
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    dx = SkScalarAbs(dx);
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    dy = SkScalarAbs(dy);
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // convert to whole pixel values (use ceiling to be conservative)
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int idx = SkScalarCeil(dx);
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int idy = SkScalarCeil(dy);
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // use the cheap approx for distance
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (idx > idy) {
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return idx + (idy >> 1);
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return idy + (idx >> 1);
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level,
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                     void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*))
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 1
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (level > 0 && quad_too_curvy(pts))
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[5];
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopQuadAtHalf(pts, tmp);
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        hairquad(tmp, clip, blitter, level - 1, lineproc);
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        lineproc(pts[0], pts[2], clip, blitter);
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = 1 << level;
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkScalar dt = SkFixedToScalar(SK_Fixed1 >> level);
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar t = dt;
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint prevPt = pts[0];
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 1; i < count; i++) {
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint nextPt;
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkEvalQuadAt(pts, t, &nextPt);
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        lineproc(prevPt, nextPt, clip, blitter);
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        t += dt;
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        prevPt = nextPt;
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // draw the last line explicitly to 1.0, in case t didn't match that exactly
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    lineproc(prevPt, pts[2], clip, blitter);
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool cubic_too_curvy(const SkPoint pts[4])
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, int level,
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (level > 0 && cubic_too_curvy(pts))
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint tmp[7];
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkChopCubicAt(pts, tmp, SK_Scalar1/2);
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        haircubic(tmp, clip, blitter, level - 1, lineproc);
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        lineproc(pts[0], pts[3], clip, blitter);
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kMaxCubicSubdivideLevel 6
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kMaxQuadSubdivideLevel  5
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                      void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
25135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (path.isEmpty()) {
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
25335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkAAClipBlitterWrapper wrap;
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkIRect* clipR = NULL;
2571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkRegion* clip = NULL;
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    {
2600e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        SkIRect ibounds;
2610e747d6d0a794242bd214fa44a6a179baeadfdf9Mike Reed        path.getBounds().roundOut(&ibounds);
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ibounds.inset(-1, -1);
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (rclip.quickReject(ibounds)) {
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return;
26635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
2671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (!rclip.quickContains(ibounds)) {
2681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            clipR = &rclip.getBounds();
2691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            if (rclip.isBW()) {
2701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                clip = &rclip.bwRgn();
2711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            } else {
2721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                wrap.init(rclip, blitter);
2731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                blitter = wrap.getBlitter();
2741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                clip = &wrap.getRgn();
2751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            }
27635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Iter    iter(path, false);
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint         pts[4];
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Verb    verb;
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
28335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verb) {
28535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case SkPath::kLine_Verb:
28635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                lineproc(pts[0], pts[1], clip, blitter);
28735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
28835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case SkPath::kQuad_Verb: {
28935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                int d = compute_int_quad_dist(pts);
29035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                /*  quadratics approach the line connecting their start and end points
29135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                 4x closer with each subdivision, so we compute the number of
29235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                 subdivisions to be the minimum need to get that distance to be less
29335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                 than a pixel.
29435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                 */
29535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                int level = (33 - SkCLZ(d)) >> 1;
29635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    //          SkDebugf("----- distance %d computedLevel %d\n", d, computedLevel);
29735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                // sanity check on level (from the previous version)
29835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                if (level > kMaxQuadSubdivideLevel) {
29935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                    level = kMaxQuadSubdivideLevel;
30035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                }
30135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                hairquad(pts, clip, blitter, level, lineproc);
30235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
30435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            case SkPath::kCubic_Verb:
30535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
30635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
30735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            default:
30835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                break;
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::HairPath(const SkPath& path, const SkRasterClip& clip,
31435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                      SkBlitter* blitter) {
3151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    hair_path(path, clip, blitter, SkScan::HairLineRgn);
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip,
31935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                          SkBlitter* blitter) {
3201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    hair_path(path, clip, blitter, SkScan::AntiHairLineRgn);
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
32387b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
32587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenbergervoid SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
3261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                       const SkRasterClip& clip, SkBlitter* blitter) {
32787b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
32987b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    if (strokeSize.fX < 0 || strokeSize.fY < 0) {
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
33187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    }
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
33387b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    const SkScalar dx = strokeSize.fX;
33487b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    const SkScalar dy = strokeSize.fY;
33587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    SkScalar rx = SkScalarHalf(dx);
33687b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    SkScalar ry = SkScalarHalf(dy);
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRect   outer, tmp;
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
33987b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    outer.set(r.fLeft - rx, r.fTop - ry,
34087b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                r.fRight + rx, r.fBottom + ry);
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
34287b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    if (r.width() <= dx || r.height() <= dx) {
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScan::FillRect(outer, clip, blitter);
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
34787b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    tmp.set(outer.fLeft, outer.fTop, outer.fRight, outer.fTop + dy);
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScan::FillRect(tmp, clip, blitter);
34987b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    tmp.fTop = outer.fBottom - dy;
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    tmp.fBottom = outer.fBottom;
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScan::FillRect(tmp, clip, blitter);
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
35387b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    tmp.set(outer.fLeft, outer.fTop + dy, outer.fLeft + dx, outer.fBottom - dy);
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScan::FillRect(tmp, clip, blitter);
35587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger    tmp.fLeft = outer.fRight - dx;
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    tmp.fRight = outer.fRight;
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScan::FillRect(tmp, clip, blitter);
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::HairLine(const SkPoint& p0, const SkPoint& p1,
3611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                      const SkRasterClip& clip, SkBlitter* blitter) {
3621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (clip.isBW()) {
3631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
3641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else {
3651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkRegion* clipRgn = NULL;
3661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkRect r;
3671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkIRect ir;
3681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.set(p0.fX, p0.fY, p1.fX, p1.fY);
3691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.sort();
3701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
3711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.roundOut(&ir);
3721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
3731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkAAClipBlitterWrapper wrap;
3741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (!clip.quickContains(ir)) {
3751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            wrap.init(clip, blitter);
3761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            blitter = wrap.getBlitter();
3771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            clipRgn = &wrap.getRgn();
3781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
3791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        HairLineRgn(p0, p1, clipRgn, blitter);
3801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
3811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
3821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
3831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkScan::AntiHairLine(const SkPoint& p0, const SkPoint& p1,
3841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                          const SkRasterClip& clip, SkBlitter* blitter) {
3851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (clip.isBW()) {
3861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
3871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else {
3881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkRegion* clipRgn = NULL;
3891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkRect r;
3901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkIRect ir;
3911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.set(p0.fX, p0.fY, p1.fX, p1.fY);
3921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.sort();
3931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        r.roundOut(&ir);
3941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        ir.inset(-1, -1);
3951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
3961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkAAClipBlitterWrapper wrap;
3971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (!clip.quickContains(ir)) {
3981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            wrap.init(clip, blitter);
3991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            blitter = wrap.getBlitter();
4001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            clipRgn = &wrap.getRgn();
4011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
4021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        AntiHairLineRgn(p0, p1, clipRgn, blitter);
4031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
4041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
405