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 
20 #include "statetracker.h"
21 #include "canvasmodel.h"
22 #include "layerlist.h"
23 #include "loader.h"
24 
25 #include "core/layerstack.h"
26 #include "core/layer.h"
27 #include "brushes/brushpainter.h"
28 #include "net/commands.h"
29 #include "net/internalmsg.h"
30 #include "tools/selection.h" // for selection transform utils
31 
32 #include "../libshared/net/brushes.h"
33 #include "../libshared/net/layer.h"
34 #include "../libshared/net/image.h"
35 #include "../libshared/net/annotation.h"
36 #include "../libshared/net/undo.h"
37 
38 #include <QDebug>
39 #include <QDateTime>
40 #include <QTimer>
41 #include <QElapsedTimer>
42 #include <QSettings>
43 #include <QPainter>
44 
45 namespace canvas {
46 
47 struct StateSavepoint::Data : public QSharedData {
48 	int streampointer = 0;
49 	qint64 timestamp = 0;
50 	paintcore::Savepoint canvas;
51 	QVector<LayerListItem> layermodel;
52 };
53 
StateSavepoint()54 StateSavepoint::StateSavepoint()
55 {
56 }
57 
StateSavepoint(Data * d)58 StateSavepoint::StateSavepoint(Data *d)
59 	: d(d)
60 {
61 }
62 
StateSavepoint(const StateSavepoint & other)63 StateSavepoint::StateSavepoint(const StateSavepoint &other)
64 	: d(other.d)
65 {
66 }
67 
operator =(const StateSavepoint & other)68 StateSavepoint &StateSavepoint::operator=(const StateSavepoint &other)
69 {
70 	d = other.d;
71 	return *this;
72 }
73 
~StateSavepoint()74 StateSavepoint::~StateSavepoint()
75 {
76 }
77 
timestamp() const78 qint64 StateSavepoint::timestamp() const
79 {
80 	return d ? d->timestamp : 0;
81 }
82 
canvas() const83 paintcore::Savepoint StateSavepoint::canvas() const
84 {
85 	Q_ASSERT(d);
86 	return d->canvas;
87 }
88 
thumbnail(const QSize & maxSize) const89 QImage StateSavepoint::thumbnail(const QSize &maxSize) const
90 {
91 	if(!d)
92 		return QImage();
93 
94 	paintcore::LayerStack stack;
95 	stack.editor(0).restoreSavepoint(d->canvas);
96 	QImage img = stack.toFlatImage(true, true, false);
97 	if(img.width() > maxSize.width() || img.height() > maxSize.height()) {
98 		img = img.scaled(maxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
99 	}
100 	return img;
101 }
102 
initCommands(uint8_t contextId,const CanvasModel * canvas) const103 protocol::MessageList StateSavepoint::initCommands(uint8_t contextId, const CanvasModel *canvas) const
104 {
105 	if(!d)
106 		return protocol::MessageList();
107 
108 	paintcore::LayerStack stack;
109 	stack.editor(0).restoreSavepoint(d->canvas);
110 	SnapshotLoader loader(contextId, &stack, canvas->aclFilter());
111 	loader.setDefaultLayer(canvas->layerlist()->defaultLayer());
112 	loader.setPinnedMessage(canvas->pinnedMessage());
113 	return loader.loadInitCommands();
114 }
115 
fromCanvasSavepoint(const paintcore::Savepoint & savepoint)116 StateSavepoint StateSavepoint::fromCanvasSavepoint(const paintcore::Savepoint &savepoint)
117 {
118 	auto *d = new StateSavepoint::Data;
119 
120 	d->timestamp = QDateTime::currentMSecsSinceEpoch();
121 	d->canvas = savepoint;
122 
123 	for(const paintcore::Layer *l : savepoint.layers) {
124 		d->layermodel << LayerListItem {
125 			uint16_t(l->id()),
126 			l->title(),
127 			l->opacity() / 255.0f,
128 			l->blendmode(),
129 			l->isHidden(),
130 			l->isCensored(),
131 			l->isFixed()
132 		};
133 	}
134 	return StateSavepoint(d);
135 }
136 
137 /**
138  * @brief Construct a state tracker instance
139  *
140  * @param image the canvas content
141  * @param layerlist layer list model for the UI
142  * @param myId ID of the local user
143  * @param parent
144  */
StateTracker(paintcore::LayerStack * image,LayerListModel * layerlist,uint8_t myId,QObject * parent)145 StateTracker::StateTracker(paintcore::LayerStack *image, LayerListModel *layerlist, uint8_t myId, QObject *parent)
146 	: QObject(parent),
147 		m_layerstack(image),
148 		m_layerlist(layerlist),
149 		m_myId(myId),
150 		m_myLastLayer(-1),
151 		_showallmarkers(false),
152 		m_hasParticipated(false),
153 		m_localPenDown(false),
154 		m_isQueued(false)
155 {
156 	connect(m_layerlist, &LayerListModel::layerOpacityPreview, this, &StateTracker::previewLayerOpacity);
157 
158 	// Reset local fork if it falls behind too much
159 	m_localfork.setFallbehind(10000);
160 
161 	// Timer for processing drawing commands in short chunks to avoid entirely locking up the UI.
162 	// In the future, canvas rendering should be done in a separate thread.
163 	m_queuetimer = new QTimer(this);
164 	m_queuetimer->setSingleShot(true);
165 	connect(m_queuetimer, &QTimer::timeout, this, &StateTracker::processQueuedCommands);
166 
167 	// Ensure that there is always at least one save point
168 	makeSavepoint(-1);
169 }
170 
~StateTracker()171 StateTracker::~StateTracker()
172 {
173 }
174 
reset()175 void StateTracker::reset()
176 {
177 	m_savepoints.clear();
178 	m_history.resetTo(m_history.end());
179 	m_hasParticipated = false;
180 	m_localPenDown = false;
181 	m_msgqueue.clear();
182 	m_localfork.clear();
183 	m_layerlist->clear();
184 
185 	// Make sure there is always a savepoint in the history
186 	makeSavepoint(m_history.end()-1);
187 }
188 
localCommand(protocol::MessagePtr msg)189 void StateTracker::localCommand(protocol::MessagePtr msg)
190 {
191 	// A fork is created at the end of the mainline history
192 	if(m_localfork.isEmpty()) {
193 		m_localfork.setOffset(m_history.end()-1);
194 
195 		// Since the presence of a local fork blocks savepoint creation,
196 		// now is a good time to try to create one.
197 		if(msg->type() == protocol::MSG_UNDOPOINT)
198 			makeSavepoint(m_history.end()-1);
199 	}
200 
201 	m_localfork.addLocalMessage(msg, affectedArea(msg));
202 
203 	// Remember last used layer
204 	switch(msg->type()) {
205 	using namespace protocol;
206 	case MSG_DRAWDABS_CLASSIC:
207 	case MSG_DRAWDABS_PIXEL:
208 	case MSG_DRAWDABS_PIXEL_SQUARE:
209 	case MSG_LAYER_CREATE:
210 	case MSG_PUTIMAGE:
211 	case MSG_FILLRECT:
212 	case MSG_REGION_MOVE:
213 		m_myLastLayer = msg->layer();
214 		break;
215 	default: break;
216 	}
217 
218 	// for the future: handle undo messages in the local fork too
219 	if(msg->type() != protocol::MSG_UNDO && msg->type() != protocol::MSG_UNDOPOINT) {
220 		int pos = m_history.end() - 1;
221 		handleCommand(msg, false, pos);
222 	}
223 }
224 
receiveQueuedCommand(protocol::MessagePtr msg)225 void StateTracker::receiveQueuedCommand(protocol::MessagePtr msg)
226 {
227 	m_msgqueue.append(msg);
228 
229 	if(!m_isQueued) {
230 		// This introduces a tiny bit of lag, but allows sequential
231 		// messages to queue up even when the system is not under very heavy
232 		// load. Won't be needed anymore when the paint engine runs in its own
233 		// thread.
234 		m_isQueued = true;
235 		m_queuetimer->start(1);
236 	}
237 }
238 
processQueuedCommands()239 void StateTracker::processQueuedCommands()
240 {
241 	QElapsedTimer elapsed;
242 	elapsed.start();
243 
244 	while(!m_msgqueue.isEmpty() && elapsed.elapsed() < 100) {
245 		receiveCommand(m_msgqueue.takeFirst());
246 	}
247 
248 	if(!m_msgqueue.isEmpty()) {
249 		qDebug("Taking a breather. Still %d messages in the queue.", m_msgqueue.size());
250 		m_isQueued = true;
251 		m_queuetimer->start(20);
252 	} else {
253 		m_isQueued = false;
254 	}
255 }
256 
receiveCommand(protocol::MessagePtr msg)257 void StateTracker::receiveCommand(protocol::MessagePtr msg)
258 {
259 	if(msg->type() == protocol::MSG_INTERNAL) {
260 		// MSG_INTERNAL is a pseudo-message used for internal synchronization
261 		const auto &ci = msg.cast<protocol::ClientInternal>();
262 		switch(ci.internalType()) {
263 		case protocol::ClientInternal::Type::Catchup:
264 			emit catchupProgress(ci.value());
265 			break;
266 		case protocol::ClientInternal::Type::SequencePoint:
267 			emit sequencePoint(ci.value());
268 			break;
269 		case protocol::ClientInternal::Type::TruncateHistory:
270 			handleTruncateHistory();
271 			break;
272 		case protocol::ClientInternal::Type::SoftResetPoint:
273 			emit softResetPoint();
274 			break;
275 		}
276 		return;
277 	}
278 
279 	// Add command to history and execute it
280 	m_history.append(msg);
281 
282 	LocalFork::MessageAction lfa = m_localfork.handleReceivedMessage(msg, affectedArea(msg));
283 
284 	// Undo messages are not handled locally (at the moment)
285 	if(lfa == LocalFork::ALREADYDONE && (msg->type()==protocol::MSG_UNDO || msg->type()==protocol::MSG_UNDOPOINT))
286 		lfa = LocalFork::CONCURRENT;
287 
288 	if(lfa==LocalFork::ROLLBACK) {
289 		// Uh oh! An inconsistency was detected: roll back the history and replay
290 
291 		// first, find the newest savepoint that precedes the fork
292 		int savepoint = m_savepoints.size()-1;
293 		while(savepoint>=0) {
294 			if(m_savepoints.at(savepoint)->streampointer <= m_localfork.offset())
295 				break;
296 			--savepoint;
297 		}
298 
299 		if(savepoint<0) {
300 			// should never happen
301 			qWarning("No savepoint for rolling back local fork at %d!", m_localfork.offset());
302 
303 		} else {
304 			const StateSavepoint &sp = m_savepoints.at(savepoint);
305 			qDebug("inconsistency at %d (local fork at %d). Rolling back to %d", m_history.end(), m_localfork.offset(), sp->streampointer);
306 
307 			// Avoid rollback churn by clearing the local fork, but not if
308 			// local drawing is in progress. If we clear the fork then,
309 			// we trigger a self-conflict feedback loop until the stroke finishes.
310 			if(!m_localPenDown)
311 				m_localfork.clear();
312 
313 			revertSavepointAndReplay(sp);
314 		}
315 
316 	} else if(lfa==LocalFork::CONCURRENT) {
317 		// Concurrent operation: safe to execute
318 		int pos = m_history.end() - 1;
319 		handleCommand(msg, false, pos);
320 	} // else ALREADYDONE
321 }
322 
handleCommand(protocol::MessagePtr msg,bool replay,int pos)323 void StateTracker::handleCommand(protocol::MessagePtr msg, bool replay, int pos)
324 {
325 	switch(msg->type()) {
326 		using namespace protocol;
327 		case MSG_CANVAS_RESIZE:
328 			handleCanvasResize(msg.cast<CanvasResize>(), pos);
329 			break;
330 		case MSG_LAYER_CREATE:
331 			handleLayerCreate(msg.cast<LayerCreate>());
332 			break;
333 		case MSG_LAYER_ATTR:
334 			handleLayerAttributes(msg.cast<LayerAttributes>());
335 			break;
336 		case MSG_LAYER_VISIBILITY:
337 			handleLayerVisibility(msg.cast<LayerVisibility>());
338 			break;
339 		case MSG_LAYER_RETITLE:
340 			handleLayerTitle(msg.cast<LayerRetitle>());
341 			break;
342 		case MSG_LAYER_ORDER:
343 			handleLayerOrder(msg.cast<LayerOrder>());
344 			break;
345 		case MSG_LAYER_DELETE:
346 			handleLayerDelete(msg.cast<LayerDelete>());
347 			break;
348 		case MSG_DRAWDABS_CLASSIC:
349 		case MSG_DRAWDABS_PIXEL:
350 		case MSG_DRAWDABS_PIXEL_SQUARE:
351 			handleDrawDabs(*msg);
352 			break;
353 		case MSG_PEN_UP:
354 			handlePenUp(msg.cast<PenUp>());
355 			break;
356 		case MSG_PUTIMAGE:
357 			handlePutImage(msg.cast<PutImage>());
358 			break;
359 		case MSG_UNDOPOINT:
360 			handleUndoPoint(msg.cast<UndoPoint>(), replay, pos);
361 			break;
362 		case MSG_UNDO:
363 			handleUndo(msg.cast<Undo>());
364 			break;
365 		case MSG_ANNOTATION_CREATE:
366 			handleAnnotationCreate(msg.cast<AnnotationCreate>());
367 			break;
368 		case MSG_ANNOTATION_RESHAPE:
369 			handleAnnotationReshape(msg.cast<AnnotationReshape>());
370 			break;
371 		case MSG_ANNOTATION_EDIT:
372 			handleAnnotationEdit(msg.cast<AnnotationEdit>());
373 			break;
374 		case MSG_ANNOTATION_DELETE:
375 			handleAnnotationDelete(msg.cast<AnnotationDelete>());
376 			break;
377 		case MSG_FILLRECT:
378 			handleFillRect(msg.cast<FillRect>());
379 			break;
380 		case MSG_REGION_MOVE:
381 			handleMoveRegion(msg.cast<MoveRegion>());
382 			break;
383 		case MSG_PUTTILE:
384 			handlePutTile(msg.cast<PutTile>());
385 			break;
386 		case MSG_CANVAS_BACKGROUND:
387 			handleCanvasBackground(msg.cast<CanvasBackground>());
388 			break;
389 		default:
390 			qWarning() << "Unhandled drawing command" << msg->type() << msg->messageName();
391 			return;
392 	}
393 }
394 
395 /**
396  * @brief Network disconnected, so end remote drawing processes
397  */
endRemoteContexts()398 void StateTracker::endRemoteContexts()
399 {
400 	// Add local fork to the mainline history
401 	auto localfork = m_localfork.messages();
402 	m_localfork.clear();
403 
404 	for(protocol::MessagePtr m : localfork)
405 		m_history.append(m);
406 
407 	// Make sure there are no lingering indirect strokes
408 	// TODO this should probably be done with an InternalMsg,
409 	// in case there is still stuff in the queue
410 	auto layers = m_layerstack->editor(0);
411 	layers.mergeAllSublayers();
412 
413 	m_myLastLayer = -1;
414 }
415 
416 /**
417  * @brief Playback ended, make sure drawing contexts (local one included) are ended
418  */
endPlayback()419 void StateTracker::endPlayback()
420 {
421 	auto layers = m_layerstack->editor(0);
422 	layers.mergeAllSublayers();
423 }
424 
425 
426 
handleCanvasResize(const protocol::CanvasResize & cmd,int pos)427 void StateTracker::handleCanvasResize(const protocol::CanvasResize &cmd, int pos)
428 {
429 	{
430 		auto layers = m_layerstack->editor(cmd.contextId());
431 		layers.resize(cmd.top(), cmd.right(), cmd.bottom(), cmd.left());
432 	}
433 
434 	// Generate the initial savepoint, just in case
435 	makeSavepoint(pos);
436 }
437 
handleCanvasBackground(const protocol::CanvasBackground & cmd)438 void StateTracker::handleCanvasBackground(const protocol::CanvasBackground &cmd)
439 {
440 	paintcore::Tile t;
441 	if(cmd.isSolidColor()) {
442 		t = paintcore::Tile(QColor::fromRgba(cmd.color()));
443 
444 	} else {
445 		QByteArray data = qUncompress(cmd.image());
446 		if(data.length() != paintcore::Tile::BYTES) {
447 			qWarning() << "Invalid canvas background: Expected" << paintcore::Tile::BYTES << "bytes, but got" << data.length();
448 			return;
449 		}
450 
451 		t = paintcore::Tile(data);
452 	}
453 	t.setLastEditedBy(cmd.contextId());
454 	m_layerstack->editor(cmd.contextId()).setBackground(t);
455 }
456 
handleLayerCreate(const protocol::LayerCreate & cmd)457 void StateTracker::handleLayerCreate(const protocol::LayerCreate &cmd)
458 {
459 	auto layers = m_layerstack->editor(cmd.contextId());
460 
461 	auto layer = layers.createLayer(
462 		cmd.layer(),
463 		cmd.source(),
464 		QColor::fromRgba(cmd.fill()),
465 		(cmd.flags() & protocol::LayerCreate::FLAG_INSERT),
466 		(cmd.flags() & protocol::LayerCreate::FLAG_COPY),
467 		cmd.title()
468 	);
469 
470 	if(layer.isNull()) {
471 		qWarning("Layer creation failed (id=%d, source=%d)", cmd.layer(), cmd.source());
472 		return;
473 	}
474 
475 	// Note: layers are listed bottom-first in the stack,
476 	// but topmost first in the view
477 	m_layerlist->createLayer(
478 		cmd.layer(),
479 		layers->layerCount() - layers->indexOf(layer->id()) - 1,
480 		cmd.title()
481 	);
482 
483 	// Auto-select layers we create
484 	// During the startup phase, autoselect new layers or if a default one is set,
485 	// just the default one. If there is a remembered layer selection, it takes precedence
486 	// over others.
487 	if(
488 			// Autoselect layers created by me
489 			(m_hasParticipated && cmd.contextId() == localId()) ||
490 			// If this user has not yet drawn anything...
491 			(!m_hasParticipated && (
492 				// ... and if there is no remembered layer...
493 				((m_myLastLayer <= 0) && ( // ...select default layer or if not selected, any new layer
494 					layer->id() == m_layerlist->defaultLayer() ||
495 					!m_layerlist->defaultLayer()
496 				)) ||
497 				// ... and if there is a remembered layer, select only that one
498 				(m_myLastLayer>0 && layer->id() == m_myLastLayer)
499 			))
500 	   )
501 	{
502 		emit layerAutoselectRequest(layer->id());
503 	}
504 }
505 
handleLayerAttributes(const protocol::LayerAttributes & cmd)506 void StateTracker::handleLayerAttributes(const protocol::LayerAttributes &cmd)
507 {
508 	auto layers = m_layerstack->editor(cmd.contextId());
509 	auto layer = layers.getEditableLayer(cmd.layer());
510 	if(layer.isNull()) {
511 		qWarning("Received layer attributes for non-existent layer #%d", cmd.layer());
512 		return;
513 	}
514 
515 	const auto bm = paintcore::BlendMode::Mode(cmd.blend());
516 
517 	if(cmd.sublayer()>0) {
518 		auto sl = layer.getEditableSubLayer(cmd.sublayer(), bm, cmd.opacity());
519 		// getSubLayer does not touch the attributes if the sublayer already exists
520 		sl.setBlend(bm);
521 		sl.setOpacity(cmd.opacity());
522 
523 	} else {
524 		layer.setBlend(bm);
525 		layer.setOpacity(cmd.opacity());
526 		layer.setCensored(cmd.isCensored());
527 		layer.setFixed(cmd.isFixed());
528 		m_layerlist->changeLayer(layer->id(), cmd.isCensored(), cmd.isFixed(), cmd.opacity() / 255.0, paintcore::BlendMode::Mode(cmd.blend()));
529 	}
530 }
531 
handleLayerVisibility(const protocol::LayerVisibility & cmd)532 void StateTracker::handleLayerVisibility(const protocol::LayerVisibility &cmd)
533 {
534 	// Layer visibility affects the sending user only
535 	// (to hide a layer from all users, one can just set its opacity to zero.)
536 	if(cmd.contextId() != localId())
537 		return;
538 
539 	auto layers = m_layerstack->editor(cmd.contextId());
540 	auto layer = layers.getEditableLayer(cmd.layer());
541 	if(layer.isNull()) {
542 		qWarning("Received layer visibility for non-existent layer #%d", cmd.layer());
543 		return;
544 	}
545 
546 	layer.setHidden(!cmd.visible());
547 	m_layerlist->setLayerHidden(layer->id(), !cmd.visible());
548 }
549 
previewLayerOpacity(int id,float opacity)550 void StateTracker::previewLayerOpacity(int id, float opacity)
551 {
552 	auto layers = m_layerstack->editor(0);
553 	auto layer = layers.getEditableLayer(id);
554 
555 	if(layer.isNull()) {
556 		qWarning("previewLayerOpacity(%d): no such layer!", id);
557 		return;
558 	}
559 	layer.setOpacity(opacity*255);
560 }
561 
handleLayerTitle(const protocol::LayerRetitle & cmd)562 void StateTracker::handleLayerTitle(const protocol::LayerRetitle &cmd)
563 {
564 	auto layers = m_layerstack->editor(cmd.contextId());
565 	auto layer = layers.getEditableLayer(cmd.layer());
566 
567 	if(layer.isNull()) {
568 		qWarning() << "received layer title for non-existent layer" << cmd.layer();
569 		return;
570 	}
571 
572 	layer.setTitle(cmd.title());
573 	m_layerlist->retitleLayer(layer->id(), cmd.title());
574 }
575 
handleLayerOrder(const protocol::LayerOrder & cmd)576 void StateTracker::handleLayerOrder(const protocol::LayerOrder &cmd)
577 {
578 	auto layers = m_layerstack->editor(cmd.contextId());
579 
580 	QList<uint16_t> currentOrder;
581 	for(int i=0;i<layers->layerCount();++i)
582 		currentOrder.append(layers->getLayerByIndex(i)->id());
583 
584 	QList<uint16_t> newOrder = cmd.sanitizedOrder(currentOrder);
585 
586 	if(newOrder != cmd.order()) {
587 		qWarning() << "invalid layer reorder!";
588 		qWarning() << "current order is:" << currentOrder;
589 		qWarning() << "  the new one was:" << cmd.order();
590 		qWarning() << "  fixed order is:" << newOrder;
591 	}
592 
593 	layers.reorderLayers(newOrder);
594 	m_layerlist->reorderLayers(newOrder);
595 }
596 
handleLayerDelete(const protocol::LayerDelete & cmd)597 void StateTracker::handleLayerDelete(const protocol::LayerDelete &cmd)
598 {
599 	auto layers = m_layerstack->editor(cmd.contextId());
600 
601 	if(cmd.merge())
602 		layers.mergeLayerDown(cmd.layer());
603 	layers.deleteLayer(cmd.layer());
604 	m_layerlist->deleteLayer(cmd.layer());
605 }
606 
handleDrawDabs(const protocol::Message & cmd)607 void StateTracker::handleDrawDabs(const protocol::Message &cmd)
608 {
609 	auto layers = m_layerstack->editor(cmd.contextId());
610 
611 	brushes::drawBrushDabs(cmd, layers);
612 
613 	if(_showallmarkers || cmd.contextId() != localId())
614 		emit userMarkerMove(cmd.contextId(), cmd.layer(), static_cast<const protocol::DrawDabs&>(cmd).lastPoint());
615 }
616 
handlePenUp(const protocol::PenUp & cmd)617 void StateTracker::handlePenUp(const protocol::PenUp &cmd)
618 {
619 	// This ends an indirect stroke. In incremental mode, this does nothing.
620 	 m_layerstack->editor(cmd.contextId()).mergeSublayers(cmd.contextId());
621 	emit userMarkerHide(cmd.contextId());
622 }
623 
handlePutImage(const protocol::PutImage & cmd)624 void StateTracker::handlePutImage(const protocol::PutImage &cmd)
625 {
626 	auto layers = m_layerstack->editor(cmd.contextId());
627 	auto layer = layers.getEditableLayer(cmd.layer());
628 	if(layer.isNull()) {
629 		qWarning("PutImage on non-existent layer #%d", cmd.layer());
630 		return;
631 	}
632 
633 	const int expectedLen = cmd.width() * cmd.height() * 4;
634 	QByteArray data = qUncompress(cmd.image());
635 	if(data.length() != expectedLen) {
636 		qWarning() << "Invalid putImage: Expected" << expectedLen << "bytes, but got" << data.length();
637 		return;
638 	}
639 	QImage img(reinterpret_cast<const uchar*>(data.constData()), cmd.width(), cmd.height(), QImage::Format_ARGB32_Premultiplied);
640 	layer.putImage(cmd.x(), cmd.y(), img, paintcore::BlendMode::Mode(cmd.blendmode()));
641 
642 	if(_showallmarkers || cmd.contextId() != m_myId)
643 		emit userMarkerMove(cmd.contextId(), layer->id(), QPoint(cmd.x() + cmd.width()/2, cmd.y()+cmd.height()/2));
644 }
645 
handlePutTile(const protocol::PutTile & cmd)646 void StateTracker::handlePutTile(const protocol::PutTile &cmd)
647 {
648 	auto layers = m_layerstack->editor(cmd.contextId());
649 	auto layer = layers.getEditableLayer(cmd.layer());
650 	if(layer.isNull()) {
651 		qWarning("PutTile on non-existent layer #%d", cmd.layer());
652 		return;
653 	}
654 
655 	paintcore::Tile t;
656 	if(cmd.isSolidColor()) {
657 		t = paintcore::Tile(QColor::fromRgba(cmd.color()), cmd.contextId());
658 
659 	} else {
660 		QByteArray data = qUncompress(cmd.image());
661 		if(data.length() != paintcore::Tile::BYTES) {
662 			qWarning() << "Invalid putTile: Expected" << paintcore::Tile::BYTES << "bytes, but got" << data.length();
663 			return;
664 		}
665 
666 		t = paintcore::Tile(data, cmd.contextId());
667 	}
668 
669 	layer.putTile(cmd.column(), cmd.row(), cmd.repeat(), t, cmd.sublayer());
670 }
671 
handleFillRect(const protocol::FillRect & cmd)672 void StateTracker::handleFillRect(const protocol::FillRect &cmd)
673 {
674 	auto layers = m_layerstack->editor(cmd.contextId());
675 	auto layer = layers.getEditableLayer(cmd.layer());
676 	if(layer.isNull()) {
677 		qWarning("FillRect on non-existent layer #%d", cmd.layer());
678 		return;
679 	}
680 
681 	layer.fillRect(QRect(cmd.x(), cmd.y(), cmd.width(), cmd.height()), QColor::fromRgba(cmd.color()), paintcore::BlendMode::Mode(cmd.blend()));
682 
683 	if(_showallmarkers || cmd.contextId() != m_myId)
684 		emit userMarkerMove(cmd.contextId(), layer->id(), QPoint(cmd.x() + cmd.width()/2, cmd.y()+cmd.height()/2));
685 }
686 
handleMoveRegion(const protocol::MoveRegion & cmd)687 void StateTracker::handleMoveRegion(const protocol::MoveRegion &cmd)
688 {
689 	auto layers = m_layerstack->editor(cmd.contextId());
690 	auto layer = layers.getEditableLayer(cmd.layer());
691 	if(layer.isNull()) {
692 		qWarning("MoveRegion on non-existent layer #%d", cmd.layer());
693 		return;
694 	}
695 
696 	if(cmd.contextId() == m_myId) {
697 		// Moving the layer for real: make sure my preview is removed
698 		layer.removeSublayer(-1);
699 	}
700 
701 	// Source region bounding rectangle
702 	const QRect bounds(cmd.bx(), cmd.by(), cmd.bw(), cmd.bh());
703 
704 	// Target quad
705 	const QPolygon target({
706 		QPoint(cmd.x1(), cmd.y1()),
707 		QPoint(cmd.x2(), cmd.y2()),
708 		QPoint(cmd.x3(), cmd.y3()),
709 		QPoint(cmd.x4(), cmd.y4())
710 	});
711 
712 	// Sanity check: without a size limit, a user could create huge temporary images and potentially other clients
713 	const auto targetSize = target.boundingRect().size();
714 	const int targetArea = targetSize.width() * targetSize.height();
715 	if(targetArea > (m_layerstack->width()+1) * (m_layerstack->height()+1)) {
716 		qWarning("moveRegion: cannot scale beyond image size");
717 		return;
718 	}
719 
720 	// Get mask bitmap
721 	QImage mask;
722 	if(!cmd.mask().isEmpty()) {
723 		const int expectedLen = (cmd.bw()+31)/32 * 4 * cmd.bh(); // 1bpp lines padded to 32bit boundaries
724 		QByteArray maskData = qUncompress(cmd.mask());
725 		if(maskData.length() != expectedLen) {
726 			qWarning("Invalid moveRegion mask: Expected %d bytes, but got %d", expectedLen, maskData.length());
727 			return;
728 		}
729 
730 		mask = QImage(reinterpret_cast<const uchar*>(maskData.constData()), cmd.bw(), cmd.bh(), QImage::Format_Mono);
731 		mask.setColor(0, 0);
732 		mask.setColor(1, 0xffffffff);
733 		mask = mask.convertToFormat(QImage::Format_ARGB32_Premultiplied);
734 	}
735 
736 	// Extract selected pixels
737 	QImage selbuf = layer->toImage().copy(bounds); // TODO optimize
738 
739 	// Mask out unselected pixels (if necessary)
740 	if(!mask.isNull()) {
741 		QPainter mp(&selbuf);
742 		mp.setCompositionMode(QPainter::CompositionMode_DestinationIn);
743 		mp.drawImage(0, 0, mask);
744 	}
745 
746 	// Transform selected pixels
747 
748 	QPoint offset;
749 	QImage transformed;
750 	if(target.boundingRect().size() == bounds.size() && target[0].x() < target[1].x()) {
751 		// Just translation
752 		transformed = selbuf;
753 		offset = target[0];
754 
755 	} else {
756 		transformed = tools::SelectionTool::transformSelectionImage(selbuf, target, &offset);
757 		if(transformed.isNull()) {
758 			qWarning("moveRegion: transformation failed (%d, %d -> %d, %d -> %d, %d -> %d, %d)!",
759 				cmd.x1(), cmd.y1(), cmd.x2(), cmd.y2(), cmd.x3(), cmd.y3(), cmd.x4(), cmd.y4());
760 			return;
761 		}
762 	}
763 
764 	// Erase selection mask and draw transformed image
765 	if(mask.isNull()) {
766 		layer.fillRect(bounds, Qt::transparent, paintcore::BlendMode::MODE_REPLACE);
767 	} else {
768 		layer.putImage(bounds.x(), bounds.y(), mask, paintcore::BlendMode::MODE_ERASE);
769 	}
770 
771 	layer.putImage(offset.x(), offset.y(), transformed, paintcore::BlendMode::MODE_NORMAL);
772 
773 	if(_showallmarkers || cmd.contextId() != m_myId)
774 		emit userMarkerMove(cmd.contextId(), layer->id(), target.boundingRect().center());
775 }
776 
handleUndoPoint(const protocol::UndoPoint & cmd,bool replay,int pos)777 void StateTracker::handleUndoPoint(const protocol::UndoPoint &cmd, bool replay, int pos)
778 {
779 	// New undo point. This branches the undo history. Since we store the
780 	// commands in a linear sequence, this branching is represented by marking
781 	// the unreachable commands as GONE.
782 	if(!replay) {
783 		int i = pos - 1; // skip the one just added
784 		int upCount = 1;
785 
786 		// Mark undone actions as GONE
787 		while(m_history.isValidIndex(i) && upCount < protocol::UNDO_DEPTH_LIMIT) {
788 			protocol::MessagePtr msg = m_history.at(i);
789 			if(msg->type() == protocol::MSG_UNDOPOINT)
790 				++upCount;
791 			if(msg->contextId() == cmd.contextId()) {
792 				// optimization: we can stop searching after finding the first GONE command
793 				if(msg->type() != protocol::MSG_UNDO && msg->undoState() == protocol::GONE)
794 					break;
795 				else if(msg->undoState() == protocol::UNDONE)
796 					msg->setUndoState(protocol::GONE);
797 			}
798 			--i;
799 		}
800 
801 		// Keep rewinding until the oldest reachable undo point is found
802 		while(m_history.isValidIndex(i) && upCount < protocol::UNDO_DEPTH_LIMIT) {
803 			if(m_history.at(i)->type() == protocol::MSG_UNDOPOINT) {
804 				++upCount;
805 			}
806 			--i;
807 		}
808 
809 		// Release all state savepoints older then the oldest UndoPoint
810 		if(upCount>=protocol::UNDO_DEPTH_LIMIT) {
811 			if(!m_localfork.isEmpty())
812 				i = qMin(i, m_localfork.offset() - 1);
813 
814 			QMutableListIterator<StateSavepoint> spi(m_savepoints);
815 			spi.toBack();
816 
817 			// In order to be able to return to the oldest undo point, we must leave
818 			// one snapshot that is as old, or older.
819 			bool first = true;
820 
821 			while(spi.hasPrevious()) {
822 				const StateSavepoint &sp = spi.previous();
823 				if(sp->streampointer <= i) {
824 					if(first)
825 						first = false;
826 					else
827 						spi.remove();
828 				}
829 			}
830 		}
831 	}
832 
833 	// Clear out history older than the oldest savepoint
834 	Q_ASSERT(!m_savepoints.isEmpty());
835 	m_history.cleanup(m_savepoints.first()->streampointer);
836 
837 	// Make a new savepoint (if possible)
838 	makeSavepoint(pos);
839 
840 	// To be correct, we should set the "participated" flag on any command
841 	// sent by us. In practice, however, an UndoPoint is always sent
842 	// when making changes so it is enough to set the flag here.
843 	if(cmd.contextId() == localId())
844 		m_hasParticipated = true;
845 }
846 
handleUndo(protocol::Undo & cmd)847 void StateTracker::handleUndo(protocol::Undo &cmd)
848 {
849 	// Undo/redo commands are never replayed, so start
850 	// by marking it as unavailable.
851 	cmd.setUndoState(protocol::GONE);
852 
853 	const uint8_t ctxid = cmd.overrideId() ? cmd.overrideId() : cmd.contextId();
854 
855 	// Step 1. Find undo or redo point
856 	int pos = m_history.end();
857 	int upCount = 0;
858 
859 	if(cmd.isRedo()) {
860 		// Find the oldest undone UndoPoint
861 		int redostart = pos;
862 		while(m_history.isValidIndex(--pos) && upCount <= protocol::UNDO_DEPTH_LIMIT) {
863 			const protocol::MessagePtr msg = m_history.at(pos);
864 			if(msg->type() == protocol::MSG_UNDOPOINT) {
865 				++upCount;
866 				if(msg->contextId() == ctxid) {
867 					if(msg->undoState() != protocol::DONE)
868 						redostart = pos;
869 					else
870 						break;
871 				}
872 			}
873 		}
874 
875 		if(redostart == m_history.end()) {
876 			qDebug() << "nothing to redo for user" << cmd.contextId();
877 			return;
878 		}
879 		pos = redostart;
880 
881 	} else {
882 		// Find the newest UndoPoint not marked as undone.
883 		while(m_history.isValidIndex(--pos) && upCount <= protocol::UNDO_DEPTH_LIMIT) {
884 			const protocol::MessagePtr msg = m_history.at(pos);
885 			if(msg->type() == protocol::MSG_UNDOPOINT) {
886 				++upCount;
887 				if(msg->contextId() == ctxid && msg->undoState() == protocol::DONE)
888 					break;
889 			}
890 		}
891 	}
892 
893 	if(upCount > protocol::UNDO_DEPTH_LIMIT) {
894 		qDebug() << "user" << cmd.contextId() << "cannot undo/redo beyond history limit";
895 		return;
896 	}
897 
898 	// pos is now at the starting UndoPoint
899 	if(!m_history.isValidIndex(pos)) {
900 		qWarning() << "Cannot " << (cmd.isRedo() ? "redo" : "undo") << "action by user" << ctxid << ": not enough messages in buffer!";
901 		return;
902 	}
903 
904 	// Step 2. Find nearest save point
905 	StateSavepoint savepoint;
906 	for(int i=m_savepoints.count()-1;i>=0;--i) {
907 		if(m_savepoints.at(i)->streampointer <= pos) {
908 			savepoint = m_savepoints.at(i);
909 			break;
910 		}
911 	}
912 
913 	if(!savepoint) {
914 		qWarning() << "Cannot" << (cmd.isRedo() ? "redo" : "undo") << "action by user" << ctxid << ": no savepoint found!";
915 		return;
916 	}
917 
918 	// Step 3. (Un)mark all actions by the user as undone
919 	if(cmd.isRedo()) {
920 		int i=pos;
921 		int sequence=2;
922 		// Un-undo messages until the start of the next undone sequence
923 		while(i<m_history.end()) {
924 			protocol::MessagePtr msg = m_history.at(i);
925 			if(msg->contextId() == ctxid) {
926 				if(msg->type() == protocol::MSG_UNDOPOINT && msg->undoState() != protocol::GONE)
927 					if(--sequence==0)
928 						break;
929 
930 				// GONE messages cannot be redone
931 				if(msg->undoState() == protocol::UNDONE)
932 					msg->setUndoState(protocol::DONE);
933 			}
934 			++i;
935 		}
936 
937 	} else {
938 		// Mark all messages from undo point to the end as undone.
939 		for(int i=pos;i<m_history.end();++i) {
940 			protocol::MessagePtr msg = m_history.at(i);
941 			if(msg->contextId() == ctxid)
942 				msg->setUndoState(protocol::MessageUndoState(protocol::UNDONE | msg->undoState()));
943 		}
944 	}
945 
946 	// Step 4. Revert to the savepoint and replay with undone commands removed (or added back)
947 	revertSavepointAndReplay(savepoint);
948 }
949 
createSavepoint(int pos)950 StateSavepoint StateTracker::createSavepoint(int pos)
951 {
952 	auto *data = new StateSavepoint::Data;
953 	data->timestamp = QDateTime::currentMSecsSinceEpoch();
954 	data->streampointer = pos;
955 	data->canvas = m_layerstack->makeSavepoint();
956 	data->layermodel = m_layerlist->getLayers();
957 
958 	return StateSavepoint(data);
959 }
960 
makeSavepoint(int pos)961 void StateTracker::makeSavepoint(int pos)
962 {
963 	// Don't make savepoints while a local fork exists, since
964 	// there will be stuff on the canvas that is not yet in
965 	// the mainline session history
966 	if(!m_localfork.isEmpty())
967 		return;
968 
969 	// Check if sufficient time and actions has elapsed from previous savepoint
970 	if(!m_savepoints.isEmpty()) {
971 		static const qint64 MIN_INTERVAL_MS = 1000;
972 		static const int MIN_INTERVAL_MSGS = 100;
973 
974 		const StateSavepoint sp = m_savepoints.last();
975 		const auto now = QDateTime::currentMSecsSinceEpoch();
976 		if(now - sp->timestamp < MIN_INTERVAL_MS && m_history.end() - sp->streampointer < MIN_INTERVAL_MSGS)
977 			return;
978 	}
979 
980 	// Looks like a good spot for a savepoint
981 	const auto sp = createSavepoint(pos);
982 	m_savepoints << sp;
983 
984 	if(m_resetpoints.isEmpty() || (sp.timestamp() - m_resetpoints.last().timestamp()) > (10*1000)) {
985 		while(m_resetpoints.size() >= 6)
986 			m_resetpoints.removeFirst();
987 		m_resetpoints << sp;
988 	}
989 }
990 
991 
resetToSavepoint(const StateSavepoint savepoint)992 void StateTracker::resetToSavepoint(const StateSavepoint savepoint)
993 {
994 	// This function is called when jumping to a recorded savepoint
995 	if(!savepoint) {
996 		qWarning("resetToSavepoint() was called with a null savepoint!");
997 		return;
998 	}
999 
1000 	m_history.resetTo(savepoint->streampointer);
1001 	m_savepoints.clear();
1002 
1003 	m_layerstack->editor(0).restoreSavepoint(savepoint->canvas);
1004 	m_layerlist->setLayers(savepoint->layermodel);
1005 
1006 	m_savepoints.append(savepoint);
1007 }
1008 
revertSavepointAndReplay(const StateSavepoint savepoint)1009 void StateTracker::revertSavepointAndReplay(const StateSavepoint savepoint)
1010 {
1011 	// This function is called when reverting to an earlier state to undo
1012 	// an action.
1013 	if(!savepoint) {
1014 		qWarning("revertSavepointAndReplay() was called with a null savepoint!");
1015 		return;
1016 	}
1017 	if(!m_savepoints.contains(savepoint)) {
1018 		qWarning("revertSavepointAndReplay() the given savepoint was not found!");
1019 		return;
1020 	}
1021 
1022 	m_layerstack->editor(0).restoreSavepoint(savepoint->canvas);
1023 	m_layerlist->setLayers(savepoint->layermodel);
1024 
1025 	// Reverting a savepoint destroys all newer savepoints
1026 	while(m_savepoints.last() != savepoint)
1027 		m_savepoints.removeLast();
1028 
1029 	// Replay all not-undo actions (and local fork)
1030 	int pos = savepoint->streampointer + 1;
1031 	while(pos < m_history.end()) {
1032 		if(m_history.at(pos)->undoState() == protocol::DONE) {
1033 			handleCommand(m_history.at(pos), true, pos);
1034 		}
1035 		++pos;
1036 	}
1037 
1038 	// Replay the local fork
1039 	if(!m_localfork.isEmpty()) {
1040 		Q_ASSERT(m_localfork.offset() >= savepoint->streampointer);
1041 		m_localfork.setOffset(pos-1);
1042 		const auto local = m_localfork.messages();
1043 		for(const protocol::MessagePtr &msg : local) {
1044 			if(msg->type() != protocol::MSG_UNDO && msg->type() != protocol::MSG_UNDOPOINT)
1045 				handleCommand(msg, true, pos);
1046 		}
1047 	}
1048 }
1049 
handleTruncateHistory()1050 void StateTracker::handleTruncateHistory()
1051 {
1052 	int pos = m_history.end()-1;
1053 	int upCount = 0;
1054 
1055 	qWarning("Truncating undo history at %d", pos);
1056 	while(m_history.isValidIndex(pos) && upCount <= protocol::UNDO_DEPTH_LIMIT) {
1057 		protocol::MessagePtr msg = m_history.at(pos);
1058 
1059 		if(msg->type() == protocol::MSG_UNDOPOINT) {
1060 			++upCount;
1061 			msg->setUndoState(protocol::GONE);
1062 		}
1063 
1064 		--pos;
1065 	}
1066 	qWarning("Marked %d UPs", upCount);
1067 }
1068 
handleAnnotationCreate(const protocol::AnnotationCreate & cmd)1069 void StateTracker::handleAnnotationCreate(const protocol::AnnotationCreate &cmd)
1070 {
1071 	m_layerstack->annotations()->addAnnotation(cmd.id(), QRect(cmd.x(), cmd.y(), cmd.w(), cmd.h()));
1072 	if(cmd.contextId() == localId())
1073 		emit myAnnotationCreated(cmd.id());
1074 }
1075 
handleAnnotationReshape(const protocol::AnnotationReshape & cmd)1076 void StateTracker::handleAnnotationReshape(const protocol::AnnotationReshape &cmd)
1077 {
1078 	m_layerstack->annotations()->reshapeAnnotation(cmd.id(), QRect(cmd.x(), cmd.y(), cmd.w(), cmd.h()));
1079 }
1080 
handleAnnotationEdit(const protocol::AnnotationEdit & cmd)1081 void StateTracker::handleAnnotationEdit(const protocol::AnnotationEdit &cmd)
1082 {
1083 	m_layerstack->annotations()->changeAnnotation(
1084 		cmd.id(),
1085 		cmd.text(),
1086 		cmd.flags() & protocol::AnnotationEdit::FLAG_PROTECT,
1087 		cmd.flags() & (protocol::AnnotationEdit::FLAG_VALIGN_BOTTOM|protocol::AnnotationEdit::FLAG_VALIGN_CENTER),
1088 		QColor::fromRgba(cmd.bg())
1089 		);
1090 }
1091 
handleAnnotationDelete(const protocol::AnnotationDelete & cmd)1092 void StateTracker::handleAnnotationDelete(const protocol::AnnotationDelete &cmd)
1093 {
1094 	m_layerstack->annotations()->deleteAnnotation(cmd.id());
1095 }
1096 
1097 /**
1098  * @brief Get the affected area of the given message
1099  *
1100  * Note. This uses the current state!
1101  *
1102  * @param msg
1103  * @return
1104  */
affectedArea(protocol::MessagePtr msg) const1105 AffectedArea StateTracker::affectedArea(protocol::MessagePtr msg) const
1106 {
1107 	Q_ASSERT(msg->isCommand());
1108 
1109 	switch(msg->type()) {
1110 	using namespace protocol;
1111 	case MSG_LAYER_CREATE:
1112 	case MSG_LAYER_ATTR:
1113 	case MSG_LAYER_RETITLE:
1114 		return AffectedArea(AffectedArea::LAYERATTRS, msg->layer());
1115 	case MSG_LAYER_VISIBILITY: return AffectedArea(AffectedArea::USERATTRS, 0);
1116 
1117 	case MSG_PUTIMAGE: {
1118 		const PutImage &m = msg.cast<PutImage>();
1119 		return AffectedArea(AffectedArea::PIXELS, m.layer(), QRect(m.x(), m.y(), m.width(), m.height()));
1120 	}
1121 	case MSG_PUTTILE: {
1122 		const PutTile &m = msg.cast<PutTile>();
1123 		return AffectedArea(AffectedArea::PIXELS, m.layer(), QRect(
1124 			m.column() * paintcore::Tile::SIZE,
1125 			m.row() * paintcore::Tile::SIZE,
1126 			paintcore::Tile::SIZE, paintcore::Tile::SIZE));
1127 	}
1128 
1129 	case MSG_DRAWDABS_CLASSIC:
1130 	case MSG_DRAWDABS_PIXEL:
1131 	case MSG_DRAWDABS_PIXEL_SQUARE: {
1132 		const DrawDabs &dd = msg.cast<DrawDabs>();
1133 
1134 		// Indirect drawing mode: check bounds in PenUp
1135 		if(dd.isIndirect())
1136 			return AffectedArea(AffectedArea::USERATTRS, 0);
1137 
1138 		return AffectedArea(AffectedArea::PIXELS, dd.layer(), dd.bounds());
1139 	}
1140 	case MSG_PEN_UP: {
1141 		QPair<int,QRect> bounds = m_layerstack->findChangeBounds(msg->contextId());
1142 		if(bounds.first)
1143 			return AffectedArea(AffectedArea::PIXELS, bounds.first, bounds.second);
1144 		else
1145 			return AffectedArea(AffectedArea::USERATTRS, 0);
1146 	}
1147 	case MSG_FILLRECT: {
1148 		const FillRect &fr = msg.cast<FillRect>();
1149 		return AffectedArea(AffectedArea::PIXELS, fr.layer(), QRect(fr.x(), fr.y(), fr.width(), fr.height()));
1150 	}
1151 
1152 	case MSG_ANNOTATION_CREATE:
1153 	case MSG_ANNOTATION_RESHAPE:
1154 	case MSG_ANNOTATION_EDIT:
1155 	case MSG_ANNOTATION_DELETE:
1156 		return AffectedArea(AffectedArea::ANNOTATION, msg->layer());
1157 
1158 	case MSG_REGION_MOVE: {
1159 		const MoveRegion &mr = msg.cast<MoveRegion>();
1160 		return AffectedArea(AffectedArea::PIXELS, mr.layer(), mr.sourceBounds().united(mr.targetBounds()));
1161 	}
1162 
1163 	case MSG_UNDOPOINT: return AffectedArea(AffectedArea::USERATTRS, 0);
1164 
1165 	case MSG_CANVAS_BACKGROUND: return AffectedArea(AffectedArea::PIXELS, -1, QRect(0, 0, 1, 1));
1166 
1167 	default:
1168 #ifndef NDEBUG
1169 		qWarning("%s: affects EVERYTHING", qPrintable(msg->messageName()));
1170 #endif
1171 		return AffectedArea(AffectedArea::EVERYTHING, 0);
1172 	}
1173 }
1174 
1175 }
1176