Home | History | Annotate | Download | only in DrawingBoard
      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 
     37 class DrawingClientView : public SampleView {
     38 public:
     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 
     75 protected:
     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 
    245 private:
    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 
    277 static SkView* MyFactory() { return new DrawingClientView; }
    278 static SkViewRegister reg(MyFactory);
    279