d6176b0dca
This CL is part II of IV (I broke down the 1280 files into 4 CLs). Review URL: https://codereview.appspot.com/6474054 git-svn-id: http://skia.googlecode.com/svn/trunk@5263 2bbb7eff-a529-9590-31e7-b0007b416f81
223 lines
7.1 KiB
C++
223 lines
7.1 KiB
C++
#include "SampleCode.h"
|
|
#include "SkView.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkGPipe.h"
|
|
#include "SkSockets.h"
|
|
#include "SkNetPipeController.h"
|
|
#include "SkCornerPathEffect.h"
|
|
#include "SkOSMenu.h"
|
|
#include <map>
|
|
|
|
/**
|
|
* Drawing Server
|
|
*
|
|
* This simple drawing server can accept connections from multiple drawing
|
|
* clients simultaneously. It accumulates drawing data from each client each
|
|
* frame, stores it in the appropriate place, and then broadcasts incremental
|
|
* changes back to all the clients. Each logical packet, meaning one brush
|
|
* stoke in this case can be of two types, append and replace. Append types are
|
|
* completed strokes ready to be stored in the fData queue and will no longer be
|
|
* modified. Replace types are drawing operations that are still in progress on
|
|
* the client side, so they are appended to fBuffer. The location and size of
|
|
* the buffered data for each client is stored in a map and updated properly.
|
|
* Each time a new replace drawing call is received from a client, its previous
|
|
* buffered data is discarded.
|
|
* Since the Server keeps all the complete drawing data and the latest buffered
|
|
* data, it's able to switch between vector and bitmap drawing
|
|
*/
|
|
|
|
class DrawingServerView : public SampleView {
|
|
public:
|
|
DrawingServerView(){
|
|
fServer = new SkTCPServer(40000);
|
|
fServer->suspendWrite();
|
|
fTotalBytesRead = fTotalBytesWritten = 0;
|
|
fVector = true;
|
|
}
|
|
~DrawingServerView() {
|
|
delete fServer;
|
|
fData.reset();
|
|
fBuffer.reset();
|
|
fClientMap.clear();
|
|
}
|
|
|
|
virtual void requestMenu(SkOSMenu* menu) {
|
|
menu->setTitle("Drawing Server");
|
|
menu->appendAction("Clear", this->getSinkID());
|
|
menu->appendSwitch("Vector", "Vector", this->getSinkID(), fVector);
|
|
}
|
|
|
|
protected:
|
|
static void readData(int cid, const void* data, size_t size,
|
|
SkSocket::DataType type, void* context) {
|
|
DrawingServerView* view = (DrawingServerView*)context;
|
|
view->onRead(cid, data, size, type);
|
|
}
|
|
|
|
void onRead(int cid, const void* data, size_t size, SkSocket::DataType type) {
|
|
if (NULL == data && size <= 0)
|
|
return;
|
|
|
|
ClientState* cs;
|
|
std::map<int, ClientState*>::iterator it = fClientMap.find(cid);
|
|
if (it == fClientMap.end()) { //New client
|
|
cs = new ClientState;
|
|
cs->bufferBase = 0;
|
|
cs->bufferSize = 0;
|
|
fClientMap[cid] = cs;
|
|
}
|
|
else {
|
|
cs = it->second;
|
|
}
|
|
|
|
if (type == SkSocket::kPipeReplace_type) {
|
|
fBuffer.remove(cs->bufferBase, cs->bufferSize);
|
|
|
|
for (it = fClientMap.begin(); it != fClientMap.end(); ++it) {
|
|
if (cid == it->first)
|
|
continue;
|
|
else {
|
|
if (it->second->bufferBase > cs->bufferBase) {
|
|
it->second->bufferBase -= cs->bufferSize;
|
|
SkASSERT(it->second->bufferBase >= 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
cs->bufferBase = fBuffer.count();
|
|
cs->bufferSize = size;
|
|
fBuffer.append(size, (const char*)data);
|
|
}
|
|
else if (type == SkSocket::kPipeAppend_type) {
|
|
fData.append(size, (const char*)data);
|
|
fServer->resumeWrite();
|
|
fServer->writePacket(fData.begin() + fTotalBytesWritten,
|
|
fData.count() - fTotalBytesWritten,
|
|
SkSocket::kPipeAppend_type);
|
|
fTotalBytesWritten = fData.count();
|
|
fServer->suspendWrite();
|
|
}
|
|
else {
|
|
//other types of data
|
|
}
|
|
}
|
|
|
|
bool onQuery(SkEvent* evt) {
|
|
if (SampleCode::TitleQ(*evt)) {
|
|
SampleCode::TitleR(evt, "Drawing Server");
|
|
return true;
|
|
}
|
|
return this->INHERITED::onQuery(evt);
|
|
}
|
|
|
|
bool onEvent(const SkEvent& evt) {
|
|
if (SkOSMenu::FindAction(evt, "Clear")) {
|
|
this->clear();
|
|
return true;
|
|
}
|
|
if (SkOSMenu::FindSwitchState(evt, "Vector", &fVector)) {
|
|
this->clearBitmap();
|
|
return true;
|
|
}
|
|
return this->INHERITED::onEvent(evt);
|
|
}
|
|
|
|
|
|
virtual void onDrawContent(SkCanvas* canvas) {
|
|
if (fCurrMatrix != canvas->getTotalMatrix()) {
|
|
fTotalBytesRead = 0;
|
|
fCurrMatrix = canvas->getTotalMatrix();
|
|
}
|
|
|
|
fServer->acceptConnections();
|
|
if (fServer->readPacket(readData, this) > 0) {
|
|
fServer->resumeWrite();
|
|
}
|
|
else {
|
|
fServer->suspendWrite();
|
|
}
|
|
|
|
size_t bytesRead;
|
|
SkGPipeReader::Status stat;
|
|
SkCanvas bufferCanvas(fBase);
|
|
SkCanvas* tempCanvas;
|
|
while (fTotalBytesRead < fData.count()) {
|
|
if (fVector) {
|
|
tempCanvas = canvas;
|
|
} else {
|
|
tempCanvas = &bufferCanvas;
|
|
}
|
|
SkGPipeReader reader(tempCanvas);
|
|
stat = reader.playback(fData.begin() + fTotalBytesRead,
|
|
fData.count() - fTotalBytesRead,
|
|
&bytesRead);
|
|
SkASSERT(SkGPipeReader::kError_Status != stat);
|
|
fTotalBytesRead += bytesRead;
|
|
}
|
|
if (fVector) {
|
|
fTotalBytesRead = 0;
|
|
} else {
|
|
canvas->drawBitmap(fBase, 0, 0, NULL);
|
|
}
|
|
|
|
size_t totalBytesRead = 0;
|
|
while (totalBytesRead < fBuffer.count()) {
|
|
SkGPipeReader reader(canvas);
|
|
stat = reader.playback(fBuffer.begin() + totalBytesRead,
|
|
fBuffer.count() - totalBytesRead,
|
|
&bytesRead);
|
|
SkASSERT(SkGPipeReader::kError_Status != stat);
|
|
totalBytesRead += bytesRead;
|
|
}
|
|
|
|
fServer->writePacket(fBuffer.begin(), fBuffer.count(),
|
|
SkSocket::kPipeReplace_type);
|
|
|
|
this->inval(NULL);
|
|
}
|
|
|
|
virtual void onSizeChange() {
|
|
this->INHERITED::onSizeChange();
|
|
fBase.setConfig(SkBitmap::kARGB_8888_Config,
|
|
this->width(),
|
|
this->height());
|
|
fBase.allocPixels(NULL);
|
|
this->clearBitmap();
|
|
}
|
|
|
|
private:
|
|
void clear() {
|
|
fData.reset();
|
|
fBuffer.reset();
|
|
fTotalBytesRead = fTotalBytesWritten = 0;
|
|
fClientMap.clear();
|
|
this->clearBitmap();
|
|
}
|
|
void clearBitmap() {
|
|
fTotalBytesRead = 0;
|
|
fBase.eraseColor(fBGColor);
|
|
}
|
|
|
|
struct ClientState {
|
|
int bufferBase;
|
|
int bufferSize;
|
|
};
|
|
|
|
std::map<int, ClientState*> fClientMap;
|
|
SkTDArray<char> fData;
|
|
SkTDArray<char> fBuffer;
|
|
size_t fTotalBytesRead;
|
|
size_t fTotalBytesWritten;
|
|
SkMatrix fCurrMatrix;
|
|
SkBitmap fBase;
|
|
bool fVector;
|
|
SkTCPServer* fServer;
|
|
typedef SampleView INHERITED;
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static SkView* MyFactory() { return new DrawingServerView; }
|
|
static SkViewRegister reg(MyFactory);
|