@@ -61,7 +61,27 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
6161 const auto b = int (base::SafeRound (symbol.y () * 255 ));
6262 const auto value = uint16 ((uint16 (a) << 8 ) | uint16 (b));
6363 const auto shuffled = uint16 (value << 5 ) | uint16 (value >> 3 );
64- return (shuffled % 90 ) - 45 ;
64+ return (shuffled % 60 ) - 30 ;
65+ }
66+
67+ [[nodiscard]] int ChooseGiftSymbolSkip (const std::vector<QRectF> &symbols) {
68+ if (symbols.empty ()) {
69+ return -1 ;
70+ }
71+ auto maxIndex = -1 ;
72+ auto maxValue = 0 .;
73+ for (auto i = 0 , count = int (symbols.size ()); i != count; ++i) {
74+ const auto &symbol = symbols[i];
75+ const auto center = symbol.center ();
76+ const auto value = std::min (center.x (), 1 . - center.x ())
77+ * std::min (center.y (), 1 . - center.y ())
78+ * std::min (symbol.width (), symbol.height ());
79+ if (maxIndex < 0 || maxValue < value) {
80+ maxIndex = i;
81+ maxValue = value;
82+ }
83+ }
84+ return maxIndex;
6585}
6686
6787[[nodiscard]] CacheBackgroundResult CacheBackgroundByRequest (
@@ -90,6 +110,8 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
90110 Qt::IgnoreAspectRatio,
91111 Qt::SmoothTransformation);
92112 result.setDevicePixelRatio (ratio);
113+ auto giftArea = QRect ();
114+ int giftRotation = 0 ;
93115 if (!request.background .prepared .isNull ()) {
94116 QPainter p (&result);
95117 if (!gradient.isNull ()) {
@@ -115,27 +137,37 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
115137 const auto h = tiled.height () / float (ratio);
116138
117139 const auto &giftSymbols = request.background .giftSymbols ;
140+ const auto giftSymbolsCount = int (giftSymbols.size ());
141+ const auto giftSymbolSkip = ChooseGiftSymbolSkip (giftSymbols);
118142 const auto &giftSymbolFrame = request.background .giftSymbolFrame ;
119143 const auto giftSymbolSize = giftSymbolFrame.size () / ratio;
144+ const auto giftSymbolRect = [&](const QRectF &symbol) {
145+ return QRectF (
146+ symbol.x () * w,
147+ symbol.y () * h,
148+ symbol.width () * w,
149+ symbol.height () * h);
150+ };
151+ const auto giftSymbolPaint = [&](QPainter &p, QRectF symbol) {
152+ const auto rect = giftSymbolRect (symbol);
153+ p.save ();
154+ p.translate (rect.center ());
155+ p.scale (
156+ rect.width () / giftSymbolSize.width (),
157+ rect.height () / giftSymbolSize.height ());
158+ p.rotate (RotationForSymbol (symbol));
159+ p.translate (-rect.center ());
160+ p.drawImage (rect.topLeft (), giftSymbolFrame);
161+ p.restore ();
162+ };
120163 if (hasGiftSymbols) {
121164 auto q = QPainter (&tiled);
122165 auto hq = PainterHighQualityEnabler (q);
123166 q.setOpacity (0.8 );
124- for (const auto &symbol : giftSymbols) {
125- const auto rect = QRectF (
126- symbol.x () * w,
127- symbol.y () * h,
128- symbol.width () * w,
129- symbol.height () * h);
130- q.save ();
131- q.translate (rect.center ());
132- q.scale (
133- rect.width () / giftSymbolSize.width (),
134- rect.height () / giftSymbolSize.height ());
135- q.rotate (RotationForSymbol (symbol));
136- q.translate (-rect.center ());
137- q.drawImage (rect.topLeft (), giftSymbolFrame);
138- q.restore ();
167+ for (auto i = 0 ; i != giftSymbolsCount; ++i) {
168+ if (i != giftSymbolSkip) {
169+ giftSymbolPaint (q, giftSymbols[i]);
170+ }
139171 }
140172 }
141173 const auto cx = int (std::ceil (request.area .width () / w));
@@ -148,10 +180,33 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
148180 ? (request.area .width () * ratio - cols * tiled.width ()) / 2
149181 : 0 ;
150182 const auto useshift = xshift / float (ratio);
183+ const auto drawTile = [&](int x, int y) {
184+ const auto position = QPointF (useshift + x * w, y * h);
185+ p.drawImage (position, tiled);
186+ };
187+
188+ // Skip a symbol in the center for the gift itself.
189+ drawTile (cols / 2 , 0 );
190+ if (hasGiftSymbols) {
191+ const auto &gift = giftSymbols[giftSymbolSkip];
192+ auto q = QPainter (&tiled);
193+ auto hq = PainterHighQualityEnabler (q);
194+ q.setOpacity (0.8 );
195+ giftSymbolPaint (q, gift);
196+ const auto exact = giftSymbolRect (gift);
197+ giftArea = QRect (
198+ useshift + (cols / 2 ) * w + exact.x (),
199+ exact.y (),
200+ exact.width (),
201+ exact.height ());
202+ giftRotation = RotationForSymbol (gift);
203+ }
204+
151205 for (auto y = 0 ; y != rows; ++y) {
152206 for (auto x = 0 ; x != cols; ++x) {
153- const auto position = QPointF (useshift + x * w, y * h);
154- p.drawImage (position, tiled);
207+ if (y || x != (cols / 2 )) {
208+ drawTile (x, y);
209+ }
155210 }
156211 }
157212 if (!gradient.isNull ()
@@ -167,6 +222,8 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
167222 QImage::Format_ARGB32_Premultiplied),
168223 .gradient = gradient,
169224 .area = request.area ,
225+ .giftArea = giftArea,
226+ .giftRotation = giftRotation,
170227 .waitingForNegativePattern
171228 = request.background .waitingForNegativePattern ()
172229 };
@@ -239,6 +296,8 @@ CachedBackground::CachedBackground(CacheBackgroundResult &&result)
239296, area(result.area)
240297, x(result.x)
241298, y(result.y)
299+ , giftArea(result.giftArea)
300+ , giftRotation(result.giftRotation)
242301, waitingForNegativePattern(result.waitingForNegativePattern) {
243302}
244303
@@ -456,6 +515,7 @@ void ChatTheme::updateBackgroundImageFrom(ChatThemeBackground &&background) {
456515 _mutableBackground.key = background.key ;
457516 _mutableBackground.prepared = std::move (background.prepared );
458517 _mutableBackground.giftSymbols = std::move (background.giftSymbols );
518+ _mutableBackground.giftId = background.giftId ;
459519 _mutableBackground.preparedForTiled = std::move (
460520 background.preparedForTiled );
461521 if (!_backgroundState.now .pixmap .isNull ()) {
@@ -1184,6 +1244,7 @@ ChatThemeBackground PrepareBackgroundImage(
11841244 .colors = data.colors ,
11851245 .giftSymbols = std::move (read.giftSymbols ),
11861246 .giftSymbolFrame = data.giftSymbolFrame ,
1247+ .giftId = data.giftId ,
11871248 .patternOpacity = data.patternOpacity ,
11881249 .gradientRotation = data.generateGradient ? data.gradientRotation : 0 ,
11891250 .isPattern = data.isPattern ,
0 commit comments