1d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "nanomsg/src/nn.h"
2d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "nanomsg/src/pipeline.h"
3d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "nanomsg/src/reqrep.h"
4d6043b20b63f895d384b4794205ac914abfafa71mtklein
5d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkCanvas.h"
6d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkCommandLineFlags.h"
7d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkData.h"
8d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkForceLinking.h"
9d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkGraphics.h"
10d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkImageEncoder.h"
11d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkOSFile.h"
12d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkPicture.h"
13d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkRandom.h"
14d6043b20b63f895d384b4794205ac914abfafa71mtklein#include "SkStream.h"
15d6043b20b63f895d384b4794205ac914abfafa71mtklein
16d6043b20b63f895d384b4794205ac914abfafa71mtklein__SK_FORCE_IMAGE_DECODER_LINKING;
17d6043b20b63f895d384b4794205ac914abfafa71mtklein
18d6043b20b63f895d384b4794205ac914abfafa71mtklein// To keep things simple, PictureHeader is fixed-size POD.
19d6043b20b63f895d384b4794205ac914abfafa71mtkleinstruct PictureHeader {
20d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkMatrix         matrix;
21d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkRect           clip;
22d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkXfermode::Mode xfermode;
23d6043b20b63f895d384b4794205ac914abfafa71mtklein    pid_t            pid;
24d6043b20b63f895d384b4794205ac914abfafa71mtklein    uint8_t          alpha;
25d6043b20b63f895d384b4794205ac914abfafa71mtklein
26d6043b20b63f895d384b4794205ac914abfafa71mtklein    PictureHeader()
27d6043b20b63f895d384b4794205ac914abfafa71mtklein        : matrix(SkMatrix::I())
28d6043b20b63f895d384b4794205ac914abfafa71mtklein        , clip(SkRect::MakeLargest())
29d6043b20b63f895d384b4794205ac914abfafa71mtklein        , xfermode(SkXfermode::kSrcOver_Mode)
30d6043b20b63f895d384b4794205ac914abfafa71mtklein        , pid(getpid())
31d6043b20b63f895d384b4794205ac914abfafa71mtklein        , alpha(0xFF) {}
32d6043b20b63f895d384b4794205ac914abfafa71mtklein};
33d6043b20b63f895d384b4794205ac914abfafa71mtklein
34d6043b20b63f895d384b4794205ac914abfafa71mtklein// A little adaptor: nn_iovec wants a non-const pointer for no obvious reason.
35d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic struct nn_iovec create_iov(const void* ptr, size_t size) {
36d6043b20b63f895d384b4794205ac914abfafa71mtklein    struct nn_iovec iov = { const_cast<void*>(ptr), size };
37d6043b20b63f895d384b4794205ac914abfafa71mtklein    return iov;
38d6043b20b63f895d384b4794205ac914abfafa71mtklein}
39d6043b20b63f895d384b4794205ac914abfafa71mtklein
40d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic void send_picture(int socket, const PictureHeader& header, const SkData& skp) {
41d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Vectored IO lets us send header and skp contiguously without first
42d6043b20b63f895d384b4794205ac914abfafa71mtklein    // copying them to a contiguous buffer.
43d6043b20b63f895d384b4794205ac914abfafa71mtklein    struct nn_iovec iov[] = {
44d6043b20b63f895d384b4794205ac914abfafa71mtklein        create_iov(&header, sizeof(header)),
45d6043b20b63f895d384b4794205ac914abfafa71mtklein        create_iov(skp.data(), skp.size()),
46d6043b20b63f895d384b4794205ac914abfafa71mtklein    };
47d6043b20b63f895d384b4794205ac914abfafa71mtklein
48d6043b20b63f895d384b4794205ac914abfafa71mtklein    struct nn_msghdr msg;
49d6043b20b63f895d384b4794205ac914abfafa71mtklein    sk_bzero(&msg, sizeof(msg));
50d6043b20b63f895d384b4794205ac914abfafa71mtklein    msg.msg_iov    = iov;
51d6043b20b63f895d384b4794205ac914abfafa71mtklein    msg.msg_iovlen = SK_ARRAY_COUNT(iov);
52d6043b20b63f895d384b4794205ac914abfafa71mtklein
53d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_sendmsg(socket, &msg, 0/*flags*/);
54d6043b20b63f895d384b4794205ac914abfafa71mtklein}
55d6043b20b63f895d384b4794205ac914abfafa71mtklein
56d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic SkPicture* recv_picture(int socket, PictureHeader* header) {
57d6043b20b63f895d384b4794205ac914abfafa71mtklein    static const size_t hSize = sizeof(*header);  // It's easy to slip up and use sizeof(header).
58d6043b20b63f895d384b4794205ac914abfafa71mtklein
59d6043b20b63f895d384b4794205ac914abfafa71mtklein    void* msg;
60d6043b20b63f895d384b4794205ac914abfafa71mtklein    int size = nn_recv(socket, &msg, NN_MSG, 0/*flags*/);
61d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkDebugf("%d bytes", size);
62d6043b20b63f895d384b4794205ac914abfafa71mtklein
63d6043b20b63f895d384b4794205ac914abfafa71mtklein    // msg is first a fixed-size header, then an .skp.
64d6043b20b63f895d384b4794205ac914abfafa71mtklein    memcpy(header, msg, hSize);
65d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkMemoryStream stream((uint8_t*)msg + hSize, size - hSize);
66d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkPicture* pic = SkPicture::CreateFromStream(&stream);
67d6043b20b63f895d384b4794205ac914abfafa71mtklein
68d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkDebugf(" from proccess %d:", header->pid);
69d6043b20b63f895d384b4794205ac914abfafa71mtklein
70d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_freemsg(msg);
71d6043b20b63f895d384b4794205ac914abfafa71mtklein    return pic;
72d6043b20b63f895d384b4794205ac914abfafa71mtklein}
73d6043b20b63f895d384b4794205ac914abfafa71mtklein
74d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic void client(const char* skpPath, const char* dataEndpoint) {
75d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Read the .skp.
76d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkAutoTUnref<const SkData> skp(SkData::NewFromFileName(skpPath));
77d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (!skp) {
78d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkDebugf("Couldn't read %s\n", skpPath);
79d6043b20b63f895d384b4794205ac914abfafa71mtklein        exit(1);
80d6043b20b63f895d384b4794205ac914abfafa71mtklein    }
81d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkMemoryStream stream(skp->data(), skp->size());
82d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&stream));
83d6043b20b63f895d384b4794205ac914abfafa71mtklein
84d6043b20b63f895d384b4794205ac914abfafa71mtklein    PictureHeader header;
85d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkRandom rand(picture->width() * picture->height());
86d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkScalar r = rand.nextRangeScalar(0, picture->width()),
87d6043b20b63f895d384b4794205ac914abfafa71mtklein             b = rand.nextRangeScalar(0, picture->height()),
88d6043b20b63f895d384b4794205ac914abfafa71mtklein             l = rand.nextRangeScalar(0, r),
89d6043b20b63f895d384b4794205ac914abfafa71mtklein             t = rand.nextRangeScalar(0, b);
90d6043b20b63f895d384b4794205ac914abfafa71mtklein    header.clip.setLTRB(l,t,r,b);
91d6043b20b63f895d384b4794205ac914abfafa71mtklein    header.matrix.setTranslate(-l, -t);
92d6043b20b63f895d384b4794205ac914abfafa71mtklein    header.matrix.postRotate(rand.nextRangeScalar(-25, 25));
93d6043b20b63f895d384b4794205ac914abfafa71mtklein    header.alpha = 0x7F;
94d6043b20b63f895d384b4794205ac914abfafa71mtklein
95d6043b20b63f895d384b4794205ac914abfafa71mtklein    //Clients use NN_REQ (request) type sockets.
96d6043b20b63f895d384b4794205ac914abfafa71mtklein    int socket = nn_socket(AF_SP, NN_REQ);
97d6043b20b63f895d384b4794205ac914abfafa71mtklein
98d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Clients connect a socket to an endpoint.
99d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_connect(socket, dataEndpoint);
100d6043b20b63f895d384b4794205ac914abfafa71mtklein
101d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Send the picture and its header.
102d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkDebugf("Sending %s (%d bytes)...", skpPath, skp->size());
103d6043b20b63f895d384b4794205ac914abfafa71mtklein    send_picture(socket, header, *skp);
104d6043b20b63f895d384b4794205ac914abfafa71mtklein
105d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Wait for ack.
106d6043b20b63f895d384b4794205ac914abfafa71mtklein    uint8_t ack;
107d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_recv(socket, &ack, sizeof(ack), 0/*flags*/);
108d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkDebugf(" ok.\n");
109d6043b20b63f895d384b4794205ac914abfafa71mtklein}
110d6043b20b63f895d384b4794205ac914abfafa71mtklein
111d6043b20b63f895d384b4794205ac914abfafa71mtklein// Wait until socketA or socketB has something to tell us, and return which one.
112d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic int poll_in(int socketA, int socketB) {
113d6043b20b63f895d384b4794205ac914abfafa71mtklein    struct nn_pollfd polls[] = {
114d6043b20b63f895d384b4794205ac914abfafa71mtklein        { socketA, NN_POLLIN, 0 },
115d6043b20b63f895d384b4794205ac914abfafa71mtklein        { socketB, NN_POLLIN, 0 },
116d6043b20b63f895d384b4794205ac914abfafa71mtklein    };
117d6043b20b63f895d384b4794205ac914abfafa71mtklein
118d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_poll(polls, SK_ARRAY_COUNT(polls), -1/*no timeout*/);
119d6043b20b63f895d384b4794205ac914abfafa71mtklein
120d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (polls[0].revents & NN_POLLIN) { return socketA; }
121d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (polls[1].revents & NN_POLLIN) { return socketB; }
122d6043b20b63f895d384b4794205ac914abfafa71mtklein
123d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkFAIL("unreachable");
124d6043b20b63f895d384b4794205ac914abfafa71mtklein    return 0;
125d6043b20b63f895d384b4794205ac914abfafa71mtklein}
126d6043b20b63f895d384b4794205ac914abfafa71mtklein
127d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic void server(const char* dataEndpoint, const char* controlEndpoint, SkCanvas* canvas) {
128d6043b20b63f895d384b4794205ac914abfafa71mtklein    // NN_REP sockets receive a request then make a reply.  NN_PULL sockets just receive a request.
129d6043b20b63f895d384b4794205ac914abfafa71mtklein    int data    = nn_socket(AF_SP, NN_REP);
130d6043b20b63f895d384b4794205ac914abfafa71mtklein    int control = nn_socket(AF_SP, NN_PULL);
131d6043b20b63f895d384b4794205ac914abfafa71mtklein
132d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Servers bind a socket to an endpoint.
133d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_bind(data,    dataEndpoint);
134d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_bind(control, controlEndpoint);
135d6043b20b63f895d384b4794205ac914abfafa71mtklein
136d6043b20b63f895d384b4794205ac914abfafa71mtklein    while (true) {
137d6043b20b63f895d384b4794205ac914abfafa71mtklein        int ready = poll_in(data, control);
138d6043b20b63f895d384b4794205ac914abfafa71mtklein
139d6043b20b63f895d384b4794205ac914abfafa71mtklein        // If we got any message on the control socket, we can stop.
140d6043b20b63f895d384b4794205ac914abfafa71mtklein        if (ready == control) {
141d6043b20b63f895d384b4794205ac914abfafa71mtklein            break;
142d6043b20b63f895d384b4794205ac914abfafa71mtklein        }
143d6043b20b63f895d384b4794205ac914abfafa71mtklein
144d6043b20b63f895d384b4794205ac914abfafa71mtklein        // We should have an .skp waiting for us on data socket.
145d6043b20b63f895d384b4794205ac914abfafa71mtklein        PictureHeader header;
146d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkAutoTUnref<SkPicture> picture(recv_picture(data, &header));
147d6043b20b63f895d384b4794205ac914abfafa71mtklein
148d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkPaint paint;
149d6043b20b63f895d384b4794205ac914abfafa71mtklein        paint.setAlpha(header.alpha);
150d6043b20b63f895d384b4794205ac914abfafa71mtklein        paint.setXfermodeMode(header.xfermode);
151d6043b20b63f895d384b4794205ac914abfafa71mtklein
152d6043b20b63f895d384b4794205ac914abfafa71mtklein        canvas->saveLayer(NULL, &paint);
153d6043b20b63f895d384b4794205ac914abfafa71mtklein            canvas->concat(header.matrix);
154d6043b20b63f895d384b4794205ac914abfafa71mtklein            canvas->clipRect(header.clip);
155d6043b20b63f895d384b4794205ac914abfafa71mtklein            picture->draw(canvas);
156d6043b20b63f895d384b4794205ac914abfafa71mtklein        canvas->restore();
157d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkDebugf(" drew");
158d6043b20b63f895d384b4794205ac914abfafa71mtklein
159d6043b20b63f895d384b4794205ac914abfafa71mtklein        // Send back an ack.
160d6043b20b63f895d384b4794205ac914abfafa71mtklein        uint8_t ack = 42;
161d6043b20b63f895d384b4794205ac914abfafa71mtklein        nn_send(data, &ack, sizeof(ack), 0/*flags*/);
162d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkDebugf(" and acked.\n");
163d6043b20b63f895d384b4794205ac914abfafa71mtklein    }
164d6043b20b63f895d384b4794205ac914abfafa71mtklein}
165d6043b20b63f895d384b4794205ac914abfafa71mtklein
166d6043b20b63f895d384b4794205ac914abfafa71mtkleinstatic void stop(const char* controlEndpoint) {
167d6043b20b63f895d384b4794205ac914abfafa71mtklein    // An NN_PUSH socket can send messages but not receive them.
168d6043b20b63f895d384b4794205ac914abfafa71mtklein    int control = nn_socket(AF_SP, NN_PUSH);
169d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_connect(control, controlEndpoint);
170d6043b20b63f895d384b4794205ac914abfafa71mtklein
171d6043b20b63f895d384b4794205ac914abfafa71mtklein    // Sending anything (including this 0-byte message) will tell server() to stop.
172d6043b20b63f895d384b4794205ac914abfafa71mtklein    nn_send(control, NULL, 0, 0/*flags*/);
173d6043b20b63f895d384b4794205ac914abfafa71mtklein}
174d6043b20b63f895d384b4794205ac914abfafa71mtklein
175d6043b20b63f895d384b4794205ac914abfafa71mtkleinDEFINE_string2(skp, r, "", ".skp to send (as client)");
176d6043b20b63f895d384b4794205ac914abfafa71mtkleinDEFINE_string2(png, w, "", ".png to write (as server)");
177d6043b20b63f895d384b4794205ac914abfafa71mtkleinDEFINE_bool(stop, false, "If true, tell server to stop and write its canvas out as a .png.");
178d6043b20b63f895d384b4794205ac914abfafa71mtkleinDEFINE_string(data,    "ipc://nanomsg-picture-data",    "Endpoint for sending pictures.");
179d6043b20b63f895d384b4794205ac914abfafa71mtkleinDEFINE_string(control, "ipc://nanomsg-picture-control", "Endpoint for control channel.");
180d6043b20b63f895d384b4794205ac914abfafa71mtklein
181d6043b20b63f895d384b4794205ac914abfafa71mtkleinint main(int argc, char** argv) {
182d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkAutoGraphics ag;
183d6043b20b63f895d384b4794205ac914abfafa71mtklein    SkCommandLineFlags::Parse(argc, argv);
184d6043b20b63f895d384b4794205ac914abfafa71mtklein
185d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (FLAGS_stop) {
186d6043b20b63f895d384b4794205ac914abfafa71mtklein        stop(FLAGS_control[0]);
187d6043b20b63f895d384b4794205ac914abfafa71mtklein    }
188d6043b20b63f895d384b4794205ac914abfafa71mtklein
189d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (!FLAGS_skp.isEmpty()) {
190d6043b20b63f895d384b4794205ac914abfafa71mtklein        client(FLAGS_skp[0], FLAGS_data[0]);
191d6043b20b63f895d384b4794205ac914abfafa71mtklein    }
192d6043b20b63f895d384b4794205ac914abfafa71mtklein
193d6043b20b63f895d384b4794205ac914abfafa71mtklein    if (!FLAGS_png.isEmpty()) {
194d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkBitmap bitmap;
195d6043b20b63f895d384b4794205ac914abfafa71mtklein        bitmap.allocN32Pixels(1000, 1000);
196d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkCanvas canvas(bitmap);
197d6043b20b63f895d384b4794205ac914abfafa71mtklein        canvas.clear(0xFFFFFFFF);
198d6043b20b63f895d384b4794205ac914abfafa71mtklein
199d6043b20b63f895d384b4794205ac914abfafa71mtklein        server(FLAGS_data[0], FLAGS_control[0], &canvas);
200d6043b20b63f895d384b4794205ac914abfafa71mtklein        canvas.flush();
201d6043b20b63f895d384b4794205ac914abfafa71mtklein
202d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkImageEncoder::EncodeFile(FLAGS_png[0], bitmap, SkImageEncoder::kPNG_Type, 100);
203d6043b20b63f895d384b4794205ac914abfafa71mtklein        SkDebugf("Wrote %s.\n", FLAGS_png[0]);
204d6043b20b63f895d384b4794205ac914abfafa71mtklein    }
205d6043b20b63f895d384b4794205ac914abfafa71mtklein
206d6043b20b63f895d384b4794205ac914abfafa71mtklein    return 0;
207d6043b20b63f895d384b4794205ac914abfafa71mtklein}
208