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
37class DrawingClientView : public SampleView {
38public:
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    }
53    ~DrawingClientView() {
54        if (fSocket) {
55            delete fSocket;
56        }
57        fData.reset();
58        fBuffer.reset();
59    }
60
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
75protected:
76
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
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
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
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
141    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
142        return new Click(this);
143    }
144
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
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
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
245private:
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;
270
271    typedef SampleView INHERITED;
272};
273
274
275///////////////////////////////////////////////////////////////////////////////
276
277static SkView* MyFactory() { return new DrawingClientView; }
278static SkViewRegister reg(MyFactory);
279