1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkCanvas.h"
8#include "SkCGUtils.h"
9#include "SkGraphics.h"
10#include "SkImageDecoder.h"
11#include "SkOSFile.h"
12#include "SkPaint.h"
13#include "SkPicture.h"
14#include "SkStream.h"
15#include "SkWindow.h"
16
17static void make_filepath(SkString* path, const char* dir, const SkString& name) {
18    size_t len = strlen(dir);
19    path->set(dir);
20    if (len > 0 && dir[len - 1] != '/') {
21        path->append("/");
22    }
23    path->append(name);
24}
25
26static SkPicture* LoadPicture(const char path[]) {
27    SkPicture* pic = NULL;
28
29    SkBitmap bm;
30    if (SkImageDecoder::DecodeFile(path, &bm)) {
31        bm.setImmutable();
32        pic = new SkPicture;
33        SkCanvas* can = pic->beginRecording(bm.width(), bm.height());
34        can->drawBitmap(bm, 0, 0, NULL);
35        pic->endRecording();
36    } else {
37        SkFILEStream stream(path);
38        if (stream.isValid()) {
39            pic = new SkPicture(&stream, NULL, &SkImageDecoder::DecodeStream);
40        }
41
42        if (false) { // re-record
43            SkPicture p2;
44            pic->draw(p2.beginRecording(pic->width(), pic->height()));
45            p2.endRecording();
46
47            SkString path2(path);
48            path2.append(".new.skp");
49            SkFILEWStream writer(path2.c_str());
50            p2.serialize(&writer);
51        }
52    }
53    return pic;
54}
55
56class SkSampleView : public SkView {
57public:
58    SkSampleView() {
59        this->setVisibleP(true);
60        this->setClipToBounds(false);
61    };
62protected:
63    virtual void onDraw(SkCanvas* canvas) {
64        canvas->drawColor(0xFFFFFFFF);
65        SkPaint p;
66        p.setTextSize(20);
67        p.setAntiAlias(true);
68        canvas->drawText("Hello World!", 13, 50, 30, p);
69     //   SkRect r = {50, 50, 80, 80};
70        p.setColor(0xAA11EEAA);
71   //     canvas->drawRect(r, p);
72
73        SkRect result;
74        SkPath path;
75        path.moveTo(0, 0);
76        path.lineTo(1, 1);
77        path.lineTo(1, 8);
78        path.lineTo(0, 9);
79        SkASSERT(path.hasRectangularInterior(&result));
80
81        path.reset();
82        path.addRect(10, 10, 100, 100, SkPath::kCW_Direction);
83        path.addRect(20, 20, 50, 50, SkPath::kCW_Direction);
84        path.addRect(50, 50, 90, 90, SkPath::kCCW_Direction);
85        p.setColor(0xAA335577);
86        canvas->drawPath(path, p);
87        SkASSERT(!path.hasRectangularInterior(NULL));
88        path.reset();
89        path.addRect(10, 10, 100, 100, SkPath::kCW_Direction);
90        path.addRect(20, 20, 80, 80, SkPath::kCW_Direction);
91        SkRect expected = {20, 20, 80, 80};
92        SkASSERT(path.hasRectangularInterior(&result));
93        SkASSERT(result == expected);
94
95    }
96private:
97    typedef SkView INHERITED;
98};
99
100void application_init();
101void application_term();
102
103static int showPathContour(SkPath::Iter& iter) {
104    uint8_t verb;
105    SkPoint pts[4];
106    int moves = 0;
107    bool waitForClose = false;
108    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
109        switch (verb) {
110            case SkPath::kMove_Verb:
111                if (!waitForClose) {
112                    ++moves;
113                    waitForClose = true;
114                }
115                SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
116                break;
117            case SkPath::kLine_Verb:
118                SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
119                break;
120            case SkPath::kQuad_Verb:
121                SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
122                    pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
123                break;
124            case SkPath::kCubic_Verb:
125                SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g, %1.9g, %1.9g);\n",
126                    pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
127                    pts[3].fX, pts[3].fY);
128                break;
129            case SkPath::kClose_Verb:
130                waitForClose = false;
131                SkDebugf("path.close();\n");
132                break;
133            default:
134                SkDEBUGFAIL("bad verb");
135                SkASSERT(0);
136                return 0;
137        }
138    }
139    return moves;
140}
141
142class PathCanvas : public SkCanvas {
143    virtual void drawPath(const SkPath& path, const SkPaint& paint) {
144        if (nameonly) {
145            SkDebugf("    %s%d,\n", filename.c_str(), ++count);
146            return;
147        }
148        SkPath::Iter iter(path, true);
149        SkDebugf("<div id=\"%s%d\">\n", filename.c_str(), ++count);
150        SkASSERT(path.getFillType() < SkPath::kInverseWinding_FillType);
151        SkDebugf("path.setFillType(SkPath::k%s_FillType);\n",
152            path.getFillType() == SkPath::kWinding_FillType ? "Winding" : "EvenOdd");
153        int contours = showPathContour(iter);
154        SkRect r;
155        SkRect copy = r;
156        bool hasOne = path.hasRectangularInterior(&r);
157        bool expected = (path.getFillType() == SkPath::kWinding_FillType && contours == 1)
158            || (path.getFillType() == SkPath::kEvenOdd_FillType && contours == 2);
159        if (!expected) {
160            SkDebugf("suspect contours=%d\n", contours);
161        }
162        int verbs = path.countVerbs();
163        int points = path.countPoints();
164        if (hasOne) {
165            if (rectVerbsMin > verbs) {
166                rectVerbsMin = verbs;
167            }
168            if (rectVerbsMax < verbs) {
169                rectVerbsMax = verbs;
170            }
171            if (rectPointsMin > points) {
172                rectPointsMin = points;
173            }
174            if (rectPointsMax < points) {
175                rectPointsMax = points;
176            }
177            SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g);\n",
178                    r.fLeft, r.fTop, r.fRight, r.fBottom);
179        } else {
180            if (verbsMin > verbs) {
181                verbsMin = verbs;
182            }
183            if (verbsMax < verbs) {
184                verbsMax = verbs;
185            }
186            if (pointsMin > points) {
187                pointsMin = points;
188            }
189            if (pointsMax < points) {
190                pointsMax = points;
191            }
192            SkDebugf("no interior bounds\n");
193        }
194        path.hasRectangularInterior(&copy);
195        SkDebugf("</div>\n\n");
196    }
197
198    virtual void drawPosTextH(const void* text, size_t byteLength,
199                              const SkScalar xpos[], SkScalar constY,
200                              const SkPaint& paint) {
201    }
202
203public:
204    void divName(const SkString& str, bool only) {
205        filename = str;
206        char* chars = filename.writable_str();
207        while (*chars) {
208            if (*chars == '.' || *chars == '-') *chars = '_';
209            chars++;
210        }
211        count = 0;
212        nameonly = only;
213    }
214
215    void init() {
216        pointsMin = verbsMin = SK_MaxS32;
217        pointsMax = verbsMax = SK_MinS32;
218        rectPointsMin = rectVerbsMin = SK_MaxS32;
219        rectPointsMax = rectVerbsMax = SK_MinS32;
220    }
221
222    SkString filename;
223    int count;
224    bool nameonly;
225    int pointsMin;
226    int pointsMax;
227    int verbsMin;
228    int verbsMax;
229    int rectPointsMin;
230    int rectPointsMax;
231    int rectVerbsMin;
232    int rectVerbsMax;
233};
234
235bool runone = false;
236
237void application_init() {
238    SkGraphics::Init();
239    SkEvent::Init();
240    if (runone) {
241        return;
242    }
243    const char pictDir[] = "/Volumes/chrome/nih/skia/skp/skp";
244    SkOSFile::Iter iter(pictDir, "skp");
245    SkString filename;
246    PathCanvas canvas;
247    canvas.init();
248    while (iter.next(&filename)) {
249        SkString path;
250     //   if (true) filename.set("tabl_www_sahadan_com.skp");
251        make_filepath(&path, pictDir, filename);
252        canvas.divName(filename, false);
253        SkPicture* pic = LoadPicture(path.c_str());
254        pic->draw(&canvas);
255        delete pic;
256    }
257    SkDebugf("\n</div>\n\n");
258
259    SkDebugf("<script type=\"text/javascript\">\n\n");
260    SkDebugf("var testDivs = [\n");
261
262    iter.reset(pictDir, "skp");
263    while (iter.next(&filename)) {
264        SkString path;
265        make_filepath(&path, pictDir, filename);
266        canvas.divName(filename, true);
267        SkPicture* pic = LoadPicture(path.c_str());
268        pic->draw(&canvas);
269        delete pic;
270    }
271    SkDebugf("];\n\n");
272
273    SkDebugf("points min=%d max=%d verbs min=%d max=%d\n", canvas.pointsMin, canvas.pointsMax,
274            canvas.verbsMin, canvas.verbsMax);
275    SkDebugf("rect points min=%d max=%d verbs min=%d max=%d\n", canvas.rectPointsMin, canvas.rectPointsMax,
276            canvas.rectVerbsMin, canvas.rectVerbsMax);
277
278    SkDebugf("\n");
279}
280
281void application_term() {
282    SkEvent::Term();
283}
284
285class FillLayout : public SkView::Layout {
286protected:
287    virtual void onLayoutChildren(SkView* parent) {
288        SkView* view = SkView::F2BIter(parent).next();
289        view->setSize(parent->width(), parent->height());
290    }
291};
292
293#import "SimpleApp.h"
294@implementation SimpleNSView
295
296- (id)initWithDefaults {
297    if ((self = [super initWithDefaults])) {
298        fWind = new SkOSWindow(self);
299        fWind->setLayout(new FillLayout, false);
300        fWind->attachChildToFront(new SkSampleView)->unref();
301    }
302    return self;
303}
304
305- (void)drawRect:(NSRect)dirtyRect {
306    CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
307    SkCGDrawBitmap(ctx, fWind->getBitmap(), 0, 0);
308}
309
310@end
311