support text underlining

This commit is contained in:
Herbert Duerr 2007-02-20 14:24:21 +00:00
parent 1389fccf9a
commit b72eefb165

View file

@ -4,9 +4,9 @@
*
* $RCSfile: textprimitive2d.cxx,v $
*
* $Revision: 1.6 $
* $Revision: 1.7 $
*
* last change: $Author: hdu $ $Date: 2007-02-15 13:25:26 $
* last change: $Author: hdu $ $Date: 2007-02-20 15:24:21 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
@ -81,6 +81,8 @@
#include <basegfx/tools/canvastools.hxx>
#endif
#include <numeric>
//////////////////////////////////////////////////////////////////////////////
namespace drawinglayer
@ -331,18 +333,186 @@ namespace drawinglayer
{
Primitive2DSequence TextComplexPortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
{
Primitive2DSequence aRetval(1);
Primitive2DSequence aRetval(3);
// First create a simple text primitive and ignore other attributes
aRetval[0] = new TextSimplePortionPrimitive2D(getTextTransform(), getText(), getDXArray(), getFontAttributes(), getFontColor());
if( meFontUnderline != FONT_UNDERLINE_NONE )
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX);
basegfx::B2DHomMatrix aUnscaledTransform;
aUnscaledTransform.rotate( fRotate );
aUnscaledTransform.shearX( fShearX );
aUnscaledTransform.translate( aTranslate.getX(), aTranslate.getY() );
basegfx::B2DHomMatrix aUnrotatedTransform = getTextTransform();
aUnrotatedTransform.rotate( -fRotate );
TextLayouterDevice aTextLayouter;
aTextLayouter.setFontAttributes(getFontAttributes(), aUnrotatedTransform );
// const double fLineHeight = aTextLayouter.getTextHeight();
double fUnderlineOffset = aTextLayouter.getUnderlineOffset();
double fUnderlineHeight = aTextLayouter.getUnderlineHeight();
// const double fStrikeoutOffset = aTextLayouter.getStrikeoutOffset();
basegfx::tools::B2DLineJoin eLineJoin = basegfx::tools::B2DLINEJOIN_NONE;
bool bDoubleLine = false;
bool bWaveLine = false;
const int* pDashDotArray = NULL;
static const int aDottedArray[] = { 1, 1, 0}; // DOTTED LINE
static const int aDashDotArray[] = { 1, 1, 4, 1, 0}; // DASHDOT
static const int aDashDotDotArray[] = { 1, 1, 1, 1, 4, 1, 0}; // DASHDOTDOT
static const int aDashedArray[] = { 5, 2, 0}; // DASHED LINE
static const int aLongDashArray[] = { 7, 2, 0}; // LONGDASH
// set Underline attribute
switch( getFontUnderline() )
{
default:
DBG_WARNING1( "DrawingLayer: Unknown underline attribute (%d)!", getFontUnderline() );
// fall through
case primitive2d::FONT_UNDERLINE_NONE:
fUnderlineHeight = 0;
break;
case primitive2d::FONT_UNDERLINE_BOLD:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_SINGLE:
break;
case primitive2d::FONT_UNDERLINE_DOUBLE:
bDoubleLine = true;
break;
case primitive2d::FONT_UNDERLINE_BOLDDOTTED:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_DOTTED:
eLineJoin = basegfx::tools::B2DLINEJOIN_ROUND;
pDashDotArray = aDottedArray;
break;
case primitive2d::FONT_UNDERLINE_BOLDDASH:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_DASH:
pDashDotArray = aDashedArray;
break;
case primitive2d::FONT_UNDERLINE_BOLDLONGDASH:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_LONGDASH:
pDashDotArray = aLongDashArray;
break;
case primitive2d::FONT_UNDERLINE_BOLDDASHDOT:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_DASHDOT:
pDashDotArray = aDashDotArray;
break;
case primitive2d::FONT_UNDERLINE_BOLDDASHDOTDOT:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_DASHDOTDOT:
eLineJoin = basegfx::tools::B2DLINEJOIN_ROUND;
pDashDotArray = aDashDotDotArray;
break;
case primitive2d::FONT_UNDERLINE_SMALLWAVE:
// TODO
bWaveLine = true;
break;
case primitive2d::FONT_UNDERLINE_BOLDWAVE:
fUnderlineHeight *= 2;
// fall through
case primitive2d::FONT_UNDERLINE_WAVE:
// TODO
bWaveLine = true;
break;
case primitive2d::FONT_UNDERLINE_DOUBLEWAVE:
bWaveLine = true;
bDoubleLine = true;
break;
}
double fTextWidth = 0.0;
if( getDXArray().empty() )
fTextWidth = aTextLayouter.getTextWidth( getText(), 0/*TODO*/, getText().Len()/*TODO*/ );
else
fTextWidth = getDXArray().back() * aScale.getX();
if( bDoubleLine )
{
fUnderlineOffset -= 0.50 * fUnderlineHeight;
fUnderlineHeight *= 0.64;
}
basegfx::B2DPolygon aUnderline;
::basegfx::B2DPoint aPoint( 0.0, fUnderlineOffset );
aUnderline.append( aPoint );
if( !bWaveLine )
{
// straight underline
aUnderline.append( aPoint + ::basegfx::B2DPoint( fTextWidth, 0.0 ) );
}
else
{
// wavy underline
basegfx::B2DPolygon& aWavePoly = aUnderline;
double fWaveWidth = 4 * fUnderlineHeight;
if( getFontUnderline() == primitive2d::FONT_UNDERLINE_SMALLWAVE )
fWaveWidth *= 0.7;
const double fWaveHeight = 0.5 * fWaveWidth;
const ::basegfx::B2DPoint aCtrlOffset( fWaveWidth * 0.467308, fWaveHeight );
for( double fPos = fWaveWidth; fPos < fTextWidth; fPos += fWaveWidth ) {
// create a symmetrical wave using one cubic bezier curve
// with y==0 for {x==0, x==0.5*fW or x==1.0*fW}
// and ymin/ymax at {x=0.25*fW or 0.75*fW}
const int n = aWavePoly.count();
aWavePoly.setControlPointA( n-1, aPoint + aCtrlOffset );
aWavePoly.append( aPoint += ::basegfx::B2DPoint( fWaveWidth, 0.0 ) );
aWavePoly.setControlPointB( n-1, aPoint - aCtrlOffset );
}
// adjust stroke style
eLineJoin = basegfx::tools::B2DLINEJOIN_ROUND;
fUnderlineHeight *= 0.5;
}
const basegfx::BColor& rLineColor = getFontColor();
attribute::StrokeAttribute aStrokeAttr( rLineColor, fUnderlineHeight, eLineJoin );
if( pDashDotArray != NULL )
{
::std::vector< double > aDoubleArray;
for( const int* p = pDashDotArray; *p; ++p )
aDoubleArray.push_back( *p * fUnderlineHeight);
const double fFullDashDotLen = ::std::accumulate(aDoubleArray.begin(), aDoubleArray.end(), 0.0);
aStrokeAttr = attribute::StrokeAttribute( rLineColor,
fUnderlineHeight, eLineJoin, aDoubleArray, fFullDashDotLen );
}
aUnderline.transform( aUnscaledTransform );
aRetval[1] = new PolygonStrokePrimitive2D( aUnderline, aStrokeAttr );
if( bDoubleLine )
{
// add another underline below the first underline
const double fLineDist = (bWaveLine ? 3 : 2) * fUnderlineHeight;
::basegfx::B2DPoint aOffsetPoint( 0.0, fLineDist );
aUnscaledTransform.translate( -aTranslate.getX(), -aTranslate.getY() );
aOffsetPoint = aUnscaledTransform * aOffsetPoint;
basegfx::B2DHomMatrix aOffsetTransform;
aOffsetTransform.translate( aOffsetPoint.getX(), aOffsetPoint.getY() );
aUnderline.transform( aOffsetTransform );
aRetval[2] = new PolygonStrokePrimitive2D( aUnderline, aStrokeAttr );
}
// TODO: need to take care of
// -underline
// -strikethrough
// -emphasis mark
// -relief (embosses/engraved)
// -shadow
// -outline
// if( getWordLineMode() )
// if( getUnderlineAbove() )
}
return aRetval;
}