[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - desktop/inc desktop/source

Marco Cecchetti marco.cecchetti at collabora.com
Fri Sep 9 20:49:59 UTC 2016


 desktop/inc/lib/init.hxx    |    5 +
 desktop/source/lib/init.cxx |  197 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 168 insertions(+), 34 deletions(-)

New commits:
commit f40a986345e91dcb01c7da565615e19ff002043b
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Fri Sep 9 21:55:12 2016 +0200

    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 at gmail.com>
    Tested-by: Marco Cecchetti <mrcekets at gmail.com>

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index 0d01997..db28168 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 8eb2d9d..cb86a63 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());
 }


More information about the Libreoffice-commits mailing list