summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2016-09-09 21:55:12 +0200
committerMarco Cecchetti <mrcekets@gmail.com>2016-09-09 20:49:36 +0000
commitf40a986345e91dcb01c7da565615e19ff002043b (patch)
treec8ad6ec79d0ca2fbdf0ab8f659a13f11ca316c83
parenta6aca59db3503948a0611e421d81b104685a8677 (diff)
LOK: new callback dropping implementation
Now view callbacks have their own collection of last states where the key is made up by both the view id and the callback type. Callback dropping based on the last state is no more handled on queueing but on flushing, since what really matters is the last performed callback (for each callback type). Anyway in order to not modify the order of callbacks, that could be changed when an already queued callback is superseeded, dropping still occurs on queuing too, just by looking for the last queued callback of the same type. The result is a substantial reduction of redundant callbacks and fix the following problem in loleaflet: when there are more views for a speadsheet and cell cursors for two view are placed on the same cell, a continuos swapping between the two cell cursors can occur. That was due to a sequence of "EMPTY" and coordinates messages or cell cursor and cell view cursor messages which were sent in an alternating way. Change-Id: I79e14d11d4e8590aff715181e3410ad88c4e6175 Reviewed-on: https://gerrit.libreoffice.org/28788 Reviewed-by: Marco Cecchetti <mrcekets@gmail.com> Tested-by: Marco Cecchetti <mrcekets@gmail.com>
-rw-r--r--desktop/inc/lib/init.hxx5
-rw-r--r--desktop/source/lib/init.cxx197
2 files changed, 168 insertions, 34 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index 0d019975a090..db281688c2f9 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -11,6 +11,7 @@
#define INCLUDED_DESKTOP_INC_LIB_INIT_HXX
#include <map>
+#include <unordered_map>
#include <memory>
#include <mutex>
@@ -46,6 +47,9 @@ namespace desktop {
void setPartTilePainting(const bool bPartPainting) { m_bPartTilePainting = bPartPainting; }
bool isPartTilePainting() const { return m_bPartTilePainting; }
+ void addViewStates(int viewId);
+ void removeViewStates(int viewId);
+
typedef std::vector<std::pair<int, std::string>> queue_type;
private:
@@ -54,6 +58,7 @@ namespace desktop {
queue_type m_queue;
std::map<int, std::string> m_states;
+ std::unordered_map<int, std::unordered_map<int, std::string>> m_viewStates;
LibreOfficeKitDocument* m_pDocument;
LibreOfficeKitCallback m_pCallback;
void *m_pData;
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 8eb2d9dbe2a8..cb86a63d8ff6 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -325,6 +325,8 @@ static boost::property_tree::ptree unoAnyToPropertyTree(const uno::Any& anyItem)
return aTree;
}
+namespace {
+
Rectangle lcl_ParseRect(const std::string& payload)
{
std::istringstream iss(payload);
@@ -335,6 +337,32 @@ Rectangle lcl_ParseRect(const std::string& payload)
return rc;
}
+bool lcl_isViewCallbackType(const int type)
+{
+ switch (type)
+ {
+ case LOK_CALLBACK_CELL_VIEW_CURSOR:
+ case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+ case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+int lcl_getViewId(const std::string& payload)
+{
+ boost::property_tree::ptree aTree;
+ std::stringstream aStream(payload);
+ boost::property_tree::read_json(aStream, aTree);
+ return aTree.get<int>("viewId");
+}
+
+} // end anonymous namespace
+
extern "C"
{
@@ -488,18 +516,13 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li
m_states.emplace(LOK_CALLBACK_TEXT_SELECTION_END, "NIL");
m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL");
m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL");
- m_states.emplace(LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "NIL");
m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL");
- m_states.emplace(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR , "NIL");
m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL");
m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL");
m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL");
- m_states.emplace(LOK_CALLBACK_CELL_VIEW_CURSOR, "NIL");
m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL");
m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL");
- m_states.emplace(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "NIL");
m_states.emplace(LOK_CALLBACK_SET_PART, "NIL");
- m_states.emplace(LOK_CALLBACK_TEXT_VIEW_SELECTION, "NIL");
Start();
}
@@ -565,24 +588,49 @@ void CallbackFlushHandler::queue(const int type, const char* data)
std::unique_lock<std::mutex> lock(m_mutex);
- const auto stateIt = m_states.find(type);
- if (stateIt != m_states.end())
+ // drop duplicate callbacks for the listed types
+ switch (type)
{
- // If the state didn't change, it's safe to ignore.
- if (stateIt->second == payload)
+ case LOK_CALLBACK_TEXT_SELECTION_START:
+ case LOK_CALLBACK_TEXT_SELECTION_END:
+ case LOK_CALLBACK_TEXT_SELECTION:
+ case LOK_CALLBACK_GRAPHIC_SELECTION:
+ case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR :
+ case LOK_CALLBACK_STATE_CHANGED:
+ case LOK_CALLBACK_MOUSE_POINTER:
+ case LOK_CALLBACK_CELL_CURSOR:
+ case LOK_CALLBACK_CELL_VIEW_CURSOR:
+ case LOK_CALLBACK_CELL_FORMULA:
+ case LOK_CALLBACK_CURSOR_VISIBLE:
+ case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+ case LOK_CALLBACK_SET_PART:
+ case LOK_CALLBACK_TEXT_VIEW_SELECTION:
{
- //SAL_WARN("lok", "Skipping duplicate [" + std::to_string(type) + "]: [" + payload + "].");
- return;
- }
+ const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
+ [type] (const queue_type::value_type& elem) { return (elem.first == type); });
- stateIt->second = payload;
+ if (pos != m_queue.rend() && pos->second == payload)
+ {
+ //SAL_WARN("lok", "Skipping queue duplicate [" + std::to_string(type) + "]: [" + payload + "].");
+ return;
+ }
+ }
+ break;
}
if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty())
{
- // Removing text selection invalidates the start and end as well.
- m_states[LOK_CALLBACK_TEXT_SELECTION_START] = "";
- m_states[LOK_CALLBACK_TEXT_SELECTION_END] = "";
+ const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(),
+ [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_TEXT_SELECTION_START); });
+ if (posStart != m_queue.rend())
+ posStart->second = "";
+
+ const auto& posEnd = std::find_if(m_queue.rbegin(), m_queue.rend(),
+ [] (const queue_type::value_type& elem) { return (elem.first == LOK_CALLBACK_TEXT_SELECTION_END); });
+ if (posEnd != m_queue.rend())
+ posEnd->second = "";
}
// When payload is empty discards any previous state.
@@ -630,25 +678,10 @@ void CallbackFlushHandler::queue(const int type, const char* data)
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
{
- boost::property_tree::ptree aTree;
- std::stringstream aStream(payload);
- boost::property_tree::read_json(aStream, aTree);
- const int nViewId = aTree.get<int>("viewId");
-
+ const int nViewId = lcl_getViewId(payload);
removeAll(
[type, nViewId] (const queue_type::value_type& elem) {
- if (elem.first == type)
- {
- boost::property_tree::ptree aElemTree;
- std::stringstream aElemStream(elem.second);
- boost::property_tree::read_json(aElemStream, aElemTree);
- int nElemViewId = aElemTree.get<int>("viewId");
- return (nViewId == nElemViewId);
- }
- else
- {
- return false;
- }
+ return (elem.first == type && nViewId == lcl_getViewId(elem.second));
}
);
}
@@ -717,9 +750,56 @@ void CallbackFlushHandler::flush()
if (m_pCallback && !m_bEventLatch)
{
std::unique_lock<std::mutex> lock(m_mutex);
+
for (auto& pair : m_queue)
{
- m_pCallback(pair.first, pair.second.c_str(), m_pData);
+ const int type = pair.first;
+ const auto& payload = pair.second;
+ const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(payload) : -1;
+
+ if (viewId == -1)
+ {
+ const auto stateIt = m_states.find(type);
+ if (stateIt != m_states.end())
+ {
+ // If the state didn't change, it's safe to ignore.
+ if (stateIt->second == payload)
+ {
+ //SAL_WARN("lok", "Skipping duplicate [" + std::to_string(type) + "]: [" + payload + "].");
+ continue;
+ }
+
+ stateIt->second = payload;
+ }
+ }
+ else
+ {
+ const auto statesIt = m_viewStates.find(viewId);
+ if (statesIt != m_viewStates.end())
+ {
+ auto& states = statesIt->second;
+ const auto stateIt = states.find(type);
+ if (stateIt != states.end())
+ {
+ // If the state didn't change, it's safe to ignore.
+ if (stateIt->second == payload)
+ {
+ //SAL_WARN("lok", "Skipping view duplicate [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "].");
+ continue;
+ }
+
+ stateIt->second = payload;
+ //SAL_WARN("lok", "Replacing an element in view states [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "].");
+ }
+ else
+ {
+ states.emplace(type, payload);
+ //SAL_WARN("lok", "Inserted a new element in view states: [" + std::to_string(type) + "," + std::to_string(viewId) + "]: [" + payload + "]");
+ }
+ }
+ }
+
+ m_pCallback(type, payload.c_str(), m_pData);
}
m_queue.clear();
@@ -732,6 +812,20 @@ void CallbackFlushHandler::removeAll(const std::function<bool (const CallbackFlu
m_queue.erase(newEnd, m_queue.end());
}
+void CallbackFlushHandler::addViewStates(int viewId)
+{
+ const auto& result = m_viewStates.emplace(viewId, decltype(m_viewStates)::mapped_type());
+ if (!result.second && result.first != m_viewStates.end())
+ {
+ result.first->second.clear();
+ }
+}
+
+void CallbackFlushHandler::removeViewStates(int viewId)
+{
+ m_viewStates.erase(viewId);
+}
+
static void doc_destroy(LibreOfficeKitDocument *pThis)
{
@@ -1475,8 +1569,43 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
if (nView < 0)
return;
+ if (pCallback != nullptr)
+ {
+ size_t nId = nView;
+ for (auto& pair : pDocument->mpCallbackFlushHandlers)
+ {
+ if (pair.first == nId)
+ continue;
+
+ pair.second->addViewStates(nView);
+ }
+ }
+ else
+ {
+ size_t nId = nView;
+ for (auto& pair : pDocument->mpCallbackFlushHandlers)
+ {
+ if (pair.first == nId)
+ continue;
+
+ pair.second->removeViewStates(nView);
+ }
+ }
+
pDocument->mpCallbackFlushHandlers[nView].reset(new CallbackFlushHandler(pThis, pCallback, pData));
+ if (pCallback != nullptr)
+ {
+ size_t nId = nView;
+ for (const auto& pair : pDocument->mpCallbackFlushHandlers)
+ {
+ if (pair.first == nId)
+ continue;
+
+ pDocument->mpCallbackFlushHandlers[nView]->addViewStates(pair.first);
+ }
+ }
+
if (SfxViewShell* pViewShell = SfxViewFrame::Current()->GetViewShell())
pViewShell->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandlers[nView].get());
}