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 <com/sun/star/xml/sax/SAXException.hpp>
21 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22 #include <com/sun/star/xml/sax/XAttributeList.hpp>
23 #include <rtl/ustrbuf.hxx>
24 #include <osl/diagnose.h>
25 #include <sax/tools/converter.hxx>
26 #include <xmloff/nmspmap.hxx>
27 #include <xmloff/xmltoken.hxx>
28 #include <xmloff/xmlnmspe.hxx>
29 #include "PropType.hxx"
30 #include "DeepTContext.hxx"
31 #include "TransformerBase.hxx"
32 #include "TransformerActions.hxx"
33 #include "ActionMapTypesOASIS.hxx"
34 #include "MutableAttrList.hxx"
35 #include "PropertyActionsOASIS.hxx"
36 #include "StyleOASISTContext.hxx"
37 #include <xmloff/xmluconv.hxx>
38 
39 using namespace ::xmloff::token;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::xml::sax;
42 
43 static const sal_uInt16 aAttrActionMaps[XML_PROP_TYPE_END] =
44 {
45     PROP_OASIS_GRAPHIC_ATTR_ACTIONS,
46     PROP_OASIS_DRAWING_PAGE_ATTR_ACTIONS,               // DRAWING_PAGE
47     PROP_OASIS_PAGE_LAYOUT_ATTR_ACTIONS,
48     PROP_OASIS_HEADER_FOOTER_ATTR_ACTIONS,
49     PROP_OASIS_TEXT_ATTR_ACTIONS,
50     PROP_OASIS_PARAGRAPH_ATTR_ACTIONS,
51     MAX_OASIS_PROP_ACTIONS,             // RUBY
52     PROP_OASIS_SECTION_ATTR_ACTIONS,
53     PROP_OASIS_TABLE_ATTR_ACTIONS,
54     PROP_OASIS_TABLE_COLUMN_ATTR_ACTIONS,
55     PROP_OASIS_TABLE_ROW_ATTR_ACTIONS,
56     PROP_OASIS_TABLE_CELL_ATTR_ACTIONS,
57     PROP_OASIS_LIST_LEVEL_ATTR_ACTIONS,
58     PROP_OASIS_CHART_ATTR_ACTIONS
59 };
60 
61 class XMLPropertiesTContext_Impl : public XMLPersElemContentTContext
62 {
63     css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList;
64 
65     XMLPropType m_ePropType;
66     bool const  m_bControlStyle;
67 
68 public:
69 
SetQNameAndPropType(const OUString & rQName,XMLPropType ePropType)70     void SetQNameAndPropType( const OUString& rQName,
71                                  XMLPropType ePropType  )
72     {
73         m_ePropType = ePropType;
74         XMLTransformerContext::SetQName( rQName );
75     };
76 
77     XMLPropertiesTContext_Impl( XMLTransformerBase& rTransformer,
78                            const OUString& rQName,
79                            XMLPropType eP,
80                            bool _bControlStyle );
81 
82     virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override;
83 
84     virtual void Export() override;
85 
86     static XMLPropType GetPropType( const OUString& rLocalName );
87 
88     static OUString const & MergeUnderline( XMLTokenEnum eUnderline,
89                                            bool bBold, bool bDouble );
90     static OUString const & MergeLineThrough( XMLTokenEnum eLineThrough,
91                                         bool bBold, bool bDouble,
92                                            sal_Unicode c );
93 };
94 
XMLPropertiesTContext_Impl(XMLTransformerBase & rImp,const OUString & rQName,XMLPropType eP,bool _bControlStyle)95 XMLPropertiesTContext_Impl::XMLPropertiesTContext_Impl(
96     XMLTransformerBase& rImp, const OUString& rQName, XMLPropType eP,
97     bool _bControlStyle ) :
98     XMLPersElemContentTContext( rImp, rQName, XML_NAMESPACE_STYLE,
99                                 XML_PROPERTIES),
100     m_ePropType( eP ),
101     m_bControlStyle( _bControlStyle )
102 {
103 }
104 
StartElement(const Reference<XAttributeList> & rAttrList)105 void XMLPropertiesTContext_Impl::StartElement(
106         const Reference< XAttributeList >& rAttrList )
107 {
108     XMLTransformerActions *pActions =  nullptr;
109     sal_uInt16 nActionMap = aAttrActionMaps[m_ePropType];
110     if( nActionMap < MAX_OASIS_PROP_ACTIONS )
111     {
112         pActions = GetTransformer().GetUserDefinedActions( nActionMap );
113         OSL_ENSURE( pActions, "go no actions" );
114     }
115 
116     if( pActions )
117     {
118         XMLMutableAttributeList *pAttrList = nullptr;
119         if( !m_xAttrList.is() )
120         {
121             pAttrList = new XMLMutableAttributeList();
122             m_xAttrList = pAttrList;
123         }
124         else
125         {
126             pAttrList =
127                 static_cast< XMLMutableAttributeList * >( m_xAttrList.get() );
128         }
129 
130         XMLTokenEnum eUnderline = XML_TOKEN_END;
131         bool bBoldUnderline = false, bDoubleUnderline = false;
132         XMLTokenEnum eLineThrough = XML_TOKEN_END;
133         bool bBoldLineThrough = false, bDoubleLineThrough = false;
134         sal_Unicode cLineThroughChar = 0;
135 
136         bool bIntervalMinorFound = false;
137         double fIntervalMajor = 0.0;
138         sal_Int32 nIntervalMinorDivisor = 0;
139 
140         // #i25616#
141         OUString aOpacityValueRemember;
142         OUString aImageOpacityValueRemember;
143 
144         sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0;
145         for( sal_Int16 i=0; i < nAttrCount; i++ )
146         {
147             const OUString& rAttrName = rAttrList->getNameByIndex( i );
148             const OUString& rAttrValue = rAttrList->getValueByIndex( i );
149             OUString aLocalName;
150             sal_uInt16 nPrefix =
151                 GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName,
152                                                                  &aLocalName );
153 
154             XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
155             XMLTransformerActions::const_iterator aIter =
156                 pActions->find( aKey );
157             if( aIter != pActions->end() )
158             {
159                 switch( (*aIter).second.m_nActionType )
160                 {
161                 case XML_ATACTION_REMOVE:
162                     break;
163                 case XML_ATACTION_COPY:
164                     pAttrList->AddAttribute( rAttrName, rAttrValue );
165                     break;
166                 case XML_ATACTION_RENAME:
167                     {
168                         OUString aNewAttrQName(
169                             GetTransformer().GetNamespaceMap().GetQNameByKey(
170                                 (*aIter).second.GetQNamePrefixFromParam1(),
171                                 ::xmloff::token::GetXMLToken(
172                                 (*aIter).second.GetQNameTokenFromParam1()) ) );
173                         pAttrList->AddAttribute( aNewAttrQName, rAttrValue );
174                     }
175                     break;
176                 case XML_ATACTION_IN2INCH:
177                     {
178                         OUString aAttrValue( rAttrValue );
179                         XMLTransformerBase::ReplaceSingleInWithInch(
180                                 aAttrValue );
181                         pAttrList->AddAttribute( rAttrName, aAttrValue );
182                     }
183                     break;
184                 case XML_ATACTION_INS2INCHS:
185                     {
186                         OUString aAttrValue( rAttrValue );
187                         XMLTransformerBase::ReplaceInWithInch(
188                                 aAttrValue );
189                         pAttrList->AddAttribute( rAttrName, aAttrValue );
190                     }
191                     break;
192                 case XML_ATACTION_DECODE_STYLE_NAME_REF:
193                     {
194                         OUString aAttrValue( rAttrValue );
195                         XMLTransformerBase::DecodeStyleName(aAttrValue);
196                         pAttrList->AddAttribute( rAttrName, aAttrValue );
197                     }
198                     break;
199                 case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF:
200                     {
201                         OUString aNewAttrQName(
202                             GetTransformer().GetNamespaceMap().GetQNameByKey(
203                                 (*aIter).second.GetQNamePrefixFromParam1(),
204                                 ::xmloff::token::GetXMLToken(
205                                 (*aIter).second.GetQNameTokenFromParam1()) ) );
206                         OUString aAttrValue( rAttrValue );
207                         XMLTransformerBase::DecodeStyleName(aAttrValue);
208                         pAttrList->AddAttribute( aNewAttrQName, aAttrValue );
209                     }
210                     break;
211                 case XML_ATACTION_NEG_PERCENT:
212                     {
213                         OUString aAttrValue( rAttrValue );
214                         XMLTransformerBase::NegPercent(aAttrValue);
215                         pAttrList->AddAttribute( rAttrName, aAttrValue );
216                     }
217                     break;
218                 case XML_ATACTION_RENAME_NEG_PERCENT:
219                     {
220                         OUString aNewAttrQName(
221                             GetTransformer().GetNamespaceMap().GetQNameByKey(
222                                 (*aIter).second.GetQNamePrefixFromParam1(),
223                                 ::xmloff::token::GetXMLToken(
224                                 (*aIter).second.GetQNameTokenFromParam1()) ) );
225                         OUString aAttrValue( rAttrValue );
226                         XMLTransformerBase::NegPercent(aAttrValue);
227                         pAttrList->AddAttribute( aNewAttrQName, aAttrValue );
228                     }
229                     break;
230                 case XML_OPTACTION_LINE_MODE:
231                     {
232                         bool bWordMode =
233                             IsXMLToken( rAttrValue, XML_SKIP_WHITE_SPACE );
234                         OUString aAttrQName(
235                             GetTransformer().GetNamespaceMap().GetQNameByKey(
236                                 XML_NAMESPACE_FO,
237                                 GetXMLToken( XML_SCORE_SPACES ) ) );
238                         sal_Int16 nIndex =
239                             pAttrList->GetIndexByName( aAttrQName );
240                         if( -1 != nIndex )
241                         {
242                             if( bWordMode )
243                             {
244                                 const OUString& rOldValue =
245                                     pAttrList->getValueByIndex( nIndex );
246                                 if( !IsXMLToken( rOldValue, XML_TRUE ) )
247                                 {
248                                     pAttrList->SetValueByIndex( nIndex,
249                                             GetXMLToken( XML_TRUE ) );
250                                 }
251                             }
252                         }
253                         else
254                         {
255                             const OUString& aAttrValue( GetXMLToken( bWordMode
256                                         ? XML_FALSE
257                                         : XML_TRUE ) );
258                             pAttrList->AddAttribute( aAttrQName, aAttrValue );
259                         }
260                     }
261                     break;
262                 case XML_OPTACTION_KEEP_WITH_NEXT:
263                     {
264                         const OUString& aAttrValue( GetXMLToken(
265                                         IsXMLToken( rAttrValue, XML_ALWAYS )
266                                                     ? XML_TRUE
267                                                     : XML_FALSE) );
268                         pAttrList->AddAttribute( rAttrName, aAttrValue );
269                     }
270                     break;
271                 case XML_OPTACTION_UNDERLINE_WIDTH:
272                     if( IsXMLToken( rAttrValue, XML_BOLD ) )
273                         bBoldUnderline = true;
274                     break;
275                 case XML_OPTACTION_UNDERLINE_TYPE:
276                     if( IsXMLToken( rAttrValue, XML_DOUBLE ) )
277                         bDoubleUnderline = true;
278                     break;
279                 case XML_OPTACTION_UNDERLINE_STYLE:
280                     eUnderline = GetTransformer().GetToken( rAttrValue );
281                     break;
282                 case XML_OPTACTION_LINETHROUGH_WIDTH:
283                     if( IsXMLToken( rAttrValue, XML_BOLD ) )
284                         bBoldLineThrough = true;
285                     break;
286                 case XML_OPTACTION_LINETHROUGH_TYPE:
287                     if( IsXMLToken( rAttrValue, XML_DOUBLE ) )
288                         bDoubleLineThrough = true;
289                     break;
290                 case XML_OPTACTION_LINETHROUGH_STYLE:
291                     eLineThrough = GetTransformer().GetToken( rAttrValue );
292                     break;
293                 case XML_OPTACTION_LINETHROUGH_TEXT:
294                     if( !rAttrValue.isEmpty() )
295                         cLineThroughChar = rAttrValue[0];
296                     break;
297                 case XML_OPTACTION_INTERPOLATION:
298                     {
299                         // 0: none (default)
300                         sal_Int32 nSplineType = 0;
301                         if( IsXMLToken( rAttrValue, XML_CUBIC_SPLINE ))
302                             nSplineType = 1;
303                         else if( IsXMLToken( rAttrValue, XML_B_SPLINE ))
304                             nSplineType = 2;
305 
306                         pAttrList->AddAttribute(
307                             GetTransformer().GetNamespaceMap().GetQNameByKey(
308                                 XML_NAMESPACE_CHART,
309                                 GetXMLToken( XML_SPLINES )),
310                             OUString::number( nSplineType ));
311                     }
312                     break;
313                 case XML_OPTACTION_INTERVAL_MAJOR:
314                     pAttrList->AddAttribute( rAttrName, rAttrValue );
315                     ::sax::Converter::convertDouble(fIntervalMajor, rAttrValue);
316                     break;
317                 case XML_OPTACTION_INTERVAL_MINOR_DIVISOR:
318                     ::sax::Converter::convertNumber(nIntervalMinorDivisor, rAttrValue);
319                     bIntervalMinorFound = true;
320                     break;
321                 case XML_OPTACTION_SYMBOL_TYPE:
322                     {
323                         // if symbol_type is "named-symbol" the "symbol"
324                         // property is set in the action XML_OPTACTION_SYMBOL_NAME
325                         sal_Int32 nSymbolType = 0;
326                         if( IsXMLToken( rAttrValue, XML_NONE ))
327                             nSymbolType = -3;
328                         else if( IsXMLToken( rAttrValue, XML_AUTOMATIC ))
329                             nSymbolType = -2;
330                         else if( IsXMLToken( rAttrValue, XML_IMAGE ))
331                             nSymbolType = -1;
332 
333                         if( nSymbolType < 0 )
334                             pAttrList->AddAttribute(
335                                 GetTransformer().GetNamespaceMap().GetQNameByKey(
336                                     XML_NAMESPACE_CHART,
337                                     GetXMLToken( XML_SYMBOL )),
338                                 OUString::number( nSymbolType ));
339                     }
340                     break;
341                 case XML_OPTACTION_SYMBOL_NAME:
342                     {
343                         // assume "symbol-type" == "named-symbol"
344                         sal_Int32 nSymbolType = -3; // NONE
345                         // "square" just has an awkward token-name
346                         if( IsXMLToken( rAttrValue, XML_GRADIENTSTYLE_SQUARE ))
347                             nSymbolType = 0;
348                         else if( IsXMLToken( rAttrValue, XML_DIAMOND ))
349                             nSymbolType = 1;
350                         else if( IsXMLToken( rAttrValue, XML_ARROW_DOWN ))
351                             nSymbolType = 2;
352                         else if( IsXMLToken( rAttrValue, XML_ARROW_UP ))
353                             nSymbolType = 3;
354                         else if( IsXMLToken( rAttrValue, XML_ARROW_RIGHT ))
355                             nSymbolType = 4;
356                         else if( IsXMLToken( rAttrValue, XML_ARROW_LEFT ))
357                             nSymbolType = 5;
358                         else if( IsXMLToken( rAttrValue, XML_BOW_TIE ))
359                             nSymbolType = 6;
360                         else if( IsXMLToken( rAttrValue, XML_HOURGLASS ))
361                             nSymbolType = 7;
362                         else if( IsXMLToken( rAttrValue, XML_CIRCLE ))
363                             nSymbolType = 8;
364                         else if( IsXMLToken( rAttrValue, XML_STAR ))
365                             nSymbolType = 9;
366                         else if( IsXMLToken( rAttrValue, XML_X ))
367                             nSymbolType = 10;
368                         else if( IsXMLToken( rAttrValue, XML_PLUS ))
369                             nSymbolType = 11;
370                         else if( IsXMLToken( rAttrValue, XML_ASTERISK ))
371                             nSymbolType = 12;
372                         else if( IsXMLToken( rAttrValue, XML_HORIZONTAL_BAR ))
373                             nSymbolType = 13;
374                         else if( IsXMLToken( rAttrValue, XML_VERTICAL_BAR ))
375                             nSymbolType = 14;
376 
377                         if( nSymbolType >= 0 )
378                             pAttrList->AddAttribute(
379                                 GetTransformer().GetNamespaceMap().GetQNameByKey(
380                                     XML_NAMESPACE_CHART,
381                                     GetXMLToken( XML_SYMBOL )),
382                                 OUString::number( nSymbolType ));
383                     }
384                     break;
385                 // #i25616#
386                 case XML_OPTACTION_OPACITY:
387                     aOpacityValueRemember = rAttrValue;
388                     XMLTransformerBase::NegPercent(aOpacityValueRemember);
389                     break;
390 
391                 // #i25616#
392                 case XML_OPTACTION_IMAGE_OPACITY:
393                     aImageOpacityValueRemember = rAttrValue;
394                     XMLTransformerBase::NegPercent(aImageOpacityValueRemember);
395                     break;
396 
397                 case XML_OPTACTION_KEEP_TOGETHER:
398                     pAttrList->AddAttribute(
399                         GetTransformer().GetNamespaceMap().GetQNameByKey(
400                             XML_NAMESPACE_STYLE,GetXMLToken(XML_BREAK_INSIDE)),
401                         GetXMLToken(
402                             IsXMLToken( rAttrValue, XML_ALWAYS )
403                             ? XML_COLUMNSPLIT_AVOID
404                             : XML_COLUMNSPLIT_AUTO ) );
405                     break;
406 
407                 case XML_OPTACTION_CONTROL_TEXT_ALIGN:
408                     if ( m_bControlStyle )
409                     {
410                         OUString aNewAttrQName(
411                             GetTransformer().GetNamespaceMap().GetQNameByKey(
412                                 XML_NAMESPACE_STYLE,
413                                 ::xmloff::token::GetXMLToken(
414                                 XML_TEXT_ALIGN ) ) );
415                         pAttrList->AddAttribute( aNewAttrQName, rAttrValue );
416                     }
417                     else
418                     {
419                         OUString aNewAttrQName(
420                             GetTransformer().GetNamespaceMap().GetQNameByKey(
421                                 XML_NAMESPACE_FO,
422                                 ::xmloff::token::GetXMLToken(
423                                 XML_TEXT_ALIGN ) ) );
424                         pAttrList->AddAttribute( aNewAttrQName, rAttrValue );
425                     }
426                     break;
427 
428                 case XML_ATACTION_CAPTION_ESCAPE_OASIS:
429                     {
430                         OUString aAttrValue( rAttrValue );
431                         if( aAttrValue.indexOf( '%' ) != -1 )
432                         {
433                             sal_Int32 nValue = 0;
434                             ::sax::Converter::convertPercent(nValue, rAttrValue);
435                             if( nValue )
436                             {
437                                 nValue *= 100;
438                                 OUStringBuffer aOut;
439                                 ::sax::Converter::convertPercent(aOut, nValue);
440                                 aAttrValue = aOut.makeStringAndClear();
441                             }
442                         }
443                         else
444                         {
445                             XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue );
446                         }
447 
448                         pAttrList->AddAttribute( rAttrName, aAttrValue );
449                     }
450                     break;
451 
452                 case XML_ATACTION_DECODE_PROTECT:
453                     {
454                         pAttrList->AddAttribute( rAttrName, rAttrValue );
455 
456                         if( rAttrValue.indexOf( GetXMLToken( XML_SIZE ) ) != -1 )
457                             pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey(
458                                     XML_NAMESPACE_DRAW,
459                                     GetXMLToken( XML_SIZE_PROTECT )), GetXMLToken( XML_TRUE ) );
460 
461                         if( rAttrValue.indexOf( GetXMLToken( XML_POSITION ) ) != -1 )
462                             pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey(
463                                     XML_NAMESPACE_DRAW,
464                                     GetXMLToken( XML_MOVE_PROTECT )), GetXMLToken( XML_TRUE ) );
465                     }
466                     break;
467 
468                 case XML_ATACTION_DRAW_MIRROR_OASIS: // renames style:mirror to draw:mirror and adapts values
469                     {
470                         // keep original for writer graphic objects
471                         // Adapts attribute values (#i49139#)
472                         OUStringBuffer aNewAttrValue;
473                         SvXMLTokenEnumerator aTokenEnum( rAttrValue );
474                         OUString aToken;
475                         while( aTokenEnum.getNextToken( aToken ) )
476                         {
477                             if ( !aNewAttrValue.isEmpty() )
478                             {
479                                 aNewAttrValue.append(" ");
480                             }
481 
482                             if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_EVEN ) )
483                             {
484                                 aNewAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_LEFT_PAGES ));
485                             }
486                             else if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_ODD ) )
487                             {
488                                 aNewAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_RIGHT_PAGES ));
489                             }
490                             else
491                             {
492                                 aNewAttrValue.append(aToken);
493                             }
494                         }
495                         pAttrList->AddAttribute( rAttrName, aNewAttrValue.makeStringAndClear() );
496 
497                         // create old draw:mirror for drawing graphic objects
498                         const OUString& aAttrValue( GetXMLToken( IsXMLToken( rAttrValue, XML_HORIZONTAL ) ? XML_TRUE : XML_FALSE ) );
499                         pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey(
500                                     XML_NAMESPACE_DRAW,
501                                     GetXMLToken( XML_MIRROR )), aAttrValue );
502                     }
503                     break;
504                 case XML_ATACTION_GAMMA_OASIS:       // converts percentage value to double
505                     {
506                         sal_Int32 nValue;
507                         ::sax::Converter::convertPercent( nValue, rAttrValue );
508                         const double fValue = static_cast<double>(nValue) / 100.0;
509                         pAttrList->AddAttribute( rAttrName, OUString::number( fValue ) );
510                     }
511                     break;
512                 case XML_ATACTION_OPACITY_FIX:
513                     {
514                         sal_Int32 nValue;
515                         if( rAttrValue.indexOf( '%' ) != -1 )
516                         {
517                             ::sax::Converter::convertPercent(nValue, rAttrValue);
518                         }
519                         else
520                         {
521                             nValue = sal_Int32( rAttrValue.toDouble() * 100.0 );
522                         }
523                         nValue = 100 - nValue;
524 
525                         OUStringBuffer aOut;
526                         ::sax::Converter::convertPercent(aOut, nValue);
527                         pAttrList->AddAttribute( rAttrName, aOut.makeStringAndClear() );
528                     }
529                     break;
530                 default:
531                     OSL_ENSURE( false, "unknown action" );
532                     break;
533                 }
534             }
535             else
536             {
537                 pAttrList->AddAttribute( rAttrName, rAttrValue );
538             }
539         }
540         if( XML_TOKEN_END != eUnderline )
541             pAttrList->AddAttribute(
542                     GetTransformer().GetNamespaceMap().GetQNameByKey(
543                         XML_NAMESPACE_STYLE,
544                         GetXMLToken( XML_TEXT_UNDERLINE ) ),
545                     MergeUnderline( eUnderline, bBoldUnderline,
546                                     bDoubleUnderline ) );
547         if( XML_TOKEN_END != eLineThrough )
548             pAttrList->AddAttribute(
549                     GetTransformer().GetNamespaceMap().GetQNameByKey(
550                         XML_NAMESPACE_STYLE,
551                         GetXMLToken( XML_TEXT_CROSSING_OUT ) ),
552                     MergeLineThrough( eLineThrough, bBoldLineThrough,
553                                     bDoubleLineThrough, cLineThroughChar ) );
554         if( bIntervalMinorFound )
555         {
556             double fIntervalMinor = 0.0;
557             if( nIntervalMinorDivisor != 0)
558                 fIntervalMinor = fIntervalMajor / static_cast< double >( nIntervalMinorDivisor );
559 
560             OUStringBuffer aBuf;
561             ::sax::Converter::convertDouble( aBuf, fIntervalMinor );
562             pAttrList->AddAttribute(
563                 GetTransformer().GetNamespaceMap().GetQNameByKey(
564                     XML_NAMESPACE_CHART,
565                     GetXMLToken( XML_INTERVAL_MINOR )),
566                 aBuf.makeStringAndClear());
567         }
568 
569         // #i25616#
570         if(!aOpacityValueRemember.isEmpty() || !aImageOpacityValueRemember.isEmpty())
571         {
572             pAttrList->AddAttribute(
573                     GetTransformer().GetNamespaceMap().GetQNameByKey(
574                         XML_NAMESPACE_DRAW,
575                         GetXMLToken( XML_TRANSPARENCY ) ),
576                     !aImageOpacityValueRemember.isEmpty()
577                     ? aImageOpacityValueRemember : aOpacityValueRemember );
578         }
579     }
580     else
581     {
582         if( !m_xAttrList.is() )
583         {
584             m_xAttrList = new XMLMutableAttributeList( rAttrList, true );
585         }
586         else
587         {
588             static_cast< XMLMutableAttributeList * >( m_xAttrList.get() )
589                 ->AppendAttributeList( rAttrList );
590         }
591     }
592 }
593 
Export()594 void XMLPropertiesTContext_Impl::Export()
595 {
596     GetTransformer().GetDocHandler()->startElement( GetExportQName(), m_xAttrList );
597     ExportContent();
598     GetTransformer().GetDocHandler()->endElement( GetExportQName() );
599 }
600 
GetPropType(const OUString & rLocalName)601 XMLPropType XMLPropertiesTContext_Impl::GetPropType( const OUString& rLocalName )
602 {
603     XMLPropType eProp = XML_PROP_TYPE_END;
604     if( IsXMLToken( rLocalName, XML_GRAPHIC_PROPERTIES )  )
605         eProp = XML_PROP_TYPE_GRAPHIC;
606     else if( IsXMLToken( rLocalName, XML_DRAWING_PAGE_PROPERTIES ) )
607         eProp = XML_PROP_TYPE_DRAWING_PAGE;
608     else if( IsXMLToken( rLocalName, XML_PAGE_LAYOUT_PROPERTIES ) )
609         eProp = XML_PROP_TYPE_PAGE_LAYOUT;
610     else if( IsXMLToken( rLocalName, XML_HEADER_FOOTER_PROPERTIES ) )
611         eProp = XML_PROP_TYPE_HEADER_FOOTER;
612     else if( IsXMLToken( rLocalName, XML_TEXT_PROPERTIES ) )
613         eProp = XML_PROP_TYPE_TEXT;
614     else if( IsXMLToken( rLocalName, XML_PARAGRAPH_PROPERTIES ) )
615         eProp = XML_PROP_TYPE_PARAGRAPH;
616     else if( IsXMLToken( rLocalName, XML_RUBY_PROPERTIES ) )
617         eProp = XML_PROP_TYPE_RUBY;
618     else if( IsXMLToken( rLocalName, XML_SECTION_PROPERTIES ) )
619         eProp = XML_PROP_TYPE_SECTION;
620     else if( IsXMLToken( rLocalName, XML_TABLE_PROPERTIES ) )
621         eProp = XML_PROP_TYPE_TABLE;
622     else if( IsXMLToken( rLocalName, XML_TABLE_COLUMN_PROPERTIES ) )
623         eProp = XML_PROP_TYPE_TABLE_COLUMN;
624     else if( IsXMLToken( rLocalName, XML_TABLE_ROW_PROPERTIES ) )
625         eProp = XML_PROP_TYPE_TABLE_ROW;
626     else if( IsXMLToken( rLocalName, XML_TABLE_CELL_PROPERTIES ) )
627         eProp = XML_PROP_TYPE_TABLE_CELL;
628     else if( IsXMLToken( rLocalName, XML_LIST_LEVEL_PROPERTIES ) )
629         eProp = XML_PROP_TYPE_LIST_LEVEL;
630     else if( IsXMLToken( rLocalName, XML_CHART_PROPERTIES ) )
631         eProp = XML_PROP_TYPE_CHART;
632 
633     return eProp;
634 }
635 
MergeUnderline(XMLTokenEnum eUnderline,bool bBold,bool bDouble)636 OUString const & XMLPropertiesTContext_Impl::MergeUnderline(
637             XMLTokenEnum eUnderline, bool bBold, bool bDouble )
638 {
639     if( bDouble )
640     {
641         switch( eUnderline )
642         {
643         case XML_WAVE:
644             eUnderline = XML_DOUBLE_WAVE;
645             break;
646         default:
647             eUnderline = XML_DOUBLE;
648             break;
649         }
650     }
651     else if( bBold )
652     {
653         switch( eUnderline )
654         {
655         case XML_NONE:
656         case XML_SOLID:
657             eUnderline = XML_BOLD;
658             break;
659         case XML_DOTTED:
660             eUnderline = XML_BOLD_DOTTED;
661             break;
662         case XML_DASH:
663             eUnderline = XML_BOLD_DASH;
664             break;
665         case XML_LONG_DASH:
666             eUnderline = XML_BOLD_LONG_DASH;
667             break;
668         case XML_DOT_DASH:
669             eUnderline = XML_BOLD_DOT_DASH;
670             break;
671         case XML_DOT_DOT_DASH:
672             eUnderline = XML_BOLD_DOT_DOT_DASH;
673             break;
674         case XML_WAVE:
675             eUnderline = XML_BOLD_WAVE;
676             break;
677         default:
678             OSL_FAIL( "xmloff::XMLPropertiesTContext_Impl::MergeUnderline(), missing underline case!" );
679             break;
680         }
681     }
682     else
683     {
684         switch( eUnderline )
685         {
686         case XML_SOLID:
687             eUnderline = XML_SINGLE;
688             break;
689         case XML_NONE:
690             eUnderline = XML_NONE;
691             break;
692         default:
693             OSL_FAIL( "xmloff::XMLPropertiesTContext_Impl::MergeUnderline(), missing underline case!" );
694             break;
695         }
696     }
697 
698     return GetXMLToken( eUnderline );
699 }
700 
MergeLineThrough(XMLTokenEnum eLineThrough,bool bBold,bool bDouble,sal_Unicode c)701 OUString const & XMLPropertiesTContext_Impl::MergeLineThrough(
702             XMLTokenEnum eLineThrough, bool bBold, bool bDouble,
703                sal_Unicode c )
704 {
705     if( c )
706         eLineThrough = c=='/' ? XML_SLASH : XML_uX;
707     else if( bDouble )
708         eLineThrough = XML_DOUBLE_LINE;
709     else if( bBold )
710         eLineThrough = XML_THICK_LINE;
711     else if( XML_NONE != eLineThrough )
712         eLineThrough = XML_SINGLE_LINE;
713 
714     return GetXMLToken( eLineThrough );
715 }
716 
XMLStyleOASISTContext(XMLTransformerBase & rImp,const OUString & rQName,bool bPersistent)717 XMLStyleOASISTContext::XMLStyleOASISTContext(XMLTransformerBase& rImp,
718     const OUString& rQName, bool bPersistent)
719     : XMLPersElemContentTContext(rImp, rQName)
720     , m_bPersistent(bPersistent)
721     , m_bControlStyle(false)
722 {
723 }
724 
XMLStyleOASISTContext(XMLTransformerBase & rImp,const OUString & rQName,sal_uInt16 nPrefix,::xmloff::token::XMLTokenEnum eToken,bool bPersistent)725 XMLStyleOASISTContext::XMLStyleOASISTContext(
726     XMLTransformerBase& rImp, const OUString& rQName,
727     sal_uInt16 nPrefix, ::xmloff::token::XMLTokenEnum eToken,
728     bool bPersistent)
729     : XMLPersElemContentTContext(rImp, rQName, nPrefix, eToken)
730     , m_bPersistent(bPersistent)
731     , m_bControlStyle(false)
732 {
733 }
734 
~XMLStyleOASISTContext()735 XMLStyleOASISTContext::~XMLStyleOASISTContext()
736 {
737 }
738 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const OUString & rQName,const Reference<XAttributeList> & rAttrList)739 rtl::Reference<XMLTransformerContext> XMLStyleOASISTContext::CreateChildContext(
740             sal_uInt16 nPrefix,
741             const OUString& rLocalName,
742             const OUString& rQName,
743             const Reference< XAttributeList >& rAttrList )
744 {
745     rtl::Reference<XMLTransformerContext> pContext;
746 
747     if( XML_NAMESPACE_STYLE == nPrefix || XML_NAMESPACE_LO_EXT == nPrefix )
748     {
749         XMLPropType ePropType =
750             XMLPropertiesTContext_Impl::GetPropType( rLocalName );
751         if( XML_PROP_TYPE_END != ePropType )
752         {
753             // if no properties context exist start a new one.
754             if( !m_xPropContext.is() )
755                 m_xPropContext = new XMLPropertiesTContext_Impl(
756                     GetTransformer(), rQName, ePropType, m_bControlStyle );
757             else
758                 m_xPropContext->SetQNameAndPropType( rQName, ePropType );
759             pContext.set(m_xPropContext.get());
760         }
761     }
762     if( !pContext.is() )
763     {
764         // if a properties context exist close it
765         if( m_xPropContext.is() && !m_bPersistent )
766         {
767             m_xPropContext->Export();
768             m_xPropContext = nullptr;
769         }
770 
771         pContext = m_bPersistent
772                         ? XMLPersElemContentTContext::CreateChildContext(
773                                 nPrefix, rLocalName, rQName, rAttrList )
774                         : XMLTransformerContext::CreateChildContext(
775                                 nPrefix, rLocalName, rQName, rAttrList );
776     }
777 
778     return pContext;
779 }
780 
StartElement(const Reference<XAttributeList> & rAttrList)781 void XMLStyleOASISTContext::StartElement(
782         const Reference< XAttributeList >& rAttrList )
783 {
784     XMLTransformerActions *pActions =
785         GetTransformer().GetUserDefinedActions( OASIS_STYLE_ACTIONS );
786     OSL_ENSURE( pActions, "go no actions" );
787 
788     Reference< XAttributeList > xAttrList( rAttrList );
789     XMLMutableAttributeList *pMutableAttrList = nullptr;
790     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
791     sal_Int16 nFamilyAttr = -1;
792     m_bControlStyle = false;
793 
794     for( sal_Int16 i=0; i < nAttrCount; i++ )
795     {
796         const OUString& rAttrName = xAttrList->getNameByIndex( i );
797         OUString aLocalName;
798         sal_uInt16 nPrefix =
799             GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName,
800                                                                  &aLocalName );
801         XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
802         XMLTransformerActions::const_iterator aIter =
803             pActions->find( aKey );
804         if( aIter != pActions->end() )
805         {
806             if( !pMutableAttrList )
807             {
808                 pMutableAttrList =
809                         new XMLMutableAttributeList( xAttrList );
810                 xAttrList = pMutableAttrList;
811             }
812             const OUString& rAttrValue = xAttrList->getValueByIndex( i );
813             switch( (*aIter).second.m_nActionType )
814             {
815             case XML_ATACTION_STYLE_FAMILY:
816                 if( IsXMLToken( rAttrValue, XML_GRAPHIC ) )
817                 {
818                     pMutableAttrList->SetValueByIndex(
819                         i, GetXMLToken(XML_GRAPHICS) );
820                 }
821                 else
822                 {
823                     if( IsXMLToken( rAttrValue, XML_PARAGRAPH ) )
824                         nFamilyAttr = i;
825                 }
826 
827                 break;
828             case XML_ATACTION_STYLE_DISPLAY_NAME:
829             case XML_ATACTION_REMOVE:
830                 pMutableAttrList->RemoveAttributeByIndex( i );
831                 --i;
832                 --nAttrCount;
833                 break;
834             case XML_ATACTION_DECODE_STYLE_NAME:
835                 m_bControlStyle = rAttrValue.startsWith( "ctrl" );
836                 [[fallthrough]];
837             case XML_ATACTION_DECODE_STYLE_NAME_REF:
838                 {
839                     OUString aAttrValue( rAttrValue );
840                     if( XMLTransformerBase::DecodeStyleName(aAttrValue) )
841                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
842                 }
843                 break;
844             case XML_ATACTION_IN2INCH:
845                 {
846                     OUString aAttrValue( rAttrValue );
847                     if( XMLTransformerBase::ReplaceSingleInWithInch(
848                                 aAttrValue ) )
849                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
850                 }
851                 break;
852             case XML_ATACTION_NEG_PERCENT:
853                 {
854                     OUString aAttrValue( rAttrValue );
855                     if( XMLTransformerBase::NegPercent(aAttrValue) )
856                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
857                 }
858                 break;
859             case XML_ATACTION_URI_OASIS:
860                 {
861                     OUString aAttrValue( rAttrValue );
862                     if( GetTransformer().ConvertURIToOOo( aAttrValue,
863                             static_cast< bool >((*aIter).second.m_nParam1)))
864                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
865                 }
866                 break;
867             default:
868                 OSL_ENSURE( false, "unknown action" );
869                 break;
870             }
871         }
872     }
873 
874     if( m_bControlStyle && nFamilyAttr != -1 )
875         pMutableAttrList->SetValueByIndex( nFamilyAttr, GetXMLToken( XML_CONTROL ) );
876 
877     if( m_bPersistent )
878         XMLPersElemContentTContext::StartElement( xAttrList );
879     else
880         GetTransformer().GetDocHandler()->startElement( GetExportQName(), xAttrList );
881 }
882 
EndElement()883 void XMLStyleOASISTContext::EndElement()
884 {
885     if( m_bPersistent )
886     {
887         XMLPersElemContentTContext::EndElement();
888     }
889     else
890     {
891         // if a properties context exist close it
892         if( m_xPropContext.is() )
893         {
894             m_xPropContext->Export();
895             m_xPropContext = nullptr;
896         }
897         GetTransformer().GetDocHandler()->endElement( GetExportQName() );
898     }
899 }
900 
Characters(const OUString &)901 void XMLStyleOASISTContext::Characters( const OUString& )
902 {
903     // element content only:
904 }
905 
ExportContent()906 void XMLStyleOASISTContext::ExportContent()
907 {
908     if( m_xPropContext.is() )
909         m_xPropContext->Export();
910     XMLPersElemContentTContext::ExportContent();
911 }
912 
IsPersistent() const913 bool XMLStyleOASISTContext::IsPersistent() const
914 {
915     return m_bPersistent;
916 }
917 
CreateTransformerActions(sal_uInt16 nType)918 XMLTransformerActions *XMLStyleOASISTContext::CreateTransformerActions(
919         sal_uInt16 nType )
920 {
921     XMLTransformerActionInit const *pInit = nullptr;
922 
923     switch( nType )
924     {
925     case PROP_OASIS_GRAPHIC_ATTR_ACTIONS:
926         pInit = aGraphicPropertyOASISAttrActionTable;
927         break;
928     case PROP_OASIS_DRAWING_PAGE_ATTR_ACTIONS:
929         pInit = aDrawingPagePropertyOASISAttrActionTable;
930         break;
931     case PROP_OASIS_PAGE_LAYOUT_ATTR_ACTIONS:
932         pInit = aPageLayoutPropertyOASISAttrActionTable;
933         break;
934     case PROP_OASIS_HEADER_FOOTER_ATTR_ACTIONS:
935         pInit = aHeaderFooterPropertyOASISAttrActionTable;
936         break;
937     case PROP_OASIS_TEXT_ATTR_ACTIONS:
938         pInit = aTextPropertyOASISAttrActionTable;
939         break;
940     case PROP_OASIS_PARAGRAPH_ATTR_ACTIONS:
941         pInit = aParagraphPropertyOASISAttrActionTable;
942         break;
943     case PROP_OASIS_SECTION_ATTR_ACTIONS:
944         pInit = aSectionPropertyOASISAttrActionTable;
945         break;
946     case PROP_OASIS_TABLE_ATTR_ACTIONS:
947         pInit = aTablePropertyOASISAttrActionTable;
948         break;
949     case PROP_OASIS_TABLE_COLUMN_ATTR_ACTIONS:
950         pInit = aTableColumnPropertyOASISAttrActionTable;
951         break;
952     case PROP_OASIS_TABLE_ROW_ATTR_ACTIONS:
953         pInit = aTableRowPropertyOASISAttrActionTable;
954         break;
955     case PROP_OASIS_TABLE_CELL_ATTR_ACTIONS:
956         pInit = aTableCellPropertyOASISAttrActionTable;
957         break;
958     case PROP_OASIS_LIST_LEVEL_ATTR_ACTIONS:
959         pInit = aListLevelPropertyOASISAttrActionTable;
960         break;
961     case PROP_OASIS_CHART_ATTR_ACTIONS:
962         pInit = aChartPropertyOASISAttrActionTable;
963         break;
964     }
965 
966     XMLTransformerActions *pActions = nullptr;
967     if( pInit )
968         pActions = new XMLTransformerActions( pInit );
969 
970     return pActions;
971 }
972 
973 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
974