update dev300-m58
[ooovba.git] / svx / source / customshapes / EnhancedCustomShapeFontWork.cxx
blobb772ca84481b07f15e77c181cb4d93b788a4f796
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: EnhancedCustomShapeFontWork.cxx,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include "EnhancedCustomShapeFontWork.hxx"
34 #include <tools/solar.h> // UINTXX
35 #include <svx/svddef.hxx>
36 #include <svx/svdogrp.hxx>
37 #include <svx/svdopath.hxx>
38 #include <vcl/metric.hxx>
39 #include <svx/svdpage.hxx>
40 #include <svx/sdasitm.hxx>
41 #include <svx/sdasaitm.hxx>
42 #include <svx/sdtfsitm.hxx>
43 #include <vcl/virdev.hxx>
44 #include <svditer.hxx>
45 #include <vcl/metric.hxx>
46 #include <svx/eeitem.hxx>
47 #include <svx/frmdiritem.hxx>
48 #include <fontitem.hxx>
49 #include <svx/postitem.hxx>
50 #include <svx/wghtitem.hxx>
51 #include <svx/charscaleitem.hxx>
52 #include "EnhancedCustomShapeTypeNames.hxx"
53 #include <svx/svdorect.hxx>
54 #include <svx/svdoashp.hxx>
55 #include <svx/outliner.hxx>
56 #include <svx/outlobj.hxx>
57 #include <svx/editobj.hxx>
58 #include <svx/editeng.hxx>
59 #include <svx/svdmodel.hxx>
60 #include <vector>
61 #include <numeric>
62 #include <algorithm>
63 #include <comphelper/processfactory.hxx>
64 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
65 #include <com/sun/star/i18n/ScriptType.hdl>
66 #endif
67 #include <basegfx/polygon/b2dpolypolygontools.hxx>
68 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
69 #ifndef _COM_SUN_STAR_I18N_CHARACTERITERATORMODE_HDL_
70 #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
71 #endif
72 #include <basegfx/polygon/b2dpolygontools.hxx>
74 using namespace com::sun::star;
75 using namespace com::sun::star::uno;
77 typedef std::vector< std::vector< double > > PolyPolygonDistances;
79 struct FWCharacterData // representing a single character
81 std::vector< PolyPolygon > vOutlines;
82 Rectangle aBoundRect;
84 struct FWParagraphData // representing a single paragraph
86 rtl::OUString aString;
87 std::vector< FWCharacterData > vCharacters;
88 Rectangle aBoundRect;
89 sal_Int16 nFrameDirection;
91 struct FWTextArea // representing multiple concluding paragraphs
93 std::vector< FWParagraphData > vParagraphs;
94 Rectangle aBoundRect;
96 struct FWData // representing the whole text
98 std::vector< FWTextArea > vTextAreas;
99 double fHorizontalTextScaling;
100 sal_uInt32 nMaxParagraphsPerTextArea;
101 sal_Int32 nSingleLineHeight;
102 sal_Bool bSingleLineMode;
106 sal_Bool InitializeFontWorkData( const SdrObject* pCustomShape, const sal_uInt16 nOutlinesCount2d, FWData& rFWData )
108 sal_Bool bNoErr = sal_False;
109 sal_Bool bSingleLineMode = sal_False;
110 sal_uInt16 nTextAreaCount = nOutlinesCount2d;
111 if ( nOutlinesCount2d & 1 )
112 bSingleLineMode = sal_True;
113 else
114 nTextAreaCount >>= 1;
116 if ( nTextAreaCount )
118 rFWData.bSingleLineMode = bSingleLineMode;
120 // setting the strings
121 OutlinerParaObject* pParaObj = ((SdrObjCustomShape*)pCustomShape)->GetOutlinerParaObject();
122 if ( pParaObj )
124 const EditTextObject& rTextObj = pParaObj->GetTextObject();
125 sal_Int32 nParagraphsLeft = rTextObj.GetParagraphCount();
127 rFWData.nMaxParagraphsPerTextArea = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
128 sal_Int16 j = 0;
129 while( nParagraphsLeft && nTextAreaCount )
131 FWTextArea aTextArea;
132 sal_Int32 i, nParagraphs = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
133 for ( i = 0; i < nParagraphs; i++, j++ )
135 FWParagraphData aParagraphData;
136 aParagraphData.aString = rTextObj.GetText( j );
138 const SfxItemSet& rParaSet = rTextObj.GetParaAttribs( j ); // retrieving some paragraph attributes
139 aParagraphData.nFrameDirection = ((SvxFrameDirectionItem&)rParaSet.Get( EE_PARA_WRITINGDIR )).GetValue();
140 aTextArea.vParagraphs.push_back( aParagraphData );
142 rFWData.vTextAreas.push_back( aTextArea );
143 nParagraphsLeft -= nParagraphs;
144 nTextAreaCount--;
146 bNoErr = sal_True;
149 return bNoErr;
152 double GetLength( const Polygon& rPolygon )
154 double fLength = 0;
155 if ( rPolygon.GetSize() > 1 )
157 sal_uInt16 nCount = rPolygon.GetSize();
158 while( --nCount )
159 fLength += ((Polygon&)rPolygon).CalcDistance( nCount, nCount - 1 );
161 return fLength;
165 /* CalculateHorizontalScalingFactor returns the horizontal scaling factor for
166 the whole text object, so that each text will match its corresponding 2d Outline */
167 void CalculateHorizontalScalingFactor( const SdrObject* pCustomShape,
168 FWData& rFWData, const PolyPolygon& rOutline2d )
170 double fScalingFactor = 1.0;
171 sal_Bool bScalingFactorDefined = sal_False;
173 sal_uInt16 i = 0;
174 sal_Bool bSingleLineMode = sal_False;
175 sal_uInt16 nOutlinesCount2d = rOutline2d.Count();
177 Font aFont;
178 SvxFontItem& rFontItem = (SvxFontItem&)pCustomShape->GetMergedItem( EE_CHAR_FONTINFO );
179 aFont.SetHeight( pCustomShape->GetLogicRect().GetHeight() / rFWData.nMaxParagraphsPerTextArea );
180 aFont.SetAlign( ALIGN_TOP );
181 aFont.SetName( rFontItem.GetFamilyName() );
182 aFont.SetFamily( rFontItem.GetFamily() );
183 aFont.SetStyleName( rFontItem.GetStyleName() );
184 aFont.SetOrientation( 0 );
185 // initializing virtual device
187 VirtualDevice aVirDev( 1 );
188 aVirDev.SetMapMode( MAP_100TH_MM );
189 aVirDev.SetFont( aFont );
191 if ( nOutlinesCount2d & 1 )
192 bSingleLineMode = sal_True;
194 std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreas.begin();
195 std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.end();
196 while( aTextAreaIter != aTextAreaIEnd )
198 // calculating the width of the corresponding 2d text area
199 double fWidth = GetLength( rOutline2d.GetObject( i++ ) );
200 if ( !bSingleLineMode )
202 fWidth += GetLength( rOutline2d.GetObject( i++ ) );
203 fWidth /= 2.0;
205 std::vector< FWParagraphData >::const_iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
206 std::vector< FWParagraphData >::const_iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
207 while( aParagraphIter != aParagraphIEnd )
209 double fTextWidth = aVirDev.GetTextWidth( aParagraphIter->aString );
210 if ( fTextWidth > 0.0 )
212 double fScale = fWidth / fTextWidth;
213 if ( !bScalingFactorDefined )
215 fScalingFactor = fScale;
216 bScalingFactorDefined = sal_True;
218 else
220 if ( fScale < fScalingFactor )
221 fScalingFactor = fScale;
224 aParagraphIter++;
226 aTextAreaIter++;
228 rFWData.fHorizontalTextScaling = fScalingFactor;
231 void GetTextAreaOutline( const FWData& rFWData, const SdrObject* pCustomShape, FWTextArea& rTextArea, sal_Bool bSameLetterHeights )
233 sal_Bool bIsVertical = ((SdrObjCustomShape*)pCustomShape)->IsVerticalWriting();
234 sal_Int32 nVerticalOffset = rFWData.nMaxParagraphsPerTextArea > rTextArea.vParagraphs.size()
235 ? rFWData.nSingleLineHeight / 2 : 0;
237 std::vector< FWParagraphData >::iterator aParagraphIter( rTextArea.vParagraphs.begin() );
238 std::vector< FWParagraphData >::iterator aParagraphIEnd( rTextArea.vParagraphs.end() );
239 while( aParagraphIter != aParagraphIEnd )
241 const rtl::OUString& rText = aParagraphIter->aString;
242 if ( rText.getLength() )
244 // generating vcl/font
245 USHORT nScriptType = i18n::ScriptType::LATIN;
246 Reference< i18n::XBreakIterator > xBI( EnhancedCustomShapeFontWork::GetBreakIterator() );
247 if ( xBI.is() )
249 nScriptType = xBI->getScriptType( rText, 0 );
250 sal_uInt16 nChg = 0;
251 if( i18n::ScriptType::WEAK == nScriptType )
253 nChg = (xub_StrLen)xBI->endOfScript( rText, nChg, nScriptType );
254 if( nChg < rText.getLength() )
255 nScriptType = xBI->getScriptType( rText, nChg );
256 else
257 nScriptType = i18n::ScriptType::LATIN;
260 UINT16 nFntItm = EE_CHAR_FONTINFO;
261 if ( nScriptType == i18n::ScriptType::COMPLEX )
262 nFntItm = EE_CHAR_FONTINFO_CTL;
263 else if ( nScriptType == i18n::ScriptType::ASIAN )
264 nFntItm = EE_CHAR_FONTINFO_CJK;
265 SvxFontItem& rFontItem = (SvxFontItem&)pCustomShape->GetMergedItem( nFntItm );
266 Font aFont;
267 aFont.SetHeight( rFWData.nSingleLineHeight );
268 aFont.SetAlign( ALIGN_TOP );
269 // aFont.SetAlign( )
271 aFont.SetName( rFontItem.GetFamilyName() );
272 aFont.SetFamily( rFontItem.GetFamily() );
273 aFont.SetStyleName( rFontItem.GetStyleName() );
274 aFont.SetOrientation( 0 );
276 SvxPostureItem& rPostureItem = (SvxPostureItem&)pCustomShape->GetMergedItem( EE_CHAR_ITALIC );
277 aFont.SetItalic( rPostureItem.GetPosture() );
279 SvxWeightItem& rWeightItem = (SvxWeightItem&)pCustomShape->GetMergedItem( EE_CHAR_WEIGHT );
280 aFont.SetWeight( rWeightItem.GetWeight() );
282 // initializing virtual device
283 VirtualDevice aVirDev( 1 );
284 aVirDev.SetMapMode( MAP_100TH_MM );
285 aVirDev.SetFont( aFont );
286 aVirDev.EnableRTL( sal_True );
287 if ( aParagraphIter->nFrameDirection == FRMDIR_HORI_RIGHT_TOP )
288 aVirDev.SetLayoutMode( TEXT_LAYOUT_BIDI_RTL );
290 SvxCharScaleWidthItem& rCharScaleWidthItem = (SvxCharScaleWidthItem&)pCustomShape->GetMergedItem( EE_CHAR_FONTWIDTH );
291 sal_uInt16 nCharScaleWidth = rCharScaleWidthItem.GetValue();
292 sal_Int32* pDXArry = NULL;
293 sal_Int32 nWidth = 0;
295 // VERTICAL
296 if ( bIsVertical )
298 // vertical _> each single character needs to be rotated by 90
299 sal_Int32 i;
300 sal_Int32 nHeight = 0;
301 Rectangle aSingleCharacterUnion;
302 for ( i = 0; i < rText.getLength(); i++ )
304 FWCharacterData aCharacterData;
305 rtl::OUString aCharText( (sal_Unicode)rText[ i ] );
306 if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, aCharText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
308 sal_Int32 nTextWidth = aVirDev.GetTextWidth( aCharText, 0, STRING_LEN );
309 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterData.vOutlines.begin();
310 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterData.vOutlines.end();
311 if ( aOutlineIter == aOutlineIEnd )
313 nHeight += rFWData.nSingleLineHeight;
315 else
317 while ( aOutlineIter != aOutlineIEnd )
319 // rotating
320 aOutlineIter->Rotate( Point( nTextWidth / 2, rFWData.nSingleLineHeight / 2 ), 900 );
321 aCharacterData.aBoundRect.Union( aOutlineIter->GetBoundRect() );
322 aOutlineIter++;
324 aOutlineIter = aCharacterData.vOutlines.begin();
325 aOutlineIEnd = aCharacterData.vOutlines.end();
326 while ( aOutlineIter != aOutlineIEnd )
328 sal_Int32 nM = - aCharacterData.aBoundRect.Left() + nHeight;
329 aOutlineIter->Move( nM, 0 );
330 aCharacterData.aBoundRect.Move( nM, 0 );
331 aOutlineIter++;
333 nHeight += aCharacterData.aBoundRect.GetWidth() + ( rFWData.nSingleLineHeight / 5 );
334 aSingleCharacterUnion.Union( aCharacterData.aBoundRect );
337 aParagraphIter->vCharacters.push_back( aCharacterData );
339 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
340 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
341 while ( aCharacterIter != aCharacterIEnd )
343 std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
344 std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
345 while ( aOutlineIter != aOutlineIEnd )
347 aOutlineIter->Move( ( aSingleCharacterUnion.GetWidth() - aCharacterIter->aBoundRect.GetWidth() ) / 2, 0 );
348 aOutlineIter++;
350 aCharacterIter++;
353 else
355 if ( ( nCharScaleWidth != 100 ) && nCharScaleWidth )
356 { // applying character spacing
357 pDXArry = new sal_Int32[ rText.getLength() ];
358 aVirDev.GetTextArray( rText, pDXArry, 0, STRING_LEN );
359 FontMetric aFontMetric( aVirDev.GetFontMetric() );
360 aFont.SetWidth( (sal_Int32)( (double)aFontMetric.GetWidth() * ( (double)100 / (double)nCharScaleWidth ) ) );
361 aVirDev.SetFont( aFont );
363 FWCharacterData aCharacterData;
364 if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, rText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
366 aParagraphIter->vCharacters.push_back( aCharacterData );
369 /* trying to retrieve each single character _> is not working well
370 sal_Int32 i;
371 for ( i = 0; i < rText.getLength(); i++ )
373 FWCharacterData aCharacterData;
374 if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, rText, 0, i, 1, TRUE, nWidth, pDXArry ) )
376 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterData.vOutlines.begin();
377 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterData.vOutlines.end();
378 while ( aOutlineIter != aOutlineIEnd )
380 aCharacterData.aBoundRect.Union( aOutlineIter->GetBoundRect() );
381 aOutlineIter++;
384 aParagraphIter->vCharacters.push_back( aCharacterData );
388 delete[] pDXArry;
390 // veritcal alignment
391 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
392 std::vector< FWCharacterData >::iterator aCharacterIEnd ( aParagraphIter->vCharacters.end() );
393 while ( aCharacterIter != aCharacterIEnd )
395 std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
396 std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
397 while( aOutlineIter != aOutlineIEnd )
400 PolyPolygon& rPolyPoly = *aOutlineIter++;
402 if ( nVerticalOffset )
403 rPolyPoly.Move( 0, nVerticalOffset );
405 // retrieving the boundrect for the paragraph
406 Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
407 aParagraphIter->aBoundRect.Union( aBoundRect );
409 aCharacterIter++;
412 // updating the boundrect for the text area by merging the current paragraph boundrect
413 if ( aParagraphIter->aBoundRect.IsEmpty() )
415 if ( rTextArea.aBoundRect.IsEmpty() )
416 rTextArea.aBoundRect = Rectangle( Point( 0, 0 ), Size( 1, rFWData.nSingleLineHeight ) );
417 else
418 rTextArea.aBoundRect.Bottom() += rFWData.nSingleLineHeight;
420 else
422 Rectangle& rParagraphBoundRect = aParagraphIter->aBoundRect;
423 rTextArea.aBoundRect.Union( rParagraphBoundRect );
425 if ( bSameLetterHeights )
427 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
428 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
429 while ( aCharacterIter != aCharacterIEnd )
431 std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
432 std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
433 while( aOutlineIter != aOutlineIEnd )
435 Rectangle aPolyPolyBoundRect( aOutlineIter->GetBoundRect() );
436 if ( aPolyPolyBoundRect.GetHeight() != rParagraphBoundRect.GetHeight() )
437 aOutlineIter->Scale( 1.0, (double)rParagraphBoundRect.GetHeight() / aPolyPolyBoundRect.GetHeight() );
438 aPolyPolyBoundRect = aOutlineIter->GetBoundRect();
439 sal_Int32 nMove = aPolyPolyBoundRect.Top() - rParagraphBoundRect.Top();
440 if ( nMove )
441 aOutlineIter->Move( 0, -nMove );
442 aOutlineIter++;
444 aCharacterIter++;
448 if ( bIsVertical )
449 nVerticalOffset -= rFWData.nSingleLineHeight;
450 else
451 nVerticalOffset += rFWData.nSingleLineHeight;
452 aParagraphIter++;
456 void GetFontWorkOutline( FWData& rFWData, const SdrObject* pCustomShape )
458 SdrTextHorzAdjust eHorzAdjust( ((SdrTextHorzAdjustItem&)pCustomShape->GetMergedItem( SDRATTR_TEXT_HORZADJUST )).GetValue() );
459 SdrFitToSizeType eFTS( ((SdrTextFitToSizeTypeItem&)pCustomShape->GetMergedItem( SDRATTR_TEXT_FITTOSIZE )).GetValue() );
461 std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreas.begin();
462 std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.end();
464 rFWData.nSingleLineHeight = (sal_Int32)( ( (double)pCustomShape->GetLogicRect().GetHeight()
465 / rFWData.nMaxParagraphsPerTextArea ) * rFWData.fHorizontalTextScaling );
467 sal_Bool bSameLetterHeights = sal_False;
468 SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
469 const rtl::OUString sTextPath( RTL_CONSTASCII_USTRINGPARAM ( "TextPath" ) );
470 const rtl::OUString sSameLetterHeights( RTL_CONSTASCII_USTRINGPARAM ( "SameLetterHeights" ) );
471 com::sun::star::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sSameLetterHeights );
472 if ( pAny )
473 *pAny >>= bSameLetterHeights;
475 while ( aTextAreaIter != aTextAreaIEnd )
477 GetTextAreaOutline( rFWData, pCustomShape, *aTextAreaIter, bSameLetterHeights );
478 if ( eFTS == SDRTEXTFIT_ALLLINES )
480 std::vector< FWParagraphData >::iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
481 std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
482 while ( aParagraphIter != aParagraphIEnd )
484 sal_Int32 nParaWidth = aParagraphIter->aBoundRect.GetWidth();
485 if ( nParaWidth )
487 double fScale = (double)aTextAreaIter->aBoundRect.GetWidth() / nParaWidth;
489 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
490 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
491 while ( aCharacterIter != aCharacterIEnd )
493 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
494 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
495 while( aOutlineIter != aOutlineIEnd )
497 aOutlineIter->Scale( fScale, 1.0 );
498 aOutlineIter++;
500 aCharacterIter++;
503 aParagraphIter++;
506 else
508 switch( eHorzAdjust )
510 case SDRTEXTHORZADJUST_RIGHT :
511 case SDRTEXTHORZADJUST_CENTER:
513 std::vector< FWParagraphData >::iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
514 std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
515 while ( aParagraphIter != aParagraphIEnd )
517 sal_Int32 nHorzDiff = 0;
518 if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
519 nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphIter->aBoundRect.GetWidth() ) / 2;
520 else if ( eHorzAdjust == SDRTEXTHORZADJUST_RIGHT )
521 nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphIter->aBoundRect.GetWidth() );
522 if ( nHorzDiff )
524 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
525 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
526 while ( aCharacterIter != aCharacterIEnd )
528 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
529 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
530 while( aOutlineIter != aOutlineIEnd )
532 aOutlineIter->Move( nHorzDiff, 0 );
533 aOutlineIter++;
535 aCharacterIter++;
538 aParagraphIter++;
541 break;
542 default:
543 case SDRTEXTHORZADJUST_BLOCK : break; // don't know
544 case SDRTEXTHORZADJUST_LEFT : break; // already left aligned -> nothing to do
547 aTextAreaIter++;
551 basegfx::B2DPolyPolygon GetOutlinesFromShape2d( const SdrObject* pShape2d )
553 basegfx::B2DPolyPolygon aOutlines2d;
555 SdrObjListIter aObjListIter( *pShape2d, IM_DEEPWITHGROUPS );
556 while( aObjListIter.IsMore() )
558 SdrObject* pPartObj = aObjListIter.Next();
559 if ( pPartObj->ISA( SdrPathObj ) )
561 basegfx::B2DPolyPolygon aCandidate(((SdrPathObj*)pPartObj)->GetPathPoly());
562 if(aCandidate.areControlPointsUsed())
564 aCandidate = basegfx::tools::adaptiveSubdivideByAngle(aCandidate);
566 aOutlines2d.append(aCandidate);
570 return aOutlines2d;
573 void CalcDistances( const Polygon& rPoly, std::vector< double >& rDistances )
575 sal_uInt16 i, nCount = rPoly.GetSize();
576 if ( nCount > 1 )
578 for ( i = 0; i < nCount; i++ )
580 double fDistance = i ? ((Polygon&)rPoly).CalcDistance( i, i - 1 ) : 0.0;
581 rDistances.push_back( fDistance );
583 std::partial_sum( rDistances.begin(), rDistances.end(), rDistances.begin() );
584 double fLength = rDistances[ rDistances.size() - 1 ];
585 if ( fLength > 0.0 )
587 std::vector< double >::iterator aIter = rDistances.begin();
588 std::vector< double >::iterator aEnd = rDistances.end();
589 while ( aIter != aEnd )
590 *aIter++ /= fLength;
595 void InsertMissingOutlinePoints( const Polygon& /*rOutlinePoly*/, const std::vector< double >& rDistances, const Rectangle& rTextAreaBoundRect, Polygon& rPoly )
597 sal_uInt16 i = 0;
598 double fLastDistance = 0.0;
599 for ( i = 0; i < rPoly.GetSize(); i++ )
601 Point& rPoint = rPoly[ i ];
602 double fDistance = (double)( rPoint.X() - rTextAreaBoundRect.Left() ) / (double)rTextAreaBoundRect.GetWidth();
603 if ( i )
605 if ( fDistance > fLastDistance )
607 std::vector< double >::const_iterator aIter = std::upper_bound( rDistances.begin(), rDistances.end(), fLastDistance );
608 if ( aIter != rDistances.end() && ( *aIter > fLastDistance ) && ( *aIter < fDistance ) )
610 Point& rPt0 = rPoly[ i - 1 ];
611 sal_Int32 fX = rPoint.X() - rPt0.X();
612 sal_Int32 fY = rPoint.Y() - rPt0.Y();
613 double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
614 rPoly.Insert( i, Point( (sal_Int32)( rPt0.X() + fX * fd ), (sal_Int32)( rPt0.Y() + fY * fd ) ) );
615 fDistance = *aIter;
618 else if ( fDistance < fLastDistance )
620 std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fLastDistance );
621 if ( aIter-- != rDistances.begin() )
623 if ( ( *aIter > fDistance ) && ( *aIter < fLastDistance ) )
625 Point& rPt0 = rPoly[ i - 1 ];
626 sal_Int32 fX = rPoint.X() - rPt0.X();
627 sal_Int32 fY = rPoint.Y() - rPt0.Y();
628 double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
629 rPoly.Insert( i, Point( (sal_Int32)( rPt0.X() + fX * fd ), (sal_Int32)( rPt0.Y() + fY * fd ) ) );
630 fDistance = *aIter;
635 fLastDistance = fDistance;
639 void GetPoint( const Polygon& rPoly, const std::vector< double >& rDistances, const double& fX, double& fx1, double& fy1 )
641 fy1 = fx1 = 0.0;
642 if ( rPoly.GetSize() > 1 )
644 std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fX );
645 sal_uInt16 nIdx = sal::static_int_cast<sal_uInt16>( std::distance( rDistances.begin(), aIter ) );
646 if ( aIter == rDistances.end() )
647 nIdx--;
648 const Point& rPt = rPoly[ nIdx ];
649 fx1 = rPt.X();
650 fy1 = rPt.Y();
651 if ( nIdx && ( aIter != rDistances.end() ) && ( *aIter != fX ) )
653 nIdx = sal::static_int_cast<sal_uInt16>( std::distance( rDistances.begin(), aIter ) );
654 double fDist0 = *( aIter - 1 );
655 double fd = ( 1.0 / ( *aIter - fDist0 ) ) * ( fX - fDist0 );
656 const Point& rPt2 = rPoly[ nIdx - 1 ];
657 double fWidth = rPt.X() - rPt2.X();
658 double fHeight= rPt.Y() - rPt2.Y();
659 fWidth *= fd;
660 fHeight*= fd;
661 fx1 = rPt2.X() + fWidth;
662 fy1 = rPt2.Y() + fHeight;
667 void FitTextOutlinesToShapeOutlines( const PolyPolygon& aOutlines2d, FWData& rFWData )
669 std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreas.begin();
670 std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.end();
672 sal_uInt16 nOutline2dIdx = 0;
673 while( aTextAreaIter != aTextAreaIEnd )
675 Rectangle rTextAreaBoundRect = aTextAreaIter->aBoundRect;
676 sal_Int32 nLeft = rTextAreaBoundRect.Left();
677 sal_Int32 nTop = rTextAreaBoundRect.Top();
678 sal_Int32 nWidth = rTextAreaBoundRect.GetWidth();
679 sal_Int32 nHeight= rTextAreaBoundRect.GetHeight();
680 if ( rFWData.bSingleLineMode && nHeight && nWidth )
682 if ( nOutline2dIdx >= aOutlines2d.Count() )
683 break;
684 const Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
685 const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
686 if ( nPointCount > 1 )
688 std::vector< double > vDistances;
689 vDistances.reserve( nPointCount );
690 CalcDistances( rOutlinePoly, vDistances );
691 if ( vDistances.size() )
693 std::vector< FWParagraphData >::iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
694 std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
695 while( aParagraphIter != aParagraphIEnd )
697 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
698 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
699 while ( aCharacterIter != aCharacterIEnd )
701 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
702 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
703 while( aOutlineIter != aOutlineIEnd )
705 PolyPolygon& rPolyPoly = *aOutlineIter;
706 Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
707 double fx1 = aBoundRect.Left() - nLeft;
708 double fx2 = aBoundRect.Right() - nLeft;
709 double fy1, fy2;
710 double fM1 = fx1 / (double)nWidth;
711 double fM2 = fx2 / (double)nWidth;
713 GetPoint( rOutlinePoly, vDistances, fM1, fx1, fy1 );
714 GetPoint( rOutlinePoly, vDistances, fM2, fx2, fy2 );
716 double fvx = ( fy2 - fy1 );
717 double fvy = - ( fx2 - fx1 );
718 fx1 = fx1 + ( ( fx2 - fx1 ) * 0.5 );
719 fy1 = fy1 + ( ( fy2 - fy1 ) * 0.5 );
721 double fAngle = atan2( -fvx, -fvy );
722 double fL = hypot( fvx, fvy );
723 fvx = fvx / fL;
724 fvy = fvy / fL;
725 fL = (double)( aTextAreaIter->aBoundRect.GetHeight() / 2.0 + aTextAreaIter->aBoundRect.Top() ) - aParagraphIter->aBoundRect.Center().Y();
726 fvx *= fL;
727 fvy *= fL;
728 rPolyPoly.Rotate( Point( aBoundRect.Center().X(), aParagraphIter->aBoundRect.Center().Y() ), sin( fAngle ), cos( fAngle ) );
729 rPolyPoly.Move( (sal_Int32)( ( fx1 + fvx )- aBoundRect.Center().X() ), (sal_Int32)( ( fy1 + fvy ) - aParagraphIter->aBoundRect.Center().Y() ) );
731 aOutlineIter++;
733 aCharacterIter++;
735 aParagraphIter++;
740 else
742 if ( ( nOutline2dIdx + 1 ) >= aOutlines2d.Count() )
743 break;
744 const Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
745 const Polygon& rOutlinePoly2( aOutlines2d[ nOutline2dIdx++ ] );
746 const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
747 const sal_uInt16 nPointCount2 = rOutlinePoly2.GetSize();
748 if ( ( nPointCount > 1 ) && ( nPointCount2 > 1 ) )
750 std::vector< double > vDistances;
751 vDistances.reserve( nPointCount );
752 std::vector< double > vDistances2;
753 vDistances2.reserve( nPointCount2 );
754 CalcDistances( rOutlinePoly, vDistances );
755 CalcDistances( rOutlinePoly2, vDistances2 );
756 std::vector< FWParagraphData >::iterator aParagraphIter = aTextAreaIter->vParagraphs.begin();
757 std::vector< FWParagraphData >::iterator aParagraphIEnd = aTextAreaIter->vParagraphs.end();
758 while( aParagraphIter != aParagraphIEnd )
760 std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
761 std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
762 while ( aCharacterIter != aCharacterIEnd )
764 std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
765 std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
766 while( aOutlineIter != aOutlineIEnd )
768 PolyPolygon& rPolyPoly = *aOutlineIter;
769 sal_uInt16 i, nPolyCount = rPolyPoly.Count();
770 for ( i = 0; i < nPolyCount; i++ )
772 // #i35928#
773 basegfx::B2DPolygon aCandidate(rPolyPoly[ i ].getB2DPolygon());
775 if(aCandidate.areControlPointsUsed())
777 aCandidate = basegfx::tools::adaptiveSubdivideByAngle(aCandidate);
780 // create local polygon copy to work on
781 Polygon aLocalPoly(aCandidate);
783 InsertMissingOutlinePoints( rOutlinePoly, vDistances, rTextAreaBoundRect, aLocalPoly );
784 InsertMissingOutlinePoints( rOutlinePoly2, vDistances2, rTextAreaBoundRect, aLocalPoly );
786 sal_uInt16 j, _nPointCount = aLocalPoly.GetSize();
787 for ( j = 0; j < _nPointCount; j++ )
789 Point& rPoint = aLocalPoly[ j ];
790 rPoint.X() -= nLeft;
791 rPoint.Y() -= nTop;
792 double fX = (double)rPoint.X() / (double)nWidth;
793 double fY = (double)rPoint.Y() / (double)nHeight;
795 double fx1, fy1, fx2, fy2;
796 GetPoint( rOutlinePoly, vDistances, fX, fx1, fy1 );
797 GetPoint( rOutlinePoly2, vDistances2, fX, fx2, fy2 );
798 double fWidth = fx2 - fx1;
799 double fHeight= fy2 - fy1;
800 rPoint.X() = (sal_Int32)( fx1 + fWidth * fY );
801 rPoint.Y() = (sal_Int32)( fy1 + fHeight* fY );
804 // write back polygon
805 rPolyPoly[ i ] = aLocalPoly;
807 aOutlineIter++;
809 aCharacterIter++;
811 aParagraphIter++;
815 aTextAreaIter++;
819 SdrObject* CreateSdrObjectFromParagraphOutlines( const FWData& rFWData, const SdrObject* pCustomShape )
821 SdrObject* pRet = NULL;
822 if ( rFWData.vTextAreas.size() )
824 pRet = new SdrObjGroup();
825 // SJ: not setting model, so we save a lot of broadcasting and the model is not modified any longer
826 // pRet->SetModel( pCustomShape->GetModel() );
827 std::vector< FWTextArea >::const_iterator aTextAreaIter = rFWData.vTextAreas.begin();
828 std::vector< FWTextArea >::const_iterator aTextAreaIEnd = rFWData.vTextAreas.end();
829 while ( aTextAreaIter != aTextAreaIEnd )
831 std::vector< FWParagraphData >::const_iterator aParagraphIter = aTextAreaIter->vParagraphs.begin();
832 std::vector< FWParagraphData >::const_iterator aParagraphIEnd = aTextAreaIter->vParagraphs.end();
833 while ( aParagraphIter != aParagraphIEnd )
835 std::vector< FWCharacterData >::const_iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
836 std::vector< FWCharacterData >::const_iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
837 while ( aCharacterIter != aCharacterIEnd )
839 std::vector< PolyPolygon >::const_iterator aOutlineIter = aCharacterIter->vOutlines.begin();
840 std::vector< PolyPolygon >::const_iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
841 while( aOutlineIter != aOutlineIEnd )
843 SdrObject* pPathObj = new SdrPathObj( OBJ_POLY, aOutlineIter->getB2DPolyPolygon() );
844 // SJ: not setting model, so we save a lot of broadcasting and the model is not modified any longer
845 // pPathObj->SetModel( pCustomShape->GetModel() );
846 ((SdrObjGroup*)pRet)->GetSubList()->NbcInsertObject( pPathObj );
847 aOutlineIter++;
849 aCharacterIter++;
851 aParagraphIter++;
853 aTextAreaIter++;
856 Point aP( pCustomShape->GetSnapRect().Center() );
857 Size aS( pCustomShape->GetLogicRect().GetSize() );
858 aP.X() -= aS.Width() / 2;
859 aP.Y() -= aS.Height() / 2;
860 Rectangle aLogicRect( aP, aS );
862 SfxItemSet aSet( pCustomShape->GetMergedItemSet() );
863 aSet.ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
864 aSet.Put(SdrShadowItem(sal_False)); // #i37011# NO shadow for FontWork geometry
865 pRet->SetMergedItemSet( aSet ); // * otherwise we would crash, because the outliner tries to create a Paraobject, but there is no model
867 return pRet;
870 ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > EnhancedCustomShapeFontWork::mxBreakIterator = 0;
872 Reference < i18n::XBreakIterator > EnhancedCustomShapeFontWork::GetBreakIterator()
874 if ( !mxBreakIterator.is() )
876 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
877 Reference < XInterface > xI = xMSF->createInstance( rtl::OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
878 if ( xI.is() )
880 Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XBreakIterator >*)0) );
881 x >>= mxBreakIterator;
884 return mxBreakIterator;
887 SdrObject* EnhancedCustomShapeFontWork::CreateFontWork( const SdrObject* pShape2d, const SdrObject* pCustomShape )
889 SdrObject* pRet = NULL;
891 Rectangle aLogicRect( pCustomShape->GetLogicRect() );
892 PolyPolygon aOutlines2d( GetOutlinesFromShape2d( pShape2d ) );
893 sal_uInt16 nOutlinesCount2d = aOutlines2d.Count();
894 if ( nOutlinesCount2d )
896 FWData aFWData;
897 if ( InitializeFontWorkData( pCustomShape, nOutlinesCount2d, aFWData ) )
899 /* retrieves the horizontal scaling factor that has to be used
900 to fit each paragraph text into its corresponding 2d outline */
901 CalculateHorizontalScalingFactor( pCustomShape, aFWData, aOutlines2d );
903 /* retrieving the Outlines for the each Paragraph. */
905 GetFontWorkOutline( aFWData, pCustomShape );
907 FitTextOutlinesToShapeOutlines( aOutlines2d, aFWData );
909 pRet = CreateSdrObjectFromParagraphOutlines( aFWData, pCustomShape );
912 return pRet;