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
24 class NetPipeReaderView : public SampleView {
25 public:
NetPipeReaderView()26 NetPipeReaderView() {
27 fSocket = NULL;
28 fSync = true;
29 }
30
~NetPipeReaderView()31 ~NetPipeReaderView() {
32 if (fSocket) {
33 delete fSocket;
34 }
35 fDataArray.reset();
36 }
requestMenu(SkOSMenu * menu)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
44 protected:
readData(int cid,const void * data,size_t size,SkSocket::DataType type,void * context)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
onRead(const void * data,size_t size)51 void onRead(const void* data, size_t size) {
52 if (size > 0)
53 fDataArray.append(size, (const char*)data);
54 }
55
onQuery(SkEvent * evt)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
onEvent(const SkEvent & evt)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
onDrawContent(SkCanvas * canvas)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
119 private:
120 bool fSync;
121 SkTDArray<char> fDataArray;
122 SkTCPClient* fSocket;
123 typedef SampleView INHERITED;
124 };
125
126 ///////////////////////////////////////////////////////////////////////////////
127
MyFactory()128 static SkView* MyFactory() { return new NetPipeReaderView; }
129 static SkViewRegister reg(MyFactory);
130