1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 #include <unordered_map>
17 #include <string_view>
19 #include <boost/property_tree/ptree.hpp>
20 #include <boost/variant.hpp>
21 #include <boost/container/flat_map.hpp>
23 #include <osl/thread.h>
24 #include <rtl/ref.hxx>
25 #include <rtl/strbuf.hxx>
26 #include <vcl/idle.hxx>
27 #include <LibreOfficeKit/LibreOfficeKit.h>
28 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/lang/XComponent.hpp>
31 #include <tools/gen.hxx>
32 #include <sfx2/lokcallback.hxx>
33 #include <sfx2/lokhelper.hxx>
35 #include <desktop/dllapi.h>
37 class LOKInteractionHandler
;
41 /// Represents an invalidated rectangle inside a given document part.
42 struct RectangleAndPart
44 tools::Rectangle m_aRectangle
;
48 // This is the "EMPTY" rectangle, which somewhat confusingly actually means
49 // to drop all rectangles (see LOK_CALLBACK_INVALIDATE_TILES documentation),
50 // and so it is actually an infinite rectangle and not an empty one.
51 constexpr static tools::Rectangle emptyAllRectangle
= {0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
};
54 : m_nPart(INT_MIN
) // -1 is reserved to mean "all parts".
59 RectangleAndPart(const tools::Rectangle
* pRect
, int nPart
, int nMode
)
60 : m_aRectangle( pRect
? SanitizedRectangle(*pRect
) : emptyAllRectangle
)
66 OString
toString() const
69 return (isInfinite() ? "EMPTY" : m_aRectangle
.toString())
70 + ", " + OString::number(m_nPart
) + ", " + OString::number(m_nMode
);
72 return (isInfinite() ? "EMPTY" : m_aRectangle
.toString());
75 /// Infinite Rectangle is both sides are
76 /// equal or longer than SfxLokHelper::MaxTwips.
77 bool isInfinite() const
79 return m_aRectangle
.GetWidth() >= SfxLokHelper::MaxTwips
&&
80 m_aRectangle
.GetHeight() >= SfxLokHelper::MaxTwips
;
83 /// Empty Rectangle is when it has zero dimensions.
86 return m_aRectangle
.IsEmpty();
89 static RectangleAndPart
Create(const std::string
& rPayload
);
90 /// Makes sure a rectangle is valid (apparently some code does not like negative coordinates for example).
91 static tools::Rectangle
SanitizedRectangle(tools::Long nLeft
, tools::Long nTop
, tools::Long nWidth
, tools::Long nHeight
);
92 static tools::Rectangle
SanitizedRectangle(const tools::Rectangle
& rect
);
95 /// One instance of this per view, handles flushing callbacks
96 class DESKTOP_DLLPUBLIC CallbackFlushHandler final
: public Idle
, public SfxLokCallbackInterface
99 explicit CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
);
100 virtual ~CallbackFlushHandler() override
;
101 virtual void Invoke() override
;
102 // TODO This should be dropped and the binary libreOfficeKitViewCallback() variants should be called?
103 void queue(const int type
, const char* data
);
105 /// Disables callbacks on this handler. Must match with identical count
106 /// of enableCallbacks. Used during painting and changing views.
107 void disableCallbacks() { ++m_nDisableCallbacks
; }
108 /// Enables callbacks on this handler. Must match with identical count
109 /// of disableCallbacks. Used during painting and changing views.
110 void enableCallbacks() { --m_nDisableCallbacks
; }
111 /// Returns true iff callbacks are disabled.
112 bool callbacksDisabled() const { return m_nDisableCallbacks
!= 0; }
114 void addViewStates(int viewId
);
115 void removeViewStates(int viewId
);
117 void setViewId( int viewId
) { m_viewId
= viewId
; }
119 // SfxLockCallbackInterface
120 virtual void libreOfficeKitViewCallback(int nType
, const char* pPayload
) override
;
121 virtual void libreOfficeKitViewCallbackWithViewId(int nType
, const char* pPayload
, int nViewId
) override
;
122 virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle
* pRect
, int nPart
, int nMode
) override
;
123 virtual void libreOfficeKitViewUpdatedCallback(int nType
) override
;
124 virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType
, int nViewId
, int nSourceViewId
) override
;
125 virtual void libreOfficeKitViewAddPendingInvalidateTiles() override
;
126 virtual void dumpState(rtl::OStringBuffer
&rState
) override
;
131 CallbackData(const char* payload
)
132 : PayloadString(payload
? payload
: "(nil)")
136 CallbackData(const char* payload
, int viewId
)
137 : PayloadString(payload
? payload
: "(nil)")
138 , PayloadObject(viewId
)
142 CallbackData(const tools::Rectangle
* pRect
, int viewId
)
143 : PayloadObject(RectangleAndPart(pRect
, viewId
, 0))
144 { // PayloadString will be done on demand
147 CallbackData(const tools::Rectangle
* pRect
, int part
, int mode
)
148 : PayloadObject(RectangleAndPart(pRect
, part
, mode
))
149 { // PayloadString will be done on demand
152 const std::string
& getPayload() const;
153 /// Update a RectangleAndPart object and update PayloadString if necessary.
154 void updateRectangleAndPart(const RectangleAndPart
& rRectAndPart
);
155 /// Return the parsed RectangleAndPart instance.
156 const RectangleAndPart
& getRectangleAndPart() const;
157 /// Parse and set the JSON object and return it. Clobbers PayloadString.
158 boost::property_tree::ptree
& setJson(const std::string
& payload
);
159 /// Set a Json object and update PayloadString.
160 void setJson(const boost::property_tree::ptree
& rTree
);
161 /// Return the parsed JSON instance.
162 const boost::property_tree::ptree
& getJson() const;
164 int getViewId() const;
168 return PayloadString
.empty() && PayloadObject
.which() == 0;
172 PayloadString
.clear();
173 PayloadObject
= boost::blank();
176 /// Validate that the payload and parsed object match.
177 bool validate() const;
179 /// Returns true iff there is cached data.
180 bool isCached() const { return PayloadObject
.which() != 0; }
183 mutable std::string PayloadString
;
185 /// The parsed payload cache. Update validate() when changing this.
186 mutable boost::variant
<boost::blank
, RectangleAndPart
, boost::property_tree::ptree
, int> PayloadObject
;
189 typedef std::vector
<int> queue_type1
;
190 typedef std::vector
<CallbackData
> queue_type2
;
193 bool removeAll(int type
);
194 bool removeAll(int type
, const std::function
<bool (const CallbackData
&)>& rTestFunc
);
195 bool processInvalidateTilesEvent(int type
, CallbackData
& aCallbackData
);
196 bool processWindowEvent(int type
, CallbackData
& aCallbackData
);
197 queue_type2::iterator
toQueue2(queue_type1::iterator
);
198 queue_type2::reverse_iterator
toQueue2(queue_type1::reverse_iterator
);
199 void queue(const int type
, CallbackData
& data
);
200 void enqueueUpdatedTypes();
201 void enqueueUpdatedType( int type
, const SfxViewShell
* sourceViewShell
, int viewId
);
203 /** we frequently want to scan the queue, and mostly when we do so, we only care about the element type
204 so we split the queue in 2 to make the scanning cache friendly. */
205 queue_type1 m_queue1
;
206 queue_type2 m_queue2
;
207 std::map
<int, std::string
> m_states
;
208 std::unordered_map
<std::string
, std::string
> m_lastStateChange
;
209 std::unordered_map
<int, std::unordered_map
<int, std::string
>> m_viewStates
;
211 // For some types only the last message matters (see isUpdatedType()) or only the last message
212 // per each viewId value matters (see isUpdatedTypePerViewId()), so instead of using push model
213 // where we'd get flooded by repeated messages (which might be costly to generate and process),
214 // the preferred way is that libreOfficeKitViewUpdatedCallback()
215 // or libreOfficeKitViewUpdatedCallbackPerViewId() get called to notify about such a message being
216 // needed, and we'll set a flag here to fetch the actual message before flushing.
217 void setUpdatedType( int nType
, bool value
);
218 void setUpdatedTypePerViewId( int nType
, int nViewId
, int nSourceViewId
, bool value
);
219 void resetUpdatedType( int nType
);
220 void resetUpdatedTypePerViewId( int nType
, int nViewId
);
221 std::vector
<bool> m_updatedTypes
; // index is type, value is if set
224 bool set
= false; // value is if set
227 // Flat_map is used in preference to unordered_map because the map is accessed very often.
228 boost::container::flat_map
<int, std::vector
<PerViewIdData
>> m_updatedTypesPerViewId
; // key is view, index is type
230 LibreOfficeKitDocument
* m_pDocument
;
231 int m_viewId
= -1; // view id of the associated SfxViewShell
232 LibreOfficeKitCallback m_pCallback
;
234 int m_nDisableCallbacks
;
235 std::recursive_mutex m_mutex
;
236 class TimeoutIdle
: public Timer
239 TimeoutIdle( CallbackFlushHandler
* handler
);
240 virtual void Invoke() override
;
242 CallbackFlushHandler
* mHandler
;
244 TimeoutIdle m_TimeoutIdle
;
247 struct DESKTOP_DLLPUBLIC LibLODocument_Impl
: public _LibreOfficeKitDocument
249 css::uno::Reference
<css::lang::XComponent
> mxComponent
;
250 std::shared_ptr
< LibreOfficeKitDocumentClass
> m_pDocumentClass
;
251 std::map
<size_t, std::shared_ptr
<CallbackFlushHandler
>> mpCallbackFlushHandlers
;
252 const int mnDocumentId
;
253 std::set
<OUString
> maFontsMissing
;
255 explicit LibLODocument_Impl(const css::uno::Reference
<css::lang::XComponent
>& xComponent
,
257 ~LibLODocument_Impl();
260 struct DESKTOP_DLLPUBLIC LibLibreOffice_Impl
: public _LibreOfficeKit
262 OUString maLastExceptionMsg
;
263 std::shared_ptr
< LibreOfficeKitClass
> m_pOfficeClass
;
265 LibreOfficeKitCallback mpCallback
;
266 void *mpCallbackData
;
267 int64_t mOptionalFeatures
;
268 std::map
<OString
, rtl::Reference
<LOKInteractionHandler
>> mInteractionMap
;
270 LibLibreOffice_Impl();
271 ~LibLibreOffice_Impl();
273 bool hasOptionalFeature(LibreOfficeKitOptionalFeatures
const feature
)
275 return (mOptionalFeatures
& feature
) != 0;
278 void dumpState(rtl::OStringBuffer
&aState
);
281 /// Helper function to extract the value from parameters delimited by
282 /// comma, like: Name1=Value1,Name2=Value2,Name3=Value3.
283 /// @param rOptions When extracted, the Param=Value is removed from it.
284 DESKTOP_DLLPUBLIC OUString
extractParameter(OUString
& aOptions
, std::u16string_view rName
);
286 /// Helper function to convert JSON to a vector of PropertyValues.
287 /// Public to be unit-test-able.
288 DESKTOP_DLLPUBLIC
std::vector
<com::sun::star::beans::PropertyValue
> jsonToPropertyValuesVector(const char* pJSON
);
291 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */