diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 97cdc5619e..6585ae023e 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -4241,11 +4241,11 @@ void Session::webpageApplyFields( const auto cachedPage = data.vcached_page(); const auto ivPhoto = photo ? processPhoto(*photo).get() : nullptr; const auto ivDocument = document ? processDocument(*document).get() : nullptr; - auto iv = (cachedPage && !IgnoreIv(type)) - ? std::make_unique( - data, - *cachedPage, - Iv::ParseRichPage(_session, *cachedPage)) + const auto richPage = (cachedPage && !IgnoreIv(type)) + ? Iv::ParseRichPage(_session, data) + : nullptr; + auto iv = richPage + ? std::make_unique(data, richPage) : nullptr; const auto resolvedPhoto = story ? story->photo() diff --git a/Telegram/SourceFiles/iv/iv_controller.h b/Telegram/SourceFiles/iv/iv_controller.h index 2d853efb1c..48e01f55e6 100644 --- a/Telegram/SourceFiles/iv/iv_controller.h +++ b/Telegram/SourceFiles/iv/iv_controller.h @@ -46,6 +46,7 @@ public: Type type = Type::Close; QString url; QString context; + uint64 webpageId = 0; }; [[nodiscard]] static bool IsGoodTonSiteUrl(const QString &uri); diff --git a/Telegram/SourceFiles/iv/iv_data.cpp b/Telegram/SourceFiles/iv/iv_data.cpp index 852d6bd23e..5aed5ad4a1 100644 --- a/Telegram/SourceFiles/iv/iv_data.cpp +++ b/Telegram/SourceFiles/iv/iv_data.cpp @@ -16,7 +16,6 @@ namespace Iv { Data::Data( const MTPDwebPage &webpage, - const MTPPage &page, std::shared_ptr richPage) : _pageId(webpage.vid().v) , _hash(webpage.vhash().v) @@ -24,19 +23,8 @@ Data::Data( , _name(webpage.vsite_name() ? qs(*webpage.vsite_name()) : SiteNameFromUrl(_url)) -, _partial(page.match([](const MTPDpage &data) { - return data.is_part(); - }, [](const auto &) { - return false; - })) -, _richPage(std::move(richPage)) -, _pageFallback(page) -, _webpagePhotoFallback(webpage.vphoto() - ? std::optional(*webpage.vphoto()) - : std::optional()) -, _webpageDocumentFallback(webpage.vdocument() - ? std::optional(*webpage.vdocument()) - : std::optional()) { +, _partial(richPage ? richPage->part : false) +, _richPage(std::move(richPage)) { } QString Data::id() const { @@ -65,17 +53,6 @@ const std::shared_ptr &Data::richPage() const { return _richPage; } -std::optional Data::sourceFallback() const { - if (!_pageFallback) { - return std::nullopt; - } - return Source{ - .page = *_pageFallback, - .webpagePhoto = _webpagePhotoFallback, - .webpageDocument = _webpageDocumentFallback, - }; -} - QString SiteNameFromUrl(const QString &url) { const auto u = QUrl(url); QString pretty = u.isValid() ? u.toDisplayString() : url; diff --git a/Telegram/SourceFiles/iv/iv_data.h b/Telegram/SourceFiles/iv/iv_data.h index 2920411f32..939f13d46f 100644 --- a/Telegram/SourceFiles/iv/iv_data.h +++ b/Telegram/SourceFiles/iv/iv_data.h @@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include -#include class DocumentData; class PhotoData; @@ -16,17 +15,10 @@ class PhotoData; namespace Iv { struct RichPage; -struct Source { - MTPPage page; - std::optional webpagePhoto; - std::optional webpageDocument; -}; - class Data final { public: Data( const MTPDwebPage &webpage, - const MTPPage &page, std::shared_ptr richPage); ~Data(); @@ -36,7 +28,6 @@ public: [[nodiscard]] int32 hash() const; [[nodiscard]] bool partial() const; [[nodiscard]] const std::shared_ptr &richPage() const; - [[nodiscard]] std::optional sourceFallback() const; private: const uint64 _pageId = 0; @@ -45,9 +36,6 @@ private: const QString _name; const bool _partial = false; const std::shared_ptr _richPage; - const std::optional _pageFallback; - const std::optional _webpagePhotoFallback; - const std::optional _webpageDocumentFallback; }; diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp index 3bc990649a..04c4246fab 100644 --- a/Telegram/SourceFiles/iv/iv_instance.cpp +++ b/Telegram/SourceFiles/iv/iv_instance.cpp @@ -401,7 +401,6 @@ Shown::Shown( void Shown::prepare(not_null data, const QString &hash) { const auto richPage = data->richPage(); - const auto sourceFallback = data->sourceFallback(); const auto id = data->id(); const auto page = _session->data().webpage(data->pageId()); @@ -412,7 +411,6 @@ void Shown::prepare(not_null data, const QString &hash) { _id = id; auto prepared = Markdown::TryPrepareNativeInstantView({ - .source = sourceFallback ? &*sourceFallback : nullptr, .richPage = richPage, .mediaRuntime = createMediaRuntime(page), }); @@ -483,6 +481,7 @@ void Shown::createMarkdownController( .type = ToType::OpenPage, .url = event.url, .context = QString::number(event.webpageId), + .webpageId = event.webpageId, }); break; case FromType::OpenFile: @@ -610,7 +609,6 @@ void Shown::moveTo(not_null data, QString hash) { void Shown::update(not_null data) { const auto richPage = data->richPage(); - const auto sourceFallback = data->sourceFallback(); const auto id = data->id(); if (_markdownRuntimeUrl != id) { @@ -621,7 +619,6 @@ void Shown::update(not_null data) { const auto page = _session->data().webpage(data->pageId()); auto prepared = Markdown::TryPrepareNativeInstantView({ - .source = sourceFallback ? &*sourceFallback : nullptr, .richPage = richPage, .mediaRuntime = createMediaRuntime(page), }); @@ -818,16 +815,54 @@ void Instance::showOpenedPage( } const auto session = _shownSession; const auto url = event.url; - auto &requested = _fullRequested[session][url]; + const auto parts = event.url.split('#'); + const auto hash = (parts.size() > 1) ? parts[1] : u""_q; + if (event.webpageId) { + const auto page = session->data().webpage( + WebPageId(event.webpageId)).get(); + if (page->iv) { + this->showOpenedPage(session, page->iv.get(), hash, false); + break; + } + } + const auto requestKey = event.webpageId + ? QString::number(event.webpageId) + : url; + auto &requested = _fullRequested[session][requestKey]; + if (event.webpageId) { + const auto page = session->data().webpage( + WebPageId(event.webpageId)).get(); + if (page->iv) { + requested.page = page; + requested.hash = page->iv->hash(); + } else { + requested.hash = 0; + } + } requested.lastRequestedAt = crl::now(); session->api().request(MTPmessages_GetWebPage( MTP_string(url), MTP_int(requested.hash) )).done([=](const MTPmessages_WebPage &result) { - const auto processed = processReceivedPage(session, url, result); + const auto processed = processReceivedPage( + session, + requestKey, + result); if (const auto page = processed.page; page && page->iv) { - const auto parts = event.url.split('#'); - const auto hash = (parts.size() > 1) ? parts[1] : u""_q; + if (event.webpageId && page->id != event.webpageId) { + const auto expected = session->data().webpage( + WebPageId(event.webpageId)).get(); + if (expected->iv) { + this->showOpenedPage( + session, + expected->iv.get(), + hash, + false); + } else { + UrlClickHandler::Open(event.url); + } + return; + } this->showOpenedPage(session, page->iv.get(), hash, false); } else { UrlClickHandler::Open(event.url); diff --git a/Telegram/SourceFiles/iv/iv_rich_page.cpp b/Telegram/SourceFiles/iv/iv_rich_page.cpp index bb4ff6b119..0013a3ea04 100644 --- a/Telegram/SourceFiles/iv/iv_rich_page.cpp +++ b/Telegram/SourceFiles/iv/iv_rich_page.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "iv/iv_rich_page.h" +#include "base/algorithm.h" #include "base/flat_map.h" #include "base/qthelp_url.h" #include "base/unixtime.h" @@ -86,12 +87,39 @@ struct ParseContext { return true; } +void AddRichAnchor( + QString *primary, + std::vector *extra, + QString anchorId) { + if (anchorId.isEmpty()) { + return; + } + if (primary && primary->isEmpty()) { + *primary = std::move(anchorId); + return; + } + if (primary && *primary == anchorId) { + return; + } + if (extra && !ranges::contains(*extra, anchorId)) { + extra->push_back(std::move(anchorId)); + } +} + void AppendRich(RichText *to, const RichText &from) { to->text.append(from.text); + AddRichAnchor(&to->anchorId, &to->anchorIds, from.anchorId); + for (const auto &anchorId : from.anchorIds) { + AddRichAnchor(&to->anchorId, &to->anchorIds, anchorId); + } } void AppendRich(RichText *to, RichText &&from) { to->text.append(std::move(from.text)); + AddRichAnchor(&to->anchorId, &to->anchorIds, std::move(from.anchorId)); + for (auto &anchorId : from.anchorIds) { + AddRichAnchor(&to->anchorId, &to->anchorIds, std::move(anchorId)); + } } [[nodiscard]] QString RichPageLinkEntityData( @@ -195,20 +223,76 @@ void AppendRich(RichText *to, RichText &&from) { return result; } +void MergeDocumentInfo( + ParseContext::DocumentInfo *existing, + ParseContext::DocumentInfo info) { + if (!existing) { + return; + } + if (existing->width <= 0 && info.width > 0) { + existing->width = info.width; + } + if (existing->height <= 0 && info.height > 0) { + existing->height = info.height; + } + if (existing->fileName.isEmpty() && !info.fileName.isEmpty()) { + existing->fileName = std::move(info.fileName); + } + if (existing->title.isEmpty() && !info.title.isEmpty()) { + existing->title = std::move(info.title); + } + if (existing->performer.isEmpty() && !info.performer.isEmpty()) { + existing->performer = std::move(info.performer); + } + if (existing->duration <= 0 && info.duration > 0) { + existing->duration = info.duration; + } + if (!existing->isVideoFile && info.isVideoFile) { + existing->isVideoFile = true; + } + if (!existing->isAnimation && info.isAnimation) { + existing->isAnimation = true; + } +} + void RememberPhoto(ParseContext *context, const MTPPhoto &photo) { const auto id = PhotoIdFromMtp(photo); - context->photos.emplace( - id, - context->session->data().processPhoto(photo).get()); - context->photoSizes.emplace(id, PhotoSizeFromMtp(photo)); + if (!id) { + return; + } + context->photos[id] = context->session->data().processPhoto(photo).get(); + const auto size = PhotoSizeFromMtp(photo); + const auto existing = context->photoSizes.find(id); + if (!size.isEmpty() || existing == end(context->photoSizes)) { + context->photoSizes[id] = size; + } } void RememberDocument(ParseContext *context, const MTPDocument &document) { const auto id = DocumentIdFromMtp(document); - context->documents.emplace( - id, - context->session->data().processDocument(document).get()); - context->documentInfos.emplace(id, DocumentInfoFromMtp(document)); + if (!id) { + return; + } + const auto processed = context->session->data().processDocument(document).get(); + context->documents[id] = processed; + auto info = DocumentInfoFromMtp(document); + const auto existing = context->documentInfos.find(id); + if (existing != end(context->documentInfos)) { + MergeDocumentInfo(&existing->second, std::move(info)); + } else { + context->documentInfos.emplace(id, std::move(info)); + } +} + +void RememberWebPageMedia( + ParseContext *context, + const MTPDwebPage &webpage) { + if (const auto photo = webpage.vphoto()) { + RememberPhoto(context, *photo); + } + if (const auto document = webpage.vdocument()) { + RememberDocument(context, *document); + } } [[nodiscard]] PhotoData *FindPhoto( @@ -273,7 +357,8 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { const MTPRichText &text, RichText *result, ParseContext *context, - QString *anchorId) { + QString *anchorId, + std::vector *anchorIds) { return text.match([&](const MTPDtextEmpty &) { return true; }, [&](const MTPDtextPlain &data) { @@ -281,7 +366,7 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { return true; }, [&](const MTPDtextConcat &data) { for (const auto &part : data.vtexts().v) { - if (!AppendRichText(part, result, context, anchorId)) { + if (!AppendRichText(part, result, context, anchorId, anchorIds)) { return false; } } @@ -341,27 +426,27 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { return true; }, [&](const MTPDtextBold &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Bold); }, [&](const MTPDtextItalic &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Italic); }, [&](const MTPDtextUnderline &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Underline); }, [&](const MTPDtextStrike &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::StrikeOut); }, [&](const MTPDtextFixed &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Code); }, [&](const MTPDtextUrl &data) { const auto from = result->text.text.size(); - if (!AppendRichText(data.vtext(), result, context, anchorId)) { + if (!AppendRichText(data.vtext(), result, context, anchorId, anchorIds)) { return false; } const auto target = qs(data.vurl()); @@ -375,7 +460,7 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { RichPageLinkEntityData(target, uint64(data.vwebpage_id().v))); }, [&](const MTPDtextEmail &data) { const auto from = result->text.text.size(); - if (!AppendRichText(data.vtext(), result, context, anchorId)) { + if (!AppendRichText(data.vtext(), result, context, anchorId, anchorIds)) { return false; } const auto email = qs(data.vemail()); @@ -386,55 +471,55 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { return AddEntity(&result->text, from, EntityType::CustomUrl, target); }, [&](const MTPDtextSubscript &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Subscript); }, [&](const MTPDtextSuperscript &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Superscript); }, [&](const MTPDtextMarked &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Marked); }, [&](const MTPDtextSpoiler &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Spoiler); }, [&](const MTPDtextMention &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Mention); }, [&](const MTPDtextHashtag &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Hashtag); }, [&](const MTPDtextBotCommand &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::BotCommand); }, [&](const MTPDtextCashtag &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Cashtag); }, [&](const MTPDtextAutoUrl &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Url); }, [&](const MTPDtextAutoEmail &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Email); }, [&](const MTPDtextAutoPhone &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::Phone); }, [&](const MTPDtextBankCard &data) { const auto from = result->text.text.size(); - return AppendRichText(data.vtext(), result, context, anchorId) + return AppendRichText(data.vtext(), result, context, anchorId, anchorIds) && AddEntity(&result->text, from, EntityType::BankCard); }, [&](const MTPDtextMentionName &data) { const auto from = result->text.text.size(); - if (!AppendRichText(data.vtext(), result, context, anchorId)) { + if (!AppendRichText(data.vtext(), result, context, anchorId, anchorIds)) { return false; } const auto entityData = MentionNameEntityData( @@ -449,7 +534,7 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { entityData); }, [&](const MTPDtextDate &data) { const auto from = result->text.text.size(); - if (!AppendRichText(data.vtext(), result, context, anchorId)) { + if (!AppendRichText(data.vtext(), result, context, anchorId, anchorIds)) { return false; } auto flags = FormattedDateFlags(); @@ -478,7 +563,7 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { SerializeFormattedDateData(data.vdate().v, flags)); }, [&](const MTPDtextPhone &data) { const auto from = result->text.text.size(); - if (!AppendRichText(data.vtext(), result, context, anchorId)) { + if (!AppendRichText(data.vtext(), result, context, anchorId, anchorIds)) { return false; } const auto phone = qs(data.vphone()); @@ -488,10 +573,16 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { const auto target = u"tel:"_q + phone; return AddEntity(&result->text, from, EntityType::CustomUrl, target); }, [&](const MTPDtextAnchor &data) { - if (anchorId && anchorId->isEmpty()) { - *anchorId = Markdown::NormalizeFragmentId(qs(data.vname())); - } - return AppendRichText(data.vtext(), result, context, anchorId); + AddRichAnchor( + anchorId, + anchorIds, + Markdown::NormalizeFragmentId(qs(data.vname()))); + return AppendRichText( + data.vtext(), + result, + context, + anchorId, + anchorIds); }); } @@ -500,8 +591,10 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { ParseContext *context) { auto result = RichText(); auto anchorId = QString(); - (void)AppendRichText(text, &result, context, &anchorId); + auto anchorIds = std::vector(); + (void)AppendRichText(text, &result, context, &anchorId, &anchorIds); result.anchorId = std::move(anchorId); + result.anchorIds = std::move(anchorIds); return result; } @@ -510,9 +603,20 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { ParseContext *context) { auto result = RichText(); auto anchorId = QString(); - (void)AppendRichText(caption.data().vtext(), &result, context, &anchorId); + auto anchorIds = std::vector(); + (void)AppendRichText( + caption.data().vtext(), + &result, + context, + &anchorId, + &anchorIds); auto credit = RichText(); - (void)AppendRichText(caption.data().vcredit(), &credit, context, &anchorId); + (void)AppendRichText( + caption.data().vcredit(), + &credit, + context, + &anchorId, + &anchorIds); if (!credit.text.empty()) { if (!result.text.empty()) { result.text.append(QChar('\n')); @@ -520,14 +624,15 @@ void RememberDocument(ParseContext *context, const MTPDocument &document) { AppendRich(&result, std::move(credit)); } result.anchorId = std::move(anchorId); + result.anchorIds = std::move(anchorIds); return result; } void AdoptAnchor(QString *anchorId, RichText *text) { if (anchorId->isEmpty() && !text->anchorId.isEmpty()) { - *anchorId = text->anchorId; + *anchorId = std::move(text->anchorId); + text->anchorId.clear(); } - text->anchorId.clear(); } void AppendBlocks( @@ -608,8 +713,7 @@ void AppendBlock( row.is_checkbox(), row.is_checked()); listItem.text = ParseRichText(row.vtext(), context); - listItem.anchorId = listItem.text.anchorId; - listItem.text.anchorId.clear(); + AdoptAnchor(&listItem.anchorId, &listItem.text); }, [&](const MTPDpageListItemBlocks &row) { listItem.taskState = TaskStateFromFlags( row.is_checkbox(), @@ -672,10 +776,11 @@ void AppendBlock( }, [&](const MTPDpageBlockEmbed &data) { auto parsed = MakeBlock(BlockKind::Embed); parsed.url = qs(data.vurl().value_or_empty()); - parsed.html = data.vhtml() ? qs(data.vhtml()->v) : QString(); + parsed.html = data.vhtml() ? qba(*data.vhtml()) : QByteArray(); parsed.width = data.vw().value_or_empty(); parsed.height = data.vh().value_or_empty(); - parsed.fullWidth = data.is_full_width(); + parsed.fullWidth = data.is_full_width() || (data.vw() && !data.vw()->v); + parsed.fixedHeight = (data.vh() != nullptr); parsed.allowScrolling = data.is_allow_scrolling(); parsed.caption = ParseCaption(data.vcaption(), context); AdoptAnchor(&parsed.anchorId, &parsed.caption); @@ -857,6 +962,7 @@ void AppendBlock( if (const auto text = cellData.vtext()) { parsedCell.text = ParseRichText(*text, context); parsedCell.text.anchorId.clear(); + parsedCell.text.anchorIds.clear(); } parsedRow.cells.push_back(std::move(parsedCell)); }); @@ -889,8 +995,7 @@ void AppendBlock( row.is_checked()); fillNumber(row); listItem.text = ParseRichText(row.vtext(), context); - listItem.anchorId = listItem.text.anchorId; - listItem.text.anchorId.clear(); + AdoptAnchor(&listItem.anchorId, &listItem.text); }, [&](const MTPDpageListOrderedItemBlocks &row) { listItem.taskState = TaskStateFromFlags( row.is_checkbox(), @@ -1163,14 +1268,42 @@ void AppendSummaryBlock(TextWithEntities *result, const Block &block) { } } +std::shared_ptr ParsePage( + not_null session, + const MTPPage &page, + const MTPDwebPage *webpage) { + return page.match([&](const MTPDpage &data) { + auto result = std::make_shared(); + auto context = ParseContext{ session }; + result->url = qs(data.vurl()); + result->rtl = data.is_rtl(); + result->part = data.is_part(); + result->views = data.vviews().value_or_empty(); + for (const auto &photo : data.vphotos().v) { + RememberPhoto(&context, photo); + } + for (const auto &document : data.vdocuments().v) { + RememberDocument(&context, document); + } + if (webpage) { + RememberWebPageMedia(&context, *webpage); + } + AppendBlocks(data.vblocks().v, &result->blocks, &context); + return std::shared_ptr(std::move(result)); + }, [](const auto &) { + return std::shared_ptr(); + }); +} + } // namespace QString EncodeRichPageLinkUrl( const QString &url, uint64 webpageId) { - return u"internal:wrapped?url=%1&context=iv&webpage_id=%2"_q - .arg(qthelp::url_encode(url)) - .arg(webpageId); + return u"internal:wrapped?url="_q + + qthelp::url_encode(url) + + u"&context=iv&webpage_id="_q + + QString::number(webpageId); } std::optional DecodeRichPageLinkUrl(const QString &data) { @@ -1222,24 +1355,17 @@ std::shared_ptr ParseRichPage( std::shared_ptr ParseRichPage( not_null session, const MTPPage &page) { - return page.match([&](const MTPDpage &data) { - auto result = std::make_shared(); - auto context = ParseContext{ session }; - result->url = qs(data.vurl()); - result->rtl = data.is_rtl(); - result->part = data.is_part(); - result->views = data.vviews().value_or_empty(); - for (const auto &photo : data.vphotos().v) { - RememberPhoto(&context, photo); - } - for (const auto &document : data.vdocuments().v) { - RememberDocument(&context, document); - } - AppendBlocks(data.vblocks().v, &result->blocks, &context); - return std::shared_ptr(std::move(result)); - }, [](const auto &) { + return ParsePage(session, page, nullptr); +} + +std::shared_ptr ParseRichPage( + not_null session, + const MTPDwebPage &webpage) { + const auto cachedPage = webpage.vcached_page(); + if (!cachedPage) { return std::shared_ptr(); - }); + } + return ParsePage(session, *cachedPage, &webpage); } TextWithEntities FlattenRichPageSummary(const RichPage &page) { diff --git a/Telegram/SourceFiles/iv/iv_rich_page.h b/Telegram/SourceFiles/iv/iv_rich_page.h index b870a962ee..58078e8f90 100644 --- a/Telegram/SourceFiles/iv/iv_rich_page.h +++ b/Telegram/SourceFiles/iv/iv_rich_page.h @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/basic_types.h" #include "ui/text/text_entity.h" +#include + #include #include #include @@ -28,6 +30,7 @@ struct RichPage { struct RichText { TextWithEntities text; QString anchorId; + std::vector anchorIds; }; enum class BlockKind : uchar { Unsupported, @@ -126,7 +129,7 @@ struct RichPage { QString language; QString formula; QString url; - QString html; + QByteArray html; QString author; QString username; QString channelTitle; @@ -143,6 +146,7 @@ struct RichPage { uint64 documentId = 0; uint64 channelId = 0; bool fullWidth = false; + bool fixedHeight = false; bool allowScrolling = false; bool autoplay = false; bool loop = false; @@ -188,6 +192,9 @@ struct RichPageLinkUrl { [[nodiscard]] std::shared_ptr ParseRichPage( not_null session, const MTPPage &page); +[[nodiscard]] std::shared_ptr ParseRichPage( + not_null session, + const MTPDwebPage &webpage); [[nodiscard]] TextWithEntities FlattenRichPageSummary( const RichPage &page); [[nodiscard]] TextWithEntities FlattenRichPageSummary( diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.cpp b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.cpp index de963aa1bc..6e6ff3ab44 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.cpp +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.cpp @@ -6,7 +6,6 @@ For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "iv/markdown/iv_markdown_prepare.h" -#include "iv/iv_data.h" #include "iv/iv_rich_page.h" #include "iv/markdown/iv_markdown_prepare_blocks.h" #include "iv/markdown/iv_markdown_prepare_formulas.h" @@ -144,75 +143,37 @@ NativeInstantViewPrepareResult TryPrepareNativeInstantView( }; }; - if (!request.source && !request.richPage) { + if (!request.richPage) { state.setFailure( PrepareTerminalFailure::InvalidRequest, - u"missing-native-iv-source"_q); + u"missing-native-iv-rich-page"_q); ClearPreparedOutput(&state.result); return finish( NativeInstantViewPrepareResultKind::Failure, state.result.failure.debugReason); } - if (request.source) { - for (const auto &photo : request.source->page.data().vphotos().v) { - RememberNativeIvPhoto(&state, photo); - } - if (request.source->webpagePhoto) { - RememberNativeIvPhoto(&state, *request.source->webpagePhoto); - } - for (const auto &document : request.source->page.data().vdocuments().v) { - RememberNativeIvDocument(&state, document); - } - if (request.source->webpageDocument) { - RememberNativeIvDocument(&state, *request.source->webpageDocument); - } - - if (!PrepareNativeIvBlocks( - request.source->page.data().vblocks().v, - &state.result.blocks.blocks, - &state)) { - if (state.result.failure.failed()) { - ClearPreparedOutput(&state.result); - return finish( - NativeInstantViewPrepareResultKind::Failure, - state.result.failure.debugReason); - } - (void)PrepareNativeIvPlainPlaceholderBlock( - u"Prepare Failed"_q, - &state.result.blocks.blocks); - } - ApplySoftPreparedBlockLimit(&state.result.blocks.blocks); - MeasureNativeIvPreparedFormulas(&state); - if (state.result.failure.failed()) { - ClearPreparedOutput(&state.result); - return finish( - NativeInstantViewPrepareResultKind::Failure, - state.result.failure.debugReason); - } - } else if (request.richPage) { - if (!PrepareNativeIvBlocks( - *request.richPage, - &state.result.blocks.blocks, - &state)) { - if (state.result.failure.failed()) { - ClearPreparedOutput(&state.result); - return finish( - NativeInstantViewPrepareResultKind::Failure, - state.result.failure.debugReason); - } - (void)PrepareNativeIvPlainPlaceholderBlock( - u"Prepare Failed"_q, - &state.result.blocks.blocks); - } - ApplySoftPreparedBlockLimit(&state.result.blocks.blocks); - MeasureNativeIvPreparedFormulas(&state); + if (!PrepareNativeIvBlocks( + *request.richPage, + &state.result.blocks.blocks, + &state)) { if (state.result.failure.failed()) { ClearPreparedOutput(&state.result); return finish( NativeInstantViewPrepareResultKind::Failure, state.result.failure.debugReason); } + (void)PrepareNativeIvPlainPlaceholderBlock( + u"Prepare Failed"_q, + &state.result.blocks.blocks); + } + ApplySoftPreparedBlockLimit(&state.result.blocks.blocks); + MeasureNativeIvPreparedFormulas(&state); + if (state.result.failure.failed()) { + ClearPreparedOutput(&state.result); + return finish( + NativeInstantViewPrepareResultKind::Failure, + state.result.failure.debugReason); } return finish( NativeInstantViewPrepareResultKind::Supported, diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.h b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.h index b35d3a85ee..bd12522fae 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.h +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare.h @@ -24,12 +24,8 @@ struct Markdown; namespace Iv { struct RichPage; -struct Source; } // namespace Iv -class DocumentData; -class PhotoData; - namespace Iv::Markdown { enum class PreparedBlockKind { @@ -337,10 +333,7 @@ struct PrepareRequest { }; struct NativeInstantViewPrepareRequest { - const Iv::Source *source = nullptr; std::shared_ptr richPage; - const PhotoData *webpagePhoto = nullptr; - const DocumentData *webpageDocument = nullptr; std::shared_ptr mediaRuntime; std::optional dimensionsOverride; }; diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.cpp b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.cpp index 2d536c1fed..019c3703c7 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.cpp +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.cpp @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include -#include #include #include @@ -71,18 +70,6 @@ using RichPageTableRow = Iv::RichPage::TableRow; return dimensions.bodyTextSize; } -[[nodiscard]] QString NativeIvRelatedArticleFooterText( - const MTPDpageRelatedArticle &data) { - const auto author = qs(data.vauthor().value_or_empty()).trimmed(); - const auto published = data.vpublished_date(); - if (published && !author.isEmpty()) { - return author + u", "_q + NativeIvDateText(published->v); - } else if (published) { - return NativeIvDateText(published->v); - } - return author; -} - [[nodiscard]] PreparedLink PrepareNativeIvRelatedArticleLink( QString url, uint64 webpageId, @@ -112,180 +99,6 @@ void SortPreparedIvRichText(PreparedIvRichText *text) { SortEntities(&text->text); } -[[nodiscard]] uint16 InternalPreparedLinkIndex(const QString &data) { - const auto prefix = u"internal:index"_q; - return (data.size() == prefix.size() + 1 && data.startsWith(prefix)) - ? uint16(data.back().unicode()) - : uint16(0); -} - -[[nodiscard]] uint16 RemappedPreparedLinkIndex( - const std::vector> &remapped, - uint16 index) { - for (const auto &[from, to] : remapped) { - if (from == index) { - return to; - } - } - return 0; -} - -void AppendPreparedIvRichText( - PreparedIvRichText *result, - PreparedIvRichText prepared) { - auto remapped = std::vector>(); - remapped.reserve(prepared.links.size()); - result->links.reserve(result->links.size() + prepared.links.size()); - for (const auto &link : prepared.links) { - const auto index = result->links.size() + 1; - if (index > std::numeric_limits::max()) { - continue; - } - auto copy = link; - copy.index = uint16(index); - remapped.push_back({ link.index, copy.index }); - result->links.push_back(std::move(copy)); - } - - const auto shift = result->text.text.size(); - result->text.text.append(prepared.text.text); - result->text.entities.reserve( - result->text.entities.size() + prepared.text.entities.size()); - for (const auto &entity : prepared.text.entities) { - auto data = entity.data(); - if (entity.type() == EntityType::CustomUrl) { - if (const auto from = InternalPreparedLinkIndex(data)) { - if (const auto to = RemappedPreparedLinkIndex(remapped, from)) { - data = InternalLinkData(to); - } - } - } - result->text.entities.push_back(EntityInText( - entity.type(), - entity.offset() + shift, - entity.length(), - data)); - } - result->anchorIds.reserve(result->anchorIds.size() + prepared.anchorIds.size()); - for (auto &anchorId : prepared.anchorIds) { - result->anchorIds.push_back(std::move(anchorId)); - } -} - -[[nodiscard]] bool PrepareNativeIvCaption( - const MTPPageCaption &caption, - PreparedIvRichText *result, - QString *blockAnchorId, - NativeIvPrepareState *state) { - auto text = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - caption.data().vtext(), - &text, - blockAnchorId, - state)) { - return false; - } - AppendPreparedIvRichText(result, std::move(text)); - - auto credit = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - caption.data().vcredit(), - &credit, - blockAnchorId, - state)) { - return false; - } - if (!credit.text.text.isEmpty()) { - if (!result->text.text.isEmpty()) { - result->text.append(QChar('\n')); - } - AppendPreparedIvRichText(result, std::move(credit)); - } - return true; -} - -[[nodiscard]] QString StripOneTrailingNewline(QString text); -[[nodiscard]] PreparedBlock PrepareNativeIvEmbedPostFallbackParagraph( - QString url); - -[[nodiscard]] std::optional EmbedRequestFromMtpBlock( - const MTPDpageBlockEmbed &data) { - auto request = EmbedRequest{ - .width = data.vw() ? data.vw()->v : 0, - .height = data.vh() ? data.vh()->v : 0, - .fullWidth = data.is_full_width() || (data.vw() && !data.vw()->v), - .fixedHeight = (data.vh() != nullptr), - .allowScrolling = data.is_allow_scrolling(), - }; - if (const auto url = data.vurl(); url && !qs(*url).isEmpty()) { - request.url = qs(*url); - } else if (const auto html = data.vhtml(); html && !html->v.isEmpty()) { - request.html = html->v; - } else { - return std::nullopt; - } - return request; -} - -[[nodiscard]] bool PrepareNativeIvEmbedBlock( - const MTPDpageBlockEmbed &data, - std::vector *result, - NativeIvPrepareState *state) { - const auto label = tr::lng_iv_click_to_view(tr::now); - auto request = EmbedRequestFromMtpBlock(data); - if (!request) { - return PrepareNativeIvPlaceholderBlock( - label, - data.vcaption(), - result, - state); - } - return PrepareNativeIvPlaceholderBlock( - label, - data.vcaption(), - result, - state, - std::move(*request)); -} - -[[nodiscard]] bool PrepareNativeIvEmbedPostBlock( - const MTPDpageBlockEmbedPost &data, - std::vector *result, - NativeIvPrepareState *state) { - auto caption = PreparedIvRichText(); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::EmbedPost; - block.embedPost.url = qs(data.vurl()).trimmed(); - block.embedPost.authorPhotoId = uint64(data.vauthor_photo_id().v); - block.embedPost.author = qs(data.vauthor()).trimmed(); - if (const auto date = data.vdate().v) { - block.embedPost.dateText = NativeIvDateText(date); - } - if (!PrepareNativeIvCaption( - data.vcaption(), - &caption, - &block.anchorId, - state)) { - return false; - } - SortPreparedIvRichText(&caption); - block.text = std::move(caption.text); - block.links = std::move(caption.links); - block.anchorIds = std::move(caption.anchorIds); - block.supplementary = true; - if (data.vblocks().v.isEmpty()) { - block.children.push_back( - PrepareNativeIvEmbedPostFallbackParagraph(block.embedPost.url)); - } else if (!PrepareNativeIvBlocks( - data.vblocks().v, - &block.children, - state)) { - return false; - } - result->push_back(std::move(block)); - return true; -} - [[nodiscard]] QString StripOneTrailingNewline(QString text) { if (text.endsWith(u"\r\n"_q)) { text.chop(2); @@ -331,47 +144,6 @@ void AppendPreparedIvRichText( return block; } -[[nodiscard]] bool PrepareNativeIvMathBlock( - const MTPDpageBlockMath &data, - std::vector *result, - NativeIvPrepareState *state) { - const auto source = qs(data.vsource()); - if (source.trimmed().isEmpty()) { - return true; - } - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::DisplayMath; - block.formulaTex = source; - block.mathKind = MathKind::Display; - block.formulaIndex = state->rememberFormula(block); - result->push_back(std::move(block)); - return true; -} - -[[nodiscard]] bool AppendNativeIvFlowBlock( - std::vector *result, - PreparedBlockKind kind, - int headingLevel, - const MTPRichText &text, - NativeIvPrepareState *state, - bool allowEmpty = false) { - auto prepared = PreparedIvRichText(); - auto anchorId = QString(); - const auto context = NativeIvRichTextContextForTextSize( - NativeIvFlowTextSize(kind, headingLevel, state->dimensions), - state->dimensions); - if (!PrepareNativeIvRichText(text, &prepared, &anchorId, state, context)) { - return false; - } - return AppendPreparedIvRichBlock( - result, - kind, - headingLevel, - std::move(prepared), - std::move(anchorId), - allowEmpty); -} - void WrapPreparedIvRichTextItalic(PreparedIvRichText *prepared) { if (!prepared || prepared->text.text.isEmpty()) { return; @@ -407,125 +179,6 @@ bool AppendPreparedQuoteParagraph( return true; } -[[nodiscard]] bool PrepareNativeIvQuoteBlock( - const MTPRichText &text, - const MTPRichText &caption, - bool pullquote, - std::vector *result, - NativeIvPrepareState *state) { - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Quote; - block.pullquote = pullquote; - auto body = PreparedIvRichText(); - if (!PrepareNativeIvRichText(text, &body, &block.anchorId, state)) { - return false; - } - if (!AppendPreparedQuoteParagraph( - &block.children, - std::move(body), - pullquote)) { - return false; - } - auto cite = PreparedIvRichText(); - if (!PrepareNativeIvRichText(caption, &cite, &block.anchorId, state)) { - return false; - } - if (!AppendPreparedQuoteParagraph( - &block.children, - std::move(cite), - pullquote, - true)) { - return false; - } - if (block.children.empty()) { - block.children.push_back(EmptyParagraphBlock()); - if (pullquote) { - block.children.back().flowAlignment = TableAlignment::Center; - } - } - result->push_back(std::move(block)); - return true; -} - -[[nodiscard]] bool PrepareNativeIvQuoteBlock( - const QVector &blocks, - const MTPRichText &caption, - std::vector *result, - NativeIvPrepareState *state) { - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Quote; - block.pullquote = false; - if (!PrepareNativeIvBlocks(blocks, &block.children, state)) { - return false; - } - auto cite = PreparedIvRichText(); - if (!PrepareNativeIvRichText(caption, &cite, &block.anchorId, state)) { - return false; - } - if (!AppendPreparedQuoteParagraph( - &block.children, - std::move(cite), - false, - true)) { - return false; - } - if (block.children.empty()) { - block.children.push_back(EmptyParagraphBlock()); - } - result->push_back(std::move(block)); - return true; -} - -[[nodiscard]] TaskState NativeIvTaskState(bool checkbox, bool checked) { - if (!checkbox) { - return TaskState::None; - } - return checked ? TaskState::Checked : TaskState::Unchecked; -} - -[[nodiscard]] bool PrepareNativeIvList( - const QVector &items, - PreparedBlock *result, - NativeIvPrepareState *state) { - for (const auto &item : items) { - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::ListItem; - block.listKind = result->listKind; - block.listDelimiter = result->listDelimiter; - const auto ok = item.match([&](const MTPDpageListItemText &data) { - block.taskState = NativeIvTaskState( - data.is_checkbox(), - data.is_checked()); - auto prepared = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - data.vtext(), - &prepared, - &block.anchorId, - state)) { - return false; - } - return AppendPreparedIvRichBlock( - &block.children, - PreparedBlockKind::Paragraph, - 0, - std::move(prepared)); - }, [&](const MTPDpageListItemBlocks &data) { - block.taskState = NativeIvTaskState( - data.is_checkbox(), - data.is_checked()); - return PrepareNativeIvBlocks(data.vblocks().v, &block.children, state); - }); - if (!ok) { - return false; - } - if (block.children.empty()) { - block.children.push_back(EmptyParagraphBlock()); - } - result->children.push_back(std::move(block)); - } - return true; -} - [[nodiscard]] bool ParseOrderedNumber( const QString &value, int *result) { @@ -544,88 +197,6 @@ bool AppendPreparedQuoteParagraph( : (result.children.back().orderedNumber + 1); } -[[nodiscard]] bool PrepareNativeIvOrderedList( - const QVector &items, - PreparedBlock *result, - NativeIvPrepareState *state) { - auto firstNumber = true; - for (const auto &item : items) { - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::ListItem; - block.listKind = result->listKind; - block.listDelimiter = result->listDelimiter; - const auto resolveNumber = [&](const auto &data) { - if (const auto value = data.vvalue()) { - return value->v; - } - auto orderedNumber = 0; - if (ParseOrderedNumber( - qs(data.vnum().value_or_empty()), - &orderedNumber)) { - return orderedNumber; - } - return NextNativeIvOrderedNumber(*result); - }; - const auto ok = item.match([&](const MTPDpageListOrderedItemText &data) { - block.taskState = NativeIvTaskState( - data.is_checkbox(), - data.is_checked()); - block.orderedNumber = resolveNumber(data); - auto prepared = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - data.vtext(), - &prepared, - &block.anchorId, - state)) { - return false; - } - return AppendPreparedIvRichBlock( - &block.children, - PreparedBlockKind::Paragraph, - 0, - std::move(prepared)); - }, [&](const MTPDpageListOrderedItemBlocks &data) { - block.taskState = NativeIvTaskState( - data.is_checkbox(), - data.is_checked()); - block.orderedNumber = resolveNumber(data); - return PrepareNativeIvBlocks(data.vblocks().v, &block.children, state); - }); - if (!ok) { - return false; - } - if (firstNumber) { - result->startNumber = block.orderedNumber; - firstNumber = false; - } - if (block.children.empty()) { - block.children.push_back(EmptyParagraphBlock()); - } - result->children.push_back(std::move(block)); - } - return true; -} - -[[nodiscard]] TableAlignment NativeIvTableAlignment( - const MTPDpageTableCell &cell) { - if (cell.is_align_right()) { - return TableAlignment::Right; - } else if (cell.is_align_center()) { - return TableAlignment::Center; - } - return TableAlignment::Left; -} - -[[nodiscard]] PreparedTableCellVerticalAlignment NativeIvTableVerticalAlignment( - const MTPDpageTableCell &cell) { - if (cell.is_valign_bottom()) { - return PreparedTableCellVerticalAlignment::Bottom; - } else if (cell.is_valign_middle()) { - return PreparedTableCellVerticalAlignment::Middle; - } - return PreparedTableCellVerticalAlignment::Top; -} - using NativeIvTableOccupancyRow = std::vector; using NativeIvTableOccupancyGrid = std::vector; @@ -774,552 +345,6 @@ void MarkNativeIvTableSlots( return result; } -[[nodiscard]] bool PrepareNativeIvTableBlock( - const MTPDpageBlockTable &data, - std::vector *result, - NativeIvPrepareState *state) { - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Table; - block.tableBordered = data.is_bordered(); - block.tableStriped = data.is_striped(); - - auto title = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - data.vtitle(), - &title, - &block.anchorId, - state)) { - return false; - } - SortPreparedIvRichText(&title); - block.text = std::move(title.text); - block.links = std::move(title.links); - block.anchorIds = std::move(title.anchorIds); - - const auto &limits = PrepareTableRenderLimitsForIv(); - const auto rowCount = std::min(int(data.vrows().v.size()), limits.maxRows); - - auto occupancy = NativeIvTableOccupancyGrid(rowCount); - block.tableRows.reserve(rowCount); - auto occupiedSlotCountSoFar = int64(0); - - auto rowIndex = 0; - for (const auto &row : data.vrows().v) { - if (rowIndex >= rowCount) { - break; - } - auto preparedRow = PreparedTableRow(); - const auto ok = row.match([&](const MTPDpageTableRow &rowData) { - preparedRow.cells.reserve(std::min( - int(rowData.vcells().v.size()), - limits.maxColumns)); - for (const auto &cell : rowData.vcells().v) { - auto preparedCell = PreparedTableCell(); - const auto cellOk = cell.match([&](const MTPDpageTableCell &cellData) { - const auto rawColspan = cellData.vcolspan() - ? cellData.vcolspan()->v - : 1; - const auto rawRowspan = cellData.vrowspan() - ? cellData.vrowspan()->v - : 1; - const auto normalizedColspan = NormalizeNativeIvTableSpan( - rawColspan); - const auto rowspan = ClampNativeIvTableRowspan( - rawRowspan, - rowIndex, - rowCount); - if (rowspan <= 0) { - return true; - } - const auto column = FirstAvailableNativeIvTableColumn( - occupancy, - rowIndex, - rowspan, - normalizedColspan, - limits.maxColumns); - if (column < 0) { - return true; - } - const auto colspan = ClampNativeIvTableColspan( - normalizedColspan, - column, - limits.maxColumns); - if (colspan <= 0) { - return true; - } - const auto occupiedSlotGrowth = int64(rowspan) * colspan; - if (occupiedSlotGrowth > limits.maxCells - || (occupiedSlotCountSoFar + occupiedSlotGrowth) - > limits.maxCells) { - return true; - } - preparedCell.column = column; - preparedCell.alignment = NativeIvTableAlignment(cellData); - preparedCell.header = cellData.is_header(); - preparedCell.verticalAlignment - = NativeIvTableVerticalAlignment(cellData); - preparedCell.colspan = colspan; - preparedCell.rowspan = rowspan; - if (cellData.vtext()) { - auto rich = PreparedIvRichText(); - const auto context = NativeIvRichTextContextForTextSize( - cellData.is_header() - ? state->dimensions.tableHeaderTextSize - : state->dimensions.tableBodyTextSize, - state->dimensions); - if (!PrepareNativeIvRichText( - *cellData.vtext(), - &rich, - nullptr, - state, - context)) { - return false; - } - SortPreparedIvRichText(&rich); - preparedCell.text = std::move(rich.text); - preparedCell.links = std::move(rich.links); - } - MarkNativeIvTableSlots( - &occupancy, - rowIndex, - column, - rowspan, - colspan); - occupiedSlotCountSoFar += occupiedSlotGrowth; - preparedRow.cells.push_back(std::move(preparedCell)); - return true; - }); - if (!cellOk) { - return false; - } - } - preparedRow.header = !preparedRow.cells.empty() - && std::all_of( - preparedRow.cells.begin(), - preparedRow.cells.end(), - [](const PreparedTableCell &cell) { - return cell.header; - }); - return true; - }); - if (!ok) { - return false; - } - block.tableRows.push_back(std::move(preparedRow)); - ++rowIndex; - } - - block.tableColumnCount = NativeIvTableColumnCount(occupancy); - - block.tableAlignments.resize(block.tableColumnCount, TableAlignment::Left); - for (const auto &preparedRow : block.tableRows) { - for (const auto &preparedCell : preparedRow.cells) { - const auto from = std::max(preparedCell.column, 0); - const auto to = std::min( - preparedCell.column + preparedCell.colspan, - block.tableColumnCount); - for (auto column = from; column != to; ++column) { - block.tableAlignments[column] = preparedCell.alignment; - } - } - } - result->push_back(std::move(block)); - return true; -} - -[[nodiscard]] bool PrepareNativeIvDetailsBlock( - const MTPDpageBlockDetails &data, - std::vector *result, - NativeIvPrepareState *state) { - auto summary = PreparedIvRichText(); - auto anchorId = NativeIvDetailsAnchorId(state); - if (!PrepareNativeIvRichText( - data.vtitle(), - &summary, - &anchorId, - state)) { - return false; - } - if (!summary.links.empty()) { - const auto isLink = [](const EntityInText &entity) { - return entity.type() == EntityType::CustomUrl; - }; - const auto from = std::remove_if( - summary.text.entities.begin(), - summary.text.entities.end(), - isLink); - summary.text.entities.erase(from, summary.text.entities.end()); - summary.links.clear(); - } - SortPreparedIvRichText(&summary); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Details; - block.anchorId = std::move(anchorId); - block.collapsed = !data.is_open(); - block.text = std::move(summary.text); - block.links = std::move(summary.links); - if (!PrepareNativeIvBlocks(data.vblocks().v, &block.children, state)) { - return false; - } - result->push_back(std::move(block)); - return true; -} - -[[nodiscard]] bool PrepareNativeIvRelatedArticlesBlock( - const MTPDpageBlockRelatedArticles &data, - std::vector *result, - NativeIvPrepareState *state) { - auto related = std::vector(); - related.reserve(data.varticles().v.size()); - for (const auto &article : data.varticles().v) { - auto prepared = PreparedBlock(); - prepared.kind = PreparedBlockKind::RelatedArticle; - const auto &row = article.data(); - prepared.relatedArticle.title = qs( - row.vtitle().value_or_empty()).trimmed(); - prepared.relatedArticle.description = qs( - row.vdescription().value_or_empty()).trimmed(); - prepared.relatedArticle.footer = NativeIvRelatedArticleFooterText(row); - prepared.relatedArticle.photoId = row.vphoto_id().value_or_empty(); - if (prepared.relatedArticle.title.isEmpty() - && prepared.relatedArticle.description.isEmpty() - && prepared.relatedArticle.footer.isEmpty()) { - prepared.relatedArticle.title = qs(row.vurl()).trimmed(); - } - const auto linkText = !prepared.relatedArticle.title.isEmpty() - ? prepared.relatedArticle.title - : !prepared.relatedArticle.description.isEmpty() - ? prepared.relatedArticle.description - : prepared.relatedArticle.footer; - prepared.relatedArticle.link = PrepareNativeIvRelatedArticleLink( - qs(row.vurl()), - uint64(row.vwebpage_id().v), - linkText); - const auto appendLine = [&](QString *copyText, const QString &line) { - if (line.isEmpty()) { - return; - } else if (!copyText->isEmpty()) { - copyText->append(QChar('\n')); - } - copyText->append(line); - }; - appendLine(&prepared.relatedArticle.copyText, prepared.relatedArticle.title); - appendLine( - &prepared.relatedArticle.copyText, - prepared.relatedArticle.description); - appendLine(&prepared.relatedArticle.copyText, prepared.relatedArticle.footer); - if (prepared.relatedArticle.copyText.isEmpty()) { - prepared.relatedArticle.copyText = prepared.relatedArticle.link.target; - } - related.push_back(std::move(prepared)); - } - if (related.empty()) { - return true; - } - - auto title = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvRichText( - data.vtitle(), - &title, - &anchorId, - state)) { - return false; - } - SortPreparedIvRichText(&title); - if (!title.text.text.isEmpty()) { - if (!AppendPreparedIvRichBlock( - result, - PreparedBlockKind::Heading, - 4, - std::move(title), - std::move(anchorId))) { - return false; - } - } else if (!anchorId.isEmpty() && related.front().anchorId.isEmpty()) { - related.front().anchorId = std::move(anchorId); - } - result->insert( - result->end(), - std::make_move_iterator(related.begin()), - std::make_move_iterator(related.end())); - return true; -} - -[[nodiscard]] bool PrepareNativeIvBlock( - const MTPPageBlock &block, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvBlock( - const MTPPageBlock &block, - std::vector *result, - NativeIvPrepareState *state) { - if (state->blocked()) { - return false; - } - return block.match([&](const MTPDpageBlockUnsupported &) { - return PrepareNativeIvPlainPlaceholderBlock( - u"Unsupported Content"_q, - result); - }, [&](const MTPDpageBlockTitle &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 1, - data.vtext(), - state); - }, [&](const MTPDpageBlockSubtitle &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 2, - data.vtext(), - state); - }, [&](const MTPDpageBlockAuthorDate &data) { - auto prepared = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvRichText( - data.vauthor(), - &prepared, - &anchorId, - state)) { - return false; - } - if (const auto date = data.vpublished_date().v) { - if (!prepared.text.text.isEmpty()) { - prepared.text.append(u" \u2022 "_q); - } - prepared.text.append(NativeIvDateText(date)); - } - return AppendPreparedIvRichBlock( - result, - PreparedBlockKind::Paragraph, - 0, - std::move(prepared), - std::move(anchorId), - false, - true); - }, [&](const MTPDpageBlockHeader &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 3, - data.vtext(), - state); - }, [&](const MTPDpageBlockSubheader &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 4, - data.vtext(), - state); - }, [&](const MTPDpageBlockParagraph &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Paragraph, - 0, - data.vtext(), - state); - }, [&](const MTPDpageBlockThinking &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Thinking, - 0, - data.vtext(), - state); - }, [&](const MTPDpageBlockPreformatted &data) { - auto prepared = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvRichText( - data.vtext(), - &prepared, - &anchorId, - state)) { - return false; - } - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::CodeBlock; - block.anchorId = std::move(anchorId); - block.codeLanguage = qs(data.vlanguage()).trimmed(); - block.text.text = StripOneTrailingNewline(prepared.text.text); - result->push_back(std::move(block)); - return true; - }, [&](const MTPDpageBlockFooter &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Paragraph, - 0, - data.vtext(), - state); - }, [&](const MTPDpageBlockDivider &) { - result->push_back(PrepareRuleBlock()); - return true; - }, [&](const MTPDpageBlockAnchor &data) { - const auto anchorId = NormalizeFragmentId(qs(data.vname())); - if (anchorId.isEmpty()) { - return true; - } - auto prepared = PreparedIvRichText(); - return AppendPreparedIvRichBlock( - result, - PreparedBlockKind::Paragraph, - 0, - std::move(prepared), - anchorId, - true); - }, [&](const MTPDpageBlockList &data) { - auto prepared = PreparedBlock(); - prepared.kind = PreparedBlockKind::List; - prepared.listKind = ListKind::Bullet; - return PrepareNativeIvList(data.vitems().v, &prepared, state) - ? (result->push_back(std::move(prepared)), true) - : false; - }, [&](const MTPDpageBlockBlockquote &data) { - return PrepareNativeIvQuoteBlock( - data.vtext(), - data.vcaption(), - false, - result, - state); - }, [&](const MTPDpageBlockBlockquoteBlocks &data) { - return PrepareNativeIvQuoteBlock( - data.vblocks().v, - data.vcaption(), - result, - state); - }, [&](const MTPDpageBlockPullquote &data) { - return PrepareNativeIvQuoteBlock( - data.vtext(), - data.vcaption(), - true, - result, - state); - }, [&](const MTPDpageBlockPhoto &data) { - return PrepareNativeIvPhotoBlock(data, result, state); - }, [&](const MTPDpageBlockVideo &data) { - return PrepareNativeIvVideoBlock(data, result, state); - }, [&](const MTPDpageBlockCover &data) { - return PrepareNativeIvBlock(data.vcover(), result, state); - }, [&](const MTPDpageBlockEmbed &data) { - return PrepareNativeIvEmbedBlock(data, result, state); - }, [&](const MTPDpageBlockEmbedPost &data) { - return PrepareNativeIvEmbedPostBlock(data, result, state); - }, [&](const MTPDpageBlockCollage &data) { - return PrepareNativeIvGroupedMediaBlock( - data.vitems().v, - data.vcaption(), - PreparedGroupedMediaIntent::Collage, - u"Collage placeholder"_q, - result, - state); - }, [&](const MTPDpageBlockSlideshow &data) { - return PrepareNativeIvGroupedMediaBlock( - data.vitems().v, - data.vcaption(), - PreparedGroupedMediaIntent::Slideshow, - u"Grouped Media Placeholder"_q, - result, - state); - }, [&](const MTPDpageBlockChannel &data) { - return PrepareNativeIvChannelBlock(data, result, state); - }, [&](const MTPDpageBlockAudio &data) { - return PrepareNativeIvAudioBlock(data, result, state); - }, [&](const MTPDpageBlockKicker &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 5, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading1 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 1, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading2 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 2, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading3 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 3, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading4 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 4, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading5 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 5, - data.vtext(), - state); - }, [&](const MTPDpageBlockHeading6 &data) { - return AppendNativeIvFlowBlock( - result, - PreparedBlockKind::Heading, - 6, - data.vtext(), - state); - }, [&](const MTPDpageBlockMath &data) { - return PrepareNativeIvMathBlock(data, result, state); - }, [&](const MTPDpageBlockTable &data) { - return PrepareNativeIvTableBlock(data, result, state); - }, [&](const MTPDpageBlockOrderedList &data) { - auto prepared = PreparedBlock(); - prepared.kind = PreparedBlockKind::List; - prepared.listKind = ListKind::Ordered; - prepared.listDelimiter = ListDelimiter::Period; - prepared.startNumber = data.vstart().value_or(1); - return PrepareNativeIvOrderedList(data.vitems().v, &prepared, state) - ? (result->push_back(std::move(prepared)), true) - : false; - }, [&](const MTPDpageBlockDetails &data) { - return PrepareNativeIvDetailsBlock(data, result, state); - }, [&](const MTPDpageBlockRelatedArticles &data) { - return PrepareNativeIvRelatedArticlesBlock(data, result, state); - }, [&](const MTPDpageBlockMap &data) { - return PrepareNativeIvMapBlock(data, result, state); - }, [&](const MTPDinputPageBlockMap &) { - return PrepareNativeIvPlainPlaceholderBlock( - u"Unsupported Content"_q, - result); - }); -} - -} // namespace - -bool PrepareNativeIvBlocks( - const QVector &blocks, - std::vector *result, - NativeIvPrepareState *state) { - for (const auto &block : blocks) { - if (!PrepareNativeIvBlock(block, result, state)) { - if (state->result.failure.failed()) { - return false; - } - (void)PrepareNativeIvPlainPlaceholderBlock( - u"Unsupported Block"_q, - result); - } - } - return !state->result.failure.failed(); -} - -namespace { - [[nodiscard]] bool PrepareNativeIvRichPlaceholderBlock( QString label, const RichPage::RichText &caption, @@ -1362,14 +387,14 @@ namespace { auto request = EmbedRequest{ .width = block.width, .height = block.height, - .fullWidth = block.fullWidth || !block.width, - .fixedHeight = (block.height > 0), + .fullWidth = block.fullWidth, + .fixedHeight = block.fixedHeight, .allowScrolling = block.allowScrolling, }; if (!block.url.isEmpty()) { request.url = block.url; } else if (!block.html.isEmpty()) { - request.html = block.html.toUtf8(); + request.html = block.html; } else { return std::nullopt; } @@ -1698,6 +723,7 @@ namespace { block.collapsed = !data.open; block.text = std::move(summary.text); block.links = std::move(summary.links); + block.anchorIds = std::move(summary.anchorIds); return PrepareNativeIvBlocks( RichPage{ .blocks = data.blocks, @@ -1906,6 +932,7 @@ namespace { code.anchorId = std::move(anchorId); code.codeLanguage = block.language; code.text.text = StripOneTrailingNewline(prepared.text.text); + code.anchorIds = std::move(prepared.anchorIds); result->push_back(std::move(code)); return true; } diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.h b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.h index 11f66604ea..5d6467ecc6 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.h +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_blocks.h @@ -9,14 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "iv/markdown/iv_markdown_prepare_native_richtext.h" -#include - namespace Iv::Markdown { -[[nodiscard]] bool PrepareNativeIvBlocks( - const QVector &blocks, - std::vector *result, - NativeIvPrepareState *state); [[nodiscard]] bool PrepareNativeIvBlocks( const Iv::RichPage &page, std::vector *result, diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.cpp b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.cpp index 1972072cba..ad43f6392f 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.cpp +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.cpp @@ -14,17 +14,12 @@ struct GeoPointLocation; #include "iv/markdown/iv_markdown_prepare_links.h" #include "iv/markdown/iv_markdown_prepare_serialize.h" #include "ui/basic_click_handlers.h" -#include "ui/text/text_utilities.h" #include "history/history_location_manager.h" #include #include #include -namespace Data { -[[nodiscard]] QString SerializeCustomEmojiId(uint64 id); -} // namespace Data - namespace Iv::Markdown { namespace { @@ -38,104 +33,6 @@ namespace { return { .value = GeneratePreparedBlockIdValue(state) }; } -[[nodiscard]] PreparedPlaceholderBlockId GeneratePreparedPlaceholderBlockId( - NativeIvPrepareState *state) { - return { .value = GeneratePreparedBlockIdValue(state) }; -} - -[[nodiscard]] const NativeIvPhotoInfo *FindNativeIvPhoto( - uint64 photoId, - const NativeIvPrepareState &state) { - for (const auto &photo : state.photos) { - if (photo.id == photoId) { - return &photo; - } - } - return nullptr; -} - -[[nodiscard]] const NativeIvDocumentInfo *FindNativeIvDocument( - uint64 documentId, - const NativeIvPrepareState &state) { - for (const auto &document : state.documents) { - if (document.id == documentId) { - return &document; - } - } - return nullptr; -} - -void MergeNativeIvDocumentInfo( - NativeIvDocumentInfo *existing, - NativeIvDocumentInfo info) { - if (!existing || (existing->id != info.id)) { - return; - } - if (existing->width <= 0 && info.width > 0) { - existing->width = info.width; - } - if (existing->height <= 0 && info.height > 0) { - existing->height = info.height; - } - if (existing->fileName.isEmpty() && !info.fileName.isEmpty()) { - existing->fileName = std::move(info.fileName); - } - if (existing->title.isEmpty() && !info.title.isEmpty()) { - existing->title = std::move(info.title); - } - if (existing->performer.isEmpty() && !info.performer.isEmpty()) { - existing->performer = std::move(info.performer); - } - if (existing->duration <= 0 && info.duration > 0) { - existing->duration = info.duration; - } - if (!existing->isVideoFile && info.isVideoFile) { - existing->isVideoFile = true; - } - if (!existing->isAnimation && info.isAnimation) { - existing->isAnimation = true; - } -} - -[[nodiscard]] bool IsNativeIvVideoDocument( - const NativeIvDocumentInfo &info) { - return info.isVideoFile || info.isAnimation; -} - -[[nodiscard]] bool PrepareNativeIvGroupedMediaItem( - const MTPPageBlock &item, - PreparedGroupedMediaItemData *result, - const NativeIvPrepareState &state) { - return item.match([&](const MTPDpageBlockPhoto &data) { - const auto info = FindNativeIvPhoto(uint64(data.vphoto_id().v), state); - if (!info || info->width <= 0 || info->height <= 0) { - return false; - } - result->media.kind = PreparedMediaItemKind::Photo; - result->media.id = info->id; - result->media.width = info->width; - result->media.height = info->height; - result->media.spoiler = data.is_spoiler(); - return true; - }, [&](const MTPDpageBlockVideo &data) { - const auto info = FindNativeIvDocument(uint64(data.vvideo_id().v), state); - if (!info - || !IsNativeIvVideoDocument(*info) - || info->width <= 0 - || info->height <= 0) { - return false; - } - result->media.kind = PreparedMediaItemKind::Document; - result->media.id = info->id; - result->media.width = info->width; - result->media.height = info->height; - result->media.spoiler = data.is_spoiler(); - return true; - }, [](const auto &) { - return false; - }); -} - [[nodiscard]] uint64 CanonicalPhotoId(const Iv::RichPage::Block &data) { return data.photoId; } @@ -268,15 +165,6 @@ void SortPreparedIvRichText(PreparedIvRichText *text) { return true; } -[[nodiscard]] bool AppendNativeIvRichText( - const MTPRichText &text, - TextWithEntities *result, - std::vector *links, - QString *blockAnchorId, - std::vector *blockAnchorIds, - NativeIvPrepareState *state, - NativeIvRichTextContext context); - void AddNativeIvBlockAnchor( QString *blockAnchorId, std::vector *blockAnchorIds, @@ -297,19 +185,6 @@ void AddNativeIvBlockAnchor( } } -[[nodiscard]] bool AddNativeIvEntity( - TextWithEntities *text, - int from, - EntityType type, - const QString &data = QString()) { - const auto length = text->text.size() - from; - if (length <= 0) { - return true; - } - text->entities.push_back(EntityInText(type, from, length, data)); - return true; -} - void RememberCanonicalInlineFormula( const EntityInText &entity, NativeIvPrepareState *state, @@ -405,506 +280,6 @@ void AppendCanonicalNativeIvRichText( return context; } -[[nodiscard]] bool AppendNativeIvEntityWrapper( - const MTPRichText &text, - TextWithEntities *result, - std::vector *links, - QString *blockAnchorId, - std::vector *blockAnchorIds, - NativeIvPrepareState *state, - NativeIvRichTextContext context, - EntityType type, - const QString &data = QString()) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - text, - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, type, data); -} - -[[nodiscard]] bool AppendNativeIvInlineFormula( - const QString &source, - TextWithEntities *result, - NativeIvPrepareState *state, - NativeIvRichTextContext context) { - const auto entityData = SerializeInlineTextObjectEntity({ - .kind = InlineTextObjectKind::Formula, - .data = InlineTextObjectFormulaData{ - .copySource = InlineFormulaCopySource(source), - .trimmedTex = source.trimmed(), - }, - }); - if (entityData.isEmpty()) { - result->append(source); - return true; - } - const auto from = result->text.size(); - result->append(QChar::ObjectReplacementCharacter); - result->entities.push_back(EntityInText( - EntityType::CustomEmoji, - from, - 1, - entityData)); - (void)state->rememberFormula( - MathKind::Inline, - source, - context.textSize, - context.renderWidthCap, - context.renderHeightCap); - return true; -} - -[[nodiscard]] bool AppendNativeIvRichText( - const MTPRichText &text, - TextWithEntities *result, - std::vector *links, - QString *blockAnchorId, - std::vector *blockAnchorIds, - NativeIvPrepareState *state, - NativeIvRichTextContext context) { - if (state->blocked()) { - return false; - } - return text.match([&](const MTPDtextEmpty &) { - return true; - }, [&](const MTPDtextPlain &data) { - result->append(qs(data.vtext())); - return true; - }, [&](const MTPDtextConcat &data) { - for (const auto &part : data.vtexts().v) { - if (!AppendNativeIvRichText( - part, - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - } - return true; - }, [&](const MTPDtextImage &data) { - const auto replacementText = u"[image]"_q; - if (!data.vdocument_id().v || data.vw().v <= 0 || data.vh().v <= 0) { - result->append(replacementText); - return true; - } - const auto entityData = SerializeInlineTextObjectEntity({ - .kind = InlineTextObjectKind::IvImage, - .data = InlineTextObjectIvImageData{ - .documentId = uint64(data.vdocument_id().v), - .width = data.vw().v, - .height = data.vh().v, - .replacementText = replacementText, - }, - }); - if (entityData.isEmpty()) { - result->append(replacementText); - return true; - } - const auto from = result->text.size(); - result->append(QChar::ObjectReplacementCharacter); - result->entities.push_back(EntityInText( - EntityType::CustomEmoji, - from, - 1, - entityData)); - return true; - }, [&](const MTPDtextMath &data) { - return AppendNativeIvInlineFormula( - qs(data.vsource()), - result, - state, - context); - }, [&](const MTPDtextCustomEmoji &data) { - result->append(Ui::Text::SingleCustomEmoji( - Data::SerializeCustomEmojiId(uint64(data.vdocument_id().v)), - qs(data.valt()))); - return true; - }, [&](const MTPDtextBold &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Bold); - }, [&](const MTPDtextItalic &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Italic); - }, [&](const MTPDtextUnderline &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Underline); - }, [&](const MTPDtextStrike &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::StrikeOut); - }, [&](const MTPDtextFixed &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Code); - }, [&](const MTPDtextUrl &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - if (result->text.size() == from) { - result->append(qs(data.vurl())); - } - const auto webpageId = uint64(data.vwebpage_id().v); - return AddNativeIvPreparedLink( - result, - links, - from, - result->text.size() - from, - qs(data.vurl()), - webpageId); - }, [&](const MTPDtextEmail &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - if (result->text.size() == from) { - result->append(qs(data.vemail())); - } - return AddNativeIvPreparedLink( - result, - links, - from, - result->text.size() - from, - u"mailto:"_q + qs(data.vemail())); - }, [&](const MTPDtextSubscript &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Subscript); - }, [&](const MTPDtextSuperscript &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Superscript); - }, [&](const MTPDtextMarked &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - return AddNativeIvEntity(result, from, EntityType::Marked); - }, [&](const MTPDtextSpoiler &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Spoiler); - }, [&](const MTPDtextMention &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Mention); - }, [&](const MTPDtextHashtag &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Hashtag); - }, [&](const MTPDtextBotCommand &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::BotCommand); - }, [&](const MTPDtextCashtag &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Cashtag); - }, [&](const MTPDtextAutoUrl &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Url); - }, [&](const MTPDtextAutoEmail &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Email); - }, [&](const MTPDtextAutoPhone &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::Phone); - }, [&](const MTPDtextBankCard &data) { - return AppendNativeIvEntityWrapper( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context, - EntityType::BankCard); - }, [&](const MTPDtextMentionName &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - const auto entityData = state->result.mediaRuntime - ? state->result.mediaRuntime->mentionNameEntityData( - uint64(data.vuser_id().v)) - : QString(); - return entityData.isEmpty() - ? true - : AddNativeIvEntity( - result, - from, - EntityType::MentionName, - entityData); - }, [&](const MTPDtextDate &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - auto flags = FormattedDateFlags(); - if (data.is_relative()) { - flags |= FormattedDateFlag::Relative; - } - if (data.is_short_time()) { - flags |= FormattedDateFlag::ShortTime; - } - if (data.is_long_time()) { - flags |= FormattedDateFlag::LongTime; - } - if (data.is_short_date()) { - flags |= FormattedDateFlag::ShortDate; - } - if (data.is_long_date()) { - flags |= FormattedDateFlag::LongDate; - } - if (data.is_day_of_week()) { - flags |= FormattedDateFlag::DayOfWeek; - } - return AddNativeIvEntity( - result, - from, - EntityType::FormattedDate, - SerializeFormattedDateData(data.vdate().v, flags)); - }, [&](const MTPDtextPhone &data) { - const auto from = result->text.size(); - if (!AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context)) { - return false; - } - if (result->text.size() == from) { - result->append(qs(data.vphone())); - } - return AddNativeIvPreparedLink( - result, - links, - from, - result->text.size() - from, - u"tel:"_q + qs(data.vphone())); - }, [&](const MTPDtextAnchor &data) { - AddNativeIvBlockAnchor( - blockAnchorId, - blockAnchorIds, - NormalizeFragmentId(qs(data.vname()))); - return AppendNativeIvRichText( - data.vtext(), - result, - links, - blockAnchorId, - blockAnchorIds, - state, - context); - }); -} - -[[nodiscard]] bool PrepareNativeIvCaption( - const MTPPageCaption &caption, - PreparedIvRichText *result, - QString *blockAnchorId, - NativeIvPrepareState *state) { - const auto context = ResolveNativeIvRichTextContext(state, {}); - if (!AppendNativeIvRichText( - caption.data().vtext(), - &result->text, - &result->links, - blockAnchorId, - &result->anchorIds, - state, - context)) { - return false; - } - auto credit = PreparedIvRichText(); - if (!PrepareNativeIvRichText( - caption.data().vcredit(), - &credit, - blockAnchorId, - state)) { - return false; - } - if (!credit.text.text.isEmpty()) { - if (!result->text.text.isEmpty()) { - result->text.append(QChar('\n')); - } - if (!AppendNativeIvRichText( - caption.data().vcredit(), - &result->text, - &result->links, - blockAnchorId, - &result->anchorIds, - state, - context)) { - return false; - } - } - return true; -} - [[nodiscard]] bool PrepareNativeIvCaption( const Iv::RichPage::RichText &caption, PreparedIvRichText *result, @@ -919,133 +294,6 @@ void AppendCanonicalNativeIvRichText( } // namespace -void RememberNativeIvPhoto( - NativeIvPrepareState *state, - const MTPPhoto &photo) { - auto info = NativeIvPhotoInfo{ - .id = photo.match([](const auto &data) { - return data.vid().v; - }), - }; - photo.match([](const MTPDphotoEmpty &) { - }, [&](const MTPDphoto &data) { - auto width = 0; - auto height = 0; - const auto assign = [&](int w, int h) { - if (w > 0 && h > 0) { - width = w; - height = h; - } - }; - for (const auto &size : data.vsizes().v) { - size.match([&](const MTPDphotoSizeEmpty &) { - }, [&](const MTPDphotoSize &data) { - if (data.vtype().v == u"y"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"x"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"w"_q) { - assign(data.vw().v, data.vh().v); - } - }, [&](const MTPDphotoCachedSize &data) { - if (data.vtype().v == u"y"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"x"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"w"_q) { - assign(data.vw().v, data.vh().v); - } - }, [&](const MTPDphotoStrippedSize &) { - }, [&](const MTPDphotoSizeProgressive &data) { - if (data.vtype().v == u"y"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"x"_q) { - assign(data.vw().v, data.vh().v); - } else if (!width && data.vtype().v == u"w"_q) { - assign(data.vw().v, data.vh().v); - } - }, [&](const MTPDphotoPathSize &) { - }); - } - info.width = width; - info.height = height; - }); - if (!info.id) { - return; - } - for (auto &existing : state->photos) { - if (existing.id == info.id) { - existing = info; - return; - } - } - state->photos.push_back(info); -} - -void RememberNativeIvDocument( - NativeIvPrepareState *state, - const MTPDocument &document) { - auto info = NativeIvDocumentInfo{ - .id = document.match([](const auto &data) { - return data.vid().v; - }), - }; - document.match([](const MTPDdocumentEmpty &) { - }, [&](const MTPDdocument &data) { - const auto assignDimensions = [&](int width, int height, bool force) { - if (width <= 0 || height <= 0) { - return; - } - if (force || info.width <= 0 || info.height <= 0) { - info.width = width; - info.height = height; - } - }; - for (const auto &attribute : data.vattributes().v) { - attribute.match([&](const MTPDdocumentAttributeAudio &data) { - info.duration = data.vduration().v; - info.title = qs(data.vtitle().value_or_empty()); - info.performer = qs(data.vperformer().value_or_empty()); - }, [&](const MTPDdocumentAttributeFilename &data) { - info.fileName = qs(data.vfile_name()); - }, [&](const MTPDdocumentAttributeImageSize &data) { - assignDimensions(data.vw().v, data.vh().v, false); - }, [&](const MTPDdocumentAttributeAnimated &) { - info.isAnimation = true; - }, [&](const MTPDdocumentAttributeVideo &data) { - info.isVideoFile = true; - assignDimensions(data.vw().v, data.vh().v, true); - }, [&](const auto &) {}); - } - }); - if (!info.id) { - return; - } - if (const auto existing = FindNativeIvDocument(info.id, *state)) { - const auto index = existing - state->documents.data(); - MergeNativeIvDocumentInfo(&state->documents[index], std::move(info)); - return; - } - state->documents.push_back(std::move(info)); -} - -bool PrepareNativeIvRichText( - const MTPRichText &text, - PreparedIvRichText *result, - QString *blockAnchorId, - NativeIvPrepareState *state, - NativeIvRichTextContext context) { - context = ResolveNativeIvRichTextContext(state, context); - return AppendNativeIvRichText( - text, - &result->text, - &result->links, - blockAnchorId, - &result->anchorIds, - state, - context); -} - bool PrepareNativeIvRichText( const Iv::RichPage::RichText &text, PreparedIvRichText *result, @@ -1054,6 +302,9 @@ bool PrepareNativeIvRichText( NativeIvRichTextContext context) { context = ResolveNativeIvRichTextContext(state, context); AddNativeIvBlockAnchor(blockAnchorId, &result->anchorIds, text.anchorId); + for (const auto &anchorId : text.anchorIds) { + AddNativeIvBlockAnchor(blockAnchorId, &result->anchorIds, anchorId); + } AppendCanonicalNativeIvRichText(text, result, state, context); return true; } @@ -1093,222 +344,6 @@ bool PrepareNativeIvPlainPlaceholderBlock( return true; } -bool PrepareNativeIvPhotoBlock( - const MTPDpageBlockPhoto &data, - std::vector *result, - NativeIvPrepareState *state) { - const auto info = FindNativeIvPhoto(uint64(data.vphoto_id().v), *state); - if (!info || info->width <= 0 || info->height <= 0) { - return true; - } - auto caption = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvCaption(data.vcaption(), &caption, &anchorId, state)) { - return false; - } - SortPreparedIvRichText(&caption); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Photo; - block.text = std::move(caption.text); - block.links = std::move(caption.links); - block.anchorId = std::move(anchorId); - block.anchorIds = std::move(caption.anchorIds); - block.supplementary = true; - block.photo.id = GeneratePreparedMediaBlockId(state); - block.photo.photoId = info->id; - block.photo.width = info->width; - block.photo.height = info->height; - block.photo.urlOverride = data.vurl() ? qs(*data.vurl()) : QString(); - block.photo.spoiler = data.is_spoiler(); - block.photo.viewerOpen = true; - result->push_back(std::move(block)); - return true; -} - -bool PrepareNativeIvVideoBlock( - const MTPDpageBlockVideo &data, - std::vector *result, - NativeIvPrepareState *state) { - const auto info = FindNativeIvDocument(uint64(data.vvideo_id().v), *state); - if (!info - || !IsNativeIvVideoDocument(*info) - || info->width <= 0 - || info->height <= 0) { - return true; - } - auto caption = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvCaption(data.vcaption(), &caption, &anchorId, state)) { - return false; - } - SortPreparedIvRichText(&caption); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Video; - block.text = std::move(caption.text); - block.links = std::move(caption.links); - block.anchorId = std::move(anchorId); - block.anchorIds = std::move(caption.anchorIds); - block.supplementary = true; - block.video.id = GeneratePreparedMediaBlockId(state); - block.video.media.kind = PreparedMediaItemKind::Document; - block.video.media.id = info->id; - block.video.media.width = info->width; - block.video.media.height = info->height; - block.video.media.spoiler = data.is_spoiler(); - result->push_back(std::move(block)); - return true; -} - -bool PrepareNativeIvAudioBlock( - const MTPDpageBlockAudio &data, - std::vector *result, - NativeIvPrepareState *state) { - const auto info = FindNativeIvDocument(uint64(data.vaudio_id().v), *state); - if (!info) { - return true; - } - auto caption = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvCaption(data.vcaption(), &caption, &anchorId, state)) { - return false; - } - SortPreparedIvRichText(&caption); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Audio; - block.text = std::move(caption.text); - block.links = std::move(caption.links); - block.anchorId = std::move(anchorId); - block.anchorIds = std::move(caption.anchorIds); - block.supplementary = true; - block.audio.id = GeneratePreparedMediaBlockId(state); - block.audio.documentId = info->id; - block.audio.title = info->title; - block.audio.performer = info->performer; - block.audio.fileName = info->fileName; - block.audio.duration = info->duration; - result->push_back(std::move(block)); - return true; -} - -bool PrepareNativeIvMapBlock( - const MTPDpageBlockMap &data, - std::vector *result, - NativeIvPrepareState *state) { - auto prepared = PreparedMapBlockData(); - const auto supported = data.vgeo().match([&](const MTPDgeoPoint &geo) { - if (!geo.vaccess_hash().v || data.vw().v <= 0 || data.vh().v <= 0) { - return false; - } - prepared.latitude = geo.vlat().v; - prepared.longitude = geo.vlong().v; - prepared.accessHash = geo.vaccess_hash().v; - prepared.width = data.vw().v; - prepared.height = data.vh().v; - prepared.zoom = data.vzoom().v; - prepared.url = LocationClickHandler::Url(Data::LocationPoint(geo)); - return true; - }, [](const auto &) { - return false; - }); - if (!supported) { - return true; - } - auto caption = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvCaption(data.vcaption(), &caption, &anchorId, state)) { - return false; - } - SortPreparedIvRichText(&caption); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Map; - block.text = std::move(caption.text); - block.links = std::move(caption.links); - block.anchorId = std::move(anchorId); - block.anchorIds = std::move(caption.anchorIds); - block.supplementary = true; - prepared.id = GeneratePreparedMediaBlockId(state); - block.map = std::move(prepared); - result->push_back(std::move(block)); - return true; -} - -bool PrepareNativeIvChannelBlock( - const MTPDpageBlockChannel &data, - std::vector *result, - NativeIvPrepareState *state) { - auto prepared = PreparedChannelBlockData(); - const auto supported = data.vchannel().match([&](const MTPDchannel &channel) { - prepared.channelId = channel.vid().v; - prepared.title = qs(channel.vtitle()); - prepared.username = qs(channel.vusername().value_or_empty()); - return true; - }, [&](const MTPDchannelForbidden &channel) { - prepared.channelId = channel.vid().v; - prepared.title = qs(channel.vtitle()); - return true; - }, [&](const MTPDchat &channel) { - prepared.channelId = channel.vid().v; - prepared.title = qs(channel.vtitle()); - return true; - }, [&](const MTPDchatForbidden &channel) { - prepared.channelId = channel.vid().v; - prepared.title = qs(channel.vtitle()); - return true; - }, [](const auto &) { - return false; - }); - if (!supported || !prepared.channelId || prepared.title.isEmpty()) { - return true; - } - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Channel; - prepared.id = GeneratePreparedMediaBlockId(state); - block.channel = std::move(prepared); - result->push_back(std::move(block)); - return true; -} - -bool PrepareNativeIvGroupedMediaBlock( - const QVector &items, - const MTPPageCaption &caption, - PreparedGroupedMediaIntent intent, - QString placeholderLabel, - std::vector *result, - NativeIvPrepareState *state) { - Q_UNUSED(placeholderLabel); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::GroupedMedia; - block.groupedMedia.id = GeneratePreparedMediaBlockId(state); - block.groupedMedia.intent = intent; - block.groupedMedia.items.reserve(items.size()); - for (const auto &item : items) { - auto prepared = PreparedGroupedMediaItemData(); - prepared.id = GeneratePreparedMediaBlockId(state); - if (!PrepareNativeIvGroupedMediaItem(item, &prepared, *state)) { - continue; - } - block.groupedMedia.items.push_back(std::move(prepared)); - } - if (block.groupedMedia.items.empty()) { - return true; - } - auto preparedCaption = PreparedIvRichText(); - if (!PrepareNativeIvCaption( - caption, - &preparedCaption, - &block.anchorId, - state)) { - return false; - } - SortPreparedIvRichText(&preparedCaption); - block.text = std::move(preparedCaption.text); - block.links = std::move(preparedCaption.links); - block.anchorIds = std::move(preparedCaption.anchorIds); - block.supplementary = true; - result->push_back(std::move(block)); - return true; -} - bool PrepareNativeIvPhotoBlock( const Iv::RichPage::Block &data, std::vector *result, @@ -1500,49 +535,4 @@ bool PrepareNativeIvGroupedMediaBlock( return true; } -namespace { - -[[nodiscard]] QString NativeIvPlaceholderCopyText( - const QString &label, - const TextWithEntities &caption) { - return caption.text.isEmpty() - ? label - : (label + u"\n"_q + caption.text); -} - -} // namespace - -bool PrepareNativeIvPlaceholderBlock( - QString label, - const MTPPageCaption &caption, - std::vector *result, - NativeIvPrepareState *state, - std::optional embed) { - auto prepared = PreparedIvRichText(); - auto anchorId = QString(); - if (!PrepareNativeIvCaption(caption, &prepared, &anchorId, state)) { - return state->result.failure.failed() - ? false - : PrepareNativeIvPlainPlaceholderBlock(std::move(label), result); - } - SortPreparedIvRichText(&prepared); - auto block = PreparedBlock(); - block.kind = PreparedBlockKind::Placeholder; - block.text = std::move(prepared.text); - block.links = std::move(prepared.links); - block.anchorId = std::move(anchorId); - block.anchorIds = std::move(prepared.anchorIds); - block.supplementary = true; - block.placeholder.label = std::move(label); - block.placeholder.embed = std::move(embed); - if (block.placeholder.embed && *block.placeholder.embed) { - block.placeholder.id = GeneratePreparedPlaceholderBlockId(state); - } - block.placeholder.copyText = NativeIvPlaceholderCopyText( - block.placeholder.label, - block.text); - result->push_back(std::move(block)); - return true; -} - } // namespace Iv::Markdown diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.h b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.h index 9f4d310de2..b30a442be1 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.h +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_native_richtext.h @@ -26,48 +26,9 @@ struct NativeIvRichTextContext { int renderHeightCap = 0; }; -void RememberNativeIvPhoto( - NativeIvPrepareState *state, - const MTPPhoto &photo); -void RememberNativeIvDocument( - NativeIvPrepareState *state, - const MTPDocument &document); [[nodiscard]] bool PrepareNativeIvPlainPlaceholderBlock( QString label, std::vector *result); -[[nodiscard]] bool PrepareNativeIvPlaceholderBlock( - QString label, - const MTPPageCaption &caption, - std::vector *result, - NativeIvPrepareState *state, - std::optional embed = std::nullopt); -[[nodiscard]] bool PrepareNativeIvPhotoBlock( - const MTPDpageBlockPhoto &data, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvVideoBlock( - const MTPDpageBlockVideo &data, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvAudioBlock( - const MTPDpageBlockAudio &data, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvMapBlock( - const MTPDpageBlockMap &data, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvChannelBlock( - const MTPDpageBlockChannel &data, - std::vector *result, - NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvGroupedMediaBlock( - const QVector &items, - const MTPPageCaption &caption, - PreparedGroupedMediaIntent intent, - QString placeholderLabel, - std::vector *result, - NativeIvPrepareState *state); [[nodiscard]] bool PrepareNativeIvPhotoBlock( const Iv::RichPage::Block &data, std::vector *result, @@ -92,12 +53,6 @@ void RememberNativeIvDocument( const Iv::RichPage::Block &data, std::vector *result, NativeIvPrepareState *state); -[[nodiscard]] bool PrepareNativeIvRichText( - const MTPRichText &text, - PreparedIvRichText *result, - QString *blockAnchorId, - NativeIvPrepareState *state, - NativeIvRichTextContext context = {}); [[nodiscard]] bool PrepareNativeIvRichText( const Iv::RichPage::RichText &text, PreparedIvRichText *result, diff --git a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_state.h b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_state.h index f340e279ae..c15f3f8e00 100644 --- a/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_state.h +++ b/Telegram/SourceFiles/iv/markdown/iv_markdown_prepare_state.h @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include -#include #include namespace Iv::Markdown { @@ -51,29 +50,9 @@ struct PrepareState { [[nodiscard]] QString formulaSourceText(int index) const; }; -struct NativeIvPhotoInfo { - uint64 id = 0; - int width = 0; - int height = 0; -}; - -struct NativeIvDocumentInfo { - uint64 id = 0; - int width = 0; - int height = 0; - QString fileName; - QString title; - QString performer; - int duration = 0; - bool isVideoFile = false; - bool isAnimation = false; -}; - struct NativeIvPrepareState { MarkdownArticleContent result; MarkdownPrepareDimensions dimensions; - std::vector photos; - std::vector documents; int nextGeneratedId = 0; int nextFormulaIndex = 0;