1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "EnhancedCustomShapeFontWork.hxx"
21 #include <tools/solar.h> // UINTXX
22 #include <svx/svddef.hxx>
23 #include <svx/svdogrp.hxx>
24 #include <svx/svdopath.hxx>
25 #include <vcl/metric.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/sdasitm.hxx>
28 #include <svx/sdasaitm.hxx>
29 #include <svx/sdtfsitm.hxx>
30 #include <vcl/virdev.hxx>
31 #include <svx/svditer.hxx>
32 #include <editeng/eeitem.hxx>
33 #include <editeng/frmdiritem.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/postitem.hxx>
36 #include <editeng/wghtitem.hxx>
37 #include <editeng/charscaleitem.hxx>
38 #include "svx/EnhancedCustomShapeTypeNames.hxx"
39 #include <svx/svdorect.hxx>
40 #include <svx/svdoashp.hxx>
41 #include <editeng/outliner.hxx>
42 #include <editeng/outlobj.hxx>
43 #include <editeng/editobj.hxx>
44 #include <editeng/editeng.hxx>
45 #include <svx/svdmodel.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <com/sun/star/i18n/BreakIterator.hpp>
51 #include <com/sun/star/i18n/ScriptType.hpp>
52 #include <basegfx/polygon/b2dpolypolygontools.hxx>
53 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
54 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
55 #include <basegfx/polygon/b2dpolygontools.hxx>
57 using namespace com::sun::star
;
58 using namespace com::sun::star::uno
;
60 struct FWCharacterData
// representing a single character
62 std::vector
< PolyPolygon
> vOutlines
;
65 struct FWParagraphData
// representing a single paragraph
68 std::vector
< FWCharacterData
> vCharacters
;
70 sal_Int16 nFrameDirection
;
72 struct FWTextArea
// representing multiple concluding paragraphs
74 std::vector
< FWParagraphData
> vParagraphs
;
77 struct FWData
// representing the whole text
79 std::vector
< FWTextArea
> vTextAreas
;
80 double fHorizontalTextScaling
;
81 sal_uInt32 nMaxParagraphsPerTextArea
;
82 sal_Int32 nSingleLineHeight
;
87 static bool InitializeFontWorkData( const SdrObject
* pCustomShape
, const sal_uInt16 nOutlinesCount2d
, FWData
& rFWData
)
90 bool bSingleLineMode
= false;
91 sal_uInt16 nTextAreaCount
= nOutlinesCount2d
;
92 if ( nOutlinesCount2d
& 1 )
93 bSingleLineMode
= true;
99 rFWData
.bSingleLineMode
= bSingleLineMode
;
101 // setting the strings
102 OutlinerParaObject
* pParaObj
= ((SdrObjCustomShape
*)pCustomShape
)->GetOutlinerParaObject();
105 const EditTextObject
& rTextObj
= pParaObj
->GetTextObject();
106 sal_Int32 nParagraphsLeft
= rTextObj
.GetParagraphCount();
108 rFWData
.nMaxParagraphsPerTextArea
= ( ( nParagraphsLeft
- 1 ) / nTextAreaCount
) + 1;
110 while( nParagraphsLeft
&& nTextAreaCount
)
112 FWTextArea aTextArea
;
113 sal_Int32 i
, nParagraphs
= ( ( nParagraphsLeft
- 1 ) / nTextAreaCount
) + 1;
114 for ( i
= 0; i
< nParagraphs
; ++i
, ++j
)
116 FWParagraphData aParagraphData
;
117 aParagraphData
.aString
= rTextObj
.GetText( j
);
119 const SfxItemSet
& rParaSet
= rTextObj
.GetParaAttribs( j
); // retrieving some paragraph attributes
120 aParagraphData
.nFrameDirection
= ((SvxFrameDirectionItem
&)rParaSet
.Get( EE_PARA_WRITINGDIR
)).GetValue();
121 aTextArea
.vParagraphs
.push_back( aParagraphData
);
123 rFWData
.vTextAreas
.push_back( aTextArea
);
124 nParagraphsLeft
-= nParagraphs
;
133 double GetLength( const Polygon
& rPolygon
)
136 if ( rPolygon
.GetSize() > 1 )
138 sal_uInt16 nCount
= rPolygon
.GetSize();
140 fLength
+= ((Polygon
&)rPolygon
).CalcDistance( nCount
, nCount
- 1 );
146 /* CalculateHorizontalScalingFactor returns the horizontal scaling factor for
147 the whole text object, so that each text will match its corresponding 2d Outline */
148 void CalculateHorizontalScalingFactor( const SdrObject
* pCustomShape
,
149 FWData
& rFWData
, const PolyPolygon
& rOutline2d
)
151 double fScalingFactor
= 1.0;
152 bool bScalingFactorDefined
= false;
155 bool bSingleLineMode
= false;
156 sal_uInt16 nOutlinesCount2d
= rOutline2d
.Count();
159 SvxFontItem
& rFontItem
= (SvxFontItem
&)pCustomShape
->GetMergedItem( EE_CHAR_FONTINFO
);
160 aFont
.SetHeight( pCustomShape
->GetLogicRect().GetHeight() / rFWData
.nMaxParagraphsPerTextArea
);
161 aFont
.SetAlign( ALIGN_TOP
);
162 aFont
.SetName( rFontItem
.GetFamilyName() );
163 aFont
.SetFamily( rFontItem
.GetFamily() );
164 aFont
.SetStyleName( rFontItem
.GetStyleName() );
165 aFont
.SetOrientation( 0 );
166 // initializing virtual device
168 VirtualDevice
aVirDev( 1 );
169 aVirDev
.SetMapMode( MAP_100TH_MM
);
170 aVirDev
.SetFont( aFont
);
172 if ( nOutlinesCount2d
& 1 )
173 bSingleLineMode
= true;
175 std::vector
< FWTextArea
>::iterator aTextAreaIter
= rFWData
.vTextAreas
.begin();
176 std::vector
< FWTextArea
>::iterator aTextAreaIEnd
= rFWData
.vTextAreas
.end();
177 while( aTextAreaIter
!= aTextAreaIEnd
)
179 // calculating the width of the corresponding 2d text area
180 double fWidth
= GetLength( rOutline2d
.GetObject( i
++ ) );
181 if ( !bSingleLineMode
)
183 fWidth
+= GetLength( rOutline2d
.GetObject( i
++ ) );
186 std::vector
< FWParagraphData
>::const_iterator
aParagraphIter( aTextAreaIter
->vParagraphs
.begin() );
187 std::vector
< FWParagraphData
>::const_iterator
aParagraphIEnd( aTextAreaIter
->vParagraphs
.end() );
188 while( aParagraphIter
!= aParagraphIEnd
)
190 double fTextWidth
= aVirDev
.GetTextWidth( aParagraphIter
->aString
);
191 if ( fTextWidth
> 0.0 )
193 double fScale
= fWidth
/ fTextWidth
;
194 if ( !bScalingFactorDefined
)
196 fScalingFactor
= fScale
;
197 bScalingFactorDefined
= true;
201 if ( fScale
< fScalingFactor
)
202 fScalingFactor
= fScale
;
209 rFWData
.fHorizontalTextScaling
= fScalingFactor
;
212 void GetTextAreaOutline( const FWData
& rFWData
, const SdrObject
* pCustomShape
, FWTextArea
& rTextArea
, sal_Bool bSameLetterHeights
)
214 sal_Bool bIsVertical
= ((SdrObjCustomShape
*)pCustomShape
)->IsVerticalWriting();
215 sal_Int32 nVerticalOffset
= rFWData
.nMaxParagraphsPerTextArea
> rTextArea
.vParagraphs
.size()
216 ? rFWData
.nSingleLineHeight
/ 2 : 0;
218 std::vector
< FWParagraphData
>::iterator
aParagraphIter( rTextArea
.vParagraphs
.begin() );
219 std::vector
< FWParagraphData
>::iterator
aParagraphIEnd( rTextArea
.vParagraphs
.end() );
220 while( aParagraphIter
!= aParagraphIEnd
)
222 const OUString
& rText
= aParagraphIter
->aString
;
223 if ( !rText
.isEmpty() )
225 // generating vcl/font
226 sal_uInt16 nScriptType
= i18n::ScriptType::LATIN
;
227 Reference
< i18n::XBreakIterator
> xBI( EnhancedCustomShapeFontWork::GetBreakIterator() );
230 nScriptType
= xBI
->getScriptType( rText
, 0 );
231 if( i18n::ScriptType::WEAK
== nScriptType
)
234 nChg
= (xub_StrLen
)xBI
->endOfScript( rText
, nChg
, nScriptType
);
235 if( nChg
< rText
.getLength() )
236 nScriptType
= xBI
->getScriptType( rText
, nChg
);
238 nScriptType
= i18n::ScriptType::LATIN
;
241 sal_uInt16 nFntItm
= EE_CHAR_FONTINFO
;
242 if ( nScriptType
== i18n::ScriptType::COMPLEX
)
243 nFntItm
= EE_CHAR_FONTINFO_CTL
;
244 else if ( nScriptType
== i18n::ScriptType::ASIAN
)
245 nFntItm
= EE_CHAR_FONTINFO_CJK
;
246 SvxFontItem
& rFontItem
= (SvxFontItem
&)pCustomShape
->GetMergedItem( nFntItm
);
248 aFont
.SetHeight( rFWData
.nSingleLineHeight
);
249 aFont
.SetAlign( ALIGN_TOP
);
251 aFont
.SetName( rFontItem
.GetFamilyName() );
252 aFont
.SetFamily( rFontItem
.GetFamily() );
253 aFont
.SetStyleName( rFontItem
.GetStyleName() );
254 aFont
.SetOrientation( 0 );
256 SvxPostureItem
& rPostureItem
= (SvxPostureItem
&)pCustomShape
->GetMergedItem( EE_CHAR_ITALIC
);
257 aFont
.SetItalic( rPostureItem
.GetPosture() );
259 SvxWeightItem
& rWeightItem
= (SvxWeightItem
&)pCustomShape
->GetMergedItem( EE_CHAR_WEIGHT
);
260 aFont
.SetWeight( rWeightItem
.GetWeight() );
262 // initializing virtual device
263 VirtualDevice
aVirDev( 1 );
264 aVirDev
.SetMapMode( MAP_100TH_MM
);
265 aVirDev
.SetFont( aFont
);
266 aVirDev
.EnableRTL( sal_True
);
267 if ( aParagraphIter
->nFrameDirection
== FRMDIR_HORI_RIGHT_TOP
)
268 aVirDev
.SetLayoutMode( TEXT_LAYOUT_BIDI_RTL
);
270 SvxCharScaleWidthItem
& rCharScaleWidthItem
= (SvxCharScaleWidthItem
&)pCustomShape
->GetMergedItem( EE_CHAR_FONTWIDTH
);
271 sal_uInt16 nCharScaleWidth
= rCharScaleWidthItem
.GetValue();
272 sal_Int32
* pDXArry
= NULL
;
273 sal_Int32 nWidth
= 0;
278 // vertical _> each single character needs to be rotated by 90
280 sal_Int32 nHeight
= 0;
281 Rectangle aSingleCharacterUnion
;
282 for ( i
= 0; i
< rText
.getLength(); i
++ )
284 FWCharacterData aCharacterData
;
285 OUString
aCharText( (sal_Unicode
)rText
[ i
] );
286 if ( aVirDev
.GetTextOutlines( aCharacterData
.vOutlines
, aCharText
, 0, 0, STRING_LEN
, sal_True
, nWidth
, pDXArry
) )
288 sal_Int32 nTextWidth
= aVirDev
.GetTextWidth( aCharText
, 0, STRING_LEN
);
289 std::vector
< PolyPolygon
>::iterator aOutlineIter
= aCharacterData
.vOutlines
.begin();
290 std::vector
< PolyPolygon
>::iterator aOutlineIEnd
= aCharacterData
.vOutlines
.end();
291 if ( aOutlineIter
== aOutlineIEnd
)
293 nHeight
+= rFWData
.nSingleLineHeight
;
297 while ( aOutlineIter
!= aOutlineIEnd
)
300 aOutlineIter
->Rotate( Point( nTextWidth
/ 2, rFWData
.nSingleLineHeight
/ 2 ), 900 );
301 aCharacterData
.aBoundRect
.Union( aOutlineIter
->GetBoundRect() );
304 aOutlineIter
= aCharacterData
.vOutlines
.begin();
305 aOutlineIEnd
= aCharacterData
.vOutlines
.end();
306 while ( aOutlineIter
!= aOutlineIEnd
)
308 sal_Int32 nM
= - aCharacterData
.aBoundRect
.Left() + nHeight
;
309 aOutlineIter
->Move( nM
, 0 );
310 aCharacterData
.aBoundRect
.Move( nM
, 0 );
313 nHeight
+= aCharacterData
.aBoundRect
.GetWidth() + ( rFWData
.nSingleLineHeight
/ 5 );
314 aSingleCharacterUnion
.Union( aCharacterData
.aBoundRect
);
317 aParagraphIter
->vCharacters
.push_back( aCharacterData
);
319 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
320 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
321 while ( aCharacterIter
!= aCharacterIEnd
)
323 std::vector
< PolyPolygon
>::iterator
aOutlineIter( aCharacterIter
->vOutlines
.begin() );
324 std::vector
< PolyPolygon
>::iterator
aOutlineIEnd( aCharacterIter
->vOutlines
.end() );
325 while ( aOutlineIter
!= aOutlineIEnd
)
327 aOutlineIter
->Move( ( aSingleCharacterUnion
.GetWidth() - aCharacterIter
->aBoundRect
.GetWidth() ) / 2, 0 );
335 if ( ( nCharScaleWidth
!= 100 ) && nCharScaleWidth
)
336 { // applying character spacing
337 pDXArry
= new sal_Int32
[ rText
.getLength() ];
338 aVirDev
.GetTextArray( rText
, pDXArry
, 0, STRING_LEN
);
339 FontMetric
aFontMetric( aVirDev
.GetFontMetric() );
340 aFont
.SetWidth( (sal_Int32
)( (double)aFontMetric
.GetWidth() * ( (double)100 / (double)nCharScaleWidth
) ) );
341 aVirDev
.SetFont( aFont
);
343 FWCharacterData aCharacterData
;
344 if ( aVirDev
.GetTextOutlines( aCharacterData
.vOutlines
, rText
, 0, 0, STRING_LEN
, sal_True
, nWidth
, pDXArry
) )
346 aParagraphIter
->vCharacters
.push_back( aCharacterData
);
351 // veritcal alignment
352 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
353 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd ( aParagraphIter
->vCharacters
.end() );
354 while ( aCharacterIter
!= aCharacterIEnd
)
356 std::vector
< PolyPolygon
>::iterator
aOutlineIter( aCharacterIter
->vOutlines
.begin() );
357 std::vector
< PolyPolygon
>::iterator
aOutlineIEnd( aCharacterIter
->vOutlines
.end() );
358 while( aOutlineIter
!= aOutlineIEnd
)
361 PolyPolygon
& rPolyPoly
= *aOutlineIter
++;
363 if ( nVerticalOffset
)
364 rPolyPoly
.Move( 0, nVerticalOffset
);
366 // retrieving the boundrect for the paragraph
367 Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
368 aParagraphIter
->aBoundRect
.Union( aBoundRect
);
373 // updating the boundrect for the text area by merging the current paragraph boundrect
374 if ( aParagraphIter
->aBoundRect
.IsEmpty() )
376 if ( rTextArea
.aBoundRect
.IsEmpty() )
377 rTextArea
.aBoundRect
= Rectangle( Point( 0, 0 ), Size( 1, rFWData
.nSingleLineHeight
) );
379 rTextArea
.aBoundRect
.Bottom() += rFWData
.nSingleLineHeight
;
383 Rectangle
& rParagraphBoundRect
= aParagraphIter
->aBoundRect
;
384 rTextArea
.aBoundRect
.Union( rParagraphBoundRect
);
386 if ( bSameLetterHeights
)
388 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
389 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
390 while ( aCharacterIter
!= aCharacterIEnd
)
392 std::vector
< PolyPolygon
>::iterator
aOutlineIter( aCharacterIter
->vOutlines
.begin() );
393 std::vector
< PolyPolygon
>::iterator
aOutlineIEnd( aCharacterIter
->vOutlines
.end() );
394 while( aOutlineIter
!= aOutlineIEnd
)
396 Rectangle
aPolyPolyBoundRect( aOutlineIter
->GetBoundRect() );
397 if ( aPolyPolyBoundRect
.GetHeight() != rParagraphBoundRect
.GetHeight() )
398 aOutlineIter
->Scale( 1.0, (double)rParagraphBoundRect
.GetHeight() / aPolyPolyBoundRect
.GetHeight() );
399 aPolyPolyBoundRect
= aOutlineIter
->GetBoundRect();
400 sal_Int32 nMove
= aPolyPolyBoundRect
.Top() - rParagraphBoundRect
.Top();
402 aOutlineIter
->Move( 0, -nMove
);
410 nVerticalOffset
-= rFWData
.nSingleLineHeight
;
412 nVerticalOffset
+= rFWData
.nSingleLineHeight
;
417 void GetFontWorkOutline( FWData
& rFWData
, const SdrObject
* pCustomShape
)
419 SdrTextHorzAdjust
eHorzAdjust( ((SdrTextHorzAdjustItem
&)pCustomShape
->GetMergedItem( SDRATTR_TEXT_HORZADJUST
)).GetValue() );
420 SdrFitToSizeType
eFTS( ((SdrTextFitToSizeTypeItem
&)pCustomShape
->GetMergedItem( SDRATTR_TEXT_FITTOSIZE
)).GetValue() );
422 std::vector
< FWTextArea
>::iterator aTextAreaIter
= rFWData
.vTextAreas
.begin();
423 std::vector
< FWTextArea
>::iterator aTextAreaIEnd
= rFWData
.vTextAreas
.end();
425 rFWData
.nSingleLineHeight
= (sal_Int32
)( ( (double)pCustomShape
->GetLogicRect().GetHeight()
426 / rFWData
.nMaxParagraphsPerTextArea
) * rFWData
.fHorizontalTextScaling
);
428 sal_Bool bSameLetterHeights
= sal_False
;
429 SdrCustomShapeGeometryItem
& rGeometryItem
= (SdrCustomShapeGeometryItem
&)pCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
430 const OUString
sTextPath( "TextPath" );
431 const OUString
sSameLetterHeights( "SameLetterHeights" );
432 com::sun::star::uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sTextPath
, sSameLetterHeights
);
434 *pAny
>>= bSameLetterHeights
;
436 while ( aTextAreaIter
!= aTextAreaIEnd
)
438 GetTextAreaOutline( rFWData
, pCustomShape
, *aTextAreaIter
, bSameLetterHeights
);
439 if ( eFTS
== SDRTEXTFIT_ALLLINES
)
441 std::vector
< FWParagraphData
>::iterator
aParagraphIter( aTextAreaIter
->vParagraphs
.begin() );
442 std::vector
< FWParagraphData
>::iterator
aParagraphIEnd( aTextAreaIter
->vParagraphs
.end() );
443 while ( aParagraphIter
!= aParagraphIEnd
)
445 sal_Int32 nParaWidth
= aParagraphIter
->aBoundRect
.GetWidth();
448 double fScale
= (double)aTextAreaIter
->aBoundRect
.GetWidth() / nParaWidth
;
450 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
451 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
452 while ( aCharacterIter
!= aCharacterIEnd
)
454 std::vector
< PolyPolygon
>::iterator aOutlineIter
= aCharacterIter
->vOutlines
.begin();
455 std::vector
< PolyPolygon
>::iterator aOutlineIEnd
= aCharacterIter
->vOutlines
.end();
456 while( aOutlineIter
!= aOutlineIEnd
)
458 aOutlineIter
->Scale( fScale
, 1.0 );
469 switch( eHorzAdjust
)
471 case SDRTEXTHORZADJUST_RIGHT
:
472 case SDRTEXTHORZADJUST_CENTER
:
474 std::vector
< FWParagraphData
>::iterator
aParagraphIter( aTextAreaIter
->vParagraphs
.begin() );
475 std::vector
< FWParagraphData
>::iterator
aParagraphIEnd( aTextAreaIter
->vParagraphs
.end() );
476 while ( aParagraphIter
!= aParagraphIEnd
)
478 sal_Int32 nHorzDiff
= 0;
479 if ( eHorzAdjust
== SDRTEXTHORZADJUST_CENTER
)
480 nHorzDiff
= ( aTextAreaIter
->aBoundRect
.GetWidth() - aParagraphIter
->aBoundRect
.GetWidth() ) / 2;
481 else if ( eHorzAdjust
== SDRTEXTHORZADJUST_RIGHT
)
482 nHorzDiff
= ( aTextAreaIter
->aBoundRect
.GetWidth() - aParagraphIter
->aBoundRect
.GetWidth() );
485 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
486 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
487 while ( aCharacterIter
!= aCharacterIEnd
)
489 std::vector
< PolyPolygon
>::iterator aOutlineIter
= aCharacterIter
->vOutlines
.begin();
490 std::vector
< PolyPolygon
>::iterator aOutlineIEnd
= aCharacterIter
->vOutlines
.end();
491 while( aOutlineIter
!= aOutlineIEnd
)
493 aOutlineIter
->Move( nHorzDiff
, 0 );
504 case SDRTEXTHORZADJUST_BLOCK
: break; // don't know
505 case SDRTEXTHORZADJUST_LEFT
: break; // already left aligned -> nothing to do
512 basegfx::B2DPolyPolygon
GetOutlinesFromShape2d( const SdrObject
* pShape2d
)
514 basegfx::B2DPolyPolygon aOutlines2d
;
516 SdrObjListIter
aObjListIter( *pShape2d
, IM_DEEPWITHGROUPS
);
517 while( aObjListIter
.IsMore() )
519 SdrObject
* pPartObj
= aObjListIter
.Next();
520 if ( pPartObj
->ISA( SdrPathObj
) )
522 basegfx::B2DPolyPolygon
aCandidate(((SdrPathObj
*)pPartObj
)->GetPathPoly());
523 if(aCandidate
.areControlPointsUsed())
525 aCandidate
= basegfx::tools::adaptiveSubdivideByAngle(aCandidate
);
527 aOutlines2d
.append(aCandidate
);
534 void CalcDistances( const Polygon
& rPoly
, std::vector
< double >& rDistances
)
536 sal_uInt16 i
, nCount
= rPoly
.GetSize();
539 for ( i
= 0; i
< nCount
; i
++ )
541 double fDistance
= i
? ((Polygon
&)rPoly
).CalcDistance( i
, i
- 1 ) : 0.0;
542 rDistances
.push_back( fDistance
);
544 std::partial_sum( rDistances
.begin(), rDistances
.end(), rDistances
.begin() );
545 double fLength
= rDistances
[ rDistances
.size() - 1 ];
548 std::vector
< double >::iterator aIter
= rDistances
.begin();
549 std::vector
< double >::iterator aEnd
= rDistances
.end();
550 while ( aIter
!= aEnd
)
556 void InsertMissingOutlinePoints( const Polygon
& /*rOutlinePoly*/, const std::vector
< double >& rDistances
, const Rectangle
& rTextAreaBoundRect
, Polygon
& rPoly
)
559 double fLastDistance
= 0.0;
560 for ( i
= 0; i
< rPoly
.GetSize(); i
++ )
562 Point
& rPoint
= rPoly
[ i
];
563 double fDistance
= (double)( rPoint
.X() - rTextAreaBoundRect
.Left() ) / (double)rTextAreaBoundRect
.GetWidth();
566 if ( fDistance
> fLastDistance
)
568 std::vector
< double >::const_iterator aIter
= std::upper_bound( rDistances
.begin(), rDistances
.end(), fLastDistance
);
569 if ( aIter
!= rDistances
.end() && ( *aIter
> fLastDistance
) && ( *aIter
< fDistance
) )
571 Point
& rPt0
= rPoly
[ i
- 1 ];
572 sal_Int32 fX
= rPoint
.X() - rPt0
.X();
573 sal_Int32 fY
= rPoint
.Y() - rPt0
.Y();
574 double fd
= ( 1.0 / ( fDistance
- fLastDistance
) ) * ( *aIter
- fLastDistance
);
575 rPoly
.Insert( i
, Point( (sal_Int32
)( rPt0
.X() + fX
* fd
), (sal_Int32
)( rPt0
.Y() + fY
* fd
) ) );
579 else if ( fDistance
< fLastDistance
)
581 std::vector
< double >::const_iterator aIter
= std::lower_bound( rDistances
.begin(), rDistances
.end(), fLastDistance
);
582 if ( aIter
!= rDistances
.begin() )
585 if ( ( *aIter
> fDistance
) && ( *aIter
< fLastDistance
) )
587 Point
& rPt0
= rPoly
[ i
- 1 ];
588 sal_Int32 fX
= rPoint
.X() - rPt0
.X();
589 sal_Int32 fY
= rPoint
.Y() - rPt0
.Y();
590 double fd
= ( 1.0 / ( fDistance
- fLastDistance
) ) * ( *aIter
- fLastDistance
);
591 rPoly
.Insert( i
, Point( (sal_Int32
)( rPt0
.X() + fX
* fd
), (sal_Int32
)( rPt0
.Y() + fY
* fd
) ) );
597 fLastDistance
= fDistance
;
601 void GetPoint( const Polygon
& rPoly
, const std::vector
< double >& rDistances
, const double& fX
, double& fx1
, double& fy1
)
604 if ( rPoly
.GetSize() > 1 )
606 std::vector
< double >::const_iterator aIter
= std::lower_bound( rDistances
.begin(), rDistances
.end(), fX
);
607 sal_uInt16 nIdx
= sal::static_int_cast
<sal_uInt16
>( std::distance( rDistances
.begin(), aIter
) );
608 if ( aIter
== rDistances
.end() )
610 const Point
& rPt
= rPoly
[ nIdx
];
613 if ( nIdx
&& ( aIter
!= rDistances
.end() ) && ( *aIter
!= fX
) )
615 nIdx
= sal::static_int_cast
<sal_uInt16
>( std::distance( rDistances
.begin(), aIter
) );
616 double fDist0
= *( aIter
- 1 );
617 double fd
= ( 1.0 / ( *aIter
- fDist0
) ) * ( fX
- fDist0
);
618 const Point
& rPt2
= rPoly
[ nIdx
- 1 ];
619 double fWidth
= rPt
.X() - rPt2
.X();
620 double fHeight
= rPt
.Y() - rPt2
.Y();
623 fx1
= rPt2
.X() + fWidth
;
624 fy1
= rPt2
.Y() + fHeight
;
629 void FitTextOutlinesToShapeOutlines( const PolyPolygon
& aOutlines2d
, FWData
& rFWData
)
631 std::vector
< FWTextArea
>::iterator aTextAreaIter
= rFWData
.vTextAreas
.begin();
632 std::vector
< FWTextArea
>::iterator aTextAreaIEnd
= rFWData
.vTextAreas
.end();
634 sal_uInt16 nOutline2dIdx
= 0;
635 while( aTextAreaIter
!= aTextAreaIEnd
)
637 Rectangle rTextAreaBoundRect
= aTextAreaIter
->aBoundRect
;
638 sal_Int32 nLeft
= rTextAreaBoundRect
.Left();
639 sal_Int32 nTop
= rTextAreaBoundRect
.Top();
640 sal_Int32 nWidth
= rTextAreaBoundRect
.GetWidth();
641 sal_Int32 nHeight
= rTextAreaBoundRect
.GetHeight();
642 if ( rFWData
.bSingleLineMode
&& nHeight
&& nWidth
)
644 if ( nOutline2dIdx
>= aOutlines2d
.Count() )
646 const Polygon
& rOutlinePoly( aOutlines2d
[ nOutline2dIdx
++ ] );
647 const sal_uInt16 nPointCount
= rOutlinePoly
.GetSize();
648 if ( nPointCount
> 1 )
650 std::vector
< double > vDistances
;
651 vDistances
.reserve( nPointCount
);
652 CalcDistances( rOutlinePoly
, vDistances
);
653 if ( !vDistances
.empty() )
655 std::vector
< FWParagraphData
>::iterator
aParagraphIter( aTextAreaIter
->vParagraphs
.begin() );
656 std::vector
< FWParagraphData
>::iterator
aParagraphIEnd( aTextAreaIter
->vParagraphs
.end() );
657 while( aParagraphIter
!= aParagraphIEnd
)
659 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
660 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
661 while ( aCharacterIter
!= aCharacterIEnd
)
663 std::vector
< PolyPolygon
>::iterator aOutlineIter
= aCharacterIter
->vOutlines
.begin();
664 std::vector
< PolyPolygon
>::iterator aOutlineIEnd
= aCharacterIter
->vOutlines
.end();
665 while( aOutlineIter
!= aOutlineIEnd
)
667 PolyPolygon
& rPolyPoly
= *aOutlineIter
;
668 Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
669 double fx1
= aBoundRect
.Left() - nLeft
;
670 double fx2
= aBoundRect
.Right() - nLeft
;
672 double fM1
= fx1
/ (double)nWidth
;
673 double fM2
= fx2
/ (double)nWidth
;
675 GetPoint( rOutlinePoly
, vDistances
, fM1
, fx1
, fy1
);
676 GetPoint( rOutlinePoly
, vDistances
, fM2
, fx2
, fy2
);
678 double fvx
= ( fy2
- fy1
);
679 double fvy
= - ( fx2
- fx1
);
680 fx1
= fx1
+ ( ( fx2
- fx1
) * 0.5 );
681 fy1
= fy1
+ ( ( fy2
- fy1
) * 0.5 );
683 double fAngle
= atan2( -fvx
, -fvy
);
684 double fL
= hypot( fvx
, fvy
);
687 fL
= (double)( aTextAreaIter
->aBoundRect
.GetHeight() / 2.0 + aTextAreaIter
->aBoundRect
.Top() ) - aParagraphIter
->aBoundRect
.Center().Y();
690 rPolyPoly
.Rotate( Point( aBoundRect
.Center().X(), aParagraphIter
->aBoundRect
.Center().Y() ), sin( fAngle
), cos( fAngle
) );
691 rPolyPoly
.Move( (sal_Int32
)( ( fx1
+ fvx
)- aBoundRect
.Center().X() ), (sal_Int32
)( ( fy1
+ fvy
) - aParagraphIter
->aBoundRect
.Center().Y() ) );
704 if ( ( nOutline2dIdx
+ 1 ) >= aOutlines2d
.Count() )
706 const Polygon
& rOutlinePoly( aOutlines2d
[ nOutline2dIdx
++ ] );
707 const Polygon
& rOutlinePoly2( aOutlines2d
[ nOutline2dIdx
++ ] );
708 const sal_uInt16 nPointCount
= rOutlinePoly
.GetSize();
709 const sal_uInt16 nPointCount2
= rOutlinePoly2
.GetSize();
710 if ( ( nPointCount
> 1 ) && ( nPointCount2
> 1 ) )
712 std::vector
< double > vDistances
;
713 vDistances
.reserve( nPointCount
);
714 std::vector
< double > vDistances2
;
715 vDistances2
.reserve( nPointCount2
);
716 CalcDistances( rOutlinePoly
, vDistances
);
717 CalcDistances( rOutlinePoly2
, vDistances2
);
718 std::vector
< FWParagraphData
>::iterator aParagraphIter
= aTextAreaIter
->vParagraphs
.begin();
719 std::vector
< FWParagraphData
>::iterator aParagraphIEnd
= aTextAreaIter
->vParagraphs
.end();
720 while( aParagraphIter
!= aParagraphIEnd
)
722 std::vector
< FWCharacterData
>::iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
723 std::vector
< FWCharacterData
>::iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
724 while ( aCharacterIter
!= aCharacterIEnd
)
726 std::vector
< PolyPolygon
>::iterator aOutlineIter
= aCharacterIter
->vOutlines
.begin();
727 std::vector
< PolyPolygon
>::iterator aOutlineIEnd
= aCharacterIter
->vOutlines
.end();
728 while( aOutlineIter
!= aOutlineIEnd
)
730 PolyPolygon
& rPolyPoly
= *aOutlineIter
;
731 sal_uInt16 i
, nPolyCount
= rPolyPoly
.Count();
732 for ( i
= 0; i
< nPolyCount
; i
++ )
735 basegfx::B2DPolygon
aCandidate(rPolyPoly
[ i
].getB2DPolygon());
737 if(aCandidate
.areControlPointsUsed())
739 aCandidate
= basegfx::tools::adaptiveSubdivideByAngle(aCandidate
);
742 // create local polygon copy to work on
743 Polygon
aLocalPoly(aCandidate
);
745 InsertMissingOutlinePoints( rOutlinePoly
, vDistances
, rTextAreaBoundRect
, aLocalPoly
);
746 InsertMissingOutlinePoints( rOutlinePoly2
, vDistances2
, rTextAreaBoundRect
, aLocalPoly
);
748 sal_uInt16 j
, _nPointCount
= aLocalPoly
.GetSize();
749 for ( j
= 0; j
< _nPointCount
; j
++ )
751 Point
& rPoint
= aLocalPoly
[ j
];
754 double fX
= (double)rPoint
.X() / (double)nWidth
;
755 double fY
= (double)rPoint
.Y() / (double)nHeight
;
757 double fx1
, fy1
, fx2
, fy2
;
758 GetPoint( rOutlinePoly
, vDistances
, fX
, fx1
, fy1
);
759 GetPoint( rOutlinePoly2
, vDistances2
, fX
, fx2
, fy2
);
760 double fWidth
= fx2
- fx1
;
761 double fHeight
= fy2
- fy1
;
762 rPoint
.X() = (sal_Int32
)( fx1
+ fWidth
* fY
);
763 rPoint
.Y() = (sal_Int32
)( fy1
+ fHeight
* fY
);
766 // write back polygon
767 rPolyPoly
[ i
] = aLocalPoly
;
781 SdrObject
* CreateSdrObjectFromParagraphOutlines( const FWData
& rFWData
, const SdrObject
* pCustomShape
)
783 SdrObject
* pRet
= NULL
;
784 basegfx::B2DPolyPolygon aPolyPoly
;
785 if ( !rFWData
.vTextAreas
.empty() )
787 std::vector
< FWTextArea
>::const_iterator aTextAreaIter
= rFWData
.vTextAreas
.begin();
788 std::vector
< FWTextArea
>::const_iterator aTextAreaIEnd
= rFWData
.vTextAreas
.end();
789 while ( aTextAreaIter
!= aTextAreaIEnd
)
791 std::vector
< FWParagraphData
>::const_iterator aParagraphIter
= aTextAreaIter
->vParagraphs
.begin();
792 std::vector
< FWParagraphData
>::const_iterator aParagraphIEnd
= aTextAreaIter
->vParagraphs
.end();
793 while ( aParagraphIter
!= aParagraphIEnd
)
795 std::vector
< FWCharacterData
>::const_iterator
aCharacterIter( aParagraphIter
->vCharacters
.begin() );
796 std::vector
< FWCharacterData
>::const_iterator
aCharacterIEnd( aParagraphIter
->vCharacters
.end() );
797 while ( aCharacterIter
!= aCharacterIEnd
)
799 std::vector
< PolyPolygon
>::const_iterator aOutlineIter
= aCharacterIter
->vOutlines
.begin();
800 std::vector
< PolyPolygon
>::const_iterator aOutlineIEnd
= aCharacterIter
->vOutlines
.end();
801 while( aOutlineIter
!= aOutlineIEnd
)
803 aPolyPoly
.append( aOutlineIter
->getB2DPolyPolygon() );
813 pRet
= new SdrPathObj( OBJ_POLY
, aPolyPoly
);
815 SfxItemSet
aSet( pCustomShape
->GetMergedItemSet() );
816 aSet
.ClearItem( SDRATTR_TEXTDIRECTION
); //SJ: vertical writing is not required, by removing this item no outliner is created
817 aSet
.Put(SdrShadowItem(sal_False
)); // #i37011# NO shadow for FontWork geometry
818 pRet
->SetMergedItemSet( aSet
); // * otherwise we would crash, because the outliner tries to create a Paraobject, but there is no model
823 Reference
< i18n::XBreakIterator
> EnhancedCustomShapeFontWork::mxBreakIterator
= 0;
825 Reference
< i18n::XBreakIterator
> EnhancedCustomShapeFontWork::GetBreakIterator()
827 if ( !mxBreakIterator
.is() )
829 Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
830 mxBreakIterator
= i18n::BreakIterator::create(xContext
);
832 return mxBreakIterator
;
835 SdrObject
* EnhancedCustomShapeFontWork::CreateFontWork( const SdrObject
* pShape2d
, const SdrObject
* pCustomShape
)
837 SdrObject
* pRet
= NULL
;
839 PolyPolygon
aOutlines2d( GetOutlinesFromShape2d( pShape2d
) );
840 sal_uInt16 nOutlinesCount2d
= aOutlines2d
.Count();
841 if ( nOutlinesCount2d
)
844 if ( InitializeFontWorkData( pCustomShape
, nOutlinesCount2d
, aFWData
) )
846 /* retrieves the horizontal scaling factor that has to be used
847 to fit each paragraph text into its corresponding 2d outline */
848 CalculateHorizontalScalingFactor( pCustomShape
, aFWData
, aOutlines2d
);
850 /* retrieving the Outlines for the each Paragraph. */
852 GetFontWorkOutline( aFWData
, pCustomShape
);
854 FitTextOutlinesToShapeOutlines( aOutlines2d
, aFWData
);
856 pRet
= CreateSdrObjectFromParagraphOutlines( aFWData
, pCustomShape
);
862 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */