blob: 542c5890302e3e74b809fa1c2e66c774c2bcbb71 [file] [log] [blame]
yangsu@google.comf3493f02011-08-08 15:12:05 +00001#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
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000011
12/**
13 * Drawing Client
14 *
rmistry@google.comd6176b02012-08-23 18:14:13 +000015 * 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
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000017 * 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
rmistry@google.comd6176b02012-08-23 18:14:13 +000020 * 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
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000022 * 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
rmistry@google.comd6176b02012-08-23 18:14:13 +000026 * produce better reponses. This can be disabled by calling
27 * controller.disablePlayBack(), which will introduce a lag between the input
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000028 * and the drawing.
29 * Note: in order to keep up with the drawing data, the client will try to read
rmistry@google.comd6176b02012-08-23 18:14:13 +000030 * a few times each frame in case more than one frame worth of data has been
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000031 * 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
yangsu@google.comf3493f02011-08-08 15:12:05 +000035#define MAX_READ_PER_FRAME 5
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000036
yangsu@google.comf3493f02011-08-08 15:12:05 +000037class DrawingClientView : public SampleView {
38public:
rmistry@google.comd6176b02012-08-23 18:14:13 +000039 DrawingClientView() {
yangsu@google.comf3493f02011-08-08 15:12:05 +000040 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();
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000047 fBrushSize = 2.5;
yangsu@google.comf3493f02011-08-08 15:12:05 +000048 fAA = false;
49 fPaletteVisible = true;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000050 fSync = true;
51 fVector = true;
yangsu@google.comf3493f02011-08-08 15:12:05 +000052 }
53 ~DrawingClientView() {
54 if (fSocket) {
55 delete fSocket;
56 }
57 fData.reset();
58 fBuffer.reset();
59 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000060
yangsu@google.comf3493f02011-08-08 15:12:05 +000061 virtual void requestMenu(SkOSMenu* menu) {
62 menu->setTitle("Drawing Client");
rmistry@google.comd6176b02012-08-23 18:14:13 +000063 menu->appendTextField("Server IP", "Server IP", this->getSinkID(),
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000064 "IP address or hostname");
yangsu@google.comf3493f02011-08-08 15:12:05 +000065 menu->appendSwitch("Vector", "Vector", this->getSinkID(), fVector);
rmistry@google.comd6176b02012-08-23 18:14:13 +000066 menu->appendSlider("Brush Size", "Brush Size", this->getSinkID(), 1.0,
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000067 100.0, fBrushSize);
yangsu@google.comf3493f02011-08-08 15:12:05 +000068 menu->appendSwitch("Anti-Aliasing", "AA", this->getSinkID(), fAA);
rmistry@google.comd6176b02012-08-23 18:14:13 +000069 menu->appendSwitch("Show Color Palette", "Palette", this->getSinkID(),
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000070 fPaletteVisible);
yangsu@google.comf3493f02011-08-08 15:12:05 +000071 menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync);
72 menu->appendAction("Clear", this->getSinkID());
73 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000074
yangsu@google.comf3493f02011-08-08 15:12:05 +000075protected:
rmistry@google.comd6176b02012-08-23 18:14:13 +000076
yangsu@google.comf3493f02011-08-08 15:12:05 +000077 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000082
yangsu@google.comf3493f02011-08-08 15:12:05 +000083 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000095
yangsu@google.comf3493f02011-08-08 15:12:05 +000096 bool onQuery(SkEvent* evt) {
97 if (SampleCode::TitleQ(*evt)) {
98 SampleCode::TitleR(evt, "Drawing Client");
99 return true;
100 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000101
yangsu@google.comf3493f02011-08-08 15:12:05 +0000102 return this->INHERITED::onQuery(evt);
103 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000104
yangsu@google.comf3493f02011-08-08 15:12:05 +0000105 bool onEvent(const SkEvent& evt) {;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000106 if (SkOSMenu::FindSliderValue(evt, "Brush Size", &fBrushSize))
yangsu@google.comf3493f02011-08-08 15:12:05 +0000107 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000108
yangsu@google.comf3493f02011-08-08 15:12:05 +0000109 SkString s;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000110 if (SkOSMenu::FindText(evt, "Server IP", &s)) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000111 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 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000123 if (SkOSMenu::FindSwitchState(evt, "AA", &fAA) ||
124 SkOSMenu::FindSwitchState(evt, "Sync", &fSync))
yangsu@google.comf3493f02011-08-08 15:12:05 +0000125 return true;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000126 if (SkOSMenu::FindSwitchState(evt, "Vector", &fVector)) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000127 this->clearBitmap();
128 return true;
129 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000130 if (SkOSMenu::FindAction(evt, "Clear")) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000131 this->clear();
132 return true;
133 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000134 if (SkOSMenu::FindSwitchState(evt, "Palette", &fPaletteVisible)) {
yangsu@google.comf3493f02011-08-08 15:12:05 +0000135 fPalette->setVisibleP(fPaletteVisible);
136 return true;
137 }
138 return this->INHERITED::onEvent(evt);
139 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000140
yangsu@google.comf3493f02011-08-08 15:12:05 +0000141 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
142 return new Click(this);
143 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000144
yangsu@google.comf3493f02011-08-08 15:12:05 +0000145 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000164
yangsu@google.comf3493f02011-08-08 15:12:05 +0000165 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 &&
rmistry@google.comd6176b02012-08-23 18:14:13 +0000171 count < MAX_READ_PER_FRAME)
yangsu@google.comf3493f02011-08-08 15:12:05 +0000172 ++count;
173 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000174 else
yangsu@google.comf3493f02011-08-08 15:12:05 +0000175 fSocket->readPacket(readData, this);
176 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000177 else
yangsu@google.comf3493f02011-08-08 15:12:05 +0000178 fSocket->connectToServer();
179 }
180 size_t bytesRead = 0;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000181 SkGPipeReader::Status status;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000182 SkCanvas bufferCanvas(fBase);
183 SkCanvas* tempCanvas;
184 while (fTotalBytesRead < fData.count()) {
185 if (fVector)
186 tempCanvas = canvas;
187 else
188 tempCanvas = &bufferCanvas;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000189 SkGPipeReader reader(tempCanvas);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000190 status = reader.playback(fData.begin() + fTotalBytesRead,
191 fData.count() - fTotalBytesRead,
192 &bytesRead);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000193 SkASSERT(SkGPipeReader::kError_Status != status);
194 fTotalBytesRead += bytesRead;
195 }
196 if (fVector)
197 fTotalBytesRead = 0;
198 else
199 canvas->drawBitmap(fBase, 0, 0, NULL);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000200
yangsu@google.comf3493f02011-08-08 15:12:05 +0000201 size_t totalBytesRead = 0;
202 while (totalBytesRead < fBuffer.count()) {
203 SkGPipeReader reader(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000204 status = reader.playback(fBuffer.begin() + totalBytesRead,
205 fBuffer.count() - totalBytesRead,
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000206 &bytesRead);
207 SkASSERT(SkGPipeReader::kError_Status != status);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000208 totalBytesRead += bytesRead;
209 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000210
yangsu@google.comf3493f02011-08-08 15:12:05 +0000211 SkNetPipeController controller(canvas);
212 SkGPipeWriter writer;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000213 SkCanvas* writerCanvas = writer.startRecording(&controller,
yangsu@google.comf3493f02011-08-08 15:12:05 +0000214 SkGPipeWriter::kCrossProcess_Flag);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000215
yangsu@google.comf3493f02011-08-08 15:12:05 +0000216 //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();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000227
yangsu@google.comf3493f02011-08-08 15:12:05 +0000228 controller.writeToSocket(fSocket, fType);
229 if (fType == SkSocket::kPipeAppend_type && fSocket) {
230 fSocket->suspendWrite();
231 fCurrLine.reset();
232 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000233
yangsu@google.comf3493f02011-08-08 15:12:05 +0000234 this->inval(NULL);
235 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000236
yangsu@google.comf3493f02011-08-08 15:12:05 +0000237 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000244
yangsu@google.comf3493f02011-08-08 15:12:05 +0000245private:
246 void clear() {
247 fData.reset();
248 fBuffer.reset();
249 fCurrLine.reset();
250 fTotalBytesRead = 0;
251 this->clearBitmap();
252 }
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;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000270
yangsu@google.comf3493f02011-08-08 15:12:05 +0000271 typedef SampleView INHERITED;
272};
273
274
275///////////////////////////////////////////////////////////////////////////////
276
277static SkView* MyFactory() { return new DrawingClientView; }
278static SkViewRegister reg(MyFactory);