summaryrefslogtreecommitdiff
path: root/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/customshapes/EnhancedCustomShapeFontWork.cxx')
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeFontWork.cxx779
1 files changed, 779 insertions, 0 deletions
diff --git a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
new file mode 100644
index 0000000000..9f1310cc3a
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
@@ -0,0 +1,779 @@
+/*************************************************************************
+ *
+ * $RCSfile: EnhancedCustomShapeFontWork.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: rt $ $Date: 2004-04-02 14:03:55 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _ENHANCEDCUSTOMSHAPEFONTWORK_HXX
+#include "EnhancedCustomShapeFontWork.hxx"
+#endif
+#ifndef _SOLAR_H
+#include <tools/solar.h> // UINTXX
+#endif
+#ifndef _XOUTX_HXX
+#include "xoutx.hxx"
+#endif
+#ifndef _SVDDEF_HXX
+#include "svddef.hxx"
+#endif
+#ifndef _SVDOGRP_HXX
+#include <svdogrp.hxx>
+#endif
+#ifndef _SVDOPATH_HXX
+#include <svdopath.hxx>
+#endif
+#ifndef _SV_METRIC_HXX
+#include <vcl/metric.hxx>
+#endif
+#ifndef _SVDPAGE_HXX
+#include <svdpage.hxx>
+#endif
+#ifndef _SDASITM_HXX
+#include <sdasitm.hxx>
+#endif
+#ifndef _SDASAITM_HXX
+#include <sdasaitm.hxx>
+#endif
+#ifndef _SDTFSITM_HXX
+#include <sdtfsitm.hxx>
+#endif
+#ifndef _SV_VIRDEV_HXX //autogen
+#include <vcl/virdev.hxx>
+#endif
+#ifndef _SVDITER_HXX
+#include <svditer.hxx>
+#endif
+
+#define ITEMID_FONT EE_CHAR_FONTINFO
+#ifndef _EEITEM_HXX //autogen
+#include <eeitem.hxx>
+#endif
+#ifndef _SVX_FONTITEM_HXX //autogen
+#include <fontitem.hxx>
+#endif
+#ifndef _ENHANCED_CUSTOMSHAPE_TYPE_NAMES_HXX
+#include "EnhancedCustomShapeTypeNames.hxx"
+#endif
+#include "svdorect.hxx"
+#include "svdoashp.hxx"
+#include "outliner.hxx"
+#include "outlobj.hxx"
+#include "editobj.hxx"
+#include "editeng.hxx"
+#include "svdmodel.hxx"
+#include <vector>
+#include <numeric>
+#include <algorithm>
+
+using namespace com::sun::star::uno;
+
+typedef std::vector< std::vector< double > > PolyPolygonDistances;
+
+
+struct FWParagraphData
+{
+ rtl::OUString aString;
+ std::vector< PolyPolygon > vOutlines;
+ Rectangle aBoundRect;
+};
+struct FWTextArea
+{
+ std::vector< FWParagraphData > vParagraphData;
+ Rectangle aBoundRect;
+};
+struct FWData
+{
+ std::vector< FWTextArea > vTextAreaData;
+ double fHorizontalTextScaling;
+ sal_uInt32 nMaxParagraphsPerTextArea;
+ sal_Int32 nSingleLineHeight;
+ sal_Bool bSingleLineMode;
+};
+
+
+sal_Bool InitializeFontWorkData( const SdrObject* pCustomShape, const sal_uInt16 nOutlinesCount2d, FWData& rFWData )
+{
+ sal_Bool bNoErr = sal_False;
+ sal_Bool bSingleLineMode = sal_False;
+ sal_uInt16 nTextAreaCount = nOutlinesCount2d;
+ if ( nOutlinesCount2d & 1 )
+ bSingleLineMode = sal_True;
+ else
+ nTextAreaCount >>= 1;
+
+ if ( nTextAreaCount )
+ {
+ rFWData.bSingleLineMode = bSingleLineMode;
+
+ // setting the strings
+ OutlinerParaObject* pParaObj = ((SdrObjCustomShape*)pCustomShape)->GetOutlinerParaObject();
+ if ( pParaObj )
+ {
+ const EditTextObject& rTextObj = pParaObj->GetTextObject();
+ sal_Int16 nParagraphsLeft = rTextObj.GetParagraphCount();
+ sal_Int16 k = 0;
+
+ rFWData.nMaxParagraphsPerTextArea = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
+
+ while( nParagraphsLeft && nTextAreaCount )
+ {
+ FWTextArea aTextArea;
+ sal_Int16 i, nParagraphs = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
+ for ( i = 0; i < nParagraphs; i++ )
+ {
+ FWParagraphData aParagraphData;
+ aParagraphData.aString = rTextObj.GetText( k++ );
+ aTextArea.vParagraphData.push_back( aParagraphData );
+ }
+ rFWData.vTextAreaData.push_back( aTextArea );
+ nParagraphsLeft -= nParagraphs;
+ nTextAreaCount--;
+ }
+ bNoErr = sal_True;
+ }
+ }
+ return bNoErr;
+}
+
+double GetLength( const Polygon& rPolygon )
+{
+ double fLength = 0;
+ if ( rPolygon.GetSize() > 1 )
+ {
+ sal_uInt16 nCount = rPolygon.GetSize();
+ while( --nCount )
+ fLength += ((Polygon&)rPolygon).CalcDistance( nCount, nCount - 1 );
+ }
+ return fLength;
+}
+
+
+/* CalculateHorizontalScalingFactor returns the horizontal scaling factor for
+the whole text object, so that each text will match its corresponding 2d Outline */
+void CalculateHorizontalScalingFactor( const SdrObject* pCustomShape,
+ FWData& rFWData, const PolyPolygon& rOutline2d )
+{
+ double fScalingFactor = 1.0;
+ sal_Bool bScalingFactorDefined = sal_False;
+
+ sal_uInt16 i = 0;
+ sal_Bool bSingleLineMode = sal_False;
+ sal_uInt16 nOutlinesCount2d = rOutline2d.Count();
+
+ Font aFont;
+ SvxFontItem& rFontItem = (SvxFontItem&)pCustomShape->GetMergedItem( EE_CHAR_FONTINFO );
+ aFont.SetHeight( pCustomShape->GetLogicRect().GetHeight() / rFWData.nMaxParagraphsPerTextArea );
+ aFont.SetAlign( ALIGN_TOP );
+ aFont.SetName( rFontItem.GetFamilyName() );
+ aFont.SetFamily( rFontItem.GetFamily() );
+ aFont.SetStyleName( rFontItem.GetStyleName() );
+ aFont.SetOrientation( 0 );
+ // initializing virtual device
+
+ VirtualDevice aVirDev( 1 );
+ aVirDev.SetMapMode( MAP_100TH_MM );
+ aVirDev.SetFont( aFont );
+
+ if ( nOutlinesCount2d & 1 )
+ bSingleLineMode = sal_True;
+
+ std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreaData.begin();
+ std::vector< FWTextArea >::iterator aTextAreaIterEnd = rFWData.vTextAreaData.end();
+ while( aTextAreaIter != aTextAreaIterEnd )
+ {
+ // calculating the width of the corresponding 2d text area
+ double fWidth = GetLength( rOutline2d.GetObject( i++ ) );
+ if ( !bSingleLineMode )
+ {
+ fWidth += GetLength( rOutline2d.GetObject( i++ ) );
+ fWidth /= 2.0;
+ }
+ std::vector< FWParagraphData >::const_iterator aParagraphDataIter( aTextAreaIter->vParagraphData.begin() );
+ std::vector< FWParagraphData >::const_iterator aParagraphDataIterEnd( aTextAreaIter->vParagraphData.end() );
+ while( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ double fTextWidth = aVirDev.GetTextWidth( aParagraphDataIter->aString );
+ if ( fTextWidth > 0.0 )
+ {
+ double fScale = fWidth / fTextWidth;
+ if ( !bScalingFactorDefined )
+ {
+ fScalingFactor = fScale;
+ bScalingFactorDefined = sal_True;
+ }
+ else
+ {
+ if ( fScale < fScalingFactor )
+ fScalingFactor = fScale;
+ }
+ }
+ aParagraphDataIter++;
+ }
+ aTextAreaIter++;
+ }
+ rFWData.fHorizontalTextScaling = fScalingFactor;
+}
+
+void GetTextAreaOutline( const FWData& rFWData, const SdrObject* pCustomShape, FWTextArea& rTextArea, sal_Bool bSameLetterHeights )
+{
+ sal_Int32 nVerticalOffset = rFWData.nMaxParagraphsPerTextArea > rTextArea.vParagraphData.size()
+ ? rFWData.nSingleLineHeight / 2 : 0;
+
+ std::vector< FWParagraphData >::iterator aParagraphDataIter( rTextArea.vParagraphData.begin() );
+ std::vector< FWParagraphData >::iterator aParagraphDataIterEnd( rTextArea.vParagraphData.end() );
+ while( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ const rtl::OUString& rText = aParagraphDataIter->aString;
+ if ( rText.getLength() )
+ {
+ // generating vcl/font
+ SvxFontItem& rFontItem = (SvxFontItem&)pCustomShape->GetMergedItem( EE_CHAR_FONTINFO );
+ Font aFont;
+ aFont.SetHeight( rFWData.nSingleLineHeight );
+ aFont.SetAlign( ALIGN_TOP );
+ // aFont.SetAlign( )
+
+ aFont.SetName( rFontItem.GetFamilyName() );
+ aFont.SetFamily( rFontItem.GetFamily() );
+ aFont.SetStyleName( rFontItem.GetStyleName() );
+ aFont.SetOrientation( 0 );
+
+ // initializing virtual device
+ VirtualDevice aVirDev( 1 );
+ aVirDev.SetMapMode( MAP_100TH_MM );
+ aVirDev.SetFont( aFont );
+ sal_Bool bIsVertical = ((SdrObjCustomShape*)pCustomShape)->IsVerticalWriting();
+ if ( bIsVertical )
+ {
+ sal_Int32 i;
+ for ( i = 0; i < rText.getLength(); i++ )
+ {
+ rtl::OUString aCharText( (sal_Unicode)rText[ i ] );
+ sal_Int32 nWidth = 0;
+ const long* pDXArry = NULL;
+
+ if ( aVirDev.GetTextOutlines( aParagraphDataIter->vOutlines, aCharText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
+ {
+ std::vector< PolyPolygon >::iterator aParagraphOutlineIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::iterator aParagraphOutlineEnd = aParagraphDataIter->vOutlines.end();
+ while ( aParagraphOutlineIter != aParagraphOutlineEnd )
+ {
+ // rotating
+ }
+ }
+ // character outline needs to be appended to the
+ // ParagraphOutline while taking care of the horizontal position
+ }
+ }
+ else
+ {
+ sal_Int32 nWidth = 0;
+ const long* pDXArry = NULL;
+
+ if ( aVirDev.GetTextOutlines( aParagraphDataIter->vOutlines, rText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
+ {
+
+ }
+ }
+
+ // veritcal alignment
+ std::vector< PolyPolygon >::iterator aOutlineIter( aParagraphDataIter->vOutlines.begin() );
+ std::vector< PolyPolygon >::iterator aOutlineIterEnd( aParagraphDataIter->vOutlines.end() );
+ while( aOutlineIter != aOutlineIterEnd )
+ {
+ PolyPolygon& rPolyPoly = *aOutlineIter++;
+
+ if ( nVerticalOffset )
+ rPolyPoly.Move( 0, nVerticalOffset );
+
+ // retrieving the boundrect for the paragraph
+ aParagraphDataIter->aBoundRect.Union( rPolyPoly.GetBoundRect() );
+ }
+ }
+ // updating the boundrect for the text area by merging the current paragraph boundrect
+ if ( aParagraphDataIter->aBoundRect.IsEmpty() )
+ {
+ if ( rTextArea.aBoundRect.IsEmpty() )
+ rTextArea.aBoundRect = Rectangle( Point( 0, 0 ), Size( 1, rFWData.nSingleLineHeight ) );
+ else
+ rTextArea.aBoundRect.Bottom() += rFWData.nSingleLineHeight;
+ }
+ else
+ {
+ Rectangle& rParagraphBoundRect = aParagraphDataIter->aBoundRect;
+ rTextArea.aBoundRect.Union( rParagraphBoundRect );
+
+ if ( bSameLetterHeights )
+ {
+ std::vector< PolyPolygon >::iterator aOutlineIter( aParagraphDataIter->vOutlines.begin() );
+ std::vector< PolyPolygon >::iterator aOutlineIterEnd( aParagraphDataIter->vOutlines.end() );
+ while( aOutlineIter != aOutlineIterEnd )
+ {
+ Rectangle aPolyPolyBoundRect( aOutlineIter->GetBoundRect() );
+ if ( aPolyPolyBoundRect.GetHeight() != rParagraphBoundRect.GetHeight() )
+ aOutlineIter->Scale( 1.0, (double)rParagraphBoundRect.GetHeight() / aPolyPolyBoundRect.GetHeight() );
+ aPolyPolyBoundRect = aOutlineIter->GetBoundRect();
+ sal_Int32 nMove = aPolyPolyBoundRect.Top() - rParagraphBoundRect.Top();
+ if ( nMove )
+ aOutlineIter->Move( 0, -nMove );
+ aOutlineIter++;
+ }
+ }
+ }
+
+
+ nVerticalOffset += rFWData.nSingleLineHeight;
+ aParagraphDataIter++;
+ }
+}
+
+void GetFontWorkOutline( FWData& rFWData, const SdrObject* pCustomShape )
+{
+ SdrTextHorzAdjust eHorzAdjust( ((SdrTextHorzAdjustItem&)pCustomShape->GetMergedItem( SDRATTR_TEXT_HORZADJUST )).GetValue() );
+ SdrFitToSizeType eFTS( ((SdrTextFitToSizeTypeItem&)pCustomShape->GetMergedItem( SDRATTR_TEXT_FITTOSIZE )).GetValue() );
+
+ std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreaData.begin();
+ std::vector< FWTextArea >::iterator aTextAreaIterEnd = rFWData.vTextAreaData.end();
+
+ rFWData.nSingleLineHeight = (sal_Int32)( ( (double)pCustomShape->GetLogicRect().GetHeight()
+ / rFWData.nMaxParagraphsPerTextArea ) * rFWData.fHorizontalTextScaling );
+
+ sal_Bool bSameLetterHeights = sal_False;
+ SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ const rtl::OUString sTextPath( RTL_CONSTASCII_USTRINGPARAM ( "TextPath" ) );
+ const rtl::OUString sSameLetterHeights( RTL_CONSTASCII_USTRINGPARAM ( "SameLetterHeights" ) );
+ com::sun::star::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sSameLetterHeights );
+ if ( pAny )
+ *pAny >>= bSameLetterHeights;
+
+ while ( aTextAreaIter != aTextAreaIterEnd )
+ {
+ GetTextAreaOutline( rFWData, pCustomShape, *aTextAreaIter, bSameLetterHeights );
+ if ( eFTS == SDRTEXTFIT_ALLLINES )
+ {
+ std::vector< FWParagraphData >::iterator aParagraphDataIter( aTextAreaIter->vParagraphData.begin() );
+ std::vector< FWParagraphData >::iterator aParagraphDataIterEnd( aTextAreaIter->vParagraphData.end() );
+ while ( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ sal_Int32 nParaWidth = aParagraphDataIter->aBoundRect.GetWidth();
+ if ( nParaWidth )
+ {
+ double fScale = (double)aTextAreaIter->aBoundRect.GetWidth() / nParaWidth;
+ std::vector< PolyPolygon >::iterator aParagraphOutlinerIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::iterator aParagraphOutlinerIterEnd = aParagraphDataIter->vOutlines.end();
+ while( aParagraphOutlinerIter != aParagraphOutlinerIterEnd )
+ {
+ aParagraphOutlinerIter->Scale( fScale, 1.0 );
+ aParagraphOutlinerIter++;
+ }
+ }
+ aParagraphDataIter++;
+ }
+ }
+ else
+ {
+ switch( eHorzAdjust )
+ {
+ case SDRTEXTHORZADJUST_RIGHT :
+ case SDRTEXTHORZADJUST_CENTER:
+ {
+ std::vector< FWParagraphData >::iterator aParagraphDataIter( aTextAreaIter->vParagraphData.begin() );
+ std::vector< FWParagraphData >::iterator aParagraphDataIterEnd( aTextAreaIter->vParagraphData.end() );
+ while ( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ sal_Int32 nHorzDiff = 0;
+ if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
+ nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphDataIter->aBoundRect.GetWidth() ) / 2;
+ else if ( eHorzAdjust == SDRTEXTHORZADJUST_RIGHT )
+ nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphDataIter->aBoundRect.GetWidth() );
+ if ( nHorzDiff )
+ {
+ std::vector< PolyPolygon >::iterator aParagraphOutlinerIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::iterator aParagraphOutlinerIterEnd = aParagraphDataIter->vOutlines.end();
+ while( aParagraphOutlinerIter != aParagraphOutlinerIterEnd )
+ {
+ aParagraphOutlinerIter->Move( nHorzDiff, 0 );
+ aParagraphOutlinerIter++;
+ }
+ }
+ aParagraphDataIter++;
+ }
+ }
+ break;
+ default:
+ case SDRTEXTHORZADJUST_BLOCK : break; // don't know
+ case SDRTEXTHORZADJUST_LEFT : break; // already left aligned -> nothing to do
+ }
+ }
+ aTextAreaIter++;
+ }
+}
+
+PolyPolygon GetOutlinesFromShape2d( const SdrObject* pShape2d )
+{
+ PolyPolygon aOutlines2d;
+
+ SdrObjListIter aObjListIter( *pShape2d, IM_DEEPWITHGROUPS );
+ while( aObjListIter.IsMore() )
+ {
+ SdrObject* pPartObj = aObjListIter.Next();
+ if ( pPartObj->ISA( SdrPathObj ) )
+ {
+ if (!((SdrShadowItem&)pPartObj->GetMergedItem( SDRATTR_SHADOW )).GetValue())
+ {
+ const XPolyPolygon& rXPolyPoly = ((SdrPathObj*)pPartObj)->GetPathPoly();
+ sal_uInt16 i, nCount = rXPolyPoly.Count();
+ for ( i = 0; i < nCount; i++ )
+ {
+ Polygon aPoly( XOutCreatePolygonBezier( rXPolyPoly.GetObject( i ), NULL ) );
+ Polygon aSimplePoly;
+ aPoly.GetSimple( aSimplePoly );
+ aOutlines2d.Insert( aSimplePoly, POLYPOLY_APPEND );
+ }
+ }
+ }
+ }
+ return aOutlines2d;
+}
+
+void CalcDistances( const Polygon& rPoly, std::vector< double >& rDistances )
+{
+ sal_uInt16 i, nCount = rPoly.GetSize();
+ if ( nCount > 1 )
+ {
+ for ( i = 0; i < nCount; i++ )
+ {
+ double fDistance = i ? ((Polygon&)rPoly).CalcDistance( i, i - 1 ) : 0.0;
+ rDistances.push_back( fDistance );
+ }
+ std::partial_sum( rDistances.begin(), rDistances.end(), rDistances.begin() );
+ double fLength = rDistances[ rDistances.size() - 1 ];
+ if ( fLength > 0.0 )
+ {
+ std::vector< double >::iterator aIter = rDistances.begin();
+ std::vector< double >::iterator aEnd = rDistances.end();
+ while ( aIter != aEnd )
+ *aIter++ /= fLength;
+ }
+ }
+}
+
+void InsertMissingOutlinePoints( const Polygon& rOutlinePoly, const std::vector< double >& rDistances, const Rectangle& rTextAreaBoundRect, Polygon& rPoly )
+{
+ sal_uInt16 i = 0;
+ double fLastDistance;
+ for ( i = 0; i < rPoly.GetSize(); i++ )
+ {
+ Point& rPoint = rPoly[ i ];
+ double fDistance = (double)( rPoint.X() - rTextAreaBoundRect.Left() ) / (double)rTextAreaBoundRect.GetWidth();
+ if ( i )
+ {
+ if ( fDistance > fLastDistance )
+ {
+ std::vector< double >::const_iterator aIter = std::upper_bound( rDistances.begin(), rDistances.end(), fLastDistance );
+ if ( aIter != rDistances.end() && ( *aIter > fLastDistance ) && ( *aIter < fDistance ) )
+ {
+ Point& rPt0 = rPoly[ i - 1 ];
+ sal_Int32 fX = rPoint.X() - rPt0.X();
+ sal_Int32 fY = rPoint.Y() - rPt0.Y();
+ double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
+ rPoly.Insert( i, Point( (sal_Int32)( rPt0.X() + fX * fd ), (sal_Int32)( rPt0.Y() + fY * fd ) ) );
+ fDistance = *aIter;
+ }
+ }
+ else if ( fDistance < fLastDistance )
+ {
+ std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fLastDistance );
+ if ( aIter-- != rDistances.begin() )
+ {
+ if ( ( *aIter > fDistance ) && ( *aIter < fLastDistance ) )
+ {
+ Point& rPt0 = rPoly[ i - 1 ];
+ sal_Int32 fX = rPoint.X() - rPt0.X();
+ sal_Int32 fY = rPoint.Y() - rPt0.Y();
+ double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
+ rPoly.Insert( i, Point( (sal_Int32)( rPt0.X() + fX * fd ), (sal_Int32)( rPt0.Y() + fY * fd ) ) );
+ fDistance = *aIter;
+ }
+ }
+ }
+ }
+ fLastDistance = fDistance;
+ }
+}
+
+void GetPoint( const Polygon& rPoly, const std::vector< double >& rDistances, const double& fX, double& fx1, double& fy1 )
+{
+ fy1 = fx1 = 0.0;
+ if ( rPoly.GetSize() )
+ {
+ std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fX );
+ sal_uInt16 nIdx = std::distance( rDistances.begin(), aIter );
+ if ( aIter == rDistances.end() )
+ nIdx--;
+ const Point& rPt = rPoly[ nIdx ];
+ fx1 = rPt.X();
+ fy1 = rPt.Y();
+ if ( nIdx && ( aIter != rDistances.end() ) && ( *aIter != fX ) )
+ {
+ nIdx = std::distance( rDistances.begin(), aIter );
+ double fDist0 = *( aIter - 1 );
+ double fd = ( 1.0 / ( *aIter - fDist0 ) ) * ( fX - fDist0 );
+ const Point& rPt2 = rPoly[ nIdx - 1 ];
+ double fWidth = rPt.X() - rPt2.X();
+ double fHeight= rPt.Y() - rPt2.Y();
+ fWidth *= fd;
+ fHeight*= fd;
+ fx1 = rPt2.X() + fWidth;
+ fy1 = rPt2.Y() + fHeight;
+ }
+ }
+}
+
+void FitTextOutlinesToShapeOutlines( const PolyPolygon& aOutlines2d, FWData& rFWData )
+{
+ std::vector< FWTextArea >::iterator aTextAreaIter = rFWData.vTextAreaData.begin();
+ std::vector< FWTextArea >::iterator aTextAreaIterEnd = rFWData.vTextAreaData.end();
+
+ sal_uInt16 nOutline2dIdx = 0;
+ while( aTextAreaIter != aTextAreaIterEnd )
+ {
+ Rectangle rTextAreaBoundRect = aTextAreaIter->aBoundRect;
+ sal_Int32 nLeft = rTextAreaBoundRect.Left();
+ sal_Int32 nTop = rTextAreaBoundRect.Top();
+ sal_Int32 nWidth = rTextAreaBoundRect.GetWidth();
+ sal_Int32 nHeight= rTextAreaBoundRect.GetHeight();
+ if ( rFWData.bSingleLineMode && nHeight && nWidth )
+ {
+ if ( nOutline2dIdx >= aOutlines2d.Count() )
+ break;
+ const Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
+ const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
+ if ( nPointCount )
+ {
+ std::vector< double > vDistances;
+ vDistances.reserve( nPointCount );
+ CalcDistances( rOutlinePoly, vDistances );
+ if ( vDistances.size() )
+ {
+ std::vector< FWParagraphData >::iterator aParagraphDataIter = aTextAreaIter->vParagraphData.begin();
+ std::vector< FWParagraphData >::iterator aParagraphDataIterEnd = aTextAreaIter->vParagraphData.end();
+ while( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ std::vector< PolyPolygon >::iterator aParagraphOutlineIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::iterator aParagraphOutlineIterEnd = aParagraphDataIter->vOutlines.end();
+ while( aParagraphOutlineIter != aParagraphOutlineIterEnd )
+ {
+ PolyPolygon& rPolyPoly = *aParagraphOutlineIter;
+ Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
+ double fx1 = aBoundRect.Left() - nLeft;
+ double fx2 = aBoundRect.Right() - nLeft;
+ double fy1, fy2;
+ double fM1 = fx1 / (double)nWidth;
+ double fM2 = fx2 / (double)nWidth;
+
+ GetPoint( rOutlinePoly, vDistances, fM1, fx1, fy1 );
+ GetPoint( rOutlinePoly, vDistances, fM2, fx2, fy2 );
+
+ double fvx = ( fy2 - fy1 );
+ double fvy = - ( fx2 - fx1 );
+ fx1 = fx1 + ( ( fx2 - fx1 ) * 0.5 );
+ fy1 = fy1 + ( ( fy2 - fy1 ) * 0.5 );
+
+ double fAngle = atan2( -fvx, -fvy );
+ double fL = hypot( fvx, fvy );
+ fvx = fvx / fL;
+ fvy = fvy / fL;
+ fL = (double)aTextAreaIter->aBoundRect.GetHeight() / 2.0 - ( aParagraphDataIter->aBoundRect.Top() - aTextAreaIter->aBoundRect.Top() );
+ fvx *= fL;
+ fvy *= fL;
+ rPolyPoly.Move( (sal_Int32)( ( fvx + fx1 ) - aBoundRect.Center().X() ), (sal_Int32)( ( fvy + fy1 ) - aParagraphDataIter->aBoundRect.Top() ) );
+ rPolyPoly.Rotate( rPolyPoly.GetBoundRect().Center(), sin( fAngle ), cos( fAngle ) );
+ aParagraphOutlineIter++;
+ }
+ aParagraphDataIter++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( ( nOutline2dIdx + 1 ) >= aOutlines2d.Count() )
+ break;
+ const Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
+ const Polygon& rOutlinePoly2( aOutlines2d[ nOutline2dIdx++ ] );
+ const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
+ const sal_uInt16 nPointCount2 = rOutlinePoly2.GetSize();
+ if ( nPointCount && nPointCount2 )
+ {
+ std::vector< double > vDistances;
+ vDistances.reserve( nPointCount );
+ std::vector< double > vDistances2;
+ vDistances2.reserve( nPointCount2 );
+ CalcDistances( rOutlinePoly, vDistances );
+ CalcDistances( rOutlinePoly2, vDistances2 );
+ std::vector< FWParagraphData >::iterator aParagraphDataIter = aTextAreaIter->vParagraphData.begin();
+ std::vector< FWParagraphData >::iterator aParagraphDataIterEnd = aTextAreaIter->vParagraphData.end();
+ while( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ std::vector< PolyPolygon >::iterator aParagraphOutlineIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::iterator aParagraphOutlineIterEnd = aParagraphDataIter->vOutlines.end();
+ while( aParagraphOutlineIter != aParagraphOutlineIterEnd )
+ {
+ PolyPolygon& rPolyPoly = *aParagraphOutlineIter;
+ sal_uInt16 i, nPolyCount = rPolyPoly.Count();
+ for ( i = 0; i < nPolyCount; i++ )
+ {
+ Polygon& rPoly = rPolyPoly[ i ];
+ InsertMissingOutlinePoints( rOutlinePoly, vDistances, rTextAreaBoundRect, rPoly );
+ InsertMissingOutlinePoints( rOutlinePoly2, vDistances2, rTextAreaBoundRect, rPoly );
+ sal_uInt16 j, nPointCount = rPoly.GetSize();
+ for ( j = 0; j < nPointCount; j++ )
+ {
+ Point& rPoint = rPoly[ j ];
+ rPoint.X() -= nLeft;
+ rPoint.Y() -= nTop;
+ double fX = (double)rPoint.X() / (double)nWidth;
+ double fY = (double)rPoint.Y() / (double)nHeight;
+
+ double fx1, fy1, fx2, fy2;
+ GetPoint( rOutlinePoly, vDistances, fX, fx1, fy1 );
+ GetPoint( rOutlinePoly2, vDistances2, fX, fx2, fy2 );
+ double fWidth = fx2 - fx1;
+ double fHeight= fy2 - fy1;
+ rPoint.X() = (sal_Int32)( fx1 + fWidth * fY );
+ rPoint.Y() = (sal_Int32)( fy1 + fHeight* fY );
+ }
+ }
+ aParagraphOutlineIter++;
+ }
+ aParagraphDataIter++;
+ }
+ }
+ }
+ aTextAreaIter++;
+ }
+}
+
+SdrObject* CreateSdrObjectFromParagraphOutlines( const FWData& rFWData, const SdrObject* pCustomShape )
+{
+ SdrObject* pRet = NULL;
+ if ( rFWData.vTextAreaData.size() )
+ {
+ pRet = new SdrObjGroup();
+ pRet->SetModel( pCustomShape->GetModel() );
+
+ std::vector< FWTextArea >::const_iterator aTextAreaIter = rFWData.vTextAreaData.begin();
+ std::vector< FWTextArea >::const_iterator aTextAreaIterEnd = rFWData.vTextAreaData.end();
+ while ( aTextAreaIter != aTextAreaIterEnd )
+ {
+ std::vector< FWParagraphData >::const_iterator aParagraphDataIter = aTextAreaIter->vParagraphData.begin();
+ std::vector< FWParagraphData >::const_iterator aParagraphDataIterEnd = aTextAreaIter->vParagraphData.end();
+ while ( aParagraphDataIter != aParagraphDataIterEnd )
+ {
+ std::vector< PolyPolygon >::const_iterator aParagraphOutlineIter = aParagraphDataIter->vOutlines.begin();
+ std::vector< PolyPolygon >::const_iterator aParagraphOutlineIterEnd = aParagraphDataIter->vOutlines.end();
+ while( aParagraphOutlineIter != aParagraphOutlineIterEnd )
+ {
+ SdrObject* pPathObj = new SdrPathObj( OBJ_POLY, *aParagraphOutlineIter );
+ pPathObj->SetModel( pCustomShape->GetModel() );
+ ((SdrObjGroup*)pRet)->GetSubList()->NbcInsertObject( pPathObj );
+ aParagraphOutlineIter++;
+ }
+ aParagraphDataIter++;
+ }
+ aTextAreaIter++;
+ }
+
+ Point aP( pCustomShape->GetSnapRect().Center() );
+ Size aS( pCustomShape->GetLogicRect().GetSize() );
+ aP.X() -= aS.Width() / 2;
+ aP.Y() -= aS.Height() / 2;
+ Rectangle aLogicRect( aP, aS );
+ pRet->SetMergedItemSet( pCustomShape->GetMergedItemSet() );
+ }
+ return pRet;
+}
+
+SdrObject* EnhancedCustomShapeFontWork::CreateFontWork( const SdrObject* pShape2d, const SdrObject* pCustomShape )
+{
+ SdrObject* pRet = NULL;
+
+ Rectangle aLogicRect( pCustomShape->GetLogicRect() );
+ PolyPolygon aOutlines2d( GetOutlinesFromShape2d( pShape2d ) );
+ sal_uInt16 nOutlinesCount2d = aOutlines2d.Count();
+ if ( nOutlinesCount2d )
+ {
+ FWData aFWData;
+ if ( InitializeFontWorkData( pCustomShape, nOutlinesCount2d, aFWData ) )
+ {
+ /* retrieves the horizontal scaling factor that has to be used
+ to fit each paragraph text into its corresponding 2d outline */
+ CalculateHorizontalScalingFactor( pCustomShape, aFWData, aOutlines2d );
+
+ /* retrieving the Outlines for the each Paragraph. */
+
+ GetFontWorkOutline( aFWData, pCustomShape );
+
+ FitTextOutlinesToShapeOutlines( aOutlines2d, aFWData );
+
+ pRet = CreateSdrObjectFromParagraphOutlines( aFWData, pCustomShape );
+ }
+ }
+ return pRet;
+}