1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SampleCode.h" 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkView.h" 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkCanvas.h" 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkGPipe.h" 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkSockets.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkNetPipeController.h" 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkCornerPathEffect.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkColorPalette.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "SkOSMenu.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/** 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Drawing Client 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * A drawing client that allows a user to perform simple brush stokes with 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * a selected color and brush size. The drawing client communicates with a 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * drawing server to send/receive data to/from other clients connected to the 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * same server. The drawing client stores data in fData and fBuffer depending on 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * the data type. Append type means that the drawing data is a completed stroke 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * and Replace type means that the drawing data is in progress and will be 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * replaced by subsequent data. fData and fBuffer are read by a pipe reader and 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * reproduce the drawing. When the client is in a normal state, the data stored 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * on the client and the server should be identical. 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * The drawing client is also able to switch between vector and bitmap drawing. 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * The drawing client also renders the latest drawing stroke locally in order to 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * produce better reponses. This can be disabled by calling 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * controller.disablePlayBack(), which will introduce a lag between the input 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * and the drawing. 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Note: in order to keep up with the drawing data, the client will try to read 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * a few times each frame in case more than one frame worth of data has been 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * received and render them together. This behavior can be adjusted by tweaking 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * MAX_READ_PER_FRAME or disabled by turning fSync to false 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define MAX_READ_PER_FRAME 5 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class DrawingClientView : public SampleView { 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)public: 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DrawingClientView() { 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fSocket = NULL; 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fTotalBytesRead = 0; 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPalette = new SkColorPalette; 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPalette->setSize(100, 300); 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPalette->setVisibleP(true); 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) this->attachChildToFront(fPalette); 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPalette->unref(); 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fBrushSize = 2.5; 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fAA = false; 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPaletteVisible = true; 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fSync = true; 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fVector = true; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ~DrawingClientView() { 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (fSocket) { 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) delete fSocket; 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fData.reset(); 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fBuffer.reset(); 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) virtual void requestMenu(SkOSMenu* menu) { 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->setTitle("Drawing Client"); 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendTextField("Server IP", "Server IP", this->getSinkID(), 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "IP address or hostname"); 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendSwitch("Vector", "Vector", this->getSinkID(), fVector); 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendSlider("Brush Size", "Brush Size", this->getSinkID(), 1.0, 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 100.0, fBrushSize); 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendSwitch("Anti-Aliasing", "AA", this->getSinkID(), fAA); 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendSwitch("Show Color Palette", "Palette", this->getSinkID(), 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fPaletteVisible); 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync); 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) menu->appendAction("Clear", this->getSinkID()); 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)protected: 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static void readData(int cid, const void* data, size_t size, 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkSocket::DataType type, void* context) { 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DrawingClientView* view = (DrawingClientView*)context; 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) view->onRead(cid, data, size, type); 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void onRead(int cid, const void* data, size_t size, SkSocket::DataType type) { 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (size > 0) { 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fBuffer.reset(); 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (type == SkSocket::kPipeReplace_type) 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fBuffer.append(size, (const char*)data); 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) else if (type == SkSocket::kPipeAppend_type) 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fData.append(size, (const char*)data); 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) else { 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) //other types of data 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool onQuery(SkEvent* evt) { 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (SampleCode::TitleQ(*evt)) { 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 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