summaryrefslogtreecommitdiff
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
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>
-rw-r--r--desktop/qa/desktop_lib/test_desktop_lib.cxx174
-rw-r--r--desktop/source/lib/init.cxx183
-rw-r--r--include/sfx2/lokhelper.hxx4
3 files changed, 270 insertions, 91 deletions
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 9219a171dc67..59bf62079b4b 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -1295,29 +1295,29 @@ void DesktopLOKTest::testNotificationCompression()
std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
handler->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, ""); // 0
- handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15 25 15 10"); // Superseeded.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15, 25, 15, 10"); // Superseeded.
handler->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, ""); // Should be dropped.
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15 25 15 10"); // Superseeded.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15 25 15 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15, 25, 15, 10"); // 1
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15, 25, 15, 10"); // Should be dropped.
handler->queue(LOK_CALLBACK_TEXT_SELECTION, ""); // Superseeded.
handler->queue(LOK_CALLBACK_STATE_CHANGED, ""); // 2
handler->queue(LOK_CALLBACK_STATE_CHANGED, ".uno:Bold"); // 3
handler->queue(LOK_CALLBACK_STATE_CHANGED, ""); // 4
handler->queue(LOK_CALLBACK_MOUSE_POINTER, "text"); // 5
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15 25 15 10"); // 6
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15 25 15 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15, 25, 15, 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "15, 25, 15, 10"); // Should be dropped.
handler->queue(LOK_CALLBACK_MOUSE_POINTER, "text"); // Should be dropped.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15 25 15 10"); // Superseeded.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15 25 15 10"); // Superseeded.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15 25 15 10"); // Superseedd.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15 25 15 10"); // Should be dropped.
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15 25 15 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15, 25, 15, 10"); // Superseeded.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15, 25, 15, 10"); // Superseeded.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15, 25, 15, 10"); // Superseedd.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15, 25, 15, 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15, 25, 15, 10"); // Should be dropped.
handler->queue(LOK_CALLBACK_TEXT_SELECTION, ""); // 7
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15 25 15 10"); // 8
- handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15 25 15 10"); // 9
- handler->queue(LOK_CALLBACK_CELL_CURSOR, "15 25 15 10"); // 10
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_START, "15, 25, 15, 10"); // 8
+ handler->queue(LOK_CALLBACK_TEXT_SELECTION_END, "15, 25, 15, 10"); // 9
+ handler->queue(LOK_CALLBACK_CELL_CURSOR, "15, 25, 15, 10"); // 10
handler->queue(LOK_CALLBACK_CURSOR_VISIBLE, ""); // 11
- handler->queue(LOK_CALLBACK_CELL_CURSOR, "15 25 15 10"); // Should be dropped.
+ handler->queue(LOK_CALLBACK_CELL_CURSOR, "15, 25, 15, 10"); // Should be dropped.
handler->queue(LOK_CALLBACK_CELL_FORMULA, "blah"); // 12
handler->queue(LOK_CALLBACK_SET_PART, "1"); // 13
handler->queue(LOK_CALLBACK_STATE_CHANGED, ".uno:AssignLayout=20"); // Superseeded
@@ -1334,6 +1334,9 @@ void DesktopLOKTest::testNotificationCompression()
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, (int)std::get<0>(notifs[i]));
CPPUNIT_ASSERT_EQUAL(std::string(""), std::get<1>(notifs[i++]));
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get<1>(notifs[i++]));
+
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_STATE_CHANGED, (int)std::get<0>(notifs[i]));
CPPUNIT_ASSERT_EQUAL(std::string(""), std::get<1>(notifs[i++]));
@@ -1346,20 +1349,17 @@ void DesktopLOKTest::testNotificationCompression()
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_MOUSE_POINTER, (int)std::get<0>(notifs[i]));
CPPUNIT_ASSERT_EQUAL(std::string("text"), std::get<1>(notifs[i++]));
- CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
- CPPUNIT_ASSERT_EQUAL(std::string("15 25 15 10"), std::get<1>(notifs[i++]));
-
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_TEXT_SELECTION, (int)std::get<0>(notifs[i]));
CPPUNIT_ASSERT_EQUAL(std::string(""), std::get<1>(notifs[i++]));
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_TEXT_SELECTION_START, (int)std::get<0>(notifs[i]));
- CPPUNIT_ASSERT_EQUAL(std::string("15 25 15 10"), std::get<1>(notifs[i++]));
+ CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get<1>(notifs[i++]));
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_TEXT_SELECTION_END, (int)std::get<0>(notifs[i]));
- CPPUNIT_ASSERT_EQUAL(std::string("15 25 15 10"), std::get<1>(notifs[i++]));
+ CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get<1>(notifs[i++]));
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_CELL_CURSOR, (int)std::get<0>(notifs[i]));
- CPPUNIT_ASSERT_EQUAL(std::string("15 25 15 10"), std::get<1>(notifs[i++]));
+ CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get<1>(notifs[i++]));
CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_CURSOR_VISIBLE, (int)std::get<0>(notifs[i]));
CPPUNIT_ASSERT_EQUAL(std::string(""), std::get<1>(notifs[i++]));
@@ -1377,8 +1377,6 @@ void DesktopLOKTest::testNotificationCompression()
void DesktopLOKTest::testTileInvalidationCompression()
{
LibLODocument_Impl* pDocument = loadDoc("blank_text.odt");
- std::vector<std::tuple<int, std::string>> notifs;
- std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
comphelper::LibreOfficeKit::setPartInInvalidation(true);
comphelper::ScopeGuard aGuard([]()
@@ -1386,23 +1384,129 @@ void DesktopLOKTest::testTileInvalidationCompression()
comphelper::LibreOfficeKit::setPartInInvalidation(false);
});
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 2147483767, 2147483767, 0");
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-121, -121, 300, 300, 0");
- handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, 0");
+ // Single part merging
+ {
+ std::vector<std::tuple<int, std::string>> notifs;
+ std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
- Scheduler::ProcessEventsToIdle();
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-100, -50, 500, 650, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "100, 100, 200, 200, 0");
-/*
- // Broken on Tinderbox, for whatever unreproducible reason.
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs.size());
- CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs.size());
+ size_t i = 0;
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 400, 600, 0"), std::get<1>(notifs[i++]));
+ }
- size_t i = 0;
- CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
- CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 2147483767, 2147483767, 0"), std::get<1>(notifs[i++]));
-*/
+ // Part Number
+ {
+ std::vector<std::tuple<int, std::string>> notifs;
+ std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 1"); // Different part
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 0, 0, 2"); // Invalid
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-121, -121, 200, 200, 0"); // Inside first
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, 1"); // Invalid
+
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs.size());
+
+ size_t i = 0;
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 1"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 239, 239, 0"), std::get<1>(notifs[i++]));
+ }
+
+ // All Parts
+ {
+ std::vector<std::tuple<int, std::string>> notifs;
+ std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); // 0
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 1"); // 1: Different part
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 0, 0, -1"); // Invalid
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-121, -121, 200, 200, -1"); // 0: All parts
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, -1"); // Invalid
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-100, -100, 1200, 1200, -1"); // 0: All parts
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 3"); // Overlapped
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "1000, 1000, 1239, 1239, 2"); // 1: Unique region
+
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs.size());
+
+ size_t i = 0;
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 1100, 1100, -1"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("1000, 1000, 1239, 1239, 2"), std::get<1>(notifs[i++]));
+ }
+
+ // All Parts (partial)
+ {
+ std::vector<std::tuple<int, std::string>> notifs;
+ std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 0"); // 0
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 100, 100, 1"); // 1: Different part
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 0, 0, -1"); // Invalid
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "150, 150, 50, 50, -1"); // 2: All-parts
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, -1"); // Invalid
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "150, 150, 40, 40, 3"); // Overlapped w/ 2
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 4"); // 3: Unique
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "1000, 1000, 1239, 1239, 1"); // 4: Unique
+
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), notifs.size());
+
+ size_t i = 0;
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 0"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 100, 100, 1"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("150, 150, 50, 50, -1"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 4"), std::get<1>(notifs[i++]));
+
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("1000, 1000, 1239, 1239, 1"), std::get<1>(notifs[i++]));
+ }
+
+ // Merge with "EMPTY"
+ {
+ std::vector<std::tuple<int, std::string>> notifs;
+ std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "EMPTY, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 240, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "-121, -121, 300, 300, 0");
+ handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, -32767, -32767, 0");
+
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs.size());
+
+ size_t i = 0;
+ CPPUNIT_ASSERT_EQUAL((int)LOK_CALLBACK_INVALIDATE_TILES, (int)std::get<0>(notifs[i]));
+ CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 1000000000, 1000000000, 0"), std::get<1>(notifs[i++]));
+ }
}
void DesktopLOKTest::testPartInInvalidation()
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())
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 0c118fbca896..a6de41cb880d 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -42,6 +42,10 @@ public:
static void notifyOtherView(SfxViewShell* pThisView, SfxViewShell* pOtherView, int nType, const OString& rKey, const OString& rPayload);
/// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed.
static void notifyInvalidation(SfxViewShell* pThisView, const OString& rPayload);
+
+ /// A special value to signify 'infinity'.
+ /// This value is chosen such that sal_Int32 will not overflow when manipulated.
+ static const long MaxTwips = 1e9;
};
template<typename ViewShellType, typename FunctionType>