1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2008-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 "layerstack.h"
21 #include "layerstackobserver.h"
22 #include "layer.h"
23 #include "tile.h"
24 #include "brushmask.h"
25 #include "point.h"
26 #include "blendmodes.h"
27 #include "rasterop.h"
28 #include "concurrent.h"
29 
30 #include <QPainter>
31 #include <QImage>
32 #include <QDataStream>
33 
34 #define OBSERVERS(notification) for(auto *observer : owner->observers()) observer->notification
35 
36 namespace paintcore {
37 
38 namespace {
39 
40 //! Sample colors at layer edges and return the most frequent color
_sampleEdgeColors(const Layer * layer,bool top,bool right,bool bottom,bool left)41 QColor _sampleEdgeColors(const Layer *layer, bool top, bool right, bool bottom, bool left)
42 {
43 	const int STEP = 22;
44 	QHash<QRgb, int> colorfreq;
45 	// Sample top & bottom edges
46 	for(int x=0;x<layer->width();x+=STEP) {
47 		int count;
48 		QRgb c;
49 		if(top) {
50 			c = layer->pixelAt(x, 0);
51 			count = colorfreq[c];
52 			++count;
53 			colorfreq[c] = count;
54 		}
55 
56 		if(bottom) {
57 			c = layer->pixelAt(x, layer->height()-1);
58 			count = colorfreq[c];
59 			++count;
60 			colorfreq[c] = count;
61 		}
62 	}
63 
64 	// Sample left & right edges
65 	for(int y=0;y<layer->height();y+=STEP) {
66 		int count;
67 		QRgb c;
68 		if(left) {
69 			c = layer->pixelAt(0, y);
70 			count = colorfreq[c];
71 			++count;
72 			colorfreq[c] = count;
73 		}
74 
75 		if(right) {
76 			c = layer->pixelAt(layer->width()-1, y);
77 			count = colorfreq[c];
78 			++count;
79 			colorfreq[c] = count;
80 		}
81 	}
82 
83 	// Return the most frequent color
84 	QRgb color=0;
85 	int freq=0;
86 	QHashIterator<QRgb, int> i(colorfreq);
87 	while(i.hasNext()) {
88 		i.next();
89 		int value = i.value();
90 		// In the unlikely case of two colors being equally frequent, pick the
91 		// smaller one just for consistency. Otherwise the random ordering of
92 		// QHash might lead to users getting different results from this.
93 		if(value > freq || (value == freq && i.key() < color)) {
94 			freq = i.value();
95 			color = i.key();
96 		}
97 	}
98 
99 	return QColor::fromRgba(qUnpremultiply(color));
100 }
101 
102 }
103 
104 /**
105  * Construct a layer initialized to a solid color
106  * @param owner the stack to which this layer belongs to
107  * @param id layer ID
108  * @param color layer color
109  * @parma size layer size
110  */
Layer(int id,const QString & title,const QColor & color,const QSize & size)111 Layer::Layer(int id, const QString& title, const QColor& color, const QSize& size)
112 	: m_info({id, title}),
113 	  m_width(size.width()),
114 	  m_height(size.height()),
115 	  m_xtiles(Tile::roundTiles(size.width())),
116 	  m_ytiles(Tile::roundTiles(size.height()))
117 {
118 	m_tiles = QVector<Tile>(
119 		m_xtiles * m_ytiles,
120 		color.alpha() > 0 ? Tile(color) : Tile()
121 	);
122 }
123 
Layer(int id,const QSize & size)124 Layer::Layer(int id, const QSize &size)
125 	: Layer(id, QString(), Qt::transparent, size)
126 {
127 	// sublayers are used for indirect drawing and previews
128 }
129 
Layer(const QVector<Tile> & tiles,const QSize & size,const LayerInfo & info,const QList<Layer * > sublayers)130 Layer::Layer(const QVector<Tile> &tiles, const QSize &size, const LayerInfo &info, const QList<Layer*> sublayers)
131 	: m_info(info),
132 	  m_tiles(tiles),
133 	  m_sublayers(sublayers),
134 	  m_width(size.width()),
135 	  m_height(size.height()),
136 	  m_xtiles(Tile::roundTiles(size.width())),
137 	  m_ytiles(Tile::roundTiles(size.height()))
138 {
139 	if(m_xtiles * m_ytiles != m_tiles.size()) {
140 		qWarning("Layer constructor: tile vector size mismatch!");
141 		m_tiles.resize(m_xtiles * m_ytiles);
142 	}
143 }
144 
Layer(const Layer & layer)145 Layer::Layer(const Layer &layer)
146 	: m_info(layer.m_info),
147 	  m_changeBounds(layer.m_changeBounds),
148 	  m_tiles(layer.m_tiles),
149 	  m_width(layer.m_width), m_height(layer.m_height),
150 	  m_xtiles(layer.m_xtiles), m_ytiles(layer.m_ytiles)
151 {
152 	// Hidden sublayers are deleted layers, kept around only as a performance
153 	// optimization. No need to copy them.
154 	for(const Layer *sl : layer.sublayers()) {
155 		if(!sl->isHidden())
156 			m_sublayers.append(new Layer(*sl));
157 	}
158 }
159 
~Layer()160 Layer::~Layer() {
161 	for(Layer *sl : m_sublayers)
162 		delete sl;
163 }
164 
toImage() const165 QImage Layer::toImage() const {
166 	QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
167 	int i=0;
168 	for(int y=0;y<m_ytiles;++y) {
169 		for(int x=0;x<m_xtiles;++x,++i)
170 			m_tiles[i].copyToImage(image, x*Tile::SIZE, y*Tile::SIZE);
171 	}
172 	return image;
173 }
174 
toCroppedImage(int * xOffset,int * yOffset) const175 QImage Layer::toCroppedImage(int *xOffset, int *yOffset) const
176 {
177 	int top=m_ytiles, bottom=0;
178 	int left=m_xtiles, right=0;
179 
180 	// Find bounding rectangle of non-blank tiles
181 	for(int y=0;y<m_ytiles;++y) {
182 		for(int x=0;x<m_xtiles;++x) {
183 			const Tile &t = m_tiles.at(y*m_xtiles + x);
184 			if(!t.isBlank()) {
185 				if(x<left)
186 					left=x;
187 				if(x>right)
188 					right=x;
189 				if(y<top)
190 					top=y;
191 				if(y>bottom)
192 					bottom=y;
193 			}
194 		}
195 	}
196 
197 	if(top==m_ytiles) {
198 		// Entire layer appears to be blank
199 		return QImage();
200 	}
201 
202 	// Copy tiles to image
203 	QImage image((right-left+1)*Tile::SIZE, (bottom-top+1)*Tile::SIZE, QImage::Format_ARGB32_Premultiplied);
204 	for(int y=top;y<=bottom;++y) {
205 		for(int x=left;x<=right;++x) {
206 			m_tiles.at(y*m_xtiles+x).copyToImage(image, (x-left)*Tile::SIZE, (y-top)*Tile::SIZE);
207 		}
208 	}
209 
210 	if(xOffset)
211 		*xOffset = left * Tile::SIZE;
212 	if(yOffset)
213 		*yOffset = top * Tile::SIZE;
214 
215 	// TODO pixel perfect cropping
216 	return image;
217 }
218 
219 /**
220  * @param x
221  * @param y
222  * @return invalid color if x or y is outside image boundaries
223  */
colorAt(int x,int y,int dia) const224 QColor Layer::colorAt(int x, int y, int dia) const
225 {
226 	if(x<0 || y<0 || x>=m_width || y>=m_height)
227 		return QColor();
228 
229 	if(dia<2) {
230 		const quint32 c = pixelAt(x, y);
231 		if(c==0)
232 			return QColor();
233 
234 		return QColor::fromRgb(qUnpremultiply(c));
235 
236 	} else {
237 		return getDabColor(makeColorSamplingStamp(dia/2, QPoint(x,y)));
238 	}
239 }
240 
pixelAt(int x,int y) const241 QRgb Layer::pixelAt(int x, int y) const
242 {
243 	if(x<0 || y<0 || x>=m_width || y>=m_height)
244 		return 0;
245 
246 	const int yindex = y/Tile::SIZE;
247 	const int xindex = x/Tile::SIZE;
248 
249 	return tile(xindex, yindex).pixel(x-xindex*Tile::SIZE, y-yindex*Tile::SIZE);
250 }
251 
252 /**
253  * Return a temporary layer with the original image padded and composited with the
254  * content of this layer.
255  *
256  * @param xpos target image position
257  * @param ypos target image position
258  * @param original the image to pad
259  * @param mode compositing mode
260  * @param contextId the ID to assign as the "last edited by" tag
261  */
padImageToTileBoundary(int xpos,int ypos,const QImage & original,BlendMode::Mode mode,int contextId) const262 Layer Layer::padImageToTileBoundary(int xpos, int ypos, const QImage &original, BlendMode::Mode mode, int contextId) const
263 {
264 	const int x0 = Tile::roundDown(xpos);
265 	const int x1 = qMin(m_width, Tile::roundUp(xpos+original.width()));
266 	const int y0 = Tile::roundDown(ypos);
267 	const int y1 = qMin(m_height, Tile::roundUp(ypos+original.height()));
268 
269 	const int w = x1 - x0;
270 	const int h = y1 - y0;
271 
272 	// Pad the image to tile boundaries
273 	QImage image;
274 	if(image.width() == w && image.height() == h) {
275 		image = original;
276 
277 	} else {
278 		image = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
279 		QPainter painter(&image);
280 
281 		if(mode == BlendMode::MODE_REPLACE) {
282 			// Replace mode is special: we must copy the original pixels
283 			// and do the composition with QPainter, since layer merge
284 			// can't distinguish the padding from image transparency
285 			for(int y=0;y<h;y+=Tile::SIZE) {
286 				for(int x=0;x<w;x+=Tile::SIZE) {
287 					tile((x0+x) / Tile::SIZE, (y0+y) / Tile::SIZE).copyToImage(image, x, y);
288 				}
289 			}
290 			painter.setCompositionMode(QPainter::CompositionMode_Source);
291 
292 		} else {
293 			image.fill(0);
294 		}
295 
296 		painter.drawImage(xpos-x0, ypos-y0, original);
297 #if 0 /* debugging aid */
298 		painter.setPen(Qt::red);
299 		painter.drawLine(0, 0, w-1, 0);
300 		painter.drawLine(0, 0, 0, h-1);
301 		painter.drawLine(w-1, 0, w-1, h-1);
302 		painter.drawLine(0, h-1, w-1, h-1);
303 #endif
304 	}
305 
306 	// Create scratch layers and composite
307 	Layer scratch(0, QString(), Qt::transparent, QSize(w,h));
308 	Layer imglayer = scratch;
309 
310 	// Copy image pixels to image layer
311 	for(int y=0;y<h;y+=Tile::SIZE) {
312 		for(int x=0;x<w;x+=Tile::SIZE) {
313 			imglayer.rtile(x/Tile::SIZE, y/Tile::SIZE) = Tile(image, x, y, contextId);
314 		}
315 	}
316 
317 	// In replace mode, compositing was already done with QPainter
318 	if(mode == BlendMode::MODE_REPLACE) {
319 		return imglayer;
320 	}
321 
322 	// Copy tiles from current layer to scratch layer
323 	for(int y=0;y<h;y+=Tile::SIZE) {
324 		for(int x=0;x<w;x+=Tile::SIZE) {
325 			scratch.rtile(x/Tile::SIZE, y/Tile::SIZE) = tile((x+x0)/Tile::SIZE, (y+y0)/Tile::SIZE);
326 		}
327 	}
328 
329 	// Merge image using standard layer compositing ops
330 	EditableLayer(&imglayer, nullptr, contextId).setBlend(mode);
331 	EditableLayer(&scratch, nullptr, contextId).merge(&imglayer);
332 
333 	return scratch;
334 }
335 
336 /**
337  * @brief Get a weighted average of the layer's color, using the given brush mask as the weight
338  *
339  * @param stamp
340  * @return color average
341  */
getDabColor(const BrushStamp & stamp) const342 QColor Layer::getDabColor(const BrushStamp &stamp) const
343 {
344 	// This is very much like directDab, instead we only read pixel values
345 	const uchar *weights = stamp.mask.data();
346 
347 	// The mask can overlap multiple tiles
348 	const int dia = stamp.mask.diameter();
349 	const int bottom = qMin(stamp.top + dia, m_height);
350 	const int right = qMin(stamp.left + dia, m_width);
351 
352 	int y = qMax(0, stamp.top);
353 	int yb = stamp.top<0?-stamp.top:0; // y in relation to brush origin
354 	const int x0 = qMax(0, stamp.left);
355 	const int xb0 = stamp.left<0?-stamp.left:0;
356 
357 	qreal weight=0, red=0, green=0, blue=0, alpha=0;
358 
359 	// collect weighted color sums
360 	while(y<bottom) {
361 		const int yindex = y / Tile::SIZE;
362 		const int yt = y - yindex * Tile::SIZE;
363 		const int hb = yt+dia-yb < Tile::SIZE ? dia-yb : Tile::SIZE-yt;
364 		int x = x0;
365 		int xb = xb0; // x in relation to brush origin
366 		while(x<right) {
367 			const int xindex = x / Tile::SIZE;
368 			const int xt = x - xindex * Tile::SIZE;
369 			const int wb = xt+dia-xb < Tile::SIZE ? dia-xb : Tile::SIZE-xt;
370 			const int i = m_xtiles * yindex + xindex;
371 
372 			std::array<quint32, 5> avg = m_tiles.at(i).weightedAverage(weights + yb * dia + xb, xt, yt, wb, hb, dia-wb);
373 			weight += avg[0];
374 			red += avg[1];
375 			green += avg[2];
376 			blue += avg[3];
377 			alpha += avg[4];
378 
379 			x = (xindex+1) * Tile::SIZE;
380 			xb = xb + wb;
381 		}
382 		y = (yindex+1) * Tile::SIZE;
383 		yb = yb + hb;
384 	}
385 
386 	// There must be at least some alpha for the results to make sense
387 	if(alpha < stamp.mask.diameter()*stamp.mask.diameter() * 30)
388 		return QColor();
389 
390 	// Calculate final average
391 	red /= weight;
392 	green /= weight;
393 	blue /= weight;
394 	alpha /= weight;
395 
396 	// Unpremultiply
397 	red = qMin(1.0, red/alpha);
398 	green = qMin(1.0, green/alpha);
399 	blue = qMin(1.0, blue/alpha);
400 
401 	return QColor::fromRgbF(red, green, blue, alpha);
402 }
403 
404 /**
405  * Free all tiles that are completely transparent
406  */
optimize()407 void Layer::optimize()
408 {
409 	// Optimize tile memory usage
410 	for(int i=0;i<m_tiles.size();++i) {
411 		if(!m_tiles[i].isNull() && m_tiles[i].isBlank())
412 			m_tiles[i] = Tile();
413 	}
414 
415 	// Delete unused sublayers
416 	QMutableListIterator<Layer*> li(m_sublayers);
417 	while(li.hasNext()) {
418 		Layer *sl = li.next();
419 		if(sl->isHidden()) {
420 			delete sl;
421 			li.remove();
422 		}
423 	}
424 }
425 
getSubLayer(int id,BlendMode::Mode blendmode,uchar opacity)426 Layer *Layer::getSubLayer(int id, BlendMode::Mode blendmode, uchar opacity)
427 {
428 	Q_ASSERT(id != 0);
429 
430 	// See if the sublayer exists already
431 	for(Layer *sl : m_sublayers)
432 		if(sl->id() == id) {
433 			if(sl->isHidden()) {
434 				// Hidden, reset properties
435 				sl->m_tiles.fill(Tile());
436 				sl->m_info.opacity = opacity;
437 				sl->m_info.blend = blendmode;
438 				sl->m_info.hidden = false;
439 				sl->m_changeBounds = QRect();
440 			}
441 			return sl;
442 		}
443 
444 	// Okay, try recycling a sublayer
445 	for(Layer *sl : m_sublayers) {
446 		if(sl->isHidden()) {
447 			// Set these flags directly to avoid markDirty call.
448 			// We know the layer is invisible at this point
449 			sl->m_tiles.fill(Tile());
450 			sl->m_info.id = id;
451 			sl->m_info.opacity = opacity;
452 			sl->m_info.blend = blendmode;
453 			sl->m_info.hidden = false;
454 			return sl;
455 		}
456 	}
457 
458 	// No available sublayers, create a new one
459 	Layer *sl = new Layer(id, QSize(m_width, m_height));
460 	sl->m_info.opacity = opacity;
461 	sl->m_info.blend = blendmode;
462 	m_sublayers.append(sl);
463 	return sl;
464 }
465 
getVisibleSublayer(int id) const466 const Layer *Layer::getVisibleSublayer(int id) const
467 {
468 	for(const Layer *sl : m_sublayers) {
469 		if(sl->id() == id && !sl->isHidden())
470 			return sl;
471 	}
472 	return nullptr;
473 }
474 
resize(int top,int right,int bottom,int left)475 void EditableLayer::resize(int top, int right, int bottom, int left)
476 {
477 	Q_ASSERT(d);
478 
479 	// Minimize amount of data that needs to be copied
480 	d->optimize();
481 
482 	// Resize sublayers
483 	for(Layer *sl : d->m_sublayers)
484 		EditableLayer(sl, nullptr, contextId).resize(top, right, bottom, left);
485 
486 	// Calculate new size
487 	int width = left + d->m_width + right;
488 	int height = top + d->m_height + bottom;
489 
490 	int xtiles = Tile::roundTiles(width);
491 	int ytiles = Tile::roundTiles(height);
492 	QVector<Tile> tiles(xtiles * ytiles);
493 
494 	// if there is no old content, resizing is simple
495 	bool hascontent = false;
496 	for(int i=0;i<d->m_tiles.size();++i) {
497 		if(!d->m_tiles.at(i).isBlank()) {
498 			hascontent = true;
499 			break;
500 		}
501 	}
502 	if(!hascontent) {
503 		d->m_width = width;
504 		d->m_height = height;
505 		d->m_xtiles = xtiles;
506 		d->m_ytiles = ytiles;
507 		d->m_tiles = tiles;
508 		return;
509 	}
510 
511 	// Sample colors around the layer edges to determine fill color
512 	// for the new tiles
513 	Tile bgtile;
514 	{
515 		QColor bgcolor = _sampleEdgeColors(d, top>0, right>0, bottom>0, left>0);
516 		if(bgcolor.alpha()>0)
517 			bgtile = Tile(bgcolor);
518 	}
519 
520 	if((left % Tile::SIZE) || (top % Tile::SIZE)) {
521 		// If top/left adjustment is not divisble by tile size,
522 		// we need to move the layer content
523 
524 		QImage oldcontent = d->toImage();
525 
526 		d->m_width = width;
527 		d->m_height = height;
528 		d->m_xtiles = xtiles;
529 		d->m_ytiles = ytiles;
530 		d->m_tiles = tiles;
531 		if(left<0 || top<0) {
532 			int cropx = 0;
533 			if(left<0) {
534 				cropx = -left;
535 				left = 0;
536 			}
537 			int cropy = 0;
538 			if(top<0) {
539 				cropy = -top;
540 				top = 0;
541 			}
542 			oldcontent = oldcontent.copy(cropx, cropy, oldcontent.width()-cropx, oldcontent.height()-cropy);
543 		}
544 
545 		d->m_tiles.fill(bgtile);
546 
547 		// temporarily set the hidden flag, because markDirty must not
548 		// be called during a resize operation.
549 		const bool hidden = d->m_info.hidden;
550 		d->m_info.hidden = true;
551 		putImage(left, top, oldcontent, BlendMode::MODE_REPLACE);
552 		d->m_info.hidden = hidden;
553 
554 	} else {
555 		// top/left offset is aligned at tile boundary:
556 		// existing tile content can be reused
557 
558 		const int firstrow = Tile::roundTiles(-top);
559 		const int firstcol = Tile::roundTiles(-left);
560 
561 		int oldy = firstrow;
562 		for(int y=0;y<ytiles;++y,++oldy) {
563 			int oldx = firstcol;
564 			const int oldyy = d->m_xtiles * oldy;
565 			const int yy = xtiles * y;
566 			for(int x=0;x<xtiles;++x,++oldx) {
567 				const int i = yy + x;
568 
569 				if(oldy<0 || oldy>=d->m_ytiles || oldx<0 || oldx>=d->m_xtiles) {
570 					tiles[i] = bgtile;
571 
572 				} else {
573 					const int oldi = oldyy + oldx;
574 					tiles[i] = d->m_tiles.at(oldi);
575 				}
576 			}
577 		}
578 
579 		d->m_width = width;
580 		d->m_height = height;
581 		d->m_xtiles = xtiles;
582 		d->m_ytiles = ytiles;
583 		d->m_tiles = tiles;
584 	}
585 }
586 
587 /**
588  * @param opacity
589  */
setOpacity(int opacity)590 void EditableLayer::setOpacity(int opacity)
591 {
592 	Q_ASSERT(d);
593 	Q_ASSERT(opacity>=0 && opacity<256);
594 	if(d->m_info.opacity != opacity) {
595 		d->m_info.opacity = opacity;
596 		markOpaqueDirty(true);
597 	}
598 }
599 
setBlend(BlendMode::Mode blend)600 void EditableLayer::setBlend(BlendMode::Mode blend)
601 {
602 	Q_ASSERT(d);
603 	if(d->m_info.blend != blend) {
604 		d->m_info.blend = blend;
605 		markOpaqueDirty();
606 	}
607 }
608 
setCensored(bool censor)609 void EditableLayer::setCensored(bool censor)
610 {
611 	Q_ASSERT(d);
612 	if(d->m_info.censored != censor) {
613 		d->m_info.censored = censor;
614 		markOpaqueDirty(true);
615 	}
616 }
617 
setFixed(bool fixed)618 void EditableLayer::setFixed(bool fixed)
619 {
620 	Q_ASSERT(d);
621 	if(d->m_info.fixed != fixed) {
622 		d->m_info.fixed = fixed;
623 		markOpaqueDirty(true);
624 	}
625 }
626 
627 /**
628  * @param hide new status
629  */
setHidden(bool hide)630 void EditableLayer::setHidden(bool hide)
631 {
632 	Q_ASSERT(d);
633 	if(d->m_info.hidden != hide) {
634 		d->m_info.hidden = hide;
635 		markOpaqueDirty(true);
636 	}
637 }
638 
639 /**
640  * @param x x coordinate
641  * @param y y coordinate
642  * @param image the image to draw
643  * @param mode blending/compositing mode (see protocol::PutImage)
644  */
putImage(int x,int y,QImage image,BlendMode::Mode mode)645 void EditableLayer::putImage(int x, int y, QImage image, BlendMode::Mode mode)
646 {
647 	Q_ASSERT(d);
648 	Q_ASSERT(image.format() == QImage::Format_ARGB32_Premultiplied);
649 
650 	// Check if the image is completely outside the layer
651 	if(x >= d->m_width || y >= d->m_height || x+image.width() < 0 || y+image.height() < 0)
652 		return;
653 
654 	// Crop image if x or y are negative
655 	if(x<0 || y<0) {
656 		const int xCrop = x<0 ? -x : 0;
657 		const int yCrop = y<0 ? -y : 0;
658 
659 		image = image.copy(xCrop, yCrop, image.width()-xCrop, image.height()-yCrop);
660 		x = qMax(0, x);
661 		y = qMax(0, y);
662 	}
663 
664 	const int x0 = Tile::roundDown(x);
665 	const int y0 = Tile::roundDown(y);
666 
667 	const Layer imageLayer = d->padImageToTileBoundary(x, y, image, mode, contextId);
668 
669 	// Replace this layer's tiles with the scratch tiles
670 	const int tx0 = x0 / Tile::SIZE;
671 	const int ty0 = y0 / Tile::SIZE;
672 	const int tx1 = qMin((x0 + imageLayer.width() - 1) / Tile::SIZE, d->m_xtiles-1);
673 	const int ty1 = qMin((y0 + imageLayer.height() - 1) / Tile::SIZE, d->m_ytiles-1);
674 
675 	for(int ty=ty0;ty<=ty1;++ty) {
676 		for(int tx=tx0;tx<=tx1;++tx) {
677 			d->rtile(tx, ty) = imageLayer.tile(tx-tx0, ty-ty0);
678 		}
679 	}
680 
681 	if(owner && d->isVisible())
682 		OBSERVERS(markDirty(QRect(x, y, image.width(), image.height())));
683 }
684 
putTile(int col,int row,int repeat,const Tile & tile,int sublayer)685 void EditableLayer::putTile(int col, int row, int repeat, const Tile &tile, int sublayer)
686 {
687 	Q_ASSERT(d);
688 	if(col<0 || col >= d->m_xtiles || row<0 || row >= d->m_ytiles)
689 		return;
690 
691 	if(sublayer != 0) {
692 		// LayerAttributes command can be used to set the sublayer's blendmode
693 		// and opacity before calling putTile, if necessary.
694 		getEditableSubLayer(sublayer, BlendMode::MODE_NORMAL, 255).putTile(col, row, repeat, tile, 0);
695 		return;
696 	}
697 
698 	int i=row*d->m_xtiles+col;
699 	const int end = qMin(i+repeat, d->m_tiles.size()-1);
700 	for(;i<=end;++i) {
701 		d->m_tiles[i] = tile;
702 		if(owner && d->isVisible())
703 			OBSERVERS(markDirty(i));
704 	}
705 }
706 
fillRect(const QRect & rectangle,const QColor & color,BlendMode::Mode blendmode)707 void EditableLayer::fillRect(const QRect &rectangle, const QColor &color, BlendMode::Mode blendmode)
708 {
709 	const QRect canvas(0, 0, d->m_width, d->m_height);
710 
711 	if(rectangle.contains(canvas) && (blendmode==BlendMode::MODE_REPLACE || (blendmode==BlendMode::MODE_NORMAL && color.alpha() == 255))) {
712 		// Special case: overwrite whole layer
713 		d->m_tiles.fill(Tile(color));
714 
715 	} else {
716 		// The usual case: only a portion of the layer is filled or pixel blending is needed
717 		QRect rect = rectangle.intersected(canvas);
718 
719 		uchar mask[Tile::LENGTH];
720 		if(blendmode==255)
721 			memset(mask, 0xff, Tile::LENGTH);
722 		else
723 			memset(mask, color.alpha(), Tile::LENGTH);
724 
725 		const int size = Tile::SIZE;
726 		const int bottom = rect.y() + rect.height();
727 		const int right = rect.x() + rect.width();
728 
729 		const int tx0 = rect.x() / size;
730 		const int tx1 = (right-1) / size;
731 		const int ty0 = rect.y() / size;
732 		const int ty1 = (bottom-1) / size;
733 
734 		bool canIncrOpacity;
735 		if(blendmode==255 && color.alpha()==0)
736 			canIncrOpacity = false;
737 		else
738 			canIncrOpacity = findBlendMode(blendmode).flags.testFlag(BlendMode::IncrOpacity);
739 
740 		for(int ty=ty0;ty<=ty1;++ty) {
741 			for(int tx=tx0;tx<=tx1;++tx) {
742 				int left = qMax(tx * size, rect.x()) - tx*size;
743 				int top = qMax(ty * size, rect.y()) - ty*size;
744 				int w = qMin((tx+1)*size, right) - tx*size - left;
745 				int h = qMin((ty+1)*size, bottom) - ty*size - top;
746 
747 				Tile &t = d->m_tiles[ty*d->m_xtiles+tx];
748 				t.setLastEditedBy(contextId);
749 
750 				if(!t.isNull() || canIncrOpacity)
751 					t.composite(blendmode, mask, color, left, top, w, h, 0);
752 			}
753 		}
754 	}
755 
756 	if(owner && d->isVisible())
757 		OBSERVERS(markDirty(rectangle));
758 }
759 
putBrushStamp(const BrushStamp & bs,const QColor & color,BlendMode::Mode blendmode)760 void EditableLayer::putBrushStamp(const BrushStamp &bs, const QColor &color, BlendMode::Mode blendmode)
761 {
762 	Q_ASSERT(d);
763 	const int top=bs.top, left=bs.left;
764 	const int dia = bs.mask.diameter();
765 	const int bottom = qMin(top + dia, d->m_height);
766 	const int right = qMin(left + dia, d->m_width);
767 
768 	if(left+dia<=0 || top+dia<=0 || left>=d->m_width || top>=d->m_height)
769 		return;
770 
771 	// Composite the brush mask onto the layer
772 	const uchar *values = bs.mask.data();
773 
774 	// A single dab can (and often does) span multiple tiles.
775 	int y = top<0?0:top;
776 	int yb = top<0?-top:0; // y in relation to brush origin
777 	const int x0 = left<0?0:left;
778 	const int xb0 = left<0?-left:0;
779 	while(y<bottom) {
780 		const int yindex = y / Tile::SIZE;
781 		const int yt = y - yindex * Tile::SIZE;
782 		const int hb = yt+dia-yb < Tile::SIZE ? dia-yb : Tile::SIZE-yt;
783 		int x = x0;
784 		int xb = xb0; // x in relation to brush origin
785 		while(x<right) {
786 			const int xindex = x / Tile::SIZE;
787 			const int xt = x - xindex * Tile::SIZE;
788 			const int wb = xt+dia-xb < Tile::SIZE ? dia-xb : Tile::SIZE-xt;
789 			const int i = d->m_xtiles * yindex + xindex;
790 			d->m_tiles[i].composite(
791 					blendmode,
792 					values + yb * dia + xb,
793 					color,
794 					xt, yt,
795 					wb, hb,
796 					dia-wb
797 					);
798 			d->m_tiles[i].setLastEditedBy(contextId);
799 
800 			x = (xindex+1) * Tile::SIZE;
801 			xb = xb + wb;
802 		}
803 		y = (yindex+1) * Tile::SIZE;
804 		yb = yb + hb;
805 	}
806 
807 	if(owner && d->isVisible())
808 		OBSERVERS(markDirty(QRect(left, top, right-left, bottom-top)));
809 }
810 
811 /**
812  * @brief Merge another layer to this layer
813  *
814  * Both layer must be the same size
815  *
816  * @param layer the source layer
817  */
merge(const Layer * layer)818 void EditableLayer::merge(const Layer *layer)
819 {
820 	Q_ASSERT(d);
821 	Q_ASSERT(layer);
822 	Q_ASSERT(layer->m_xtiles == d->m_xtiles);
823 	Q_ASSERT(layer->m_ytiles == d->m_ytiles);
824 
825 	// Gather a list of non-null source tiles to merge
826 	QList<int> mergeidx;
827 	for(int i=0;i<d->m_tiles.size();++i) {
828 		if(!layer->m_tiles.at(i).isNull())
829 			mergeidx.append(i);
830 	}
831 
832 	// Detach tile vector explicitly to make sure concurrent modifications
833 	// are all done to the same vector
834 	d->m_tiles.detach();
835 
836 	// Merge tiles
837 	concurrentForEach<int>(mergeidx, [this, layer](int idx) {
838 		d->m_tiles[idx].merge(layer->m_tiles.at(idx), layer->opacity(), layer->blendmode());
839 	});
840 
841 	// Merging a layer does not cause an immediate visual change, so we don't
842 	// mark the area as dirty here.
843 }
844 
makeBlank()845 void EditableLayer::makeBlank()
846 {
847 	Q_ASSERT(d);
848 	d->m_tiles.fill(Tile());
849 
850 	if(owner && d->isVisible())
851 		OBSERVERS(markDirty());
852 }
853 
854 /**
855  * This is used to end an indirect stroke.
856  * If a sublayer with the given ID does not exist, this function does nothing.
857  * @param id
858  */
mergeSublayer(int id)859 void EditableLayer::mergeSublayer(int id)
860 {
861 	Q_ASSERT(d);
862 	for(Layer *sl : d->m_sublayers) {
863 		if(sl->id() == id) {
864 			if(!sl->isHidden()) {
865 				merge(sl);
866 				// Set hidden flag directly to avoid markDirty call.
867 				// The merge should cause no visual change.
868 				sl->m_info.hidden = true;
869 			}
870 			return;
871 		}
872 	}
873 }
874 
mergeAllSublayers()875 void EditableLayer::mergeAllSublayers()
876 {
877 	Q_ASSERT(d);
878 	for(Layer *sl : d->m_sublayers) {
879 		if(sl->id() > 0) {
880 			if(!sl->isHidden()) {
881 				merge(sl);
882 				// Set hidden flag directly to avoid markDirty call.
883 				// The merge should cause no visual change.
884 				sl->m_info.hidden = true;
885 			}
886 			return;
887 		}
888 	}
889 }
890 
891 /**
892  * @brief This is used to remove temporary sublayers
893  *
894  * The layer isn't actually deleted, but is just marked as hidden for recycling.
895  * Call optimize() to clean up removed sublayers.
896  * @param id
897  */
removeSublayer(int id)898 void EditableLayer::removeSublayer(int id)
899 {
900 	Q_ASSERT(d);
901 	for(Layer *sl : d->m_sublayers) {
902 		if(sl->id() == id) {
903 			EditableLayer(sl, owner, contextId).setHidden(true);
904 			return;
905 		}
906 	}
907 }
908 
removePreviews()909 void EditableLayer::removePreviews()
910 {
911 	Q_ASSERT(d);
912 	for(Layer *sl : d->m_sublayers) {
913 		if(sl->id() < 0)
914 			EditableLayer(sl, owner, contextId).setHidden(true);
915 	}
916 }
917 
markOpaqueDirty(bool forceVisible)918 void EditableLayer::markOpaqueDirty(bool forceVisible)
919 {
920 	if(!owner || !(forceVisible || d->isVisible()))
921 		return;
922 
923 	for(int i=0;i<d->m_tiles.size();++i) {
924 		if(!d->m_tiles.at(i).isNull())
925 			OBSERVERS(markDirty(i));
926 	}
927 }
928 
929 }
930 
931