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
33#include "SkGlyphCache.h"
34
35#include "SkDrawFilter.h"
36class SkCounterDrawFilter : public SkDrawFilter {
37public:
38    SkCounterDrawFilter(int count) : fCount(count) {}
39
40    bool filter(SkPaint*, Type t) override {
41        return --fCount >= 0;
42    }
43
44    int fCount;
45};
46
47class PictFileView : public SampleView {
48public:
49    PictFileView(const char name[] = nullptr)
50        : fFilename(name)
51        , fBBox(kNo_BBoxType)
52        , fTileSize(SkSize::Make(0, 0)) {
53        for (int i = 0; i < kBBoxTypeCount; ++i) {
54            fPictures[i] = nullptr;
55        }
56        fCount = 0;
57    }
58
59    virtual ~PictFileView() {
60        for (int i = 0; i < kBBoxTypeCount; ++i) {
61            SkSafeUnref(fPictures[i]);
62        }
63    }
64
65    void onTileSizeChanged(const SkSize &tileSize) override {
66        if (tileSize != fTileSize) {
67            fTileSize = tileSize;
68        }
69    }
70
71protected:
72    // overrides from SkEventSink
73    bool onQuery(SkEvent* evt) override {
74        if (SampleCode::TitleQ(*evt)) {
75            SkString name("P:");
76            const char* basename = strrchr(fFilename.c_str(), SkPATH_SEPARATOR);
77            name.append(basename ? basename+1: fFilename.c_str());
78            switch (fBBox) {
79            case kNo_BBoxType:
80                // No name appended
81                break;
82            case kRTree_BBoxType:
83                name.append(" <bbox: R>");
84                break;
85            default:
86                SkASSERT(false);
87                break;
88            }
89            SampleCode::TitleR(evt, name.c_str());
90            return true;
91        }
92        SkUnichar uni;
93        if (SampleCode::CharQ(*evt, &uni)) {
94            switch (uni) {
95                case 'n': fCount += 1; this->inval(nullptr); return true;
96                case 'p': fCount -= 1; this->inval(nullptr); return true;
97                case 's': fCount =  0; this->inval(nullptr); return true;
98                default: break;
99            }
100        }
101        return this->INHERITED::onQuery(evt);
102    }
103
104    bool onEvent(const SkEvent& evt) override {
105        if (evt.isType("PictFileView::toggleBBox")) {
106            fBBox = (BBoxType)((fBBox + 1) % kBBoxTypeCount);
107            return true;
108        }
109        return this->INHERITED::onEvent(evt);
110    }
111
112    void onDrawContent(SkCanvas* canvas) override {
113        SkASSERT(static_cast<int>(fBBox) < kBBoxTypeCount);
114        SkPicture** picture = fPictures + fBBox;
115
116#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
117        SkGraphics::PurgeFontCache();
118#endif
119
120        if (!*picture) {
121            *picture = LoadPicture(fFilename.c_str(), fBBox);
122        }
123        if (*picture) {
124            SkCounterDrawFilter filter(fCount);
125            if (fCount > 0) {
126                canvas->setDrawFilter(&filter);
127            }
128            canvas->drawPicture(*picture);
129            canvas->setDrawFilter(nullptr);
130        }
131
132#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
133        SkGlyphCache::Dump();
134        SkDebugf("\n");
135#endif
136    }
137
138private:
139    enum BBoxType {
140        kNo_BBoxType,
141        kRTree_BBoxType,
142
143        kLast_BBoxType = kRTree_BBoxType,
144    };
145    static const int kBBoxTypeCount = kLast_BBoxType + 1;
146
147    SkString    fFilename;
148    SkPicture*  fPictures[kBBoxTypeCount];
149    BBoxType    fBBox;
150    SkSize      fTileSize;
151    int         fCount;
152
153    SkPicture* LoadPicture(const char path[], BBoxType bbox) {
154        SkAutoTUnref<SkPicture> pic;
155
156        SkBitmap bm;
157        if (SkImageDecoder::DecodeFile(path, &bm)) {
158            bm.setImmutable();
159            SkPictureRecorder recorder;
160            SkCanvas* can = recorder.beginRecording(SkIntToScalar(bm.width()),
161                                                    SkIntToScalar(bm.height()),
162                                                    nullptr, 0);
163            can->drawBitmap(bm, 0, 0, nullptr);
164            pic.reset(recorder.endRecording());
165        } else {
166            SkFILEStream stream(path);
167            if (stream.isValid()) {
168                pic.reset(SkPicture::CreateFromStream(&stream));
169            } else {
170                SkDebugf("coun't load picture at \"path\"\n", path);
171            }
172
173            if (false) { // re-record
174                SkPictureRecorder recorder;
175                pic->playback(recorder.beginRecording(pic->cullRect().width(),
176                                                      pic->cullRect().height(),
177                                                      nullptr, 0));
178                SkAutoTUnref<SkPicture> p2(recorder.endRecording());
179
180                SkString path2(path);
181                path2.append(".new.skp");
182                SkFILEWStream writer(path2.c_str());
183                p2->serialize(&writer);
184            }
185        }
186
187        if (nullptr == pic) {
188            return nullptr;
189        }
190
191        SkAutoTDelete<SkBBHFactory> factory;
192        switch (bbox) {
193        case kNo_BBoxType:
194            // no bbox playback necessary
195            return pic.detach();
196        case kRTree_BBoxType:
197            factory.reset(new SkRTreeFactory);
198            break;
199        default:
200            SkASSERT(false);
201        }
202
203        SkPictureRecorder recorder;
204        pic->playback(recorder.beginRecording(pic->cullRect().width(),
205                                              pic->cullRect().height(),
206                                              factory.get(), 0));
207        return recorder.endRecording();
208    }
209
210    typedef SampleView INHERITED;
211};
212
213SampleView* CreateSamplePictFileView(const char filename[]);
214SampleView* CreateSamplePictFileView(const char filename[]) {
215    return new PictFileView(filename);
216}
217
218//////////////////////////////////////////////////////////////////////////////
219
220#if 0
221static SkView* MyFactory() { return new PictFileView; }
222static SkViewRegister reg(MyFactory);
223#endif
224