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
8#include "SampleCode.h"
9#include "SkDumpCanvas.h"
10#include "SkView.h"
11#include "SkCanvas.h"
12#include "SkGradientShader.h"
13#include "SkGraphics.h"
14#include "SkImageDecoder.h"
15#include "SkOSFile.h"
16#include "SkPath.h"
17#include "SkPicture.h"
18#include "SkPictureRecorder.h"
19#include "SkRandom.h"
20#include "SkRegion.h"
21#include "SkShader.h"
22#include "SkUtils.h"
23#include "SkColorPriv.h"
24#include "SkColorFilter.h"
25#include "SkTime.h"
26#include "SkTypeface.h"
27#include "SkXfermode.h"
28
29#include "SkStream.h"
30#include "SkSurface.h"
31#include "SkXMLParser.h"
32
33class PictFileView : public SampleView {
34public:
35    PictFileView(const char name[] = NULL)
36        : fFilename(name)
37        , fBBox(kNo_BBoxType)
38        , fTileSize(SkSize::Make(0, 0)) {
39        for (int i = 0; i < kBBoxTypeCount; ++i) {
40            fPictures[i] = NULL;
41        }
42    }
43
44    virtual ~PictFileView() {
45        for (int i = 0; i < kBBoxTypeCount; ++i) {
46            SkSafeUnref(fPictures[i]);
47        }
48    }
49
50    virtual void onTileSizeChanged(const SkSize &tileSize) SK_OVERRIDE {
51        if (tileSize != fTileSize) {
52            fTileSize = tileSize;
53            SkSafeSetNull(fPictures[kTileGrid_BBoxType]);
54        }
55    }
56
57protected:
58    // overrides from SkEventSink
59    virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
60        if (SampleCode::TitleQ(*evt)) {
61            SkString name("P:");
62            const char* basename = strrchr(fFilename.c_str(), SkPATH_SEPARATOR);
63            name.append(basename ? basename+1: fFilename.c_str());
64            switch (fBBox) {
65            case kNo_BBoxType:
66                // No name appended
67                break;
68            case kRTree_BBoxType:
69                name.append(" <bbox: R>");
70                break;
71            case kQuadTree_BBoxType:
72                name.append(" <bbox: Q>");
73                break;
74            case kTileGrid_BBoxType:
75                name.append(" <bbox: T>");
76                break;
77            default:
78                SkASSERT(false);
79                break;
80            }
81            SampleCode::TitleR(evt, name.c_str());
82            return true;
83        }
84        return this->INHERITED::onQuery(evt);
85    }
86
87    virtual bool onEvent(const SkEvent& evt) SK_OVERRIDE {
88        if (evt.isType("PictFileView::toggleBBox")) {
89            fBBox = (BBoxType)((fBBox + 1) % kBBoxTypeCount);
90            return true;
91        }
92        return this->INHERITED::onEvent(evt);
93    }
94
95    virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
96        SkASSERT(static_cast<int>(fBBox) < kBBoxTypeCount);
97        SkPicture** picture = fPictures + fBBox;
98
99        if (!*picture) {
100            *picture = LoadPicture(fFilename.c_str(), fBBox);
101        }
102        if (*picture) {
103            canvas->drawPicture(*picture);
104        }
105    }
106
107private:
108    enum BBoxType {
109        kNo_BBoxType,
110        kQuadTree_BBoxType,
111        kRTree_BBoxType,
112        kTileGrid_BBoxType,
113
114        kLast_BBoxType = kTileGrid_BBoxType
115    };
116    static const int kBBoxTypeCount = kLast_BBoxType + 1;
117
118    SkString    fFilename;
119    SkPicture*  fPictures[kBBoxTypeCount];
120    BBoxType    fBBox;
121    SkSize      fTileSize;
122
123    SkPicture* LoadPicture(const char path[], BBoxType bbox) {
124        SkAutoTUnref<SkPicture> pic;
125
126        SkBitmap bm;
127        if (SkImageDecoder::DecodeFile(path, &bm)) {
128            bm.setImmutable();
129            SkPictureRecorder recorder;
130            SkCanvas* can = recorder.beginRecording(bm.width(), bm.height(), NULL, 0);
131            can->drawBitmap(bm, 0, 0, NULL);
132            pic.reset(recorder.endRecording());
133        } else {
134            SkFILEStream stream(path);
135            if (stream.isValid()) {
136                pic.reset(SkPicture::CreateFromStream(&stream));
137            } else {
138                SkDebugf("coun't load picture at \"path\"\n", path);
139            }
140
141            if (false) {
142                SkSurface* surf = SkSurface::NewRasterPMColor(pic->width(), pic->height());
143                surf->getCanvas()->drawPicture(pic);
144                surf->unref();
145            }
146            if (false) { // re-record
147                SkPictureRecorder recorder;
148                pic->draw(recorder.beginRecording(pic->width(), pic->height(), NULL, 0));
149                SkAutoTUnref<SkPicture> p2(recorder.endRecording());
150
151                SkString path2(path);
152                path2.append(".new.skp");
153                SkFILEWStream writer(path2.c_str());
154                p2->serialize(&writer);
155            }
156        }
157
158        if (NULL == pic) {
159            return NULL;
160        }
161
162        SkAutoTDelete<SkBBHFactory> factory;
163        switch (bbox) {
164        case kNo_BBoxType:
165            // no bbox playback necessary
166            return pic.detach();
167        case kRTree_BBoxType:
168            factory.reset(SkNEW(SkRTreeFactory));
169            break;
170        case kQuadTree_BBoxType:
171            factory.reset(SkNEW(SkQuadTreeFactory));
172            break;
173        case kTileGrid_BBoxType: {
174            SkASSERT(!fTileSize.isEmpty());
175            SkTileGridFactory::TileGridInfo gridInfo;
176            gridInfo.fMargin = SkISize::Make(0, 0);
177            gridInfo.fOffset = SkIPoint::Make(0, 0);
178            gridInfo.fTileInterval = fTileSize.toRound();
179            factory.reset(SkNEW_ARGS(SkTileGridFactory, (gridInfo)));
180            break;
181        }
182        default:
183            SkASSERT(false);
184        }
185
186        SkPictureRecorder recorder;
187        pic->draw(recorder.beginRecording(pic->width(), pic->height(), factory.get(), 0));
188        return recorder.endRecording();
189    }
190
191    typedef SampleView INHERITED;
192};
193
194SampleView* CreateSamplePictFileView(const char filename[]);
195SampleView* CreateSamplePictFileView(const char filename[]) {
196    return new PictFileView(filename);
197}
198
199//////////////////////////////////////////////////////////////////////////////
200
201#if 0
202static SkView* MyFactory() { return new PictFileView; }
203static SkViewRegister reg(MyFactory);
204#endif
205