1#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkGPipe.h"
6#include "SkSockets.h"
7#include "SkOSMenu.h"
8
9/**
10 * A simple networked pipe reader
11 *
12 * This view will connect to a user specified server, in this case meaning any
13 * Skia app that's has a SkTCPServer set up to broadcast its piped drawing data,
14 * received all the data transmitted and attempt to reproduce the drawing calls.
15 * This reader will only keep the latest batch of data. In order to keep up with
16 * the server, which may be producing data at a much higher rate than the reader
17 * is consuming, the reader will attempt multiple reads and only render the
18 * latest frame. this behavior can be adjusted by changing MAX_READS_PER_FRAME
19 * or disabled by setting fSync to false
20 */
21
22#define MAX_READS_PER_FRAME 12
23
24class NetPipeReaderView : public SampleView {
25public:
26    NetPipeReaderView() {
27        fSocket = NULL;
28        fSync = true;
29    }
30
31    ~NetPipeReaderView() {
32        if (fSocket) {
33            delete fSocket;
34        }
35        fDataArray.reset();
36    }
37    virtual void requestMenu(SkOSMenu* menu) {
38        menu->setTitle("Net Pipe Reader");
39        menu->appendTextField("Server IP", "Server IP", this->getSinkID(),
40                              "IP address");
41        menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync);
42    }
43
44protected:
45    static void readData(int cid, const void* data, size_t size,
46                         SkSocket::DataType type, void* context) {
47        NetPipeReaderView* view = (NetPipeReaderView*)context;
48        view->onRead(data, size);
49    }
50
51    void onRead(const void* data, size_t size) {
52        if (size > 0)
53            fDataArray.append(size, (const char*)data);
54    }
55
56    bool onQuery(SkEvent* evt) {
57        if (SampleCode::TitleQ(*evt)) {
58            SampleCode::TitleR(evt, "Net Pipe Reader");
59            return true;
60        }
61        return this->INHERITED::onQuery(evt);
62    }
63
64    bool onEvent(const SkEvent& evt) {
65        SkString s;
66        if (SkOSMenu::FindText(evt, "Server IP", &s)) {
67            if (NULL != fSocket) {
68                delete fSocket;
69            }
70            fSocket = new SkTCPClient(s.c_str());
71            fSocket->connectToServer();
72            SkDebugf("Connecting to %s\n", s.c_str());
73            return true;
74        }
75        if (SkOSMenu::FindSwitchState(evt, "Sync", &fSync))
76            return true;
77        return this->INHERITED::onEvent(evt);
78    }
79
80    void onDrawContent(SkCanvas* canvas) {
81        if (NULL == fSocket)
82            return;
83
84        if (fSocket->isConnected()) {
85            int dataToRemove = fDataArray.count();
86            if (fSync) {
87                int numreads = 0;
88                while (fSocket->readPacket(readData, this) > 0 &&
89                       numreads < MAX_READS_PER_FRAME) {
90                    // at this point, new data has been read and stored, discard
91                    // old data since it's not needed anymore
92                    SkASSERT(fDataArray.count() > dataToRemove);
93                    fDataArray.remove(0, dataToRemove);
94                    dataToRemove = fDataArray.count();
95                    ++numreads;
96                }
97                // clean up if max reads reached
98                if (numreads == MAX_READS_PER_FRAME &&
99                    fDataArray.count() > dataToRemove)
100                    fDataArray.remove(0, dataToRemove);
101            }
102            else {
103                if (fSocket->readPacket(readData, this) > 0)
104                    fDataArray.remove(0, dataToRemove);
105            }
106        }
107        else
108            fSocket->connectToServer();
109
110        SkGPipeReader reader(canvas);
111        size_t bytesRead;
112        SkGPipeReader::Status fStatus = reader.playback(fDataArray.begin(),
113                                                        fDataArray.count(),
114                                                        &bytesRead);
115        SkASSERT(SkGPipeReader::kError_Status != fStatus);
116        this->inval(NULL);
117    }
118
119private:
120    bool fSync;
121    SkTDArray<char> fDataArray;
122    SkTCPClient* fSocket;
123    typedef SampleView INHERITED;
124};
125
126///////////////////////////////////////////////////////////////////////////////
127
128static SkView* MyFactory() { return new NetPipeReaderView; }
129static SkViewRegister reg(MyFactory);
130