optimized enumeration of userpics

This commit is contained in:
John Preston 2016-03-23 14:47:32 +03:00
parent e45de88bd6
commit 02ca81ac64
6 changed files with 76 additions and 34 deletions

View File

@ -293,8 +293,8 @@ History::History(const PeerId &peerId) : width(0), height(0)
if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) { if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) {
outboxReadBefore = INT_MAX; outboxReadBefore = INT_MAX;
} }
for (int32 i = 0; i < OverviewCount; ++i) { for (auto &countData : overviewCountData) {
overviewCountData[i] = -1; // not loaded yet countData = -1; // not loaded yet
} }
} }
@ -309,6 +309,15 @@ void History::clearLastKeyboard() {
lastKeyboardFrom = 0; lastKeyboardFrom = 0;
} }
bool History::canHaveFromPhotos() const {
if (peer->isUser() && !Adaptive::Wide()) {
return false;
} else if (isChannel() && asChannelHistory()->onlyImportant()) {
return false;
}
return true;
}
void History::setHasPendingResizedItems() { void History::setHasPendingResizedItems() {
_flags |= Flag::f_has_pending_resized_items; _flags |= Flag::f_has_pending_resized_items;
Global::RefHandleHistoryUpdate().call(); Global::RefHandleHistoryUpdate().call();
@ -6030,8 +6039,7 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
} }
HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) :
HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) {
, _text(st::msgMinWidth) {
PeerId authorOriginalId = 0, fromOriginalId = 0; PeerId authorOriginalId = 0, fromOriginalId = 0;
MsgId originalId = 0; MsgId originalId = 0;
if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) {
@ -7540,9 +7548,7 @@ bool HistoryServiceMessage::updatePinnedText(const QString *pfrom, QString *ptex
} }
HistoryServiceMessage::HistoryServiceMessage(History *history, const MTPDmessageService &msg) : HistoryServiceMessage::HistoryServiceMessage(History *history, const MTPDmessageService &msg) :
HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) {
, _text(st::msgMinWidth)
, _media(0) {
if (msg.has_reply_to_msg_id()) { if (msg.has_reply_to_msg_id()) {
UpdateInterfaces(HistoryServicePinned::Bit()); UpdateInterfaces(HistoryServicePinned::Bit());
MsgId pinnedMsgId = Get<HistoryServicePinned>()->msgId = msg.vreply_to_msg_id.v; MsgId pinnedMsgId = Get<HistoryServicePinned>()->msgId = msg.vreply_to_msg_id.v;

View File

@ -346,6 +346,10 @@ public:
bool updateTyping(uint64 ms, bool force = false); bool updateTyping(uint64 ms, bool force = false);
void clearLastKeyboard(); void clearLastKeyboard();
// optimization for userpics displayed on the left
// if this returns false there is no need to even try to handle them
bool canHaveFromPhotos() const;
typedef QList<HistoryBlock*> Blocks; typedef QList<HistoryBlock*> Blocks;
Blocks blocks; Blocks blocks;
@ -2717,8 +2721,8 @@ protected:
bool updatePinned(bool force = false); bool updatePinned(bool force = false);
bool updatePinnedText(const QString *pfrom = nullptr, QString *ptext = nullptr); bool updatePinnedText(const QString *pfrom = nullptr, QString *ptext = nullptr);
Text _text; Text _text = { int(st::msgMinWidth) };
HistoryMedia *_media; HistoryMedia *_media = nullptr;
int32 _textWidth, _textHeight; int32 _textWidth, _textHeight;
}; };

View File

@ -94,32 +94,53 @@ void HistoryInner::repaintItem(const HistoryItem *item) {
} }
} }
namespace {
// helper binary search for an item in a list that is not completely below the given bottom of the visible area
// is applied once for blocks list in a history and once for items list in the found block
template <typename T>
int binarySearchBlocksOrItems(const T &list, int bottom) {
int start = 0, end = list.size();
while (end - start > 1) {
int middle = (start + end) / 2;
if (list.at(middle)->y >= bottom) {
end = middle;
} else {
start = middle;
}
}
return start;
}
}
template <typename Method> template <typename Method>
void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method method) { void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method method) {
// no displayed messages in this history // no displayed messages in this history
if (htop < 0) return; if (htop < 0 || h->isEmpty() || !h->canHaveFromPhotos() || _visibleAreaBottom <= htop) {
return;
}
// find and remember the bottom of an attached messages pack // find and remember the bottom of an attached messages pack
// -1 means we didn't find an attached to previous message yet // -1 means we didn't find an attached to previous message yet
int lowestAttachedItemBottom = -1; int lowestAttachedItemBottom = -1;
int blockIndex = h->blocks.size(); // binary search for blockIndex of the first block that is not completely below the visible area
int itemIndex = 0; int blockIndex = binarySearchBlocksOrItems(h->blocks, _visibleAreaBottom - htop);
while (blockIndex > 0) {
HistoryBlock *block = h->blocks.at(--blockIndex);
itemIndex = block->items.size();
int blocktop = htop + block->y; // binary search for itemIndex of the first item that is not completely below the visible area
while (itemIndex > 0) { HistoryBlock *block = h->blocks.at(blockIndex);
HistoryItem *item = block->items.at(--itemIndex); int blocktop = htop + block->y;
int itemIndex = binarySearchBlocksOrItems(block->items, _visibleAreaBottom - blocktop);
while (true) {
while (itemIndex >= 0) {
HistoryItem *item = block->items.at(itemIndex--);
int itemtop = blocktop + item->y; int itemtop = blocktop + item->y;
int itembottom = itemtop + item->height(); int itembottom = itemtop + item->height();
// skip items that are below the visible area // binary search should've skipped all the items that are below the visible area
if (itemtop >= _visibleAreaBottom) { t_assert(itemtop < _visibleAreaBottom);
continue;
}
// skip all service messages
if (HistoryMessage *message = item->toHistoryMessage()) { if (HistoryMessage *message = item->toHistoryMessage()) {
if (lowestAttachedItemBottom < 0 && message->isAttachedToPrevious()) { if (lowestAttachedItemBottom < 0 && message->isAttachedToPrevious()) {
lowestAttachedItemBottom = itembottom - message->marginBottom(); lowestAttachedItemBottom = itembottom - message->marginBottom();
@ -131,15 +152,21 @@ void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method metho
if (lowestAttachedItemBottom < 0) { if (lowestAttachedItemBottom < 0) {
lowestAttachedItemBottom = itembottom - message->marginBottom(); lowestAttachedItemBottom = itembottom - message->marginBottom();
} }
int userpicTop = qMin(qMax(itemtop + message->marginTop(), _visibleAreaTop + st::msgMargin.left()), lowestAttachedItemBottom - int(st::msgPhotoSize)); // attach userpic to the top of the visible area with the same margin as it is from the left side
int userpicTop = qMax(itemtop + message->marginTop(), _visibleAreaTop + st::msgMargin.left());
// do not let the userpic go below the attached messages pack bottom line
userpicTop = qMin(userpicTop, lowestAttachedItemBottom - int(st::msgPhotoSize));
// call the template callback function that was passed // call the template callback function that was passed
// and return if it finished everything it needed // and return if it finished everything it needed
if (!method(message, userpicTop)) { if (!method(message, userpicTop)) {
return; return;
} }
}
// forget the found bottom of the pack, search for the next one from scratch // forget the found bottom of the pack, search for the next one from scratch
if (!message->isAttachedToPrevious()) {
lowestAttachedItemBottom = -1; lowestAttachedItemBottom = -1;
} }
} }
@ -154,6 +181,14 @@ void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method metho
if (blocktop <= _visibleAreaTop) { if (blocktop <= _visibleAreaTop) {
return; return;
} }
if (--blockIndex < 0) {
return;
} else {
block = h->blocks.at(blockIndex);
blocktop = htop + block->y;
itemIndex = block->items.size() - 1;
}
} }
} }

View File

@ -1066,12 +1066,7 @@ namespace {
} }
} }
LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(OverviewItemInfo::Bit(), parent) LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(OverviewItemInfo::Bit(), parent) {
, _titlew(0)
, _page(0)
, _pixw(0)
, _pixh(0)
, _text(st::msgMinWidth) {
QString text = _parent->originalText(); QString text = _parent->originalText();
EntitiesInText entities = _parent->originalEntities(); EntitiesInText entities = _parent->originalEntities();

View File

@ -440,10 +440,11 @@ private:
TextLinkPtr _photol; TextLinkPtr _photol;
QString _title, _letter; QString _title, _letter;
int32 _titlew; int _titlew = 0;
WebPageData *_page; WebPageData *_page = nullptr;
int32 _pixw, _pixh; int _pixw = 0;
Text _text; int _pixh = 0;
Text _text = { int(st::msgMinWidth) };
struct Link { struct Link {
Link() : width(0) { Link() : width(0) {

View File

@ -89,6 +89,7 @@
<ImageHasSafeExceptionHandlers /> <ImageHasSafeExceptionHandlers />
<IgnoreSpecificDefaultLibraries>LIBCMT</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>LIBCMT</IgnoreSpecificDefaultLibraries>
<ImportLibrary>$(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib</ImportLibrary> <ImportLibrary>$(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib</ImportLibrary>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
<CustomBuildStep> <CustomBuildStep>
</CustomBuildStep> </CustomBuildStep>