#include "SampleCode.h" #include "SkView.h" #include "SkCanvas.h" #include "SkGradientShader.h" #include "SkGPipe.h" #include "SkSockets.h" #include "SkOSMenu.h" /** * A simple networked pipe reader * * This view will connect to a user specified server, in this case meaning any * Skia app that's has a SkTCPServer set up to broadcast its piped drawing data, * received all the data transmitted and attempt to reproduce the drawing calls. * This reader will only keep the latest batch of data. In order to keep up with * the server, which may be producing data at a much higher rate than the reader * is consuming, the reader will attempt multiple reads and only render the * latest frame. this behavior can be adjusted by changing MAX_READS_PER_FRAME * or disabled by setting fSync to false */ #define MAX_READS_PER_FRAME 12 class NetPipeReaderView : public SampleView { public: NetPipeReaderView() { fSocket = NULL; fSync = true; } ~NetPipeReaderView() { if (fSocket) { delete fSocket; } fDataArray.reset(); } virtual void requestMenu(SkOSMenu* menu) { menu->setTitle("Net Pipe Reader"); menu->appendTextField("Server IP", "Server IP", this->getSinkID(), "IP address"); menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync); } protected: static void readData(int cid, const void* data, size_t size, SkSocket::DataType type, void* context) { NetPipeReaderView* view = (NetPipeReaderView*)context; view->onRead(data, size); } void onRead(const void* data, size_t size) { if (size > 0) fDataArray.append(size, (const char*)data); } bool onQuery(SkEvent* evt) { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "Net Pipe Reader"); return true; } return this->INHERITED::onQuery(evt); } bool onEvent(const SkEvent& evt) { SkString s; if (SkOSMenu::FindText(evt, "Server IP", &s)) { if (NULL != fSocket) { delete fSocket; } fSocket = new SkTCPClient(s.c_str()); fSocket->connectToServer(); SkDebugf("Connecting to %s\n", s.c_str()); return true; } if (SkOSMenu::FindSwitchState(evt, "Sync", &fSync)) return true; return this->INHERITED::onEvent(evt); } void onDrawContent(SkCanvas* canvas) { if (NULL == fSocket) return; if (fSocket->isConnected()) { int dataToRemove = fDataArray.count(); if (fSync) { int numreads = 0; while (fSocket->readPacket(readData, this) > 0 && numreads < MAX_READS_PER_FRAME) { // at this point, new data has been read and stored, discard // old data since it's not needed anymore SkASSERT(fDataArray.count() > dataToRemove); fDataArray.remove(0, dataToRemove); dataToRemove = fDataArray.count(); ++numreads; } // clean up if max reads reached if (numreads == MAX_READS_PER_FRAME && fDataArray.count() > dataToRemove) fDataArray.remove(0, dataToRemove); } else { if (fSocket->readPacket(readData, this) > 0) fDataArray.remove(0, dataToRemove); } } else fSocket->connectToServer(); SkGPipeReader reader(canvas); size_t bytesRead; SkGPipeReader::Status fStatus = reader.playback(fDataArray.begin(), fDataArray.count(), &bytesRead); SkASSERT(SkGPipeReader::kError_Status != fStatus); this->inval(NULL); } private: bool fSync; SkTDArray<char> fDataArray; SkTCPClient* fSocket; typedef SampleView INHERITED; }; /////////////////////////////////////////////////////////////////////////////// static SkView* MyFactory() { return new NetPipeReaderView; } static SkViewRegister reg(MyFactory);