tdf#131098 docx export: write fill property of graphic
[LibreOffice.git] / oox / source / drawingml / textparagraphproperties.cxx
blob54c1d23c7b1ab9310b154685a19a038f63a0b822
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/textparagraphproperties.hxx>
22 #include <com/sun/star/text/XNumberingRulesSupplier.hpp>
23 #include <com/sun/star/container/XIndexReplace.hpp>
24 #include <com/sun/star/text/HoriOrientation.hpp>
25 #include <com/sun/star/awt/FontDescriptor.hpp>
26 #include <com/sun/star/awt/FontWeight.hpp>
27 #include <com/sun/star/awt/XBitmap.hpp>
28 #include <com/sun/star/graphic/XGraphic.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/style/NumberingType.hpp>
31 #include <com/sun/star/style/TabStop.hpp>
32 #include <com/sun/star/style/ParagraphAdjust.hpp>
33 #include <com/sun/star/drawing/XDrawPage.hpp>
35 #include <osl/diagnose.h>
37 #include <oox/helper/propertyset.hxx>
38 #include <oox/core/xmlfilterbase.hxx>
39 #include <oox/token/properties.hxx>
40 #include <oox/token/tokens.hxx>
42 #if OSL_DEBUG_LEVEL > 0
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <com/sun/star/text/XText.hpp>
45 #include <com/sun/star/drawing/XShape.hpp>
46 #include <oox/ppt/pptimport.hxx>
47 #include <oox/ppt/slidepersist.hxx>
48 #endif
50 using namespace ::oox::core;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::beans;
53 using namespace ::com::sun::star::style;
54 using namespace ::com::sun::star::text;
55 using namespace ::com::sun::star::container;
56 using ::com::sun::star::awt::FontDescriptor;
58 namespace oox::drawingml {
60 BulletList::BulletList( )
61 : maBulletColorPtr( std::make_shared<Color>() ),
62 mbBulletColorFollowText ( false ),
63 mbBulletFontFollowText ( false ),
64 mbBulletSizeFollowText ( false )
68 bool BulletList::is() const
70 return mnNumberingType.hasValue();
73 void BulletList::setBulletChar( const OUString & sChar )
75 mnNumberingType <<= NumberingType::CHAR_SPECIAL;
76 msBulletChar <<= sChar;
79 void BulletList::setGraphic( css::uno::Reference< css::graphic::XGraphic > const & rXGraphic )
81 mnNumberingType <<= NumberingType::BITMAP;
82 maGraphic <<= rXGraphic;
85 void BulletList::setNone( )
87 mnNumberingType <<= NumberingType::NUMBER_NONE;
90 void BulletList::setSuffixParenBoth()
92 msNumberingSuffix <<= u")"_ustr;
93 msNumberingPrefix <<= u"("_ustr;
96 void BulletList::setSuffixParenRight()
98 msNumberingSuffix <<= u")"_ustr;
99 msNumberingPrefix <<= OUString();
102 void BulletList::setSuffixPeriod()
104 msNumberingSuffix <<= u"."_ustr;
105 msNumberingPrefix <<= OUString();
108 void BulletList::setSuffixNone()
110 msNumberingSuffix <<= OUString();
111 msNumberingPrefix <<= OUString();
114 void BulletList::setSuffixMinusRight()
116 msNumberingSuffix <<= u"-"_ustr;
117 msNumberingPrefix <<= OUString();
120 void BulletList::setType( sal_Int32 nType )
122 OSL_ASSERT((nType & sal_Int32(0xFFFF0000))==0);
123 switch( nType )
125 case XML_alphaLcParenBoth:
126 mnNumberingType <<= NumberingType::CHARS_LOWER_LETTER;
127 setSuffixParenBoth();
128 break;
129 case XML_alphaLcParenR:
130 mnNumberingType <<= NumberingType::CHARS_LOWER_LETTER;
131 setSuffixParenRight();
132 break;
133 case XML_alphaLcPeriod:
134 mnNumberingType <<= NumberingType::CHARS_LOWER_LETTER;
135 setSuffixPeriod();
136 break;
137 case XML_alphaUcParenBoth:
138 mnNumberingType <<= NumberingType::CHARS_UPPER_LETTER;
139 setSuffixParenBoth();
140 break;
141 case XML_alphaUcParenR:
142 mnNumberingType <<= NumberingType::CHARS_UPPER_LETTER;
143 setSuffixParenRight();
144 break;
145 case XML_alphaUcPeriod:
146 mnNumberingType <<= NumberingType::CHARS_UPPER_LETTER;
147 setSuffixPeriod();
148 break;
149 case XML_arabic1Minus:
150 case XML_arabic2Minus:
151 case XML_arabicDbPeriod:
152 case XML_arabicDbPlain:
153 // TODO
154 break;
155 case XML_arabicParenBoth:
156 mnNumberingType <<= NumberingType::ARABIC;
157 setSuffixParenBoth();
158 break;
159 case XML_arabicParenR:
160 mnNumberingType <<= NumberingType::ARABIC;
161 setSuffixParenRight();
162 break;
163 case XML_arabicPeriod:
164 mnNumberingType <<= NumberingType::ARABIC;
165 setSuffixPeriod();
166 break;
167 case XML_arabicPlain:
168 mnNumberingType <<= NumberingType::ARABIC;
169 setSuffixNone();
170 break;
171 case XML_circleNumDbPlain:
172 case XML_circleNumWdBlackPlain:
173 case XML_circleNumWdWhitePlain:
174 mnNumberingType <<= NumberingType::CIRCLE_NUMBER;
175 break;
176 case XML_ea1ChsPeriod:
177 mnNumberingType <<= NumberingType::NUMBER_UPPER_ZH;
178 setSuffixPeriod();
179 break;
180 case XML_ea1ChsPlain:
181 mnNumberingType <<= NumberingType::NUMBER_UPPER_ZH;
182 setSuffixNone();
183 break;
184 case XML_ea1ChtPeriod:
185 mnNumberingType <<= NumberingType::NUMBER_UPPER_ZH_TW;
186 setSuffixPeriod();
187 break;
188 case XML_ea1ChtPlain:
189 mnNumberingType <<= NumberingType::NUMBER_UPPER_ZH_TW;
190 setSuffixNone();
191 break;
192 case XML_ea1JpnChsDbPeriod:
193 case XML_ea1JpnKorPeriod:
194 case XML_ea1JpnKorPlain:
195 break;
196 case XML_hebrew2Minus:
197 mnNumberingType <<= NumberingType::CHARS_HEBREW;
198 setSuffixMinusRight();
199 break;
200 case XML_hindiAlpha1Period:
201 case XML_hindiAlphaPeriod:
202 case XML_hindiNumParenR:
203 case XML_hindiNumPeriod:
204 // TODO
205 break;
206 case XML_romanLcParenBoth:
207 mnNumberingType <<= NumberingType::ROMAN_LOWER;
208 setSuffixParenBoth();
209 break;
210 case XML_romanLcParenR:
211 mnNumberingType <<= NumberingType::ROMAN_LOWER;
212 setSuffixParenRight();
213 break;
214 case XML_romanLcPeriod:
215 mnNumberingType <<= NumberingType::ROMAN_LOWER;
216 setSuffixPeriod();
217 break;
218 case XML_romanUcParenBoth:
219 mnNumberingType <<= NumberingType::ROMAN_UPPER;
220 setSuffixParenBoth();
221 break;
222 case XML_romanUcParenR:
223 mnNumberingType <<= NumberingType::ROMAN_UPPER;
224 setSuffixParenRight();
225 break;
226 case XML_romanUcPeriod:
227 mnNumberingType <<= NumberingType::ROMAN_UPPER;
228 setSuffixPeriod();
229 break;
230 case XML_thaiAlphaParenBoth:
231 case XML_thaiNumParenBoth:
232 mnNumberingType <<= NumberingType::CHARS_THAI;
233 setSuffixParenBoth();
234 break;
235 case XML_thaiAlphaParenR:
236 case XML_thaiNumParenR:
237 mnNumberingType <<= NumberingType::CHARS_THAI;
238 setSuffixParenRight();
239 break;
240 case XML_thaiAlphaPeriod:
241 case XML_thaiNumPeriod:
242 mnNumberingType <<= NumberingType::CHARS_THAI;
243 setSuffixPeriod();
244 break;
248 void BulletList::setBulletSize(sal_Int16 nSize)
250 mnSize <<= nSize;
253 void BulletList::setBulletAspectRatio(double nAspectRatio)
255 mnAspectRatio <<= nAspectRatio;
258 void BulletList::setFontSize(sal_Int16 nSize)
260 mnFontSize <<= nSize;
263 void BulletList::apply( const BulletList& rSource )
265 if ( rSource.maBulletColorPtr->isUsed() )
266 maBulletColorPtr = rSource.maBulletColorPtr;
267 if ( rSource.mbBulletColorFollowText.hasValue() )
268 mbBulletColorFollowText = rSource.mbBulletColorFollowText;
269 if ( rSource.mbBulletFontFollowText.hasValue() )
270 mbBulletFontFollowText = rSource.mbBulletFontFollowText;
271 if ( rSource.mbBulletSizeFollowText.hasValue() )
272 mbBulletSizeFollowText = rSource.mbBulletSizeFollowText;
273 maBulletFont.assignIfUsed( rSource.maBulletFont );
274 if ( rSource.msBulletChar.hasValue() )
275 msBulletChar = rSource.msBulletChar;
276 if ( rSource.mnStartAt.hasValue() )
277 mnStartAt = rSource.mnStartAt;
278 if ( rSource.mnNumberingType.hasValue() )
279 mnNumberingType = rSource.mnNumberingType;
280 if ( rSource.msNumberingPrefix.hasValue() )
281 msNumberingPrefix = rSource.msNumberingPrefix;
282 if ( rSource.msNumberingSuffix.hasValue() )
283 msNumberingSuffix = rSource.msNumberingSuffix;
284 if ( rSource.mnSize.hasValue() )
285 mnSize = rSource.mnSize;
286 if ( rSource.mnAspectRatio.hasValue() )
287 mnAspectRatio = rSource.mnAspectRatio;
288 if ( rSource.mnFontSize.hasValue() )
289 mnFontSize = rSource.mnFontSize;
290 if ( rSource.maStyleName.hasValue() )
291 maStyleName = rSource.maStyleName;
292 if ( rSource.maGraphic.hasValue() )
293 maGraphic = rSource.maGraphic;
296 void BulletList::pushToPropMap( const ::oox::core::XmlFilterBase* pFilterBase, PropertyMap& rPropMap ) const
298 if( msNumberingPrefix.hasValue() )
299 rPropMap.setAnyProperty( PROP_Prefix, msNumberingPrefix);
300 if( msNumberingSuffix.hasValue() )
301 rPropMap.setAnyProperty( PROP_Suffix, msNumberingSuffix);
302 if( mnStartAt.hasValue() )
303 rPropMap.setAnyProperty( PROP_StartWith, mnStartAt);
304 rPropMap.setProperty( PROP_Adjust, HoriOrientation::LEFT);
306 if( mnNumberingType.hasValue() )
307 rPropMap.setAnyProperty( PROP_NumberingType, mnNumberingType);
309 OUString aBulletFontName;
310 sal_Int16 nBulletFontPitch = 0;
311 sal_Int16 nBulletFontFamily = 0;
312 float nBulletFontWeight = css::awt::FontWeight::NORMAL;
313 bool bSymbolFont = false;
314 if( pFilterBase) {
315 bool bFollowTextFont = false;
316 mbBulletFontFollowText >>= bFollowTextFont;
317 if (!bFollowTextFont && maBulletFont.getFontData( aBulletFontName, nBulletFontPitch, nBulletFontFamily, &bSymbolFont, *pFilterBase ) )
319 FontDescriptor aFontDesc;
320 sal_Int16 nFontSize = 0;
321 if( mnFontSize >>= nFontSize )
322 aFontDesc.Height = nFontSize;
324 // TODO It is likely that bSymbolFont from getFontData is sufficient to check here
325 // and looking at the font name is not necessary, if it is necessary then moving
326 // the name lookup into getFontData is likely the best fix
327 aFontDesc.Name = aBulletFontName;
328 aFontDesc.Pitch = nBulletFontPitch;
329 aFontDesc.Family = nBulletFontFamily;
330 aFontDesc.Weight = nBulletFontWeight;
331 if ( bSymbolFont ||
332 aBulletFontName.equalsIgnoreAsciiCase("Wingdings") ||
333 aBulletFontName.equalsIgnoreAsciiCase("Wingdings 2") ||
334 aBulletFontName.equalsIgnoreAsciiCase("Wingdings 3") ||
335 aBulletFontName.equalsIgnoreAsciiCase("Monotype Sorts") ||
336 aBulletFontName.equalsIgnoreAsciiCase("Monotype Sorts 2") ||
337 aBulletFontName.equalsIgnoreAsciiCase("Webdings") ||
338 aBulletFontName.equalsIgnoreAsciiCase("StarBats") ||
339 aBulletFontName.equalsIgnoreAsciiCase("StarMath") ||
340 aBulletFontName.equalsIgnoreAsciiCase("ZapfDingbats") ) {
341 aFontDesc.CharSet = RTL_TEXTENCODING_SYMBOL;
342 bSymbolFont = true;
344 rPropMap.setProperty( PROP_BulletFont, aFontDesc);
345 rPropMap.setProperty( PROP_BulletFontName, aBulletFontName);
348 if ( msBulletChar.hasValue() ) {
349 OUString sBuChar;
351 msBulletChar >>= sBuChar;
353 if( pFilterBase && sBuChar.getLength() == 1 && maBulletFont.getFontData( aBulletFontName, nBulletFontPitch, nBulletFontFamily, nullptr, *pFilterBase ) && bSymbolFont )
355 sal_Unicode nBuChar = sBuChar.toChar();
356 nBuChar &= 0x00ff;
357 nBuChar |= 0xf000;
358 sBuChar = OUString( &nBuChar, 1 );
361 rPropMap.setProperty( PROP_BulletChar, sBuChar);
363 if ( maGraphic.hasValue() )
365 Reference<css::awt::XBitmap> xBitmap(maGraphic, UNO_QUERY);
366 if (xBitmap.is())
367 rPropMap.setProperty(PROP_GraphicBitmap, xBitmap);
369 bool bFollowTextSize = false;
370 mbBulletSizeFollowText >>= bFollowTextSize;
371 if( !bFollowTextSize && mnSize.hasValue() )
372 rPropMap.setAnyProperty( PROP_BulletRelSize, mnSize);
373 if ( maStyleName.hasValue() )
374 rPropMap.setAnyProperty( PROP_CharStyleName, maStyleName);
375 if (pFilterBase ) {
376 bool bFollowTextColor = false;
377 mbBulletColorFollowText >>= bFollowTextColor;
378 if ( maBulletColorPtr->isUsed() && !bFollowTextColor )
379 rPropMap.setProperty( PROP_BulletColor, maBulletColorPtr->getColor( pFilterBase->getGraphicHelper() ));
383 TextParagraphProperties::TextParagraphProperties()
384 : mnLevel( 0 )
388 void TextParagraphProperties::apply( const TextParagraphProperties& rSourceProps )
390 maTextParagraphPropertyMap.assignAll( rSourceProps.maTextParagraphPropertyMap );
391 maBulletList.apply( rSourceProps.maBulletList );
392 maTextCharacterProperties.assignUsed( rSourceProps.maTextCharacterProperties );
393 if ( rSourceProps.maParaTopMargin.bHasValue )
394 maParaTopMargin = rSourceProps.maParaTopMargin;
395 if ( rSourceProps.maParaBottomMargin.bHasValue )
396 maParaBottomMargin = rSourceProps.maParaBottomMargin;
397 if ( rSourceProps.moParaLeftMargin )
398 moParaLeftMargin = rSourceProps.moParaLeftMargin;
399 if ( rSourceProps.moFirstLineIndentation )
400 moFirstLineIndentation = rSourceProps.moFirstLineIndentation;
401 if ( rSourceProps.moDefaultTabSize )
402 moDefaultTabSize = rSourceProps.moDefaultTabSize;
403 if( rSourceProps.mnLevel )
404 mnLevel = rSourceProps.mnLevel;
405 if( rSourceProps.moParaAdjust )
406 moParaAdjust = rSourceProps.moParaAdjust;
407 if( rSourceProps.maLineSpacing.bHasValue )
408 maLineSpacing = rSourceProps.maLineSpacing;
411 void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase* pFilterBase,
412 const Reference < XPropertySet >& xPropSet, PropertyMap& rioBulletMap, const BulletList* pMasterBuList, bool bApplyBulletMap, float fCharacterSize,
413 bool bPushDefaultValues ) const
415 PropertySet aPropSet( xPropSet );
416 aPropSet.setProperties( maTextParagraphPropertyMap );
418 sal_Int32 nNumberingType = NumberingType::NUMBER_NONE;
419 if ( maBulletList.mnNumberingType.hasValue() )
421 maBulletList.mnNumberingType >>= nNumberingType;
422 aPropSet.setProperty< sal_Int16 >( PROP_NumberingLevel, getLevel() );
424 else if ( pMasterBuList && pMasterBuList->mnNumberingType.hasValue() )
425 pMasterBuList->mnNumberingType >>= nNumberingType;
426 if ( nNumberingType == NumberingType::NUMBER_NONE
427 && aPropSet.hasProperty(PROP_NumberingLevel) )
428 aPropSet.setProperty< sal_Int16 >( PROP_NumberingLevel, -1 );
430 maBulletList.pushToPropMap( pFilterBase, rioBulletMap );
432 if ( maParaTopMargin.bHasValue || bPushDefaultValues )
433 aPropSet.setProperty( PROP_ParaTopMargin, maParaTopMargin.toMargin( fCharacterSize != 0.0 ? fCharacterSize : getCharHeightPoints ( 12.0 ) ) );
434 if ( maParaBottomMargin.bHasValue || bPushDefaultValues )
435 aPropSet.setProperty( PROP_ParaBottomMargin, maParaBottomMargin.toMargin( fCharacterSize != 0.0 ? fCharacterSize : getCharHeightPoints ( 12.0 ) ) );
437 std::optional< sal_Int32 > noParaLeftMargin( moParaLeftMargin );
438 std::optional< sal_Int32 > noFirstLineIndentation( moFirstLineIndentation );
440 if ( nNumberingType != NumberingType::NUMBER_NONE )
442 if ( noParaLeftMargin )
444 aPropSet.setProperty<sal_Int32>( PROP_ParaLeftMargin, 0);
445 rioBulletMap.setProperty( PROP_LeftMargin, *noParaLeftMargin);
446 noParaLeftMargin.reset();
448 if ( noFirstLineIndentation )
450 // Force Paragraph property as zero - impress seems to use the value from previous
451 // (non) bullet line if not set to zero explicitly :(
452 aPropSet.setProperty<sal_Int32>( PROP_ParaFirstLineIndent, 0);
453 rioBulletMap.setProperty( PROP_FirstLineOffset, *noFirstLineIndentation);
454 noFirstLineIndentation.reset();
456 if ( nNumberingType != NumberingType::BITMAP && !rioBulletMap.hasProperty( PROP_BulletColor ) && pFilterBase )
457 rioBulletMap.setProperty( PROP_BulletColor, maTextCharacterProperties.maFillProperties.getBestSolidColor().getColor( pFilterBase->getGraphicHelper()));
460 if ( bApplyBulletMap )
462 Reference< XIndexReplace > xNumRule;
463 aPropSet.getProperty( xNumRule, PROP_NumberingRules );
464 OSL_ENSURE( xNumRule.is(), "can't get Numbering rules");
468 if( xNumRule.is() )
470 if( !rioBulletMap.empty() )
472 // fix default bullet size to be 100%
473 if( !rioBulletMap.hasProperty( PROP_BulletRelSize ) )
474 rioBulletMap.setProperty<sal_Int16>( PROP_BulletRelSize, 100);
475 Sequence< PropertyValue > aBulletPropSeq = rioBulletMap.makePropertyValueSequence();
476 xNumRule->replaceByIndex( getLevel(), Any( aBulletPropSeq ) );
479 aPropSet.setProperty( PROP_NumberingRules, xNumRule );
482 catch (const Exception &)
484 // Don't warn for now, expected to fail for Writer.
487 if ( noParaLeftMargin )
488 aPropSet.setProperty( PROP_ParaLeftMargin, *noParaLeftMargin);
489 if ( noFirstLineIndentation )
491 aPropSet.setProperty( PROP_ParaFirstLineIndent, *noFirstLineIndentation );
492 if( bPushDefaultValues )
494 // Reset TabStops - these would be auto calculated by Impress
495 TabStop aTabStop;
496 aTabStop.Position = 0;
497 Sequence< TabStop > aSeq { aTabStop };
498 aPropSet.setProperty( PROP_ParaTabStops, aSeq );
501 else
502 aPropSet.setProperty<sal_Int32>( PROP_ParaFirstLineIndent, 0);
504 if ( moDefaultTabSize )
506 aPropSet.setProperty( PROP_ParaTabStopDefaultDistance, *moDefaultTabSize );
509 if ( moParaAdjust )
511 aPropSet.setProperty( PROP_ParaAdjust, *moParaAdjust);
513 else
515 aPropSet.setProperty( PROP_ParaAdjust, css::style::ParagraphAdjust_LEFT);
518 if ( maLineSpacing.bHasValue )
520 aPropSet.setProperty( PROP_ParaLineSpacing, maLineSpacing.toLineSpacing());
522 else
524 aPropSet.setProperty( PROP_ParaLineSpacing, css::style::LineSpacing( css::style::LineSpacingMode::PROP, 100 ));
528 float TextParagraphProperties::getCharHeightPoints( float fDefault ) const
530 return maTextCharacterProperties.getCharHeightPoints( fDefault );
533 #ifdef DBG_UTIL
534 // Note: Please don't remove this function. This is required for
535 // debugging pptx import problems.
536 void TextParagraphProperties::dump() const
538 Reference< css::drawing::XShape > xShape( oox::ppt::PowerPointImport::mpDebugFilterBase->getModelFactory()->createInstance( u"com.sun.star.presentation.TitleTextShape"_ustr ), UNO_QUERY );
539 Reference< css::text::XText > xText( xShape, UNO_QUERY );
541 Reference< css::drawing::XDrawPage > xDebugPage(ppt::SlidePersist::mxDebugPage.get(), UNO_QUERY);
542 if (xDebugPage.is())
543 xDebugPage->add( xShape );
545 PropertyMap emptyMap;
547 xText->setString( u"debug"_ustr );
548 Reference< css::text::XTextCursor > xStart = xText->createTextCursor();
549 xStart->gotoEnd( true );
550 Reference< XPropertySet > xPropSet( xStart, UNO_QUERY );
551 pushToPropSet( nullptr, xPropSet, emptyMap, nullptr, false, 0 );
552 PropertySet aPropSet( xPropSet );
553 aPropSet.dump();
555 #endif
558 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */