Add td_api::backgroundFillFreeformGradient.

This commit is contained in:
levlam 2021-05-21 01:49:59 +03:00
parent 9662679968
commit bb957644cf
7 changed files with 252 additions and 96 deletions

View File

@ -2619,6 +2619,9 @@ backgroundFillSolid color:int32 = BackgroundFill;
//@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Should be always divisible by 45 //@rotation_angle Clockwise rotation angle of the gradient, in degrees; 0-359. Should be always divisible by 45
backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = BackgroundFill; backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = BackgroundFill;
//@description Describes a freeform gradient fill of a background @colors A list of 3 or 4 colors of the freeform gradients in the RGB24 format
backgroundFillFreeformGradient colors:vector<int32> = BackgroundFill;
//@class BackgroundType @description Describes the type of a background //@class BackgroundType @description Describes the type of a background

View File

@ -28,6 +28,7 @@
#include "td/db/SqliteKeyValueAsync.h" #include "td/db/SqliteKeyValueAsync.h"
#include "td/utils/algorithm.h" #include "td/utils/algorithm.h"
#include "td/utils/base64.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/format.h" #include "td/utils/format.h"
@ -393,7 +394,7 @@ void BackgroundManager::reload_background(BackgroundId background_id, int64 acce
} }
static bool is_background_name_local(Slice name) { static bool is_background_name_local(Slice name) {
return name.size() <= 6 || name.find('?') <= 13u; return name.size() <= 13u || name.find('?') <= 13u || !is_base64url_characters(name.substr(0, name.find('?')));
} }
BackgroundId BackgroundManager::search_background(const string &name, Promise<Unit> &&promise) { BackgroundId BackgroundManager::search_background(const string &name, Promise<Unit> &&promise) {
@ -409,49 +410,12 @@ BackgroundId BackgroundManager::search_background(const string &name, Promise<Un
} }
if (is_background_name_local(name)) { if (is_background_name_local(name)) {
Slice fill_colors = name; auto r_fill = BackgroundFill::get_background_fill(name);
Slice parameters; if (r_fill.is_error()) {
auto parameters_pos = fill_colors.find('?'); promise.set_error(r_fill.move_as_error());
if (parameters_pos != Slice::npos) { return BackgroundId();
parameters = fill_colors.substr(parameters_pos + 1);
fill_colors = fill_colors.substr(0, parameters_pos);
} }
CHECK(fill_colors.size() <= 13u); auto background_id = add_fill_background(r_fill.ok());
bool have_hyphen = false;
size_t hyphen_pos = 0;
for (size_t i = 0; i < fill_colors.size(); i++) {
auto c = fill_colors[i];
if (!is_hex_digit(c)) {
if (c != '-' || have_hyphen || i > 6 || i + 7 < fill_colors.size()) {
promise.set_error(Status::Error(400, "WALLPAPER_INVALID"));
return BackgroundId();
}
have_hyphen = true;
hyphen_pos = i;
}
}
BackgroundFill fill;
if (have_hyphen) {
int32 top_color = static_cast<int32>(hex_to_integer<uint32>(fill_colors.substr(0, hyphen_pos)));
int32 bottom_color = static_cast<int32>(hex_to_integer<uint32>(fill_colors.substr(hyphen_pos + 1)));
int32 rotation_angle = 0;
Slice prefix("rotation=");
if (begins_with(parameters, prefix)) {
rotation_angle = to_integer<int32>(parameters.substr(prefix.size()));
if (!BackgroundFill::is_valid_rotation_angle(rotation_angle)) {
rotation_angle = 0;
}
}
fill = BackgroundFill(top_color, bottom_color, rotation_angle);
} else {
int32 color = static_cast<int32>(hex_to_integer<uint32>(fill_colors));
fill = BackgroundFill(color);
}
auto background_id = add_fill_background(fill);
promise.set_value(Unit()); promise.set_value(Unit());
return background_id; return background_id;
} }
@ -538,7 +502,7 @@ Result<FileId> BackgroundManager::prepare_input_file(const tl_object_ptr<td_api:
} }
BackgroundId BackgroundManager::add_fill_background(const BackgroundFill &fill) { BackgroundId BackgroundManager::add_fill_background(const BackgroundFill &fill) {
return add_fill_background(fill, false, (fill.top_color & 0x808080) == 0 && (fill.bottom_color & 0x808080) == 0); return add_fill_background(fill, false, fill.is_dark());
} }
BackgroundId BackgroundManager::add_fill_background(const BackgroundFill &fill, bool is_default, bool is_dark) { BackgroundId BackgroundManager::add_fill_background(const BackgroundFill &fill, bool is_default, bool is_dark) {
@ -933,16 +897,10 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
return BackgroundId(); return BackgroundId();
} }
bool has_color = (settings->flags_ & telegram_api::wallPaperSettings::BACKGROUND_COLOR_MASK) != 0;
auto color = has_color ? settings->background_color_ : 0;
auto is_default = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DEFAULT_MASK) != 0; auto is_default = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DEFAULT_MASK) != 0;
auto is_dark = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DARK_MASK) != 0; auto is_dark = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DARK_MASK) != 0;
BackgroundFill fill = BackgroundFill(color); return add_fill_background(BackgroundFill(settings.get()), is_default, is_dark);
if ((settings->flags_ & telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK) != 0) {
fill = BackgroundFill(color, settings->second_background_color_, settings->rotation_);
}
return add_fill_background(fill, is_default, is_dark);
} }
auto wallpaper = move_tl_object_as<telegram_api::wallPaper>(wallpaper_ptr); auto wallpaper = move_tl_object_as<telegram_api::wallPaper>(wallpaper_ptr);
@ -994,8 +952,9 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
name_to_background_id_.emplace(expected_background_name, id); name_to_background_id_.emplace(expected_background_name, id);
} }
if (G()->parameters().use_file_db && !is_background_name_local(background.name)) { if (G()->parameters().use_file_db) {
LOG(INFO) << "Save " << id << " to database with name " << background.name; LOG(INFO) << "Save " << id << " to database with name " << background.name;
CHECK(!is_background_name_local(background.name));
G()->td_db()->get_sqlite_pmc()->set(get_background_name_database_key(background.name), G()->td_db()->get_sqlite_pmc()->set(get_background_name_database_key(background.name),
log_event_store(background).as_slice().str(), Auto()); log_event_store(background).as_slice().str(), Auto());
} }

View File

@ -7,6 +7,7 @@
#include "td/telegram/BackgroundType.h" #include "td/telegram/BackgroundType.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/SliceBuilder.h" #include "td/utils/SliceBuilder.h"
@ -15,7 +16,7 @@ namespace td {
static string get_color_hex_string(int32 color) { static string get_color_hex_string(int32 color) {
string result; string result;
for (int i = 20; i >= 0; i -= 4) { for (int i = 20; i >= 0; i -= 4) {
result += "0123456789abcdef"[(color >> i) & 0xf]; result += "0123456789abcdef"[(color >> i) & 0xF];
} }
return result; return result;
} }
@ -24,6 +25,57 @@ static bool is_valid_color(int32 color) {
return 0 <= color && color <= 0xFFFFFF; return 0 <= color && color <= 0xFFFFFF;
} }
static bool is_valid_rotation_angle(int32 rotation_angle) {
return 0 <= rotation_angle && rotation_angle < 360 && rotation_angle % 45 == 0;
}
BackgroundFill::BackgroundFill(const telegram_api::wallPaperSettings *settings) {
if (settings == nullptr) {
return;
}
auto flags = settings->flags_;
if ((flags & telegram_api::wallPaperSettings::BACKGROUND_COLOR_MASK) != 0) {
top_color = settings->background_color_;
if (!is_valid_color(top_color)) {
LOG(ERROR) << "Receive " << to_string(*settings);
top_color = 0;
}
}
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0 ||
(flags & telegram_api::wallPaperSettings::THIRD_BACKGROUND_COLOR_MASK) != 0) {
bottom_color = settings->second_background_color_;
if (!is_valid_color(bottom_color)) {
LOG(ERROR) << "Receive " << to_string(*settings);
bottom_color = 0;
}
third_color = settings->third_background_color_;
if (!is_valid_color(third_color)) {
LOG(ERROR) << "Receive " << to_string(*settings);
third_color = 0;
}
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0) {
fourth_color = settings->fourth_background_color_;
if (!is_valid_color(fourth_color)) {
LOG(ERROR) << "Receive " << to_string(*settings);
fourth_color = 0;
}
}
} else if ((flags & telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK) != 0) {
bottom_color = settings->second_background_color_;
if (!is_valid_color(bottom_color)) {
LOG(ERROR) << "Receive " << to_string(*settings);
bottom_color = 0;
}
rotation_angle = settings->rotation_;
if (!is_valid_rotation_angle(rotation_angle)) {
LOG(ERROR) << "Receive " << to_string(*settings);
rotation_angle = 0;
}
}
}
static Result<BackgroundFill> get_background_fill(const td_api::BackgroundFill *fill) { static Result<BackgroundFill> get_background_fill(const td_api::BackgroundFill *fill) {
if (fill == nullptr) { if (fill == nullptr) {
return Status::Error(400, "Background fill info must be non-empty"); return Status::Error(400, "Background fill info must be non-empty");
@ -44,17 +96,85 @@ static Result<BackgroundFill> get_background_fill(const td_api::BackgroundFill *
if (!is_valid_color(gradient->bottom_color_)) { if (!is_valid_color(gradient->bottom_color_)) {
return Status::Error(400, "Invalid bottom gradient color value"); return Status::Error(400, "Invalid bottom gradient color value");
} }
if (!BackgroundFill::is_valid_rotation_angle(gradient->rotation_angle_)) { if (!is_valid_rotation_angle(gradient->rotation_angle_)) {
return Status::Error(400, "Invalid rotation angle value"); return Status::Error(400, "Invalid rotation angle value");
} }
return BackgroundFill(gradient->top_color_, gradient->bottom_color_, gradient->rotation_angle_); return BackgroundFill(gradient->top_color_, gradient->bottom_color_, gradient->rotation_angle_);
} }
case td_api::backgroundFillFreeformGradient::ID: {
auto freeform = static_cast<const td_api::backgroundFillFreeformGradient *>(fill);
if (freeform->colors_.size() != 3 && freeform->colors_.size() != 4) {
return Status::Error(400, "Wrong number of gradient colors");
}
for (auto &color : freeform->colors_) {
if (!is_valid_color(color)) {
return Status::Error(400, "Invalid freeform gradient color value");
}
}
return BackgroundFill(freeform->colors_[0], freeform->colors_[1], freeform->colors_[2],
freeform->colors_.size() == 3 ? -1 : freeform->colors_[3]);
}
default: default:
UNREACHABLE(); UNREACHABLE();
return {}; return {};
} }
} }
Result<BackgroundFill> BackgroundFill::get_background_fill(Slice name) {
name = name.substr(0, name.find('#'));
Slice parameters;
auto parameters_pos = name.find('?');
if (parameters_pos != Slice::npos) {
parameters = name.substr(parameters_pos + 1);
name = name.substr(0, parameters_pos);
}
auto get_color = [](Slice color_string) -> Result<int32> {
auto r_color = hex_to_integer_safe<uint32>(color_string);
if (r_color.is_error() || color_string.size() > 6) {
return Status::Error(400, "WALLPAPER_INVALID");
}
return static_cast<int32>(r_color.ok());
};
if (name.find('~') < name.size()) {
vector<Slice> color_strings = full_split(name, '~');
if (color_strings.size() != 4 && color_strings.size() != 3) {
return Status::Error(400, "WALLPAPER_INVALID");
}
TRY_RESULT(first_color, get_color(color_strings[0]));
TRY_RESULT(second_color, get_color(color_strings[1]));
TRY_RESULT(third_color, get_color(color_strings[2]));
int32 fourth_color = -1;
if (color_strings.size() == 4) {
TRY_RESULT_ASSIGN(fourth_color, get_color(color_strings[3]));
}
return BackgroundFill(first_color, second_color, third_color, fourth_color);
}
size_t hyphen_pos = name.find('-');
if (hyphen_pos < name.size()) {
TRY_RESULT(top_color, get_color(name.substr(0, hyphen_pos)));
TRY_RESULT(bottom_color, get_color(name.substr(hyphen_pos + 1)));
int32 rotation_angle = 0;
Slice prefix("rotation=");
if (begins_with(parameters, prefix)) {
rotation_angle = to_integer<int32>(parameters.substr(prefix.size()));
if (!is_valid_rotation_angle(rotation_angle)) {
rotation_angle = 0;
}
}
return BackgroundFill(top_color, bottom_color, rotation_angle);
}
TRY_RESULT(color, get_color(name));
return BackgroundFill(color);
}
static string get_background_fill_color_hex_string(const BackgroundFill &fill, bool is_first) { static string get_background_fill_color_hex_string(const BackgroundFill &fill, bool is_first) {
switch (fill.get_type()) { switch (fill.get_type()) {
case BackgroundFill::Type::Solid: case BackgroundFill::Type::Solid:
@ -67,6 +187,15 @@ static string get_background_fill_color_hex_string(const BackgroundFill &fill, b
} }
return colors; return colors;
} }
case BackgroundFill::Type::FreeformGradient: {
SliceBuilder sb;
sb << get_color_hex_string(fill.top_color) << '~' << get_color_hex_string(fill.bottom_color) << '~'
<< get_color_hex_string(fill.third_color);
if (fill.fourth_color != -1) {
sb << '~' << get_color_hex_string(fill.fourth_color);
}
return sb.as_cslice().str();
}
default: default:
UNREACHABLE(); UNREACHABLE();
return string(); return string();
@ -80,13 +209,38 @@ static bool is_valid_intensity(int32 intensity) {
int64 BackgroundFill::get_id() const { int64 BackgroundFill::get_id() const {
CHECK(is_valid_color(top_color)); CHECK(is_valid_color(top_color));
CHECK(is_valid_color(bottom_color)); CHECK(is_valid_color(bottom_color));
CHECK(is_valid_rotation_angle(rotation_angle));
switch (get_type()) { switch (get_type()) {
case Type::Solid: case Type::Solid:
return static_cast<int64>(top_color) + 1; return static_cast<int64>(top_color) + 1;
case Type::Gradient: case Type::Gradient:
CHECK(is_valid_rotation_angle(rotation_angle));
return (rotation_angle / 45) * 0x1000001000001 + (static_cast<int64>(top_color) << 24) + bottom_color + return (rotation_angle / 45) * 0x1000001000001 + (static_cast<int64>(top_color) << 24) + bottom_color +
(1 << 24) + 1; (1 << 24) + 1;
case Type::FreeformGradient: {
CHECK(is_valid_color(third_color));
CHECK(fourth_color == -1 || is_valid_color(fourth_color));
const uint64 mul = 123456789;
uint64 result = static_cast<uint64>(top_color);
result = result * mul + static_cast<uint64>(bottom_color);
result = result * mul + static_cast<uint64>(third_color);
result = result * mul + static_cast<uint64>(fourth_color);
return 0x8000008000008 + static_cast<int64>(result % 0x8000008000008);
}
default:
UNREACHABLE();
return 0;
}
}
bool BackgroundFill::is_dark() const {
switch (get_type()) {
case Type::Solid:
return (top_color & 0x808080) == 0;
case Type::Gradient:
return (top_color & 0x808080) == 0 && (bottom_color & 0x808080) == 0;
case Type::FreeformGradient:
return (top_color & 0x808080) == 0 && (bottom_color & 0x808080) == 0 && (third_color & 0x808080) == 0 &&
(fourth_color == -1 || (fourth_color & 0x808080) == 0);
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
@ -94,12 +248,13 @@ int64 BackgroundFill::get_id() const {
} }
bool BackgroundFill::is_valid_id(int64 id) { bool BackgroundFill::is_valid_id(int64 id) {
return 0 < id && id < 0x8000008000008; return 0 < id && id < 0x8000008000008 * 2;
} }
bool operator==(const BackgroundFill &lhs, const BackgroundFill &rhs) { bool operator==(const BackgroundFill &lhs, const BackgroundFill &rhs) {
return lhs.top_color == rhs.top_color && lhs.bottom_color == rhs.bottom_color && return lhs.top_color == rhs.top_color && lhs.bottom_color == rhs.bottom_color &&
lhs.rotation_angle == rhs.rotation_angle; lhs.rotation_angle == rhs.rotation_angle && lhs.third_color == rhs.third_color &&
lhs.fourth_color == rhs.fourth_color;
} }
string BackgroundType::get_link() const { string BackgroundType::get_link() const {
@ -198,39 +353,13 @@ BackgroundType get_background_type(bool is_pattern,
telegram_api::object_ptr<telegram_api::wallPaperSettings> settings) { telegram_api::object_ptr<telegram_api::wallPaperSettings> settings) {
bool is_blurred = false; bool is_blurred = false;
bool is_moving = false; bool is_moving = false;
BackgroundFill fill; BackgroundFill fill(settings.get());
int32 intensity = 0; int32 intensity = 0;
if (settings) { if (settings) {
auto flags = settings->flags_; auto flags = settings->flags_;
is_blurred = (flags & telegram_api::wallPaperSettings::BLUR_MASK) != 0; is_blurred = (flags & telegram_api::wallPaperSettings::BLUR_MASK) != 0;
is_moving = (flags & telegram_api::wallPaperSettings::MOTION_MASK) != 0; is_moving = (flags & telegram_api::wallPaperSettings::MOTION_MASK) != 0;
int32 color = 0;
if ((flags & telegram_api::wallPaperSettings::BACKGROUND_COLOR_MASK) != 0) {
color = settings->background_color_;
if (!is_valid_color(color)) {
LOG(ERROR) << "Receive " << to_string(settings);
color = 0;
}
}
if ((flags & telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK) != 0) {
int32 second_color = settings->second_background_color_;
if (!is_valid_color(second_color)) {
LOG(ERROR) << "Receive " << to_string(settings);
second_color = 0;
}
int32 rotation_angle = settings->rotation_;
if (!BackgroundFill::is_valid_rotation_angle(rotation_angle)) {
LOG(ERROR) << "Receive " << to_string(settings);
rotation_angle = 0;
}
fill = BackgroundFill(color, second_color, rotation_angle);
} else {
fill = BackgroundFill(color);
}
if ((flags & telegram_api::wallPaperSettings::INTENSITY_MASK) != 0) { if ((flags & telegram_api::wallPaperSettings::INTENSITY_MASK) != 0) {
intensity = settings->intensity_; intensity = settings->intensity_;
if (!is_valid_intensity(intensity)) { if (!is_valid_intensity(intensity)) {
@ -253,6 +382,13 @@ static td_api::object_ptr<td_api::BackgroundFill> get_background_fill_object(con
case BackgroundFill::Type::Gradient: case BackgroundFill::Type::Gradient:
return td_api::make_object<td_api::backgroundFillGradient>(fill.top_color, fill.bottom_color, return td_api::make_object<td_api::backgroundFillGradient>(fill.top_color, fill.bottom_color,
fill.rotation_angle); fill.rotation_angle);
case BackgroundFill::Type::FreeformGradient: {
vector<int32> colors{fill.top_color, fill.bottom_color, fill.third_color, fill.fourth_color};
if (colors.back() == -1) {
colors.pop_back();
}
return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
}
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
@ -285,6 +421,12 @@ telegram_api::object_ptr<telegram_api::wallPaperSettings> get_input_wallpaper_se
flags |= telegram_api::wallPaperSettings::MOTION_MASK; flags |= telegram_api::wallPaperSettings::MOTION_MASK;
} }
switch (type.fill.get_type()) { switch (type.fill.get_type()) {
case BackgroundFill::Type::FreeformGradient:
if (type.fill.fourth_color != -1) {
flags |= telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK;
}
flags |= telegram_api::wallPaperSettings::THIRD_BACKGROUND_COLOR_MASK;
// fallthrough
case BackgroundFill::Type::Gradient: case BackgroundFill::Type::Gradient:
flags |= telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK; flags |= telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK;
// fallthrough // fallthrough
@ -297,9 +439,9 @@ telegram_api::object_ptr<telegram_api::wallPaperSettings> get_input_wallpaper_se
if (type.intensity != 0) { if (type.intensity != 0) {
flags |= telegram_api::wallPaperSettings::INTENSITY_MASK; flags |= telegram_api::wallPaperSettings::INTENSITY_MASK;
} }
return telegram_api::make_object<telegram_api::wallPaperSettings>(flags, false /*ignored*/, false /*ignored*/, return telegram_api::make_object<telegram_api::wallPaperSettings>(
type.fill.top_color, type.fill.bottom_color, 0, 0, flags, false /*ignored*/, false /*ignored*/, type.fill.top_color, type.fill.bottom_color, type.fill.third_color,
type.intensity, type.fill.rotation_angle); type.fill.fourth_color, type.intensity, type.fill.rotation_angle);
} }
} // namespace td } // namespace td

View File

@ -19,6 +19,8 @@ struct BackgroundFill {
int32 top_color = 0; int32 top_color = 0;
int32 bottom_color = 0; int32 bottom_color = 0;
int32 rotation_angle = 0; int32 rotation_angle = 0;
int32 third_color = -1;
int32 fourth_color = -1;
BackgroundFill() = default; BackgroundFill() = default;
explicit BackgroundFill(int32 solid_color) : top_color(solid_color), bottom_color(solid_color) { explicit BackgroundFill(int32 solid_color) : top_color(solid_color), bottom_color(solid_color) {
@ -26,9 +28,19 @@ struct BackgroundFill {
BackgroundFill(int32 top_color, int32 bottom_color, int32 rotation_angle) BackgroundFill(int32 top_color, int32 bottom_color, int32 rotation_angle)
: top_color(top_color), bottom_color(bottom_color), rotation_angle(rotation_angle) { : top_color(top_color), bottom_color(bottom_color), rotation_angle(rotation_angle) {
} }
BackgroundFill(int32 first_color, int32 second_color, int32 third_color, int32 fourth_color)
: top_color(first_color), bottom_color(second_color), third_color(third_color), fourth_color(fourth_color) {
}
enum class Type : int32 { Solid, Gradient }; explicit BackgroundFill(const telegram_api::wallPaperSettings *settings);
static Result<BackgroundFill> get_background_fill(Slice name);
enum class Type : int32 { Solid, Gradient, FreeformGradient };
Type get_type() const { Type get_type() const {
if (third_color != -1) {
return Type::FreeformGradient;
}
if (top_color == bottom_color) { if (top_color == bottom_color) {
return Type::Solid; return Type::Solid;
} }
@ -37,11 +49,9 @@ struct BackgroundFill {
int64 get_id() const; int64 get_id() const;
static bool is_valid_id(int64 id); bool is_dark() const;
static bool is_valid_rotation_angle(int32 rotation_angle) { static bool is_valid_id(int64 id);
return 0 <= rotation_angle && rotation_angle < 360 && rotation_angle % 45 == 0;
}
}; };
bool operator==(const BackgroundFill &lhs, const BackgroundFill &rhs); bool operator==(const BackgroundFill &lhs, const BackgroundFill &rhs);

View File

@ -18,15 +18,22 @@ void store(const BackgroundType &type, StorerT &storer) {
bool has_intensity = type.intensity != 0; bool has_intensity = type.intensity != 0;
auto fill_type = type.fill.get_type(); auto fill_type = type.fill.get_type();
bool is_gradient = fill_type == BackgroundFill::Type::Gradient; bool is_gradient = fill_type == BackgroundFill::Type::Gradient;
bool is_freeform_gradient = fill_type == BackgroundFill::Type::FreeformGradient;
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(type.is_blurred); STORE_FLAG(type.is_blurred);
STORE_FLAG(type.is_moving); STORE_FLAG(type.is_moving);
STORE_FLAG(has_fill); STORE_FLAG(has_fill);
STORE_FLAG(has_intensity); STORE_FLAG(has_intensity);
STORE_FLAG(is_gradient); STORE_FLAG(is_gradient);
STORE_FLAG(is_freeform_gradient);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(type.type, storer); store(type.type, storer);
if (has_fill) { if (is_freeform_gradient) {
store(type.fill.top_color, storer);
store(type.fill.bottom_color, storer);
store(type.fill.third_color, storer);
store(type.fill.fourth_color, storer);
} else if (has_fill) {
store(type.fill.top_color, storer); store(type.fill.top_color, storer);
if (is_gradient) { if (is_gradient) {
store(type.fill.bottom_color, storer); store(type.fill.bottom_color, storer);
@ -43,15 +50,22 @@ void parse(BackgroundType &type, ParserT &parser) {
bool has_fill; bool has_fill;
bool has_intensity; bool has_intensity;
bool is_gradient; bool is_gradient;
bool is_freeform_gradient;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(type.is_blurred); PARSE_FLAG(type.is_blurred);
PARSE_FLAG(type.is_moving); PARSE_FLAG(type.is_moving);
PARSE_FLAG(has_fill); PARSE_FLAG(has_fill);
PARSE_FLAG(has_intensity); PARSE_FLAG(has_intensity);
PARSE_FLAG(is_gradient); PARSE_FLAG(is_gradient);
PARSE_FLAG(is_freeform_gradient);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
parse(type.type, parser); parse(type.type, parser);
if (has_fill) { if (is_freeform_gradient) {
parse(type.fill.top_color, parser);
parse(type.fill.bottom_color, parser);
parse(type.fill.third_color, parser);
parse(type.fill.fourth_color, parser);
} else if (has_fill) {
parse(type.fill.top_color, parser); parse(type.fill.top_color, parser);
if (is_gradient) { if (is_gradient) {
parse(type.fill.bottom_color, parser); parse(type.fill.bottom_color, parser);

View File

@ -1535,6 +1535,10 @@ class CliClient final : public Actor {
return td_api::make_object<td_api::backgroundFillGradient>(top_color, bottom_color, Random::fast(0, 7) * 45); return td_api::make_object<td_api::backgroundFillGradient>(top_color, bottom_color, Random::fast(0, 7) * 45);
} }
static td_api::object_ptr<td_api::BackgroundFill> get_background_fill(vector<int32> colors) {
return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
}
static td_api::object_ptr<td_api::BackgroundType> get_solid_pattern_background(int32 color, int32 intensity, static td_api::object_ptr<td_api::BackgroundType> get_solid_pattern_background(int32 color, int32 intensity,
bool is_moving) { bool is_moving) {
return get_gradient_pattern_background(color, color, intensity, is_moving); return get_gradient_pattern_background(color, color, intensity, is_moving);
@ -1546,6 +1550,13 @@ class CliClient final : public Actor {
is_moving); is_moving);
} }
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_pattern_background(vector<int32> colors,
int32 intensity,
bool is_moving) {
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(std::move(colors)), intensity,
is_moving);
}
static td_api::object_ptr<td_api::BackgroundType> get_solid_background(int32 color) { static td_api::object_ptr<td_api::BackgroundType> get_solid_background(int32 color) {
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(color)); return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(color));
} }
@ -1554,6 +1565,10 @@ class CliClient final : public Actor {
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(top_color, bottom_color)); return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(top_color, bottom_color));
} }
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_background(vector<int32> colors) {
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(std::move(colors)));
}
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> f) { static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> f) {
if (combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) { if (combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) {
LOG(ERROR) << "Execute request: " << to_string(f); LOG(ERROR) << "Execute request: " << to_string(f);
@ -2206,12 +2221,19 @@ class CliClient final : public Actor {
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, true)); send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, true));
send_get_background_url(get_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, true)); send_get_background_url(get_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, true));
send_get_background_url(get_gradient_pattern_background(0, 0x1000000, 49, true)); send_get_background_url(get_gradient_pattern_background(0, 0x1000000, 49, true));
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA}, 49, true));
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0x111111, 0x222222}, 49, true));
send_get_background_url(
get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}, 49, true));
send_get_background_url(get_solid_background(-1)); send_get_background_url(get_solid_background(-1));
send_get_background_url(get_solid_background(0xABCDEF)); send_get_background_url(get_solid_background(0xABCDEF));
send_get_background_url(get_solid_background(0x1000000)); send_get_background_url(get_solid_background(0x1000000));
send_get_background_url(get_gradient_background(0xABCDEF, 0xFEDCBA)); send_get_background_url(get_gradient_background(0xABCDEF, 0xFEDCBA));
send_get_background_url(get_gradient_background(0, 0)); send_get_background_url(get_gradient_background(0, 0));
send_get_background_url(get_gradient_background(-1, -1)); send_get_background_url(get_gradient_background(-1, -1));
send_get_background_url(get_freeform_gradient_background({0xFEDCBA, 0x222222}));
send_get_background_url(get_freeform_gradient_background({0xFEDCBA, 0x111111, 0x222222}));
send_get_background_url(get_freeform_gradient_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}));
} else if (op == "sbg") { } else if (op == "sbg") {
send_request(td_api::make_object<td_api::searchBackground>(args)); send_request(td_api::make_object<td_api::searchBackground>(args));
} else if (op == "sbgd") { } else if (op == "sbgd") {
@ -2237,6 +2259,9 @@ class CliClient final : public Actor {
get_args(args, top_color, bottom_color); get_args(args, top_color, bottom_color);
auto background_type = get_gradient_background(top_color, bottom_color); auto background_type = get_gradient_background(top_color, bottom_color);
send_request(td_api::make_object<td_api::setBackground>(nullptr, std::move(background_type), op == "sbggd")); send_request(td_api::make_object<td_api::setBackground>(nullptr, std::move(background_type), op == "sbggd"));
} else if (op == "sbgfg" || op == "sbgfgd") {
auto background_type = get_freeform_gradient_background(to_integers<int32>(args));
send_request(td_api::make_object<td_api::setBackground>(nullptr, std::move(background_type), op == "sbgfgd"));
} else if (op == "sbgwid" || op == "sbgwidd") { } else if (op == "sbgwid" || op == "sbgwidd") {
send_request(td_api::make_object<td_api::setBackground>( send_request(td_api::make_object<td_api::setBackground>(
td_api::make_object<td_api::inputBackgroundRemote>(to_integer<int64>(args)), td_api::make_object<td_api::inputBackgroundRemote>(to_integer<int64>(args)),

View File

@ -226,13 +226,16 @@ Result<typename std::enable_if<std::is_unsigned<T>::value, T>::type> hex_to_inte
T integer_value = 0; T integer_value = 0;
auto begin = str.begin(); auto begin = str.begin();
auto end = str.end(); auto end = str.end();
if (begin == end) {
return Status::Error("String is empty");
}
while (begin != end) { while (begin != end) {
T digit = hex_to_int(*begin++); T digit = hex_to_int(*begin++);
if (digit == 16) { if (digit == 16) {
return Status::Error("Not a hex digit"); return Status::Error("String contains non-hex digit");
} }
if (integer_value > std::numeric_limits<T>::max() / 16) { if (integer_value > std::numeric_limits<T>::max() / 16) {
return Status::Error("Hex number overflow"); return Status::Error("String hex number overflows");
} }
integer_value = integer_value * 16 + digit; integer_value = integer_value * 16 + digit;
} }