1 #include "SampleCode.h"
2 #include "SkView.h"
3 #include "SkCanvas.h"
4 #include "SkGPipe.h"
5 #include "SkSockets.h"
6 #include "SkNetPipeController.h"
7 #include "SkCornerPathEffect.h"
8 #include "SkColorPalette.h"
9 #include "SkOSMenu.h"
10 
11 
12 /**
13  * Drawing Client
14  *
15  * A drawing client that allows a user to perform simple brush stokes with
16  * a selected color and brush size. The drawing client communicates with a
17  * drawing server to send/receive data to/from other clients connected to the
18  * same server. The drawing client stores data in fData and fBuffer depending on
19  * the data type. Append type means that the drawing data is a completed stroke
20  * and Replace type means that the drawing data is in progress and will be
21  * replaced by subsequent data. fData and fBuffer are read by a pipe reader and
22  * reproduce the drawing. When the client is in a normal state, the data stored
23  * on the client and the server should be identical.
24  * The drawing client is also able to switch between vector and bitmap drawing.
25  * The drawing client also renders the latest drawing stroke locally in order to
26  * produce better reponses. This can be disabled by calling
27  * controller.disablePlayBack(), which will introduce a lag between the input
28  * and the drawing.
29  * Note: in order to keep up with the drawing data, the client will try to read
30  * a few times each frame in case more than one frame worth of data has been
31  * received and render them together. This behavior can be adjusted by tweaking
32  * MAX_READ_PER_FRAME or disabled by turning fSync to false
33  */
34 
35 #define MAX_READ_PER_FRAME 5
36 
37 class DrawingClientView : public SampleView {
38 public:
DrawingClientView()39     DrawingClientView() {
40         fSocket = NULL;
41         fTotalBytesRead = 0;
42         fPalette = new SkColorPalette;
43         fPalette->setSize(100, 300);
44         fPalette->setVisibleP(true);
45         this->attachChildToFront(fPalette);
46         fPalette->unref();
47         fBrushSize = 2.5;
48         fAA = false;
49         fPaletteVisible = true;
50         fSync = true;
51         fVector = true;
52     }
~DrawingClientView()53     ~DrawingClientView() {
54         if (fSocket) {
55             delete fSocket;
56         }
57         fData.reset();
58         fBuffer.reset();
59     }
60 
requestMenu(SkOSMenu * menu)61     virtual void requestMenu(SkOSMenu* menu) {
62         menu->setTitle("Drawing Client");
63         menu->appendTextField("Server IP", "Server IP", this->getSinkID(),
64                               "IP address or hostname");
65         menu->appendSwitch("Vector", "Vector", this->getSinkID(), fVector);
66         menu->appendSlider("Brush Size", "Brush Size", this->getSinkID(), 1.0,
67                            100.0, fBrushSize);
68         menu->appendSwitch("Anti-Aliasing", "AA", this->getSinkID(), fAA);
69         menu->appendSwitch("Show Color Palette", "Palette", this->getSinkID(),
70                            fPaletteVisible);
71         menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync);
72         menu->appendAction("Clear", this->getSinkID());
73     }
74 
75 protected:
76 
readData(int cid,const void * data,size_t size,SkSocket::DataType type,void * context)77     static void readData(int cid, const void* data, size_t size,
78                          SkSocket::DataType type, void* context) {
79         DrawingClientView* view = (DrawingClientView*)context;
80         view->onRead(cid, data, size, type);
81     }
82 
onRead(int cid,const void * data,size_t size,SkSocket::DataType type)83     void onRead(int cid, const void* data, size_t size, SkSocket::DataType type) {
84         if (size > 0) {
85             fBuffer.reset();
86             if (type == SkSocket::kPipeReplace_type)
87                 fBuffer.append(size, (const char*)data);
88             else if (type == SkSocket::kPipeAppend_type)
89                 fData.append(size, (const char*)data);
90             else {
91                 //other types of data
92             }
93         }
94     }
95 
onQuery(SkEvent * evt)96     bool onQuery(SkEvent* evt) {
97         if (SampleCode::TitleQ(*evt)) {
98             SampleCode::TitleR(evt, "Drawing Client");
99             return true;
100         }
101 
102         return this->INHERITED::onQuery(evt);
103     }
104 
onEvent(const SkEvent & evt)105     bool onEvent(const SkEvent& evt) {;
106         if (SkOSMenu::FindSliderValue(evt, "Brush Size", &fBrushSize))
107             return true;
108 
109         SkString s;
110         if (SkOSMenu::FindText(evt, "Server IP", &s)) {
111             if (NULL != fSocket) {
112                 delete fSocket;
113             }
114             fSocket = new SkTCPClient(s.c_str(), 40000);
115             fSocket->connectToServer();
116             fSocket->suspendWrite();
117             SkDebugf("Connecting to %s\n", s.c_str());
118             fData.reset();
119             fBuffer.reset();
120             this->inval(NULL);
121             return true;
122         }
123         if (SkOSMenu::FindSwitchState(evt, "AA", &fAA) ||
124             SkOSMenu::FindSwitchState(evt, "Sync", &fSync))
125             return true;
126         if (SkOSMenu::FindSwitchState(evt, "Vector", &fVector)) {
127             this->clearBitmap();
128             return true;
129         }
130         if (SkOSMenu::FindAction(evt, "Clear")) {
131             this->clear();
132             return true;
133         }
134         if (SkOSMenu::FindSwitchState(evt, "Palette", &fPaletteVisible)) {
135             fPalette->setVisibleP(fPaletteVisible);
136             return true;
137         }
138         return this->INHERITED::onEvent(evt);
139     }
140 
onFindClickHandler(SkScalar x,SkScalar y)141     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
142         return new Click(this);
143     }
144 
onClick(SkView::Click * click)145     virtual bool onClick(SkView::Click* click) {
146         switch (click->fState) {
147             case SkView::Click::kDown_State:
148                 fCurrLine.moveTo(click->fCurr);
149                 fType = SkSocket::kPipeReplace_type;
150                 if (fSocket)
151                     fSocket->resumeWrite();
152                 break;
153             case SkView::Click::kMoved_State:
154                 fCurrLine.lineTo(click->fCurr);
155                 break;
156             case SkView::Click::kUp_State:
157                 fType = SkSocket::kPipeAppend_type;
158                 break;
159             default:
160                 break;
161         }
162         return true;
163     }
164 
onDrawContent(SkCanvas * canvas)165     virtual void onDrawContent(SkCanvas* canvas) {
166         if (fSocket) {
167             if (fSocket->isConnected()) {
168                 if (fSync) {
169                     int count = 0;
170                     while (fSocket->readPacket(readData, this) > 0 &&
171                            count < MAX_READ_PER_FRAME)
172                         ++count;
173                 }
174                 else
175                     fSocket->readPacket(readData, this);
176             }
177             else
178                 fSocket->connectToServer();
179         }
180         size_t bytesRead = 0;
181         SkGPipeReader::Status status;
182         SkCanvas bufferCanvas(fBase);
183         SkCanvas* tempCanvas;
184         while (fTotalBytesRead < fData.count()) {
185             if (fVector)
186                 tempCanvas = canvas;
187             else
188                 tempCanvas = &bufferCanvas;
189             SkGPipeReader reader(tempCanvas);
190             status = reader.playback(fData.begin() + fTotalBytesRead,
191                                      fData.count() - fTotalBytesRead,
192                                      &bytesRead);
193             SkASSERT(SkGPipeReader::kError_Status != status);
194             fTotalBytesRead += bytesRead;
195         }
196         if (fVector)
197             fTotalBytesRead = 0;
198         else
199             canvas->drawBitmap(fBase, 0, 0, NULL);
200 
201         size_t totalBytesRead = 0;
202         while (totalBytesRead < fBuffer.count()) {
203             SkGPipeReader reader(canvas);
204             status = reader.playback(fBuffer.begin() + totalBytesRead,
205                                      fBuffer.count() - totalBytesRead,
206                                      &bytesRead);
207             SkASSERT(SkGPipeReader::kError_Status != status);
208             totalBytesRead += bytesRead;
209         }
210 
211         SkNetPipeController controller(canvas);
212         SkGPipeWriter writer;
213         SkCanvas* writerCanvas = writer.startRecording(&controller,
214                                                        SkGPipeWriter::kCrossProcess_Flag);
215 
216         //controller.disablePlayback();
217         SkPaint p;
218         p.setColor(fPalette->getColor());
219         p.setStyle(SkPaint::kStroke_Style);
220         p.setStrokeWidth(fBrushSize);
221         p.setStrokeCap(SkPaint::kRound_Cap);
222         p.setStrokeJoin(SkPaint::kRound_Join);
223         p.setAntiAlias(fAA);
224         p.setPathEffect(new SkCornerPathEffect(55))->unref();
225         writerCanvas->drawPath(fCurrLine, p);
226         writer.endRecording();
227 
228         controller.writeToSocket(fSocket, fType);
229         if (fType == SkSocket::kPipeAppend_type && fSocket) {
230             fSocket->suspendWrite();
231             fCurrLine.reset();
232         }
233 
234         this->inval(NULL);
235     }
236 
onSizeChange()237     virtual void onSizeChange() {
238         this->INHERITED::onSizeChange();
239         fPalette->setLoc(this->width()-100, 0);
240         fBase.setConfig(SkBitmap::kARGB_8888_Config, this->width(), this->height());
241         fBase.allocPixels(NULL);
242         this->clearBitmap();
243     }
244 
245 private:
clear()246     void clear() {
247         fData.reset();
248         fBuffer.reset();
249         fCurrLine.reset();
250         fTotalBytesRead = 0;
251         this->clearBitmap();
252     }
clearBitmap()253     void clearBitmap() {
254         fTotalBytesRead = 0;
255         fBase.eraseColor(fBGColor);
256     }
257     SkTDArray<char>     fData;
258     SkTDArray<char>     fBuffer;
259     SkBitmap            fBase;
260     SkPath              fCurrLine;
261     SkTCPClient*        fSocket;
262     SkSocket::DataType  fType;
263     SkColorPalette*     fPalette;
264     bool                fPaletteVisible;
265     size_t              fTotalBytesRead;
266     SkScalar            fBrushSize;
267     bool                fAA;
268     bool                fSync;
269     bool                fVector;
270 
271     typedef SampleView INHERITED;
272 };
273 
274 
275 ///////////////////////////////////////////////////////////////////////////////
276 
MyFactory()277 static SkView* MyFactory() { return new DrawingClientView; }
278 static SkViewRegister reg(MyFactory);
279