1/*
2 *  CAUTION: EXPERIMENTAL CODE
3 *
4 *  This code is not to be used and will not be supported
5 *  if it fails on you. DO NOT USE!
6 *
7 */
8
9#include "SkPathUtils.h"
10
11#include "SkPath.h"
12#include "SkPathOps.h" // this can't be found, how do I link it?
13#include "SkRegion.h"
14
15typedef void (*line2path)(SkPath*, const char*, int, int);
16#define SQRT_2 1.41421356237f
17#define ON  0xFF000000 // black pixel
18#define OFF 0x00000000 // transparent pixel
19
20// assumes stride is in bytes
21/*
22static void FillRandomBits( int chars, char* bits ){
23    SkTime time;
24    SkRandom rand = SkRandom( time.GetMSecs() );
25
26    for (int i = 0; i < chars; ++i){
27        bits[i] = rand.nextU();
28    }
29}OA
30*/
31
32static int GetBit( const char* buffer, int x ) {
33    int byte = x >> 3;
34    int bit = x & 7;
35
36    return buffer[byte] & (128 >> bit);
37}
38
39/*
40static void Line2path_pixel(SkPath* path, const char* line,
41                            int lineIdx, int width) {
42    for (int i = 0; i < width; ++i) {
43        // simply makes every ON pixel into a rect path
44        if (GetBit(line,i)) {
45            path->addRect(SkRect::MakeXYWH(i, lineIdx, 1, 1),
46                          SkPath::kCW_Direction);
47        }
48    }
49}
50
51static void Line2path_pixelCircle(SkPath* path, const char* line,
52                                  int lineIdx, int width) {
53    for (int i = 0; i < width; ++i) {
54        // simply makes every ON pixel into a circle path
55        if (GetBit(line,i)) {
56            path->addCircle(i + SK_ScalarHalf,
57                            lineIdx + SK_ScalarHalf,
58                            SQRT_2 / 2.0f);
59        }
60    }
61}
62*/
63
64static void Line2path_span(SkPath* path, const char* line,
65                           int lineIdx, int width) {
66    bool inRun = 0;
67    int start = 1;
68
69    for (int i = 0; i < width; ++i) {
70        int curPixel = GetBit(line,i);
71
72        if ( (curPixel!=0) != inRun ) { // if transition
73            if (curPixel) { // if transition on
74                inRun = 1;
75                start = i; // mark beginning of span
76            }else { // if transition off add the span as a path
77                inRun = 0;
78                path->addRect(SkRect::MakeXYWH(SkIntToScalar(start), SkIntToScalar(lineIdx),
79                                               SkIntToScalar(i-start), SK_Scalar1),
80                              SkPath::kCW_Direction);
81            }
82        }
83    }
84
85    if (inRun==1) { // close any open spans
86        int end = 0;
87        if ( GetBit(line,width-1) ) ++end;
88        path->addRect(SkRect::MakeXYWH(SkIntToScalar(start), SkIntToScalar(lineIdx),
89                                       SkIntToScalar(width - 1 + end - start), SK_Scalar1),
90                      SkPath::kCW_Direction);
91    } else if ( GetBit(line, width - 1) ) { // if last pixel on add
92        path->addRect(SkRect::MakeXYWH(width - SK_Scalar1, SkIntToScalar(lineIdx),
93                                       SK_Scalar1, SK_Scalar1),
94                      SkPath::kCW_Direction);
95    }
96}
97
98void SkPathUtils::BitsToPath_Path(SkPath* path,
99                        const char* bitmap,
100                        int w, int h, int stride) {
101    // loop for every line in bitmap
102    for (int i = 0; i < h; ++i) {
103        // fn ptr handles each line separately
104        //l2p_fn(path, &bitmap[i*stride], i, w);
105        Line2path_span(path, &bitmap[i*stride], i, w);
106    }
107    Simplify(*path, path); // simplify resulting path.
108}
109
110void SkPathUtils::BitsToPath_Region(SkPath* path,
111                               const char* bitmap,
112                               int w, int h, int stride) {
113    SkRegion region;
114
115    // loop for each line
116    for (int y = 0; y < h; ++y){
117        bool inRun = 0;
118        int start = 1;
119        const char* line = &bitmap[y * stride];
120
121        // loop for each pixel
122        for (int i = 0; i < w; ++i) {
123            int curPixel = GetBit(line,i);
124
125            if ( (curPixel!=0) != inRun ) { // if transition
126                if (curPixel) { // if transition on
127                    inRun = 1;
128                    start = i; // mark beginning of span
129                }else { // if transition off add the span as a path
130                    inRun = 0;
131                    //add here
132                    region.op(SkIRect::MakeXYWH(start, y, i-start, 1),
133                              SkRegion::kUnion_Op );
134                }
135            }
136        }
137        if (inRun==1) { // close any open spans
138            int end = 0;
139            if ( GetBit(line,w-1) ) ++end;
140            // add the thing here
141            region.op(SkIRect::MakeXYWH(start, y, w-1-start+end, 1),
142                      SkRegion::kUnion_Op );
143
144        } else if ( GetBit(line,w-1) ) { // if last pixel on add rect
145            // add the thing here
146            region.op(SkIRect::MakeXYWH(w-1, y, 1, 1),
147                      SkRegion::kUnion_Op );
148        }
149    }
150    // convert region to path
151    region.getBoundaryPath(path);
152}
153