1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2013-2019 Calle Laakkonen
5 
6    Drawpile is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Drawpile is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Drawpile.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef DP_NET_LAYER_H
20 #define DP_NET_LAYER_H
21 
22 #include <cstdint>
23 #include <QString>
24 #include <QList>
25 
26 #include "message.h"
27 
28 namespace protocol {
29 
30 /**
31  * \brief Canvas size adjustment command
32  *
33  * This is the first command that must be sent to initialize the session.
34  *
35  * This affects the size of all existing and future layers.
36  *
37  * The new canvas size is relative to the old one. The four adjustement
38  * parameters extend or rectract their respective borders.
39  * Initial canvas resize should be (0, w, h, 0).
40  */
41 class CanvasResize : public Message {
42 public:
CanvasResize(uint8_t ctx,int32_t top,int32_t right,int32_t bottom,int32_t left)43 	CanvasResize(uint8_t ctx, int32_t top, int32_t right, int32_t bottom, int32_t left)
44 		: Message(MSG_CANVAS_RESIZE, ctx), m_top(top), m_right(right), m_bottom(bottom), m_left(left)
45 		{}
46 
47 	static CanvasResize *deserialize(uint8_t ctx, const uchar *data, uint len);
48 	static CanvasResize *fromText(uint8_t ctx, const Kwargs &kwargs);
49 
top()50 	int32_t top() const { return m_top; }
right()51 	int32_t right() const { return m_right; }
bottom()52 	int32_t bottom() const { return m_bottom; }
left()53 	int32_t left() const { return m_left; }
54 
messageName()55 	QString messageName() const override { return QStringLiteral("resize"); }
56 
57 protected:
58 	int payloadLength() const override;
59 	int serializePayload(uchar *data) const override;
60 	Kwargs kwargs() const override;
61 
62 private:
63 	int32_t m_top;
64 	int32_t m_right;
65 	int32_t m_bottom;
66 	int32_t m_left;
67 };
68 
69 /**
70  * \brief Layer creation command.
71  *
72  * A session starts with zero layers, so a layer creation command is typically
73  * the second command to be sent, right after setting the canvas size.
74  *
75  * The layer ID must be prefixed with the context ID of the user creating it.
76  * This allows users to choose the layer ID themselves without worrying about
77  * clashes. In single user mode, the client can assign IDs as it pleases,
78  * but in multiuser mode the server validates the prefix for all new layers.
79  *
80  * The following flags can be used with layer creation:
81  * - COPY   -- a copy of the Source layer is made, rather than a blank layer
82  * - INSERT -- the new layer is inserted above the Source layer. Source 0 means
83  *             the layer will be placed bottom-most on the stack
84  *
85  * The Source layer ID should be zero when COPY or INSERT flags are not used.
86  * When COPY is used, it should refer to an existing layer. Copy commands
87  * referring to missing layers are dropped.
88  * When INSERT is used, referring to 0 or a nonexistent layer places
89  * the new layer at the bottom of the stack.
90  *
91  * If layer controls are locked, this command requires session operator privileges.
92  */
93 class LayerCreate : public Message {
94 public:
95 	static const uint8_t FLAG_COPY = 0x01;
96 	static const uint8_t FLAG_INSERT = 0x02;
97 
LayerCreate(uint8_t ctxid,uint16_t id,uint16_t source,uint32_t fill,uint8_t flags,const QString & title)98 	LayerCreate(uint8_t ctxid, uint16_t id, uint16_t source, uint32_t fill, uint8_t flags, const QString &title)
99 		: Message(MSG_LAYER_CREATE, ctxid), m_id(id), m_source(source), m_fill(fill), m_flags(flags), m_title(title.toUtf8())
100 		{}
101 
102 	static LayerCreate *deserialize(uint8_t ctx, const uchar *data, uint len);
103 	static LayerCreate *fromText(uint8_t ctx, const Kwargs &kwargs);
104 
layer()105 	uint16_t layer() const override { return m_id; }
source()106 	uint16_t source() const { return m_source; }
fill()107 	uint32_t fill() const { return m_fill; }
flags()108 	uint8_t flags() const { return m_flags; }
title()109 	QString title() const { return QString::fromUtf8(m_title); }
110 
111 	/**
112 	 * @brief Check if the ID's namespace portition matches the context ID
113 	 *
114 	 * Note. This check is only needed during normal multiuser operation. Layers
115 	 * created in single-user mode can use any ID.
116 	 * This means layer IDs of the initial snapshot need not be validated.
117 	 */
isValidId()118 	bool isValidId() const { return (m_id>>8) == contextId(); }
119 
messageName()120 	QString messageName() const override { return QStringLiteral("newlayer"); }
121 
122 protected:
123 	int payloadLength() const override;
124 	int serializePayload(uchar *data) const override;
125 	Kwargs kwargs() const override;
126 
127 private:
128 	uint16_t m_id;
129 	uint16_t m_source;
130 	uint32_t m_fill;
131 	uint8_t m_flags;
132 	QByteArray m_title;
133 };
134 
135 /**
136  * @brief Layer attribute change command
137  *
138  * If the current layer or layer controls in general are locked, this command
139  * requires session operator privileges.
140  *
141  * Specifying a sublayer requires session operator privileges. Currently, it is used
142  * only when sublayers are needed at canvas initialization.
143  */
144 class LayerAttributes : public Message {
145 public:
146 	static const uint8_t FLAG_CENSOR = 0x01; // censored layer
147 	static const uint8_t FLAG_FIXED  = 0x02; // fixed background/foreground layer (drawn even in solo modo)
148 
LayerAttributes(uint8_t ctx,uint16_t id,uint8_t sublayer,uint8_t flags,uint8_t opacity,uint8_t blend)149 	LayerAttributes(uint8_t ctx, uint16_t id, uint8_t sublayer, uint8_t flags, uint8_t opacity, uint8_t blend)
150 		: Message(MSG_LAYER_ATTR, ctx), m_id(id),
151 		m_sublayer(sublayer), m_flags(flags), m_opacity(opacity), m_blend(blend)
152 		{}
153 
154 	static LayerAttributes *deserialize(uint8_t ctx, const uchar *data, uint len);
155 	static LayerAttributes *fromText(uint8_t ctx, const Kwargs &kwargs);
156 
layer()157 	uint16_t layer() const override { return m_id; }
sublayer()158 	uint8_t sublayer() const { return m_sublayer; }
flags()159 	uint8_t flags() const { return m_flags; }
opacity()160 	uint8_t opacity() const { return m_opacity; }
blend()161 	uint8_t blend() const { return m_blend; }
162 
isCensored()163 	bool isCensored() const { return m_flags & FLAG_CENSOR; }
isFixed()164 	bool isFixed() const { return m_flags & FLAG_FIXED; }
165 
messageName()166 	QString messageName() const override { return QStringLiteral("layerattr"); }
167 
168 protected:
169 	int payloadLength() const override;
170 	int serializePayload(uchar *data) const override;
171 	Kwargs kwargs() const override;
172 
173 private:
174 	uint16_t m_id;
175 	uint8_t m_sublayer;
176 	uint8_t m_flags;
177 	uint8_t m_opacity;
178 	uint8_t m_blend;
179 };
180 
181 /**
182  * @brief Layer visibility (visible/hidden) change command
183  *
184  * This command is used to toggle the layer visibility for the local user.
185  * (I.e. any user is allowed to send this command and it has no effect on
186  * other users.)
187  * Even though this only affects the sending user, this message can be
188  * sent through the official session history to keep the architecture simple.
189  *
190  * Note: to hide the layer for all users, use LayerAttributes to set its opacity
191  * to zero.
192  */
193 class LayerVisibility : public Message {
194 public:
LayerVisibility(uint8_t ctx,uint16_t id,uint8_t visible)195 	LayerVisibility(uint8_t ctx, uint16_t id, uint8_t visible)
196 		: Message(MSG_LAYER_VISIBILITY, ctx), m_id(id), m_visible(visible)
197 	{ }
198 
199 	static LayerVisibility *deserialize(uint8_t ctx, const uchar *data, uint len);
200 	static LayerVisibility *fromText(uint8_t ctx, const Kwargs &kwargs);
201 
layer()202 	uint16_t layer() const override { return m_id; }
visible()203 	uint8_t visible() const { return m_visible; }
204 
messageName()205 	QString messageName() const override { return QStringLiteral("layervisibility"); }
206 
207 protected:
208 	int payloadLength() const override;
209 	int serializePayload(uchar *data) const override;
210 	Kwargs kwargs() const override;
211 
212 private:
213 	uint16_t m_id;
214 	uint8_t m_visible;
215 };
216 
217 /**
218  * @brief Layer title change command
219  *
220  * If the current layer or layer controls in general are locked, this command
221  * requires session operator privileges.
222  */
223 class LayerRetitle : public Message {
224 public:
LayerRetitle(uint8_t ctx,uint16_t id,const QByteArray & title)225 	LayerRetitle(uint8_t ctx, uint16_t id, const QByteArray &title)
226 		: Message(MSG_LAYER_RETITLE, ctx), m_id(id), m_title(title)
227 		{}
LayerRetitle(uint8_t ctx,uint16_t id,const QString & title)228 	LayerRetitle(uint8_t ctx, uint16_t id, const QString &title)
229 		: LayerRetitle(ctx, id, title.toUtf8())
230 		{}
231 
232 	static LayerRetitle *deserialize(uint8_t ctx, const uchar *data, uint len);
233 	static LayerRetitle *fromText(uint8_t ctx, const Kwargs &kwargs);
234 
layer()235 	uint16_t layer() const override { return m_id; }
title()236 	QString title() const { return QString::fromUtf8(m_title); }
237 
messageName()238 	QString messageName() const override { return QStringLiteral("retitlelayer"); }
239 
240 protected:
241 	int payloadLength() const override;
242 	int serializePayload(uchar *data) const override;
243 	Kwargs kwargs() const override;
244 
245 private:
246 	uint16_t m_id;
247 	QByteArray m_title;
248 };
249 
250 /**
251  * @brief Layer order change command
252  *
253  * New layers are always added to the top of the stack.
254  * This command includes a list of layer IDs that define the new stacking order.
255  *
256  * An order change should list all layers in the stack, but due to synchronization issues, that
257  * is not always possible.
258  * The layer order should therefore be sanitized by removing all layers not in the current layer stack
259  * and adding all missing layers to the end in their current relative order.
260  *
261  * For example: if the current stack is [1,2,3,4,5] and the client receives
262  * a reordering command [3,4,1], the missing layers are appended: [3,4,1,2,5].
263  *
264  * If layer controls are locked, this command requires session operator privileges.
265  */
266 class LayerOrder : public Message {
267 public:
LayerOrder(uint8_t ctx,const QList<uint16_t> & order)268 	LayerOrder(uint8_t ctx, const QList<uint16_t> &order)
269 		: Message(MSG_LAYER_ORDER, ctx),
270 		m_order(order)
271 		{}
272 
273 	static LayerOrder *deserialize(uint8_t ctx, const uchar *data, uint len);
274 	static LayerOrder *fromText(uint8_t ctx, const Kwargs &kwargs);
275 
order()276 	const QList<uint16_t> &order() const { return m_order; }
277 
278 	/**
279 	 * @brief Get sanitized layer order
280 	 *
281 	 * This function checks that the new ordering is valid in respect to the current order
282 	 * and returns a sanitized ordering.
283 	 *
284 	 * The following corrections are made:
285 	 * - duplicate IDs are removed
286 	 * - IDs not in the current order are removed
287 	 * - missing IDs are appended to the new order
288 	 *
289 	 * @param currentOrder the current ordering
290 	 * @return cleaned up ordering
291 	 */
292 	QList<uint16_t> sanitizedOrder(const QList<uint16_t> &currentOrder) const;
293 
messageName()294 	QString messageName() const override { return QStringLiteral("layerorder"); }
295 protected:
296 	int payloadLength() const override;
297 	int serializePayload(uchar *data) const override;
298 	Kwargs kwargs() const override;
299 
300 private:
301 	QList<uint16_t> m_order;
302 };
303 
304 /**
305  * @brief Layer deletion command
306  *
307  * If the merge attribute is set, the contents of the layer is merged
308  * to the layer below it. Merging the bottom-most layer does nothing.
309  *
310  * If the current layer or layer controls in general are locked, this command
311  * requires session operator privileges.
312  */
313 class LayerDelete : public Message {
314 public:
LayerDelete(uint8_t ctx,uint16_t id,uint8_t merge)315 	LayerDelete(uint8_t ctx, uint16_t id, uint8_t merge)
316 		: Message(MSG_LAYER_DELETE, ctx),
317 		m_id(id),
318 		m_merge(merge)
319 		{}
320 
321 	static LayerDelete *deserialize(uint8_t ctx, const uchar *data, uint len);
322 	static LayerDelete *fromText(uint8_t ctx, const Kwargs &kwargs);
323 
layer()324 	uint16_t layer() const override { return m_id; }
merge()325 	uint8_t merge() const { return m_merge; }
326 
messageName()327 	QString messageName() const override { return QStringLiteral("deletelayer"); }
328 
329 protected:
330 	int payloadLength() const override;
331 	int serializePayload(uchar *data) const override;
332 	Kwargs kwargs() const override;
333 
334 private:
335 	uint16_t m_id;
336 	uint8_t m_merge;
337 };
338 
339 }
340 
341 #endif
342 
343