1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScanPriv.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkEdge.h"
11948639b823dc76dbaa8cc68f32c1f7defcb8fb07mike@reedtribe.org#include "SkEdgeBuilder.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkGeometry.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
14c07d23a6e220c0aff36e3e4e06c1b685a440108ereed@android.com#include "SkQuadClipper.h"
15045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h"
180a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#include "SkTSort.h"
190a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com
200951ded8d887174a3ca575e3295daae547c3c6f7reed@google.com#ifdef SK_USE_LEGACY_AA_COVERAGE
210951ded8d887174a3ca575e3295daae547c3c6f7reed@google.com    #define SK_USE_STD_SORT_FOR_EDGES
220951ded8d887174a3ca575e3295daae547c3c6f7reed@google.com#endif
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kEDGE_HEAD_Y    SK_MinS32
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kEDGE_TAIL_Y    SK_MaxS32
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    static void validate_sort(const SkEdge* edge) {
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int y = kEDGE_HEAD_Y;
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3199219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        while (edge->fFirstY != SK_MaxS32) {
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            edge->validate();
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(y <= edge->fFirstY);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            y = edge->fFirstY;
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            edge = edge->fNext;
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define validate_sort(edge)
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4399219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgstatic inline void remove_edge(SkEdge* edge) {
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge->fPrev->fNext = edge->fNext;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge->fNext->fPrev = edge->fPrev;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgstatic inline void swap_edges(SkEdge* prev, SkEdge* next) {
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(prev->fNext == next && next->fPrev == prev);
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // remove prev from the list
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    prev->fPrev->fNext = next;
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    next->fPrev = prev->fPrev;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // insert prev after next
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    prev->fNext = next->fNext;
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    next->fNext->fPrev = prev;
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    next->fNext = prev;
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    prev->fPrev = next;
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6299219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgstatic void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed x = edge->fX;
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6599219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    for (;;) {
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkEdge* prev = edge->fPrev;
6755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // add 1 to curr_y since we may have added new edges (built from curves)
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // that start on the next scanline
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(prev && prev->fFirstY <= curr_y + 1);
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7299219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        if (prev->fX <= x) {
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
7499219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        }
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        swap_edges(prev, edge);
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7999219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgstatic void insert_new_edges(SkEdge* newEdge, int curr_y) {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(newEdge->fFirstY >= curr_y);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8299219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    while (newEdge->fFirstY == curr_y) {
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkEdge* next = newEdge->fNext;
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        backward_insert_edge_based_on_x(newEdge  SkPARAM(curr_y));
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        newEdge = next;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
9099219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgstatic void validate_edges_for_y(const SkEdge* edge, int curr_y) {
9199219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    while (edge->fFirstY <= curr_y) {
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(edge->fPrev && edge->fNext);
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(edge->fPrev->fNext == edge);
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(edge->fNext->fPrev == edge);
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(edge->fFirstY <= edge->fLastY);
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(edge->fPrev->fX <= edge->fX);
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge = edge->fNext;
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define validate_edges_for_y(edge, curr_y)
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( push )
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( disable : 4701 )
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define PREPOST_START   true
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define PREPOST_END     false
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
115dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com                       SkBlitter* blitter, int start_y, int stop_y,
11699219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                       PrePostProc proc) {
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    validate_sort(prevHead->fNext);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
119dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    int curr_y = start_y;
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int windingMask = (fillType & 1) ? 1 : -1;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12399219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    for (;;) {
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int     w = 0;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int     left SK_INIT_TO_AVOID_WARNING;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bool    in_interval = false;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkEdge* currE = prevHead->fNext;
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFixed prevX = prevHead->fX;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        validate_edges_for_y(currE, curr_y);
13155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (proc) {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            proc(blitter, curr_y, PREPOST_START);    // pre-proc
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
13699219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        while (currE->fFirstY <= curr_y) {
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(currE->fLastY >= curr_y);
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1390a9cc44a40a2bc101da1af89926152098ffcc44breed@google.com            int x = SkFixedRoundToInt(currE->fX);
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            w += currE->fWinding;
14199219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            if ((w & windingMask) == 0) { // we finished an interval
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(in_interval);
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                int width = x - left;
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(width >= 0);
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (width)
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    blitter->blitH(left, curr_y, width);
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                in_interval = false;
14899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            } else if (!in_interval) {
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                left = x;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                in_interval = true;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkEdge* next = currE->fNext;
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkFixed newX;
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15699219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            if (currE->fLastY == curr_y) {    // are we done with this edge?
15799219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                if (currE->fCurveCount < 0) {
15899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                    if (((SkCubicEdge*)currE)->updateCubic()) {
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkASSERT(currE->fFirstY == curr_y + 1);
16055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        newX = currE->fX;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        goto NEXT_X;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    }
16499219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                } else if (currE->fCurveCount > 0) {
16599219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                    if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        newX = currE->fX;
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        goto NEXT_X;
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    }
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                remove_edge(currE);
17199219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            } else {
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(currE->fLastY > curr_y);
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                newX = currE->fX + currE->fDX;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                currE->fX = newX;
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            NEXT_X:
17699219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                if (newX < prevX) { // ripple currE backwards until it is x-sorted
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    backward_insert_edge_based_on_x(currE  SkPARAM(curr_y));
17899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                } else {
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    prevX = newX;
18099219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                }
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            currE = next;
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(currE);
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
18555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (proc) {
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            proc(blitter, curr_y, PREPOST_END);    // post-proc
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        curr_y += 1;
19199219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        if (curr_y >= stop_y) {
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
19399219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        }
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now currE points to the first edge with a Yint larger than curr_y
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        insert_new_edges(currE, curr_y);
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
199e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com// return true if we're done with this edge
200e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.comstatic bool update_edge(SkEdge* edge, int last_y) {
201e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkASSERT(edge->fLastY >= last_y);
202e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    if (last_y == edge->fLastY) {
203e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        if (edge->fCurveCount < 0) {
204e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            if (((SkCubicEdge*)edge)->updateCubic()) {
205e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                SkASSERT(edge->fFirstY == last_y + 1);
206e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                return false;
207e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            }
208e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        } else if (edge->fCurveCount > 0) {
209e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
210e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                SkASSERT(edge->fFirstY == last_y + 1);
211e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                return false;
212e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            }
213e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        }
214e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        return true;
215e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    }
216e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    return false;
217e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com}
218e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com
219e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.comstatic void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
220e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                              SkBlitter* blitter, int start_y, int stop_y,
221e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                              PrePostProc proc) {
222e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    validate_sort(prevHead->fNext);
223fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
224e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkEdge* leftE = prevHead->fNext;
225e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkEdge* riteE = leftE->fNext;
226e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkEdge* currE = riteE->fNext;
227fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org
228fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org#if 0
229e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    int local_top = leftE->fFirstY;
230e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkASSERT(local_top == riteE->fFirstY);
231fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org#else
232fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org    // our edge choppers for curves can result in the initial edges
233fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org    // not lining up, so we take the max.
234fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org    int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY);
235fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org#endif
236e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    SkASSERT(local_top >= start_y);
237fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
238e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    for (;;) {
239e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(leftE->fFirstY <= stop_y);
240e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(riteE->fFirstY <= stop_y);
241e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com
242e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
243e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                                      leftE->fDX > riteE->fDX)) {
244e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            SkTSwap(leftE, riteE);
245e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        }
246fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
247e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        int local_bot = SkMin32(leftE->fLastY, riteE->fLastY);
248a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com        local_bot = SkMin32(local_bot, stop_y - 1);
249e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(local_top <= local_bot);
250fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
251e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkFixed left = leftE->fX;
252e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkFixed dLeft = leftE->fDX;
253e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkFixed rite = riteE->fX;
254e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkFixed dRite = riteE->fDX;
255e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        int count = local_bot - local_top;
256e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(count >= 0);
257562a2ac95b8cd8b359574f8c4d6300b0475938dbreed@google.com        if (0 == (dLeft | dRite)) {
2580a9cc44a40a2bc101da1af89926152098ffcc44breed@google.com            int L = SkFixedRoundToInt(left);
2590a9cc44a40a2bc101da1af89926152098ffcc44breed@google.com            int R = SkFixedRoundToInt(rite);
260e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            if (L < R) {
261e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                count += 1;
262e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                blitter->blitRect(L, local_top, R - L, count);
263e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                left += count * dLeft;
264e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                rite += count * dRite;
265e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            }
266fc5da9266eae18f1ee3635a061af27788ad4b62emike@reedtribe.org            local_top = local_bot + 1;
267e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        } else {
268e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            do {
2690a9cc44a40a2bc101da1af89926152098ffcc44breed@google.com                int L = SkFixedRoundToInt(left);
2700a9cc44a40a2bc101da1af89926152098ffcc44breed@google.com                int R = SkFixedRoundToInt(rite);
271e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                if (L < R) {
272e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                    blitter->blitH(L, local_top, R - L);
273e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                }
274e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                left += dLeft;
275e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                rite += dRite;
276e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                local_top += 1;
277e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            } while (--count >= 0);
278e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        }
279e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com
280e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        leftE->fX = left;
281e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        riteE->fX = rite;
282e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com
283e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        if (update_edge(leftE, local_bot)) {
284e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            if (currE->fFirstY >= stop_y) {
285e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                break;
286e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            }
287e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            leftE = currE;
288e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            currE = currE->fNext;
289e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        }
290e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        if (update_edge(riteE, local_bot)) {
291e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            if (currE->fFirstY >= stop_y) {
292e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com                break;
293e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            }
294e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            riteE = currE;
295e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com            currE = currE->fNext;
296e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        }
297fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
298e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(leftE);
299e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        SkASSERT(riteE);
300a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com
301a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com        // check our bottom clip
302a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com        SkASSERT(local_top == local_bot + 1);
303a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com        if (local_top >= stop_y) {
304a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com            break;
305a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com        }
306e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    }
307e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com}
308e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this guy overrides blitH, and will call its proxy blitter with the inverse
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// of the spans it is given (clipped to the left/right of the cliprect)
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// used to implement inverse filltypes on paths
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass InverseBlitter : public SkBlitter {
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlitter = blitter;
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fFirstX = clip.fLeft << shift;
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fLastX = clip.fRight << shift;
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void prepost(int y, bool isStart) {
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (isStart) {
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevX = fFirstX;
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int invWidth = fLastX - fPrevX;
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (invWidth > 0) {
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fBlitter->blitH(fPrevX, y, invWidth);
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // overrides
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitH(int x, int y, int width) {
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int invWidth = x - fPrevX;
3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (invWidth > 0) {
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBlitter->blitH(fPrevX, y, invWidth);
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fPrevX = x + width;
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
34255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we do not expect to get called with these entrypoints
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) {
3450c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("blitAntiH unexpected");
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitV(int x, int y, int height, SkAlpha alpha) {
3480c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("blitV unexpected");
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitRect(int x, int y, int width, int height) {
3510c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("blitRect unexpected");
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitMask(const SkMask&, const SkIRect& clip) {
3540c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("blitMask unexpected");
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) {
3570c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("justAnOpaqueColor unexpected");
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return NULL;
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
36055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlitter*  fBlitter;
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         fFirstX, fLastX, fPrevX;
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ((InverseBlitter*)blitter)->prepost(y, isStart);
3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if defined _WIN32 && _MSC_VER >= 1300
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( pop )
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3760a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#ifdef SK_USE_STD_SORT_FOR_EDGES
377e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.comextern "C" {
378e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    static int edge_compare(const void* a, const void* b) {
379e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        const SkEdge* edgea = *(const SkEdge**)a;
380e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        const SkEdge* edgeb = *(const SkEdge**)b;
38155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
382e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        int valuea = edgea->fFirstY;
383e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        int valueb = edgeb->fFirstY;
38455b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
385e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        if (valuea == valueb) {
386e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com            valuea = edgea->fX;
387e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com            valueb = edgeb->fX;
388e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        }
38955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
390e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        // this overflows if valuea >>> valueb or vice-versa
391e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        //     return valuea - valueb;
392e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        // do perform the slower but safe compares
393e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        return (valuea < valueb) ? -1 : (valuea > valueb);
394e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    }
395e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com}
3960a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#else
3970a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.comstatic bool operator<(const SkEdge& a, const SkEdge& b) {
3980a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    int valuea = a.fFirstY;
3990a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    int valueb = b.fFirstY;
400fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4010a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    if (valuea == valueb) {
4020a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com        valuea = a.fX;
4030a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com        valueb = b.fX;
4040a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    }
405fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4060a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    return valuea < valueb;
4070a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com}
4080a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#endif
409e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com
410e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.comstatic SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
4110a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#ifdef SK_USE_STD_SORT_FOR_EDGES
412e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    qsort(list, count, sizeof(SkEdge*), edge_compare);
4130a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#else
4140a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com    SkTQSort(list, list + count - 1);
4150a71a9cc372c2fd42e3b1623321878aaa27aa103reed@google.com#endif
41655b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
417e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    // now make the edges linked in sorted order
418e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    for (int i = 1; i < count; i++) {
419e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        list[i - 1]->fNext = list[i];
420e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com        list[i]->fPrev = list[i - 1];
421e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    }
42255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
423e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    *last = list[count - 1];
424e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    return list[0];
425e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com}
426e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// clipRect may be null, even though we always have a clip. This indicates that
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// the path is contained in the clip, and so we can ignore it during the blit
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// clipRect (if no null) has already been shifted up
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
43399219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                  int start_y, int stop_y, int shiftEdgesUp,
43499219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                  const SkRegion& clipRgn) {
435a10742c69ce47d346e3cf23e7be909c9f29b401ecaryclark    SkASSERT(blitter);
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
437909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkEdgeBuilder   builder;
43855b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
439909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    int count = builder.build(path, clipRect, shiftEdgesUp);
440909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkEdge**    list = builder.edgeList();
441909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
4429da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com    if (count < 2) {
4438cfdf01ff953b47fdd5c29ebd54fea8a7a9be83eagl@chromium.org        if (path.isInverseFillType()) {
4449d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            /*
4459d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com             *  Since we are in inverse-fill, our caller has already drawn above
4469d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com             *  our top (start_y) and will draw below our bottom (stop_y). Thus
4479d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com             *  we need to restrict our drawing to the intersection of the clip
4489d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com             *  and those two limits.
4499d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com             */
4509d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            SkIRect rect = clipRgn.getBounds();
4519d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            if (rect.fTop < start_y) {
4529d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                rect.fTop = start_y;
4539d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            }
4549d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            if (rect.fBottom > stop_y) {
4559d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                rect.fBottom = stop_y;
4569d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            }
4579d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            if (!rect.isEmpty()) {
4589d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                blitter->blitRect(rect.fLeft << shiftEdgesUp,
4599d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                                  rect.fTop << shiftEdgesUp,
4609d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                                  rect.width() << shiftEdgesUp,
4619d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com                                  rect.height() << shiftEdgesUp);
4629d5f76a250502620952d4aaa2926ff5bfeffc980reed@google.com            }
4638cfdf01ff953b47fdd5c29ebd54fea8a7a9be83eagl@chromium.org        }
4648cfdf01ff953b47fdd5c29ebd54fea8a7a9be83eagl@chromium.org
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
468909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkEdge headEdge, tailEdge, *last;
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // this returns the first and last edge after they're sorted into a dlink list
470909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkEdge* edge = sort_edges(list, count, &last);
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fPrev = NULL;
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fNext = edge;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fFirstY = kEDGE_HEAD_Y;
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fX = SK_MinS32;
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge->fPrev = &headEdge;
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fPrev = last;
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fNext = NULL;
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fFirstY = kEDGE_TAIL_Y;
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    last->fNext = &tailEdge;
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now edge is the head of the sorted linklist
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
485dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    start_y <<= shiftEdgesUp;
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    stop_y <<= shiftEdgesUp;
487dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    if (clipRect && start_y < clipRect->fTop) {
488dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com        start_y = clipRect->fTop;
489dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    }
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clipRect && stop_y > clipRect->fBottom) {
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        stop_y = clipRect->fBottom;
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    InverseBlitter  ib;
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    PrePostProc     proc = NULL;
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (path.isInverseFillType()) {
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter = &ib;
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        proc = PrePostInverseBlitterProc;
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
503a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com    if (path.isConvex() && (NULL == proc)) {
504e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, NULL);
505e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    } else {
506e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com        walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
507e3a83ec4e5c0abd2f5b756d7a6e7d58515969f18reed@google.com    }
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
51055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.comvoid sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect& cr = clip.getBounds();
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect tmp;
51355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fLeft = cr.fLeft;
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fRight = cr.fRight;
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fTop = cr.fTop;
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fBottom = ir.fTop;
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!tmp.isEmpty()) {
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitRectRegion(tmp, clip);
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
52155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com}
52255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
52355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.comvoid sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
52455b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    const SkIRect& cr = clip.getBounds();
52555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    SkIRect tmp;
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
52755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    tmp.fLeft = cr.fLeft;
52855b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    tmp.fRight = cr.fRight;
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fTop = ir.fBottom;
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tmp.fBottom = cr.fBottom;
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!tmp.isEmpty()) {
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitRectRegion(tmp, clip);
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
53699219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
53897caebc7462c202ab0ec5cce4eb26a616930813ereed@google.com/**
5395ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com *  If the caller is drawing an inverse-fill path, then it pass true for
5405ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com *  skipRejectTest, so we don't abort drawing just because the src bounds (ir)
5415ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com *  is outside of the clip.
54297caebc7462c202ab0ec5cce4eb26a616930813ereed@google.com */
54399219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.orgSkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip,
5445ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com                             const SkIRect& ir, bool skipRejectTest) {
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBlitter = NULL;     // null means blit nothing
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fClipRect = NULL;
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
54899219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org    if (clip) {
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fClipRect = &clip->getBounds();
5505ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com        if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
55299219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        }
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
55499219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        if (clip->isRect()) {
55599219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            if (fClipRect->contains(ir)) {
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fClipRect = NULL;
55799219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org            } else {
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // only need a wrapper blitter if we're horizontally clipped
55999219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org                if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) {
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    fRectBlitter.init(blitter, *fClipRect);
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    blitter = &fRectBlitter;
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
56499219d337f66cb6a8e566e1c6407bfb4b1b6cb8bmike@reedtribe.org        } else {
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fRgnBlitter.init(blitter, clip);
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blitter = &fRgnBlitter;
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBlitter = blitter;
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5741501803e93a9c76b4632086d05c2813cb475db27reed@google.comstatic bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
5751501803e93a9c76b4632086d05c2813cb475db27reed@google.com    const int32_t limit = 32767;
5761501803e93a9c76b4632086d05c2813cb475db27reed@google.com
5771501803e93a9c76b4632086d05c2813cb475db27reed@google.com    SkIRect limitR;
5781501803e93a9c76b4632086d05c2813cb475db27reed@google.com    limitR.set(-limit, -limit, limit, limit);
5791501803e93a9c76b4632086d05c2813cb475db27reed@google.com    if (limitR.contains(orig.getBounds())) {
5801501803e93a9c76b4632086d05c2813cb475db27reed@google.com        return false;
5811501803e93a9c76b4632086d05c2813cb475db27reed@google.com    }
5821501803e93a9c76b4632086d05c2813cb475db27reed@google.com    reduced->op(orig, limitR, SkRegion::kIntersect_Op);
5831501803e93a9c76b4632086d05c2813cb475db27reed@google.com    return true;
5841501803e93a9c76b4632086d05c2813cb475db27reed@google.com}
5851501803e93a9c76b4632086d05c2813cb475db27reed@google.com
5861501803e93a9c76b4632086d05c2813cb475db27reed@google.comvoid SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                      SkBlitter* blitter) {
5881501803e93a9c76b4632086d05c2813cb475db27reed@google.com    if (origClip.isEmpty()) {
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5921501803e93a9c76b4632086d05c2813cb475db27reed@google.com    // Our edges are fixed-point, and don't like the bounds of the clip to
5931501803e93a9c76b4632086d05c2813cb475db27reed@google.com    // exceed that. Here we trim the clip just so we don't overflow later on
5941501803e93a9c76b4632086d05c2813cb475db27reed@google.com    const SkRegion* clipPtr = &origClip;
5951501803e93a9c76b4632086d05c2813cb475db27reed@google.com    SkRegion finiteClip;
5961501803e93a9c76b4632086d05c2813cb475db27reed@google.com    if (clip_to_limit(origClip, &finiteClip)) {
5971501803e93a9c76b4632086d05c2813cb475db27reed@google.com        if (finiteClip.isEmpty()) {
5981501803e93a9c76b4632086d05c2813cb475db27reed@google.com            return;
5991501803e93a9c76b4632086d05c2813cb475db27reed@google.com        }
6001501803e93a9c76b4632086d05c2813cb475db27reed@google.com        clipPtr = &finiteClip;
6011501803e93a9c76b4632086d05c2813cb475db27reed@google.com    }
6021501803e93a9c76b4632086d05c2813cb475db27reed@google.com        // don't reference "origClip" any more, just use clipPtr
6031501803e93a9c76b4632086d05c2813cb475db27reed@google.com
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect ir;
6054e332f82fce0126045e9cb2ef0a2097a6c4c40a3commit-bot@chromium.org    // We deliberately call dround() instead of round(), since we can't afford to generate a
6064e332f82fce0126045e9cb2ef0a2097a6c4c40a3commit-bot@chromium.org    // bounds that is tighter than the corresponding SkEdges. The edge code basically converts
6074e332f82fce0126045e9cb2ef0a2097a6c4c40a3commit-bot@chromium.org    // the floats to fixed, and then "rounds". If we called round() instead of dround() here,
6084e332f82fce0126045e9cb2ef0a2097a6c4c40a3commit-bot@chromium.org    // we could generate the wrong ir for values like 0.4999997.
6094e332f82fce0126045e9cb2ef0a2097a6c4c40a3commit-bot@chromium.org    path.getBounds().dround(&ir);
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (ir.isEmpty()) {
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (path.isInverseFillType()) {
6121501803e93a9c76b4632086d05c2813cb475db27reed@google.com            blitter->blitRegion(*clipPtr);
6138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6175ee6491b7a1e7c177abc0186c2749ebe1f71fcf7reed@google.com    SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType());
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    blitter = clipper.getBlitter();
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (blitter) {
62155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com        // we have to keep our calls to blitter in sorted order, so we
62255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com        // must blit the above section first, then the middle, then the bottom.
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (path.isInverseFillType()) {
6241501803e93a9c76b4632086d05c2813cb475db27reed@google.com            sk_blit_above(blitter, ir, *clipPtr);
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6261501803e93a9c76b4632086d05c2813cb475db27reed@google.com        sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
6271501803e93a9c76b4632086d05c2813cb475db27reed@google.com                     0, *clipPtr);
62855b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com        if (path.isInverseFillType()) {
6291501803e93a9c76b4632086d05c2813cb475db27reed@google.com            sk_blit_below(blitter, ir, *clipPtr);
63055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com        }
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // what does it mean to not have a blitter if path.isInverseFillType???
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
636045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::FillPath(const SkPath& path, const SkIRect& ir,
637045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com                      SkBlitter* blitter) {
638045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    SkRegion rgn(ir);
639045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    FillPath(path, rgn, blitter);
640045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com}
641045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int build_tri_edges(SkEdge edge[], const SkPoint pts[],
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           const SkIRect* clipRect, SkEdge* list[]) {
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge** start = list;
64755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *list++ = edge;
6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *list++ = edge;
6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *list++ = edge;
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (int)(list - start);
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
663800046eba45c9e982ecfe8964b2107f7713ed639reed@android.comstatic void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
664800046eba45c9e982ecfe8964b2107f7713ed639reed@android.com                             SkBlitter* blitter, const SkIRect& ir) {
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(pts && blitter);
66655b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge edgeStorage[3];
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge* list[3];
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = build_tri_edges(edgeStorage, pts, clipRect, list);
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count < 2) {
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge headEdge, tailEdge, *last;
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // this returns the first and last edge after they're sorted into a dlink list
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge* edge = sort_edges(list, count, &last);
67955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fPrev = NULL;
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fNext = edge;
6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fFirstY = kEDGE_HEAD_Y;
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    headEdge.fX = SK_MinS32;
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge->fPrev = &headEdge;
68555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fPrev = last;
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fNext = NULL;
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tailEdge.fFirstY = kEDGE_TAIL_Y;
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    last->fNext = &tailEdge;
69055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now edge is the head of the sorted linklist
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int stop_y = ir.fBottom;
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clipRect && stop_y > clipRect->fBottom) {
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        stop_y = clipRect->fBottom;
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
696dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    int start_y = ir.fTop;
697dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    if (clipRect && start_y < clipRect->fTop) {
698dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com        start_y = clipRect->fTop;
699dca6a56b71b922aab32098d6a55bbb041f3a2b48reed@android.com    }
700a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com    walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
701a6c7c4803e144f5c1d0a86a437ac1e2e8ff5e211reed@google.com//    walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
704045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          SkBlitter* blitter) {
706045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (clip.isEmpty()) {
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
70955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect  r;
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect ir;
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(pts, 3);
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.round(&ir);
714045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
71755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
718045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    SkAAClipBlitterWrapper wrap;
719045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    const SkRegion* clipRgn;
720045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (clip.isBW()) {
721045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        clipRgn = &clip.bwRgn();
722045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    } else {
723045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        wrap.init(clip, blitter);
724045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        clipRgn = &wrap.getRgn();
725045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        blitter = wrap.getBlitter();
726045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    }
72755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
728045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    SkScanClipper clipper(blitter, clipRgn, ir);
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    blitter = clipper.getBlitter();
73049f085dddff10473b6ebf832a974288300224e60bsalomon    if (blitter) {
7318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
734