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