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 kTileGrid_BBoxType:
72                name.append(" <bbox: T>");
73                break;
74            default:
75                SkASSERT(false);
76                break;
77            }
78            SampleCode::TitleR(evt, name.c_str());
79            return true;
80        }
81        return this->INHERITED::onQuery(evt);
82    }
83
84    virtual bool onEvent(const SkEvent& evt) SK_OVERRIDE {
85        if (evt.isType("PictFileView::toggleBBox")) {
86            fBBox = (BBoxType)((fBBox + 1) % kBBoxTypeCount);
87            return true;
88        }
89        return this->INHERITED::onEvent(evt);
90    }
91
92    virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
93        SkASSERT(static_cast<int>(fBBox) < kBBoxTypeCount);
94        SkPicture** picture = fPictures + fBBox;
95
96        if (!*picture) {
97            *picture = LoadPicture(fFilename.c_str(), fBBox);
98        }
99        if (*picture) {
100            canvas->drawPicture(*picture);
101        }
102    }
103
104private:
105    enum BBoxType {
106        kNo_BBoxType,
107        kRTree_BBoxType,
108        kTileGrid_BBoxType,
109
110        kLast_BBoxType = kTileGrid_BBoxType
111    };
112    static const int kBBoxTypeCount = kLast_BBoxType + 1;
113
114    SkString    fFilename;
115    SkPicture*  fPictures[kBBoxTypeCount];
116    BBoxType    fBBox;
117    SkSize      fTileSize;
118
119    SkPicture* LoadPicture(const char path[], BBoxType bbox) {
120        SkAutoTUnref<SkPicture> pic;
121
122        SkBitmap bm;
123        if (SkImageDecoder::DecodeFile(path, &bm)) {
124            bm.setImmutable();
125            SkPictureRecorder recorder;
126            SkCanvas* can = recorder.beginRecording(SkIntToScalar(bm.width()),
127                                                    SkIntToScalar(bm.height()),
128                                                    NULL, 0);
129            can->drawBitmap(bm, 0, 0, NULL);
130            pic.reset(recorder.endRecording());
131        } else {
132            SkFILEStream stream(path);
133            if (stream.isValid()) {
134                pic.reset(SkPicture::CreateFromStream(&stream));
135            } else {
136                SkDebugf("coun't load picture at \"path\"\n", path);
137            }
138
139            if (false) {
140                SkSurface* surf = SkSurface::NewRasterPMColor(SkScalarCeilToInt(pic->cullRect().width()),
141                                                              SkScalarCeilToInt(pic->cullRect().height()));
142                surf->getCanvas()->drawPicture(pic);
143                surf->unref();
144            }
145            if (false) { // re-record
146                SkPictureRecorder recorder;
147                pic->playback(recorder.beginRecording(pic->cullRect().width(),
148                                                      pic->cullRect().height(),
149                                                      NULL, 0));
150                SkAutoTUnref<SkPicture> p2(recorder.endRecording());
151
152                SkString path2(path);
153                path2.append(".new.skp");
154                SkFILEWStream writer(path2.c_str());
155                p2->serialize(&writer);
156            }
157        }
158
159        if (NULL == pic) {
160            return NULL;
161        }
162
163        SkAutoTDelete<SkBBHFactory> factory;
164        switch (bbox) {
165        case kNo_BBoxType:
166            // no bbox playback necessary
167            return pic.detach();
168        case kRTree_BBoxType:
169            factory.reset(SkNEW(SkRTreeFactory));
170            break;
171        case kTileGrid_BBoxType: {
172            SkASSERT(!fTileSize.isEmpty());
173            SkTileGridFactory::TileGridInfo gridInfo;
174            gridInfo.fMargin = SkISize::Make(0, 0);
175            gridInfo.fOffset = SkIPoint::Make(0, 0);
176            gridInfo.fTileInterval = fTileSize.toRound();
177            factory.reset(SkNEW_ARGS(SkTileGridFactory, (gridInfo)));
178            break;
179        }
180        default:
181            SkASSERT(false);
182        }
183
184        SkPictureRecorder recorder;
185        pic->playback(recorder.beginRecording(pic->cullRect().width(),
186                                              pic->cullRect().height(),
187                                              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