mirror of https://github.com/procxx/kepka.git
				
				
				
			Seek done in video player in MediaView. Some memory leaks fixed.
Using pixmapFromImageInPlace() instead of QPixmap::fromImage().
This commit is contained in:
		
							parent
							
								
									fc716af002
								
							
						
					
					
						commit
						cb0c99acc8
					
				|  | @ -2064,7 +2064,7 @@ namespace { | ||||||
| 		cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); | 		cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); | ||||||
| 		if (index != SmallMaskCorners && index != LargeMaskCorners) { | 		if (index != SmallMaskCorners && index != LargeMaskCorners) { | ||||||
| 			for (int i = 0; i < 4; ++i) { | 			for (int i = 0; i < 4; ++i) { | ||||||
| 				::corners[index].p[i] = new QPixmap(QPixmap::fromImage(cors[i], Qt::ColorOnly)); | 				::corners[index].p[i] = new QPixmap(pixmapFromImageInPlace(std_::move(cors[i]))); | ||||||
| 				::corners[index].p[i]->setDevicePixelRatio(cRetinaFactor()); | 				::corners[index].p[i]->setDevicePixelRatio(cRetinaFactor()); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -2101,12 +2101,12 @@ namespace { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		QImage mask[4]; | 		QImage mask[4]; | ||||||
| 		prepareCorners(LargeMaskCorners, st::msgRadius, st::white, 0, mask); | 		prepareCorners(LargeMaskCorners, st::msgRadius, st::white, nullptr, mask); | ||||||
| 		for (int i = 0; i < 4; ++i) { | 		for (int i = 0; i < 4; ++i) { | ||||||
| 			::cornersMaskLarge[i] = new QImage(mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied)); | 			::cornersMaskLarge[i] = new QImage(mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied)); | ||||||
| 			::cornersMaskLarge[i]->setDevicePixelRatio(cRetinaFactor()); | 			::cornersMaskLarge[i]->setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		} | 		} | ||||||
| 		prepareCorners(SmallMaskCorners, st::buttonRadius, st::white, 0, mask); | 		prepareCorners(SmallMaskCorners, st::buttonRadius, st::white, nullptr, mask); | ||||||
| 		for (int i = 0; i < 4; ++i) { | 		for (int i = 0; i < 4; ++i) { | ||||||
| 			::cornersMaskSmall[i] = new QImage(mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied)); | 			::cornersMaskSmall[i] = new QImage(mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied)); | ||||||
| 			::cornersMaskSmall[i]->setDevicePixelRatio(cRetinaFactor()); | 			::cornersMaskSmall[i]->setDevicePixelRatio(cRetinaFactor()); | ||||||
|  | @ -2267,7 +2267,7 @@ namespace { | ||||||
| 				p.setCompositionMode(m); | 				p.setCompositionMode(m); | ||||||
| 				emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - ESize) / 2); | 				emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - ESize) / 2); | ||||||
| 			} | 			} | ||||||
| 			i = map->insert(emojiKey(emoji), QPixmap::fromImage(img, Qt::ColorOnly)); | 			i = map->insert(emojiKey(emoji), App::pixmapFromImageInPlace(std_::move(img))); | ||||||
| 		} | 		} | ||||||
| 		return i.value(); | 		return i.value(); | ||||||
| 	} | 	} | ||||||
|  | @ -2603,13 +2603,13 @@ namespace { | ||||||
| 		if (i == cornersMap.cend()) { | 		if (i == cornersMap.cend()) { | ||||||
| 			QImage images[4]; | 			QImage images[4]; | ||||||
| 			switch (radius) { | 			switch (radius) { | ||||||
| 			case ImageRoundRadius::Small: prepareCorners(SmallMaskCorners, st::buttonRadius, bg, 0, images); break; | 			case ImageRoundRadius::Small: prepareCorners(SmallMaskCorners, st::buttonRadius, bg, nullptr, images); break; | ||||||
| 			case ImageRoundRadius::Large: prepareCorners(LargeMaskCorners, st::msgRadius, bg, 0, images); break; | 			case ImageRoundRadius::Large: prepareCorners(LargeMaskCorners, st::msgRadius, bg, nullptr, images); break; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			CornersPixmaps pixmaps; | 			CornersPixmaps pixmaps; | ||||||
| 			for (int j = 0; j < 4; ++j) { | 			for (int j = 0; j < 4; ++j) { | ||||||
| 				pixmaps.p[j] = new QPixmap(QPixmap::fromImage(images[j], Qt::ColorOnly)); | 				pixmaps.p[j] = new QPixmap(pixmapFromImageInPlace(std_::move(images[j]))); | ||||||
| 				pixmaps.p[j]->setDevicePixelRatio(cRetinaFactor()); | 				pixmaps.p[j]->setDevicePixelRatio(cRetinaFactor()); | ||||||
| 			} | 			} | ||||||
| 			i = cornersMap.insert(colorKey, pixmaps); | 			i = cornersMap.insert(colorKey, pixmaps); | ||||||
|  | @ -2620,46 +2620,51 @@ namespace { | ||||||
| 	void initBackground(int32 id, const QImage &p, bool nowrite) { | 	void initBackground(int32 id, const QImage &p, bool nowrite) { | ||||||
| 		if (Local::readBackground()) return; | 		if (Local::readBackground()) return; | ||||||
| 
 | 
 | ||||||
| 		QImage img(p); |  | ||||||
| 		bool remove = false; |  | ||||||
| 		if (p.isNull()) { |  | ||||||
| 			if (id == DefaultChatBackground) { |  | ||||||
| 				img.load(st::msgBG); |  | ||||||
| 			} else { |  | ||||||
| 				img.load(st::msgBG0); |  | ||||||
| 				if (cRetina()) { |  | ||||||
| 					img = img.scaledToWidth(img.width() * 2, Qt::SmoothTransformation); |  | ||||||
| 				} else if (cScale() != dbisOne) { |  | ||||||
| 					img = img.scaledToWidth(convertScale(img.width()), Qt::SmoothTransformation); |  | ||||||
| 				} |  | ||||||
| 				id = 0; |  | ||||||
| 			} |  | ||||||
| 			remove = true; |  | ||||||
| 		} |  | ||||||
| 		if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied && img.format() != QImage::Format_RGB32) { |  | ||||||
| 			img = img.convertToFormat(QImage::Format_RGB32); |  | ||||||
| 		} |  | ||||||
| 		img.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 
 |  | ||||||
| 		if (!nowrite) { |  | ||||||
| 			Local::writeBackground(id, remove ? QImage() : img); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		delete cChatBackground(); |  | ||||||
| 		cSetChatBackground(new QPixmap(QPixmap::fromImage(img, Qt::ColorOnly))); |  | ||||||
| 		cSetChatBackgroundId(id); |  | ||||||
| 
 |  | ||||||
| 		if (App::main()) App::main()->clearCachedBackground(); |  | ||||||
| 
 |  | ||||||
| 		uint64 components[3] = { 0 }, componentsScroll[3] = { 0 }, componentsPoint[3] = { 0 }; | 		uint64 components[3] = { 0 }, componentsScroll[3] = { 0 }, componentsPoint[3] = { 0 }; | ||||||
| 		int w = img.width(), h = img.height(), size = w * h; | 		int size = 0; | ||||||
| 		const uchar *pix = img.constBits(); | 		{ | ||||||
| 		if (pix) { | 			QImage img(p); | ||||||
| 			for (int32 i = 0, l = size * 4; i < l; i += 4) { | 			bool remove = false; | ||||||
| 				components[2] += pix[i + 0]; | 			if (p.isNull()) { | ||||||
| 				components[1] += pix[i + 1]; | 				if (id == DefaultChatBackground) { | ||||||
| 				components[0] += pix[i + 2]; | 					img.load(st::msgBG); | ||||||
|  | 				} else { | ||||||
|  | 					img.load(st::msgBG0); | ||||||
|  | 					if (cRetina()) { | ||||||
|  | 						img = img.scaledToWidth(img.width() * 2, Qt::SmoothTransformation); | ||||||
|  | 					} else if (cScale() != dbisOne) { | ||||||
|  | 						img = img.scaledToWidth(convertScale(img.width()), Qt::SmoothTransformation); | ||||||
|  | 					} | ||||||
|  | 					id = 0; | ||||||
|  | 				} | ||||||
|  | 				remove = true; | ||||||
| 			} | 			} | ||||||
|  | 			if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied && img.format() != QImage::Format_RGB32) { | ||||||
|  | 				img = img.convertToFormat(QImage::Format_RGB32); | ||||||
|  | 			} | ||||||
|  | 			img.setDevicePixelRatio(cRetinaFactor()); | ||||||
|  | 
 | ||||||
|  | 			if (!nowrite) { | ||||||
|  | 				Local::writeBackground(id, remove ? QImage() : img); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			int w = img.width(), h = img.height(); | ||||||
|  | 			size = w * h; | ||||||
|  | 			const uchar *pix = img.constBits(); | ||||||
|  | 			if (pix) { | ||||||
|  | 				for (int32 i = 0, l = size * 4; i < l; i += 4) { | ||||||
|  | 					components[2] += pix[i + 0]; | ||||||
|  | 					components[1] += pix[i + 1]; | ||||||
|  | 					components[0] += pix[i + 2]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			delete cChatBackground(); | ||||||
|  | 			cSetChatBackground(new QPixmap(pixmapFromImageInPlace(std_::move(img)))); | ||||||
|  | 			cSetChatBackgroundId(id); | ||||||
|  | 
 | ||||||
|  | 			if (App::main()) App::main()->clearCachedBackground(); | ||||||
|  | 
 | ||||||
| 		} | 		} | ||||||
| 		if (size) { | 		if (size) { | ||||||
| 			for (int32 i = 0; i < 3; ++i) components[i] /= size; | 			for (int32 i = 0; i < 3; ++i) components[i] /= size; | ||||||
|  | @ -2677,41 +2682,43 @@ namespace { | ||||||
| 
 | 
 | ||||||
| 		uint64 max = qMax(1ULL, components[maxtomin[0]]), mid = qMax(1ULL, components[maxtomin[1]]), min = qMax(1ULL, components[maxtomin[2]]); | 		uint64 max = qMax(1ULL, components[maxtomin[0]]), mid = qMax(1ULL, components[maxtomin[1]]), min = qMax(1ULL, components[maxtomin[2]]); | ||||||
| 
 | 
 | ||||||
| 		QImage dog = App::sprite().toImage().copy(st::msgDogImg.rect()); | 		{ | ||||||
| 		QImage::Format f = dog.format(); | 			QImage dog = App::sprite().toImage().copy(st::msgDogImg.rect()); | ||||||
| 		if (f != QImage::Format_ARGB32 && f != QImage::Format_ARGB32_Premultiplied) { | 			QImage::Format f = dog.format(); | ||||||
| 			dog = dog.convertToFormat(QImage::Format_ARGB32_Premultiplied); | 			if (f != QImage::Format_ARGB32 && f != QImage::Format_ARGB32_Premultiplied) { | ||||||
| 		} | 				dog = dog.convertToFormat(QImage::Format_ARGB32_Premultiplied); | ||||||
| 		uchar *dogBits = dog.bits(); | 			} | ||||||
| 		if (max != min) { | 			uchar *dogBits = dog.bits(); | ||||||
| 			float64 coef = float64(mid - min) / float64(max - min); | 			if (max != min) { | ||||||
| 			for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { | 				float64 coef = float64(mid - min) / float64(max - min); | ||||||
| 				int dogmaxtomin[3] = { i, i + 1, i + 2 }; | 				for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { | ||||||
| 				if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { | 					int dogmaxtomin[3] = { i, i + 1, i + 2 }; | ||||||
| 					qSwap(dogmaxtomin[0], dogmaxtomin[1]); |  | ||||||
| 				} |  | ||||||
| 				if (dogBits[dogmaxtomin[1]] < dogBits[dogmaxtomin[2]]) { |  | ||||||
| 					qSwap(dogmaxtomin[1], dogmaxtomin[2]); |  | ||||||
| 					if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { | 					if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { | ||||||
| 						qSwap(dogmaxtomin[0], dogmaxtomin[1]); | 						qSwap(dogmaxtomin[0], dogmaxtomin[1]); | ||||||
| 					} | 					} | ||||||
|  | 					if (dogBits[dogmaxtomin[1]] < dogBits[dogmaxtomin[2]]) { | ||||||
|  | 						qSwap(dogmaxtomin[1], dogmaxtomin[2]); | ||||||
|  | 						if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { | ||||||
|  | 							qSwap(dogmaxtomin[0], dogmaxtomin[1]); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					uchar result[3]; | ||||||
|  | 					result[maxtomin[0]] = dogBits[dogmaxtomin[0]]; | ||||||
|  | 					result[maxtomin[2]] = dogBits[dogmaxtomin[2]]; | ||||||
|  | 					result[maxtomin[1]] = uchar(qRound(result[maxtomin[2]] + (result[maxtomin[0]] - result[maxtomin[2]]) * coef)); | ||||||
|  | 					dogBits[i] = result[2]; | ||||||
|  | 					dogBits[i + 1] = result[1]; | ||||||
|  | 					dogBits[i + 2] = result[0]; | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { | ||||||
|  | 					uchar b = dogBits[i], g = dogBits[i + 1], r = dogBits[i + 2]; | ||||||
|  | 					dogBits[i] = dogBits[i + 1] = dogBits[i + 2] = (r + r + b + g + g + g) / 6; | ||||||
| 				} | 				} | ||||||
| 				uchar result[3]; |  | ||||||
| 				result[maxtomin[0]] = dogBits[dogmaxtomin[0]]; |  | ||||||
| 				result[maxtomin[2]] = dogBits[dogmaxtomin[2]]; |  | ||||||
| 				result[maxtomin[1]] = uchar(qRound(result[maxtomin[2]] + (result[maxtomin[0]] - result[maxtomin[2]]) * coef)); |  | ||||||
| 				dogBits[i] = result[2]; |  | ||||||
| 				dogBits[i + 1] = result[1]; |  | ||||||
| 				dogBits[i + 2] = result[0]; |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { |  | ||||||
| 				uchar b = dogBits[i], g = dogBits[i + 1], r = dogBits[i + 2]; |  | ||||||
| 				dogBits[i] = dogBits[i + 1] = dogBits[i + 2] = (r + r + b + g + g + g) / 6; |  | ||||||
| 			} | 			} | ||||||
|  | 			delete cChatDogImage(); | ||||||
|  | 			cSetChatDogImage(new QPixmap(pixmapFromImageInPlace(std_::move(dog)))); | ||||||
| 		} | 		} | ||||||
| 		delete cChatDogImage(); |  | ||||||
| 		cSetChatDogImage(new QPixmap(QPixmap::fromImage(dog))); |  | ||||||
| 
 | 
 | ||||||
| 		memcpy(componentsScroll, components, sizeof(components)); | 		memcpy(componentsScroll, components, sizeof(components)); | ||||||
| 		memcpy(componentsPoint, components, sizeof(components)); | 		memcpy(componentsPoint, components, sizeof(components)); | ||||||
|  | @ -2768,6 +2775,10 @@ namespace { | ||||||
| 		uchar bsel = snap(qRound(((1. - alphaSel) * b + addSel) / alphaSel), 0, 0xFF); | 		uchar bsel = snap(qRound(((1. - alphaSel) * b + addSel) / alphaSel), 0, 0xFF); | ||||||
| 		_msgServiceSelectBg = style::color(r, g, b, qRound(alphaSel * 0xFF)); | 		_msgServiceSelectBg = style::color(r, g, b, qRound(alphaSel * 0xFF)); | ||||||
| 
 | 
 | ||||||
|  | 		for (int i = 0; i < 4; ++i) { | ||||||
|  | 			delete ::corners[StickerCorners].p[i]; ::corners[StickerCorners].p[i] = nullptr; | ||||||
|  | 			delete ::corners[StickerSelectedCorners].p[i]; ::corners[StickerSelectedCorners].p[i] = nullptr; | ||||||
|  | 		} | ||||||
| 		prepareCorners(StickerCorners, st::dateRadius, _msgServiceBg); | 		prepareCorners(StickerCorners, st::dateRadius, _msgServiceBg); | ||||||
| 		prepareCorners(StickerSelectedCorners, st::dateRadius, _msgServiceSelectBg); | 		prepareCorners(StickerSelectedCorners, st::dateRadius, _msgServiceSelectBg); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1014,11 +1014,11 @@ void AppClass::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) { | ||||||
| 	PreparedPhotoThumbs photoThumbs; | 	PreparedPhotoThumbs photoThumbs; | ||||||
| 	QVector<MTPPhotoSize> photoSizes; | 	QVector<MTPPhotoSize> photoSizes; | ||||||
| 
 | 
 | ||||||
| 	QPixmap thumb = QPixmap::fromImage(tosend.scaled(160, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 	QPixmap thumb = App::pixmapFromImageInPlace(tosend.scaled(160, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); | ||||||
| 	photoThumbs.insert('a', thumb); | 	photoThumbs.insert('a', thumb); | ||||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("a"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); | 	photoSizes.push_back(MTP_photoSize(MTP_string("a"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); | ||||||
| 
 | 
 | ||||||
| 	QPixmap medium = QPixmap::fromImage(tosend.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 	QPixmap medium = App::pixmapFromImageInPlace(tosend.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)); | ||||||
| 	photoThumbs.insert('b', medium); | 	photoThumbs.insert('b', medium); | ||||||
| 	photoSizes.push_back(MTP_photoSize(MTP_string("b"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); | 	photoSizes.push_back(MTP_photoSize(MTP_string("b"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -595,7 +595,7 @@ void GroupInfoBox::onPhoto() { | ||||||
| 
 | 
 | ||||||
| void GroupInfoBox::onPhotoReady(const QImage &img) { | void GroupInfoBox::onPhotoReady(const QImage &img) { | ||||||
| 	_photoBig = img; | 	_photoBig = img; | ||||||
| 	_photoSmall = QPixmap::fromImage(img.scaled(st::newGroupPhotoSize * cIntRetinaFactor(), st::newGroupPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 	_photoSmall = App::pixmapFromImageInPlace(img.scaled(st::newGroupPhotoSize * cIntRetinaFactor(), st::newGroupPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 	_photoSmall.setDevicePixelRatio(cRetinaFactor()); | 	_photoSmall.setDevicePixelRatio(cRetinaFactor()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ void PhotoCropBox::init(const QImage &img, PeerData *peer) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); | 	int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); | ||||||
| 	_thumb = QPixmap::fromImage(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 	_thumb = App::pixmapFromImageInPlace(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation)); | ||||||
| 	_thumbw = _thumb.width(); | 	_thumbw = _thumb.width(); | ||||||
| 	_thumbh = _thumb.height(); | 	_thumbh = _thumb.height(); | ||||||
| 	if (_thumbw > _thumbh) { | 	if (_thumbw > _thumbh) { | ||||||
|  |  | ||||||
|  | @ -110,7 +110,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW | ||||||
| 		} | 		} | ||||||
| 		_thumbx = (width() - _thumbw) / 2; | 		_thumbx = (width() - _thumbw) / 2; | ||||||
| 
 | 
 | ||||||
| 		_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 		_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 		_thumb.setDevicePixelRatio(cRetinaFactor()); | 		_thumb.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	} else { | 	} else { | ||||||
| 		if (_file->thumb.isNull()) { | 		if (_file->thumb.isNull()) { | ||||||
|  | @ -483,7 +483,7 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) | ||||||
| 		} | 		} | ||||||
| 		_thumbx = (width() - _thumbw) / 2; | 		_thumbx = (width() - _thumbw) / 2; | ||||||
| 
 | 
 | ||||||
| 		_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 		_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 		_thumb.setDevicePixelRatio(cRetinaFactor()); | 		_thumb.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,6 +24,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | ||||||
| 
 | 
 | ||||||
| #include <openssl/crypto.h> | #include <openssl/crypto.h> | ||||||
| #include <openssl/sha.h> | #include <openssl/sha.h> | ||||||
|  | #include <openssl/err.h> | ||||||
|  | #include <openssl/evp.h> | ||||||
|  | #include <openssl/engine.h> | ||||||
|  | #include <openssl/conf.h> | ||||||
|  | #include <openssl/ssl.h> | ||||||
| 
 | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
| #include <libavcodec/avcodec.h> | #include <libavcodec/avcodec.h> | ||||||
|  | @ -288,10 +293,19 @@ namespace ThirdParty { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void finish() { | 	void finish() { | ||||||
| 		av_lockmgr_register(0); | 		av_lockmgr_register(nullptr); | ||||||
|  | 
 | ||||||
|  | 		CRYPTO_cleanup_all_ex_data(); | ||||||
|  | 		FIPS_mode_set(0); | ||||||
|  | 		ENGINE_cleanup(); | ||||||
|  | 		CONF_modules_unload(1); | ||||||
|  | 		ERR_remove_state(0); | ||||||
|  | 		ERR_free_strings(); | ||||||
|  | 		ERR_remove_thread_state(nullptr); | ||||||
|  | 		EVP_cleanup(); | ||||||
| 
 | 
 | ||||||
| 		delete[] _sslLocks; | 		delete[] _sslLocks; | ||||||
| 		_sslLocks = 0; | 		_sslLocks = nullptr; | ||||||
| 
 | 
 | ||||||
| 		Platform::ThirdParty::finish(); | 		Platform::ThirdParty::finish(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -5857,7 +5857,7 @@ HistoryWebPage::~HistoryWebPage() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 	LocationManager manager; | 	LocationManager *locationManager = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocationManager::init() { | void LocationManager::init() { | ||||||
|  | @ -5869,13 +5869,16 @@ void LocationManager::init() { | ||||||
| 	connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*))); | 	connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*))); | ||||||
| 	connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); | 	connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); | ||||||
| 
 | 
 | ||||||
| 	if (black) delete black; | 	if (black) { | ||||||
|  | 		delete black->v(); | ||||||
|  | 		delete black; | ||||||
|  | 	} | ||||||
| 	QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); | 	QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); | ||||||
| 	{ | 	{ | ||||||
| 		QPainter p(&b); | 		QPainter p(&b); | ||||||
| 		p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b); | 		p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b); | ||||||
| 	} | 	} | ||||||
| 	QPixmap p = QPixmap::fromImage(b, Qt::ColorOnly); | 	QPixmap p = App::pixmapFromImageInPlace(std_::move(b)); | ||||||
| 	p.setDevicePixelRatio(cRetinaFactor()); | 	p.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	black = new ImagePtr(p, "PNG"); | 	black = new ImagePtr(p, "PNG"); | ||||||
| } | } | ||||||
|  | @ -5887,26 +5890,36 @@ void LocationManager::reinit() { | ||||||
| void LocationManager::deinit() { | void LocationManager::deinit() { | ||||||
| 	if (manager) { | 	if (manager) { | ||||||
| 		delete manager; | 		delete manager; | ||||||
| 		manager = 0; | 		manager = nullptr; | ||||||
| 	} | 	} | ||||||
| 	if (black) { | 	if (black) { | ||||||
|  | 		delete black->v(); | ||||||
| 		delete black; | 		delete black; | ||||||
| 		black = 0; | 		black = nullptr; | ||||||
| 	} | 	} | ||||||
| 	dataLoadings.clear(); | 	dataLoadings.clear(); | ||||||
| 	imageLoadings.clear(); | 	imageLoadings.clear(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void initImageLinkManager() { | void initImageLinkManager() { | ||||||
| 	manager.init(); | 	if (!locationManager) { | ||||||
|  | 		locationManager = new LocationManager(); | ||||||
|  | 		locationManager->init(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void reinitImageLinkManager() { | void reinitImageLinkManager() { | ||||||
| 	manager.reinit(); | 	if (locationManager) { | ||||||
|  | 		locationManager->reinit(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void deinitImageLinkManager() { | void deinitImageLinkManager() { | ||||||
| 	manager.deinit(); | 	if (locationManager) { | ||||||
|  | 		locationManager->deinit(); | ||||||
|  | 		delete locationManager; | ||||||
|  | 		locationManager = nullptr; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocationManager::getData(LocationData *data) { | void LocationManager::getData(LocationData *data) { | ||||||
|  | @ -6046,7 +6059,9 @@ void LocationData::load() { | ||||||
| 	if (loading) return; | 	if (loading) return; | ||||||
| 
 | 
 | ||||||
| 	loading = true; | 	loading = true; | ||||||
| 	manager.getData(this); | 	if (locationManager) { | ||||||
|  | 		locationManager->getData(this); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent) | HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent) | ||||||
|  |  | ||||||
|  | @ -2445,8 +2445,6 @@ struct LocationData; | ||||||
| class LocationManager : public QObject { | class LocationManager : public QObject { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	LocationManager() : manager(0), black(0) { |  | ||||||
| 	} |  | ||||||
| 	void init(); | 	void init(); | ||||||
| 	void reinit(); | 	void reinit(); | ||||||
| 	void deinit(); | 	void deinit(); | ||||||
|  | @ -2464,10 +2462,10 @@ public slots: | ||||||
| private: | private: | ||||||
| 	void failed(LocationData *data); | 	void failed(LocationData *data); | ||||||
| 
 | 
 | ||||||
| 	QNetworkAccessManager *manager; | 	QNetworkAccessManager *manager = nullptr; | ||||||
| 	QMap<QNetworkReply*, LocationData*> dataLoadings, imageLoadings; | 	QMap<QNetworkReply*, LocationData*> dataLoadings, imageLoadings; | ||||||
| 	QMap<LocationData*, int32> serverRedirects; | 	QMap<LocationData*, int32> serverRedirects; | ||||||
| 	ImagePtr *black; | 	ImagePtr *black = nullptr; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class HistoryLocation : public HistoryMedia { | class HistoryLocation : public HistoryMedia { | ||||||
|  |  | ||||||
|  | @ -53,7 +53,7 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) | ||||||
| 	_inner->setGeometry(rect()); | 	_inner->setGeometry(rect()); | ||||||
| 	_scroll->setGeometry(rect()); | 	_scroll->setGeometry(rect()); | ||||||
| 
 | 
 | ||||||
| 	_scroll->setWidget(_inner); | 	_scroll->setOwnedWidget(_inner); | ||||||
| 	_scroll->show(); | 	_scroll->show(); | ||||||
| 	_inner->show(); | 	_inner->show(); | ||||||
| 
 | 
 | ||||||
|  | @ -946,4 +946,7 @@ void FieldAutocompleteInner::onPreview() { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | FieldAutocompleteInner::~FieldAutocompleteInner() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace internal
 | } // namespace internal
 | ||||||
|  |  | ||||||
|  | @ -37,7 +37,6 @@ class FieldAutocomplete final : public TWidget { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 
 |  | ||||||
| 	FieldAutocomplete(QWidget *parent); | 	FieldAutocomplete(QWidget *parent); | ||||||
| 
 | 
 | ||||||
| 	void fastHide(); | 	void fastHide(); | ||||||
|  | @ -79,7 +78,6 @@ public: | ||||||
| 	~FieldAutocomplete(); | 	~FieldAutocomplete(); | ||||||
| 
 | 
 | ||||||
| signals: | signals: | ||||||
| 
 |  | ||||||
| 	void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; | 	void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; | ||||||
| 	void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; | 	void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; | ||||||
| 	void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; | 	void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; | ||||||
|  | @ -88,14 +86,12 @@ signals: | ||||||
| 	void moderateKeyActivate(int key, bool *outHandled) const; | 	void moderateKeyActivate(int key, bool *outHandled) const; | ||||||
| 
 | 
 | ||||||
| public slots: | public slots: | ||||||
| 
 |  | ||||||
| 	void hideStart(); | 	void hideStart(); | ||||||
| 	void hideFinish(); | 	void hideFinish(); | ||||||
| 
 | 
 | ||||||
| 	void showStart(); | 	void showStart(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 
 |  | ||||||
| 	void paintEvent(QPaintEvent *e) override; | 	void paintEvent(QPaintEvent *e) override; | ||||||
| 
 | 
 | ||||||
| 	void updateFiltered(bool resetScroll = false); | 	void updateFiltered(bool resetScroll = false); | ||||||
|  | @ -146,7 +142,6 @@ class FieldAutocompleteInner final : public TWidget { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 
 |  | ||||||
| 	FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerPack *srows); | 	FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerPack *srows); | ||||||
| 
 | 
 | ||||||
| 	void clearSel(bool hidden = false); | 	void clearSel(bool hidden = false); | ||||||
|  | @ -155,8 +150,9 @@ public: | ||||||
| 
 | 
 | ||||||
| 	void setRecentInlineBotsInRows(int32 bots); | 	void setRecentInlineBotsInRows(int32 bots); | ||||||
| 
 | 
 | ||||||
| signals: | 	~FieldAutocompleteInner(); | ||||||
| 
 | 
 | ||||||
|  | signals: | ||||||
| 	void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; | 	void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; | ||||||
| 	void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; | 	void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; | ||||||
| 	void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; | 	void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; | ||||||
|  | @ -164,13 +160,11 @@ signals: | ||||||
| 	void mustScrollTo(int scrollToTop, int scrollToBottom); | 	void mustScrollTo(int scrollToTop, int scrollToBottom); | ||||||
| 
 | 
 | ||||||
| public slots: | public slots: | ||||||
| 
 |  | ||||||
| 	void onParentGeometryChanged(); | 	void onParentGeometryChanged(); | ||||||
| 	void onUpdateSelected(bool force = false); | 	void onUpdateSelected(bool force = false); | ||||||
| 	void onPreview(); | 	void onPreview(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 
 |  | ||||||
| 	void paintEvent(QPaintEvent *e) override; | 	void paintEvent(QPaintEvent *e) override; | ||||||
| 	void resizeEvent(QResizeEvent *e) override; | 	void resizeEvent(QResizeEvent *e) override; | ||||||
| 
 | 
 | ||||||
|  | @ -199,6 +193,7 @@ private: | ||||||
| 	bool _previewShown; | 	bool _previewShown; | ||||||
| 
 | 
 | ||||||
| 	QTimer _previewTimer; | 	QTimer _previewTimer; | ||||||
|  | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace internal
 | } // namespace internal
 | ||||||
|  |  | ||||||
|  | @ -2143,7 +2143,7 @@ int HistoryInner::itemTop(const HistoryItem *item) const { // -1 if should not b | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryInner::notifyIsBotChanged() { | void HistoryInner::notifyIsBotChanged() { | ||||||
| 	BotInfo *newinfo = (_history && _history->peer->isUser()) ? _history->peer->asUser()->botInfo : nullptr; | 	BotInfo *newinfo = (_history && _history->peer->isUser()) ? _history->peer->asUser()->botInfo.get() : nullptr; | ||||||
| 	if ((!newinfo && !_botAbout) || (newinfo && _botAbout && _botAbout->info == newinfo)) { | 	if ((!newinfo && !_botAbout) || (newinfo && _botAbout && _botAbout->info == newinfo)) { | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -242,7 +242,7 @@ void IntroSignup::onCheckRequest() { | ||||||
| 
 | 
 | ||||||
| void IntroSignup::onPhotoReady(const QImage &img) { | void IntroSignup::onPhotoReady(const QImage &img) { | ||||||
| 	_photoBig = img; | 	_photoBig = img; | ||||||
| 	_photoSmall = QPixmap::fromImage(img.scaled(st::introPhotoSize * cIntRetinaFactor(), st::introPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 	_photoSmall = App::pixmapFromImageInPlace(img.scaled(st::introPhotoSize * cIntRetinaFactor(), st::introPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 	_photoSmall.setDevicePixelRatio(cRetinaFactor()); | 	_photoSmall.setDevicePixelRatio(cRetinaFactor()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -312,7 +312,7 @@ void FileLoadTask::process() { | ||||||
| 				if (!cover.isNull()) { // cover to thumb
 | 				if (!cover.isNull()) { // cover to thumb
 | ||||||
| 					int32 cw = cover.width(), ch = cover.height(); | 					int32 cw = cover.width(), ch = cover.height(); | ||||||
| 					if (cw < 20 * ch && ch < 20 * cw) { | 					if (cw < 20 * ch && ch < 20 * cw) { | ||||||
| 						QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly); | 						QPixmap full = (cw > 90 || ch > 90) ? App::pixmapFromImageInPlace(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std_::move(cover)); | ||||||
| 						{ | 						{ | ||||||
| 							QByteArray thumbFormat = "JPG"; | 							QByteArray thumbFormat = "JPG"; | ||||||
| 							int32 thumbQuality = 87; | 							int32 thumbQuality = 87; | ||||||
|  | @ -339,7 +339,7 @@ void FileLoadTask::process() { | ||||||
| 					attributes.push_back(animatedAttribute); | 					attributes.push_back(animatedAttribute); | ||||||
| 					gif = true; | 					gif = true; | ||||||
| 
 | 
 | ||||||
| 					QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly); | 					QPixmap full = (cw > 90 || ch > 90) ? App::pixmapFromImageInPlace(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std_::move(cover)); | ||||||
| 					{ | 					{ | ||||||
| 						QByteArray thumbFormat = "JPG"; | 						QByteArray thumbFormat = "JPG"; | ||||||
| 						int32 thumbQuality = 87; | 						int32 thumbQuality = 87; | ||||||
|  | @ -369,15 +369,15 @@ void FileLoadTask::process() { | ||||||
| 			if (animated) { | 			if (animated) { | ||||||
| 				attributes.push_back(MTP_documentAttributeAnimated()); | 				attributes.push_back(MTP_documentAttributeAnimated()); | ||||||
| 			} else if (_type != PrepareDocument) { | 			} else if (_type != PrepareDocument) { | ||||||
| 				QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage); | 				QPixmap thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage); | ||||||
| 				photoThumbs.insert('s', thumb); | 				photoThumbs.insert('s', thumb); | ||||||
| 				photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); | 				photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0))); | ||||||
| 
 | 
 | ||||||
| 				QPixmap medium = (w > 320 || h > 320) ? QPixmap::fromImage(fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage); | 				QPixmap medium = (w > 320 || h > 320) ? App::pixmapFromImageInPlace(fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage); | ||||||
| 				photoThumbs.insert('m', medium); | 				photoThumbs.insert('m', medium); | ||||||
| 				photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); | 				photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); | ||||||
| 
 | 
 | ||||||
| 				QPixmap full = (w > 1280 || h > 1280) ? QPixmap::fromImage(fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage); | 				QPixmap full = (w > 1280 || h > 1280) ? App::pixmapFromImageInPlace(fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage); | ||||||
| 				photoThumbs.insert('y', full); | 				photoThumbs.insert('y', full); | ||||||
| 				photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); | 				photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); | ||||||
| 
 | 
 | ||||||
|  | @ -397,7 +397,7 @@ void FileLoadTask::process() { | ||||||
| 				thumbname = qsl("thumb.webp"); | 				thumbname = qsl("thumb.webp"); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(fullimage.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage, Qt::ColorOnly); | 			QPixmap full = (w > 90 || h > 90) ? App::pixmapFromImageInPlace(fullimage.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage, Qt::ColorOnly); | ||||||
| 
 | 
 | ||||||
| 			{ | 			{ | ||||||
| 				QBuffer buffer(&thumbdata); | 				QBuffer buffer(&thumbdata); | ||||||
|  |  | ||||||
|  | @ -2643,7 +2643,7 @@ namespace Local { | ||||||
| 						case StorageFileWebp: guessFormat = "WEBP"; break; | 						case StorageFileWebp: guessFormat = "WEBP"; break; | ||||||
| 						default: guessFormat = QByteArray(); break; | 						default: guessFormat = QByteArray(); break; | ||||||
| 					} | 					} | ||||||
| 					pixmap = QPixmap::fromImage(App::readImage(data, &guessFormat, false), Qt::ColorOnly); | 					pixmap = App::pixmapFromImageInPlace(App::readImage(data, &guessFormat, false)); | ||||||
| 					if (!pixmap.isNull()) { | 					if (!pixmap.isNull()) { | ||||||
| 						format = guessFormat; | 						format = guessFormat; | ||||||
| 					} | 					} | ||||||
|  | @ -2910,7 +2910,7 @@ namespace Local { | ||||||
| 		struct Result { | 		struct Result { | ||||||
| 			Result(StorageFileType type, const QByteArray &data) : image(type, data) { | 			Result(StorageFileType type, const QByteArray &data) : image(type, data) { | ||||||
| 				QByteArray guessFormat; | 				QByteArray guessFormat; | ||||||
| 				pixmap = QPixmap::fromImage(App::readImage(data, &guessFormat, false), Qt::ColorOnly); | 				pixmap = App::pixmapFromImageInPlace(App::readImage(data, &guessFormat, false)); | ||||||
| 				if (!pixmap.isNull()) { | 				if (!pixmap.isNull()) { | ||||||
| 					format = guessFormat; | 					format = guessFormat; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | @ -1019,13 +1019,13 @@ void MainWidget::onCacheBackground() { | ||||||
| 		} | 		} | ||||||
| 		_cachedX = 0; | 		_cachedX = 0; | ||||||
| 		_cachedY = 0; | 		_cachedY = 0; | ||||||
| 		_cachedBackground = QPixmap::fromImage(result); | 		_cachedBackground = App::pixmapFromImageInPlace(std_::move(result)); | ||||||
| 	} else { | 	} else { | ||||||
| 		QRect to, from; | 		QRect to, from; | ||||||
| 		backgroundParams(_willCacheFor, to, from); | 		backgroundParams(_willCacheFor, to, from); | ||||||
| 		_cachedX = to.x(); | 		_cachedX = to.x(); | ||||||
| 		_cachedY = to.y(); | 		_cachedY = to.y(); | ||||||
| 		_cachedBackground = QPixmap::fromImage(bg.toImage().copy(from).scaled(to.width() * cIntRetinaFactor(), to.height() * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | 		_cachedBackground = App::pixmapFromImageInPlace(bg.toImage().copy(from).scaled(to.width() * cIntRetinaFactor(), to.height() * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 		_cachedBackground.setDevicePixelRatio(cRetinaFactor()); | 		_cachedBackground.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	} | 	} | ||||||
| 	_cachedFor = _willCacheFor; | 	_cachedFor = _willCacheFor; | ||||||
|  |  | ||||||
|  | @ -174,7 +174,7 @@ void NotifyWindow::updateNotifyDisplay() { | ||||||
| 			history->peer->loadUserpic(true, true); | 			history->peer->loadUserpic(true, true); | ||||||
| 			history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); | 			history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); | ||||||
| 		} else { | 		} else { | ||||||
| 			static QPixmap icon = QPixmap::fromImage(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); | 			static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
| 			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon); | 			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -234,7 +234,7 @@ void NotifyWindow::updateNotifyDisplay() { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pm = QPixmap::fromImage(img, Qt::ColorOnly); | 	pm = App::pixmapFromImageInPlace(std_::move(img)); | ||||||
| 	update(); | 	update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -246,7 +246,7 @@ void NotifyWindow::updatePeerPhoto() { | ||||||
| 			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); | 			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); | ||||||
| 		} | 		} | ||||||
| 		peerPhoto = ImagePtr(); | 		peerPhoto = ImagePtr(); | ||||||
| 		pm = QPixmap::fromImage(img, Qt::ColorOnly); | 		pm = App::pixmapFromImageInPlace(std_::move(img)); | ||||||
| 		update(); | 		update(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -1882,7 +1882,7 @@ QImage MainWindow::iconWithCounter(int size, int count, style::color bg, bool sm | ||||||
| 		placeSmallCounter(img, size, count, bg, QPoint(), st::counterColor); | 		placeSmallCounter(img, size, count, bg, QPoint(), st::counterColor); | ||||||
| 	} else { | 	} else { | ||||||
| 		QPainter p(&img); | 		QPainter p(&img); | ||||||
| 		p.drawPixmap(size / 2, size / 2, QPixmap::fromImage(iconWithCounter(-size / 2, count, bg, false), Qt::ColorOnly)); | 		p.drawPixmap(size / 2, size / 2, App::pixmapFromImageInPlace(iconWithCounter(-size / 2, count, bg, false))); | ||||||
| 	} | 	} | ||||||
| 	return img; | 	return img; | ||||||
| } | } | ||||||
|  | @ -1952,7 +1952,7 @@ PreLaunchWindow *PreLaunchWindowInstance = 0; | ||||||
| PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) { | PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) { | ||||||
| 	Fonts::start(); | 	Fonts::start(); | ||||||
| 
 | 
 | ||||||
| 	QIcon icon(QPixmap::fromImage(QImage(cPlatform() == dbipMac ? qsl(":/gui/art/iconbig256.png") : qsl(":/gui/art/icon256.png")), Qt::ColorOnly)); | 	QIcon icon(App::pixmapFromImageInPlace(QImage(cPlatform() == dbipMac ? qsl(":/gui/art/iconbig256.png") : qsl(":/gui/art/icon256.png")))); | ||||||
| 	if (cPlatform() == dbipLinux32 || cPlatform() == dbipLinux64) { | 	if (cPlatform() == dbipLinux32 || cPlatform() == dbipLinux64) { | ||||||
| 		icon = QIcon::fromTheme("telegram", icon); | 		icon = QIcon::fromTheme("telegram", icon); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -484,14 +484,12 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) { | ||||||
| 	if (stopped) emit updated(stopped); | 	if (stopped) emit updated(stopped); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AudioPlayer::initFromVideo(const AudioMsgId &audio, uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position) { | void AudioPlayer::initFromVideo(uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position) { | ||||||
| 	t_assert(audio.type() == AudioMsgId::Type::Video); |  | ||||||
| 
 |  | ||||||
| 	auto type = audio.type(); |  | ||||||
| 	AudioMsgId stopped; | 	AudioMsgId stopped; | ||||||
| 	{ | 	{ | ||||||
| 		QMutexLocker lock(&playerMutex); | 		QMutexLocker lock(&playerMutex); | ||||||
| 
 | 
 | ||||||
|  | 		auto type = AudioMsgId::Type::Video; | ||||||
| 		auto current = dataForType(type); | 		auto current = dataForType(type); | ||||||
| 		t_assert(current != nullptr); | 		t_assert(current != nullptr); | ||||||
| 
 | 
 | ||||||
|  | @ -503,7 +501,7 @@ void AudioPlayer::initFromVideo(const AudioMsgId &audio, uint64 videoPlayId, std | ||||||
| 		} | 		} | ||||||
| 		emit faderOnTimer(); | 		emit faderOnTimer(); | ||||||
| 		current->clear(); | 		current->clear(); | ||||||
| 		current->audio = audio; | 		current->audio = AudioMsgId(AudioMsgId::Type::Video); | ||||||
| 		current->videoPlayId = videoPlayId; | 		current->videoPlayId = videoPlayId; | ||||||
| 		current->videoData = std_::move(data); | 		current->videoData = std_::move(data); | ||||||
| 		{ | 		{ | ||||||
|  | @ -516,7 +514,7 @@ void AudioPlayer::initFromVideo(const AudioMsgId &audio, uint64 videoPlayId, std | ||||||
| 
 | 
 | ||||||
| 		current->playbackState.state = AudioPlayerPaused; | 		current->playbackState.state = AudioPlayerPaused; | ||||||
| 		current->loading = true; | 		current->loading = true; | ||||||
| 		emit loaderOnStart(audio, position); | 		emit loaderOnStart(current->audio, position); | ||||||
| 	} | 	} | ||||||
| 	if (stopped) emit updated(stopped); | 	if (stopped) emit updated(stopped); | ||||||
| } | } | ||||||
|  | @ -651,7 +649,7 @@ void AudioPlayer::videoSoundProgress(const AudioMsgId &audio) { | ||||||
| 	auto current = dataForType(type); | 	auto current = dataForType(type); | ||||||
| 	t_assert(current != nullptr); | 	t_assert(current != nullptr); | ||||||
| 
 | 
 | ||||||
| 	if (current->videoPlayId == _lastVideoPlayId && current->playbackState.frequency) { | 	if (current->videoPlayId == _lastVideoPlayId && current->playbackState.duration && current->playbackState.frequency) { | ||||||
| 		_lastVideoPlaybackWhen = getms(); | 		_lastVideoPlaybackWhen = getms(); | ||||||
| 		_lastVideoPlaybackCorrectedMs = (current->playbackState.position * 1000ULL) / current->playbackState.frequency; | 		_lastVideoPlaybackCorrectedMs = (current->playbackState.position * 1000ULL) / current->playbackState.frequency; | ||||||
| 	} | 	} | ||||||
|  | @ -1523,15 +1521,11 @@ void AudioCaptureInner::onStop(bool needResult) { | ||||||
| 	if (d->device) { | 	if (d->device) { | ||||||
| 		alcCaptureStop(d->device); | 		alcCaptureStop(d->device); | ||||||
| 		alcCaptureCloseDevice(d->device); | 		alcCaptureCloseDevice(d->device); | ||||||
| 		d->device = 0; | 		d->device = nullptr; | ||||||
| 
 | 
 | ||||||
| 		if (d->ioContext) { |  | ||||||
| 			av_free(d->ioContext); |  | ||||||
| 			d->ioContext = 0; |  | ||||||
| 		} |  | ||||||
| 		if (d->codecContext) { | 		if (d->codecContext) { | ||||||
| 			avcodec_close(d->codecContext); | 			avcodec_close(d->codecContext); | ||||||
| 			d->codecContext = 0; | 			d->codecContext = nullptr; | ||||||
| 		} | 		} | ||||||
| 		if (d->srcSamplesData) { | 		if (d->srcSamplesData) { | ||||||
| 			if (d->srcSamplesData[0]) { | 			if (d->srcSamplesData[0]) { | ||||||
|  | @ -1548,23 +1542,28 @@ void AudioCaptureInner::onStop(bool needResult) { | ||||||
| 		d->fullSamples = 0; | 		d->fullSamples = 0; | ||||||
| 		if (d->swrContext) { | 		if (d->swrContext) { | ||||||
| 			swr_free(&d->swrContext); | 			swr_free(&d->swrContext); | ||||||
| 			d->swrContext = 0; | 			d->swrContext = nullptr; | ||||||
| 		} | 		} | ||||||
| 		if (d->opened) { | 		if (d->opened) { | ||||||
| 			avformat_close_input(&d->fmtContext); | 			avformat_close_input(&d->fmtContext); | ||||||
| 			d->opened = false; | 			d->opened = false; | ||||||
| 			d->ioBuffer = 0; | 		} | ||||||
|  | 		if (d->ioContext) { | ||||||
|  | 			av_free(d->ioContext->buffer); | ||||||
|  | 			av_free(d->ioContext); | ||||||
|  | 			d->ioContext = nullptr; | ||||||
|  | 			d->ioBuffer = nullptr; | ||||||
| 		} else if (d->ioBuffer) { | 		} else if (d->ioBuffer) { | ||||||
| 			av_free(d->ioBuffer); | 			av_free(d->ioBuffer); | ||||||
| 			d->ioBuffer = 0; | 			d->ioBuffer = nullptr; | ||||||
| 		} | 		} | ||||||
| 		if (d->fmtContext) { | 		if (d->fmtContext) { | ||||||
| 			avformat_free_context(d->fmtContext); | 			avformat_free_context(d->fmtContext); | ||||||
| 			d->fmtContext = 0; | 			d->fmtContext = nullptr; | ||||||
| 		} | 		} | ||||||
| 		d->fmt = 0; | 		d->fmt = nullptr; | ||||||
| 		d->stream = 0; | 		d->stream = nullptr; | ||||||
| 		d->codec = 0; | 		d->codec = nullptr; | ||||||
| 
 | 
 | ||||||
| 		d->lastUpdate = 0; | 		d->lastUpdate = 0; | ||||||
| 		d->levelMax = 0; | 		d->levelMax = 0; | ||||||
|  |  | ||||||
|  | @ -67,7 +67,7 @@ public: | ||||||
| 	void stop(AudioMsgId::Type type); | 	void stop(AudioMsgId::Type type); | ||||||
| 
 | 
 | ||||||
| 	// Video player audio stream interface.
 | 	// Video player audio stream interface.
 | ||||||
| 	void initFromVideo(const AudioMsgId &audio, uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position); | 	void initFromVideo(uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position); | ||||||
| 	void feedFromVideo(VideoSoundPart &&part); | 	void feedFromVideo(VideoSoundPart &&part); | ||||||
| 	int64 getVideoCorrectedTime(uint64 playId, uint64 systemMs); | 	int64 getVideoCorrectedTime(uint64 playId, uint64 systemMs); | ||||||
| 	void videoSoundProgress(const AudioMsgId &audio); | 	void videoSoundProgress(const AudioMsgId &audio); | ||||||
|  |  | ||||||
|  | @ -76,9 +76,12 @@ bool AbstractFFMpegLoader::open(qint64 position) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AbstractFFMpegLoader::~AbstractFFMpegLoader() { | AbstractFFMpegLoader::~AbstractFFMpegLoader() { | ||||||
| 	if (ioContext) av_free(ioContext); |  | ||||||
| 	if (_opened) { | 	if (_opened) { | ||||||
| 		avformat_close_input(&fmtContext); | 		avformat_close_input(&fmtContext); | ||||||
|  | 	} | ||||||
|  | 	if (ioContext) { | ||||||
|  | 		av_free(ioContext->buffer); | ||||||
|  | 		av_free(ioContext); | ||||||
| 	} else if (ioBuffer) { | 	} else if (ioBuffer) { | ||||||
| 		av_free(ioBuffer); | 		av_free(ioBuffer); | ||||||
| 	} | 	} | ||||||
|  | @ -221,9 +224,6 @@ bool FFMpegLoader::open(qint64 position) { | ||||||
| 			if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) { | 			if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		//if (dstSamplesData) {
 |  | ||||||
| 		//	position = qRound(srcRate * (position / float64(dstRate)));
 |  | ||||||
| 		//}
 |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
|  |  | ||||||
|  | @ -201,7 +201,7 @@ void AudioPlayerLoaders::loadData(AudioMsgId audio, qint64 position) { | ||||||
| 		} | 		} | ||||||
| 		m->skipStart = position; | 		m->skipStart = position; | ||||||
| 		m->skipEnd = m->playbackState.duration - position; | 		m->skipEnd = m->playbackState.duration - position; | ||||||
| 		m->playbackState.position = 0; | 		m->playbackState.position = position; | ||||||
| 		m->started = 0; | 		m->started = 0; | ||||||
| 	} | 	} | ||||||
| 	if (samplesCount) { | 	if (samplesCount) { | ||||||
|  |  | ||||||
|  | @ -182,6 +182,7 @@ ChildFFMpegLoader::~ChildFFMpegLoader() { | ||||||
| 	for (auto &packet : queue) { | 	for (auto &packet : queue) { | ||||||
| 		FFMpeg::freePacket(&packet); | 		FFMpeg::freePacket(&packet); | ||||||
| 	} | 	} | ||||||
|  | 	if (_swrContext) swr_free(&_swrContext); | ||||||
| 	if (_dstSamplesData) { | 	if (_dstSamplesData) { | ||||||
| 		if (_dstSamplesData[0]) { | 		if (_dstSamplesData[0]) { | ||||||
| 			av_freep(&_dstSamplesData[0]); | 			av_freep(&_dstSamplesData[0]); | ||||||
|  |  | ||||||
|  | @ -233,7 +233,7 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Read some future packets for audio stream.
 | 	// Read some future packets for audio stream.
 | ||||||
| 	if (_audioStreamId) { | 	if (_audioStreamId >= 0) { | ||||||
| 		while (_frameMs + 5000 > _lastReadPacketMs) { | 		while (_frameMs + 5000 > _lastReadPacketMs) { | ||||||
| 			auto packetResult = readPacket(); | 			auto packetResult = readPacket(); | ||||||
| 			if (packetResult != PacketResult::Ok) { | 			if (packetResult != PacketResult::Ok) { | ||||||
|  | @ -246,7 +246,7 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool FFMpegReaderImplementation::start(Mode mode) { | bool FFMpegReaderImplementation::start(Mode mode, int64 positionMs) { | ||||||
| 	_mode = mode; | 	_mode = mode; | ||||||
| 
 | 
 | ||||||
| 	initDevice(); | 	initDevice(); | ||||||
|  | @ -309,6 +309,7 @@ bool FFMpegReaderImplementation::start(Mode mode) { | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	std_::unique_ptr<VideoSoundData> soundData; | ||||||
| 	if (_audioStreamId >= 0) { | 	if (_audioStreamId >= 0) { | ||||||
| 		// Get a pointer to the codec context for the audio stream
 | 		// Get a pointer to the codec context for the audio stream
 | ||||||
| 		auto audioContextOriginal = _fmtContext->streams[_audioStreamId]->codec; | 		auto audioContextOriginal = _fmtContext->streams[_audioStreamId]->codec; | ||||||
|  | @ -326,7 +327,7 @@ bool FFMpegReaderImplementation::start(Mode mode) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		auto soundData = std_::make_unique<VideoSoundData>(); | 		soundData = std_::make_unique<VideoSoundData>(); | ||||||
| 		soundData->context = audioContext; | 		soundData->context = audioContext; | ||||||
| 		soundData->frequency = audioContextOriginal->sample_rate; | 		soundData->frequency = audioContextOriginal->sample_rate; | ||||||
| 		if (_fmtContext->streams[_audioStreamId]->duration == AV_NOPTS_VALUE) { | 		if (_fmtContext->streams[_audioStreamId]->duration == AV_NOPTS_VALUE) { | ||||||
|  | @ -334,7 +335,20 @@ bool FFMpegReaderImplementation::start(Mode mode) { | ||||||
| 		} else { | 		} else { | ||||||
| 			soundData->length = (_fmtContext->streams[_audioStreamId]->duration * soundData->frequency * _fmtContext->streams[_audioStreamId]->time_base.num) / _fmtContext->streams[_audioStreamId]->time_base.den; | 			soundData->length = (_fmtContext->streams[_audioStreamId]->duration * soundData->frequency * _fmtContext->streams[_audioStreamId]->time_base.num) / _fmtContext->streams[_audioStreamId]->time_base.den; | ||||||
| 		} | 		} | ||||||
| 		audioPlayer()->initFromVideo(AudioMsgId(AudioMsgId::Type::Video), _playId, std_::move(soundData), 0); | 	} | ||||||
|  | 
 | ||||||
|  | 	if (positionMs) { | ||||||
|  | 		int64 ts = (positionMs * _fmtContext->streams[_streamId]->time_base.den) / (1000LL * _fmtContext->streams[_streamId]->time_base.num); | ||||||
|  | 		if (av_seek_frame(_fmtContext, _streamId, ts, AVSEEK_FLAG_ANY) < 0) { | ||||||
|  | 			if (av_seek_frame(_fmtContext, _streamId, ts, 0) < 0) { | ||||||
|  | 				positionMs = 0; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (_audioStreamId >= 0) { | ||||||
|  | 		int64 position = (positionMs * soundData->frequency) / 1000LL; | ||||||
|  | 		audioPlayer()->initFromVideo(_playId, std_::move(soundData), position); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
|  | @ -348,22 +362,26 @@ FFMpegReaderImplementation::~FFMpegReaderImplementation() { | ||||||
| 	if (_audioStreamId >= 0) { | 	if (_audioStreamId >= 0) { | ||||||
| 		audioPlayer()->stopFromVideo(_playId); | 		audioPlayer()->stopFromVideo(_playId); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	clearPacketQueue(); | ||||||
|  | 
 | ||||||
| 	if (_frameRead) { | 	if (_frameRead) { | ||||||
| 		av_frame_unref(_frame); | 		av_frame_unref(_frame); | ||||||
| 		_frameRead = false; | 		_frameRead = false; | ||||||
| 	} | 	} | ||||||
| 	if (_ioContext) av_free(_ioContext); |  | ||||||
| 	if (_codecContext) avcodec_close(_codecContext); | 	if (_codecContext) avcodec_close(_codecContext); | ||||||
| 	if (_swsContext) sws_freeContext(_swsContext); | 	if (_swsContext) sws_freeContext(_swsContext); | ||||||
| 	if (_opened) { | 	if (_opened) { | ||||||
| 		avformat_close_input(&_fmtContext); | 		avformat_close_input(&_fmtContext); | ||||||
|  | 	} | ||||||
|  | 	if (_ioContext) { | ||||||
|  | 		av_free(_ioContext->buffer); | ||||||
|  | 		av_free(_ioContext); | ||||||
| 	} else if (_ioBuffer) { | 	} else if (_ioBuffer) { | ||||||
| 		av_free(_ioBuffer); | 		av_free(_ioBuffer); | ||||||
| 	} | 	} | ||||||
| 	if (_fmtContext) avformat_free_context(_fmtContext); | 	if (_fmtContext) avformat_free_context(_fmtContext); | ||||||
| 	av_frame_free(&_frame); | 	av_frame_free(&_frame); | ||||||
| 
 |  | ||||||
| 	clearPacketQueue(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket() { | FFMpegReaderImplementation::PacketResult FFMpegReaderImplementation::readPacket() { | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ public: | ||||||
| 	void pauseAudio() override; | 	void pauseAudio() override; | ||||||
| 	void resumeAudio() override; | 	void resumeAudio() override; | ||||||
| 
 | 
 | ||||||
| 	bool start(Mode mode) override; | 	bool start(Mode mode, int64 positionMs) override; | ||||||
| 
 | 
 | ||||||
| 	QString logData() const; | 	QString logData() const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ public: | ||||||
| 	virtual void pauseAudio() = 0; | 	virtual void pauseAudio() = 0; | ||||||
| 	virtual void resumeAudio() = 0; | 	virtual void resumeAudio() = 0; | ||||||
| 
 | 
 | ||||||
| 	virtual bool start(Mode mode) = 0; | 	virtual bool start(Mode mode, int64 positionMs) = 0; | ||||||
| 	virtual ~ReaderImplementation() { | 	virtual ~ReaderImplementation() { | ||||||
| 	} | 	} | ||||||
| 	int64 dataSize() const { | 	int64 dataSize() const { | ||||||
|  |  | ||||||
|  | @ -99,7 +99,7 @@ int64 QtGifReaderImplementation::durationMs() const { | ||||||
| 	return 0; // not supported
 | 	return 0; // not supported
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool QtGifReaderImplementation::start(Mode mode) { | bool QtGifReaderImplementation::start(Mode mode, int64 positionMs) { | ||||||
| 	if (mode == Mode::OnlyGifv) return false; | 	if (mode == Mode::OnlyGifv) return false; | ||||||
| 	_mode = mode; | 	_mode = mode; | ||||||
| 	return jumpToStart(); | 	return jumpToStart(); | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ public: | ||||||
| 	void resumeAudio() override { | 	void resumeAudio() override { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool start(Mode mode) override; | 	bool start(Mode mode, int64 positionMs) override; | ||||||
| 
 | 
 | ||||||
| 	~QtGifReaderImplementation(); | 	~QtGifReaderImplementation(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -85,10 +85,11 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
| Reader::Reader(const FileLocation &location, const QByteArray &data, Callback &&callback, Mode mode) | Reader::Reader(const FileLocation &location, const QByteArray &data, Callback &&callback, Mode mode, int64 seekMs) | ||||||
| : _callback(std_::move(callback)) | : _callback(std_::move(callback)) | ||||||
| , _mode(mode) | , _mode(mode) | ||||||
| , _playId(rand_value<uint64>()) { | , _playId(rand_value<uint64>()) | ||||||
|  | , _seekPositionMs(seekMs) { | ||||||
| 	if (threads.size() < ClipThreadsCount) { | 	if (threads.size() < ClipThreadsCount) { | ||||||
| 		_threadIndex = threads.size(); | 		_threadIndex = threads.size(); | ||||||
| 		threads.push_back(new QThread()); | 		threads.push_back(new QThread()); | ||||||
|  | @ -269,7 +270,7 @@ int64 Reader::getPositionMs() const { | ||||||
| 	if (auto frame = frameToShow()) { | 	if (auto frame = frameToShow()) { | ||||||
| 		return frame->positionMs; | 		return frame->positionMs; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return _seekPositionMs; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int64 Reader::getDurationMs() const { | int64 Reader::getDurationMs() const { | ||||||
|  | @ -310,10 +311,12 @@ void Reader::stop() { | ||||||
| 
 | 
 | ||||||
| void Reader::error() { | void Reader::error() { | ||||||
| 	_state = State::Error; | 	_state = State::Error; | ||||||
|  | 	_private = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Reader::finished() { | void Reader::finished() { | ||||||
| 	_state = State::Finished; | 	_state = State::Finished; | ||||||
|  | 	_private = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Reader::~Reader() { | Reader::~Reader() { | ||||||
|  | @ -325,6 +328,7 @@ public: | ||||||
| 	ReaderPrivate(Reader *reader, const FileLocation &location, const QByteArray &data) : _interface(reader) | 	ReaderPrivate(Reader *reader, const FileLocation &location, const QByteArray &data) : _interface(reader) | ||||||
| 	, _mode(reader->mode()) | 	, _mode(reader->mode()) | ||||||
| 	, _playId(reader->playId()) | 	, _playId(reader->playId()) | ||||||
|  | 	, _seekPositionMs(reader->seekPositionMs()) | ||||||
| 	, _data(data) { | 	, _data(data) { | ||||||
| 		if (_data.isEmpty()) { | 		if (_data.isEmpty()) { | ||||||
| 			_location = std_::make_unique<FileLocation>(location); | 			_location = std_::make_unique<FileLocation>(location); | ||||||
|  | @ -337,7 +341,7 @@ public: | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ProcessResult start(uint64 ms) { | 	ProcessResult start(uint64 ms) { | ||||||
| 		if (!_implementation && !init()) { | 		if (!_implementation && !init(_seekPositionMs)) { | ||||||
| 			return error(); | 			return error(); | ||||||
| 		} | 		} | ||||||
| 		if (frame() && frame()->original.isNull()) { | 		if (frame() && frame()->original.isNull()) { | ||||||
|  | @ -348,6 +352,8 @@ public: | ||||||
| 			if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize())) { | 			if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize())) { | ||||||
| 				return error(); | 				return error(); | ||||||
| 			} | 			} | ||||||
|  | 			frame()->positionMs = _implementation->frameRealTime(); | ||||||
|  | 
 | ||||||
| 			_width = frame()->original.width(); | 			_width = frame()->original.width(); | ||||||
| 			_height = frame()->original.height(); | 			_height = frame()->original.height(); | ||||||
| 			_durationMs = _implementation->durationMs(); | 			_durationMs = _implementation->durationMs(); | ||||||
|  | @ -381,7 +387,7 @@ public: | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ProcessResult finishProcess(uint64 ms) { | 	ProcessResult finishProcess(uint64 ms) { | ||||||
| 		auto readResult = _implementation->readFramesTill(ms - _animationStarted); | 		auto readResult = _implementation->readFramesTill(_skippedMs + ms - _animationStarted); | ||||||
| 		if (readResult == internal::ReaderImplementation::ReadResult::Eof) { | 		if (readResult == internal::ReaderImplementation::ReadResult::Eof) { | ||||||
| 			stop(); | 			stop(); | ||||||
| 			_state = State::Finished; | 			_state = State::Finished; | ||||||
|  | @ -391,6 +397,11 @@ public: | ||||||
| 		} | 		} | ||||||
| 		_nextFramePositionMs = _implementation->frameRealTime(); | 		_nextFramePositionMs = _implementation->frameRealTime(); | ||||||
| 		_nextFrameWhen = _animationStarted + _implementation->framePresentationTime(); | 		_nextFrameWhen = _animationStarted + _implementation->framePresentationTime(); | ||||||
|  | 		if (static_cast<int64>(_nextFrameWhen) > _skippedMs) { | ||||||
|  | 			_nextFrameWhen -= _skippedMs; | ||||||
|  | 		} else { | ||||||
|  | 			_nextFrameWhen = 1; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!renderFrame()) { | 		if (!renderFrame()) { | ||||||
| 			return error(); | 			return error(); | ||||||
|  | @ -411,7 +422,7 @@ public: | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool init() { | 	bool init(int64 positionMs) { | ||||||
| 		if (_data.isEmpty() && QFileInfo(_location->name()).size() <= AnimationInMemory) { | 		if (_data.isEmpty() && QFileInfo(_location->name()).size() <= AnimationInMemory) { | ||||||
| 			QFile f(_location->name()); | 			QFile f(_location->name()); | ||||||
| 			if (f.open(QIODevice::ReadOnly)) { | 			if (f.open(QIODevice::ReadOnly)) { | ||||||
|  | @ -432,7 +443,8 @@ public: | ||||||
| 			} | 			} | ||||||
| 			return ImplementationMode::Normal; | 			return ImplementationMode::Normal; | ||||||
| 		}; | 		}; | ||||||
| 		return _implementation->start(implementationMode()); | 		_skippedMs = positionMs; | ||||||
|  | 		return _implementation->start(implementationMode(), positionMs); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void startedAt(uint64 ms) { | 	void startedAt(uint64 ms) { | ||||||
|  | @ -485,6 +497,7 @@ private: | ||||||
| 	State _state = State::Reading; | 	State _state = State::Reading; | ||||||
| 	Reader::Mode _mode; | 	Reader::Mode _mode; | ||||||
| 	uint64 _playId; | 	uint64 _playId; | ||||||
|  | 	int64 _seekPositionMs = 0; | ||||||
| 
 | 
 | ||||||
| 	QByteArray _data; | 	QByteArray _data; | ||||||
| 	std_::unique_ptr<FileLocation> _location; | 	std_::unique_ptr<FileLocation> _location; | ||||||
|  | @ -517,6 +530,7 @@ private: | ||||||
| 	uint64 _animationStarted = 0; | 	uint64 _animationStarted = 0; | ||||||
| 	uint64 _nextFrameWhen = 0; | 	uint64 _nextFrameWhen = 0; | ||||||
| 	int64 _nextFramePositionMs = 0; | 	int64 _nextFramePositionMs = 0; | ||||||
|  | 	int64 _skippedMs = 0; | ||||||
| 
 | 
 | ||||||
| 	bool _autoPausedGif = false; | 	bool _autoPausedGif = false; | ||||||
| 	bool _started = false; | 	bool _started = false; | ||||||
|  | @ -699,11 +713,12 @@ void Manager::process() { | ||||||
| 	_timer.stop(); | 	_timer.stop(); | ||||||
| 	_processingInThread = thread(); | 	_processingInThread = thread(); | ||||||
| 
 | 
 | ||||||
|  | 	bool checkAllReaders = false; | ||||||
| 	uint64 ms = getms(), minms = ms + 86400 * 1000ULL; | 	uint64 ms = getms(), minms = ms + 86400 * 1000ULL; | ||||||
| 	{ | 	{ | ||||||
| 		QReadLocker lock(&_readerPointersMutex); | 		QReadLocker lock(&_readerPointersMutex); | ||||||
| 		for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { | 		for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { | ||||||
| 			if (it->v.loadAcquire()) { | 			if (it->v.loadAcquire() && it.key()->_private != nullptr) { | ||||||
| 				auto i = _readers.find(it.key()->_private); | 				auto i = _readers.find(it.key()->_private); | ||||||
| 				if (i == _readers.cend()) { | 				if (i == _readers.cend()) { | ||||||
| 					_readers.insert(it.key()->_private, 0); | 					_readers.insert(it.key()->_private, 0); | ||||||
|  | @ -723,6 +738,7 @@ void Manager::process() { | ||||||
| 				it->v.storeRelease(0); | 				it->v.storeRelease(0); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		checkAllReaders = (_readers.size() > _readerPointers.size()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (auto i = _readers.begin(), e = _readers.end(); i != e;) { | 	for (auto i = _readers.begin(), e = _readers.end(); i != e;) { | ||||||
|  | @ -744,6 +760,15 @@ void Manager::process() { | ||||||
| 			} else { | 			} else { | ||||||
| 				i.value() = (ms + 86400 * 1000ULL); | 				i.value() = (ms + 86400 * 1000ULL); | ||||||
| 			} | 			} | ||||||
|  | 		} else if (checkAllReaders) { | ||||||
|  | 			QReadLocker lock(&_readerPointersMutex); | ||||||
|  | 			ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader); | ||||||
|  | 			if (it == _readerPointers.cend()) { | ||||||
|  | 				_loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : AverageGifSize)); | ||||||
|  | 				delete reader; | ||||||
|  | 				i = _readers.erase(i); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		if (!reader->_autoPausedGif && i.value() < minms) { | 		if (!reader->_autoPausedGif && i.value() < minms) { | ||||||
| 			minms = i.value(); | 			minms = i.value(); | ||||||
|  | @ -771,7 +796,7 @@ void Manager::clear() { | ||||||
| 	{ | 	{ | ||||||
| 		QWriteLocker lock(&_readerPointersMutex); | 		QWriteLocker lock(&_readerPointersMutex); | ||||||
| 		for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { | 		for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { | ||||||
| 			it.key()->_private = 0; | 			it.key()->_private = nullptr; | ||||||
| 		} | 		} | ||||||
| 		_readerPointers.clear(); | 		_readerPointers.clear(); | ||||||
| 	} | 	} | ||||||
|  | @ -792,7 +817,7 @@ MTPDocumentAttribute readAttributes(const QString &fname, const QByteArray &data | ||||||
| 
 | 
 | ||||||
| 	auto playId = 0ULL; | 	auto playId = 0ULL; | ||||||
| 	auto reader = std_::make_unique<internal::FFMpegReaderImplementation>(&localloc, &localdata, playId); | 	auto reader = std_::make_unique<internal::FFMpegReaderImplementation>(&localloc, &localdata, playId); | ||||||
| 	if (reader->start(internal::ReaderImplementation::Mode::OnlyGifv)) { | 	if (reader->start(internal::ReaderImplementation::Mode::OnlyGifv, 0)) { | ||||||
| 		bool hasAlpha = false; | 		bool hasAlpha = false; | ||||||
| 		auto readResult = reader->readFramesTill(-1); | 		auto readResult = reader->readFramesTill(-1); | ||||||
| 		auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success); | 		auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success); | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ public: | ||||||
| 		Video, | 		Video, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	Reader(const FileLocation &location, const QByteArray &data, Callback &&callback, Mode mode = Mode::Gif); | 	Reader(const FileLocation &location, const QByteArray &data, Callback &&callback, Mode mode = Mode::Gif, int64 seekMs = 0); | ||||||
| 	static void callback(Reader *reader, int threadIndex, Notification notification); // reader can be deleted
 | 	static void callback(Reader *reader, int threadIndex, Notification notification); // reader can be deleted
 | ||||||
| 
 | 
 | ||||||
| 	void setAutoplay() { | 	void setAutoplay() { | ||||||
|  | @ -71,6 +71,9 @@ public: | ||||||
| 	uint64 playId() const { | 	uint64 playId() const { | ||||||
| 		return _playId; | 		return _playId; | ||||||
| 	} | 	} | ||||||
|  | 	int64 seekPositionMs() const { | ||||||
|  | 		return _seekPositionMs; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	void start(int framew, int frameh, int outerw, int outerh, bool rounded); | 	void start(int framew, int frameh, int outerw, int outerh, bool rounded); | ||||||
| 	QPixmap current(int framew, int frameh, int outerw, int outerh, uint64 ms); | 	QPixmap current(int framew, int frameh, int outerw, int outerh, uint64 ms); | ||||||
|  | @ -128,6 +131,7 @@ private: | ||||||
| 	uint64 _playId; | 	uint64 _playId; | ||||||
| 	bool _hasAudio = false; | 	bool _hasAudio = false; | ||||||
| 	int64 _durationMs = 0; | 	int64 _durationMs = 0; | ||||||
|  | 	int64 _seekPositionMs = 0; | ||||||
| 
 | 
 | ||||||
| 	mutable int _width = 0; | 	mutable int _width = 0; | ||||||
| 	mutable int _height = 0; | 	mutable int _height = 0; | ||||||
|  |  | ||||||
|  | @ -48,19 +48,29 @@ Controller::Controller(QWidget *parent) : TWidget(parent) | ||||||
| 
 | 
 | ||||||
| 	connect(_playPauseResume, SIGNAL(clicked()), this, SIGNAL(playPressed())); | 	connect(_playPauseResume, SIGNAL(clicked()), this, SIGNAL(playPressed())); | ||||||
| 	connect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); | 	connect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); | ||||||
| 	connect(_playback, SIGNAL(seekProgress(int64)), this, SLOT(onSeekProgress(int64))); | 	connect(_playback, SIGNAL(seekProgress(float64)), this, SLOT(onSeekProgress(float64))); | ||||||
| 	connect(_playback, SIGNAL(seekFinished(int64)), this, SLOT(onSeekFinished(int64))); | 	connect(_playback, SIGNAL(seekFinished(float64)), this, SLOT(onSeekFinished(float64))); | ||||||
| 	connect(_volumeController, SIGNAL(volumeChanged(float64)), this, SIGNAL(volumeChanged(float64))); | 	connect(_volumeController, SIGNAL(volumeChanged(float64)), this, SIGNAL(volumeChanged(float64))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Controller::onSeekProgress(int64 position) { | void Controller::onSeekProgress(float64 progress) { | ||||||
| 	_seekPosition = position; | 	if (!_lastDurationMs) return; | ||||||
| 	emit seekProgress(position); | 
 | ||||||
|  | 	auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs); | ||||||
|  | 	if (_seekPositionMs != positionMs) { | ||||||
|  | 		_seekPositionMs = positionMs; | ||||||
|  | 		emit seekProgress(positionMs); | ||||||
|  | 		refreshTimeTexts(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Controller::onSeekFinished(int64 position) { | void Controller::onSeekFinished(float64 progress) { | ||||||
| 	_seekPosition = -1; | 	if (!_lastDurationMs) return; | ||||||
| 	emit seekFinished(position); | 
 | ||||||
|  | 	auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs); | ||||||
|  | 	_seekPositionMs = -1; | ||||||
|  | 	emit seekFinished(positionMs); | ||||||
|  | 	refreshTimeTexts(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Controller::showAnimated() { | void Controller::showAnimated() { | ||||||
|  | @ -89,14 +99,14 @@ void Controller::fadeUpdated(float64 opacity) { | ||||||
| 	_playback->setFadeOpacity(opacity); | 	_playback->setFadeOpacity(opacity); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Controller::updatePlayback(const AudioPlaybackState &playbackState) { | void Controller::updatePlayback(const AudioPlaybackState &playbackState, bool reset) { | ||||||
| 	updatePlayPauseResumeState(playbackState); | 	updatePlayPauseResumeState(playbackState); | ||||||
| 	_playback->updateState(playbackState); | 	_playback->updateState(playbackState, reset); | ||||||
| 	updateTimeTexts(playbackState); | 	updateTimeTexts(playbackState); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackState) { | void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackState) { | ||||||
| 	bool showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming); | 	bool showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || _seekPositionMs >= 0); | ||||||
| 	if (showPause != _showPause) { | 	if (showPause != _showPause) { | ||||||
| 		disconnect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); | 		disconnect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); | ||||||
| 		_showPause = showPause; | 		_showPause = showPause; | ||||||
|  | @ -120,11 +130,30 @@ void Controller::updateTimeTexts(const AudioPlaybackState &playbackState) { | ||||||
| 	auto playAlready = position / playFrequency; | 	auto playAlready = position / playFrequency; | ||||||
| 	auto playLeft = (playbackState.duration / playFrequency) - playAlready; | 	auto playLeft = (playbackState.duration / playFrequency) - playAlready; | ||||||
| 
 | 
 | ||||||
| 	auto timeAlready = formatDurationText(playAlready); | 	_lastDurationMs = (playbackState.duration * 1000LL) / playFrequency; | ||||||
| 	auto minus = QChar(8722); |  | ||||||
| 	auto timeLeft = minus + formatDurationText(playLeft); |  | ||||||
| 
 | 
 | ||||||
|  | 	_timeAlready = formatDurationText(playAlready); | ||||||
|  | 	auto minus = QChar(8722); | ||||||
|  | 	_timeLeft = minus + formatDurationText(playLeft); | ||||||
|  | 
 | ||||||
|  | 	if (_seekPositionMs < 0) { | ||||||
|  | 		refreshTimeTexts(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Controller::refreshTimeTexts() { | ||||||
| 	auto alreadyChanged = false, leftChanged = false; | 	auto alreadyChanged = false, leftChanged = false; | ||||||
|  | 	auto timeAlready = _timeAlready; | ||||||
|  | 	auto timeLeft = _timeLeft; | ||||||
|  | 	if (_seekPositionMs >= 0) { | ||||||
|  | 		auto playAlready = _seekPositionMs / 1000LL; | ||||||
|  | 		auto playLeft = (_lastDurationMs / 1000LL) - playAlready; | ||||||
|  | 
 | ||||||
|  | 		timeAlready = formatDurationText(playAlready); | ||||||
|  | 		auto minus = QChar(8722); | ||||||
|  | 		timeLeft = minus + formatDurationText(playLeft); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	_playedAlready->setText(timeAlready, &alreadyChanged); | 	_playedAlready->setText(timeAlready, &alreadyChanged); | ||||||
| 	_toPlayLeft->setText(timeLeft, &leftChanged); | 	_toPlayLeft->setText(timeLeft, &leftChanged); | ||||||
| 	if (alreadyChanged || leftChanged) { | 	if (alreadyChanged || leftChanged) { | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ public: | ||||||
| 	void showAnimated(); | 	void showAnimated(); | ||||||
| 	void hideAnimated(); | 	void hideAnimated(); | ||||||
| 
 | 
 | ||||||
| 	void updatePlayback(const AudioPlaybackState &playbackState); | 	void updatePlayback(const AudioPlaybackState &playbackState, bool reset); | ||||||
| 	void setInFullScreen(bool inFullScreen); | 	void setInFullScreen(bool inFullScreen); | ||||||
| 
 | 
 | ||||||
| 	void grabStart() override; | 	void grabStart() override; | ||||||
|  | @ -52,15 +52,15 @@ public: | ||||||
| signals: | signals: | ||||||
| 	void playPressed(); | 	void playPressed(); | ||||||
| 	void pausePressed(); | 	void pausePressed(); | ||||||
| 	void seekProgress(int64 position); | 	void seekProgress(int64 positionMs); | ||||||
| 	void seekFinished(int64 position); | 	void seekFinished(int64 positionMs); | ||||||
| 	void volumeChanged(float64 volume); | 	void volumeChanged(float64 volume); | ||||||
| 	void toFullScreenPressed(); | 	void toFullScreenPressed(); | ||||||
| 	void fromFullScreenPressed(); | 	void fromFullScreenPressed(); | ||||||
| 
 | 
 | ||||||
| private slots: | private slots: | ||||||
| 	void onSeekProgress(int64 position); | 	void onSeekProgress(float64 progress); | ||||||
| 	void onSeekFinished(int64 position); | 	void onSeekFinished(float64 progress); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void resizeEvent(QResizeEvent *e) override; | 	void resizeEvent(QResizeEvent *e) override; | ||||||
|  | @ -75,9 +75,12 @@ private: | ||||||
| 
 | 
 | ||||||
| 	void updatePlayPauseResumeState(const AudioPlaybackState &playbackState); | 	void updatePlayPauseResumeState(const AudioPlaybackState &playbackState); | ||||||
| 	void updateTimeTexts(const AudioPlaybackState &playbackState); | 	void updateTimeTexts(const AudioPlaybackState &playbackState); | ||||||
|  | 	void refreshTimeTexts(); | ||||||
| 
 | 
 | ||||||
| 	bool _showPause = false; | 	bool _showPause = false; | ||||||
| 	int64 _seekPosition = -1; | 	QString _timeAlready, _timeLeft; | ||||||
|  | 	int64 _seekPositionMs = -1; | ||||||
|  | 	int64 _lastDurationMs = 0; | ||||||
| 
 | 
 | ||||||
| 	ChildWidget<Ui::IconButton> _playPauseResume; | 	ChildWidget<Ui::IconButton> _playPauseResume; | ||||||
| 	ChildWidget<Playback> _playback; | 	ChildWidget<Playback> _playback; | ||||||
|  |  | ||||||
|  | @ -32,11 +32,11 @@ Playback::Playback(QWidget *parent) : TWidget(parent) | ||||||
| 	setCursor(style::cur_pointer); | 	setCursor(style::cur_pointer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Playback::updateState(const AudioPlaybackState &playbackState) { | void Playback::updateState(const AudioPlaybackState &playbackState, bool reset) { | ||||||
| 	qint64 position = 0, duration = playbackState.duration; | 	qint64 position = 0, duration = playbackState.duration; | ||||||
| 
 | 
 | ||||||
| 	_playing = !(playbackState.state & AudioPlayerStoppedMask); | 	_playing = !(playbackState.state & AudioPlayerStoppedMask); | ||||||
| 	if (_playing && playbackState.state != AudioPlayerFinishing) { | 	if (_playing || playbackState.state == AudioPlayerStopped) { | ||||||
| 		position = playbackState.position; | 		position = playbackState.position; | ||||||
| 	} else if (playbackState.state == AudioPlayerStoppedAtEnd) { | 	} else if (playbackState.state == AudioPlayerStoppedAtEnd) { | ||||||
| 		position = playbackState.duration; | 		position = playbackState.duration; | ||||||
|  | @ -51,7 +51,7 @@ void Playback::updateState(const AudioPlaybackState &playbackState) { | ||||||
| 		progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.; | 		progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.; | ||||||
| 	} | 	} | ||||||
| 	if (duration != _duration || position != _position) { | 	if (duration != _duration || position != _position) { | ||||||
| 		if (duration && _duration && playbackState.state != AudioPlayerStopped) { | 		if (duration && _duration && !reset) { | ||||||
| 			a_progress.start(progress); | 			a_progress.start(progress); | ||||||
| 			_a_progress.start(); | 			_a_progress.start(); | ||||||
| 		} else { | 		} else { | ||||||
|  | @ -112,12 +112,26 @@ void Playback::paintEvent(QPaintEvent *e) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Playback::mouseMoveEvent(QMouseEvent *e) { | void Playback::mouseMoveEvent(QMouseEvent *e) { | ||||||
|  | 	if (_mouseDown) { | ||||||
|  | 		_downProgress = snap(e->pos().x() / float64(width()), 0., 1.); | ||||||
|  | 		emit seekProgress(_downProgress); | ||||||
|  | 		update(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Playback::mousePressEvent(QMouseEvent *e) { | void Playback::mousePressEvent(QMouseEvent *e) { | ||||||
|  | 	_mouseDown = true; | ||||||
|  | 	_downProgress = snap(e->pos().x() / float64(width()), 0., 1.); | ||||||
|  | 	emit seekProgress(_downProgress); | ||||||
|  | 	update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Playback::mouseReleaseEvent(QMouseEvent *e) { | void Playback::mouseReleaseEvent(QMouseEvent *e) { | ||||||
|  | 	if (_mouseDown) { | ||||||
|  | 		_mouseDown = false; | ||||||
|  | 		emit seekFinished(_downProgress); | ||||||
|  | 		update(); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Playback::enterEvent(QEvent *e) { | void Playback::enterEvent(QEvent *e) { | ||||||
|  |  | ||||||
|  | @ -31,12 +31,12 @@ class Playback : public TWidget { | ||||||
| public: | public: | ||||||
| 	Playback(QWidget *parent); | 	Playback(QWidget *parent); | ||||||
| 
 | 
 | ||||||
| 	void updateState(const AudioPlaybackState &playbackState); | 	void updateState(const AudioPlaybackState &playbackState, bool reset); | ||||||
| 	void setFadeOpacity(float64 opacity); | 	void setFadeOpacity(float64 opacity); | ||||||
| 
 | 
 | ||||||
| signals: | signals: | ||||||
| 	void seekProgress(int64 position); | 	void seekProgress(float64 progress); | ||||||
| 	void seekFinished(int64 position); | 	void seekFinished(float64 progress); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void paintEvent(QPaintEvent *e) override; | 	void paintEvent(QPaintEvent *e) override; | ||||||
|  |  | ||||||
|  | @ -236,6 +236,7 @@ bool MediaView::gifShown() const { | ||||||
| 
 | 
 | ||||||
| void MediaView::stopGif() { | void MediaView::stopGif() { | ||||||
| 	_gif = nullptr; | 	_gif = nullptr; | ||||||
|  | 	_videoPaused = _videoIsSilent = false; | ||||||
| 	_clipController.destroy(); | 	_clipController.destroy(); | ||||||
| 	Sandbox::removeEventFilter(this); | 	Sandbox::removeEventFilter(this); | ||||||
| 	if (audioPlayer()) { | 	if (audioPlayer()) { | ||||||
|  | @ -1121,7 +1122,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty | ||||||
| 				const FileLocation &location(_doc->location(true)); | 				const FileLocation &location(_doc->location(true)); | ||||||
| 				if (location.accessEnable()) { | 				if (location.accessEnable()) { | ||||||
| 					if (QImageReader(location.name()).canRead()) { | 					if (QImageReader(location.name()).canRead()) { | ||||||
| 						_current = QPixmap::fromImage(App::readImage(location.name(), 0, false), Qt::ColorOnly); | 						_current = App::pixmapFromImageInPlace(App::readImage(location.name(), 0, false)); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				location.accessDisable(); | 				location.accessDisable(); | ||||||
|  | @ -1258,7 +1259,7 @@ void MediaView::createClipReader() { | ||||||
| 	_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); | 	_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); | ||||||
| 
 | 
 | ||||||
| 	// Correct values will be set when gif gets inited.
 | 	// Correct values will be set when gif gets inited.
 | ||||||
| 	_videoIsSilent = false; | 	_videoPaused = _videoIsSilent = false; | ||||||
| 	_videoPositionMs = 0ULL; | 	_videoPositionMs = 0ULL; | ||||||
| 	_videoDurationMs = _doc->duration() * 1000ULL; | 	_videoDurationMs = _doc->duration() * 1000ULL; | ||||||
| 
 | 
 | ||||||
|  | @ -1306,21 +1307,7 @@ void MediaView::onVideoPauseResume() { | ||||||
| 		if (_gif->state() == Media::Clip::State::Error) { | 		if (_gif->state() == Media::Clip::State::Error) { | ||||||
| 			displayDocument(_doc, item); | 			displayDocument(_doc, item); | ||||||
| 		} else if (_gif->state() == Media::Clip::State::Finished) { | 		} else if (_gif->state() == Media::Clip::State::Finished) { | ||||||
| 			_autoplayVideoDocument = _doc; | 			restartVideoAtSeekPosition(0); | ||||||
| 
 |  | ||||||
| 			_current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); |  | ||||||
| 			_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video); |  | ||||||
| 
 |  | ||||||
| 			// Correct values will be set when gif gets inited.
 |  | ||||||
| 			_videoIsSilent = false; |  | ||||||
| 			_videoPositionMs = 0; |  | ||||||
| 
 |  | ||||||
| 			AudioPlaybackState state; |  | ||||||
| 			state.state = AudioPlayerStopped; |  | ||||||
| 			state.position = _videoPositionMs; |  | ||||||
| 			state.duration = _videoDurationMs; |  | ||||||
| 			state.frequency = _videoFrequencyMs; |  | ||||||
| 			updateVideoPlaybackState(state); |  | ||||||
| 		} else { | 		} else { | ||||||
| 			_gif->pauseResumeVideo(); | 			_gif->pauseResumeVideo(); | ||||||
| 			_videoPaused = _gif->videoPaused(); | 			_videoPaused = _gif->videoPaused(); | ||||||
|  | @ -1333,12 +1320,34 @@ void MediaView::onVideoPauseResume() { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaView::onVideoSeekProgress(int64 position) { | void MediaView::restartVideoAtSeekPosition(int64 positionMs) { | ||||||
|  | 	_autoplayVideoDocument = _doc; | ||||||
| 
 | 
 | ||||||
|  | 	if (_current.isNull()) { | ||||||
|  | 		_current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); | ||||||
|  | 	} | ||||||
|  | 	_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video, positionMs); | ||||||
|  | 
 | ||||||
|  | 	// Correct values will be set when gif gets inited.
 | ||||||
|  | 	_videoPaused = _videoIsSilent = false; | ||||||
|  | 	_videoPositionMs = positionMs; | ||||||
|  | 
 | ||||||
|  | 	AudioPlaybackState state; | ||||||
|  | 	state.state = AudioPlayerPlaying; | ||||||
|  | 	state.position = _videoPositionMs; | ||||||
|  | 	state.duration = _videoDurationMs; | ||||||
|  | 	state.frequency = _videoFrequencyMs; | ||||||
|  | 	updateVideoPlaybackState(state, true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaView::onVideoSeekFinished(int64 position) { | void MediaView::onVideoSeekProgress(int64 positionMs) { | ||||||
|  | 	if (!_videoPaused) { | ||||||
|  | 		onVideoPauseResume(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | void MediaView::onVideoSeekFinished(int64 positionMs) { | ||||||
|  | 	restartVideoAtSeekPosition(positionMs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaView::onVideoVolumeChanged(float64 volume) { | void MediaView::onVideoVolumeChanged(float64 volume) { | ||||||
|  | @ -1361,12 +1370,14 @@ void MediaView::onVideoPlayProgress(const AudioMsgId &audioId) { | ||||||
| 
 | 
 | ||||||
| 	t_assert(audioPlayer() != nullptr); | 	t_assert(audioPlayer() != nullptr); | ||||||
| 	auto state = audioPlayer()->currentVideoState(_gif->playId()); | 	auto state = audioPlayer()->currentVideoState(_gif->playId()); | ||||||
| 	updateVideoPlaybackState(state); | 	if (state.duration) { | ||||||
|  | 		updateVideoPlaybackState(state); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaView::updateVideoPlaybackState(const AudioPlaybackState &state) { | void MediaView::updateVideoPlaybackState(const AudioPlaybackState &state, bool reset) { | ||||||
| 	if (state.frequency) { | 	if (state.frequency) { | ||||||
| 		_clipController->updatePlayback(state); | 		_clipController->updatePlayback(state, reset); | ||||||
| 	} else { // Audio has stopped already.
 | 	} else { // Audio has stopped already.
 | ||||||
| 		_videoIsSilent = true; | 		_videoIsSilent = true; | ||||||
| 		updateSilentVideoPlaybackState(); | 		updateSilentVideoPlaybackState(); | ||||||
|  |  | ||||||
|  | @ -118,8 +118,8 @@ protected: | ||||||
| 
 | 
 | ||||||
| private slots: | private slots: | ||||||
| 	void onVideoPauseResume(); | 	void onVideoPauseResume(); | ||||||
| 	void onVideoSeekProgress(int64 position); | 	void onVideoSeekProgress(int64 positionMs); | ||||||
| 	void onVideoSeekFinished(int64 position); | 	void onVideoSeekFinished(int64 positionMs); | ||||||
| 	void onVideoVolumeChanged(float64 volume); | 	void onVideoVolumeChanged(float64 volume); | ||||||
| 	void onVideoToFullScreen(); | 	void onVideoToFullScreen(); | ||||||
| 	void onVideoFromFullScreen(); | 	void onVideoFromFullScreen(); | ||||||
|  | @ -131,8 +131,9 @@ private: | ||||||
| 	void findCurrent(); | 	void findCurrent(); | ||||||
| 	void loadBack(); | 	void loadBack(); | ||||||
| 
 | 
 | ||||||
| 	void updateVideoPlaybackState(const AudioPlaybackState &state); | 	void updateVideoPlaybackState(const AudioPlaybackState &state, bool reset = false); | ||||||
| 	void updateSilentVideoPlaybackState(); | 	void updateSilentVideoPlaybackState(); | ||||||
|  | 	void restartVideoAtSeekPosition(int64 positionMs); | ||||||
| 
 | 
 | ||||||
| 	void createClipController(); | 	void createClipController(); | ||||||
| 	void setClipControllerGeometry(); | 	void setClipControllerGeometry(); | ||||||
|  |  | ||||||
|  | @ -105,9 +105,10 @@ void FileLoader::readImage(const QSize &shrinkBox) const { | ||||||
| 	QImage image = App::readImage(_data, &format, false); | 	QImage image = App::readImage(_data, &format, false); | ||||||
| 	if (!image.isNull()) { | 	if (!image.isNull()) { | ||||||
| 		if (!shrinkBox.isEmpty() && (image.width() > shrinkBox.width() || image.height() > shrinkBox.height())) { | 		if (!shrinkBox.isEmpty() && (image.width() > shrinkBox.width() || image.height() > shrinkBox.height())) { | ||||||
| 			image = image.scaled(shrinkBox, Qt::KeepAspectRatio, Qt::SmoothTransformation); | 			_imagePixmap = App::pixmapFromImageInPlace(image.scaled(shrinkBox, Qt::KeepAspectRatio, Qt::SmoothTransformation)); | ||||||
|  | 		} else { | ||||||
|  | 			_imagePixmap = App::pixmapFromImageInPlace(std_::move(image)); | ||||||
| 		} | 		} | ||||||
| 		_imagePixmap = QPixmap::fromImage(image, Qt::ColorOnly); |  | ||||||
| 		_imageFormat = format; | 		_imageFormat = format; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -202,7 +202,7 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const | ||||||
| 			img.setDevicePixelRatio(cRetinaFactor()); | 			img.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 			_data->forget(); | 			_data->forget(); | ||||||
| 
 | 
 | ||||||
| 			_pix = QPixmap::fromImage(img, Qt::ColorOnly); | 			_pix = App::pixmapFromImageInPlace(std_::move(img)); | ||||||
| 		} else if (!_pix.isNull()) { | 		} else if (!_pix.isNull()) { | ||||||
| 			_pix = QPixmap(); | 			_pix = QPixmap(); | ||||||
| 		} | 		} | ||||||
|  | @ -274,7 +274,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const | ||||||
| 			img.setDevicePixelRatio(cRetinaFactor()); | 			img.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 			_data->forget(); | 			_data->forget(); | ||||||
| 
 | 
 | ||||||
| 			_pix = QPixmap::fromImage(img, Qt::ColorOnly); | 			_pix = App::pixmapFromImageInPlace(std_::move(img)); | ||||||
| 		} else if (!_pix.isNull()) { | 		} else if (!_pix.isNull()) { | ||||||
| 			_pix = QPixmap(); | 			_pix = QPixmap(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -360,8 +360,8 @@ void MainWindow::psUpdateCounter() { | ||||||
| 			bool muted = App::histories().unreadOnlyMuted(); | 			bool muted = App::histories().unreadOnlyMuted(); | ||||||
| 
 | 
 | ||||||
| 			style::color bg = muted ? st::counterMuteBG : st::counterBG; | 			style::color bg = muted ? st::counterMuteBG : st::counterBG; | ||||||
| 			icon.addPixmap(QPixmap::fromImage(iconWithCounter(16, counter, bg, true), Qt::ColorOnly)); | 			icon.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(16, counter, bg, true), Qt::ColorOnly)); | ||||||
| 			icon.addPixmap(QPixmap::fromImage(iconWithCounter(32, counter, bg, true), Qt::ColorOnly)); | 			icon.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(32, counter, bg, true), Qt::ColorOnly)); | ||||||
| 		} | 		} | ||||||
| 		trayIcon->setIcon(icon); | 		trayIcon->setIcon(icon); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -212,8 +212,8 @@ void MainWindow::psUpdateCounter() { | ||||||
| 		int32 size = cRetina() ? 44 : 22; | 		int32 size = cRetina() ? 44 : 22; | ||||||
| 		_placeCounter(img, size, counter, bg, (dm && muted) ? st::counterMacInvColor : st::counterColor); | 		_placeCounter(img, size, counter, bg, (dm && muted) ? st::counterMacInvColor : st::counterColor); | ||||||
| 		_placeCounter(imgsel, size, counter, st::white, st::counterMacInvColor); | 		_placeCounter(imgsel, size, counter, st::white, st::counterMacInvColor); | ||||||
| 		icon.addPixmap(QPixmap::fromImage(img, Qt::ColorOnly)); | 		icon.addPixmap(App::pixmapFromImageInPlace(std_::move(img))); | ||||||
| 		icon.addPixmap(QPixmap::fromImage(imgsel, Qt::ColorOnly), QIcon::Selected); | 		icon.addPixmap(App::pixmapFromImageInPlace(std_::move(imgsel)), QIcon::Selected); | ||||||
| 		trayIcon->setIcon(icon); | 		trayIcon->setIcon(icon); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -736,10 +736,10 @@ void MainWindow::psUpdateCounter() { | ||||||
| 
 | 
 | ||||||
| 	style::color bg = muted ? st::counterMuteBG : st::counterBG; | 	style::color bg = muted ? st::counterMuteBG : st::counterBG; | ||||||
| 	QIcon iconSmall, iconBig; | 	QIcon iconSmall, iconBig; | ||||||
| 	iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(16, counter, bg, true), Qt::ColorOnly)); | 	iconSmall.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(16, counter, bg, true))); | ||||||
| 	iconSmall.addPixmap(QPixmap::fromImage(iconWithCounter(32, counter, bg, true), Qt::ColorOnly)); | 	iconSmall.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(32, counter, bg, true))); | ||||||
| 	iconBig.addPixmap(QPixmap::fromImage(iconWithCounter(32, taskbarList.Get() ? 0 : counter, bg, false), Qt::ColorOnly)); | 	iconBig.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(32, taskbarList.Get() ? 0 : counter, bg, false))); | ||||||
| 	iconBig.addPixmap(QPixmap::fromImage(iconWithCounter(64, taskbarList.Get() ? 0 : counter, bg, false), Qt::ColorOnly)); | 	iconBig.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(64, taskbarList.Get() ? 0 : counter, bg, false))); | ||||||
| 	if (trayIcon) { | 	if (trayIcon) { | ||||||
| 		trayIcon->setIcon(iconSmall); | 		trayIcon->setIcon(iconSmall); | ||||||
| 	} | 	} | ||||||
|  | @ -753,8 +753,8 @@ void MainWindow::psUpdateCounter() { | ||||||
| 	if (taskbarList.Get()) { | 	if (taskbarList.Get()) { | ||||||
| 		if (counter > 0) { | 		if (counter > 0) { | ||||||
| 			QIcon iconOverlay; | 			QIcon iconOverlay; | ||||||
| 			iconOverlay.addPixmap(QPixmap::fromImage(iconWithCounter(-16, counter, bg, false), Qt::ColorOnly)); | 			iconOverlay.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(-16, counter, bg, false))); | ||||||
| 			iconOverlay.addPixmap(QPixmap::fromImage(iconWithCounter(-32, counter, bg, false), Qt::ColorOnly)); | 			iconOverlay.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(-32, counter, bg, false))); | ||||||
| 			ps_iconOverlay = createHIconFromQIcon(iconOverlay, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); | 			ps_iconOverlay = createHIconFromQIcon(iconOverlay, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); | ||||||
| 		} | 		} | ||||||
| 		QString description = counter > 0 ? QString("%1 unread messages").arg(counter) : qsl("No unread messages"); | 		QString description = counter > 0 ? QString("%1 unread messages").arg(counter) : qsl("No unread messages"); | ||||||
|  |  | ||||||
|  | @ -585,7 +585,7 @@ namespace { | ||||||
| 			if (!iconindex) { // try to read image
 | 			if (!iconindex) { // try to read image
 | ||||||
| 				QImage img(QString::fromWCharArray(icon)); | 				QImage img(QString::fromWCharArray(icon)); | ||||||
| 				if (!img.isNull()) { | 				if (!img.isNull()) { | ||||||
| 					return qt_pixmapToWinHBITMAP(QPixmap::fromImage(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), /* HBitmapAlpha */ 2); | 					return qt_pixmapToWinHBITMAP(App::pixmapFromImageInPlace(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), /* HBitmapAlpha */ 2); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
|  | @ -1753,7 +1753,7 @@ void SettingsInner::updateChatBackground() { | ||||||
| 		p.setRenderHint(QPainter::SmoothPixmapTransform); | 		p.setRenderHint(QPainter::SmoothPixmapTransform); | ||||||
| 		p.drawPixmap(0, 0, st::setBackgroundSize, st::setBackgroundSize, pix, sx, sy, s, s); | 		p.drawPixmap(0, 0, st::setBackgroundSize, st::setBackgroundSize, pix, sx, sy, s, s); | ||||||
| 	} | 	} | ||||||
| 	_background = QPixmap::fromImage(back); | 	_background = App::pixmapFromImageInPlace(std_::move(back)); | ||||||
| 	_background.setDevicePixelRatio(cRetinaFactor()); | 	_background.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	_needBackgroundUpdate = false; | 	_needBackgroundUpdate = false; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -220,7 +220,7 @@ void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer a | ||||||
| 		newPhotoId = 0; | 		newPhotoId = 0; | ||||||
| 		if (id == ServiceUserId) { | 		if (id == ServiceUserId) { | ||||||
| 			if (_userpic.v() == userDefPhoto(colorIndex).v()) { | 			if (_userpic.v() == userDefPhoto(colorIndex).v()) { | ||||||
| 				newPhoto = ImagePtr(QPixmap::fromImage(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation), Qt::ColorOnly), "PNG"); | 				newPhoto = ImagePtr(App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation)), "PNG"); | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			newPhoto = userDefPhoto(colorIndex); | 			newPhoto = userDefPhoto(colorIndex); | ||||||
|  | @ -299,12 +299,11 @@ void UserData::setBotInfoVersion(int version) { | ||||||
| 				botInfo->commands.clear(); | 				botInfo->commands.clear(); | ||||||
| 				Notify::botCommandsChanged(this); | 				Notify::botCommandsChanged(this); | ||||||
| 			} | 			} | ||||||
| 			delete botInfo; | 			botInfo = nullptr; | ||||||
| 			botInfo = 0; |  | ||||||
| 			Notify::userIsBotChanged(this); | 			Notify::userIsBotChanged(this); | ||||||
| 		} | 		} | ||||||
| 	} else if (!botInfo) { | 	} else if (!botInfo) { | ||||||
| 		botInfo = new BotInfo(); | 		botInfo = std_::make_unique<BotInfo>(); | ||||||
| 		botInfo->version = version; | 		botInfo->version = version; | ||||||
| 		Notify::userIsBotChanged(this); | 		Notify::userIsBotChanged(this); | ||||||
| 	} else if (botInfo->version < version) { | 	} else if (botInfo->version < version) { | ||||||
|  |  | ||||||
|  | @ -471,7 +471,7 @@ public: | ||||||
| 		return _about; | 		return _about; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BotInfo *botInfo = nullptr; | 	std_::unique_ptr<BotInfo> botInfo; | ||||||
| 
 | 
 | ||||||
| 	QString restrictionReason() const override { | 	QString restrictionReason() const override { | ||||||
| 		return _restrictionReason; | 		return _restrictionReason; | ||||||
|  |  | ||||||
|  | @ -279,7 +279,7 @@ void TitleWidget::updateCounter() { | ||||||
| 		case dbisOneAndHalf: size = -24; break; | 		case dbisOneAndHalf: size = -24; break; | ||||||
| 		case dbisTwo: size = -32; break; | 		case dbisTwo: size = -32; break; | ||||||
| 		} | 		} | ||||||
| 		_counter = QPixmap::fromImage(App::wnd()->iconWithCounter(size, counter, bg, false), Qt::ColorOnly); | 		_counter = App::pixmapFromImageInPlace(App::wnd()->iconWithCounter(size, counter, bg, false)); | ||||||
| 		_counter.setDevicePixelRatio(cRetinaFactor()); | 		_counter.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		update(QRect(st::titleIconPos, st::titleIconImg.pxSize())); | 		update(QRect(st::titleIconPos, st::titleIconImg.pxSize())); | ||||||
| 	} else { | 	} else { | ||||||
|  |  | ||||||
|  | @ -56,8 +56,6 @@ BoxShadow::BoxShadow(const style::sprite &topLeft) : _size(topLeft.pxWidth()), _ | ||||||
| 		m.setDevicePixelRatio(cRetinaFactor()); | 		m.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		p.drawImage(_size, 0, m, _pixsize, 0, _pixsize, _pixsize * 2); | 		p.drawImage(_size, 0, m, _pixsize, 0, _pixsize, _pixsize * 2); | ||||||
| 	} | 	} | ||||||
| 	_corners = QPixmap::fromImage(cornersImage, Qt::ColorOnly); |  | ||||||
| 	_corners.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 	_colors.reserve(_pixsize); | 	_colors.reserve(_pixsize); | ||||||
| 	uchar prev = 0; | 	uchar prev = 0; | ||||||
| 	for (int i = 0; i < _pixsize; ++i) { | 	for (int i = 0; i < _pixsize; ++i) { | ||||||
|  | @ -68,15 +66,17 @@ BoxShadow::BoxShadow(const style::sprite &topLeft) : _size(topLeft.pxWidth()), _ | ||||||
| 		prev = a; | 		prev = a; | ||||||
| 	} | 	} | ||||||
| 	if (cRetina()) { | 	if (cRetina()) { | ||||||
| 		_left = QPixmap::fromImage(cornersImage.copy(0, _pixsize - 1, _colors.size(), 1), Qt::ColorOnly); | 		_left = App::pixmapFromImageInPlace(cornersImage.copy(0, _pixsize - 1, _colors.size(), 1)); | ||||||
| 		_left.setDevicePixelRatio(cRetinaFactor()); | 		_left.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		_top = QPixmap::fromImage(cornersImage.copy(_pixsize - 1, 0, 1, _colors.size()), Qt::ColorOnly); | 		_top = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize - 1, 0, 1, _colors.size())); | ||||||
| 		_top.setDevicePixelRatio(cRetinaFactor()); | 		_top.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		_right = QPixmap::fromImage(cornersImage.copy(_pixsize * 2 - _colors.size(), _pixsize, _colors.size(), 1), Qt::ColorOnly); | 		_right = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize * 2 - _colors.size(), _pixsize, _colors.size(), 1)); | ||||||
| 		_right.setDevicePixelRatio(cRetinaFactor()); | 		_right.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		_bottom = QPixmap::fromImage(cornersImage.copy(_pixsize, _pixsize * 2 - _colors.size(), 1, _colors.size()), Qt::ColorOnly); | 		_bottom = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize, _pixsize * 2 - _colors.size(), 1, _colors.size())); | ||||||
| 		_bottom.setDevicePixelRatio(cRetinaFactor()); | 		_bottom.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	} | 	} | ||||||
|  | 	_corners = App::pixmapFromImageInPlace(std_::move(cornersImage)); | ||||||
|  | 	_corners.setDevicePixelRatio(cRetinaFactor()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void BoxShadow::paint(QPainter &p, const QRect &box, int32 shifty, int32 flags) { | void BoxShadow::paint(QPainter &p, const QRect &box, int32 shifty, int32 flags) { | ||||||
|  | @ -140,8 +140,6 @@ RectShadow::RectShadow(const style::icon &topLeft) : _size(topLeft.width()), _pi | ||||||
| 		m.setDevicePixelRatio(cRetinaFactor()); | 		m.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		p.drawImage(_size, 0, m, _pixsize, 0, _pixsize, _pixsize * 2); | 		p.drawImage(_size, 0, m, _pixsize, 0, _pixsize, _pixsize * 2); | ||||||
| 	} | 	} | ||||||
| 	_corners = QPixmap::fromImage(cornersImage, Qt::ColorOnly); |  | ||||||
| 	_corners.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 
 | 
 | ||||||
| 	uchar prev = 0; | 	uchar prev = 0; | ||||||
| 	for (int i = 0; i < _pixsize; ++i) { | 	for (int i = 0; i < _pixsize; ++i) { | ||||||
|  | @ -152,14 +150,17 @@ RectShadow::RectShadow(const style::icon &topLeft) : _size(topLeft.width()), _pi | ||||||
| 		prev = a; | 		prev = a; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_left = QPixmap::fromImage(cornersImage.copy(0, _pixsize - 1, _thickness, 1), Qt::ColorOnly); | 	_left = App::pixmapFromImageInPlace(cornersImage.copy(0, _pixsize - 1, _thickness, 1)); | ||||||
| 	_left.setDevicePixelRatio(cRetinaFactor()); | 	_left.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	_top = QPixmap::fromImage(cornersImage.copy(_pixsize - 1, 0, 1, _thickness), Qt::ColorOnly); | 	_top = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize - 1, 0, 1, _thickness)); | ||||||
| 	_top.setDevicePixelRatio(cRetinaFactor()); | 	_top.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	_right = QPixmap::fromImage(cornersImage.copy(_pixsize * 2 - _thickness, _pixsize, _thickness, 1), Qt::ColorOnly); | 	_right = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize * 2 - _thickness, _pixsize, _thickness, 1)); | ||||||
| 	_right.setDevicePixelRatio(cRetinaFactor()); | 	_right.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	_bottom = QPixmap::fromImage(cornersImage.copy(_pixsize, _pixsize * 2 - _thickness, 1, _thickness), Qt::ColorOnly); | 	_bottom = App::pixmapFromImageInPlace(cornersImage.copy(_pixsize, _pixsize * 2 - _thickness, 1, _thickness)); | ||||||
| 	_bottom.setDevicePixelRatio(cRetinaFactor()); | 	_bottom.setDevicePixelRatio(cRetinaFactor()); | ||||||
|  | 
 | ||||||
|  | 	_corners = App::pixmapFromImageInPlace(std_::move(cornersImage)); | ||||||
|  | 	_corners.setDevicePixelRatio(cRetinaFactor()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RectShadow::paint(Painter &p, const QRect &box, int shifty, Sides sides) { | void RectShadow::paint(Painter &p, const QRect &box, int shifty, Sides sides) { | ||||||
|  |  | ||||||
|  | @ -106,7 +106,7 @@ CountryInput::CountryInput(QWidget *parent, const style::countryInput &st) : QWi | ||||||
| 		p.setBrush(_st.bgColor->b); | 		p.setBrush(_st.bgColor->b); | ||||||
| 		p.drawPolygon(trPoints, 3); | 		p.drawPolygon(trPoints, 3); | ||||||
| 	} | 	} | ||||||
| 	_arrow = QPixmap::fromImage(trImage, Qt::ColorOnly); | 	_arrow = App::pixmapFromImageInPlace(std_::move(trImage)); | ||||||
| 	_inner = QRect(0, 0, _st.width, _st.height); | 	_inner = QRect(0, 0, _st.width, _st.height); | ||||||
| 	_arrowRect = QRect((st::inpIntroCountryCode.width - _arrow.width() - 1) / 2, _st.height, _arrow.width(), _arrow.height()); | 	_arrowRect = QRect((st::inpIntroCountryCode.width - _arrow.width() - 1) / 2, _st.height, _arrow.width(), _arrow.height()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, I | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Image::Image(const QString &file, QByteArray fmt) : _forgot(false) { | Image::Image(const QString &file, QByteArray fmt) : _forgot(false) { | ||||||
| 	_data = QPixmap::fromImage(App::readImage(file, &fmt, false, 0, &_saved), Qt::ColorOnly); | 	_data = App::pixmapFromImageInPlace(App::readImage(file, &fmt, false, 0, &_saved)); | ||||||
| 	_format = fmt; | 	_format = fmt; | ||||||
| 	if (!_data.isNull()) { | 	if (!_data.isNull()) { | ||||||
| 		globalAcquiredSize += int64(_data.width()) * _data.height() * 4; | 		globalAcquiredSize += int64(_data.width()) * _data.height() * 4; | ||||||
|  | @ -72,7 +72,7 @@ Image::Image(const QString &file, QByteArray fmt) : _forgot(false) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) { | Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) { | ||||||
| 	_data = QPixmap::fromImage(App::readImage(filecontent, &fmt, false), Qt::ColorOnly); | 	_data = App::pixmapFromImageInPlace(App::readImage(filecontent, &fmt, false)); | ||||||
| 	_format = fmt; | 	_format = fmt; | ||||||
| 	_saved = filecontent; | 	_saved = filecontent; | ||||||
| 	if (!_data.isNull()) { | 	if (!_data.isNull()) { | ||||||
|  | @ -420,7 +420,7 @@ const QPixmap &circleMask(int width, int height) { | ||||||
| 			p.drawEllipse(0, 0, width, height); | 			p.drawEllipse(0, 0, width, height); | ||||||
| 		} | 		} | ||||||
| 		mask.setDevicePixelRatio(cRetinaFactor()); | 		mask.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 		i = masks.insert(key, QPixmap::fromImage(mask)); | 		i = masks.insert(key, App::pixmapFromImageInPlace(std_::move(mask))); | ||||||
| 	} | 	} | ||||||
| 	return i.value(); | 	return i.value(); | ||||||
| } | } | ||||||
|  | @ -543,7 +543,7 @@ QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 ou | ||||||
| 		imageRound(img, ImageRoundRadius::Small); | 		imageRound(img, ImageRoundRadius::Small); | ||||||
| 	} | 	} | ||||||
| 	img.setDevicePixelRatio(cRetinaFactor()); | 	img.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	return QPixmap::fromImage(img, Qt::ColorOnly); | 	return App::pixmapFromImageInPlace(std_::move(img)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int outerh) const { | QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int outerh) const { | ||||||
|  | @ -584,7 +584,7 @@ QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int | ||||||
| 		} else if (options.testFlag(ImagePixRoundedSmall)) { | 		} else if (options.testFlag(ImagePixRoundedSmall)) { | ||||||
| 			imageRound(result, ImageRoundRadius::Small); | 			imageRound(result, ImageRoundRadius::Small); | ||||||
| 		} | 		} | ||||||
| 		return QPixmap::fromImage(result, Qt::ColorOnly); | 		return App::pixmapFromImageInPlace(std_::move(result)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return imagePix(_data.toImage(), w, h, options, outerw, outerh); | 	return imagePix(_data.toImage(), w, h, options, outerw, outerh); | ||||||
|  | @ -596,11 +596,11 @@ QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool | ||||||
| 	if (_data.isNull()) return blank()->pix(); | 	if (_data.isNull()) return blank()->pix(); | ||||||
| 
 | 
 | ||||||
| 	QImage img = _data.toImage(); | 	QImage img = _data.toImage(); | ||||||
| 	if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return QPixmap::fromImage(imageColored(add, img)); | 	if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return App::pixmapFromImageInPlace(imageColored(add, img)); | ||||||
| 	if (h <= 0) { | 	if (h <= 0) { | ||||||
| 		return QPixmap::fromImage(imageColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly); | 		return App::pixmapFromImageInPlace(imageColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation))); | ||||||
| 	} | 	} | ||||||
| 	return QPixmap::fromImage(imageColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly); | 	return App::pixmapFromImageInPlace(imageColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const { | QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const { | ||||||
|  | @ -615,7 +615,7 @@ QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 | ||||||
| 		img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | 		img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return QPixmap::fromImage(imageColored(add, img), Qt::ColorOnly); | 	return App::pixmapFromImageInPlace(imageColored(add, img)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Image::forget() const { | void Image::forget() const { | ||||||
|  | @ -738,7 +738,7 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) { | ||||||
| 		globalAcquiredSize -= int64(_data.width()) * _data.height() * 4; | 		globalAcquiredSize -= int64(_data.width()) * _data.height() * 4; | ||||||
| 	} | 	} | ||||||
| 	QByteArray fmt(bytesFormat); | 	QByteArray fmt(bytesFormat); | ||||||
| 	_data = QPixmap::fromImage(App::readImage(bytes, &fmt, false), Qt::ColorOnly); | 	_data = App::pixmapFromImageInPlace(App::readImage(bytes, &fmt, false)); | ||||||
| 	if (!_data.isNull()) { | 	if (!_data.isNull()) { | ||||||
| 		globalAcquiredSize += int64(_data.width()) * _data.height() * 4; | 		globalAcquiredSize += int64(_data.width()) * _data.height() * 4; | ||||||
| 		setInformation(bytes.size(), _data.width(), _data.height()); | 		setInformation(bytes.size(), _data.width(), _data.height()); | ||||||
|  |  | ||||||
|  | @ -73,6 +73,8 @@ void stopManager() { | ||||||
| 	internal::stopModules(); | 	internal::stopModules(); | ||||||
| 	internal::destroyFonts(); | 	internal::destroyFonts(); | ||||||
| 	internal::destroyColors(); | 	internal::destroyColors(); | ||||||
|  | 	internal::destroyIcons(); | ||||||
|  | 	internal::destroySprite(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QImage colorizeImage(const QImage &src, const color &c, const QRect &r) { | QImage colorizeImage(const QImage &src, const color &c, const QRect &r) { | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ QPixmap createIconPixmap(const IconMask *mask, const Color &color) { | ||||||
| 	} | 	} | ||||||
| 	finalImage = colorizeImage(maskImage, color, r); | 	finalImage = colorizeImage(maskImage, color, r); | ||||||
| 	finalImage.setDevicePixelRatio(cRetinaFactor()); | 	finalImage.setDevicePixelRatio(cRetinaFactor()); | ||||||
| 	return QPixmap::fromImage(finalImage, Qt::ColorOnly); | 	return App::pixmapFromImageInPlace(std_::move(finalImage)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -131,5 +131,7 @@ private: | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | void destroyIcons(); | ||||||
|  | 
 | ||||||
| } // namespace internal
 | } // namespace internal
 | ||||||
| } // namespace style
 | } // namespace style
 | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ void loadSprite() { | ||||||
| 	} | 	} | ||||||
| 	QString spriteFile = qsl(":/gui/art/sprite") + spriteFilePostfix + qsl(".png"); | 	QString spriteFile = qsl(":/gui/art/sprite") + spriteFilePostfix + qsl(".png"); | ||||||
| 	if (rtl()) { | 	if (rtl()) { | ||||||
| 		spriteData = new QPixmap(QPixmap::fromImage(QImage(spriteFile).mirrored(true, false))); | 		spriteData = new QPixmap(App::pixmapFromImageInPlace(QImage(spriteFile).mirrored(true, false))); | ||||||
| 	} else { | 	} else { | ||||||
| 		spriteData = new QPixmap(spriteFile); | 		spriteData = new QPixmap(spriteFile); | ||||||
| 	} | 	} | ||||||
|  | @ -53,6 +53,11 @@ int spriteWidth() { | ||||||
| 	return spriteWidthValue; | 	return spriteWidthValue; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void destroySprite() { | ||||||
|  | 	delete spriteData; | ||||||
|  | 	spriteData = nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace internal
 | } // namespace internal
 | ||||||
| 
 | 
 | ||||||
| const QPixmap &spritePixmap() { | const QPixmap &spritePixmap() { | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ namespace internal { | ||||||
| 
 | 
 | ||||||
| void loadSprite(); | void loadSprite(); | ||||||
| int spriteWidth(); | int spriteWidth(); | ||||||
|  | void destroySprite(); | ||||||
| 
 | 
 | ||||||
| class Sprite { | class Sprite { | ||||||
| public: | public: | ||||||
|  |  | ||||||
|  | @ -337,14 +337,7 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi | ||||||
| 		layout.beginLayout(); | 		layout.beginLayout(); | ||||||
| 		layout.createLine(); | 		layout.createLine(); | ||||||
| 
 | 
 | ||||||
| 		bool logCrashString = (rand_value<uchar>() % 4 == 1); |  | ||||||
| 		if (logCrashString) { |  | ||||||
| 			SignalHandlers::setCrashAnnotationRef("CrashString", &str); |  | ||||||
| 		} |  | ||||||
| 		BlockParser parser(&engine, this, minResizeWidth, _from, part); | 		BlockParser parser(&engine, this, minResizeWidth, _from, part); | ||||||
| 		if (logCrashString) { |  | ||||||
| 			SignalHandlers::clearCrashAnnotationRef("CrashString"); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		layout.endLayout(); | 		layout.endLayout(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue