0ec42c482c
2008/07/10 13:00:51 aw 1.19.58.1: #i39532# XOutputDevice removed, PrepareDelete removed
913 lines
42 KiB
C++
913 lines
42 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: EnhancedCustomShapeFontWork.cxx,v $
|
|
* $Revision: 1.20 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org 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 version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_svx.hxx"
|
|
#include "EnhancedCustomShapeFontWork.hxx"
|
|
#include <tools/solar.h> // UINTXX
|
|
#include <svx/svddef.hxx>
|
|
#include <svx/svdogrp.hxx>
|
|
#include <svx/svdopath.hxx>
|
|
#include <vcl/metric.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/sdasitm.hxx>
|
|
#include <svx/sdasaitm.hxx>
|
|
#include <svx/sdtfsitm.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <svditer.hxx>
|
|
#include <vcl/metric.hxx>
|
|
#include <svx/eeitem.hxx>
|
|
#include <svx/frmdiritem.hxx>
|
|
#include <fontitem.hxx>
|
|
#include <svx/postitem.hxx>
|
|
#include <svx/wghtitem.hxx>
|
|
#include <svx/charscaleitem.hxx>
|
|
#include "EnhancedCustomShapeTypeNames.hxx"
|
|
#include <svx/svdorect.hxx>
|
|
#include <svx/svdoashp.hxx>
|
|
#include <svx/outliner.hxx>
|
|
#include <svx/outlobj.hxx>
|
|
#include <svx/editobj.hxx>
|
|
#include <svx/editeng.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include <vector>
|
|
#include <numeric>
|
|
#include <algorithm>
|
|
#include <comphelper/processfactory.hxx>
|
|
#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
|
|
#include <com/sun/star/i18n/ScriptType.hdl>
|
|
#endif
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#ifndef _COM_SUN_STAR_I18N_CHARACTERITERATORMODE_HDL_
|
|
#include <com/sun/star/i18n/CharacterIteratorMode.hdl>
|
|
#endif
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
using namespace com::sun::star::uno;
|
|
|
|
typedef std::vector< std::vector< double > > PolyPolygonDistances;
|
|
|
|
struct FWCharacterData // representing a single character
|
|
{
|
|
std::vector< PolyPolygon > vOutlines;
|
|
Rectangle aBoundRect;
|
|
};
|
|
struct FWParagraphData // representing a single paragraph
|
|
{
|
|
rtl::OUString aString;
|
|
std::vector< FWCharacterData > vCharacters;
|
|
Rectangle aBoundRect;
|
|
sal_Int16 nFrameDirection;
|
|
};
|
|
struct FWTextArea // representing multiple concluding paragraphs
|
|
{
|
|
std::vector< FWParagraphData > vParagraphs;
|
|
Rectangle aBoundRect;
|
|
};
|
|
struct FWData // representing the whole text
|
|
{
|
|
std::vector< FWTextArea > vTextAreas;
|
|
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_Int32 nParagraphsLeft = rTextObj.GetParagraphCount();
|
|
|
|
rFWData.nMaxParagraphsPerTextArea = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
|
|
sal_Int16 j = 0;
|
|
while( nParagraphsLeft && nTextAreaCount )
|
|
{
|
|
FWTextArea aTextArea;
|
|
sal_Int32 i, nParagraphs = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
|
|
for ( i = 0; i < nParagraphs; i++, j++ )
|
|
{
|
|
FWParagraphData aParagraphData;
|
|
aParagraphData.aString = rTextObj.GetText( j );
|
|
|
|
const SfxItemSet& rParaSet = rTextObj.GetParaAttribs( j ); // retrieving some paragraph attributes
|
|
aParagraphData.nFrameDirection = ((SvxFrameDirectionItem&)rParaSet.Get( EE_PARA_WRITINGDIR )).GetValue();
|
|
aTextArea.vParagraphs.push_back( aParagraphData );
|
|
}
|
|
rFWData.vTextAreas.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.vTextAreas.begin();
|
|
std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.end();
|
|
while( aTextAreaIter != aTextAreaIEnd )
|
|
{
|
|
// 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 aParagraphIter( aTextAreaIter->vParagraphs.begin() );
|
|
std::vector< FWParagraphData >::const_iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
|
|
while( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
double fTextWidth = aVirDev.GetTextWidth( aParagraphIter->aString );
|
|
if ( fTextWidth > 0.0 )
|
|
{
|
|
double fScale = fWidth / fTextWidth;
|
|
if ( !bScalingFactorDefined )
|
|
{
|
|
fScalingFactor = fScale;
|
|
bScalingFactorDefined = sal_True;
|
|
}
|
|
else
|
|
{
|
|
if ( fScale < fScalingFactor )
|
|
fScalingFactor = fScale;
|
|
}
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
aTextAreaIter++;
|
|
}
|
|
rFWData.fHorizontalTextScaling = fScalingFactor;
|
|
}
|
|
|
|
void GetTextAreaOutline( const FWData& rFWData, const SdrObject* pCustomShape, FWTextArea& rTextArea, sal_Bool bSameLetterHeights )
|
|
{
|
|
sal_Bool bIsVertical = ((SdrObjCustomShape*)pCustomShape)->IsVerticalWriting();
|
|
sal_Int32 nVerticalOffset = rFWData.nMaxParagraphsPerTextArea > rTextArea.vParagraphs.size()
|
|
? rFWData.nSingleLineHeight / 2 : 0;
|
|
|
|
std::vector< FWParagraphData >::iterator aParagraphIter( rTextArea.vParagraphs.begin() );
|
|
std::vector< FWParagraphData >::iterator aParagraphIEnd( rTextArea.vParagraphs.end() );
|
|
while( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
const rtl::OUString& rText = aParagraphIter->aString;
|
|
if ( rText.getLength() )
|
|
{
|
|
// generating vcl/font
|
|
USHORT nScriptType = i18n::ScriptType::LATIN;
|
|
Reference< i18n::XBreakIterator > xBI( EnhancedCustomShapeFontWork::GetBreakIterator() );
|
|
if ( xBI.is() )
|
|
{
|
|
nScriptType = xBI->getScriptType( rText, 0 );
|
|
sal_uInt16 nChg = 0;
|
|
if( i18n::ScriptType::WEAK == nScriptType )
|
|
{
|
|
nChg = (xub_StrLen)xBI->endOfScript( rText, nChg, nScriptType );
|
|
if( nChg < rText.getLength() )
|
|
nScriptType = xBI->getScriptType( rText, nChg );
|
|
else
|
|
nScriptType = i18n::ScriptType::LATIN;
|
|
}
|
|
}
|
|
UINT16 nFntItm = EE_CHAR_FONTINFO;
|
|
if ( nScriptType == i18n::ScriptType::COMPLEX )
|
|
nFntItm = EE_CHAR_FONTINFO_CTL;
|
|
else if ( nScriptType == i18n::ScriptType::ASIAN )
|
|
nFntItm = EE_CHAR_FONTINFO_CJK;
|
|
SvxFontItem& rFontItem = (SvxFontItem&)pCustomShape->GetMergedItem( nFntItm );
|
|
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 );
|
|
|
|
SvxPostureItem& rPostureItem = (SvxPostureItem&)pCustomShape->GetMergedItem( EE_CHAR_ITALIC );
|
|
aFont.SetItalic( rPostureItem.GetPosture() );
|
|
|
|
SvxWeightItem& rWeightItem = (SvxWeightItem&)pCustomShape->GetMergedItem( EE_CHAR_WEIGHT );
|
|
aFont.SetWeight( rWeightItem.GetWeight() );
|
|
|
|
// initializing virtual device
|
|
VirtualDevice aVirDev( 1 );
|
|
aVirDev.SetMapMode( MAP_100TH_MM );
|
|
aVirDev.SetFont( aFont );
|
|
aVirDev.EnableRTL( sal_True );
|
|
if ( aParagraphIter->nFrameDirection == FRMDIR_HORI_RIGHT_TOP )
|
|
aVirDev.SetLayoutMode( TEXT_LAYOUT_BIDI_RTL );
|
|
|
|
SvxCharScaleWidthItem& rCharScaleWidthItem = (SvxCharScaleWidthItem&)pCustomShape->GetMergedItem( EE_CHAR_FONTWIDTH );
|
|
sal_uInt16 nCharScaleWidth = rCharScaleWidthItem.GetValue();
|
|
sal_Int32* pDXArry = NULL;
|
|
sal_Int32 nWidth = 0;
|
|
|
|
// VERTICAL
|
|
if ( bIsVertical )
|
|
{
|
|
// vertical _> each single character needs to be rotated by 90
|
|
sal_Int32 i;
|
|
sal_Int32 nHeight = 0;
|
|
Rectangle aSingleCharacterUnion;
|
|
for ( i = 0; i < rText.getLength(); i++ )
|
|
{
|
|
FWCharacterData aCharacterData;
|
|
rtl::OUString aCharText( (sal_Unicode)rText[ i ] );
|
|
if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, aCharText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
|
|
{
|
|
sal_Int32 nTextWidth = aVirDev.GetTextWidth( aCharText, 0, STRING_LEN );
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterData.vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterData.vOutlines.end();
|
|
if ( aOutlineIter == aOutlineIEnd )
|
|
{
|
|
nHeight += rFWData.nSingleLineHeight;
|
|
}
|
|
else
|
|
{
|
|
while ( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
// rotating
|
|
aOutlineIter->Rotate( Point( nTextWidth / 2, rFWData.nSingleLineHeight / 2 ), 900 );
|
|
aCharacterData.aBoundRect.Union( aOutlineIter->GetBoundRect() );
|
|
aOutlineIter++;
|
|
}
|
|
aOutlineIter = aCharacterData.vOutlines.begin();
|
|
aOutlineIEnd = aCharacterData.vOutlines.end();
|
|
while ( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
sal_Int32 nM = - aCharacterData.aBoundRect.Left() + nHeight;
|
|
aOutlineIter->Move( nM, 0 );
|
|
aCharacterData.aBoundRect.Move( nM, 0 );
|
|
aOutlineIter++;
|
|
}
|
|
nHeight += aCharacterData.aBoundRect.GetWidth() + ( rFWData.nSingleLineHeight / 5 );
|
|
aSingleCharacterUnion.Union( aCharacterData.aBoundRect );
|
|
}
|
|
}
|
|
aParagraphIter->vCharacters.push_back( aCharacterData );
|
|
}
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
|
|
while ( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
aOutlineIter->Move( ( aSingleCharacterUnion.GetWidth() - aCharacterIter->aBoundRect.GetWidth() ) / 2, 0 );
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ( nCharScaleWidth != 100 ) && nCharScaleWidth )
|
|
{ // applying character spacing
|
|
pDXArry = new sal_Int32[ rText.getLength() ];
|
|
aVirDev.GetTextArray( rText, pDXArry, 0, STRING_LEN );
|
|
FontMetric aFontMetric( aVirDev.GetFontMetric() );
|
|
aFont.SetWidth( (sal_Int32)( (double)aFontMetric.GetWidth() * ( (double)100 / (double)nCharScaleWidth ) ) );
|
|
aVirDev.SetFont( aFont );
|
|
}
|
|
FWCharacterData aCharacterData;
|
|
if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, rText, 0, 0, STRING_LEN, TRUE, nWidth, pDXArry ) )
|
|
{
|
|
aParagraphIter->vCharacters.push_back( aCharacterData );
|
|
}
|
|
|
|
/* trying to retrieve each single character _> is not working well
|
|
sal_Int32 i;
|
|
for ( i = 0; i < rText.getLength(); i++ )
|
|
{
|
|
FWCharacterData aCharacterData;
|
|
if ( aVirDev.GetTextOutlines( aCharacterData.vOutlines, rText, 0, i, 1, TRUE, nWidth, pDXArry ) )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterData.vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterData.vOutlines.end();
|
|
while ( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
aCharacterData.aBoundRect.Union( aOutlineIter->GetBoundRect() );
|
|
aOutlineIter++;
|
|
}
|
|
}
|
|
aParagraphIter->vCharacters.push_back( aCharacterData );
|
|
}
|
|
*/
|
|
}
|
|
delete[] pDXArry;
|
|
|
|
// veritcal alignment
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd ( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
|
|
PolyPolygon& rPolyPoly = *aOutlineIter++;
|
|
|
|
if ( nVerticalOffset )
|
|
rPolyPoly.Move( 0, nVerticalOffset );
|
|
|
|
// retrieving the boundrect for the paragraph
|
|
Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
|
|
aParagraphIter->aBoundRect.Union( aBoundRect );
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
}
|
|
// updating the boundrect for the text area by merging the current paragraph boundrect
|
|
if ( aParagraphIter->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 = aParagraphIter->aBoundRect;
|
|
rTextArea.aBoundRect.Union( rParagraphBoundRect );
|
|
|
|
if ( bSameLetterHeights )
|
|
{
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter( aCharacterIter->vOutlines.begin() );
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd( aCharacterIter->vOutlines.end() );
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
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++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
}
|
|
}
|
|
if ( bIsVertical )
|
|
nVerticalOffset -= rFWData.nSingleLineHeight;
|
|
else
|
|
nVerticalOffset += rFWData.nSingleLineHeight;
|
|
aParagraphIter++;
|
|
}
|
|
}
|
|
|
|
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.vTextAreas.begin();
|
|
std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.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 != aTextAreaIEnd )
|
|
{
|
|
GetTextAreaOutline( rFWData, pCustomShape, *aTextAreaIter, bSameLetterHeights );
|
|
if ( eFTS == SDRTEXTFIT_ALLLINES )
|
|
{
|
|
std::vector< FWParagraphData >::iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
|
|
std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
|
|
while ( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
sal_Int32 nParaWidth = aParagraphIter->aBoundRect.GetWidth();
|
|
if ( nParaWidth )
|
|
{
|
|
double fScale = (double)aTextAreaIter->aBoundRect.GetWidth() / nParaWidth;
|
|
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
aOutlineIter->Scale( fScale, 1.0 );
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch( eHorzAdjust )
|
|
{
|
|
case SDRTEXTHORZADJUST_RIGHT :
|
|
case SDRTEXTHORZADJUST_CENTER:
|
|
{
|
|
std::vector< FWParagraphData >::iterator aParagraphIter( aTextAreaIter->vParagraphs.begin() );
|
|
std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
|
|
while ( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
sal_Int32 nHorzDiff = 0;
|
|
if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
|
|
nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphIter->aBoundRect.GetWidth() ) / 2;
|
|
else if ( eHorzAdjust == SDRTEXTHORZADJUST_RIGHT )
|
|
nHorzDiff = ( aTextAreaIter->aBoundRect.GetWidth() - aParagraphIter->aBoundRect.GetWidth() );
|
|
if ( nHorzDiff )
|
|
{
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
aOutlineIter->Move( nHorzDiff, 0 );
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
case SDRTEXTHORZADJUST_BLOCK : break; // don't know
|
|
case SDRTEXTHORZADJUST_LEFT : break; // already left aligned -> nothing to do
|
|
}
|
|
}
|
|
aTextAreaIter++;
|
|
}
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon GetOutlinesFromShape2d( const SdrObject* pShape2d )
|
|
{
|
|
basegfx::B2DPolyPolygon aOutlines2d;
|
|
|
|
SdrObjListIter aObjListIter( *pShape2d, IM_DEEPWITHGROUPS );
|
|
while( aObjListIter.IsMore() )
|
|
{
|
|
SdrObject* pPartObj = aObjListIter.Next();
|
|
if ( pPartObj->ISA( SdrPathObj ) )
|
|
{
|
|
basegfx::B2DPolyPolygon aCandidate(((SdrPathObj*)pPartObj)->GetPathPoly());
|
|
if(aCandidate.areControlPointsUsed())
|
|
{
|
|
aCandidate = basegfx::tools::adaptiveSubdivideByAngle(aCandidate);
|
|
}
|
|
aOutlines2d.append(aCandidate);
|
|
}
|
|
}
|
|
|
|
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 = 0.0;
|
|
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 = sal::static_int_cast<sal_uInt16>( 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 = sal::static_int_cast<sal_uInt16>( 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.vTextAreas.begin();
|
|
std::vector< FWTextArea >::iterator aTextAreaIEnd = rFWData.vTextAreas.end();
|
|
|
|
sal_uInt16 nOutline2dIdx = 0;
|
|
while( aTextAreaIter != aTextAreaIEnd )
|
|
{
|
|
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 aParagraphIter( aTextAreaIter->vParagraphs.begin() );
|
|
std::vector< FWParagraphData >::iterator aParagraphIEnd( aTextAreaIter->vParagraphs.end() );
|
|
while( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
PolyPolygon& rPolyPoly = *aOutlineIter;
|
|
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 + aTextAreaIter->aBoundRect.Top() ) - aParagraphIter->aBoundRect.Center().Y();
|
|
fvx *= fL;
|
|
fvy *= fL;
|
|
rPolyPoly.Rotate( Point( aBoundRect.Center().X(), aParagraphIter->aBoundRect.Center().Y() ), sin( fAngle ), cos( fAngle ) );
|
|
rPolyPoly.Move( (sal_Int32)( ( fx1 + fvx )- aBoundRect.Center().X() ), (sal_Int32)( ( fy1 + fvy ) - aParagraphIter->aBoundRect.Center().Y() ) );
|
|
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 aParagraphIter = aTextAreaIter->vParagraphs.begin();
|
|
std::vector< FWParagraphData >::iterator aParagraphIEnd = aTextAreaIter->vParagraphs.end();
|
|
while( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
std::vector< FWCharacterData >::iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::iterator aOutlineIter = aCharacterIter->vOutlines.begin();
|
|
std::vector< PolyPolygon >::iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
PolyPolygon& rPolyPoly = *aOutlineIter;
|
|
sal_uInt16 i, nPolyCount = rPolyPoly.Count();
|
|
for ( i = 0; i < nPolyCount; i++ )
|
|
{
|
|
// #i35928#
|
|
basegfx::B2DPolygon aCandidate(rPolyPoly[ i ].getB2DPolygon());
|
|
|
|
if(aCandidate.areControlPointsUsed())
|
|
{
|
|
aCandidate = basegfx::tools::adaptiveSubdivideByAngle(aCandidate);
|
|
}
|
|
|
|
// create local polygon copy to work on
|
|
Polygon aLocalPoly(aCandidate);
|
|
|
|
InsertMissingOutlinePoints( rOutlinePoly, vDistances, rTextAreaBoundRect, aLocalPoly );
|
|
InsertMissingOutlinePoints( rOutlinePoly2, vDistances2, rTextAreaBoundRect, aLocalPoly );
|
|
|
|
sal_uInt16 j, _nPointCount = aLocalPoly.GetSize();
|
|
for ( j = 0; j < _nPointCount; j++ )
|
|
{
|
|
Point& rPoint = aLocalPoly[ 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 );
|
|
}
|
|
|
|
// write back polygon
|
|
rPolyPoly[ i ] = aLocalPoly;
|
|
}
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
}
|
|
}
|
|
aTextAreaIter++;
|
|
}
|
|
}
|
|
|
|
SdrObject* CreateSdrObjectFromParagraphOutlines( const FWData& rFWData, const SdrObject* pCustomShape )
|
|
{
|
|
SdrObject* pRet = NULL;
|
|
if ( rFWData.vTextAreas.size() )
|
|
{
|
|
pRet = new SdrObjGroup();
|
|
// SJ: not setting model, so we save a lot of broadcasting and the model is not modified any longer
|
|
// pRet->SetModel( pCustomShape->GetModel() );
|
|
std::vector< FWTextArea >::const_iterator aTextAreaIter = rFWData.vTextAreas.begin();
|
|
std::vector< FWTextArea >::const_iterator aTextAreaIEnd = rFWData.vTextAreas.end();
|
|
while ( aTextAreaIter != aTextAreaIEnd )
|
|
{
|
|
std::vector< FWParagraphData >::const_iterator aParagraphIter = aTextAreaIter->vParagraphs.begin();
|
|
std::vector< FWParagraphData >::const_iterator aParagraphIEnd = aTextAreaIter->vParagraphs.end();
|
|
while ( aParagraphIter != aParagraphIEnd )
|
|
{
|
|
std::vector< FWCharacterData >::const_iterator aCharacterIter( aParagraphIter->vCharacters.begin() );
|
|
std::vector< FWCharacterData >::const_iterator aCharacterIEnd( aParagraphIter->vCharacters.end() );
|
|
while ( aCharacterIter != aCharacterIEnd )
|
|
{
|
|
std::vector< PolyPolygon >::const_iterator aOutlineIter = aCharacterIter->vOutlines.begin();
|
|
std::vector< PolyPolygon >::const_iterator aOutlineIEnd = aCharacterIter->vOutlines.end();
|
|
while( aOutlineIter != aOutlineIEnd )
|
|
{
|
|
SdrObject* pPathObj = new SdrPathObj( OBJ_POLY, aOutlineIter->getB2DPolyPolygon() );
|
|
// SJ: not setting model, so we save a lot of broadcasting and the model is not modified any longer
|
|
// pPathObj->SetModel( pCustomShape->GetModel() );
|
|
((SdrObjGroup*)pRet)->GetSubList()->NbcInsertObject( pPathObj );
|
|
aOutlineIter++;
|
|
}
|
|
aCharacterIter++;
|
|
}
|
|
aParagraphIter++;
|
|
}
|
|
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 );
|
|
|
|
SfxItemSet aSet( pCustomShape->GetMergedItemSet() );
|
|
aSet.ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
|
|
aSet.Put(SdrShadowItem(sal_False)); // #i37011# NO shadow for FontWork geometry
|
|
pRet->SetMergedItemSet( aSet ); // * otherwise we would crash, because the outliner tries to create a Paraobject, but there is no model
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > EnhancedCustomShapeFontWork::mxBreakIterator = 0;
|
|
|
|
Reference < i18n::XBreakIterator > EnhancedCustomShapeFontWork::GetBreakIterator()
|
|
{
|
|
if ( !mxBreakIterator.is() )
|
|
{
|
|
Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
|
|
Reference < XInterface > xI = xMSF->createInstance( rtl::OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
|
|
if ( xI.is() )
|
|
{
|
|
Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XBreakIterator >*)0) );
|
|
x >>= mxBreakIterator;
|
|
}
|
|
}
|
|
return mxBreakIterator;
|
|
}
|
|
|
|
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;
|
|
}
|