/************************************************************************* * * 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: svdtxhdl.cxx,v $ * $Revision: 1.29 $ * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #include "svdtxhdl.hxx" #include #include "svditext.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "unolingu.hxx" #include #include #include #include using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::i18n; //////////////////////////////////////////////////////////////////////////////////////////////////// ImpTextPortionHandler::ImpTextPortionHandler(SdrOutliner& rOutln, const SdrTextObj& rTxtObj): rOutliner(rOutln), rTextObj(rTxtObj) { SdrModel* pModel = rTextObj.GetModel(); MapMode aMap=aVDev.GetMapMode(); aMap.SetMapUnit(pModel->GetScaleUnit()); aMap.SetScaleX(pModel->GetScaleFraction()); aMap.SetScaleY(pModel->GetScaleFraction()); aVDev.SetMapMode(aMap); } void ImpTextPortionHandler::ConvertToPathObj(SdrObjGroup& rGroup, FASTBOOL bPoly) { bToPoly=bPoly; pGroup=&rGroup; Rectangle aAnchorRect; Rectangle aTextRect; SdrFitToSizeType eFit=rTextObj.GetFitToSize(); FASTBOOL bFitToSize=(eFit==SDRTEXTFIT_PROPORTIONAL || eFit==SDRTEXTFIT_ALLLINES); // Bei TakeTextRect wird u.a. auch der Text in // den Outliner gesteckt rTextObj.TakeTextRect(rOutliner,aTextRect,FALSE,&aAnchorRect); maTextRect=aTextRect; if (bFitToSize) maTextRect=aAnchorRect; rOutliner.SetDrawPortionHdl(LINK(this,ImpTextPortionHandler,ConvertHdl)); rOutliner.StripPortions(); rOutliner.SetDrawPortionHdl(Link()); rOutliner.Clear(); if(bFitToSize) { Fraction nX(aAnchorRect.Right()-aAnchorRect.Left(),aTextRect.Right()-aTextRect.Left()); Fraction nY(aAnchorRect.Bottom()-aAnchorRect.Top(),aTextRect.Bottom()-aTextRect.Top()); // #95395# scale from top-right when vertical text if(rOutliner.IsVertical()) pGroup->NbcResize(aAnchorRect.TopRight(),nX,nY); else pGroup->NbcResize(aAnchorRect.TopLeft(),nX,nY); } if (rTextObj.aGeo.nDrehWink!=0) { // #35825# Rotieren erst nach Resize (wg. FitToSize) pGroup->NbcRotate(maTextRect.TopLeft(),rTextObj.aGeo.nDrehWink,rTextObj.aGeo.nSin,rTextObj.aGeo.nCos); } } // #101498# Helper class to remember text portions in sorted manner class ImpRecordPortion { public: Point maPosition; String maText; xub_StrLen mnTextStart; xub_StrLen mnTextLength; sal_uInt16 mnPara; xub_StrLen mnIndex; // #102819# Here SvxFont needs to be used instead of Font SvxFont maFont; sal_Int32* mpDXArray; sal_uInt8 mnBiDiLevel; ImpRecordPortion(DrawPortionInfo* pInfo); ~ImpRecordPortion(); sal_uInt8 GetBiDiLevel() const { return mnBiDiLevel; } }; ImpRecordPortion::ImpRecordPortion(DrawPortionInfo* pInfo) : maPosition(pInfo->mrStartPos), maText(pInfo->mrText), mnTextStart((xub_StrLen)pInfo->mnTextStart), mnTextLength((xub_StrLen)pInfo->mnTextLen), mnPara(pInfo->mnPara), mnIndex(pInfo->mnIndex), maFont(pInfo->mrFont), mpDXArray(NULL), mnBiDiLevel(pInfo->GetBiDiLevel()) { if(pInfo->mpDXArray) { mpDXArray = new sal_Int32[pInfo->mnTextLen]; for(sal_uInt32 a(0L); a < pInfo->mnTextLen; a++) { mpDXArray[a] = pInfo->mpDXArray[a]; } } } ImpRecordPortion::~ImpRecordPortion() { if(mpDXArray) { delete[] mpDXArray; } } IMPL_LINK(ImpTextPortionHandler,ConvertHdl,DrawPortionInfo*,pInfo) { // maTextRect enthaelt den Ausgabebereich des Textobjekts BOOL bIsVertical(rOutliner.IsVertical()); Point aPos2(maTextRect.TopLeft() + pInfo->mrStartPos); Color aColor(pInfo->mrFont.GetColor()); if(bIsVertical) aPos2 = maTextRect.TopRight() + pInfo->mrStartPos; Point aStartPos(aPos2); SfxItemSet aAttrSet((SfxItemPool&)(*rTextObj.GetObjectItemPool())); long nHochTief(pInfo->mrFont.GetEscapement()); FontMetric aFontMetric(aVDev.GetFontMetric()); sal_Int32 nLineLen(0L); Font aFont( pInfo->mrFont ); if( nHochTief) { // shrink the font for sub-/superscripting long nPercent(pInfo->mrFont.GetPropr()); if(nPercent != 100) { Size aSize(aFont.GetSize()); aSize.Height() = (aSize.Height() * nPercent +50) / 100; aSize.Width() = (aSize.Width() * nPercent +50) / 100; aFont.SetSize(aSize); } sal_Bool bNeg(nHochTief < 0); if(bNeg) nHochTief = -nHochTief; nHochTief = (nHochTief * pInfo->mrFont.GetSize().Height() +50) /100; if(bNeg) nHochTief = -nHochTief; } aFont.SetOrientation( 0 ); aVDev.SetFont( aFont ); if(bIsVertical) // #83068# aPos2.X() += aFontMetric.GetAscent() + nHochTief; else aPos2.Y() -= aFontMetric.GetAscent() + nHochTief; if (pInfo->mrFont.IsOutline()) { aAttrSet.Put(XLineColorItem(String(),aColor)); aAttrSet.Put(XLineStyleItem(XLINE_SOLID)); aAttrSet.Put(XLineWidthItem(0)); aAttrSet.Put(XFillStyleItem(XFILL_NONE)); } else { aAttrSet.Put(XFillColorItem(String(),aColor)); aAttrSet.Put(XLineStyleItem(XLINE_NONE)); aAttrSet.Put(XFillStyleItem(XFILL_SOLID)); } // #100318# convert in a single step // #101499# Use GetTextOutlines and a PolyPolyVector now PolyPolyVector aPolyPolyVector; if(aVDev.GetTextOutlines(aPolyPolyVector, pInfo->mrText, pInfo->mnTextStart, pInfo->mnTextStart, pInfo->mnTextLen) && aPolyPolyVector.size()) { for(sal_uInt32 a(0); a < aPolyPolyVector.size(); a++) { PolyPolygon aPolyPoly(aPolyPolyVector[a]); if(aPolyPoly.Count() > 0 && aPolyPoly[0].GetSize() > 0) { basegfx::B2DPolyPolygon aPolyPolygon(aPolyPoly.getB2DPolyPolygon()); basegfx::B2DHomMatrix aMatrix; // rotate 270 degree if vertical since result is unrotated if(pInfo->mrFont.GetOrientation()) { double fAngle(F_PI * (pInfo->mrFont.GetOrientation() % 3600) / 1800.0); aMatrix.rotate(fAngle); } // result is baseline oriented, thus move one line height, too if(bIsVertical) { aMatrix.translate(-aFontMetric.GetAscent(), 0.0); } else { aMatrix.translate(0.0, aFontMetric.GetAscent()); } // move to output coordinates aMatrix.translate(aPos2.X(), aPos2.Y()); // transform aPolyPolygon.transform(aMatrix); // create object SdrObject* pObj = rTextObj.ImpConvertMakeObj(aPolyPolygon, sal_True, !bToPoly, sal_True); pObj->SetMergedItemSet(aAttrSet); pGroup->GetSubList()->InsertObject(pObj); } } nLineLen = pInfo->mpDXArray[pInfo->mnTextLen - 1]; } FontUnderline eUndl=pInfo->mrFont.GetUnderline(); FontStrikeout eStrk=pInfo->mrFont.GetStrikeout(); if (eUndl!=UNDERLINE_NONE) { FASTBOOL bDouble=eUndl==UNDERLINE_DOUBLE; long nDescent=aFontMetric.GetDescent(); long nAscend=aFontMetric.GetAscent(); long nDick=nDescent / (bDouble ? 5 : 3); long nDist=(nDescent-nDick*2)/3; // Linienabstand bei doppelt basegfx::B2DPolyPolygon aPolyPolygon; if (eUndl!=UNDERLINE_DOTTED) { Point aPoint(0,0); XPolygon aXP(Rectangle(aPoint,bIsVertical ? Point(nDick,nLineLen) : Point(nLineLen,nDick))); if(bIsVertical) aXP.Move(nAscend-nDist,0); aPolyPolygon.append(aXP.getB2DPolygon()); if (bDouble) { if(bIsVertical) aXP.Move(-(nDick+nDist),0); else aXP.Move(0,nDick+nDist); aPolyPolygon.append(aXP.getB2DPolygon()); } } else { Point aPoint(0,0); XPolygon aXP(Rectangle(aPoint,Point(nDick,nDick))); long n=0; while (n<=nLineLen) { if (n+nDick>nLineLen) { // ler letzte Dot ggf. etwas schmaler aXP=XPolygon(Rectangle( bIsVertical ? Point(0,n) : Point(n,0), bIsVertical ? Point(nDick,nLineLen) : Point(nLineLen,nDick))); } aPolyPolygon.append(aXP.getB2DPolygon()); if(bIsVertical) aXP.Move(0,2*nDick); else aXP.Move(2*nDick,0); n+=2*nDick; } } long y=nDescent-nDick; // y-Position der Striche zur Baseline bestimmen if (bDouble) y-=nDick+nDist; y=(y+1)/2; basegfx::B2DHomMatrix aMatrix; if(bIsVertical) { aMatrix.translate(aStartPos.X() - (y - nHochTief), aStartPos.Y()); } else { aMatrix.translate(aStartPos.X(), aStartPos.Y() + y - nHochTief); } aPolyPolygon.transform(aMatrix); // maTextRect enthaelt den Ausgabebereich des Textobjekts SdrObject* pObj=rTextObj.ImpConvertMakeObj(aPolyPolygon, sal_True, !bToPoly, sal_True); pObj->SetMergedItemSet(aAttrSet); pGroup->GetSubList()->InsertObject(pObj); } if (eStrk!=STRIKEOUT_NONE) { FASTBOOL bDouble=eStrk==STRIKEOUT_DOUBLE; long nDescent=aFontMetric.GetDescent(); //long nAscend=aFontMetric.GetAscent(); long nDick=nDescent / (bDouble ? 5 : 3); long nDist=(nDescent-nDick*2)/3; // Linienabstand bei doppelt basegfx::B2DPolyPolygon aPolyPolygon; const Point aPoint(0,0); const Rectangle aRect(aPoint,bIsVertical ? Point(nDick,nLineLen) : Point(nLineLen,nDick)); const basegfx::B2DRange aRectRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); basegfx::B2DPolygon aPolyFromRect(basegfx::tools::createPolygonFromRect(aRectRange)); aPolyPolygon.append(aPolyFromRect); if (bDouble) { basegfx::B2DHomMatrix aMatrix; if(bIsVertical) aMatrix.translate(-(nDick+nDist), 0.0); else aMatrix.translate(0.0, nDick+nDist); aPolyFromRect.transform(aMatrix); aPolyPolygon.append(aPolyFromRect); } // y-Position der Striche zur Baseline bestimmen long y=-(long)(aFontMetric.GetAscent()-aFontMetric.GetIntLeading()+1)/3; if (!bDouble) y-=(nDick+1)/2; else y-=nDick+(nDist+1)/2; basegfx::B2DHomMatrix aMatrix; if(bIsVertical) { aMatrix.translate(aStartPos.X() - (y - nHochTief), aStartPos.Y()); } else { aMatrix.translate(aStartPos.X(), aStartPos.Y() + y - nHochTief); } aPolyPolygon.transform(aMatrix); // maTextRect enthaelt den Ausgabebereich des Textobjekts SdrObject* pObj=rTextObj.ImpConvertMakeObj(aPolyPolygon, sal_True, !bToPoly, sal_True); pObj->SetMergedItemSet(aAttrSet); pGroup->GetSubList()->InsertObject(pObj); } return 0; } // eof