1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "data/data_wall_paper.h"
9 
10 #include "data/data_document.h"
11 #include "data/data_file_origin.h"
12 #include "data/data_session.h"
13 #include "storage/serialize_common.h"
14 #include "ui/chat/chat_theme.h"
15 #include "core/application.h"
16 #include "main/main_session.h"
17 
18 namespace Data {
19 namespace {
20 
FromLegacyBackgroundId(int32 legacyId)21 constexpr auto FromLegacyBackgroundId(int32 legacyId) -> WallPaperId {
22 	return uint64(0xFFFFFFFF00000000ULL) | uint64(uint32(legacyId));
23 }
24 
25 constexpr auto kUninitializedBackground = FromLegacyBackgroundId(-999);
26 constexpr auto kTestingThemeBackground = FromLegacyBackgroundId(-666);
27 constexpr auto kTestingDefaultBackground = FromLegacyBackgroundId(-665);
28 constexpr auto kTestingEditorBackground = FromLegacyBackgroundId(-664);
29 constexpr auto kThemeBackground = FromLegacyBackgroundId(-2);
30 constexpr auto kCustomBackground = FromLegacyBackgroundId(-1);
31 constexpr auto kLegacy1DefaultBackground = FromLegacyBackgroundId(0);
32 constexpr auto kLegacy2DefaultBackground = 5947530738516623361;
33 constexpr auto kLegacy3DefaultBackground = 5778236420632084488;
34 constexpr auto kLegacy4DefaultBackground = 5945087215657811969;
35 constexpr auto kDefaultBackground = 5933856211186221059;
36 constexpr auto kIncorrectDefaultBackground = FromLegacyBackgroundId(105);
37 
38 constexpr auto kVersionTag = qint32(0x7FFFFFFF);
39 constexpr auto kVersion = 1;
40 
SerializeColor(const QColor & color)41 [[nodiscard]] quint32 SerializeColor(const QColor &color) {
42 	return (quint32(std::clamp(color.red(), 0, 255)) << 16)
43 		| (quint32(std::clamp(color.green(), 0, 255)) << 8)
44 		| quint32(std::clamp(color.blue(), 0, 255));
45 }
46 
SerializeMaybeColor(std::optional<QColor> color)47 [[nodiscard]] quint32 SerializeMaybeColor(std::optional<QColor> color) {
48 	return color ? SerializeColor(*color) : quint32(-1);
49 }
50 
ColorsFromMTP(const MTPDwallPaperSettings & data)51 [[nodiscard]] std::vector<QColor> ColorsFromMTP(
52 		const MTPDwallPaperSettings &data) {
53 	auto result = std::vector<QColor>();
54 	const auto c1 = MaybeColorFromSerialized(data.vbackground_color());
55 	if (!c1) {
56 		return result;
57 	}
58 	result.reserve(4);
59 	result.push_back(*c1);
60 	const auto c2 = MaybeColorFromSerialized(data.vsecond_background_color());
61 	if (!c2) {
62 		return result;
63 	}
64 	result.push_back(*c2);
65 	const auto c3 = MaybeColorFromSerialized(data.vthird_background_color());
66 	if (!c3) {
67 		return result;
68 	}
69 	result.push_back(*c3);
70 	const auto c4 = MaybeColorFromSerialized(data.vfourth_background_color());
71 	if (!c4) {
72 		return result;
73 	}
74 	result.push_back(*c4);
75 	return result;
76 }
77 
ColorFromString(QStringView string)78 [[nodiscard]] std::optional<QColor> ColorFromString(QStringView string) {
79 	if (string.size() != 6) {
80 		return {};
81 	} else if (ranges::any_of(string, [](QChar ch) {
82 		return (ch < 'a' || ch > 'f')
83 			&& (ch < 'A' || ch > 'F')
84 			&& (ch < '0' || ch > '9');
85 	})) {
86 		return {};
87 	}
88 	const auto component = [](QStringView text, int index) {
89 		const auto decimal = [](QChar hex) {
90 			const auto code = hex.unicode();
91 			return (code >= '0' && code <= '9')
92 				? int(code - '0')
93 				: (code >= 'a' && code <= 'f')
94 				? int(code - 'a' + 0x0a)
95 				: int(code - 'A' + 0x0a);
96 		};
97 		index *= 2;
98 		return decimal(text[index]) * 0x10 + decimal(text[index + 1]);
99 	};
100 	return QColor(
101 		component(string, 0),
102 		component(string, 1),
103 		component(string, 2),
104 		255);
105 }
106 
ColorsFromString(const QString & string)107 [[nodiscard]] std::vector<QColor> ColorsFromString(const QString &string) {
108 	constexpr auto kMaxColors = 4;
109 	const auto view = QStringView(string);
110 	const auto count = int(view.size() / 6);
111 	if (!count || count > kMaxColors || view.size() != count * 7 - 1) {
112 		return {};
113 	}
114 	auto result = std::vector<QColor>();
115 	result.reserve(count);
116 	for (auto i = 0; i != count; ++i) {
117 		if (i + 1 < count
118 			&& view[i * 7 + 6] != '~'
119 			&& (count > 2 || view[i * 7 + 6] != '-')) {
120 			return {};
121 		} else if (const auto parsed = ColorFromString(view.mid(i * 7, 6))) {
122 			result.push_back(*parsed);
123 		} else {
124 			return {};
125 		}
126 	}
127 	return result;
128 }
129 
StringFromColor(QColor color)130 [[nodiscard]] QString StringFromColor(QColor color) {
131 	const auto component = [](int value) {
132 		const auto hex = [](int value) {
133 			value = std::clamp(value, 0, 15);
134 			return (value > 9)
135 				? ('a' + (value - 10))
136 				: ('0' + value);
137 		};
138 		return QString() + hex(value / 16) + hex(value % 16);
139 	};
140 	return component(color.red())
141 		+ component(color.green())
142 		+ component(color.blue());
143 }
144 
StringFromColors(const std::vector<QColor> & colors)145 [[nodiscard]] QString StringFromColors(const std::vector<QColor> &colors) {
146 	Expects(!colors.empty());
147 
148 	auto strings = QStringList();
149 	strings.reserve(colors.size());
150 	for (const auto &color : colors) {
151 		strings.push_back(StringFromColor(color));
152 	}
153 	const auto separator = (colors.size() > 2) ? '~' : '-';
154 	return strings.join(separator);
155 }
156 
RawFromLegacyFlags(qint32 legacyFlags)157 [[nodiscard]] qint32 RawFromLegacyFlags(qint32 legacyFlags) {
158 	using Flag = WallPaperFlag;
159 	return ((legacyFlags & (1 << 0)) ? qint32(Flag::Creator) : 0)
160 		| ((legacyFlags & (1 << 1)) ? qint32(Flag::Default) : 0)
161 		| ((legacyFlags & (1 << 3)) ? qint32(Flag::Pattern) : 0)
162 		| ((legacyFlags & (1 << 4)) ? qint32(Flag::Dark) : 0);
163 }
164 
165 } // namespace
166 
WallPaper(WallPaperId id)167 WallPaper::WallPaper(WallPaperId id) : _id(id) {
168 }
169 
setLocalImageAsThumbnail(std::shared_ptr<Image> image)170 void WallPaper::setLocalImageAsThumbnail(std::shared_ptr<Image> image) {
171 	Expects(IsDefaultWallPaper(*this)
172 		|| IsLegacy1DefaultWallPaper(*this)
173 		|| IsCustomWallPaper(*this));
174 	Expects(_thumbnail == nullptr);
175 
176 	_thumbnail = std::move(image);
177 }
178 
id() const179 WallPaperId WallPaper::id() const {
180 	return _id;
181 }
182 
backgroundColors() const183 const std::vector<QColor> WallPaper::backgroundColors() const {
184 	return _backgroundColors;
185 }
186 
document() const187 DocumentData *WallPaper::document() const {
188 	return _document;
189 }
190 
localThumbnail() const191 Image *WallPaper::localThumbnail() const {
192 	return _thumbnail.get();
193 }
194 
isPattern() const195 bool WallPaper::isPattern() const {
196 	return _flags & WallPaperFlag::Pattern;
197 }
198 
isDefault() const199 bool WallPaper::isDefault() const {
200 	return _flags & WallPaperFlag::Default;
201 }
202 
isCreator() const203 bool WallPaper::isCreator() const {
204 	return _flags & WallPaperFlag::Creator;
205 }
206 
isDark() const207 bool WallPaper::isDark() const {
208 	return _flags & WallPaperFlag::Dark;
209 }
210 
isLocal() const211 bool WallPaper::isLocal() const {
212 	return !document() && _thumbnail;
213 }
214 
isBlurred() const215 bool WallPaper::isBlurred() const {
216 	return _blurred;
217 }
218 
patternIntensity() const219 int WallPaper::patternIntensity() const {
220 	return _intensity;
221 }
222 
patternOpacity() const223 float64 WallPaper::patternOpacity() const {
224 	return _intensity / 100.;
225 }
226 
gradientRotation() const227 int WallPaper::gradientRotation() const {
228 	// In case of complex gradients rotation value is dynamic.
229 	return (_backgroundColors.size() < 3) ? _rotation : 0;
230 }
231 
hasShareUrl() const232 bool WallPaper::hasShareUrl() const {
233 	return !_slug.isEmpty();
234 }
235 
shareUrl(not_null<Main::Session * > session) const236 QString WallPaper::shareUrl(not_null<Main::Session*> session) const {
237 	if (!hasShareUrl()) {
238 		return QString();
239 	}
240 	const auto base = session->createInternalLinkFull("bg/" + _slug);
241 	auto params = QStringList();
242 	if (isPattern()) {
243 		if (!backgroundColors().empty()) {
244 			params.push_back(
245 				"bg_color=" + StringFromColors(backgroundColors()));
246 		}
247 		if (_intensity) {
248 			params.push_back("intensity=" + QString::number(_intensity));
249 		}
250 	}
251 	if (_rotation && backgroundColors().size() == 2) {
252 		params.push_back("rotation=" + QString::number(_rotation));
253 	}
254 	auto mode = QStringList();
255 	if (_blurred) {
256 		mode.push_back("blur");
257 	}
258 	if (!mode.isEmpty()) {
259 		params.push_back("mode=" + mode.join('+'));
260 	}
261 	return params.isEmpty()
262 		? base
263 		: base + '?' + params.join('&');
264 }
265 
loadDocumentThumbnail() const266 void WallPaper::loadDocumentThumbnail() const {
267 	if (_document) {
268 		_document->loadThumbnail(fileOrigin());
269 	}
270 }
271 
loadDocument() const272 void WallPaper::loadDocument() const {
273 	if (_document) {
274 		_document->save(fileOrigin(), QString());
275 	}
276 }
277 
fileOrigin() const278 FileOrigin WallPaper::fileOrigin() const {
279 	return FileOriginWallpaper(_id, _accessHash, _ownerId, _slug);
280 }
281 
ownerId() const282 UserId WallPaper::ownerId() const {
283 	return _ownerId;
284 }
285 
mtpInput(not_null<Main::Session * > session) const286 MTPInputWallPaper WallPaper::mtpInput(not_null<Main::Session*> session) const {
287 	return (_ownerId && _ownerId != session->userId() && !_slug.isEmpty())
288 		? MTP_inputWallPaperSlug(MTP_string(_slug))
289 		: MTP_inputWallPaper(MTP_long(_id), MTP_long(_accessHash));
290 }
291 
mtpSettings() const292 MTPWallPaperSettings WallPaper::mtpSettings() const {
293 	const auto serializeForIndex = [&](int index) {
294 		return (_backgroundColors.size() > index)
295 			? MTP_int(SerializeColor(_backgroundColors[index]))
296 			: MTP_int(0);
297 	};
298 	using Flag = MTPDwallPaperSettings::Flag;
299 	const auto flagForIndex = [&](int index) {
300 		return (_backgroundColors.size() <= index)
301 			? Flag(0)
302 			: (index == 0)
303 			? Flag::f_background_color
304 			: (index == 1)
305 			? Flag::f_second_background_color
306 			: (index == 2)
307 			? Flag::f_third_background_color
308 			: Flag::f_fourth_background_color;
309 	};
310 	return MTP_wallPaperSettings(
311 		MTP_flags((_blurred ? Flag::f_blur : Flag(0))
312 			| flagForIndex(0)
313 			| flagForIndex(1)
314 			| flagForIndex(2)
315 			| flagForIndex(3)),
316 		serializeForIndex(0),
317 		serializeForIndex(1),
318 		serializeForIndex(2),
319 		serializeForIndex(3),
320 		MTP_int(_intensity),
321 		MTP_int(_rotation));
322 }
323 
withUrlParams(const QMap<QString,QString> & params) const324 WallPaper WallPaper::withUrlParams(
325 		const QMap<QString, QString> &params) const {
326 	auto result = *this;
327 	result._blurred = false;
328 	result._backgroundColors = ColorsFromString(_slug);
329 	result._intensity = kDefaultIntensity;
330 	if (auto mode = params.value("mode"); !mode.isEmpty()) {
331 		const auto list = mode.replace('+', ' ').split(' ');
332 		for (const auto &change : list) {
333 			if (change == qstr("blur")) {
334 				result._blurred = true;
335 			}
336 		}
337 	}
338 	if (result._backgroundColors.empty()) {
339 		result._backgroundColors = ColorsFromString(params.value("bg_color"));
340 	}
341 	if (result._backgroundColors.empty()) {
342 		result._backgroundColors = ColorsFromString(params.value("gradient"));
343 	}
344 	if (result._backgroundColors.empty()) {
345 		result._backgroundColors = ColorsFromString(params.value("color"));
346 	}
347 	if (result._backgroundColors.empty()) {
348 		result._backgroundColors = ColorsFromString(params.value("slug"));
349 	}
350 	if (const auto string = params.value("intensity"); !string.isEmpty()) {
351 		auto ok = false;
352 		const auto intensity = string.toInt(&ok);
353 		if (ok && base::in_range(intensity, -100, 101)) {
354 			result._intensity = intensity;
355 		}
356 	}
357 	result._rotation = params.value("rotation").toInt();
358 	result._rotation = (std::clamp(result._rotation, 0, 315) / 45) * 45;
359 
360 	return result;
361 }
362 
withBlurred(bool blurred) const363 WallPaper WallPaper::withBlurred(bool blurred) const {
364 	auto result = *this;
365 	result._blurred = blurred;
366 	return result;
367 }
368 
withPatternIntensity(int intensity) const369 WallPaper WallPaper::withPatternIntensity(int intensity) const {
370 	auto result = *this;
371 	result._intensity = intensity;
372 	return result;
373 }
374 
withGradientRotation(int rotation) const375 WallPaper WallPaper::withGradientRotation(int rotation) const {
376 	auto result = *this;
377 	result._rotation = rotation;
378 	return result;
379 }
380 
withBackgroundColors(std::vector<QColor> colors) const381 WallPaper WallPaper::withBackgroundColors(std::vector<QColor> colors) const {
382 	auto result = *this;
383 	result._backgroundColors = std::move(colors);
384 	if (!ColorsFromString(_slug).empty()) {
385 		result._slug = StringFromColors(result._backgroundColors);
386 	}
387 	return result;
388 }
389 
withParamsFrom(const WallPaper & other) const390 WallPaper WallPaper::withParamsFrom(const WallPaper &other) const {
391 	auto result = *this;
392 	result._blurred = other._blurred;
393 	if (!other._backgroundColors.empty()) {
394 		result._backgroundColors = other._backgroundColors;
395 		if (!ColorsFromString(_slug).empty()) {
396 			result._slug = StringFromColors(result._backgroundColors);
397 		}
398 	}
399 	result._intensity = other._intensity;
400 	if (other.isPattern()) {
401 		result._flags |= WallPaperFlag::Pattern;
402 	}
403 	return result;
404 }
405 
withoutImageData() const406 WallPaper WallPaper::withoutImageData() const {
407 	auto result = *this;
408 	result._thumbnail = nullptr;
409 	return result;
410 }
411 
Create(not_null<Main::Session * > session,const MTPWallPaper & data)412 std::optional<WallPaper> WallPaper::Create(
413 		not_null<Main::Session*> session,
414 		const MTPWallPaper &data) {
415 	return data.match([&](const MTPDwallPaper &data) {
416 		return Create(session, data);
417 	}, [](const MTPDwallPaperNoFile &data) {
418 		return Create(data);
419 	});
420 }
421 
Create(not_null<Main::Session * > session,const MTPDwallPaper & data)422 std::optional<WallPaper> WallPaper::Create(
423 		not_null<Main::Session*> session,
424 		const MTPDwallPaper &data) {
425 	const auto document = session->data().processDocument(
426 		data.vdocument());
427 	if (!document->checkWallPaperProperties()) {
428 		return std::nullopt;
429 	}
430 	auto result = WallPaper(data.vid().v);
431 	result._accessHash = data.vaccess_hash().v;
432 	result._ownerId = session->userId();
433 	result._flags = (data.is_dark() ? WallPaperFlag::Dark : WallPaperFlag(0))
434 		| (data.is_pattern() ? WallPaperFlag::Pattern : WallPaperFlag(0))
435 		| (data.is_default() ? WallPaperFlag::Default : WallPaperFlag(0))
436 		| (data.is_creator() ? WallPaperFlag::Creator : WallPaperFlag(0));
437 	result._slug = qs(data.vslug());
438 	result._document = document;
439 	if (const auto settings = data.vsettings()) {
440 		settings->match([&](const MTPDwallPaperSettings &data) {
441 			result._blurred = data.is_blur();
442 			if (result.isPattern()) {
443 				result._backgroundColors = ColorsFromMTP(data);
444 				if (const auto intensity = data.vintensity()) {
445 					result._intensity = intensity->v;
446 				}
447 				if (const auto rotation = data.vrotation()) {
448 					result._rotation = rotation->v;
449 				}
450 			}
451 		});
452 	}
453 	return result;
454 }
455 
Create(const MTPDwallPaperNoFile & data)456 std::optional<WallPaper> WallPaper::Create(const MTPDwallPaperNoFile &data) {
457 	auto result = WallPaper(data.vid().v);
458 	result._flags = (data.is_dark() ? WallPaperFlag::Dark : WallPaperFlag(0))
459 		| (data.is_default() ? WallPaperFlag::Default : WallPaperFlag(0));
460 	result._blurred = false;
461 	result._backgroundColors.clear();
462 	if (const auto settings = data.vsettings()) {
463 		settings->match([&](const MTPDwallPaperSettings &data) {
464 			result._blurred = data.is_blur();
465 			result._backgroundColors = ColorsFromMTP(data);
466 			if (const auto rotation = data.vrotation()) {
467 				result._rotation = rotation->v;
468 			}
469 		});
470 	}
471 	return result;
472 }
473 
serialize() const474 QByteArray WallPaper::serialize() const {
475 	auto size = sizeof(quint64) // _id
476 		+ sizeof(quint64) // _accessHash
477 		+ sizeof(qint32) // version tag
478 		+ sizeof(qint32) // version
479 		+ sizeof(qint32) // _flags
480 		+ Serialize::stringSize(_slug)
481 		+ sizeof(qint32) // _settings
482 		+ sizeof(qint32) // _backgroundColors.size()
483 		+ (_backgroundColors.size() * sizeof(quint32)) // _backgroundColors
484 		+ sizeof(qint32) // _intensity
485 		+ sizeof(qint32) // _rotation
486 		+ sizeof(quint64); // ownerId
487 
488 	auto result = QByteArray();
489 	result.reserve(size);
490 	{
491 		auto stream = QDataStream(&result, QIODevice::WriteOnly);
492 		stream.setVersion(QDataStream::Qt_5_1);
493 		stream
494 			<< quint64(_id)
495 			<< quint64(_accessHash)
496 			<< qint32(kVersionTag)
497 			<< qint32(kVersion)
498 			<< qint32(_flags)
499 			<< _slug
500 			<< qint32(_blurred ? 1 : 0)
501 			<< qint32(_backgroundColors.size());
502 		for (const auto &color : _backgroundColors) {
503 			stream << SerializeMaybeColor(color);
504 		}
505 		stream
506 			<< qint32(_intensity)
507 			<< qint32(_rotation)
508 			<< quint64(_ownerId.bare);
509 	}
510 	return result;
511 }
512 
FromSerialized(const QByteArray & serialized)513 std::optional<WallPaper> WallPaper::FromSerialized(
514 		const QByteArray &serialized) {
515 	if (serialized.isEmpty()) {
516 		return std::nullopt;
517 	}
518 
519 	auto id = quint64();
520 	auto accessHash = quint64();
521 	auto versionTag = qint32();
522 	auto version = qint32(0);
523 
524 	auto stream = QDataStream(serialized);
525 	stream.setVersion(QDataStream::Qt_5_1);
526 	stream
527 		>> id
528 		>> accessHash
529 		>> versionTag;
530 
531 	auto flags = qint32();
532 	auto ownerId = UserId();
533 	auto slug = QString();
534 	auto blurred = qint32();
535 	auto backgroundColors = std::vector<QColor>();
536 	auto intensity = qint32();
537 	auto rotation = qint32();
538 	if (versionTag == kVersionTag) {
539 		auto bareOwnerId = quint64();
540 		auto backgroundColorsCount = qint32();
541 		stream
542 			>> version
543 			>> flags
544 			>> slug
545 			>> blurred
546 			>> backgroundColorsCount;
547 		if (backgroundColorsCount < 0 || backgroundColorsCount > 4) {
548 			return std::nullopt;
549 		}
550 		backgroundColors.reserve(backgroundColorsCount);
551 		for (auto i = 0; i != backgroundColorsCount; ++i) {
552 			auto serialized = quint32();
553 			stream >> serialized;
554 			const auto color = MaybeColorFromSerialized(serialized);
555 			if (!color) {
556 				return std::nullopt;
557 			}
558 			backgroundColors.push_back(*color);
559 		}
560 		stream
561 			>> intensity
562 			>> rotation
563 			>> bareOwnerId;
564 		ownerId = UserId(BareId(bareOwnerId));
565 	} else {
566 		auto settings = qint32();
567 		auto backgroundColor = quint32();
568 		stream
569 			>> slug
570 			>> settings
571 			>> backgroundColor
572 			>> intensity;
573 		if (!stream.atEnd()) {
574 			auto field1 = qint32();
575 			auto field2 = qint32();
576 			stream >> field1;
577 			if (!stream.atEnd()) {
578 				stream >> field2;
579 			}
580 			ownerId = UserId(
581 				BareId(uint32(field1)) | (BareId(uint32(field2)) << 32));
582 		}
583 		flags = RawFromLegacyFlags(versionTag);
584 		blurred = (settings & qint32(1U << 1)) ? 1 : 0;
585 		if (const auto color = MaybeColorFromSerialized(backgroundColor)) {
586 			backgroundColors.push_back(*color);
587 		}
588 	}
589 	if (stream.status() != QDataStream::Ok) {
590 		return std::nullopt;
591 	} else if (intensity < -100 || intensity > 100) {
592 		return std::nullopt;
593 	}
594 	auto result = WallPaper(id);
595 	result._accessHash = accessHash;
596 	result._ownerId = ownerId;
597 	result._flags = WallPaperFlags::from_raw(flags);
598 	result._slug = slug;
599 	result._blurred = (blurred == 1);
600 	result._backgroundColors = std::move(backgroundColors);
601 	result._intensity = intensity;
602 	result._rotation = rotation;
603 	return result;
604 }
605 
FromLegacySerialized(quint64 id,quint64 accessHash,quint32 flags,QString slug)606 std::optional<WallPaper> WallPaper::FromLegacySerialized(
607 		quint64 id,
608 		quint64 accessHash,
609 		quint32 flags,
610 		QString slug) {
611 	auto result = WallPaper(id);
612 	result._accessHash = accessHash;
613 	result._flags = WallPaperFlags::from_raw(RawFromLegacyFlags(flags));
614 	result._slug = slug;
615 	if (const auto color = ColorFromString(slug)) {
616 		result._backgroundColors.push_back(*color);
617 	}
618 	return result;
619 }
620 
FromLegacyId(qint32 legacyId)621 std::optional<WallPaper> WallPaper::FromLegacyId(qint32 legacyId) {
622 	auto result = WallPaper(FromLegacyBackgroundId(legacyId));
623 	if (!IsCustomWallPaper(result)) {
624 		result._flags = WallPaperFlag::Default;
625 	}
626 	return result;
627 }
628 
FromColorsSlug(const QString & slug)629 std::optional<WallPaper> WallPaper::FromColorsSlug(const QString &slug) {
630 	auto colors = ColorsFromString(slug);
631 	if (colors.empty()) {
632 		return std::nullopt;
633 	}
634 	auto result = CustomWallPaper();
635 	result._slug = slug;
636 	result._backgroundColors = std::move(colors);
637 	return result;
638 }
639 
ConstructDefault()640 WallPaper WallPaper::ConstructDefault() {
641 	auto result = WallPaper(
642 		kDefaultBackground
643 	).withPatternIntensity(50).withBackgroundColors({
644 		QColor(219, 221, 187),
645 		QColor(107, 165, 135),
646 		QColor(213, 216, 141),
647 		QColor(136, 184, 132),
648 	});
649 	result._flags |= WallPaperFlag::Default | WallPaperFlag::Pattern;
650 	return result;
651 }
652 
ThemeWallPaper()653 WallPaper ThemeWallPaper() {
654 	return WallPaper(kThemeBackground);
655 }
656 
IsThemeWallPaper(const WallPaper & paper)657 bool IsThemeWallPaper(const WallPaper &paper) {
658 	return (paper.id() == kThemeBackground);
659 }
660 
CustomWallPaper()661 WallPaper CustomWallPaper() {
662 	return WallPaper(kCustomBackground);
663 }
664 
IsCustomWallPaper(const WallPaper & paper)665 bool IsCustomWallPaper(const WallPaper &paper) {
666 	return (paper.id() == kCustomBackground);
667 }
668 
Legacy1DefaultWallPaper()669 WallPaper Legacy1DefaultWallPaper() {
670 	return WallPaper(kLegacy1DefaultBackground);
671 }
672 
IsLegacy1DefaultWallPaper(const WallPaper & paper)673 bool IsLegacy1DefaultWallPaper(const WallPaper &paper) {
674 	return (paper.id() == kLegacy1DefaultBackground);
675 }
676 
IsLegacy2DefaultWallPaper(const WallPaper & paper)677 bool IsLegacy2DefaultWallPaper(const WallPaper &paper) {
678 	return (paper.id() == kLegacy2DefaultBackground)
679 		|| (paper.id() == kIncorrectDefaultBackground);
680 }
681 
IsLegacy3DefaultWallPaper(const WallPaper & paper)682 bool IsLegacy3DefaultWallPaper(const WallPaper &paper) {
683 	return (paper.id() == kLegacy3DefaultBackground);
684 }
685 
IsLegacy4DefaultWallPaper(const WallPaper & paper)686 bool IsLegacy4DefaultWallPaper(const WallPaper &paper) {
687 	return (paper.id() == kLegacy4DefaultBackground);
688 }
689 
DefaultWallPaper()690 WallPaper DefaultWallPaper() {
691 	return WallPaper::ConstructDefault();
692 }
693 
IsDefaultWallPaper(const WallPaper & paper)694 bool IsDefaultWallPaper(const WallPaper &paper) {
695 	return (paper.id() == kDefaultBackground);
696 }
697 
IsCloudWallPaper(const WallPaper & paper)698 bool IsCloudWallPaper(const WallPaper &paper) {
699 	return (paper.id() != kIncorrectDefaultBackground)
700 		&& !IsThemeWallPaper(paper)
701 		&& !IsCustomWallPaper(paper)
702 		&& !IsLegacy1DefaultWallPaper(paper)
703 		&& !details::IsUninitializedWallPaper(paper)
704 		&& !details::IsTestingThemeWallPaper(paper)
705 		&& !details::IsTestingDefaultWallPaper(paper)
706 		&& !details::IsTestingEditorWallPaper(paper);
707 }
708 
GenerateDitheredGradient(const Data::WallPaper & paper)709 QImage GenerateDitheredGradient(const Data::WallPaper &paper) {
710 	return Ui::GenerateDitheredGradient(
711 		paper.backgroundColors(),
712 		paper.gradientRotation());
713 }
714 
ColorFromSerialized(quint32 serialized)715 QColor ColorFromSerialized(quint32 serialized) {
716 	return QColor(
717 		int((serialized >> 16) & 0xFFU),
718 		int((serialized >> 8) & 0xFFU),
719 		int(serialized & 0xFFU));
720 }
721 
ColorFromSerialized(MTPint serialized)722 QColor ColorFromSerialized(MTPint serialized) {
723 	return ColorFromSerialized(serialized.v);
724 }
725 
MaybeColorFromSerialized(quint32 serialized)726 std::optional<QColor> MaybeColorFromSerialized(
727 		quint32 serialized) {
728 	return (serialized == quint32(-1))
729 		? std::nullopt
730 		: std::make_optional(ColorFromSerialized(serialized));
731 }
732 
MaybeColorFromSerialized(const tl::conditional<MTPint> & mtp)733 std::optional<QColor> MaybeColorFromSerialized(
734 		const tl::conditional<MTPint> &mtp) {
735 	return mtp ? std::make_optional(ColorFromSerialized(*mtp)) : std::nullopt;
736 }
737 
738 namespace details {
739 
UninitializedWallPaper()740 WallPaper UninitializedWallPaper() {
741 	return WallPaper(kUninitializedBackground);
742 }
743 
IsUninitializedWallPaper(const WallPaper & paper)744 bool IsUninitializedWallPaper(const WallPaper &paper) {
745 	return (paper.id() == kUninitializedBackground);
746 }
747 
TestingThemeWallPaper()748 WallPaper TestingThemeWallPaper() {
749 	return WallPaper(kTestingThemeBackground);
750 }
751 
IsTestingThemeWallPaper(const WallPaper & paper)752 bool IsTestingThemeWallPaper(const WallPaper &paper) {
753 	return (paper.id() == kTestingThemeBackground);
754 }
755 
TestingDefaultWallPaper()756 WallPaper TestingDefaultWallPaper() {
757 	return WallPaper(
758 		kTestingDefaultBackground
759 	).withParamsFrom(DefaultWallPaper());
760 }
761 
IsTestingDefaultWallPaper(const WallPaper & paper)762 bool IsTestingDefaultWallPaper(const WallPaper &paper) {
763 	return (paper.id() == kTestingDefaultBackground);
764 }
765 
TestingEditorWallPaper()766 WallPaper TestingEditorWallPaper() {
767 	return WallPaper(kTestingEditorBackground);
768 }
769 
IsTestingEditorWallPaper(const WallPaper & paper)770 bool IsTestingEditorWallPaper(const WallPaper &paper) {
771 	return (paper.id() == kTestingEditorBackground);
772 }
773 
774 } // namespace details
775 } // namespace Data
776