/src/libreoffice/xmloff/source/style/xmlexppr.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <memory> |
21 | | #include <optional> |
22 | | #include <string_view> |
23 | | #include <com/sun/star/container/XNameContainer.hpp> |
24 | | #include <com/sun/star/xml/AttributeData.hpp> |
25 | | #include <com/sun/star/beans/XPropertySet.hpp> |
26 | | #include <com/sun/star/beans/XPropertyState.hpp> |
27 | | #include <com/sun/star/beans/XMultiPropertySet.hpp> |
28 | | #include <com/sun/star/beans/XTolerantMultiPropertySet.hpp> |
29 | | #include <com/sun/star/beans/TolerantPropertySetResultType.hpp> |
30 | | #include <comphelper/anycompare.hxx> |
31 | | #include <comphelper/diagnose_ex.hxx> |
32 | | #include <cppuhelper/weakref.hxx> |
33 | | #include <osl/diagnose.h> |
34 | | #include <list> |
35 | | #include <map> |
36 | | #include <o3tl/sorted_vector.hxx> |
37 | | |
38 | | #include <utility> |
39 | | #include <xmloff/xmlexppr.hxx> |
40 | | #include <xmloff/xmltoken.hxx> |
41 | | #include <xmloff/namespacemap.hxx> |
42 | | #include <xmloff/xmlnamespace.hxx> |
43 | | #include <xmloff/xmlexp.hxx> |
44 | | #include <xmloff/xmlprmap.hxx> |
45 | | #include <xmloff/maptype.hxx> |
46 | | #include <xmloff/xmltypes.hxx> |
47 | | #include <xmloff/xmlprhdl.hxx> |
48 | | |
49 | | using namespace ::com::sun::star; |
50 | | using namespace ::com::sun::star::beans; |
51 | | using namespace ::com::sun::star::uno; |
52 | | using namespace ::xmloff::token; |
53 | | |
54 | 59.3k | #define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT) |
55 | | |
56 | | namespace { |
57 | | |
58 | | struct XMLPropTokens_Impl |
59 | | { |
60 | | sal_uInt16 nType; |
61 | | XMLTokenEnum eToken; |
62 | | }; |
63 | | |
64 | | const sal_uInt16 MAX_PROP_TYPES = |
65 | | (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) - |
66 | | (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT); |
67 | | |
68 | | XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] = |
69 | | { |
70 | | { GET_PROP_TYPE(XML_TYPE_PROP_CHART), XML_CHART_PROPERTIES }, |
71 | | { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC), XML_GRAPHIC_PROPERTIES }, |
72 | | { GET_PROP_TYPE(XML_TYPE_PROP_TABLE), XML_TABLE_PROPERTIES }, |
73 | | { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN), XML_TABLE_COLUMN_PROPERTIES }, |
74 | | { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW), XML_TABLE_ROW_PROPERTIES }, |
75 | | { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL), XML_TABLE_CELL_PROPERTIES }, |
76 | | { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL), XML_LIST_LEVEL_PROPERTIES }, |
77 | | { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH), XML_PARAGRAPH_PROPERTIES }, |
78 | | { GET_PROP_TYPE(XML_TYPE_PROP_TEXT), XML_TEXT_PROPERTIES }, |
79 | | { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE), XML_DRAWING_PAGE_PROPERTIES }, |
80 | | { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT), XML_PAGE_LAYOUT_PROPERTIES }, |
81 | | { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER), XML_HEADER_FOOTER_PROPERTIES }, |
82 | | { GET_PROP_TYPE(XML_TYPE_PROP_RUBY), XML_RUBY_PROPERTIES }, |
83 | | { GET_PROP_TYPE(XML_TYPE_PROP_SECTION), XML_SECTION_PROPERTIES } |
84 | | }; |
85 | | |
86 | | // public methods |
87 | | |
88 | | // Take all properties of the XPropertySet which are also found in the |
89 | | // XMLPropertyMapEntry-array and which are not set to their default-value, |
90 | | // if a state is available. |
91 | | // After that I call the method 'ContextFilter'. |
92 | | |
93 | | struct ComparePropertyState |
94 | | { |
95 | | bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs) |
96 | 895k | { |
97 | 895k | return lhs.mnIndex < rhs.mnIndex; |
98 | 895k | } |
99 | | }; |
100 | | class XMLPropertyStates_Impl |
101 | | { |
102 | | o3tl::sorted_vector<XMLPropertyState, ComparePropertyState> aPropStates; |
103 | | public: |
104 | | XMLPropertyStates_Impl(); |
105 | | void AddPropertyState(const XMLPropertyState& rPropState); |
106 | | void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector); |
107 | | }; |
108 | | |
109 | | XMLPropertyStates_Impl::XMLPropertyStates_Impl() |
110 | 15.6k | { |
111 | 15.6k | } |
112 | | |
113 | | void XMLPropertyStates_Impl::AddPropertyState( |
114 | | const XMLPropertyState& rPropState) |
115 | 200k | { |
116 | 200k | aPropStates.insert(rPropState); |
117 | 200k | } |
118 | | |
119 | | void XMLPropertyStates_Impl::FillPropertyStateVector( |
120 | | std::vector<XMLPropertyState>& rVector) |
121 | 15.6k | { |
122 | 15.6k | rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() ); |
123 | 15.6k | } |
124 | | |
125 | | class FilterPropertyInfo_Impl |
126 | | { |
127 | | OUString msApiName; |
128 | | std::vector<sal_uInt32> maIndexes; |
129 | | |
130 | | public: |
131 | | |
132 | | FilterPropertyInfo_Impl( OUString aApiName, |
133 | | const sal_uInt32 nIndex); |
134 | | |
135 | 887k | const OUString& GetApiName() const { return msApiName; } |
136 | 229k | std::vector<sal_uInt32>& GetIndexes() { return maIndexes; } |
137 | | |
138 | | // for sort |
139 | | bool operator< ( const FilterPropertyInfo_Impl& rArg ) const |
140 | 287k | { |
141 | 287k | return (GetApiName() < rArg.GetApiName()); |
142 | 287k | } |
143 | | }; |
144 | | |
145 | | FilterPropertyInfo_Impl::FilterPropertyInfo_Impl( |
146 | | OUString aApiName, |
147 | | const sal_uInt32 nIndex ) : |
148 | 54.1k | msApiName(std::move( aApiName )) |
149 | 54.1k | { |
150 | 54.1k | maIndexes.push_back(nIndex); |
151 | 54.1k | } |
152 | | |
153 | | typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl; |
154 | | |
155 | | class FilterPropertiesInfo_Impl |
156 | | { |
157 | | FilterPropertyInfoList_Impl aPropInfos; |
158 | | |
159 | | std::optional<Sequence<OUString>> mxApiNames; |
160 | | |
161 | | public: |
162 | | FilterPropertiesInfo_Impl(); |
163 | | |
164 | | void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex); |
165 | | const uno::Sequence<OUString>& GetApiNames(); |
166 | | void FillPropertyStateArray( |
167 | | std::vector< XMLPropertyState >& rPropStates, |
168 | | const Reference< XPropertySet >& xPropSet, |
169 | | const rtl::Reference< XMLPropertySetMapper >& maPropMapper, |
170 | | const bool bDefault); |
171 | 15.6k | sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); } |
172 | | }; |
173 | | |
174 | | FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl() |
175 | 532 | { |
176 | 532 | } |
177 | | |
178 | | void FilterPropertiesInfo_Impl::AddProperty( |
179 | | const OUString& rApiName, const sal_uInt32 nIndex) |
180 | 54.1k | { |
181 | 54.1k | aPropInfos.emplace_back(rApiName, nIndex); |
182 | | |
183 | 54.1k | OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" ); |
184 | 54.1k | mxApiNames.reset(); |
185 | 54.1k | } |
186 | | |
187 | | const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames() |
188 | 15.6k | { |
189 | 15.6k | if( !mxApiNames ) |
190 | 532 | { |
191 | | // we have to do three things: |
192 | | // 1) sort API names, |
193 | | // 2) merge duplicates, |
194 | | // 3) construct sequence |
195 | | |
196 | | // sort names |
197 | 532 | aPropInfos.sort(); |
198 | | |
199 | | // merge duplicates |
200 | 532 | if ( aPropInfos.size() > 1 ) |
201 | 455 | { |
202 | 455 | FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin(); |
203 | 455 | FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end(); |
204 | 455 | FilterPropertyInfoList_Impl::iterator aCurrent = aOld; |
205 | 455 | ++aCurrent; |
206 | | |
207 | 54.1k | while ( aCurrent != aEnd ) |
208 | 53.6k | { |
209 | | // equal to next element? |
210 | 53.6k | if ( aOld->GetApiName() == aCurrent->GetApiName() ) |
211 | 10.1k | { |
212 | | // if equal: merge index lists |
213 | 10.1k | std::vector<sal_uInt32> aMerged; |
214 | 10.1k | std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(), |
215 | 10.1k | aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(), |
216 | 10.1k | std::back_inserter(aMerged)); |
217 | 10.1k | aOld->GetIndexes() = std::move(aMerged); |
218 | 10.1k | aCurrent->GetIndexes().clear(); |
219 | | // erase element, and continue with next |
220 | 10.1k | aCurrent = aPropInfos.erase( aCurrent ); |
221 | 10.1k | } |
222 | 43.5k | else |
223 | 43.5k | { |
224 | | // remember old element and continue with next |
225 | 43.5k | aOld = aCurrent; |
226 | 43.5k | ++aCurrent; |
227 | 43.5k | } |
228 | 53.6k | } |
229 | 455 | } |
230 | | |
231 | | // construct sequence |
232 | 532 | mxApiNames.emplace( aPropInfos.size() ); |
233 | 532 | OUString *pNames = mxApiNames->getArray(); |
234 | | |
235 | 532 | for (auto const& propInfo : aPropInfos) |
236 | 44.0k | { |
237 | 44.0k | *pNames = propInfo.GetApiName(); |
238 | 44.0k | ++pNames; |
239 | 44.0k | } |
240 | 532 | } |
241 | | |
242 | 15.6k | return *mxApiNames; |
243 | 15.6k | } |
244 | | |
245 | | void FilterPropertiesInfo_Impl::FillPropertyStateArray( |
246 | | std::vector< XMLPropertyState >& rPropStates, |
247 | | const Reference< XPropertySet >& rPropSet, |
248 | | const rtl::Reference< XMLPropertySetMapper >& rPropMapper, |
249 | | const bool bDefault ) |
250 | 15.6k | { |
251 | 15.6k | XMLPropertyStates_Impl aPropStates; |
252 | | |
253 | 15.6k | const uno::Sequence<OUString>& rApiNames = GetApiNames(); |
254 | | |
255 | 15.6k | Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY ); |
256 | 15.6k | if (xTolPropSet.is()) |
257 | 0 | { |
258 | 0 | if (!bDefault) |
259 | 0 | { |
260 | 0 | Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames)); |
261 | 0 | sal_Int32 nResultCount(aResults.getLength()); |
262 | 0 | if (nResultCount > 0) |
263 | 0 | { |
264 | 0 | const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray(); |
265 | 0 | FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); |
266 | 0 | XMLPropertyState aNewProperty( -1 ); |
267 | 0 | while (nResultCount > 0 && aPropIter != aPropInfos.end()) |
268 | 0 | { |
269 | 0 | if (pResults->Name == aPropIter->GetApiName()) |
270 | 0 | { |
271 | 0 | aNewProperty.mnIndex = -1; |
272 | 0 | aNewProperty.maValue = pResults->Value; |
273 | |
|
274 | 0 | for (auto const& index : aPropIter->GetIndexes()) |
275 | 0 | { |
276 | 0 | aNewProperty.mnIndex = index; |
277 | 0 | aPropStates.AddPropertyState( aNewProperty ); |
278 | 0 | } |
279 | 0 | ++pResults; |
280 | 0 | --nResultCount; |
281 | 0 | } |
282 | 0 | ++aPropIter; |
283 | 0 | } |
284 | 0 | } |
285 | 0 | } |
286 | 0 | else |
287 | 0 | { |
288 | 0 | const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames)); |
289 | 0 | OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" ); |
290 | 0 | FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); |
291 | 0 | XMLPropertyState aNewProperty( -1 ); |
292 | 0 | OSL_ENSURE( aPropInfos.size() == static_cast<sal_uInt32>(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" ); |
293 | 0 | for( const auto& rResult : aResults ) |
294 | 0 | { |
295 | 0 | if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) && |
296 | 0 | ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE))) |
297 | 0 | { |
298 | 0 | aNewProperty.mnIndex = -1; |
299 | 0 | aNewProperty.maValue = rResult.Value; |
300 | |
|
301 | 0 | for (auto const& index : aPropIter->GetIndexes()) |
302 | 0 | { |
303 | 0 | aNewProperty.mnIndex = index; |
304 | 0 | aPropStates.AddPropertyState( aNewProperty ); |
305 | 0 | } |
306 | 0 | } |
307 | 0 | ++aPropIter; |
308 | 0 | } |
309 | 0 | } |
310 | 0 | } |
311 | 15.6k | else |
312 | 15.6k | { |
313 | 15.6k | Sequence < PropertyState > aStates; |
314 | 15.6k | const PropertyState *pStates = nullptr; |
315 | 15.6k | Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY ); |
316 | 15.6k | if( xPropState.is() ) |
317 | 15.4k | { |
318 | 15.4k | aStates = xPropState->getPropertyStates( rApiNames ); |
319 | 15.4k | pStates = aStates.getConstArray(); |
320 | 15.4k | } |
321 | | |
322 | 15.6k | Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY ); |
323 | 15.6k | if( xMultiPropSet.is() && !bDefault ) |
324 | 15.5k | { |
325 | 15.5k | Sequence < Any > aValues; |
326 | 15.5k | if( pStates ) |
327 | 15.3k | { |
328 | | // step 1: get value count |
329 | 15.3k | sal_uInt32 nValueCount = 0; |
330 | | |
331 | 1.39M | for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates) |
332 | 1.38M | { |
333 | 1.38M | if( *pStates == PropertyState_DIRECT_VALUE ) |
334 | 159k | nValueCount++; |
335 | 1.38M | } |
336 | | |
337 | 15.3k | if( nValueCount ) |
338 | 7.94k | { |
339 | | // step 2: collect property names |
340 | 7.94k | Sequence < OUString > aAPINames( nValueCount ); |
341 | 7.94k | OUString *pAPINames = aAPINames.getArray(); |
342 | | |
343 | 7.94k | ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters; |
344 | 7.94k | aPropIters.reserve( nValueCount ); |
345 | | |
346 | 7.94k | FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); |
347 | 7.94k | OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!"); |
348 | | |
349 | 7.94k | pStates = aStates.getConstArray(); |
350 | 7.94k | sal_uInt32 i = 0; |
351 | 670k | while( i < nValueCount ) |
352 | 663k | { |
353 | 663k | if( *pStates == PropertyState_DIRECT_VALUE ) |
354 | 159k | { |
355 | 159k | *pAPINames++ = aItr->GetApiName(); |
356 | 159k | aPropIters.push_back( aItr ); |
357 | 159k | ++i; |
358 | 159k | } |
359 | 663k | ++aItr; |
360 | 663k | ++pStates; |
361 | 663k | } |
362 | | |
363 | 7.94k | aValues = xMultiPropSet->getPropertyValues( aAPINames ); |
364 | 7.94k | const Any *pValues = aValues.getConstArray(); |
365 | | |
366 | 7.94k | ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator |
367 | 7.94k | pPropIter = aPropIters.begin(); |
368 | | |
369 | 7.94k | XMLPropertyState aNewProperty( -1 ); |
370 | 167k | for( i = 0; i < nValueCount; ++i ) |
371 | 159k | { |
372 | 159k | aNewProperty.mnIndex = -1; |
373 | 159k | aNewProperty.maValue = *pValues; |
374 | | |
375 | 159k | for (auto const& index : (*pPropIter)->GetIndexes()) |
376 | 197k | { |
377 | 197k | aNewProperty.mnIndex = index; |
378 | 197k | aPropStates.AddPropertyState( aNewProperty ); |
379 | 197k | } |
380 | | |
381 | 159k | ++pPropIter; |
382 | 159k | ++pValues; |
383 | 159k | } |
384 | 7.94k | } |
385 | 15.3k | } |
386 | 237 | else |
387 | 237 | { |
388 | 237 | aValues = xMultiPropSet->getPropertyValues( rApiNames ); |
389 | 237 | const Any *pValues = aValues.getConstArray(); |
390 | | |
391 | 237 | FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); |
392 | 474 | for (size_t i = 0; i < aPropInfos.size(); ++i) |
393 | 237 | { |
394 | | // The value is stored in the PropertySet itself, add to list. |
395 | 237 | XMLPropertyState aNewProperty( -1 ); |
396 | 237 | aNewProperty.maValue = *pValues; |
397 | 237 | ++pValues; |
398 | 237 | for (auto const& index : aItr->GetIndexes()) |
399 | 237 | { |
400 | 237 | aNewProperty.mnIndex = index; |
401 | 237 | aPropStates.AddPropertyState( aNewProperty ); |
402 | 237 | } |
403 | 237 | ++aItr; |
404 | 237 | } |
405 | 237 | } |
406 | 15.5k | } |
407 | 126 | else |
408 | 126 | { |
409 | 126 | FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); |
410 | 10.2k | for (size_t i = 0; i < aPropInfos.size(); ++i) |
411 | 10.1k | { |
412 | 10.1k | bool bDirectValue = |
413 | 10.1k | !pStates || *pStates == PropertyState_DIRECT_VALUE; |
414 | 10.1k | if( bDirectValue || bDefault ) |
415 | 8.85k | { |
416 | | // The value is stored in the PropertySet itself, add to list. |
417 | 8.85k | bool bGotValue = false; |
418 | 8.85k | XMLPropertyState aNewProperty( -1 ); |
419 | 8.85k | for (auto const& index : aItr->GetIndexes()) |
420 | 10.3k | { |
421 | 10.3k | if( bDirectValue || |
422 | 8.86k | (rPropMapper->GetEntryFlags(index) & |
423 | 8.86k | MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 ) |
424 | 2.53k | { |
425 | 2.53k | try |
426 | 2.53k | { |
427 | 2.53k | if( !bGotValue ) |
428 | 1.89k | { |
429 | 1.89k | aNewProperty.maValue = |
430 | 1.89k | rPropSet->getPropertyValue( aItr->GetApiName() ); |
431 | 1.89k | bGotValue = true; |
432 | 1.89k | } |
433 | 2.53k | aNewProperty.mnIndex = index; |
434 | 2.53k | aPropStates.AddPropertyState( aNewProperty ); |
435 | 2.53k | } |
436 | 2.53k | catch( UnknownPropertyException& ) |
437 | 2.53k | { |
438 | | // might be a problem of getImplementationId |
439 | 0 | TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyValue" ); |
440 | 0 | } |
441 | | |
442 | 2.53k | } |
443 | 10.3k | } |
444 | 8.85k | } |
445 | | |
446 | 10.1k | ++aItr; |
447 | 10.1k | if( pStates ) |
448 | 10.1k | ++pStates; |
449 | 10.1k | } |
450 | 126 | } |
451 | 15.6k | } |
452 | 15.6k | aPropStates.FillPropertyStateVector(rPropStates); |
453 | 15.6k | } |
454 | | |
455 | | } |
456 | | |
457 | | struct SvXMLExportPropertyMapper::Impl |
458 | | { |
459 | | typedef std::map<css::uno::Reference<css::beans::XPropertySetInfo>, std::unique_ptr<FilterPropertiesInfo_Impl>> CacheType; |
460 | | CacheType maCache; |
461 | | |
462 | | rtl::Reference<SvXMLExportPropertyMapper> mxNextMapper; |
463 | | rtl::Reference<XMLPropertySetMapper> mxPropMapper; |
464 | | |
465 | | OUString maStyleName; |
466 | | }; |
467 | | |
468 | | // ctor/dtor , class SvXMLExportPropertyMapper |
469 | | |
470 | | SvXMLExportPropertyMapper::SvXMLExportPropertyMapper( |
471 | | const rtl::Reference< XMLPropertySetMapper >& rMapper ) : |
472 | 1.37k | mpImpl(new Impl) |
473 | 1.37k | { |
474 | 1.37k | mpImpl->mxPropMapper = rMapper; |
475 | 1.37k | } |
476 | | |
477 | | SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper() |
478 | 1.37k | { |
479 | 1.37k | } |
480 | | |
481 | | void SvXMLExportPropertyMapper::ChainExportMapper( |
482 | | const rtl::Reference< SvXMLExportPropertyMapper>& rMapper ) |
483 | 329 | { |
484 | | // add map entries from rMapper to current map |
485 | 329 | mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() ); |
486 | | // rMapper uses the same map as 'this' |
487 | 329 | rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper; |
488 | | |
489 | | // set rMapper as last mapper in current chain |
490 | 329 | rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper; |
491 | 329 | if( xNext.is()) |
492 | 126 | { |
493 | 126 | while (xNext->mpImpl->mxNextMapper.is()) |
494 | 0 | xNext = xNext->mpImpl->mxNextMapper; |
495 | 126 | xNext->mpImpl->mxNextMapper = rMapper; |
496 | 126 | } |
497 | 203 | else |
498 | 203 | mpImpl->mxNextMapper = rMapper; |
499 | | |
500 | | // if rMapper was already chained, correct |
501 | | // map pointer of successors |
502 | 329 | xNext = rMapper; |
503 | | |
504 | 329 | while (xNext->mpImpl->mxNextMapper.is()) |
505 | 0 | { |
506 | 0 | xNext = xNext->mpImpl->mxNextMapper; |
507 | 0 | xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper; |
508 | 0 | } |
509 | 329 | } |
510 | | |
511 | | std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter( |
512 | | SvXMLExport const& rExport, |
513 | | const uno::Reference<beans::XPropertySet>& rPropSet, bool bEnableFoFontFamily ) const |
514 | 15.6k | { |
515 | 15.6k | return Filter_(rExport, rPropSet, false, bEnableFoFontFamily); |
516 | 15.6k | } |
517 | | |
518 | | std::vector<XMLPropertyState> SvXMLExportPropertyMapper::FilterDefaults( |
519 | | SvXMLExport const& rExport, |
520 | | const uno::Reference<beans::XPropertySet>& rPropSet ) const |
521 | 49 | { |
522 | 49 | return Filter_(rExport, rPropSet, true, false/*bEnableFoFontFamily*/); |
523 | 49 | } |
524 | | |
525 | | std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter_( |
526 | | SvXMLExport const& rExport, |
527 | | const Reference<XPropertySet>& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const |
528 | 15.6k | { |
529 | 15.6k | std::vector< XMLPropertyState > aPropStateArray; |
530 | | |
531 | | // Retrieve XPropertySetInfo and XPropertyState |
532 | 15.6k | Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() ); |
533 | 15.6k | if( !xInfo.is() ) |
534 | 0 | return aPropStateArray; |
535 | | |
536 | 15.6k | sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount(); |
537 | | |
538 | 15.6k | FilterPropertiesInfo_Impl *pFilterInfo = nullptr; |
539 | | |
540 | 15.6k | Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo); |
541 | 15.6k | if (aIter != mpImpl->maCache.end()) |
542 | 15.1k | pFilterInfo = (*aIter).second.get(); |
543 | | |
544 | 15.6k | bool bDelInfo = false; |
545 | 15.6k | if( !pFilterInfo ) |
546 | 532 | { |
547 | 532 | assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN); |
548 | 532 | const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion()); |
549 | 532 | pFilterInfo = new FilterPropertiesInfo_Impl; |
550 | 101k | for( sal_Int32 i=0; i < nProps; i++ ) |
551 | 101k | { |
552 | | // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..) |
553 | | // Does the PropertySet contain name of mpEntries-array ? |
554 | 101k | const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i ); |
555 | 101k | const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i ); |
556 | 101k | if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) && |
557 | 100k | ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) || |
558 | 100k | xInfo->hasPropertyByName( rAPIName ) ) ) |
559 | 54.1k | { |
560 | 54.1k | const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport( |
561 | 54.1k | mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i)); |
562 | | // note: only standard ODF versions are allowed here, |
563 | | // only exception is the unknown future |
564 | 54.1k | assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0 |
565 | 54.1k | || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); |
566 | 54.1k | static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); |
567 | | /// standard ODF namespaces for elements and attributes |
568 | 54.1k | static const sal_uInt16 s_OdfNs[] = { |
569 | 54.1k | XML_NAMESPACE_OFFICE, |
570 | 54.1k | XML_NAMESPACE_STYLE, |
571 | 54.1k | XML_NAMESPACE_TEXT, |
572 | 54.1k | XML_NAMESPACE_TABLE, |
573 | 54.1k | XML_NAMESPACE_DRAW, |
574 | 54.1k | XML_NAMESPACE_FO, |
575 | 54.1k | XML_NAMESPACE_XLINK, |
576 | 54.1k | XML_NAMESPACE_DC, |
577 | 54.1k | XML_NAMESPACE_META, |
578 | 54.1k | XML_NAMESPACE_NUMBER, |
579 | 54.1k | XML_NAMESPACE_PRESENTATION, |
580 | 54.1k | XML_NAMESPACE_SVG, |
581 | 54.1k | XML_NAMESPACE_CHART, |
582 | 54.1k | XML_NAMESPACE_DR3D, |
583 | 54.1k | XML_NAMESPACE_MATH, |
584 | 54.1k | XML_NAMESPACE_FORM, |
585 | 54.1k | XML_NAMESPACE_SCRIPT, |
586 | 54.1k | XML_NAMESPACE_CONFIG, |
587 | 54.1k | XML_NAMESPACE_DB, |
588 | 54.1k | XML_NAMESPACE_XFORMS, |
589 | 54.1k | XML_NAMESPACE_SMIL, |
590 | 54.1k | XML_NAMESPACE_ANIMATION, |
591 | 54.1k | XML_NAMESPACE_XML, |
592 | 54.1k | XML_NAMESPACE_XHTML, |
593 | 54.1k | XML_NAMESPACE_GRDDL, |
594 | 54.1k | }; |
595 | 54.1k | static bool s_Assert(false); |
596 | 54.1k | if (!s_Assert) |
597 | 1 | { |
598 | 1 | assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); |
599 | 1 | s_Assert = true; |
600 | 1 | } |
601 | | //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); |
602 | 54.1k | auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i)); |
603 | 54.1k | auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs), |
604 | 54.1k | ns)); |
605 | 54.1k | bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns |
606 | | // FIXME: very special hack to suppress style:hyperlink |
607 | 45.9k | || (ns == XML_NAMESPACE_STYLE |
608 | 21.1k | && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK))); |
609 | 54.1k | if (isExtension |
610 | 54.1k | ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED) |
611 | | // if it's in standard ODF, don't export extension |
612 | 8.19k | && (nCurrentVersion < nEarliestODFVersionForExport)) |
613 | 54.1k | : (nEarliestODFVersionForExport <= nCurrentVersion)) |
614 | 54.1k | { |
615 | 54.1k | pFilterInfo->AddProperty(rAPIName, i); |
616 | 54.1k | } |
617 | 54.1k | } |
618 | 101k | } |
619 | | |
620 | | // Check whether the property set info is destroyed if it is assigned to |
621 | | // a weak reference only; If it is destroyed, then every instance of |
622 | | // getPropertySetInfo returns a new object; such property set infos must |
623 | | // not be cached: |
624 | 532 | WeakReference < XPropertySetInfo > xWeakInfo( xInfo ); |
625 | 532 | xInfo.clear(); |
626 | 532 | xInfo = xWeakInfo; |
627 | 532 | if( xInfo.is() ) |
628 | 532 | { |
629 | 532 | mpImpl->maCache.emplace(xInfo, std::unique_ptr<FilterPropertiesInfo_Impl>(pFilterInfo)); |
630 | 532 | } |
631 | 0 | else |
632 | 0 | bDelInfo = true; |
633 | 532 | } |
634 | | |
635 | 15.6k | if( pFilterInfo->GetPropertyCount() ) |
636 | 15.6k | { |
637 | 15.6k | try |
638 | 15.6k | { |
639 | 15.6k | pFilterInfo->FillPropertyStateArray( |
640 | 15.6k | aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault); |
641 | 15.6k | } |
642 | 15.6k | catch( UnknownPropertyException& ) |
643 | 15.6k | { |
644 | | // might be a problem of getImplementationId |
645 | 0 | TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyStates" ); |
646 | 0 | } |
647 | 15.6k | } |
648 | | |
649 | | // Call context-filter |
650 | 15.6k | if( !aPropStateArray.empty() ) |
651 | 8.30k | ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet); |
652 | | |
653 | | // Have to do if we change from a vector to a list or something like that |
654 | | |
655 | 15.6k | if( bDelInfo ) |
656 | 0 | delete pFilterInfo; |
657 | | |
658 | 15.6k | return aPropStateArray; |
659 | 15.6k | } |
660 | | |
661 | | void SvXMLExportPropertyMapper::ContextFilter( |
662 | | bool bEnableFoFontFamily, |
663 | | std::vector< XMLPropertyState >& rProperties, |
664 | | const Reference< XPropertySet >& rPropSet ) const |
665 | 11.0k | { |
666 | | // Derived class could implement this. |
667 | 11.0k | if (mpImpl->mxNextMapper.is()) |
668 | 2.74k | mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); |
669 | 11.0k | } |
670 | | |
671 | | // Compares two Sequences of XMLPropertyState: |
672 | | // 1.Number of elements equal ? |
673 | | // 2.Index of each element equal ? (So I know whether the propertynames are the same) |
674 | | // 3.Value of each element equal ? |
675 | | bool SvXMLExportPropertyMapper::Equals( |
676 | | const std::vector< XMLPropertyState >& aProperties1, |
677 | | const std::vector< XMLPropertyState >& aProperties2 ) const |
678 | 9.18k | { |
679 | 9.18k | if (aProperties1.size() < aProperties2.size()) |
680 | 0 | return true; |
681 | 9.18k | if (aProperties1.size() > aProperties2.size()) |
682 | 0 | return false; |
683 | | |
684 | 9.18k | sal_uInt32 nCount = aProperties1.size(); |
685 | | |
686 | 223k | for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) |
687 | 217k | { |
688 | 217k | const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; |
689 | 217k | const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; |
690 | | |
691 | | // Compare index. If equal, compare value |
692 | 217k | if( rProp1.mnIndex < rProp2.mnIndex ) |
693 | 0 | return true; |
694 | 217k | if( rProp1.mnIndex > rProp2.mnIndex ) |
695 | 0 | return false; |
696 | | |
697 | 217k | if( rProp1.mnIndex != -1 ) |
698 | 155k | { |
699 | | // Now compare values |
700 | 155k | if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & |
701 | 155k | XML_TYPE_BUILDIN_CMP ) != 0 ) |
702 | 64.0k | { |
703 | | // simple type ( binary compare ) |
704 | 64.0k | if ( rProp1.maValue != rProp2.maValue) |
705 | 0 | return false; |
706 | 64.0k | } |
707 | 91.8k | else |
708 | 91.8k | { |
709 | | // complex type ( ask for compare-function ) |
710 | 91.8k | if (!mpImpl->mxPropMapper->GetPropertyHandler( |
711 | 91.8k | rProp1.mnIndex )->equals( rProp1.maValue, |
712 | 91.8k | rProp2.maValue )) |
713 | 2.84k | return false; |
714 | 91.8k | } |
715 | 155k | } |
716 | 217k | } |
717 | | |
718 | 6.34k | return true; |
719 | 9.18k | } |
720 | | |
721 | | // Compares two Sequences of XMLPropertyState: |
722 | | // 1.Number of elements equal ? |
723 | | // 2.Index of each element equal ? (So I know whether the propertynames are the same) |
724 | | // 3.Value of each element equal ? |
725 | | bool SvXMLExportPropertyMapper::LessPartial( |
726 | | const std::vector< XMLPropertyState >& aProperties1, |
727 | | const std::vector< XMLPropertyState >& aProperties2 ) const |
728 | 33.6k | { |
729 | 33.6k | if (aProperties1.size() < aProperties2.size()) |
730 | 11.0k | return true; |
731 | 22.5k | if (aProperties1.size() > aProperties2.size()) |
732 | 4.22k | return false; |
733 | | |
734 | 18.3k | sal_uInt32 nCount = aProperties1.size(); |
735 | | |
736 | 479k | for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) |
737 | 464k | { |
738 | 464k | const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; |
739 | 464k | const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; |
740 | | |
741 | | // Compare index. If equal, compare value |
742 | 464k | if( rProp1.mnIndex < rProp2.mnIndex ) |
743 | 0 | return true; |
744 | 464k | if( rProp1.mnIndex > rProp2.mnIndex ) |
745 | 0 | return false; |
746 | | |
747 | 464k | if( rProp1.mnIndex != -1 ) |
748 | 336k | { |
749 | | // Now compare values |
750 | 336k | if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & |
751 | 336k | XML_TYPE_BUILDIN_CMP ) != 0 ) |
752 | 132k | { |
753 | | // simple type ( binary compare ) |
754 | 132k | if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) ) |
755 | 2.63k | return true; |
756 | 129k | if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) ) |
757 | 939 | return false; |
758 | 129k | } |
759 | 336k | } |
760 | 464k | } |
761 | | |
762 | 14.7k | return false; |
763 | 18.3k | } |
764 | | |
765 | | /** fills the given attribute list with the items in the given set |
766 | | void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, |
767 | | const ::std::vector< XMLPropertyState >& rProperties, |
768 | | const SvXMLUnitConverter& rUnitConverter, |
769 | | const SvXMLNamespaceMap& rNamespaceMap, |
770 | | sal_uInt16 nFlags ) const |
771 | | { |
772 | | _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, |
773 | | nFlags, 0, -1, -1 ); |
774 | | } |
775 | | |
776 | | void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, |
777 | | const ::std::vector< XMLPropertyState >& rProperties, |
778 | | const SvXMLUnitConverter& rUnitConverter, |
779 | | const SvXMLNamespaceMap& rNamespaceMap, |
780 | | sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, |
781 | | sal_uInt16 nFlags ) const |
782 | | { |
783 | | _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, |
784 | | nFlags, 0, nPropMapStartIdx, nPropMapEndIdx ); |
785 | | } |
786 | | */ |
787 | | |
788 | | void SvXMLExportPropertyMapper::exportXML( |
789 | | SvXMLExport& rExport, |
790 | | const ::std::vector< XMLPropertyState >& rProperties, |
791 | | SvXmlExportFlags nFlags, |
792 | | bool bUseExtensionNamespaceForGraphicProperties) const |
793 | 1.37k | { |
794 | 1.37k | exportXML(rExport, rProperties, -1, -1, nFlags, bUseExtensionNamespaceForGraphicProperties); |
795 | 1.37k | } |
796 | | |
797 | | |
798 | | void SvXMLExportPropertyMapper::exportXML( |
799 | | SvXMLExport& rExport, |
800 | | const ::std::vector< XMLPropertyState >& rProperties, |
801 | | sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, |
802 | | SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const |
803 | 1.88k | { |
804 | 1.88k | sal_uInt16 nPropTypeFlags = 0; |
805 | 28.3k | for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i ) |
806 | 26.4k | { |
807 | 26.4k | sal_uInt16 nPropType = aPropTokens[i].nType; |
808 | 26.4k | if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 ) |
809 | 4.99k | { |
810 | 4.99k | sal_uInt16 nNamespace = XML_NAMESPACE_STYLE; |
811 | 4.99k | if (bUseExtensionNamespaceForGraphicProperties && |
812 | 660 | aPropTokens[i].eToken == xmloff::token::XML_GRAPHIC_PROPERTIES) |
813 | 152 | { |
814 | 152 | nNamespace = XML_NAMESPACE_LO_EXT; |
815 | 152 | if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) |
816 | 0 | { |
817 | 0 | continue; // don't write for ODF <= 1.2 |
818 | 0 | } |
819 | 152 | } |
820 | | |
821 | 4.99k | std::vector<sal_uInt16> aIndexArray; |
822 | | |
823 | 4.99k | _exportXML( nPropType, nPropTypeFlags, |
824 | 4.99k | rExport.GetAttrList(), rProperties, |
825 | 4.99k | rExport.GetMM100UnitConverter(), |
826 | 4.99k | rExport.GetNamespaceMap(), |
827 | 4.99k | &aIndexArray, |
828 | 4.99k | nPropMapStartIdx, nPropMapEndIdx ); |
829 | | |
830 | 4.99k | if( rExport.GetAttrList().getLength() > 0 || |
831 | 1.93k | !aIndexArray.empty() ) |
832 | 3.06k | { |
833 | 3.06k | SvXMLElementExport aElem( rExport, nNamespace, |
834 | 3.06k | aPropTokens[i].eToken, |
835 | 3.06k | bool(nFlags & SvXmlExportFlags::IGN_WS), |
836 | 3.06k | false ); |
837 | | |
838 | 3.06k | exportElementItems( rExport, rProperties, nFlags, aIndexArray ); |
839 | 3.06k | } |
840 | 4.99k | } |
841 | 26.4k | } |
842 | 1.88k | } |
843 | | |
844 | | /** this method is called for every item that has the |
845 | | MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ |
846 | | void SvXMLExportPropertyMapper::handleSpecialItem( |
847 | | comphelper::AttributeList& rAttrList, |
848 | | const XMLPropertyState& rProperty, |
849 | | const SvXMLUnitConverter& rUnitConverter, |
850 | | const SvXMLNamespaceMap& rNamespaceMap, |
851 | | const ::std::vector< XMLPropertyState > *pProperties, |
852 | | sal_uInt32 nIdx ) const |
853 | 0 | { |
854 | 0 | if (mpImpl->mxNextMapper.is()) |
855 | 0 | { |
856 | 0 | mpImpl->mxNextMapper->handleSpecialItem( |
857 | 0 | rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx); |
858 | 0 | return; |
859 | 0 | } |
860 | | // An empty Any (e.g. unset UserDefinedAttributes / ChartUserDefinedAttributes) |
861 | | // or a null XNameContainer reference means there is nothing to export; this |
862 | | // is a normal state, not a missing-handler bug. |
863 | 0 | if (!rProperty.maValue.hasValue() |
864 | 0 | || rProperty.maValue.getValueTypeClass() == uno::TypeClass_INTERFACE) |
865 | 0 | return; |
866 | 0 | SAL_WARN("xmloff.style", |
867 | 0 | "special item not handled in xml export: index=" << rProperty.mnIndex |
868 | 0 | << " ns=" << mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex) |
869 | 0 | << " xmlName=" << mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex) |
870 | 0 | << " apiName=" << mpImpl->mxPropMapper->GetEntryAPIName(rProperty.mnIndex)); |
871 | 0 | } |
872 | | |
873 | | /** this method is called for every item that has the |
874 | | MID_FLAG_ELEMENT_EXPORT flag set */ |
875 | | void SvXMLExportPropertyMapper::handleElementItem( |
876 | | SvXMLExport& rExport, |
877 | | const XMLPropertyState& rProperty, |
878 | | SvXmlExportFlags nFlags, |
879 | | const ::std::vector< XMLPropertyState > *pProperties, |
880 | | sal_uInt32 nIdx ) const |
881 | 802 | { |
882 | 802 | OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export"); |
883 | 802 | if (mpImpl->mxNextMapper.is()) |
884 | 802 | mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx); |
885 | 802 | } |
886 | | |
887 | | // protected methods |
888 | | |
889 | | /** fills the given attribute list with the items in the given set */ |
890 | | void SvXMLExportPropertyMapper::_exportXML( |
891 | | sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags, |
892 | | comphelper::AttributeList& rAttrList, |
893 | | const ::std::vector< XMLPropertyState >& rProperties, |
894 | | const SvXMLUnitConverter& rUnitConverter, |
895 | | const SvXMLNamespaceMap& rNamespaceMap, |
896 | | std::vector<sal_uInt16>* pIndexArray, |
897 | | sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const |
898 | 4.99k | { |
899 | 4.99k | const sal_uInt32 nCount = rProperties.size(); |
900 | 4.99k | sal_uInt32 nIndex = 0; |
901 | | |
902 | 4.99k | if( -1 == nPropMapStartIdx ) |
903 | 4.99k | nPropMapStartIdx = 0; |
904 | 4.99k | if( -1 == nPropMapEndIdx ) |
905 | 4.99k | nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount(); |
906 | | |
907 | 78.5k | while( nIndex < nCount ) |
908 | 73.5k | { |
909 | 73.5k | sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex; |
910 | 73.5k | if( nPropMapIdx >= nPropMapStartIdx && |
911 | 59.3k | nPropMapIdx < nPropMapEndIdx )// valid entry? |
912 | 59.3k | { |
913 | 59.3k | sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx); |
914 | 59.3k | sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags); |
915 | 59.3k | OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT), |
916 | 59.3k | "no prop type specified"); |
917 | 59.3k | rPropTypeFlags |= (1 << nEPType); |
918 | 59.3k | if( nEPType == nPropType ) |
919 | 19.9k | { |
920 | | // we have a valid map entry here, so let's use it... |
921 | 19.9k | if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 ) |
922 | 953 | { |
923 | | // element items do not add any properties, |
924 | | // we export it later |
925 | 953 | if( pIndexArray ) |
926 | 953 | { |
927 | 953 | pIndexArray->push_back( static_cast<sal_uInt16>(nIndex) ); |
928 | 953 | } |
929 | 953 | } |
930 | 19.0k | else |
931 | 19.0k | { |
932 | 19.0k | _exportXML( rAttrList, rProperties[nIndex], rUnitConverter, |
933 | 19.0k | rNamespaceMap, &rProperties, nIndex ); |
934 | 19.0k | } |
935 | 19.9k | } |
936 | 59.3k | } |
937 | | |
938 | 73.5k | nIndex++; |
939 | 73.5k | } |
940 | 4.99k | } |
941 | | |
942 | | namespace |
943 | | { |
944 | | // -1 = Attribute needs extended namespace, but current ODF version is strict. |
945 | | // 1 = Attribute needs extended namespace and current ODF version allows it. |
946 | | // 0 = Attribute does not need extended namespace |
947 | | sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue, |
948 | | const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion) |
949 | 15.7k | { |
950 | 15.7k | if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE) |
951 | 88 | && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90))) |
952 | 0 | return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; |
953 | 15.7k | else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL) |
954 | 0 | && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM) |
955 | 0 | || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP))) |
956 | 0 | return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; |
957 | | // don't export end zones when they have the default no-limit value |
958 | 15.7k | else if (IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_ALWAYS) |
959 | 15.7k | || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_COLUMN) |
960 | 15.7k | || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_PAGE) |
961 | 15.7k | || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_SPREAD)) |
962 | 0 | return IsXMLToken(sValue, XML_NO_LIMIT) ? -1 : 1; |
963 | | // don't export word spacing and glyph scaling when they have the default 100% value |
964 | 15.7k | else if (IsXMLToken(sXMLAttributeName, XML_WORD_SPACING) |
965 | 15.7k | || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MINIMUM) |
966 | 15.6k | || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MAXIMUM) |
967 | 15.6k | || IsXMLToken(sXMLAttributeName, XML_TEXT_SCALE_MINIMUM) |
968 | 15.5k | || IsXMLToken(sXMLAttributeName, XML_TEXT_SCALE_MAXIMUM)) |
969 | 250 | { |
970 | 250 | static constexpr OUString s100PercentCompare( u"100%"_ustr ); |
971 | 250 | size_t nBegin = sValue.find( s100PercentCompare ); |
972 | 250 | return nBegin != std::u16string_view::npos ? -1 : 1; |
973 | 250 | } |
974 | | // don't export letter spacing when they have the default 0% value |
975 | 15.5k | else if (IsXMLToken(sXMLAttributeName, XML_LETTER_SPACING_MINIMUM) |
976 | 15.4k | || IsXMLToken(sXMLAttributeName, XML_LETTER_SPACING_MAXIMUM)) |
977 | 100 | { |
978 | 100 | static constexpr OUString sDefaultPercentCompare( u"0%"_ustr ); |
979 | 100 | size_t nBegin = sValue.find( sDefaultPercentCompare ); |
980 | 100 | return nBegin == static_cast<size_t>(0) ? -1 : 1; |
981 | 100 | } |
982 | 15.4k | return 0; |
983 | 15.7k | } |
984 | | } |
985 | | |
986 | | void SvXMLExportPropertyMapper::_exportXML( |
987 | | comphelper::AttributeList& rAttrList, |
988 | | const XMLPropertyState& rProperty, |
989 | | const SvXMLUnitConverter& rUnitConverter, |
990 | | const SvXMLNamespaceMap& rNamespaceMap, |
991 | | const ::std::vector< XMLPropertyState > *pProperties, |
992 | | sal_uInt32 nIdx ) const |
993 | 19.0k | { |
994 | 19.0k | if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0) |
995 | 98 | { |
996 | 98 | uno::Reference< container::XNameContainer > xAttrContainer; |
997 | 98 | if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() ) |
998 | 98 | { |
999 | 98 | std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap; |
1000 | 98 | const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap; |
1001 | | |
1002 | 98 | const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() ); |
1003 | | |
1004 | 98 | xml::AttributeData aData; |
1005 | 98 | for( const auto& rAttribName : aAttribNames ) |
1006 | 0 | { |
1007 | 0 | xAttrContainer->getByName( rAttribName ) >>= aData; |
1008 | 0 | OUString sAttribName( rAttribName ); |
1009 | | |
1010 | | // extract namespace prefix from attribute name if it exists |
1011 | 0 | OUString sPrefix; |
1012 | 0 | const sal_Int32 nColonPos = |
1013 | 0 | rAttribName.indexOf( ':' ); |
1014 | 0 | if( nColonPos != -1 ) |
1015 | 0 | sPrefix = rAttribName.copy( 0, nColonPos ); |
1016 | |
|
1017 | 0 | if( !sPrefix.isEmpty() ) |
1018 | 0 | { |
1019 | 0 | OUString sNamespace( aData.Namespace ); |
1020 | | |
1021 | | // if the prefix isn't defined yet or has another meaning, |
1022 | | // we have to redefine it now. |
1023 | 0 | sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); |
1024 | 0 | if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace ) |
1025 | 0 | { |
1026 | 0 | bool bAddNamespace = false; |
1027 | 0 | if( USHRT_MAX == nKey ) |
1028 | 0 | { |
1029 | | // The prefix is unused, so it is sufficient |
1030 | | // to add it to the namespace map. |
1031 | 0 | bAddNamespace = true; |
1032 | 0 | } |
1033 | 0 | else |
1034 | 0 | { |
1035 | | // check if there is a prefix registered for the |
1036 | | // namespace URI |
1037 | 0 | nKey = pNamespaceMap->GetKeyByName( sNamespace ); |
1038 | 0 | if( XML_NAMESPACE_UNKNOWN == nKey ) |
1039 | 0 | { |
1040 | | // There is no prefix for the namespace, so |
1041 | | // we have to generate one and have to add it. |
1042 | 0 | sal_Int32 n=0; |
1043 | 0 | OUString sOrigPrefix( sPrefix ); |
1044 | 0 | do |
1045 | 0 | { |
1046 | 0 | sPrefix = sOrigPrefix + OUString::number( ++n ); |
1047 | 0 | nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); |
1048 | 0 | } |
1049 | 0 | while( nKey != USHRT_MAX ); |
1050 | |
|
1051 | 0 | bAddNamespace = true; |
1052 | 0 | } |
1053 | 0 | else |
1054 | 0 | { |
1055 | | // If there is a prefix for the namespace, |
1056 | | // we reuse that. |
1057 | 0 | sPrefix = pNamespaceMap->GetPrefixByKey( nKey ); |
1058 | 0 | } |
1059 | | // In any case, the attribute name has to be adapted. |
1060 | 0 | sAttribName = sPrefix + ":" + rAttribName.subView(nColonPos+1); |
1061 | 0 | } |
1062 | |
|
1063 | 0 | if( bAddNamespace ) |
1064 | 0 | { |
1065 | 0 | if( !pNewNamespaceMap ) |
1066 | 0 | { |
1067 | 0 | pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap )); |
1068 | 0 | pNamespaceMap = pNewNamespaceMap.get(); |
1069 | 0 | } |
1070 | 0 | pNewNamespaceMap->Add( sPrefix, sNamespace ); |
1071 | 0 | OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix; |
1072 | 0 | rAttrList.AddAttribute( sAttr, sNamespace ); |
1073 | 0 | } |
1074 | 0 | } |
1075 | 0 | } |
1076 | 0 | OUString sOldValue( rAttrList.getValueByName( sAttribName ) ); |
1077 | 0 | OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" ); |
1078 | 0 | OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out"); |
1079 | 0 | if( sOldValue.isEmpty() ) |
1080 | 0 | rAttrList.AddAttribute( sAttribName, aData.Value ); |
1081 | 0 | } |
1082 | 98 | } |
1083 | 0 | else |
1084 | 0 | { |
1085 | 0 | handleSpecialItem( rAttrList, rProperty, rUnitConverter, |
1086 | 0 | rNamespaceMap, pProperties, nIdx ); |
1087 | 0 | } |
1088 | 98 | } |
1089 | 18.9k | else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0) |
1090 | 18.9k | { |
1091 | 18.9k | OUString aValue; |
1092 | 18.9k | OUString sName = rNamespaceMap.GetQNameByKey( |
1093 | 18.9k | mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex), |
1094 | 18.9k | mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); |
1095 | | |
1096 | 18.9k | bool bRemove = false; |
1097 | 18.9k | if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0) |
1098 | 253 | { |
1099 | 253 | aValue = rAttrList.getValueByName( sName ); |
1100 | 253 | bRemove = true; |
1101 | 253 | } |
1102 | | |
1103 | 18.9k | if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter)) |
1104 | 15.7k | { |
1105 | 15.7k | if( bRemove ) |
1106 | 253 | rAttrList.RemoveAttribute( sName ); |
1107 | | |
1108 | | // We don't seem to have a generic mechanism to write an attribute in the extension |
1109 | | // namespace in case of certain attribute values only, so do this manually. |
1110 | 15.7k | sal_Int8 nExtendedStatus |
1111 | 15.7k | = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), |
1112 | 15.7k | aValue, rUnitConverter.getSaneDefaultVersion()); |
1113 | 15.7k | if (nExtendedStatus == -1) |
1114 | 350 | return; |
1115 | 15.4k | if (nExtendedStatus == 1) |
1116 | 0 | sName = rNamespaceMap.GetQNameByKey( |
1117 | 0 | XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); |
1118 | 15.4k | rAttrList.AddAttribute( sName, aValue ); |
1119 | 15.4k | } |
1120 | 18.9k | } |
1121 | 19.0k | } |
1122 | | |
1123 | | void SvXMLExportPropertyMapper::exportElementItems( |
1124 | | SvXMLExport& rExport, |
1125 | | const ::std::vector< XMLPropertyState >& rProperties, |
1126 | | SvXmlExportFlags nFlags, |
1127 | | const std::vector<sal_uInt16>& rIndexArray ) const |
1128 | 3.06k | { |
1129 | 3.06k | bool bItemsExported = false; |
1130 | 3.06k | for (const sal_uInt16 nElement : rIndexArray) |
1131 | 953 | { |
1132 | 953 | OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags( |
1133 | 953 | rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT), |
1134 | 953 | "wrong mid flag!" ); |
1135 | | |
1136 | 953 | rExport.IgnorableWhitespace(); |
1137 | 953 | handleElementItem( rExport, rProperties[nElement], |
1138 | 953 | nFlags, &rProperties, nElement ); |
1139 | 953 | bItemsExported = true; |
1140 | 953 | } |
1141 | | |
1142 | 3.06k | if( bItemsExported ) |
1143 | 855 | rExport.IgnorableWhitespace(); |
1144 | 3.06k | } |
1145 | | |
1146 | | const rtl::Reference<XMLPropertySetMapper>& SvXMLExportPropertyMapper::getPropertySetMapper() const |
1147 | 228k | { |
1148 | 228k | return mpImpl->mxPropMapper; |
1149 | 228k | } |
1150 | | |
1151 | | void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName ) |
1152 | 2.64k | { |
1153 | 2.64k | mpImpl->maStyleName = rStyleName; |
1154 | 2.64k | } |
1155 | | |
1156 | | const OUString& SvXMLExportPropertyMapper::GetStyleName() const |
1157 | 49 | { |
1158 | 49 | return mpImpl->maStyleName; |
1159 | 49 | } |
1160 | | |
1161 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |