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