summaryrefslogtreecommitdiff
path: root/desktop/source
diff options
context:
space:
mode:
authorAshod Nakashian <ashod.nakashian@collabora.co.uk>2016-12-06 00:42:58 -0500
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-01-16 09:09:33 +0000
commit3db1ce30ab235ad22aed71c22e4f6f52b7b88829 (patch)
treeedd0a7e399dc0fd07f27ef187a4c5ab1e9e06318 /desktop/source
parent2abe0df63c59637ea1b00703458edf71dff8167c (diff)
Lok: improved tile invalidation compression
Handle corner cases better and eliminate invalid rects and out-of-bounds coordinates. Change-Id: Ib9247ae4f0306cf68937cd2678f6386fe7710eec Reviewed-on: https://gerrit.libreoffice.org/31665 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'desktop/source')
-rw-r--r--desktop/source/lib/init.cxx183
1 files changed, 127 insertions, 56 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index e3f517288150..79e284a2e7b8 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -348,7 +348,7 @@ struct RectangleAndPart
int m_nPart;
RectangleAndPart()
- : m_nPart(-1)
+ : m_nPart(INT_MIN) // -1 is reserved to mean "all parts".
{
}
@@ -356,17 +356,23 @@ struct RectangleAndPart
{
std::stringstream ss;
ss << m_aRectangle.toString().getStr();
- if (m_nPart != -1)
+ if (m_nPart >= -1)
ss << ", " << m_nPart;
return ss.str().c_str();
}
- /// Infinite Rectangle is when both dimensions are >= 2e7.
- // ~2 billion twips is INT_MAX, which is full-area.
+ /// Infinite Rectangle is both sides are
+ /// equal or longer than SfxLokHelper::MaxTwips.
bool isInfinite() const
{
- return m_aRectangle.GetWidth() >= 2e7 &&
- m_aRectangle.GetHeight() >= 2e7;
+ return m_aRectangle.GetWidth() >= SfxLokHelper::MaxTwips &&
+ m_aRectangle.GetHeight() >= SfxLokHelper::MaxTwips;
+ }
+
+ /// Empty Rectangle is when it has zero dimensions.
+ bool isEmpty() const
+ {
+ return m_aRectangle.IsEmpty();
}
static RectangleAndPart Create(const std::string& rPayload)
@@ -374,7 +380,7 @@ struct RectangleAndPart
RectangleAndPart aRet;
if (rPayload.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
{
- aRet.m_aRectangle = Rectangle(0, 0, INT_MAX, INT_MAX);
+ aRet.m_aRectangle = Rectangle(0, 0, SfxLokHelper::MaxTwips, SfxLokHelper::MaxTwips);
if (comphelper::LibreOfficeKit::isPartInInvalidation())
aRet.m_nPart = std::stol(rPayload.substr(6));
@@ -382,15 +388,41 @@ struct RectangleAndPart
}
std::istringstream aStream(rPayload);
- long nLeft, nTop, nRight, nBottom;
- long nPart = -1;
+ long nLeft, nTop, nWidth, nHeight;
+ long nPart = INT_MIN;
char nComma;
if (comphelper::LibreOfficeKit::isPartInInvalidation())
- aStream >> nLeft >> nComma >> nTop >> nComma >> nRight >> nComma >> nBottom >> nComma >> nPart;
+ {
+ aStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight >> nComma >> nPart;
+ }
else
- aStream >> nLeft >> nComma >> nTop >> nComma >> nRight >> nComma >> nBottom;
+ {
+ aStream >> nLeft >> nComma >> nTop >> nComma >> nWidth >> nComma >> nHeight;
+ }
+
+ if (nWidth > 0 && nHeight > 0)
+ {
+ // The top-left corner starts at (0, 0).
+ // Anything negative is invalid.
+ if (nLeft < 0)
+ {
+ nWidth += nLeft;
+ nLeft = 0;
+ }
+
+ if (nTop < 0)
+ {
+ nHeight += nTop;
+ nTop = 0;
+ }
+
+ if (nWidth > 0 && nHeight > 0)
+ {
+ aRet.m_aRectangle = Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
+ }
+ }
+ // else leave empty rect.
- aRet.m_aRectangle = Rectangle(nLeft, nTop, nLeft + nRight, nTop + nBottom);
aRet.m_nPart = nPart;
return aRet;
}
@@ -607,6 +639,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
std::string payload(data ? data : "(nil)");
//SAL_WARN("lok", "Queue: " << type << " : " << payload);
+
if (m_bPartTilePainting)
{
// We drop notifications when this is set, except for important ones.
@@ -678,24 +711,6 @@ void CallbackFlushHandler::queue(const int type, const char* data)
break;
}
- // if we have to invalidate all tiles, we can skip any new tile invalidation
- if (type == LOK_CALLBACK_INVALIDATE_TILES)
- {
- const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
- [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_INVALIDATE_TILES); });
-
- if (pos != m_queue.rend())
- {
- RectangleAndPart rcOld = RectangleAndPart::Create(pos->second);
- RectangleAndPart rcNew = RectangleAndPart::Create(payload);
- if (rcOld.isInfinite() && rcOld.m_nPart == rcNew.m_nPart)
- {
- SAL_WARN("lok", "Skipping queue [" << type << "]: [" << payload << "] since all tiles need to be invalidated.");
- return;
- }
- }
- }
-
if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty())
{
const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(),
@@ -778,20 +793,50 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
RectangleAndPart rcNew = RectangleAndPart::Create(payload);
//SAL_WARN("lok", "New: " << rcNew.toString());
+ if (rcNew.isEmpty())
+ {
+ SAL_WARN("lok", "Skipping invalid event [" << type << "]: [" << payload << "].");
+ return;
+ }
+
+ // If we have to invalidate all tiles, we can skip any new tile invalidation.
+ // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
+ const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
+ [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_INVALIDATE_TILES); });
+ if (pos != m_queue.rend())
+ {
+ RectangleAndPart rcOld = RectangleAndPart::Create(pos->second);
+ if (rcOld.isInfinite() && (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart))
+ {
+ SAL_WARN("lok", "Skipping queue [" << type << "]: [" << payload << "] since all tiles need to be invalidated.");
+ return;
+ }
+
+ if (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart)
+ {
+ // If fully overlapping.
+ if (rcOld.m_aRectangle.IsInside(rcNew.m_aRectangle))
+ {
+ SAL_WARN("lok", "Skipping queue [" << type << "]: [" << payload << "] since overlaps existing all-parts.");
+ return;
+ }
+ }
+ }
+
if (rcNew.isInfinite())
{
SAL_WARN("lok", "Have Empty [" << type << "]: [" << payload << "] so removing all with part " << rcNew.m_nPart << ".");
removeAll(
- [type, &rcNew] (const queue_type::value_type& elem) {
- if (elem.first == type)
+ [&rcNew] (const queue_type::value_type& elem) {
+ if (elem.first == LOK_CALLBACK_INVALIDATE_TILES)
{
+ // Remove exiting if new is all-encompasing, or if of the same part.
const RectangleAndPart rcOld = RectangleAndPart::Create(elem.second);
- return (rcOld.m_nPart == rcNew.m_nPart);
- }
- else
- {
- return false;
+ return (rcNew.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart);
}
+
+ // Keep others.
+ return false;
}
);
}
@@ -799,30 +844,55 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
const auto rcOrig = rcNew;
- //SAL_WARN("lok", "Have [" << type << "]: [" << payload << "] so merging overlapping.");
+ SAL_WARN("lok", "Have [" << type << "]: [" << payload << "] so merging overlapping.");
removeAll(
- [type, &rcNew] (const queue_type::value_type& elem) {
- if (elem.first == type)
+ [&rcNew] (const queue_type::value_type& elem) {
+ if (elem.first == LOK_CALLBACK_INVALIDATE_TILES)
{
const RectangleAndPart rcOld = RectangleAndPart::Create(elem.second);
- if (rcOld.m_nPart != rcNew.m_nPart)
+ if (rcNew.m_nPart != -1 && rcOld.m_nPart != -1 && rcOld.m_nPart != rcNew.m_nPart)
+ {
+ SAL_WARN("lok", "Nothing to merge between new: " << rcNew.toString() << ", and old: " << rcOld.toString());
return false;
+ }
- const Rectangle rcOverlap = rcNew.m_aRectangle.GetIntersection(rcOld.m_aRectangle);
- bool bOverlap = (rcOverlap.GetWidth() > 0 && rcOverlap.GetHeight() > 0);
- SAL_WARN("lok", "Merging " << rcNew.toString() << " & " << rcOld.toString() << " => " <<
- rcOverlap.toString() << " Overlap: " << bOverlap);
- if (bOverlap)
+ if (rcNew.m_nPart == -1)
{
- rcNew.m_aRectangle.Union(rcOld.m_aRectangle);
- SAL_WARN("lok", "Merged: " << rcNew.toString());
+ // Don't merge unless fully overlaped.
+ SAL_WARN("lok", "New " << rcNew.toString() << " has " << rcOld.toString() << "?");
+ if (rcNew.m_aRectangle.IsInside(rcOld.m_aRectangle))
+ {
+ SAL_WARN("lok", "New " << rcNew.toString() << " engulfs old " << rcOld.toString() << ".");
+ return true;
+ }
+ }
+ else if (rcOld.m_nPart == -1)
+ {
+ // Don't merge unless fully overlaped.
+ SAL_WARN("lok", "Old " << rcOld.toString() << " has " << rcNew.toString() << "?");
+ if (rcOld.m_aRectangle.IsInside(rcNew.m_aRectangle))
+ {
+ SAL_WARN("lok", "New " << rcNew.toString() << " engulfs old " << rcOld.toString() << ".");
+ return true;
+ }
+ }
+ else
+ {
+ const Rectangle rcOverlap = rcNew.m_aRectangle.GetIntersection(rcOld.m_aRectangle);
+ const bool bOverlap = !rcOverlap.IsEmpty();
+ SAL_WARN("lok", "Merging " << rcNew.toString() << " & " << rcOld.toString() << " => " <<
+ rcOverlap.toString() << " Overlap: " << bOverlap);
+ if (bOverlap)
+ {
+ rcNew.m_aRectangle.Union(rcOld.m_aRectangle);
+ SAL_WARN("lok", "Merged: " << rcNew.toString());
+ return true;
+ }
}
- return bOverlap;
- }
- else
- {
- return false;
}
+
+ // Keep others.
+ return false;
}
);
@@ -834,10 +904,10 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
SAL_WARN("lok", "Error: merged rect smaller.");
}
-
- payload = rcNew.toString().getStr();
}
}
+
+ payload = rcNew.toString().getStr();
}
break;
@@ -862,7 +932,8 @@ void CallbackFlushHandler::queue(const int type, const char* data)
}
m_queue.emplace_back(type, payload);
- SAL_WARN("lok", "Queued [" << type << "]: [" << payload << "] to have " << m_queue.size() << " entries.");
+ SAL_WARN("lok", "Queued #" << (m_queue.size() - 1) <<
+ " [" << type << "]: [" << payload << "] to have " << m_queue.size() << " entries.");
lock.unlock();
if (!IsActive())