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> ¤tOrder) 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