1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: EnhancedCustomShapeFontWork.cxx,v $
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>
63 #include <comphelper/processfactory.hxx>
64 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
65 #include <com/sun/star/i18n/ScriptType.hdl>
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>
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
;
84 struct FWParagraphData
// representing a single paragraph
86 rtl::OUString aString
;
87 std::vector
< FWCharacterData
> vCharacters
;
89 sal_Int16 nFrameDirection
;
91 struct FWTextArea
// representing multiple concluding paragraphs
93 std::vector
< FWParagraphData
> vParagraphs
;
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
;
114 nTextAreaCount
>>= 1;
116 if ( nTextAreaCount
)
118 rFWData
.bSingleLineMode
= bSingleLineMode
;
120 // setting the strings
121 OutlinerParaObject
* pParaObj
= ((SdrObjCustomShape
*)pCustomShape
)->GetOutlinerParaObject();
124 const EditTextObject
& rTextObj
= pParaObj
->GetTextObject();
125 sal_Int32 nParagraphsLeft
= rTextObj
.GetParagraphCount();
127 rFWData
.nMaxParagraphsPerTextArea
= ( ( nParagraphsLeft
- 1 ) / nTextAreaCount
) + 1;
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
;
152 double GetLength( const Polygon
& rPolygon
)
155 if ( rPolygon
.GetSize() > 1 )
157 sal_uInt16 nCount
= rPolygon
.GetSize();
159 fLength
+= ((Polygon
&)rPolygon
).CalcDistance( nCount
, nCount
- 1 );
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
;
174 sal_Bool bSingleLineMode
= sal_False
;
175 sal_uInt16 nOutlinesCount2d
= rOutline2d
.Count();
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
++ ) );
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
;
220 if ( fScale
< fScalingFactor
)
221 fScalingFactor
= fScale
;
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() );
249 nScriptType
= xBI
->getScriptType( rText
, 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
);
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
);
267 aFont
.SetHeight( rFWData
.nSingleLineHeight
);
268 aFont
.SetAlign( ALIGN_TOP
);
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;
298 // vertical _> each single character needs to be rotated by 90
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
;
317 while ( aOutlineIter
!= aOutlineIEnd
)
320 aOutlineIter
->Rotate( Point( nTextWidth
/ 2, rFWData
.nSingleLineHeight
/ 2 ), 900 );
321 aCharacterData
.aBoundRect
.Union( aOutlineIter
->GetBoundRect() );
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 );
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 );
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
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() );
384 aParagraphIter->vCharacters.push_back( aCharacterData );
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
);
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
) );
418 rTextArea
.aBoundRect
.Bottom() += rFWData
.nSingleLineHeight
;
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();
441 aOutlineIter
->Move( 0, -nMove
);
449 nVerticalOffset
-= rFWData
.nSingleLineHeight
;
451 nVerticalOffset
+= rFWData
.nSingleLineHeight
;
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
);
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();
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 );
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() );
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 );
543 case SDRTEXTHORZADJUST_BLOCK
: break; // don't know
544 case SDRTEXTHORZADJUST_LEFT
: break; // already left aligned -> nothing to do
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
);
573 void CalcDistances( const Polygon
& rPoly
, std::vector
< double >& rDistances
)
575 sal_uInt16 i
, nCount
= rPoly
.GetSize();
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 ];
587 std::vector
< double >::iterator aIter
= rDistances
.begin();
588 std::vector
< double >::iterator aEnd
= rDistances
.end();
589 while ( aIter
!= aEnd
)
595 void InsertMissingOutlinePoints( const Polygon
& /*rOutlinePoly*/, const std::vector
< double >& rDistances
, const Rectangle
& rTextAreaBoundRect
, Polygon
& rPoly
)
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();
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
) ) );
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
) ) );
635 fLastDistance
= fDistance
;
639 void GetPoint( const Polygon
& rPoly
, const std::vector
< double >& rDistances
, const double& fX
, double& fx1
, double& fy1
)
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() )
648 const Point
& rPt
= rPoly
[ nIdx
];
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();
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() )
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
;
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
);
725 fL
= (double)( aTextAreaIter
->aBoundRect
.GetHeight() / 2.0 + aTextAreaIter
->aBoundRect
.Top() ) - aParagraphIter
->aBoundRect
.Center().Y();
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() ) );
742 if ( ( nOutline2dIdx
+ 1 ) >= aOutlines2d
.Count() )
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
++ )
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
];
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
;
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
);
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
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" ) );
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
)
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
);