From 740880b9ca61ae67638514c18f327e422bf0f5df Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 27 Apr 2019 03:57:59 +0300 Subject: [PATCH] Refactor WebPagesManager::PageBlock to a separate class. GitOrigin-RevId: 7a705f0929c1b4419d2cf0693dda747a172dbc28 --- CMakeLists.txt | 2 + td/telegram/WebPageBlock.cpp | 2283 ++++++++++++++++++++++++++++++ td/telegram/WebPageBlock.h | 104 ++ td/telegram/WebPagesManager.cpp | 2288 +------------------------------ td/telegram/WebPagesManager.h | 83 +- 5 files changed, 2394 insertions(+), 2366 deletions(-) create mode 100644 td/telegram/WebPageBlock.cpp create mode 100644 td/telegram/WebPageBlock.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d0519729..e585cb4e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -446,6 +446,7 @@ set(TDLIB_SOURCE td/telegram/VideosManager.cpp td/telegram/VoiceNotesManager.cpp td/telegram/WallpaperManager.cpp + td/telegram/WebPageBlock.cpp td/telegram/WebPagesManager.cpp td/mtproto/AuthData.h @@ -611,6 +612,7 @@ set(TDLIB_SOURCE td/telegram/VideosManager.h td/telegram/VoiceNotesManager.h td/telegram/WallpaperManager.h + td/telegram/WebPageBlock.h td/telegram/WebPageId.h td/telegram/WebPagesManager.h diff --git a/td/telegram/WebPageBlock.cpp b/td/telegram/WebPageBlock.cpp new file mode 100644 index 000000000..e4dceb318 --- /dev/null +++ b/td/telegram/WebPageBlock.cpp @@ -0,0 +1,2283 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/WebPageBlock.h" + +#include "td/telegram/AnimationsManager.h" +#include "td/telegram/AnimationsManager.hpp" +#include "td/telegram/AudiosManager.h" +#include "td/telegram/AudiosManager.hpp" +#include "td/telegram/ChannelId.h" +#include "td/telegram/ContactsManager.h" +#include "td/telegram/Document.h" +#include "td/telegram/Document.hpp" +#include "td/telegram/DocumentsManager.h" +#include "td/telegram/DocumentsManager.hpp" +#include "td/telegram/files/FileId.h" +#include "td/telegram/files/FileManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/Location.h" +#include "td/telegram/Photo.h" +#include "td/telegram/Photo.hpp" +#include "td/telegram/StickersManager.h" +#include "td/telegram/StickersManager.hpp" +#include "td/telegram/Td.h" +#include "td/telegram/Version.h" +#include "td/telegram/VideoNotesManager.h" +#include "td/telegram/VideoNotesManager.hpp" +#include "td/telegram/VideosManager.h" +#include "td/telegram/VideosManager.hpp" +#include "td/telegram/VoiceNotesManager.h" +#include "td/telegram/VoiceNotesManager.hpp" + +#include "td/utils/common.h" +#include "td/utils/logging.h" +#include "td/utils/misc.h" +#include "td/utils/tl_helpers.h" + +#include + +namespace td { + +namespace { + +class RichText { + static vector> get_rich_text_objects(const vector &rich_texts) { + return transform(rich_texts, [](const RichText &rich_text) { return rich_text.get_rich_text_object(); }); + } + + public: + enum class Type : int32 { + Plain, + Bold, + Italic, + Underline, + Strikethrough, + Fixed, + Url, + EmailAddress, + Concatenation, + Subscript, + Superscript, + Marked, + PhoneNumber, + Icon, + Anchor + }; + Type type = Type::Plain; + string content; + vector texts; + FileId document_file_id; + WebPageId web_page_id; + + bool empty() const { + return type == Type::Plain && content.empty(); + } + + void append_file_ids(vector &file_ids) const { + if (type == RichText::Type::Icon) { + CHECK(document_file_id.is_valid()); + file_ids.push_back(document_file_id); + auto thumbnail_file_id = + G()->td().get_actor_unsafe()->documents_manager_->get_document_thumbnail_file_id(document_file_id); + if (thumbnail_file_id.is_valid()) { + file_ids.push_back(thumbnail_file_id); + } + } else { + for (auto &text : texts) { + text.append_file_ids(file_ids); + } + } + } + + td_api::object_ptr get_rich_text_object() const { + switch (type) { + case RichText::Type::Plain: + return make_tl_object(content); + case RichText::Type::Bold: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Italic: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Underline: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Strikethrough: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Fixed: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Url: + return make_tl_object(texts[0].get_rich_text_object(), content); + case RichText::Type::EmailAddress: + return make_tl_object(texts[0].get_rich_text_object(), content); + case RichText::Type::Concatenation: + return make_tl_object(get_rich_text_objects(texts)); + case RichText::Type::Subscript: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Superscript: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::Marked: + return make_tl_object(texts[0].get_rich_text_object()); + case RichText::Type::PhoneNumber: + return make_tl_object(texts[0].get_rich_text_object(), content); + case RichText::Type::Icon: { + auto dimensions = to_integer(content); + auto width = static_cast(dimensions / 65536); + auto height = static_cast(dimensions % 65536); + return make_tl_object( + G()->td().get_actor_unsafe()->documents_manager_->get_document_object(document_file_id), width, height); + } + case RichText::Type::Anchor: + return make_tl_object(texts[0].get_rich_text_object(), content); + } + UNREACHABLE(); + return nullptr; + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(type, storer); + store(content, storer); + store(texts, storer); + if (type == Type::Icon) { + storer.context()->td().get_actor_unsafe()->documents_manager_->store_document(document_file_id, storer); + } + if (type == Type::Url) { + store(web_page_id, storer); + } + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(type, parser); + parse(content, parser); + parse(texts, parser); + if (type == Type::Icon) { + document_file_id = parser.context()->td().get_actor_unsafe()->documents_manager_->parse_document(parser); + if (!document_file_id.is_valid()) { + LOG(ERROR) << "Failed to load document from database"; + *this = RichText(); + } + } else { + document_file_id = FileId(); + } + if (type == Type::Url && parser.version() >= static_cast(Version::SupportInstantView2_0)) { + parse(web_page_id, parser); + } else { + web_page_id = WebPageId(); + } + } +}; + +class WebPageBlockCaption { + public: + RichText text; + RichText credit; + + void append_file_ids(vector &file_ids) const { + text.append_file_ids(file_ids); + credit.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_caption_object() const { + return td_api::make_object(text.get_rich_text_object(), credit.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(text, storer); + store(credit, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(text, parser); + if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { + parse(credit, parser); + } else { + credit = RichText(); + } + } +}; + +class WebPageBlockTableCell { + public: + RichText text; + bool is_header = false; + bool align_left = false; + bool align_center = false; + bool align_right = false; + bool valign_top = false; + bool valign_middle = false; + bool valign_bottom = false; + int32 colspan = 1; + int32 rowspan = 1; + + td_api::object_ptr get_page_block_table_cell_object() const { + auto align = [&]() -> td_api::object_ptr { + if (align_left) { + return td_api::make_object(); + } + if (align_center) { + return td_api::make_object(); + } + if (align_right) { + return td_api::make_object(); + } + UNREACHABLE(); + return nullptr; + }(); + auto valign = [&]() -> td_api::object_ptr { + if (valign_top) { + return td_api::make_object(); + } + if (valign_middle) { + return td_api::make_object(); + } + if (valign_bottom) { + return td_api::make_object(); + } + UNREACHABLE(); + return nullptr; + }(); + return td_api::make_object(text.get_rich_text_object(), is_header, colspan, rowspan, + std::move(align), std::move(valign)); + } + + template + void store(StorerT &storer) const { + using ::td::store; + bool has_text = !text.empty(); + bool has_colspan = colspan != 1; + bool has_rowspan = rowspan != 1; + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_header); + STORE_FLAG(align_left); + STORE_FLAG(align_center); + STORE_FLAG(align_right); + STORE_FLAG(valign_top); + STORE_FLAG(valign_middle); + STORE_FLAG(valign_bottom); + STORE_FLAG(has_text); + STORE_FLAG(has_colspan); + STORE_FLAG(has_rowspan); + END_STORE_FLAGS(); + if (has_text) { + store(text, storer); + } + if (has_colspan) { + store(colspan, storer); + } + if (has_rowspan) { + store(rowspan, storer); + } + } + + template + void parse(ParserT &parser) { + using ::td::parse; + bool has_text; + bool has_colspan; + bool has_rowspan; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_header); + PARSE_FLAG(align_left); + PARSE_FLAG(align_center); + PARSE_FLAG(align_right); + PARSE_FLAG(valign_top); + PARSE_FLAG(valign_middle); + PARSE_FLAG(valign_bottom); + PARSE_FLAG(has_text); + PARSE_FLAG(has_colspan); + PARSE_FLAG(has_rowspan); + END_PARSE_FLAGS(); + if (has_text) { + parse(text, parser); + } + if (has_colspan) { + parse(colspan, parser); + } + if (has_rowspan) { + parse(rowspan, parser); + } + } +}; + +class RelatedArticle { + public: + string url; + WebPageId web_page_id; + string title; + string description; + Photo photo; + string author; + int32 published_date = 0; + + template + void store(StorerT &storer) const { + using ::td::store; + bool has_title = !title.empty(); + bool has_description = !description.empty(); + bool has_photo = photo.id != -2; + bool has_author = !author.empty(); + bool has_date = published_date != 0; + BEGIN_STORE_FLAGS(); + STORE_FLAG(has_title); + STORE_FLAG(has_description); + STORE_FLAG(has_photo); + STORE_FLAG(has_author); + STORE_FLAG(has_date); + END_STORE_FLAGS(); + store(url, storer); + store(web_page_id, storer); + if (has_title) { + store(title, storer); + } + if (has_description) { + store(description, storer); + } + if (has_photo) { + store(photo, storer); + } + if (has_author) { + store(author, storer); + } + if (has_date) { + store(published_date, storer); + } + } + + template + void parse(ParserT &parser) { + using ::td::parse; + bool has_title; + bool has_description; + bool has_photo; + bool has_author; + bool has_date; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_title); + PARSE_FLAG(has_description); + PARSE_FLAG(has_photo); + PARSE_FLAG(has_author); + PARSE_FLAG(has_date); + END_PARSE_FLAGS(); + parse(url, parser); + parse(web_page_id, parser); + if (has_title) { + parse(title, parser); + } + if (has_description) { + parse(description, parser); + } + if (has_photo) { + parse(photo, parser); + } else { + photo.id = -2; + } + if (has_author) { + parse(author, parser); + } + if (has_date) { + parse(published_date, parser); + } + } +}; + +class WebPageBlockTitle : public WebPageBlock { + RichText title; + + public: + WebPageBlockTitle() = default; + + explicit WebPageBlockTitle(RichText &&title) : title(std::move(title)) { + } + + Type get_type() const override { + return Type::Title; + } + + void append_file_ids(vector &file_ids) const override { + title.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(title.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(title, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(title, parser); + } +}; + +class WebPageBlockSubtitle : public WebPageBlock { + RichText subtitle; + + public: + WebPageBlockSubtitle() = default; + explicit WebPageBlockSubtitle(RichText &&subtitle) : subtitle(std::move(subtitle)) { + } + + Type get_type() const override { + return Type::Subtitle; + } + + void append_file_ids(vector &file_ids) const override { + subtitle.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(subtitle.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(subtitle, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(subtitle, parser); + } +}; + +class WebPageBlockAuthorDate : public WebPageBlock { + RichText author; + int32 date = 0; + + public: + WebPageBlockAuthorDate() = default; + WebPageBlockAuthorDate(RichText &&author, int32 date) : author(std::move(author)), date(max(date, 0)) { + } + + Type get_type() const override { + return Type::AuthorDate; + } + + void append_file_ids(vector &file_ids) const override { + author.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(author.get_rich_text_object(), date); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(author, storer); + store(date, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(author, parser); + parse(date, parser); + } +}; + +class WebPageBlockHeader : public WebPageBlock { + RichText header; + + public: + WebPageBlockHeader() = default; + explicit WebPageBlockHeader(RichText &&header) : header(std::move(header)) { + } + + Type get_type() const override { + return Type::Header; + } + + void append_file_ids(vector &file_ids) const override { + header.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(header.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(header, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(header, parser); + } +}; + +class WebPageBlockSubheader : public WebPageBlock { + RichText subheader; + + public: + WebPageBlockSubheader() = default; + explicit WebPageBlockSubheader(RichText &&subheader) : subheader(std::move(subheader)) { + } + + Type get_type() const override { + return Type::Subheader; + } + + void append_file_ids(vector &file_ids) const override { + subheader.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(subheader.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(subheader, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(subheader, parser); + } +}; + +class WebPageBlockKicker : public WebPageBlock { + RichText kicker; + + public: + WebPageBlockKicker() = default; + explicit WebPageBlockKicker(RichText &&kicker) : kicker(std::move(kicker)) { + } + + Type get_type() const override { + return Type::Kicker; + } + + void append_file_ids(vector &file_ids) const override { + kicker.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(kicker.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(kicker, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(kicker, parser); + } +}; + +class WebPageBlockParagraph : public WebPageBlock { + RichText text; + + public: + WebPageBlockParagraph() = default; + explicit WebPageBlockParagraph(RichText &&text) : text(std::move(text)) { + } + + Type get_type() const override { + return Type::Paragraph; + } + + void append_file_ids(vector &file_ids) const override { + text.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(text.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(text, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(text, parser); + } +}; + +class WebPageBlockPreformatted : public WebPageBlock { + RichText text; + string language; + + public: + WebPageBlockPreformatted() = default; + WebPageBlockPreformatted(RichText &&text, string language) : text(std::move(text)), language(std::move(language)) { + } + + Type get_type() const override { + return Type::Preformatted; + } + + void append_file_ids(vector &file_ids) const override { + text.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(text.get_rich_text_object(), language); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(text, storer); + store(language, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(text, parser); + parse(language, parser); + } +}; + +class WebPageBlockFooter : public WebPageBlock { + RichText footer; + + public: + WebPageBlockFooter() = default; + explicit WebPageBlockFooter(RichText &&footer) : footer(std::move(footer)) { + } + + Type get_type() const override { + return Type::Footer; + } + + void append_file_ids(vector &file_ids) const override { + footer.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(footer.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(footer, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(footer, parser); + } +}; + +class WebPageBlockDivider : public WebPageBlock { + public: + Type get_type() const override { + return Type::Divider; + } + + void append_file_ids(vector &file_ids) const override { + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(); + } + + template + void store(StorerT &storer) const { + } + + template + void parse(ParserT &parser) { + } +}; + +class WebPageBlockAnchor : public WebPageBlock { + string name; + + public: + WebPageBlockAnchor() = default; + explicit WebPageBlockAnchor(string name) : name(std::move(name)) { + } + + Type get_type() const override { + return Type::Anchor; + } + + void append_file_ids(vector &file_ids) const override { + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(name); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(name, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(name, parser); + } +}; + +class WebPageBlockList : public WebPageBlock { + public: + struct Item { + string label; + vector> page_blocks; + + template + void store(StorerT &storer) const { + using ::td::store; + store(label, storer); + store(page_blocks, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(label, parser); + parse(page_blocks, parser); + } + }; + + private: + vector items; + + static td_api::object_ptr get_page_block_list_item_object(const Item &item) { + // if label is empty, then Bullet U+2022 is used as a label + return td_api::make_object(item.label.empty() ? "\xE2\x80\xA2" : item.label, + get_page_block_objects(item.page_blocks)); + } + + public: + WebPageBlockList() = default; + explicit WebPageBlockList(vector &&items) : items(std::move(items)) { + } + + Type get_type() const override { + return Type::List; + } + + void append_file_ids(vector &file_ids) const override { + for (auto &item : items) { + for (auto &page_block : item.page_blocks) { + page_block->append_file_ids(file_ids); + } + } + } + + td_api::object_ptr get_page_block_object() const override { + return td_api::make_object( + transform(items, [](const Item &item) { return get_page_block_list_item_object(item); })); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(items, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + + if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { + parse(items, parser); + } else { + vector text_items; + bool is_ordered; + + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_ordered); + END_PARSE_FLAGS(); + + parse(text_items, parser); + + int pos = 0; + items.reserve(text_items.size()); + for (auto &text_item : text_items) { + Item item; + if (is_ordered) { + pos++; + item.label = (PSTRING() << pos << '.'); + } + item.page_blocks.push_back(make_unique(std::move(text_item))); + items.push_back(std::move(item)); + } + } + } +}; + +class WebPageBlockBlockQuote : public WebPageBlock { + RichText text; + RichText credit; + + public: + WebPageBlockBlockQuote() = default; + WebPageBlockBlockQuote(RichText &&text, RichText &&credit) : text(std::move(text)), credit(std::move(credit)) { + } + + Type get_type() const override { + return Type::BlockQuote; + } + + void append_file_ids(vector &file_ids) const override { + text.append_file_ids(file_ids); + credit.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(text.get_rich_text_object(), credit.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(text, storer); + store(credit, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(text, parser); + parse(credit, parser); + } +}; + +class WebPageBlockPullQuote : public WebPageBlock { + RichText text; + RichText credit; + + public: + WebPageBlockPullQuote() = default; + WebPageBlockPullQuote(RichText &&text, RichText &&credit) : text(std::move(text)), credit(std::move(credit)) { + } + + Type get_type() const override { + return Type::PullQuote; + } + + void append_file_ids(vector &file_ids) const override { + text.append_file_ids(file_ids); + credit.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(text.get_rich_text_object(), credit.get_rich_text_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(text, storer); + store(credit, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(text, parser); + parse(credit, parser); + } +}; + +class WebPageBlockAnimation : public WebPageBlock { + FileId animation_file_id; + WebPageBlockCaption caption; + bool need_autoplay = false; + + public: + WebPageBlockAnimation() = default; + WebPageBlockAnimation(FileId animation_file_id, WebPageBlockCaption &&caption, bool need_autoplay) + : animation_file_id(animation_file_id), caption(std::move(caption)), need_autoplay(need_autoplay) { + } + + Type get_type() const override { + return Type::Animation; + } + + void append_file_ids(vector &file_ids) const override { + caption.append_file_ids(file_ids); + if (animation_file_id.is_valid()) { + file_ids.push_back(animation_file_id); + auto thumbnail_file_id = + G()->td().get_actor_unsafe()->animations_manager_->get_animation_thumbnail_file_id(animation_file_id); + if (thumbnail_file_id.is_valid()) { + file_ids.push_back(thumbnail_file_id); + } + } + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + G()->td().get_actor_unsafe()->animations_manager_->get_animation_object(animation_file_id, + "get_page_block_object"), + caption.get_page_block_caption_object(), need_autoplay); + } + + template + void store(StorerT &storer) const { + using ::td::store; + + bool has_empty_animation = !animation_file_id.is_valid(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(need_autoplay); + STORE_FLAG(has_empty_animation); + END_STORE_FLAGS(); + + if (!has_empty_animation) { + storer.context()->td().get_actor_unsafe()->animations_manager_->store_animation(animation_file_id, storer); + } + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + + bool has_empty_animation; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(need_autoplay); + PARSE_FLAG(has_empty_animation); + END_PARSE_FLAGS(); + + if (parser.version() >= static_cast(Version::FixWebPageInstantViewDatabase)) { + if (!has_empty_animation) { + animation_file_id = parser.context()->td().get_actor_unsafe()->animations_manager_->parse_animation(parser); + } else { + animation_file_id = FileId(); + } + } else { + animation_file_id = FileId(); + parser.set_error("Wrong stored object"); + } + parse(caption, parser); + } +}; + +class WebPageBlockPhoto : public WebPageBlock { + Photo photo; + WebPageBlockCaption caption; + string url; + WebPageId web_page_id; + + public: + WebPageBlockPhoto() = default; + WebPageBlockPhoto(Photo photo, WebPageBlockCaption &&caption, string &&url, WebPageId web_page_id) + : photo(std::move(photo)), caption(std::move(caption)), url(std::move(url)), web_page_id(web_page_id) { + } + + Type get_type() const override { + return Type::Photo; + } + + void append_file_ids(vector &file_ids) const override { + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &photo), + caption.get_page_block_caption_object(), url); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(photo, storer); + store(caption, storer); + store(url, storer); + store(web_page_id, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(photo, parser); + parse(caption, parser); + if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { + parse(url, parser); + parse(web_page_id, parser); + } else { + url.clear(); + web_page_id = WebPageId(); + } + } +}; + +class WebPageBlockVideo : public WebPageBlock { + FileId video_file_id; + WebPageBlockCaption caption; + bool need_autoplay = false; + bool is_looped = false; + + public: + WebPageBlockVideo() = default; + WebPageBlockVideo(FileId video_file_id, WebPageBlockCaption &&caption, bool need_autoplay, bool is_looped) + : video_file_id(video_file_id), caption(std::move(caption)), need_autoplay(need_autoplay), is_looped(is_looped) { + } + + Type get_type() const override { + return Type::Video; + } + + void append_file_ids(vector &file_ids) const override { + caption.append_file_ids(file_ids); + if (video_file_id.is_valid()) { + file_ids.push_back(video_file_id); + auto thumbnail_file_id = + G()->td().get_actor_unsafe()->videos_manager_->get_video_thumbnail_file_id(video_file_id); + if (thumbnail_file_id.is_valid()) { + file_ids.push_back(thumbnail_file_id); + } + } + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + G()->td().get_actor_unsafe()->videos_manager_->get_video_object(video_file_id), + caption.get_page_block_caption_object(), need_autoplay, is_looped); + } + + template + void store(StorerT &storer) const { + using ::td::store; + + bool has_empty_video = !video_file_id.is_valid(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(need_autoplay); + STORE_FLAG(is_looped); + STORE_FLAG(has_empty_video); + END_STORE_FLAGS(); + + if (!has_empty_video) { + storer.context()->td().get_actor_unsafe()->videos_manager_->store_video(video_file_id, storer); + } + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + + bool has_empty_video; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(need_autoplay); + PARSE_FLAG(is_looped); + PARSE_FLAG(has_empty_video); + END_PARSE_FLAGS(); + + if (parser.version() >= static_cast(Version::FixWebPageInstantViewDatabase)) { + if (!has_empty_video) { + video_file_id = parser.context()->td().get_actor_unsafe()->videos_manager_->parse_video(parser); + } else { + video_file_id = FileId(); + } + } else { + video_file_id = FileId(); + parser.set_error("Wrong stored object"); + } + parse(caption, parser); + } +}; + +class WebPageBlockCover : public WebPageBlock { + unique_ptr cover; + + public: + WebPageBlockCover() = default; + explicit WebPageBlockCover(unique_ptr &&cover) : cover(std::move(cover)) { + } + + Type get_type() const override { + return Type::Cover; + } + + void append_file_ids(vector &file_ids) const override { + cover->append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(cover->get_page_block_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(cover, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(cover, parser); + } +}; + +class WebPageBlockEmbedded : public WebPageBlock { + string url; + string html; + Photo poster_photo; + Dimensions dimensions; + WebPageBlockCaption caption; + bool is_full_width; + bool allow_scrolling; + + public: + WebPageBlockEmbedded() = default; + WebPageBlockEmbedded(string url, string html, Photo poster_photo, Dimensions dimensions, + WebPageBlockCaption &&caption, bool is_full_width, bool allow_scrolling) + : url(std::move(url)) + , html(std::move(html)) + , poster_photo(std::move(poster_photo)) + , dimensions(dimensions) + , caption(std::move(caption)) + , is_full_width(is_full_width) + , allow_scrolling(allow_scrolling) { + } + + Type get_type() const override { + return Type::Embedded; + } + + void append_file_ids(vector &file_ids) const override { + append(file_ids, photo_get_file_ids(poster_photo)); + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + url, html, get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &poster_photo), dimensions.width, + dimensions.height, caption.get_page_block_caption_object(), is_full_width, allow_scrolling); + } + + template + void store(StorerT &storer) const { + using ::td::store; + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_full_width); + STORE_FLAG(allow_scrolling); + END_STORE_FLAGS(); + + store(url, storer); + store(html, storer); + store(poster_photo, storer); + store(dimensions, storer); + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_full_width); + PARSE_FLAG(allow_scrolling); + END_PARSE_FLAGS(); + + parse(url, parser); + parse(html, parser); + parse(poster_photo, parser); + parse(dimensions, parser); + parse(caption, parser); + } +}; + +class WebPageBlockEmbeddedPost : public WebPageBlock { + string url; + string author; + Photo author_photo; + int32 date; + vector> page_blocks; + WebPageBlockCaption caption; + + public: + WebPageBlockEmbeddedPost() = default; + WebPageBlockEmbeddedPost(string url, string author, Photo author_photo, int32 date, + vector> &&page_blocks, WebPageBlockCaption &&caption) + : url(std::move(url)) + , author(std::move(author)) + , author_photo(std::move(author_photo)) + , date(max(date, 0)) + , page_blocks(std::move(page_blocks)) + , caption(std::move(caption)) { + } + + Type get_type() const override { + return Type::EmbeddedPost; + } + + void append_file_ids(vector &file_ids) const override { + append(file_ids, photo_get_file_ids(author_photo)); + for (auto &page_block : page_blocks) { + page_block->append_file_ids(file_ids); + } + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + url, author, get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &author_photo), date, + get_page_block_objects(page_blocks), caption.get_page_block_caption_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(url, storer); + store(author, storer); + store(author_photo, storer); + store(date, storer); + store(page_blocks, storer); + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(url, parser); + parse(author, parser); + parse(author_photo, parser); + parse(date, parser); + parse(page_blocks, parser); + parse(caption, parser); + } +}; + +class WebPageBlockCollage : public WebPageBlock { + vector> page_blocks; + WebPageBlockCaption caption; + + public: + WebPageBlockCollage() = default; + WebPageBlockCollage(vector> &&page_blocks, WebPageBlockCaption &&caption) + : page_blocks(std::move(page_blocks)), caption(std::move(caption)) { + } + + Type get_type() const override { + return Type::Collage; + } + + void append_file_ids(vector &file_ids) const override { + for (auto &page_block : page_blocks) { + page_block->append_file_ids(file_ids); + } + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(get_page_block_objects(page_blocks), + caption.get_page_block_caption_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(page_blocks, storer); + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(page_blocks, parser); + parse(caption, parser); + } +}; + +class WebPageBlockSlideshow : public WebPageBlock { + vector> page_blocks; + WebPageBlockCaption caption; + + public: + WebPageBlockSlideshow() = default; + WebPageBlockSlideshow(vector> &&page_blocks, WebPageBlockCaption &&caption) + : page_blocks(std::move(page_blocks)), caption(std::move(caption)) { + } + + Type get_type() const override { + return Type::Slideshow; + } + + void append_file_ids(vector &file_ids) const override { + for (auto &page_block : page_blocks) { + page_block->append_file_ids(file_ids); + } + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(get_page_block_objects(page_blocks), + caption.get_page_block_caption_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(page_blocks, storer); + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(page_blocks, parser); + parse(caption, parser); + } +}; + +class WebPageBlockChatLink : public WebPageBlock { + string title; + DialogPhoto photo; + string username; + + public: + WebPageBlockChatLink() = default; + WebPageBlockChatLink(string title, DialogPhoto photo, string username) + : title(std::move(title)), photo(std::move(photo)), username(std::move(username)) { + } + + Type get_type() const override { + return Type::ChatLink; + } + + void append_file_ids(vector &file_ids) const override { + append(file_ids, dialog_photo_get_file_ids(photo)); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + title, get_chat_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &photo), username); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(title, storer); + store(photo, storer); + store(username, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(title, parser); + parse(photo, parser); + parse(username, parser); + } +}; + +class WebPageBlockAudio : public WebPageBlock { + FileId audio_file_id; + WebPageBlockCaption caption; + + public: + WebPageBlockAudio() = default; + WebPageBlockAudio(FileId audio_file_id, WebPageBlockCaption &&caption) + : audio_file_id(audio_file_id), caption(std::move(caption)) { + } + + Type get_type() const override { + return Type::Audio; + } + + void append_file_ids(vector &file_ids) const override { + if (audio_file_id.is_valid()) { + file_ids.push_back(audio_file_id); + auto thumbnail_file_id = + G()->td().get_actor_unsafe()->audios_manager_->get_audio_thumbnail_file_id(audio_file_id); + if (thumbnail_file_id.is_valid()) { + file_ids.push_back(thumbnail_file_id); + } + } + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object( + G()->td().get_actor_unsafe()->audios_manager_->get_audio_object(audio_file_id), + caption.get_page_block_caption_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + + bool has_empty_audio = !audio_file_id.is_valid(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(has_empty_audio); + END_STORE_FLAGS(); + + if (!has_empty_audio) { + storer.context()->td().get_actor_unsafe()->audios_manager_->store_audio(audio_file_id, storer); + } + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + + bool has_empty_audio; + if (parser.version() >= static_cast(Version::FixPageBlockAudioEmptyFile)) { + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_empty_audio); + END_PARSE_FLAGS(); + } else { + has_empty_audio = false; + } + + if (!has_empty_audio) { + audio_file_id = parser.context()->td().get_actor_unsafe()->audios_manager_->parse_audio(parser); + } else { + audio_file_id = FileId(); + } + parse(caption, parser); + } +}; + +class WebPageBlockTable : public WebPageBlock { + RichText title; + vector> cells; + bool is_bordered = false; + bool is_striped = false; + + public: + WebPageBlockTable() = default; + WebPageBlockTable(RichText &&title, vector> &&cells, bool is_bordered, bool is_striped) + : title(std::move(title)), cells(std::move(cells)), is_bordered(is_bordered), is_striped(is_striped) { + } + + Type get_type() const override { + return Type::Table; + } + + void append_file_ids(vector &file_ids) const override { + title.append_file_ids(file_ids); + for (auto &row : cells) { + for (auto &cell : row) { + cell.text.append_file_ids(file_ids); + } + } + } + + td_api::object_ptr get_page_block_object() const override { + auto cell_objects = transform(cells, [&](const vector &row) { + return transform(row, [&](const WebPageBlockTableCell &cell) { return cell.get_page_block_table_cell_object(); }); + }); + + return make_tl_object(title.get_rich_text_object(), std::move(cell_objects), is_bordered, + is_striped); + } + + template + void store(StorerT &storer) const { + using ::td::store; + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_bordered); + STORE_FLAG(is_striped); + END_STORE_FLAGS(); + store(title, storer); + store(cells, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_bordered); + PARSE_FLAG(is_striped); + END_PARSE_FLAGS(); + parse(title, parser); + parse(cells, parser); + } +}; + +class WebPageBlockDetails : public WebPageBlock { + RichText header; + vector> page_blocks; + bool is_open; + + public: + WebPageBlockDetails() = default; + WebPageBlockDetails(RichText &&header, vector> &&page_blocks, bool is_open) + : header(std::move(header)), page_blocks(std::move(page_blocks)), is_open(is_open) { + } + + Type get_type() const override { + return Type::Details; + } + + void append_file_ids(vector &file_ids) const override { + header.append_file_ids(file_ids); + for (auto &page_block : page_blocks) { + page_block->append_file_ids(file_ids); + } + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(header.get_rich_text_object(), get_page_block_objects(page_blocks), + is_open); + } + + template + void store(StorerT &storer) const { + using ::td::store; + BEGIN_STORE_FLAGS(); + STORE_FLAG(is_open); + END_STORE_FLAGS(); + store(header, storer); + store(page_blocks, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(is_open); + END_PARSE_FLAGS(); + parse(header, parser); + parse(page_blocks, parser); + } +}; + +class WebPageBlockRelatedArticles : public WebPageBlock { + RichText header; + vector related_articles; + + public: + WebPageBlockRelatedArticles() = default; + WebPageBlockRelatedArticles(RichText &&header, vector &&related_articles) + : header(std::move(header)), related_articles(std::move(related_articles)) { + } + + Type get_type() const override { + return Type::RelatedArticles; + } + + void append_file_ids(vector &file_ids) const override { + header.append_file_ids(file_ids); + for (auto &article : related_articles) { + if (article.photo.id != -2) { + append(file_ids, photo_get_file_ids(article.photo)); + } + } + } + + td_api::object_ptr get_page_block_object() const override { + auto related_article_objects = transform(related_articles, [](const RelatedArticle &article) { + return td_api::make_object( + article.url, article.title, article.description, + get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &article.photo), article.author, + article.published_date); + }); + return make_tl_object(header.get_rich_text_object(), + std::move(related_article_objects)); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(header, storer); + store(related_articles, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(header, parser); + parse(related_articles, parser); + } +}; + +class WebPageBlockMap : public WebPageBlock { + Location location; + int32 zoom = 0; + Dimensions dimensions; + WebPageBlockCaption caption; + + public: + WebPageBlockMap() = default; + WebPageBlockMap(Location location, int32 zoom, Dimensions dimensions, WebPageBlockCaption &&caption) + : location(std::move(location)), zoom(zoom), dimensions(dimensions), caption(std::move(caption)) { + } + + Type get_type() const override { + return Type::Map; + } + + void append_file_ids(vector &file_ids) const override { + caption.append_file_ids(file_ids); + } + + td_api::object_ptr get_page_block_object() const override { + return make_tl_object(location.get_location_object(), zoom, dimensions.width, + dimensions.height, caption.get_page_block_caption_object()); + } + + template + void store(StorerT &storer) const { + using ::td::store; + store(location, storer); + store(zoom, storer); + store(dimensions, storer); + store(caption, storer); + } + + template + void parse(ParserT &parser) { + using ::td::parse; + parse(location, parser); + parse(zoom, parser); + parse(dimensions, parser); + parse(caption, parser); + } +}; + +vector get_rich_texts(vector> &&rich_text_ptrs, + const std::unordered_map &documents); + +RichText get_rich_text(tl_object_ptr &&rich_text_ptr, + const std::unordered_map &documents) { + CHECK(rich_text_ptr != nullptr); + + RichText result; + switch (rich_text_ptr->get_id()) { + case telegram_api::textEmpty::ID: + break; + case telegram_api::textPlain::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.content = std::move(rich_text->text_); + break; + } + case telegram_api::textBold::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Bold; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textItalic::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Italic; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textUnderline::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Underline; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textStrike::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Strikethrough; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textFixed::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Fixed; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textUrl::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Url; + result.content = std::move(rich_text->url_); + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + result.web_page_id = WebPageId(rich_text->webpage_id_); + break; + } + case telegram_api::textEmail::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::EmailAddress; + result.content = std::move(rich_text->email_); + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textConcat::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Concatenation; + result.texts = get_rich_texts(std::move(rich_text->texts_), documents); + break; + } + case telegram_api::textSubscript::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Subscript; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textSuperscript::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Superscript; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textMarked::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Marked; + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textPhone::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::PhoneNumber; + result.content = std::move(rich_text->phone_); + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + case telegram_api::textImage::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + auto it = documents.find(rich_text->document_id_); + if (it != documents.end()) { + result.type = RichText::Type::Icon; + result.document_file_id = it->second; + Dimensions dimensions = get_dimensions(rich_text->w_, rich_text->h_); + result.content = PSTRING() << (dimensions.width * static_cast(65536) + dimensions.height); + } else { + LOG(ERROR) << "Can't find document " << rich_text->document_id_; + } + break; + } + case telegram_api::textAnchor::ID: { + auto rich_text = move_tl_object_as(rich_text_ptr); + result.type = RichText::Type::Anchor; + result.content = std::move(rich_text->name_); + result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); + break; + } + default: + UNREACHABLE(); + } + return result; +} + +vector get_rich_texts(vector> &&rich_text_ptrs, + const std::unordered_map &documents) { + return transform(std::move(rich_text_ptrs), [&documents](tl_object_ptr &&rich_text) { + return get_rich_text(std::move(rich_text), documents); + }); +} + +WebPageBlockCaption get_page_block_caption(tl_object_ptr &&page_caption, + const std::unordered_map &documents) { + CHECK(page_caption != nullptr); + WebPageBlockCaption result; + result.text = get_rich_text(std::move(page_caption->text_), documents); + result.credit = get_rich_text(std::move(page_caption->credit_), documents); + return result; +} + +unique_ptr get_web_page_block(Td *td, tl_object_ptr page_block_ptr, + const std::unordered_map &animations, + const std::unordered_map &audios, + const std::unordered_map &documents, + const std::unordered_map &photos, + const std::unordered_map &videos) { + CHECK(page_block_ptr != nullptr); + switch (page_block_ptr->get_id()) { + case telegram_api::pageBlockUnsupported::ID: + return nullptr; + case telegram_api::pageBlockTitle::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockSubtitle::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockAuthorDate::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->author_), documents), + page_block->published_date_); + } + case telegram_api::pageBlockHeader::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockSubheader::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockKicker::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockParagraph::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockPreformatted::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return td::make_unique(get_rich_text(std::move(page_block->text_), documents), + std::move(page_block->language_)); + } + case telegram_api::pageBlockFooter::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents)); + } + case telegram_api::pageBlockDivider::ID: + return make_unique(); + case telegram_api::pageBlockAnchor::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return td::make_unique(std::move(page_block->name_)); + } + case telegram_api::pageBlockList::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return td::make_unique(transform(std::move(page_block->items_), [&](auto &&list_item_ptr) { + WebPageBlockList::Item item; + CHECK(list_item_ptr != nullptr); + switch (list_item_ptr->get_id()) { + case telegram_api::pageListItemText::ID: { + auto list_item = telegram_api::move_object_as(list_item_ptr); + item.page_blocks.push_back( + make_unique(get_rich_text(std::move(list_item->text_), documents))); + break; + } + case telegram_api::pageListItemBlocks::ID: { + auto list_item = telegram_api::move_object_as(list_item_ptr); + item.page_blocks = + get_web_page_blocks(td, std::move(list_item->blocks_), animations, audios, documents, photos, videos); + break; + } + } + if (item.page_blocks.empty()) { + item.page_blocks.push_back(make_unique(RichText())); + } + return item; + })); + } + case telegram_api::pageBlockOrderedList::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + int32 current_label = 0; + return td::make_unique(transform(std::move(page_block->items_), [&](auto &&list_item_ptr) { + WebPageBlockList::Item item; + CHECK(list_item_ptr != nullptr); + switch (list_item_ptr->get_id()) { + case telegram_api::pageListOrderedItemText::ID: { + auto list_item = telegram_api::move_object_as(list_item_ptr); + item.label = std::move(list_item->num_); + item.page_blocks.push_back( + make_unique(get_rich_text(std::move(list_item->text_), documents))); + break; + } + case telegram_api::pageListOrderedItemBlocks::ID: { + auto list_item = telegram_api::move_object_as(list_item_ptr); + item.label = std::move(list_item->num_); + item.page_blocks = + get_web_page_blocks(td, std::move(list_item->blocks_), animations, audios, documents, photos, videos); + break; + } + } + if (item.page_blocks.empty()) { + item.page_blocks.push_back(make_unique(RichText())); + } + ++current_label; + if (item.label.empty()) { + item.label = PSTRING() << current_label << '.'; + } else { + item.label += '.'; + } + return item; + })); + } + case telegram_api::pageBlockBlockquote::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents), + get_rich_text(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockPullquote::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return make_unique(get_rich_text(std::move(page_block->text_), documents), + get_rich_text(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockPhoto::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto it = photos.find(page_block->photo_id_); + Photo photo; + if (it == photos.end()) { + photo.id = -2; + } else { + photo = it->second; + } + string url; + WebPageId web_page_id; + if ((page_block->flags_ & telegram_api::pageBlockPhoto::URL_MASK) != 0) { + url = std::move(page_block->url_); + web_page_id = WebPageId(page_block->webpage_id_); + } + return td::make_unique(std::move(photo), + get_page_block_caption(std::move(page_block->caption_), documents), + std::move(url), web_page_id); + } + case telegram_api::pageBlockVideo::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + bool need_autoplay = (page_block->flags_ & telegram_api::pageBlockVideo::AUTOPLAY_MASK) != 0; + bool is_looped = (page_block->flags_ & telegram_api::pageBlockVideo::LOOP_MASK) != 0; + auto animations_it = animations.find(page_block->video_id_); + if (animations_it != animations.end()) { + LOG_IF(ERROR, !is_looped) << "Receive non-looped animation"; + return make_unique( + animations_it->second, get_page_block_caption(std::move(page_block->caption_), documents), need_autoplay); + } + + auto it = videos.find(page_block->video_id_); + FileId video_file_id; + if (it != videos.end()) { + video_file_id = it->second; + } + return make_unique( + video_file_id, get_page_block_caption(std::move(page_block->caption_), documents), need_autoplay, is_looped); + } + case telegram_api::pageBlockCover::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto cover = get_web_page_block(td, std::move(page_block->cover_), animations, audios, documents, photos, videos); + if (cover == nullptr) { + return nullptr; + } + return make_unique(std::move(cover)); + } + case telegram_api::pageBlockEmbed::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + bool is_full_width = (page_block->flags_ & telegram_api::pageBlockEmbed::FULL_WIDTH_MASK) != 0; + bool allow_scrolling = (page_block->flags_ & telegram_api::pageBlockEmbed::ALLOW_SCROLLING_MASK) != 0; + bool has_dimensions = (page_block->flags_ & telegram_api::pageBlockEmbed::W_MASK) != 0; + auto it = (page_block->flags_ & telegram_api::pageBlockEmbed::POSTER_PHOTO_ID_MASK) != 0 + ? photos.find(page_block->poster_photo_id_) + : photos.end(); + Photo poster_photo; + if (it == photos.end()) { + poster_photo.id = -2; + } else { + poster_photo = it->second; + } + Dimensions dimensions; + if (has_dimensions) { + dimensions = get_dimensions(page_block->w_, page_block->h_); + } + return td::make_unique( + std::move(page_block->url_), std::move(page_block->html_), std::move(poster_photo), dimensions, + get_page_block_caption(std::move(page_block->caption_), documents), is_full_width, allow_scrolling); + } + case telegram_api::pageBlockEmbedPost::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto it = photos.find(page_block->author_photo_id_); + Photo author_photo; + if (it == photos.end()) { + author_photo.id = -2; + } else { + author_photo = it->second; + } + return td::make_unique( + std::move(page_block->url_), std::move(page_block->author_), std::move(author_photo), page_block->date_, + get_web_page_blocks(td, std::move(page_block->blocks_), animations, audios, documents, photos, videos), + get_page_block_caption(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockCollage::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return td::make_unique( + get_web_page_blocks(td, std::move(page_block->items_), animations, audios, documents, photos, videos), + get_page_block_caption(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockSlideshow::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + return td::make_unique( + get_web_page_blocks(td, std::move(page_block->items_), animations, audios, documents, photos, videos), + get_page_block_caption(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockChannel::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + CHECK(page_block->channel_ != nullptr); + if (page_block->channel_->get_id() == telegram_api::channel::ID) { + auto channel = static_cast(page_block->channel_.get()); + ChannelId channel_id(channel->id_); + if (!channel_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << channel_id; + return nullptr; + } + + if (td->contacts_manager_->have_channel_force(channel_id)) { + td->contacts_manager_->on_get_chat(std::move(page_block->channel_), "pageBlockChannel"); + LOG(INFO) << "Receive known min " << channel_id; + return td::make_unique(td->contacts_manager_->get_channel_title(channel_id), + *td->contacts_manager_->get_channel_dialog_photo(channel_id), + td->contacts_manager_->get_channel_username(channel_id)); + } else { + return td::make_unique( + std::move(channel->title_), get_dialog_photo(td->file_manager_.get(), std::move(channel->photo_)), + std::move(channel->username_)); + } + } else { + LOG(ERROR) << "Receive wrong channel " << to_string(page_block->channel_); + return nullptr; + } + } + case telegram_api::pageBlockAudio::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto it = audios.find(page_block->audio_id_); + FileId audio_file_id; + if (it != audios.end()) { + audio_file_id = it->second; + } + return make_unique(audio_file_id, + get_page_block_caption(std::move(page_block->caption_), documents)); + } + case telegram_api::pageBlockTable::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto is_bordered = (page_block->flags_ & telegram_api::pageBlockTable::BORDERED_MASK) != 0; + auto is_striped = (page_block->flags_ & telegram_api::pageBlockTable::STRIPED_MASK) != 0; + auto cells = transform(std::move(page_block->rows_), [&](tl_object_ptr &&row) { + return transform(std::move(row->cells_), [&](tl_object_ptr &&table_cell) { + WebPageBlockTableCell cell; + auto flags = table_cell->flags_; + cell.is_header = (flags & telegram_api::pageTableCell::HEADER_MASK) != 0; + cell.align_center = (flags & telegram_api::pageTableCell::ALIGN_CENTER_MASK) != 0; + if (!cell.align_center) { + cell.align_right = (flags & telegram_api::pageTableCell::ALIGN_RIGHT_MASK) != 0; + if (!cell.align_right) { + cell.align_left = true; + } + } + cell.valign_middle = (flags & telegram_api::pageTableCell::VALIGN_MIDDLE_MASK) != 0; + if (!cell.valign_middle) { + cell.valign_bottom = (flags & telegram_api::pageTableCell::VALIGN_BOTTOM_MASK) != 0; + if (!cell.valign_bottom) { + cell.valign_top = true; + } + } + if (table_cell->text_ != nullptr) { + cell.text = get_rich_text(std::move(table_cell->text_), documents); + } + if ((flags & telegram_api::pageTableCell::COLSPAN_MASK) != 0) { + cell.colspan = table_cell->colspan_; + } + if ((flags & telegram_api::pageTableCell::ROWSPAN_MASK) != 0) { + cell.rowspan = table_cell->rowspan_; + } + return cell; + }); + }); + return td::make_unique(get_rich_text(std::move(page_block->title_), documents), + std::move(cells), is_bordered, is_striped); + } + case telegram_api::pageBlockDetails::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto is_open = (page_block->flags_ & telegram_api::pageBlockDetails::OPEN_MASK) != 0; + return td::make_unique( + get_rich_text(std::move(page_block->title_), documents), + get_web_page_blocks(td, std::move(page_block->blocks_), animations, audios, documents, photos, videos), + is_open); + } + case telegram_api::pageBlockRelatedArticles::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + auto articles = transform( + std::move(page_block->articles_), [&](tl_object_ptr &&related_article) { + RelatedArticle article; + article.url = std::move(related_article->url_); + article.web_page_id = WebPageId(related_article->webpage_id_); + article.title = std::move(related_article->title_); + article.description = std::move(related_article->description_); + auto it = (related_article->flags_ & telegram_api::pageRelatedArticle::PHOTO_ID_MASK) != 0 + ? photos.find(related_article->photo_id_) + : photos.end(); + if (it == photos.end()) { + article.photo.id = -2; + } else { + article.photo = it->second; + } + article.author = std::move(related_article->author_); + if ((related_article->flags_ & telegram_api::pageRelatedArticle::PUBLISHED_DATE_MASK) != 0) { + article.published_date = related_article->published_date_; + } + return article; + }); + return td::make_unique(get_rich_text(std::move(page_block->title_), documents), + std::move(articles)); + } + case telegram_api::pageBlockMap::ID: { + auto page_block = move_tl_object_as(page_block_ptr); + Location location(std::move(page_block->geo_)); + auto zoom = page_block->zoom_; + Dimensions dimensions = get_dimensions(page_block->w_, page_block->h_); + if (location.empty()) { + LOG(ERROR) << "Receive invalid map location"; + break; + } + if (zoom <= 0 || zoom > 30) { + LOG(ERROR) << "Receive invalid map zoom " << zoom; + break; + } + if (dimensions.width == 0) { + LOG(ERROR) << "Receive invalid map dimensions " << page_block->w_ << " " << page_block->h_; + break; + } + return make_unique(std::move(location), zoom, dimensions, + get_page_block_caption(std::move(page_block->caption_), documents)); + } + default: + UNREACHABLE(); + } + return nullptr; +} + +} // namespace + +template +void WebPageBlock::call_impl(Type type, const WebPageBlock *ptr, F &&f) { + switch (type) { + case Type::Title: + return f(static_cast(ptr)); + case Type::Subtitle: + return f(static_cast(ptr)); + case Type::AuthorDate: + return f(static_cast(ptr)); + case Type::Header: + return f(static_cast(ptr)); + case Type::Subheader: + return f(static_cast(ptr)); + case Type::Kicker: + return f(static_cast(ptr)); + case Type::Paragraph: + return f(static_cast(ptr)); + case Type::Preformatted: + return f(static_cast(ptr)); + case Type::Footer: + return f(static_cast(ptr)); + case Type::Divider: + return f(static_cast(ptr)); + case Type::Anchor: + return f(static_cast(ptr)); + case Type::List: + return f(static_cast(ptr)); + case Type::BlockQuote: + return f(static_cast(ptr)); + case Type::PullQuote: + return f(static_cast(ptr)); + case Type::Animation: + return f(static_cast(ptr)); + case Type::Photo: + return f(static_cast(ptr)); + case Type::Video: + return f(static_cast(ptr)); + case Type::Cover: + return f(static_cast(ptr)); + case Type::Embedded: + return f(static_cast(ptr)); + case Type::EmbeddedPost: + return f(static_cast(ptr)); + case Type::Collage: + return f(static_cast(ptr)); + case Type::Slideshow: + return f(static_cast(ptr)); + case Type::ChatLink: + return f(static_cast(ptr)); + case Type::Audio: + return f(static_cast(ptr)); + case Type::Table: + return f(static_cast(ptr)); + case Type::Details: + return f(static_cast(ptr)); + case Type::RelatedArticles: + return f(static_cast(ptr)); + case Type::Map: + return f(static_cast(ptr)); + } + UNREACHABLE(); +} + +template +void WebPageBlock::store(StorerT &storer) const { + Type type = get_type(); + td::store(type, storer); + call_impl(type, this, [&](const auto *object) { td::store(*object, storer); }); +} + +template +unique_ptr WebPageBlock::parse(ParserT &parser) { + Type type; + td::parse(type, parser); + unique_ptr res; + call_impl(type, nullptr, [&](const auto *ptr) { + using ObjT = std::decay_t; + auto object = make_unique(); + td::parse(*object, parser); + res = std::move(object); + }); + return res; +} + +template +void store_web_page_block(const unique_ptr &block, StorerT &storer) { + block->store(storer); +} + +template +void parse_web_page_block(unique_ptr &block, ParserT &parser) { + block = WebPageBlock::parse(parser); +} + +void store(const unique_ptr &block, LogEventStorerCalcLength &storer) { + store_web_page_block(block, storer); +} + +void store(const unique_ptr &block, LogEventStorerUnsafe &storer) { + store_web_page_block(block, storer); +} + +void parse(unique_ptr &block, LogEventParser &parser) { + parse_web_page_block(block, parser); +} + +vector> get_web_page_blocks(Td *td, + vector> page_block_ptrs, + const std::unordered_map &animations, + const std::unordered_map &audios, + const std::unordered_map &documents, + const std::unordered_map &photos, + const std::unordered_map &videos) { + vector> result; + result.reserve(page_block_ptrs.size()); + for (auto &page_block_ptr : page_block_ptrs) { + auto page_block = get_web_page_block(td, std::move(page_block_ptr), animations, audios, documents, photos, videos); + if (page_block != nullptr) { + result.push_back(std::move(page_block)); + } + } + return result; +} + +vector> get_page_block_objects( + const vector> &page_blocks) { + return transform(page_blocks, + [](const unique_ptr &page_block) { return page_block->get_page_block_object(); }); +} + +} // namespace td diff --git a/td/telegram/WebPageBlock.h b/td/telegram/WebPageBlock.h new file mode 100644 index 000000000..bde0267ee --- /dev/null +++ b/td/telegram/WebPageBlock.h @@ -0,0 +1,104 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/telegram/files/FileId.h" +#include "td/telegram/logevent/LogEvent.h" +#include "td/telegram/Photo.h" + +#include "td/utils/common.h" + +#include + +namespace td { + +class Td; + +class WebPageBlock { + protected: + enum class Type : int32 { + Title, + Subtitle, + AuthorDate, + Header, + Subheader, + Paragraph, + Preformatted, + Footer, + Divider, + Anchor, + List, + BlockQuote, + PullQuote, + Animation, + Photo, + Video, + Cover, + Embedded, + EmbeddedPost, + Collage, + Slideshow, + ChatLink, + Audio, + Kicker, + Table, + Details, + RelatedArticles, + Map + }; + + virtual Type get_type() const = 0; + + template + static void call_impl(Type type, const WebPageBlock *ptr, F &&f); + + template + void store(StorerT &storer) const; + + template + static unique_ptr parse(ParserT &parser); + + template + friend void store_web_page_block(const unique_ptr &block, StorerT &storer); + + template + friend void parse_web_page_block(unique_ptr &block, ParserT &parser); + + public: + WebPageBlock() = default; + WebPageBlock(const WebPageBlock &) = delete; + WebPageBlock &operator=(const WebPageBlock &) = delete; + WebPageBlock(WebPageBlock &&) = delete; + WebPageBlock &operator=(WebPageBlock &&) = delete; + virtual ~WebPageBlock() = default; + + virtual void append_file_ids(vector &file_ids) const = 0; + + virtual td_api::object_ptr get_page_block_object() const = 0; +}; + +void store(const unique_ptr &block, LogEventStorerCalcLength &storer); + +void store(const unique_ptr &block, LogEventStorerUnsafe &storer); + +void parse(unique_ptr &block, LogEventParser &parser); + +vector> get_web_page_blocks(Td *td, + vector> page_block_ptrs, + const std::unordered_map &animations, + const std::unordered_map &audios, + const std::unordered_map &documents, + const std::unordered_map &photos, + const std::unordered_map &videos); + +vector> get_page_block_objects( + const vector> &page_blocks); + +} // namespace td diff --git a/td/telegram/WebPagesManager.cpp b/td/telegram/WebPagesManager.cpp index ac8ce86e8..62cbd7385 100644 --- a/td/telegram/WebPagesManager.cpp +++ b/td/telegram/WebPagesManager.cpp @@ -7,40 +7,29 @@ #include "td/telegram/WebPagesManager.h" #include "td/telegram/secret_api.h" -#include "td/telegram/telegram_api.hpp" #include "td/telegram/AnimationsManager.h" -#include "td/telegram/AnimationsManager.hpp" #include "td/telegram/AudiosManager.h" -#include "td/telegram/AudiosManager.hpp" -#include "td/telegram/ChannelId.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Document.h" #include "td/telegram/Document.hpp" #include "td/telegram/DocumentsManager.h" -#include "td/telegram/DocumentsManager.hpp" #include "td/telegram/FileReferenceManager.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileSourceId.h" #include "td/telegram/Global.h" -#include "td/telegram/Location.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/Photo.h" -#include "td/telegram/Photo.hpp" #include "td/telegram/StickersManager.h" -#include "td/telegram/StickersManager.hpp" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" -#include "td/telegram/Version.h" #include "td/telegram/VideoNotesManager.h" -#include "td/telegram/VideoNotesManager.hpp" #include "td/telegram/VideosManager.h" -#include "td/telegram/VideosManager.hpp" #include "td/telegram/VoiceNotesManager.h" -#include "td/telegram/VoiceNotesManager.hpp" +#include "td/telegram/WebPageBlock.h" #include "td/actor/PromiseFuture.h" @@ -137,7 +126,7 @@ class GetWebPageQuery : public Td::ResultHandler { class WebPagesManager::WebPageInstantView { public: - vector> page_blocks; + vector> page_blocks; string url; int32 hash = 0; bool is_v2 = false; @@ -366,1669 +355,6 @@ class WebPagesManager::WebPage { } }; -class WebPagesManager::RichText { - public: - enum class Type : int32 { - Plain, - Bold, - Italic, - Underline, - Strikethrough, - Fixed, - Url, - EmailAddress, - Concatenation, - Subscript, - Superscript, - Marked, - PhoneNumber, - Icon, - Anchor - }; - Type type = Type::Plain; - string content; - vector texts; - FileId document_file_id; - WebPageId web_page_id; - - bool empty() const { - return type == Type::Plain && content.empty(); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(type, storer); - store(content, storer); - store(texts, storer); - if (type == Type::Icon) { - storer.context()->td().get_actor_unsafe()->documents_manager_->store_document(document_file_id, storer); - } - if (type == Type::Url) { - store(web_page_id, storer); - } - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(type, parser); - parse(content, parser); - parse(texts, parser); - if (type == Type::Icon) { - document_file_id = parser.context()->td().get_actor_unsafe()->documents_manager_->parse_document(parser); - if (!document_file_id.is_valid()) { - LOG(ERROR) << "Failed to load document from database"; - *this = RichText(); - } - } else { - document_file_id = FileId(); - } - if (type == Type::Url && parser.version() >= static_cast(Version::SupportInstantView2_0)) { - parse(web_page_id, parser); - } else { - web_page_id = WebPageId(); - } - } -}; - -class WebPagesManager::PageBlockCaption { - public: - RichText text; - RichText credit; - - template - void store(StorerT &storer) const { - using ::td::store; - store(text, storer); - store(credit, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(text, parser); - if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { - parse(credit, parser); - } else { - credit = RichText(); - } - } -}; - -class WebPagesManager::PageBlockTableCell { - public: - RichText text; - bool is_header = false; - bool align_left = false; - bool align_center = false; - bool align_right = false; - bool valign_top = false; - bool valign_middle = false; - bool valign_bottom = false; - int32 colspan = 1; - int32 rowspan = 1; - - template - void store(StorerT &storer) const { - using ::td::store; - bool has_text = !text.empty(); - bool has_colspan = colspan != 1; - bool has_rowspan = rowspan != 1; - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_header); - STORE_FLAG(align_left); - STORE_FLAG(align_center); - STORE_FLAG(align_right); - STORE_FLAG(valign_top); - STORE_FLAG(valign_middle); - STORE_FLAG(valign_bottom); - STORE_FLAG(has_text); - STORE_FLAG(has_colspan); - STORE_FLAG(has_rowspan); - END_STORE_FLAGS(); - if (has_text) { - store(text, storer); - } - if (has_colspan) { - store(colspan, storer); - } - if (has_rowspan) { - store(rowspan, storer); - } - } - - template - void parse(ParserT &parser) { - using ::td::parse; - bool has_text; - bool has_colspan; - bool has_rowspan; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_header); - PARSE_FLAG(align_left); - PARSE_FLAG(align_center); - PARSE_FLAG(align_right); - PARSE_FLAG(valign_top); - PARSE_FLAG(valign_middle); - PARSE_FLAG(valign_bottom); - PARSE_FLAG(has_text); - PARSE_FLAG(has_colspan); - PARSE_FLAG(has_rowspan); - END_PARSE_FLAGS(); - if (has_text) { - parse(text, parser); - } - if (has_colspan) { - parse(colspan, parser); - } - if (has_rowspan) { - parse(rowspan, parser); - } - } -}; - -class WebPagesManager::RelatedArticle { - public: - string url; - WebPageId web_page_id; - string title; - string description; - Photo photo; - string author; - int32 published_date = 0; - - template - void store(StorerT &storer) const { - using ::td::store; - bool has_title = !title.empty(); - bool has_description = !description.empty(); - bool has_photo = photo.id != -2; - bool has_author = !author.empty(); - bool has_date = published_date != 0; - BEGIN_STORE_FLAGS(); - STORE_FLAG(has_title); - STORE_FLAG(has_description); - STORE_FLAG(has_photo); - STORE_FLAG(has_author); - STORE_FLAG(has_date); - END_STORE_FLAGS(); - store(url, storer); - store(web_page_id, storer); - if (has_title) { - store(title, storer); - } - if (has_description) { - store(description, storer); - } - if (has_photo) { - store(photo, storer); - } - if (has_author) { - store(author, storer); - } - if (has_date) { - store(published_date, storer); - } - } - - template - void parse(ParserT &parser) { - using ::td::parse; - bool has_title; - bool has_description; - bool has_photo; - bool has_author; - bool has_date; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(has_title); - PARSE_FLAG(has_description); - PARSE_FLAG(has_photo); - PARSE_FLAG(has_author); - PARSE_FLAG(has_date); - END_PARSE_FLAGS(); - parse(url, parser); - parse(web_page_id, parser); - if (has_title) { - parse(title, parser); - } - if (has_description) { - parse(description, parser); - } - if (has_photo) { - parse(photo, parser); - } else { - photo.id = -2; - } - if (has_author) { - parse(author, parser); - } - if (has_date) { - parse(published_date, parser); - } - } -}; - -class WebPagesManager::PageBlock { - public: - enum class Type : int32 { - Title, - Subtitle, - AuthorDate, - Header, - Subheader, - Paragraph, - Preformatted, - Footer, - Divider, - Anchor, - List, - BlockQuote, - PullQuote, - Animation, - Photo, - Video, - Cover, - Embedded, - EmbeddedPost, - Collage, - Slideshow, - ChatLink, - Audio, - Kicker, - Table, - Details, - RelatedArticles, - Map - }; - - virtual Type get_type() const = 0; - - virtual void append_file_ids(vector &file_ids) const = 0; - - virtual tl_object_ptr get_page_block_object() const = 0; - - PageBlock() = default; - PageBlock(const PageBlock &) = delete; - PageBlock &operator=(const PageBlock &) = delete; - PageBlock(PageBlock &&) = delete; - PageBlock &operator=(PageBlock &&) = delete; - virtual ~PageBlock() = default; - - template - void store(StorerT &storer) const { - using ::td::store; - Type type = get_type(); - store(type, storer); - call_impl(type, this, [&](const auto *object) { store(*object, storer); }); - } - - template - static unique_ptr parse(ParserT &parser) { - using ::td::parse; - Type type; - parse(type, parser); - unique_ptr res; - call_impl(type, nullptr, [&](const auto *ptr) { - using ObjT = std::decay_t; - auto object = make_unique(); - parse(*object, parser); - res = std::move(object); - }); - return res; - } - - private: - template - static void call_impl(Type type, const PageBlock *ptr, F &&f); -}; - -template -void store(const unique_ptr &block, StorerT &storer) { - block->store(storer); -} - -template -void parse(unique_ptr &block, ParserT &parser) { - block = WebPagesManager::PageBlock::parse(parser); -} - -class WebPagesManager::PageBlockTitle : public PageBlock { - RichText title; - - public: - PageBlockTitle() = default; - - explicit PageBlockTitle(RichText &&title) : title(std::move(title)) { - } - - Type get_type() const override { - return Type::Title; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(title, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(title)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(title, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(title, parser); - } -}; - -class WebPagesManager::PageBlockSubtitle : public PageBlock { - RichText subtitle; - - public: - PageBlockSubtitle() = default; - explicit PageBlockSubtitle(RichText &&subtitle) : subtitle(std::move(subtitle)) { - } - - Type get_type() const override { - return Type::Subtitle; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(subtitle, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(subtitle)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(subtitle, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(subtitle, parser); - } -}; - -class WebPagesManager::PageBlockAuthorDate : public PageBlock { - RichText author; - int32 date = 0; - - public: - PageBlockAuthorDate() = default; - PageBlockAuthorDate(RichText &&author, int32 date) : author(std::move(author)), date(max(date, 0)) { - } - - Type get_type() const override { - return Type::AuthorDate; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(author, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(author), date); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(author, storer); - store(date, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(author, parser); - parse(date, parser); - } -}; - -class WebPagesManager::PageBlockHeader : public PageBlock { - RichText header; - - public: - PageBlockHeader() = default; - explicit PageBlockHeader(RichText &&header) : header(std::move(header)) { - } - - Type get_type() const override { - return Type::Header; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(header, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(header)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(header, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(header, parser); - } -}; - -class WebPagesManager::PageBlockSubheader : public PageBlock { - RichText subheader; - - public: - PageBlockSubheader() = default; - explicit PageBlockSubheader(RichText &&subheader) : subheader(std::move(subheader)) { - } - - Type get_type() const override { - return Type::Subheader; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(subheader, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(subheader)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(subheader, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(subheader, parser); - } -}; - -class WebPagesManager::PageBlockKicker : public PageBlock { - RichText kicker; - - public: - PageBlockKicker() = default; - explicit PageBlockKicker(RichText &&kicker) : kicker(std::move(kicker)) { - } - - Type get_type() const override { - return Type::Kicker; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(kicker, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(kicker)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(kicker, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(kicker, parser); - } -}; - -class WebPagesManager::PageBlockParagraph : public PageBlock { - RichText text; - - public: - PageBlockParagraph() = default; - explicit PageBlockParagraph(RichText &&text) : text(std::move(text)) { - } - - Type get_type() const override { - return Type::Paragraph; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(text, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(text)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(text, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(text, parser); - } -}; - -class WebPagesManager::PageBlockPreformatted : public PageBlock { - RichText text; - string language; - - public: - PageBlockPreformatted() = default; - PageBlockPreformatted(RichText &&text, string language) : text(std::move(text)), language(std::move(language)) { - } - - Type get_type() const override { - return Type::Preformatted; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(text, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(text), language); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(text, storer); - store(language, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(text, parser); - parse(language, parser); - } -}; - -class WebPagesManager::PageBlockFooter : public PageBlock { - RichText footer; - - public: - PageBlockFooter() = default; - explicit PageBlockFooter(RichText &&footer) : footer(std::move(footer)) { - } - - Type get_type() const override { - return Type::Footer; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(footer, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(footer)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(footer, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(footer, parser); - } -}; - -class WebPagesManager::PageBlockDivider : public PageBlock { - public: - Type get_type() const override { - return Type::Divider; - } - - void append_file_ids(vector &file_ids) const override { - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(); - } - - template - void store(StorerT &storer) const { - } - - template - void parse(ParserT &parser) { - } -}; - -class WebPagesManager::PageBlockAnchor : public PageBlock { - string name; - - public: - PageBlockAnchor() = default; - explicit PageBlockAnchor(string name) : name(std::move(name)) { - } - - Type get_type() const override { - return Type::Anchor; - } - - void append_file_ids(vector &file_ids) const override { - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(name); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(name, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(name, parser); - } -}; - -class WebPagesManager::PageBlockList : public PageBlock { - public: - struct Item { - string label; - vector> page_blocks; - - template - void store(StorerT &storer) const { - using ::td::store; - store(label, storer); - store(page_blocks, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(label, parser); - parse(page_blocks, parser); - } - }; - - private: - vector items; - - static td_api::object_ptr get_page_block_list_item_object(const Item &item) { - // if label is empty, then Bullet U+2022 is used as a label - return td_api::make_object(item.label.empty() ? "\xE2\x80\xA2" : item.label, - get_page_block_objects(item.page_blocks)); - } - - public: - PageBlockList() = default; - explicit PageBlockList(vector &&items) : items(std::move(items)) { - } - - Type get_type() const override { - return Type::List; - } - - void append_file_ids(vector &file_ids) const override { - for (auto &item : items) { - for (auto &page_block : item.page_blocks) { - page_block->append_file_ids(file_ids); - } - } - } - - tl_object_ptr get_page_block_object() const override { - return td_api::make_object( - transform(items, [](const Item &item) { return get_page_block_list_item_object(item); })); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(items, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - - if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { - parse(items, parser); - } else { - vector text_items; - bool is_ordered; - - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_ordered); - END_PARSE_FLAGS(); - - parse(text_items, parser); - - int pos = 0; - items.reserve(text_items.size()); - for (auto &text_item : text_items) { - Item item; - if (is_ordered) { - pos++; - item.label = (PSTRING() << pos << '.'); - } - item.page_blocks.push_back(make_unique(std::move(text_item))); - items.push_back(std::move(item)); - } - } - } -}; - -class WebPagesManager::PageBlockBlockQuote : public PageBlock { - RichText text; - RichText credit; - - public: - PageBlockBlockQuote() = default; - PageBlockBlockQuote(RichText &&text, RichText &&credit) : text(std::move(text)), credit(std::move(credit)) { - } - - Type get_type() const override { - return Type::BlockQuote; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(text, file_ids); - append_rich_text_file_ids(credit, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(text), get_rich_text_object(credit)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(text, storer); - store(credit, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(text, parser); - parse(credit, parser); - } -}; - -class WebPagesManager::PageBlockPullQuote : public PageBlock { - RichText text; - RichText credit; - - public: - PageBlockPullQuote() = default; - PageBlockPullQuote(RichText &&text, RichText &&credit) : text(std::move(text)), credit(std::move(credit)) { - } - - Type get_type() const override { - return Type::PullQuote; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(text, file_ids); - append_rich_text_file_ids(credit, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(text), get_rich_text_object(credit)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(text, storer); - store(credit, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(text, parser); - parse(credit, parser); - } -}; - -class WebPagesManager::PageBlockAnimation : public PageBlock { - FileId animation_file_id; - PageBlockCaption caption; - bool need_autoplay = false; - - public: - PageBlockAnimation() = default; - PageBlockAnimation(FileId animation_file_id, PageBlockCaption &&caption, bool need_autoplay) - : animation_file_id(animation_file_id), caption(std::move(caption)), need_autoplay(need_autoplay) { - } - - Type get_type() const override { - return Type::Animation; - } - - void append_file_ids(vector &file_ids) const override { - append_page_block_caption_file_ids(caption, file_ids); - if (animation_file_id.is_valid()) { - file_ids.push_back(animation_file_id); - auto thumbnail_file_id = - G()->td().get_actor_unsafe()->animations_manager_->get_animation_thumbnail_file_id(animation_file_id); - if (thumbnail_file_id.is_valid()) { - file_ids.push_back(thumbnail_file_id); - } - } - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - G()->td().get_actor_unsafe()->animations_manager_->get_animation_object(animation_file_id, - "get_page_block_object"), - get_page_block_caption_object(caption), need_autoplay); - } - - template - void store(StorerT &storer) const { - using ::td::store; - - bool has_empty_animation = !animation_file_id.is_valid(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(need_autoplay); - STORE_FLAG(has_empty_animation); - END_STORE_FLAGS(); - - if (!has_empty_animation) { - storer.context()->td().get_actor_unsafe()->animations_manager_->store_animation(animation_file_id, storer); - } - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - - bool has_empty_animation; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(need_autoplay); - PARSE_FLAG(has_empty_animation); - END_PARSE_FLAGS(); - - if (parser.version() >= static_cast(Version::FixWebPageInstantViewDatabase)) { - if (!has_empty_animation) { - animation_file_id = parser.context()->td().get_actor_unsafe()->animations_manager_->parse_animation(parser); - } else { - animation_file_id = FileId(); - } - } else { - animation_file_id = FileId(); - parser.set_error("Wrong stored object"); - } - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockPhoto : public PageBlock { - Photo photo; - PageBlockCaption caption; - string url; - WebPageId web_page_id; - - public: - PageBlockPhoto() = default; - PageBlockPhoto(Photo photo, PageBlockCaption &&caption, string &&url, WebPageId web_page_id) - : photo(std::move(photo)), caption(std::move(caption)), url(std::move(url)), web_page_id(web_page_id) { - } - - Type get_type() const override { - return Type::Photo; - } - - void append_file_ids(vector &file_ids) const override { - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &photo), - get_page_block_caption_object(caption), url); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(photo, storer); - store(caption, storer); - store(url, storer); - store(web_page_id, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(photo, parser); - parse(caption, parser); - if (parser.version() >= static_cast(Version::SupportInstantView2_0)) { - parse(url, parser); - parse(web_page_id, parser); - } else { - url.clear(); - web_page_id = WebPageId(); - } - } -}; - -class WebPagesManager::PageBlockVideo : public PageBlock { - FileId video_file_id; - PageBlockCaption caption; - bool need_autoplay = false; - bool is_looped = false; - - public: - PageBlockVideo() = default; - PageBlockVideo(FileId video_file_id, PageBlockCaption &&caption, bool need_autoplay, bool is_looped) - : video_file_id(video_file_id), caption(std::move(caption)), need_autoplay(need_autoplay), is_looped(is_looped) { - } - - Type get_type() const override { - return Type::Video; - } - - void append_file_ids(vector &file_ids) const override { - append_page_block_caption_file_ids(caption, file_ids); - if (video_file_id.is_valid()) { - file_ids.push_back(video_file_id); - auto thumbnail_file_id = - G()->td().get_actor_unsafe()->videos_manager_->get_video_thumbnail_file_id(video_file_id); - if (thumbnail_file_id.is_valid()) { - file_ids.push_back(thumbnail_file_id); - } - } - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - G()->td().get_actor_unsafe()->videos_manager_->get_video_object(video_file_id), - get_page_block_caption_object(caption), need_autoplay, is_looped); - } - - template - void store(StorerT &storer) const { - using ::td::store; - - bool has_empty_video = !video_file_id.is_valid(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(need_autoplay); - STORE_FLAG(is_looped); - STORE_FLAG(has_empty_video); - END_STORE_FLAGS(); - - if (!has_empty_video) { - storer.context()->td().get_actor_unsafe()->videos_manager_->store_video(video_file_id, storer); - } - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - - bool has_empty_video; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(need_autoplay); - PARSE_FLAG(is_looped); - PARSE_FLAG(has_empty_video); - END_PARSE_FLAGS(); - - if (parser.version() >= static_cast(Version::FixWebPageInstantViewDatabase)) { - if (!has_empty_video) { - video_file_id = parser.context()->td().get_actor_unsafe()->videos_manager_->parse_video(parser); - } else { - video_file_id = FileId(); - } - } else { - video_file_id = FileId(); - parser.set_error("Wrong stored object"); - } - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockCover : public PageBlock { - unique_ptr cover; - - public: - PageBlockCover() = default; - explicit PageBlockCover(unique_ptr &&cover) : cover(std::move(cover)) { - } - - Type get_type() const override { - return Type::Cover; - } - - void append_file_ids(vector &file_ids) const override { - cover->append_file_ids(file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(cover->get_page_block_object()); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(cover, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(cover, parser); - } -}; - -class WebPagesManager::PageBlockEmbedded : public PageBlock { - string url; - string html; - Photo poster_photo; - Dimensions dimensions; - PageBlockCaption caption; - bool is_full_width; - bool allow_scrolling; - - public: - PageBlockEmbedded() = default; - PageBlockEmbedded(string url, string html, Photo poster_photo, Dimensions dimensions, PageBlockCaption &&caption, - bool is_full_width, bool allow_scrolling) - : url(std::move(url)) - , html(std::move(html)) - , poster_photo(std::move(poster_photo)) - , dimensions(dimensions) - , caption(std::move(caption)) - , is_full_width(is_full_width) - , allow_scrolling(allow_scrolling) { - } - - Type get_type() const override { - return Type::Embedded; - } - - void append_file_ids(vector &file_ids) const override { - append(file_ids, photo_get_file_ids(poster_photo)); - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - url, html, get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &poster_photo), dimensions.width, - dimensions.height, get_page_block_caption_object(caption), is_full_width, allow_scrolling); - } - - template - void store(StorerT &storer) const { - using ::td::store; - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_full_width); - STORE_FLAG(allow_scrolling); - END_STORE_FLAGS(); - - store(url, storer); - store(html, storer); - store(poster_photo, storer); - store(dimensions, storer); - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_full_width); - PARSE_FLAG(allow_scrolling); - END_PARSE_FLAGS(); - - parse(url, parser); - parse(html, parser); - parse(poster_photo, parser); - parse(dimensions, parser); - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockEmbeddedPost : public PageBlock { - string url; - string author; - Photo author_photo; - int32 date; - vector> page_blocks; - PageBlockCaption caption; - - public: - PageBlockEmbeddedPost() = default; - PageBlockEmbeddedPost(string url, string author, Photo author_photo, int32 date, - vector> &&page_blocks, PageBlockCaption &&caption) - : url(std::move(url)) - , author(std::move(author)) - , author_photo(std::move(author_photo)) - , date(max(date, 0)) - , page_blocks(std::move(page_blocks)) - , caption(std::move(caption)) { - } - - Type get_type() const override { - return Type::EmbeddedPost; - } - - void append_file_ids(vector &file_ids) const override { - append(file_ids, photo_get_file_ids(author_photo)); - for (auto &page_block : page_blocks) { - page_block->append_file_ids(file_ids); - } - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - url, author, get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &author_photo), date, - get_page_block_objects(page_blocks), get_page_block_caption_object(caption)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(url, storer); - store(author, storer); - store(author_photo, storer); - store(date, storer); - store(page_blocks, storer); - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(url, parser); - parse(author, parser); - parse(author_photo, parser); - parse(date, parser); - parse(page_blocks, parser); - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockCollage : public PageBlock { - vector> page_blocks; - PageBlockCaption caption; - - public: - PageBlockCollage() = default; - PageBlockCollage(vector> &&page_blocks, PageBlockCaption &&caption) - : page_blocks(std::move(page_blocks)), caption(std::move(caption)) { - } - - Type get_type() const override { - return Type::Collage; - } - - void append_file_ids(vector &file_ids) const override { - for (auto &page_block : page_blocks) { - page_block->append_file_ids(file_ids); - } - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_page_block_objects(page_blocks), - get_page_block_caption_object(caption)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(page_blocks, storer); - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(page_blocks, parser); - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockSlideshow : public PageBlock { - vector> page_blocks; - PageBlockCaption caption; - - public: - PageBlockSlideshow() = default; - PageBlockSlideshow(vector> &&page_blocks, PageBlockCaption &&caption) - : page_blocks(std::move(page_blocks)), caption(std::move(caption)) { - } - - Type get_type() const override { - return Type::Slideshow; - } - - void append_file_ids(vector &file_ids) const override { - for (auto &page_block : page_blocks) { - page_block->append_file_ids(file_ids); - } - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_page_block_objects(page_blocks), - get_page_block_caption_object(caption)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(page_blocks, storer); - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(page_blocks, parser); - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockChatLink : public PageBlock { - string title; - DialogPhoto photo; - string username; - - public: - PageBlockChatLink() = default; - PageBlockChatLink(string title, DialogPhoto photo, string username) - : title(std::move(title)), photo(std::move(photo)), username(std::move(username)) { - } - - Type get_type() const override { - return Type::ChatLink; - } - - void append_file_ids(vector &file_ids) const override { - append(file_ids, dialog_photo_get_file_ids(photo)); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - title, get_chat_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &photo), username); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(title, storer); - store(photo, storer); - store(username, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(title, parser); - parse(photo, parser); - parse(username, parser); - } -}; - -class WebPagesManager::PageBlockAudio : public PageBlock { - FileId audio_file_id; - PageBlockCaption caption; - - public: - PageBlockAudio() = default; - PageBlockAudio(FileId audio_file_id, PageBlockCaption &&caption) - : audio_file_id(audio_file_id), caption(std::move(caption)) { - } - - Type get_type() const override { - return Type::Audio; - } - - void append_file_ids(vector &file_ids) const override { - if (audio_file_id.is_valid()) { - file_ids.push_back(audio_file_id); - auto thumbnail_file_id = - G()->td().get_actor_unsafe()->audios_manager_->get_audio_thumbnail_file_id(audio_file_id); - if (thumbnail_file_id.is_valid()) { - file_ids.push_back(thumbnail_file_id); - } - } - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object( - G()->td().get_actor_unsafe()->audios_manager_->get_audio_object(audio_file_id), - get_page_block_caption_object(caption)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - - bool has_empty_audio = !audio_file_id.is_valid(); - BEGIN_STORE_FLAGS(); - STORE_FLAG(has_empty_audio); - END_STORE_FLAGS(); - - if (!has_empty_audio) { - storer.context()->td().get_actor_unsafe()->audios_manager_->store_audio(audio_file_id, storer); - } - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - - bool has_empty_audio; - if (parser.version() >= static_cast(Version::FixPageBlockAudioEmptyFile)) { - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(has_empty_audio); - END_PARSE_FLAGS(); - } else { - has_empty_audio = false; - } - - if (!has_empty_audio) { - audio_file_id = parser.context()->td().get_actor_unsafe()->audios_manager_->parse_audio(parser); - } else { - audio_file_id = FileId(); - } - parse(caption, parser); - } -}; - -class WebPagesManager::PageBlockTable : public PageBlock { - RichText title; - vector> cells; - bool is_bordered = false; - bool is_striped = false; - - public: - PageBlockTable() = default; - PageBlockTable(RichText &&title, vector> &&cells, bool is_bordered, bool is_striped) - : title(std::move(title)), cells(std::move(cells)), is_bordered(is_bordered), is_striped(is_striped) { - } - - Type get_type() const override { - return Type::Table; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(title, file_ids); - for (auto &row : cells) { - for (auto &cell : row) { - append_rich_text_file_ids(cell.text, file_ids); - } - } - } - - tl_object_ptr get_page_block_object() const override { - auto cell_objects = transform(cells, [&](const vector &row) { - return transform(row, [&](const PageBlockTableCell &cell) { return get_page_block_table_cell_object(cell); }); - }); - - return make_tl_object(get_rich_text_object(title), std::move(cell_objects), is_bordered, - is_striped); - } - - template - void store(StorerT &storer) const { - using ::td::store; - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_bordered); - STORE_FLAG(is_striped); - END_STORE_FLAGS(); - store(title, storer); - store(cells, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_bordered); - PARSE_FLAG(is_striped); - END_PARSE_FLAGS(); - parse(title, parser); - parse(cells, parser); - } -}; - -class WebPagesManager::PageBlockDetails : public PageBlock { - RichText header; - vector> page_blocks; - bool is_open; - - public: - PageBlockDetails() = default; - PageBlockDetails(RichText &&header, vector> &&page_blocks, bool is_open) - : header(std::move(header)), page_blocks(std::move(page_blocks)), is_open(is_open) { - } - - Type get_type() const override { - return Type::Details; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(header, file_ids); - for (auto &page_block : page_blocks) { - page_block->append_file_ids(file_ids); - } - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(get_rich_text_object(header), get_page_block_objects(page_blocks), - is_open); - } - - template - void store(StorerT &storer) const { - using ::td::store; - BEGIN_STORE_FLAGS(); - STORE_FLAG(is_open); - END_STORE_FLAGS(); - store(header, storer); - store(page_blocks, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - BEGIN_PARSE_FLAGS(); - PARSE_FLAG(is_open); - END_PARSE_FLAGS(); - parse(header, parser); - parse(page_blocks, parser); - } -}; - -class WebPagesManager::PageBlockRelatedArticles : public PageBlock { - RichText header; - vector related_articles; - - public: - PageBlockRelatedArticles() = default; - PageBlockRelatedArticles(RichText &&header, vector &&related_articles) - : header(std::move(header)), related_articles(std::move(related_articles)) { - } - - Type get_type() const override { - return Type::RelatedArticles; - } - - void append_file_ids(vector &file_ids) const override { - append_rich_text_file_ids(header, file_ids); - for (auto &article : related_articles) { - if (article.photo.id != -2) { - append(file_ids, photo_get_file_ids(article.photo)); - } - } - } - - tl_object_ptr get_page_block_object() const override { - auto related_article_objects = transform(related_articles, [](const RelatedArticle &article) { - return td_api::make_object( - article.url, article.title, article.description, - get_photo_object(G()->td().get_actor_unsafe()->file_manager_.get(), &article.photo), article.author, - article.published_date); - }); - return make_tl_object(get_rich_text_object(header), - std::move(related_article_objects)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(header, storer); - store(related_articles, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(header, parser); - parse(related_articles, parser); - } -}; - -class WebPagesManager::PageBlockMap : public PageBlock { - Location location; - int32 zoom = 0; - Dimensions dimensions; - PageBlockCaption caption; - - public: - PageBlockMap() = default; - PageBlockMap(Location location, int32 zoom, Dimensions dimensions, PageBlockCaption &&caption) - : location(std::move(location)), zoom(zoom), dimensions(dimensions), caption(std::move(caption)) { - } - - Type get_type() const override { - return Type::Map; - } - - void append_file_ids(vector &file_ids) const override { - append_page_block_caption_file_ids(caption, file_ids); - } - - tl_object_ptr get_page_block_object() const override { - return make_tl_object(location.get_location_object(), zoom, dimensions.width, - dimensions.height, get_page_block_caption_object(caption)); - } - - template - void store(StorerT &storer) const { - using ::td::store; - store(location, storer); - store(zoom, storer); - store(dimensions, storer); - store(caption, storer); - } - - template - void parse(ParserT &parser) { - using ::td::parse; - parse(location, parser); - parse(zoom, parser); - parse(dimensions, parser); - parse(caption, parser); - } -}; - -template -void WebPagesManager::PageBlock::call_impl(Type type, const PageBlock *ptr, F &&f) { - switch (type) { - case Type::Title: - return f(static_cast(ptr)); - case Type::Subtitle: - return f(static_cast(ptr)); - case Type::AuthorDate: - return f(static_cast(ptr)); - case Type::Header: - return f(static_cast(ptr)); - case Type::Subheader: - return f(static_cast(ptr)); - case Type::Kicker: - return f(static_cast(ptr)); - case Type::Paragraph: - return f(static_cast(ptr)); - case Type::Preformatted: - return f(static_cast(ptr)); - case Type::Footer: - return f(static_cast(ptr)); - case Type::Divider: - return f(static_cast(ptr)); - case Type::Anchor: - return f(static_cast(ptr)); - case Type::List: - return f(static_cast(ptr)); - case Type::BlockQuote: - return f(static_cast(ptr)); - case Type::PullQuote: - return f(static_cast(ptr)); - case Type::Animation: - return f(static_cast(ptr)); - case Type::Photo: - return f(static_cast(ptr)); - case Type::Video: - return f(static_cast(ptr)); - case Type::Cover: - return f(static_cast(ptr)); - case Type::Embedded: - return f(static_cast(ptr)); - case Type::EmbeddedPost: - return f(static_cast(ptr)); - case Type::Collage: - return f(static_cast(ptr)); - case Type::Slideshow: - return f(static_cast(ptr)); - case Type::ChatLink: - return f(static_cast(ptr)); - case Type::Audio: - return f(static_cast(ptr)); - case Type::Table: - return f(static_cast(ptr)); - case Type::Details: - return f(static_cast(ptr)); - case Type::RelatedArticles: - return f(static_cast(ptr)); - case Type::Map: - return f(static_cast(ptr)); - } - UNREACHABLE(); -} - WebPagesManager::WebPagesManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { pending_web_pages_timeout_.set_callback(on_pending_web_page_timeout_callback); pending_web_pages_timeout_.set_callback_data(static_cast(this)); @@ -2860,593 +1186,6 @@ void WebPagesManager::on_pending_web_page_timeout(WebPageId web_page_id) { } } -WebPagesManager::RichText WebPagesManager::get_rich_text(tl_object_ptr &&rich_text_ptr, - const std::unordered_map &documents) { - CHECK(rich_text_ptr != nullptr); - - RichText result; - switch (rich_text_ptr->get_id()) { - case telegram_api::textEmpty::ID: - break; - case telegram_api::textPlain::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.content = std::move(rich_text->text_); - break; - } - case telegram_api::textBold::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Bold; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textItalic::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Italic; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textUnderline::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Underline; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textStrike::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Strikethrough; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textFixed::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Fixed; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textUrl::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Url; - result.content = std::move(rich_text->url_); - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - result.web_page_id = WebPageId(rich_text->webpage_id_); - break; - } - case telegram_api::textEmail::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::EmailAddress; - result.content = std::move(rich_text->email_); - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textConcat::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Concatenation; - result.texts = get_rich_texts(std::move(rich_text->texts_), documents); - break; - } - case telegram_api::textSubscript::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Subscript; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textSuperscript::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Superscript; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textMarked::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Marked; - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textPhone::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::PhoneNumber; - result.content = std::move(rich_text->phone_); - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - case telegram_api::textImage::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - auto it = documents.find(rich_text->document_id_); - if (it != documents.end()) { - result.type = RichText::Type::Icon; - result.document_file_id = it->second; - Dimensions dimensions = get_dimensions(rich_text->w_, rich_text->h_); - result.content = PSTRING() << (dimensions.width * static_cast(65536) + dimensions.height); - } else { - LOG(ERROR) << "Can't find document " << rich_text->document_id_; - } - break; - } - case telegram_api::textAnchor::ID: { - auto rich_text = move_tl_object_as(rich_text_ptr); - result.type = RichText::Type::Anchor; - result.content = std::move(rich_text->name_); - result.texts.push_back(get_rich_text(std::move(rich_text->text_), documents)); - break; - } - default: - UNREACHABLE(); - } - return result; -} - -vector WebPagesManager::get_rich_texts( - vector> &&rich_text_ptrs, - const std::unordered_map &documents) { - return transform(std::move(rich_text_ptrs), [&documents](tl_object_ptr &&rich_text) { - return get_rich_text(std::move(rich_text), documents); - }); -} - -tl_object_ptr WebPagesManager::get_rich_text_object(const RichText &rich_text) { - switch (rich_text.type) { - case RichText::Type::Plain: - return make_tl_object(rich_text.content); - case RichText::Type::Bold: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Italic: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Underline: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Strikethrough: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Fixed: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Url: - return make_tl_object(get_rich_text_object(rich_text.texts[0]), rich_text.content); - case RichText::Type::EmailAddress: - return make_tl_object(get_rich_text_object(rich_text.texts[0]), rich_text.content); - case RichText::Type::Concatenation: - return make_tl_object(get_rich_text_objects(rich_text.texts)); - case RichText::Type::Subscript: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Superscript: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::Marked: - return make_tl_object(get_rich_text_object(rich_text.texts[0])); - case RichText::Type::PhoneNumber: - return make_tl_object(get_rich_text_object(rich_text.texts[0]), rich_text.content); - case RichText::Type::Icon: { - auto dimensions = to_integer(rich_text.content); - auto width = static_cast(dimensions / 65536); - auto height = static_cast(dimensions % 65536); - return make_tl_object( - G()->td().get_actor_unsafe()->documents_manager_->get_document_object(rich_text.document_file_id), width, - height); - } - case RichText::Type::Anchor: - return make_tl_object(get_rich_text_object(rich_text.texts[0]), rich_text.content); - } - UNREACHABLE(); - return nullptr; -} - -vector> WebPagesManager::get_rich_text_objects(const vector &rich_texts) { - return transform(rich_texts, [](const RichText &rich_text) { return get_rich_text_object(rich_text); }); -} - -WebPagesManager::PageBlockCaption WebPagesManager::get_page_block_caption( - tl_object_ptr &&page_caption, const std::unordered_map &documents) { - CHECK(page_caption != nullptr); - PageBlockCaption result; - result.text = get_rich_text(std::move(page_caption->text_), documents); - result.credit = get_rich_text(std::move(page_caption->credit_), documents); - return result; -} - -td_api::object_ptr WebPagesManager::get_page_block_caption_object( - const PageBlockCaption &caption) { - return td_api::make_object(get_rich_text_object(caption.text), - get_rich_text_object(caption.credit)); -} - -td_api::object_ptr WebPagesManager::get_page_block_table_cell_object( - const PageBlockTableCell &cell) { - auto align = [&]() -> td_api::object_ptr { - if (cell.align_left) { - return td_api::make_object(); - } - if (cell.align_center) { - return td_api::make_object(); - } - if (cell.align_right) { - return td_api::make_object(); - } - UNREACHABLE(); - return nullptr; - }(); - auto valign = [&]() -> td_api::object_ptr { - if (cell.valign_top) { - return td_api::make_object(); - } - if (cell.valign_middle) { - return td_api::make_object(); - } - if (cell.valign_bottom) { - return td_api::make_object(); - } - UNREACHABLE(); - return nullptr; - }(); - return td_api::make_object(get_rich_text_object(cell.text), cell.is_header, cell.colspan, - cell.rowspan, std::move(align), std::move(valign)); -} - -vector> WebPagesManager::get_page_block_objects( - const vector> &page_blocks) { - return transform(page_blocks, - [](const unique_ptr &page_block) { return page_block->get_page_block_object(); }); -} - -unique_ptr WebPagesManager::get_page_block( - tl_object_ptr page_block_ptr, const std::unordered_map &animations, - const std::unordered_map &audios, const std::unordered_map &documents, - const std::unordered_map &photos, const std::unordered_map &videos) const { - CHECK(page_block_ptr != nullptr); - switch (page_block_ptr->get_id()) { - case telegram_api::pageBlockUnsupported::ID: - return nullptr; - case telegram_api::pageBlockTitle::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockSubtitle::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockAuthorDate::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->author_), documents), - page_block->published_date_); - } - case telegram_api::pageBlockHeader::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockSubheader::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockKicker::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockParagraph::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockPreformatted::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return td::make_unique(get_rich_text(std::move(page_block->text_), documents), - std::move(page_block->language_)); - } - case telegram_api::pageBlockFooter::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents)); - } - case telegram_api::pageBlockDivider::ID: - return make_unique(); - case telegram_api::pageBlockAnchor::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return td::make_unique(std::move(page_block->name_)); - } - case telegram_api::pageBlockList::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return td::make_unique(transform(std::move(page_block->items_), [&](auto &&list_item_ptr) { - PageBlockList::Item item; - CHECK(list_item_ptr != nullptr); - switch (list_item_ptr->get_id()) { - case telegram_api::pageListItemText::ID: { - auto list_item = telegram_api::move_object_as(list_item_ptr); - item.page_blocks.push_back( - make_unique(get_rich_text(std::move(list_item->text_), documents))); - break; - } - case telegram_api::pageListItemBlocks::ID: { - auto list_item = telegram_api::move_object_as(list_item_ptr); - item.page_blocks = - this->get_page_blocks(std::move(list_item->blocks_), animations, audios, documents, photos, videos); - break; - } - } - if (item.page_blocks.empty()) { - item.page_blocks.push_back(make_unique(RichText())); - } - return item; - })); - } - case telegram_api::pageBlockOrderedList::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - int32 current_label = 0; - return td::make_unique(transform(std::move(page_block->items_), [&](auto &&list_item_ptr) { - PageBlockList::Item item; - CHECK(list_item_ptr != nullptr); - switch (list_item_ptr->get_id()) { - case telegram_api::pageListOrderedItemText::ID: { - auto list_item = telegram_api::move_object_as(list_item_ptr); - item.label = std::move(list_item->num_); - item.page_blocks.push_back( - make_unique(get_rich_text(std::move(list_item->text_), documents))); - break; - } - case telegram_api::pageListOrderedItemBlocks::ID: { - auto list_item = telegram_api::move_object_as(list_item_ptr); - item.label = std::move(list_item->num_); - item.page_blocks = - this->get_page_blocks(std::move(list_item->blocks_), animations, audios, documents, photos, videos); - break; - } - } - if (item.page_blocks.empty()) { - item.page_blocks.push_back(make_unique(RichText())); - } - ++current_label; - if (item.label.empty()) { - item.label = PSTRING() << current_label << '.'; - } else { - item.label += '.'; - } - return item; - })); - } - case telegram_api::pageBlockBlockquote::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents), - get_rich_text(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockPullquote::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return make_unique(get_rich_text(std::move(page_block->text_), documents), - get_rich_text(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockPhoto::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto it = photos.find(page_block->photo_id_); - Photo photo; - if (it == photos.end()) { - photo.id = -2; - } else { - photo = it->second; - } - string url; - WebPageId web_page_id; - if ((page_block->flags_ & telegram_api::pageBlockPhoto::URL_MASK) != 0) { - url = std::move(page_block->url_); - web_page_id = WebPageId(page_block->webpage_id_); - } - return td::make_unique(std::move(photo), - get_page_block_caption(std::move(page_block->caption_), documents), - std::move(url), web_page_id); - } - case telegram_api::pageBlockVideo::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - bool need_autoplay = (page_block->flags_ & telegram_api::pageBlockVideo::AUTOPLAY_MASK) != 0; - bool is_looped = (page_block->flags_ & telegram_api::pageBlockVideo::LOOP_MASK) != 0; - auto animations_it = animations.find(page_block->video_id_); - if (animations_it != animations.end()) { - LOG_IF(ERROR, !is_looped) << "Receive non-looped animation"; - return make_unique( - animations_it->second, get_page_block_caption(std::move(page_block->caption_), documents), need_autoplay); - } - - auto it = videos.find(page_block->video_id_); - FileId video_file_id; - if (it != videos.end()) { - video_file_id = it->second; - } - return make_unique( - video_file_id, get_page_block_caption(std::move(page_block->caption_), documents), need_autoplay, is_looped); - } - case telegram_api::pageBlockCover::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto cover = get_page_block(std::move(page_block->cover_), animations, audios, documents, photos, videos); - if (cover == nullptr) { - return nullptr; - } - return make_unique(std::move(cover)); - } - case telegram_api::pageBlockEmbed::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - bool is_full_width = (page_block->flags_ & telegram_api::pageBlockEmbed::FULL_WIDTH_MASK) != 0; - bool allow_scrolling = (page_block->flags_ & telegram_api::pageBlockEmbed::ALLOW_SCROLLING_MASK) != 0; - bool has_dimensions = (page_block->flags_ & telegram_api::pageBlockEmbed::W_MASK) != 0; - auto it = (page_block->flags_ & telegram_api::pageBlockEmbed::POSTER_PHOTO_ID_MASK) != 0 - ? photos.find(page_block->poster_photo_id_) - : photos.end(); - Photo poster_photo; - if (it == photos.end()) { - poster_photo.id = -2; - } else { - poster_photo = it->second; - } - Dimensions dimensions; - if (has_dimensions) { - dimensions = get_dimensions(page_block->w_, page_block->h_); - } - return td::make_unique( - std::move(page_block->url_), std::move(page_block->html_), std::move(poster_photo), dimensions, - get_page_block_caption(std::move(page_block->caption_), documents), is_full_width, allow_scrolling); - } - case telegram_api::pageBlockEmbedPost::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto it = photos.find(page_block->author_photo_id_); - Photo author_photo; - if (it == photos.end()) { - author_photo.id = -2; - } else { - author_photo = it->second; - } - return td::make_unique( - std::move(page_block->url_), std::move(page_block->author_), std::move(author_photo), page_block->date_, - get_page_blocks(std::move(page_block->blocks_), animations, audios, documents, photos, videos), - get_page_block_caption(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockCollage::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return td::make_unique( - get_page_blocks(std::move(page_block->items_), animations, audios, documents, photos, videos), - get_page_block_caption(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockSlideshow::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - return td::make_unique( - get_page_blocks(std::move(page_block->items_), animations, audios, documents, photos, videos), - get_page_block_caption(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockChannel::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - CHECK(page_block->channel_ != nullptr); - if (page_block->channel_->get_id() == telegram_api::channel::ID) { - auto channel = static_cast(page_block->channel_.get()); - ChannelId channel_id(channel->id_); - if (!channel_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << channel_id; - return nullptr; - } - - if (td_->contacts_manager_->have_channel_force(channel_id)) { - td_->contacts_manager_->on_get_chat(std::move(page_block->channel_), "pageBlockChannel"); - LOG(INFO) << "Receive known min " << channel_id; - return td::make_unique(td_->contacts_manager_->get_channel_title(channel_id), - *td_->contacts_manager_->get_channel_dialog_photo(channel_id), - td_->contacts_manager_->get_channel_username(channel_id)); - } else { - return td::make_unique( - std::move(channel->title_), get_dialog_photo(td_->file_manager_.get(), std::move(channel->photo_)), - std::move(channel->username_)); - } - } else { - LOG(ERROR) << "Receive wrong channel " << to_string(page_block->channel_); - return nullptr; - } - } - case telegram_api::pageBlockAudio::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto it = audios.find(page_block->audio_id_); - FileId audio_file_id; - if (it != audios.end()) { - audio_file_id = it->second; - } - return make_unique(audio_file_id, - get_page_block_caption(std::move(page_block->caption_), documents)); - } - case telegram_api::pageBlockTable::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto is_bordered = (page_block->flags_ & telegram_api::pageBlockTable::BORDERED_MASK) != 0; - auto is_striped = (page_block->flags_ & telegram_api::pageBlockTable::STRIPED_MASK) != 0; - auto cells = transform(std::move(page_block->rows_), [&](tl_object_ptr &&row) { - return transform(std::move(row->cells_), [&](tl_object_ptr &&table_cell) { - PageBlockTableCell cell; - auto flags = table_cell->flags_; - cell.is_header = (flags & telegram_api::pageTableCell::HEADER_MASK) != 0; - cell.align_center = (flags & telegram_api::pageTableCell::ALIGN_CENTER_MASK) != 0; - if (!cell.align_center) { - cell.align_right = (flags & telegram_api::pageTableCell::ALIGN_RIGHT_MASK) != 0; - if (!cell.align_right) { - cell.align_left = true; - } - } - cell.valign_middle = (flags & telegram_api::pageTableCell::VALIGN_MIDDLE_MASK) != 0; - if (!cell.valign_middle) { - cell.valign_bottom = (flags & telegram_api::pageTableCell::VALIGN_BOTTOM_MASK) != 0; - if (!cell.valign_bottom) { - cell.valign_top = true; - } - } - if (table_cell->text_ != nullptr) { - cell.text = get_rich_text(std::move(table_cell->text_), documents); - } - if ((flags & telegram_api::pageTableCell::COLSPAN_MASK) != 0) { - cell.colspan = table_cell->colspan_; - } - if ((flags & telegram_api::pageTableCell::ROWSPAN_MASK) != 0) { - cell.rowspan = table_cell->rowspan_; - } - return cell; - }); - }); - return td::make_unique(get_rich_text(std::move(page_block->title_), documents), std::move(cells), - is_bordered, is_striped); - } - case telegram_api::pageBlockDetails::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto is_open = (page_block->flags_ & telegram_api::pageBlockDetails::OPEN_MASK) != 0; - return td::make_unique( - get_rich_text(std::move(page_block->title_), documents), - get_page_blocks(std::move(page_block->blocks_), animations, audios, documents, photos, videos), is_open); - } - case telegram_api::pageBlockRelatedArticles::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - auto articles = transform( - std::move(page_block->articles_), [&](tl_object_ptr &&related_article) { - RelatedArticle article; - article.url = std::move(related_article->url_); - article.web_page_id = WebPageId(related_article->webpage_id_); - article.title = std::move(related_article->title_); - article.description = std::move(related_article->description_); - auto it = (related_article->flags_ & telegram_api::pageRelatedArticle::PHOTO_ID_MASK) != 0 - ? photos.find(related_article->photo_id_) - : photos.end(); - if (it == photos.end()) { - article.photo.id = -2; - } else { - article.photo = it->second; - } - article.author = std::move(related_article->author_); - if ((related_article->flags_ & telegram_api::pageRelatedArticle::PUBLISHED_DATE_MASK) != 0) { - article.published_date = related_article->published_date_; - } - return article; - }); - return td::make_unique(get_rich_text(std::move(page_block->title_), documents), - std::move(articles)); - } - case telegram_api::pageBlockMap::ID: { - auto page_block = move_tl_object_as(page_block_ptr); - Location location(std::move(page_block->geo_)); - auto zoom = page_block->zoom_; - Dimensions dimensions = get_dimensions(page_block->w_, page_block->h_); - if (location.empty()) { - LOG(ERROR) << "Receive invalid map location"; - break; - } - if (zoom <= 0 || zoom > 30) { - LOG(ERROR) << "Receive invalid map zoom " << zoom; - break; - } - if (dimensions.width == 0) { - LOG(ERROR) << "Receive invalid map dimensions " << page_block->w_ << " " << page_block->h_; - break; - } - return make_unique(std::move(location), zoom, dimensions, - get_page_block_caption(std::move(page_block->caption_), documents)); - } - default: - UNREACHABLE(); - } - return nullptr; -} - -vector> WebPagesManager::get_page_blocks( - vector> page_block_ptrs, const std::unordered_map &animations, - const std::unordered_map &audios, const std::unordered_map &documents, - const std::unordered_map &photos, const std::unordered_map &videos) const { - vector> result; - result.reserve(page_block_ptrs.size()); - for (auto &page_block_ptr : page_block_ptrs) { - auto page_block = get_page_block(std::move(page_block_ptr), animations, audios, documents, photos, videos); - if (page_block != nullptr) { - result.push_back(std::move(page_block)); - } - } - return result; -} - void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_ptr &&page, int32 hash, DialogId owner_dialog_id) { CHECK(page != nullptr); @@ -3522,7 +1261,7 @@ void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_ << " animations, " << audios.size() << " audios, " << documents.size() << " documents, " << photos.size() << " photos and " << videos.size() << " videos"; web_page->instant_view.page_blocks = - get_page_blocks(std::move(page->blocks_), animations, audios, documents, photos, videos); + get_web_page_blocks(td_, std::move(page->blocks_), animations, audios, documents, photos, videos); web_page->instant_view.is_v2 = (page->flags_ & telegram_api::page::V2_MASK) != 0; web_page->instant_view.is_rtl = (page->flags_ & telegram_api::page::RTL_MASK) != 0; web_page->instant_view.hash = hash; @@ -3738,27 +1477,6 @@ string WebPagesManager::get_web_page_search_text(WebPageId web_page_id) const { return PSTRING() << web_page->title + " " + web_page->description; } -void WebPagesManager::append_rich_text_file_ids(const RichText &rich_text, vector &file_ids) { - if (rich_text.type == RichText::Type::Icon) { - CHECK(rich_text.document_file_id.is_valid()); - file_ids.push_back(rich_text.document_file_id); - auto thumbnail_file_id = - G()->td().get_actor_unsafe()->documents_manager_->get_document_thumbnail_file_id(rich_text.document_file_id); - if (thumbnail_file_id.is_valid()) { - file_ids.push_back(thumbnail_file_id); - } - } else { - for (auto &text : rich_text.texts) { - append_rich_text_file_ids(text, file_ids); - } - } -} - -void WebPagesManager::append_page_block_caption_file_ids(const PageBlockCaption &caption, vector &file_ids) { - append_rich_text_file_ids(caption.text, file_ids); - append_rich_text_file_ids(caption.credit, file_ids); -} - vector WebPagesManager::get_web_page_file_ids(const WebPage *web_page) const { if (web_page == nullptr) { return vector(); diff --git a/td/telegram/WebPagesManager.h b/td/telegram/WebPagesManager.h index d724667b9..420f8cb16 100644 --- a/td/telegram/WebPagesManager.h +++ b/td/telegram/WebPagesManager.h @@ -33,6 +33,8 @@ struct BinlogEvent; class Td; +class WebPageBlock; + class WebPagesManager : public Actor { public: WebPagesManager(Td *td, ActorShared<> parent); @@ -98,52 +100,10 @@ class WebPagesManager : public Actor { class WebPage; - class RichText; - - class PageBlockCaption; - class PageBlockTableCell; - class RelatedArticle; - - class PageBlock; - class PageBlockTitle; - class PageBlockSubtitle; - class PageBlockAuthorDate; - class PageBlockHeader; - class PageBlockSubheader; - class PageBlockKicker; - class PageBlockParagraph; - class PageBlockPreformatted; - class PageBlockFooter; - class PageBlockDivider; - class PageBlockAnchor; - class PageBlockList; - class PageBlockBlockQuote; - class PageBlockPullQuote; - class PageBlockAnimation; - class PageBlockPhoto; - class PageBlockVideo; - class PageBlockCover; - class PageBlockEmbedded; - class PageBlockEmbeddedPost; - class PageBlockCollage; - class PageBlockSlideshow; - class PageBlockChatLink; - class PageBlockAudio; - class PageBlockTable; - class PageBlockDetails; - class PageBlockRelatedArticles; - class PageBlockMap; - class WebPageInstantView; class WebPageLogEvent; - template - friend void store(const unique_ptr &block, StorerT &storer); - - template - friend void parse(unique_ptr &block, ParserT &parser); - void update_web_page(unique_ptr web_page, WebPageId web_page_id, bool from_binlog, bool from_database); void update_web_page_instant_view(WebPageId web_page_id, WebPageInstantView &new_instant_view, @@ -169,41 +129,6 @@ class WebPagesManager : public Actor { void on_get_web_page_preview_success(int64 request_id, const string &url, WebPageId web_page_id, Promise &&promise); - static RichText get_rich_text(tl_object_ptr &&rich_text_ptr, - const std::unordered_map &documents); - - static vector get_rich_texts(vector> &&rich_text_ptrs, - const std::unordered_map &documents); - - static tl_object_ptr get_rich_text_object(const RichText &rich_text); - - static vector> get_rich_text_objects(const vector &rich_texts); - - static PageBlockCaption get_page_block_caption(tl_object_ptr &&page_caption, - const std::unordered_map &documents); - - static td_api::object_ptr get_page_block_caption_object(const PageBlockCaption &caption); - - static td_api::object_ptr get_page_block_table_cell_object( - const PageBlockTableCell &cell); - - static vector> get_page_block_objects( - const vector> &page_blocks); - - unique_ptr get_page_block(tl_object_ptr page_block_ptr, - const std::unordered_map &animations, - const std::unordered_map &audios, - const std::unordered_map &documents, - const std::unordered_map &photos, - const std::unordered_map &videos) const; - - vector> get_page_blocks(vector> page_block_ptrs, - const std::unordered_map &animations, - const std::unordered_map &audios, - const std::unordered_map &documents, - const std::unordered_map &photos, - const std::unordered_map &videos) const; - void on_get_web_page_instant_view(WebPage *web_page, tl_object_ptr &&page, int32 hash, DialogId owner_dialog_id); @@ -242,10 +167,6 @@ class WebPagesManager : public Actor { FileSourceId get_web_page_file_source_id(WebPage *web_page); - static void append_rich_text_file_ids(const RichText &rich_text, vector &file_ids); - - static void append_page_block_caption_file_ids(const PageBlockCaption &caption, vector &file_ids); - vector get_web_page_file_ids(const WebPage *web_page) const; Td *td_;