Kaydet (Commit) ffce13a5 authored tarafından Chris Sherlock's avatar Chris Sherlock

Move VCL text line functions from text.cxx to textline.cxx

Change-Id: I3adea9cd08c86f676e6af525e5a7caf430c96d8d
üst 588bb542
...@@ -243,6 +243,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ ...@@ -243,6 +243,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/outdev/bitmap \ vcl/source/outdev/bitmap \
vcl/source/outdev/font \ vcl/source/outdev/font \
vcl/source/outdev/text \ vcl/source/outdev/text \
vcl/source/outdev/textline \
vcl/source/outdev/pixel \ vcl/source/outdev/pixel \
vcl/source/outdev/rect \ vcl/source/outdev/rect \
vcl/source/outdev/line \ vcl/source/outdev/line \
......
...@@ -135,19 +135,6 @@ void ImplMultiTextLineInfo::Clear() ...@@ -135,19 +135,6 @@ void ImplMultiTextLineInfo::Clear()
mnLines = 0; mnLines = 0;
} }
bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
{
if ( !rFont.IsVertical() )
return false;
if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
|| (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
// the underline is right for Japanese only
return true;
return false;
}
void OutputDevice::ImplInitTextColor() void OutputDevice::ImplInitTextColor()
{ {
DBG_TESTSOLARMUTEX(); DBG_TESTSOLARMUTEX();
...@@ -273,745 +260,6 @@ Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout ) ...@@ -273,745 +260,6 @@ Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ); return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
} }
void OutputDevice::ImplInitTextLineSize()
{
mpFontEntry->maMetric.ImplInitTextLineSize( this );
}
void OutputDevice::ImplInitAboveTextLineSize()
{
mpFontEntry->maMetric.ImplInitAboveTextLineSize();
}
static void ImplDrawWavePixel( long nOriginX, long nOriginY,
long nCurX, long nCurY,
short nOrientation,
SalGraphics* pGraphics,
OutputDevice* pOutDev,
bool bDrawPixAsRect,
long nPixWidth, long nPixHeight )
{
if ( nOrientation )
ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
if ( bDrawPixAsRect )
{
pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
}
else
{
pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
}
}
void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
long nDistX, long nDistY,
long nWidth, long nHeight,
long nLineWidth, short nOrientation,
const Color& rColor )
{
if ( !nHeight )
return;
long nStartX = nBaseX + nDistX;
long nStartY = nBaseY + nDistY;
// If the height is 1 pixel, it's enough ouput a line
if ( (nLineWidth == 1) && (nHeight == 1) )
{
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = true;
long nEndX = nStartX+nWidth;
long nEndY = nStartY;
if ( nOrientation )
{
ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
}
mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
}
else
{
long nCurX = nStartX;
long nCurY = nStartY;
long nDiffX = 2;
long nDiffY = nHeight-1;
long nCount = nWidth;
long nOffY = -1;
long nFreq;
long i;
long nPixWidth;
long nPixHeight;
bool bDrawPixAsRect;
// On printers that ouput pixel via DrawRect()
if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
mbInitFillColor = true;
bDrawPixAsRect = true;
nPixWidth = nLineWidth;
nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
}
else
{
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = true;
nPixWidth = 1;
nPixHeight = 1;
bDrawPixAsRect = false;
}
if ( !nDiffY )
{
while ( nWidth )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nWidth--;
}
}
else
{
nCurY += nDiffY;
nFreq = nCount / (nDiffX+nDiffY);
while ( nFreq-- )
{
for( i = nDiffY; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
nOffY = -nOffY;
}
nFreq = nCount % (nDiffX+nDiffY);
if ( nFreq )
{
for( i = nDiffY; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
}
}
}
}
void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontUnderline eTextLine,
Color aColor,
bool bIsAbove )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight;
long nLinePos;
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
}
if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
nLineHeight = 3;
long nLineWidth = (mnDPIX/300);
if ( !nLineWidth )
nLineWidth = 1;
if ( eTextLine == UNDERLINE_BOLDWAVE )
nLineWidth *= 2;
nLinePos += nDistY - (nLineHeight / 2);
long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
if ( eTextLine == UNDERLINE_DOUBLEWAVE )
{
long nOrgLineHeight = nLineHeight;
nLineHeight /= 3;
if ( nLineHeight < 2 )
{
if ( nOrgLineHeight > 1 )
nLineHeight = 2;
else
nLineHeight = 1;
}
long nLineDY = nOrgLineHeight-(nLineHeight*2);
if ( nLineDY < nLineWidthHeight )
nLineDY = nLineWidthHeight;
long nLineDY2 = nLineDY/2;
if ( !nLineDY2 )
nLineDY2 = 1;
nLinePos -= nLineWidthHeight-nLineDY2;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
nLinePos += nLineWidthHeight+nLineDY;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
}
else
{
nLinePos -= nLineWidthHeight/2;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
}
}
void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontUnderline eTextLine,
Color aColor,
bool bIsAbove )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight = 0;
long nLinePos = 0;
long nLinePos2 = 0;
const long nY = nDistY;
if ( eTextLine > UNDERLINE_LAST )
eTextLine = UNDERLINE_SINGLE;
switch ( eTextLine )
{
case UNDERLINE_SINGLE:
case UNDERLINE_DOTTED:
case UNDERLINE_DASH:
case UNDERLINE_LONGDASH:
case UNDERLINE_DASHDOT:
case UNDERLINE_DASHDOTDOT:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
}
break;
case UNDERLINE_BOLD:
case UNDERLINE_BOLDDOTTED:
case UNDERLINE_BOLDDASH:
case UNDERLINE_BOLDLONGDASH:
case UNDERLINE_BOLDDASHDOT:
case UNDERLINE_BOLDDASHDOTDOT:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
}
break;
case UNDERLINE_DOUBLE:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
}
else
{
nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
}
break;
default:
break;
}
if ( nLineHeight )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
mbInitFillColor = true;
long nLeft = nDistX;
switch ( eTextLine )
{
case UNDERLINE_SINGLE:
case UNDERLINE_BOLD:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
break;
case UNDERLINE_DOUBLE:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
break;
case UNDERLINE_DOTTED:
case UNDERLINE_BOLDDOTTED:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nTempWidth = nDotWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDotWidth*2;
}
}
break;
case UNDERLINE_DASH:
case UNDERLINE_LONGDASH:
case UNDERLINE_BOLDDASH:
case UNDERLINE_BOLDLONGDASH:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nMinDashWidth;
long nMinSpaceWidth;
long nSpaceWidth;
long nDashWidth;
if ( (eTextLine == UNDERLINE_LONGDASH) ||
(eTextLine == UNDERLINE_BOLDLONGDASH) )
{
nMinDashWidth = nDotWidth*6;
nMinSpaceWidth = nDotWidth*2;
nDashWidth = 200;
nSpaceWidth = 100;
}
else
{
nMinDashWidth = nDotWidth*4;
nMinSpaceWidth = (nDotWidth*150)/100;
nDashWidth = 100;
nSpaceWidth = 50;
}
nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
if ( nSpaceWidth < nMinSpaceWidth )
nSpaceWidth = nMinSpaceWidth;
long nTempWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDashWidth+nSpaceWidth;
}
}
break;
case UNDERLINE_DASHDOT:
case UNDERLINE_BOLDDASHDOT:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
break;
case UNDERLINE_DASHDOTDOT:
case UNDERLINE_BOLDDASHDOTDOT:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
break;
default:
break;
}
}
}
void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontStrikeout eStrikeout,
Color aColor )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight = 0;
long nLinePos = 0;
long nLinePos2 = 0;
long nY = nDistY;
if ( eStrikeout > STRIKEOUT_LAST )
eStrikeout = STRIKEOUT_SINGLE;
switch ( eStrikeout )
{
case STRIKEOUT_SINGLE:
nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
break;
case STRIKEOUT_BOLD:
nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
break;
case STRIKEOUT_DOUBLE:
nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
break;
default:
break;
}
if ( nLineHeight )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
mbInitFillColor = true;
const long& nLeft = nDistX;
switch ( eStrikeout )
{
case STRIKEOUT_SINGLE:
case STRIKEOUT_BOLD:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
break;
case STRIKEOUT_DOUBLE:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
break;
default:
break;
}
}
}
void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontStrikeout eStrikeout,
Color aColor )
{
// See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
// to tweak this
if (!nWidth)
return;
// prepare string for strikeout measurement
static char cStrikeoutChar;
if ( eStrikeout == STRIKEOUT_SLASH )
cStrikeoutChar = '/';
else // ( eStrikeout == STRIKEOUT_X )
cStrikeoutChar = 'X';
static const int nTestStrLen = 4;
static const int nMaxStrikeStrLen = 2048;
sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
for( int i = 0; i < nTestStrLen; ++i)
aChars[i] = cStrikeoutChar;
const OUString aStrikeoutTest(aChars, nTestStrLen);
// calculate approximation of strikeout atom size
long nStrikeoutWidth = 0;
SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
if( pLayout )
{
nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
pLayout->Release();
}
if( nStrikeoutWidth <= 0 ) // sanity check
return;
int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
if( nStrikeStrLen > nMaxStrikeStrLen )
nStrikeStrLen = nMaxStrikeStrLen;
// build the strikeout string
for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
aChars[i] = cStrikeoutChar;
const OUString aStrikeoutText(aChars, nStrikeStrLen);
if( mpFontEntry->mnOrientation )
ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
nBaseX += nDistX;
nBaseY += nDistY;
// strikeout text has to be left aligned
sal_uLong nOrigTLM = mnTextLayoutMode;
mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
pLayout = ImplLayout( aStrikeoutText, 0, aStrikeoutText.getLength() );
mnTextLayoutMode = nOrigTLM;
if( !pLayout )
return;
// draw the strikeout text
const Color aOldColor = GetTextColor();
SetTextColor( aColor );
ImplInitTextColor();
pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
Rectangle aPixelRect;
aPixelRect.Left() = nBaseX+mnTextOffX;
aPixelRect.Right() = aPixelRect.Left()+nWidth;
aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
if (mpFontEntry->mnOrientation)
{
Polygon aPoly( aPixelRect );
aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
aPixelRect = aPoly.GetBoundRect();
}
Push( PUSH_CLIPREGION );
IntersectClipRegion( PixelToLogic(aPixelRect) );
if( mbInitClipRegion )
ImplInitClipRegion();
pLayout->DrawText( *mpGraphics );
pLayout->Release();
Pop();
SetTextColor( aOldColor );
ImplInitTextColor();
}
void OutputDevice::ImplDrawTextLine( long nX, long nY,
long nDistX, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline,
FontUnderline eOverline,
bool bUnderlineAbove )
{
if ( !nWidth )
return;
Color aStrikeoutColor = GetTextColor();
Color aUnderlineColor = GetTextLineColor();
Color aOverlineColor = GetOverlineColor();
bool bStrikeoutDone = false;
bool bUnderlineDone = false;
bool bOverlineDone = false;
if ( IsRTLEnabled() )
{
// --- RTL --- mirror at basex
long nXAdd = nWidth - nDistX;
if( mpFontEntry->mnOrientation )
nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
nX += nXAdd - 1;
}
if ( !IsTextLineColor() )
aUnderlineColor = GetTextColor();
if ( !IsOverlineColor() )
aOverlineColor = GetTextColor();
if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
(eUnderline == UNDERLINE_WAVE) ||
(eUnderline == UNDERLINE_DOUBLEWAVE) ||
(eUnderline == UNDERLINE_BOLDWAVE) )
{
ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
bUnderlineDone = true;
}
if ( (eOverline == UNDERLINE_SMALLWAVE) ||
(eOverline == UNDERLINE_WAVE) ||
(eOverline == UNDERLINE_DOUBLEWAVE) ||
(eOverline == UNDERLINE_BOLDWAVE) )
{
ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
bOverlineDone = true;
}
if ( (eStrikeout == STRIKEOUT_SLASH) ||
(eStrikeout == STRIKEOUT_X) )
{
ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
bStrikeoutDone = true;
}
if ( !bUnderlineDone )
ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
if ( !bOverlineDone )
ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
if ( !bStrikeoutDone )
ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
}
void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bWordLine, bool bUnderlineAbove )
{
if( bWordLine )
{
// draw everything relative to the layout base point
const Point aStartPt = rSalLayout.DrawBase();
// calculate distance of each word from the base point
Point aPos;
sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
for( int nStart = 0;;)
{
// iterate through the layouted glyphs
sal_GlyphId aGlyphId;
if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
break;
// calculate the boundaries of each word
if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
{
if( !nWidth )
{
// get the distance to the base point (as projected to baseline)
nDist = aPos.X() - aStartPt.X();
if( mpFontEntry->mnOrientation )
{
const long nDY = aPos.Y() - aStartPt.Y();
const double fRad = mpFontEntry->mnOrientation * F_PI1800;
nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
}
}
// update the length of the textline
nWidth += nAdvance;
}
else if( nWidth > 0 )
{
// draw the textline for each word
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
nWidth = 0;
}
}
// draw textline for the last word
if( nWidth > 0 )
{
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
}
else
{
Point aStartPt = rSalLayout.GetDrawPosition();
int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
}
void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
{
long nBaseX = nX;
if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
{
// --- RTL ---
// add some strange offset
nX += 2;
// revert the hack that will be done later in ImplDrawTextLine
nX = nBaseX - nWidth - (nX - nBaseX - 1);
}
ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, false );
}
bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout ) bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
{ {
int nX = rSalLayout.DrawBase().X(); int nX = rSalLayout.DrawBase().X();
...@@ -1641,108 +889,6 @@ Color OutputDevice::GetTextFillColor() const ...@@ -1641,108 +889,6 @@ Color OutputDevice::GetTextFillColor() const
return maFont.GetFillColor(); return maFont.GetFillColor();
} }
void OutputDevice::SetTextLineColor()
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) );
maTextLineColor = Color( COL_TRANSPARENT );
if( mpAlphaVDev )
mpAlphaVDev->SetTextLineColor();
}
void OutputDevice::SetTextLineColor( const Color& rColor )
{
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
DRAWMODE_SETTINGSTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const sal_uInt8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
aColor = GetSettings().GetStyleSettings().GetFontColor();
if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
&& (aColor.GetColor() != COL_TRANSPARENT) )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) );
maTextLineColor = aColor;
if( mpAlphaVDev )
mpAlphaVDev->SetTextLineColor( COL_BLACK );
}
void OutputDevice::SetOverlineColor()
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) );
maOverlineColor = Color( COL_TRANSPARENT );
if( mpAlphaVDev )
mpAlphaVDev->SetOverlineColor();
}
void OutputDevice::SetOverlineColor( const Color& rColor )
{
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
DRAWMODE_SETTINGSTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const sal_uInt8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
aColor = GetSettings().GetStyleSettings().GetFontColor();
if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
&& (aColor.GetColor() != COL_TRANSPARENT) )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) );
maOverlineColor = aColor;
if( mpAlphaVDev )
mpAlphaVDev->SetOverlineColor( COL_BLACK );
}
void OutputDevice::SetTextAlign( TextAlign eAlign ) void OutputDevice::SetTextAlign( TextAlign eAlign )
{ {
...@@ -1759,119 +905,6 @@ void OutputDevice::SetTextAlign( TextAlign eAlign ) ...@@ -1759,119 +905,6 @@ void OutputDevice::SetTextAlign( TextAlign eAlign )
mpAlphaVDev->SetTextAlign( eAlign ); mpAlphaVDev->SetTextAlign( eAlign );
} }
void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline,
FontUnderline eOverline,
bool bUnderlineAbove )
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
return;
if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
return;
// we need a graphics
if( !mpGraphics && !ImplGetGraphics() )
return;
if( mbInitClipRegion )
ImplInitClipRegion();
if( mbOutputClipped )
return;
// initialize font if needed to get text offsets
// TODO: only needed for mnTextOff!=(0,0)
if( mbNewFont )
if( !ImplNewFont() )
return;
if( mbInitFont )
InitFont();
Point aPos = ImplLogicToDevicePixel( rPos );
nWidth = ImplLogicWidthToDevicePixel( nWidth );
aPos += Point( mnTextOffX, mnTextOffY );
ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
if( mpAlphaVDev )
mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos )
{
if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
return;
// we need a graphics
if( !mpGraphics )
if( !ImplGetGraphics() )
return;
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
if( mbNewFont )
if( !ImplNewFont() )
return;
Point aStartPt = ImplLogicToDevicePixel( rStartPos );
Point aEndPt = ImplLogicToDevicePixel( rEndPos );
long nStartX = aStartPt.X();
long nStartY = aStartPt.Y();
long nEndX = aEndPt.X();
long nEndY = aEndPt.Y();
short nOrientation = 0;
// when rotated
if ( (nStartY != nEndY) || (nStartX > nEndX) )
{
long nDX = nEndX - nStartX;
double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
nO /= F_PI1800;
nOrientation = (short)nO;
ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
}
long nWaveHeight;
nWaveHeight = 3;
nStartY++;
nEndY++;
if (mnDPIScaleFactor > 1)
{
nWaveHeight *= mnDPIScaleFactor;
nStartY += mnDPIScaleFactor - 1; // Shift down additional pixel(s) to create more visual separation.
// odd heights look better than even
if (mnDPIScaleFactor % 2 == 0)
{
nWaveHeight--;
}
}
// #109280# make sure the waveline does not exceed the descent to avoid paint problems
ImplFontEntry* pFontEntry = mpFontEntry;
if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
ImplDrawWaveLine(nStartX, nStartY, 0, 0,
nEndX-nStartX, nWaveHeight,
mnDPIScaleFactor, nOrientation, GetLineColor());
if( mpAlphaVDev )
mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos );
}
void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr, void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
sal_Int32 nIndex, sal_Int32 nLen, sal_Int32 nIndex, sal_Int32 nLen,
MetricVector* pVector, OUString* pDisplayText MetricVector* pVector, OUString* pDisplayText
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
*/
#include "i18nlangtag/mslangid.hxx"
#include "i18nlangtag/languagetag.hxx"
#include "rtl/tencinfo.h"
#include "rtl/logfile.hxx"
#include "tools/debug.hxx"
#include "tools/poly.hxx"
#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/polygon/b2dpolypolygon.hxx"
#include "basegfx/matrix/b2dhommatrix.hxx"
#include "vcl/metric.hxx"
#include "vcl/metaact.hxx"
#include "vcl/gdimtf.hxx"
#include "vcl/virdev.hxx"
#include "vcl/print.hxx"
#include "vcl/event.hxx"
#include "vcl/window.hxx"
#include "vcl/svapp.hxx"
#include "vcl/bmpacc.hxx"
#include "vcl/outdev.hxx"
#include "vcl/edit.hxx"
#include <vcl/settings.hxx>
// declare system types in sysdata.hxx
#include <svsys.h>
#include "vcl/sysdata.hxx"
#include "vcl/unohelp.hxx"
#include "vcl/controllayout.hxx"
#include "salgdi.hxx"
#include "sallayout.hxx"
#include "svdata.hxx"
#include "impfont.hxx"
#include "outdata.hxx"
#include "outfont.hxx"
#include "outdev.h"
#include "PhysicalFontCollection.hxx"
#include "PhysicalFontFace.hxx"
#include "PhysicalFontFamily.hxx"
#include "textlayout.hxx"
#include "svids.hrc"
#include "window.h"
#include "unotools/fontcvt.hxx"
#include "unotools/fontcfg.hxx"
#include "osl/file.h"
#include <config_graphite.h>
#if ENABLE_GRAPHITE
#include "graphite_features.hxx"
#endif
#include "../gdi/pdfwriter_impl.hxx"
#include "com/sun/star/beans/PropertyValues.hpp"
#include "com/sun/star/i18n/XBreakIterator.hpp"
#include "com/sun/star/i18n/WordType.hpp"
#include "com/sun/star/linguistic2/LinguServiceManager.hpp"
#include <comphelper/processfactory.hxx>
#include "sal/alloca.h"
#include <cmath>
#include <cstring>
#include <memory>
#include <algorithm>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::rtl;
using namespace ::vcl;
using namespace ::utl;
#define UNDERLINE_LAST UNDERLINE_BOLDWAVE
#define STRIKEOUT_LAST STRIKEOUT_X
bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
{
if ( !rFont.IsVertical() )
return false;
if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
|| (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
// the underline is right for Japanese only
return true;
return false;
}
void OutputDevice::ImplInitTextLineSize()
{
mpFontEntry->maMetric.ImplInitTextLineSize( this );
}
void OutputDevice::ImplInitAboveTextLineSize()
{
mpFontEntry->maMetric.ImplInitAboveTextLineSize();
}
static void ImplDrawWavePixel( long nOriginX, long nOriginY,
long nCurX, long nCurY,
short nOrientation,
SalGraphics* pGraphics,
OutputDevice* pOutDev,
bool bDrawPixAsRect,
long nPixWidth, long nPixHeight )
{
if ( nOrientation )
ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
if ( bDrawPixAsRect )
{
pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
}
else
{
pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
}
}
void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
long nDistX, long nDistY,
long nWidth, long nHeight,
long nLineWidth, short nOrientation,
const Color& rColor )
{
if ( !nHeight )
return;
long nStartX = nBaseX + nDistX;
long nStartY = nBaseY + nDistY;
// If the height is 1 pixel, it's enough ouput a line
if ( (nLineWidth == 1) && (nHeight == 1) )
{
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = true;
long nEndX = nStartX+nWidth;
long nEndY = nStartY;
if ( nOrientation )
{
ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
}
mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
}
else
{
long nCurX = nStartX;
long nCurY = nStartY;
long nDiffX = 2;
long nDiffY = nHeight-1;
long nCount = nWidth;
long nOffY = -1;
long nFreq;
long i;
long nPixWidth;
long nPixHeight;
bool bDrawPixAsRect;
// On printers that ouput pixel via DrawRect()
if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
mbInitFillColor = true;
bDrawPixAsRect = true;
nPixWidth = nLineWidth;
nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
}
else
{
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = true;
nPixWidth = 1;
nPixHeight = 1;
bDrawPixAsRect = false;
}
if ( !nDiffY )
{
while ( nWidth )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nWidth--;
}
}
else
{
nCurY += nDiffY;
nFreq = nCount / (nDiffX+nDiffY);
while ( nFreq-- )
{
for( i = nDiffY; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
nOffY = -nOffY;
}
nFreq = nCount % (nDiffX+nDiffY);
if ( nFreq )
{
for( i = nDiffY; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics, this,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
}
}
}
}
void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontUnderline eTextLine,
Color aColor,
bool bIsAbove )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight;
long nLinePos;
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
}
if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
nLineHeight = 3;
long nLineWidth = (mnDPIX/300);
if ( !nLineWidth )
nLineWidth = 1;
if ( eTextLine == UNDERLINE_BOLDWAVE )
nLineWidth *= 2;
nLinePos += nDistY - (nLineHeight / 2);
long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
if ( eTextLine == UNDERLINE_DOUBLEWAVE )
{
long nOrgLineHeight = nLineHeight;
nLineHeight /= 3;
if ( nLineHeight < 2 )
{
if ( nOrgLineHeight > 1 )
nLineHeight = 2;
else
nLineHeight = 1;
}
long nLineDY = nOrgLineHeight-(nLineHeight*2);
if ( nLineDY < nLineWidthHeight )
nLineDY = nLineWidthHeight;
long nLineDY2 = nLineDY/2;
if ( !nLineDY2 )
nLineDY2 = 1;
nLinePos -= nLineWidthHeight-nLineDY2;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
nLinePos += nLineWidthHeight+nLineDY;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
}
else
{
nLinePos -= nLineWidthHeight/2;
ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aColor );
}
}
void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontUnderline eTextLine,
Color aColor,
bool bIsAbove )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight = 0;
long nLinePos = 0;
long nLinePos2 = 0;
const long nY = nDistY;
if ( eTextLine > UNDERLINE_LAST )
eTextLine = UNDERLINE_SINGLE;
switch ( eTextLine )
{
case UNDERLINE_SINGLE:
case UNDERLINE_DOTTED:
case UNDERLINE_DASH:
case UNDERLINE_LONGDASH:
case UNDERLINE_DASHDOT:
case UNDERLINE_DASHDOTDOT:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
}
break;
case UNDERLINE_BOLD:
case UNDERLINE_BOLDDOTTED:
case UNDERLINE_BOLDDASH:
case UNDERLINE_BOLDLONGDASH:
case UNDERLINE_BOLDDASHDOT:
case UNDERLINE_BOLDDASHDOTDOT:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
}
else
{
nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
}
break;
case UNDERLINE_DOUBLE:
if ( bIsAbove )
{
nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
}
else
{
nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
}
break;
default:
break;
}
if ( nLineHeight )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
mbInitFillColor = true;
long nLeft = nDistX;
switch ( eTextLine )
{
case UNDERLINE_SINGLE:
case UNDERLINE_BOLD:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
break;
case UNDERLINE_DOUBLE:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
break;
case UNDERLINE_DOTTED:
case UNDERLINE_BOLDDOTTED:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nTempWidth = nDotWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDotWidth*2;
}
}
break;
case UNDERLINE_DASH:
case UNDERLINE_LONGDASH:
case UNDERLINE_BOLDDASH:
case UNDERLINE_BOLDLONGDASH:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nMinDashWidth;
long nMinSpaceWidth;
long nSpaceWidth;
long nDashWidth;
if ( (eTextLine == UNDERLINE_LONGDASH) ||
(eTextLine == UNDERLINE_BOLDLONGDASH) )
{
nMinDashWidth = nDotWidth*6;
nMinSpaceWidth = nDotWidth*2;
nDashWidth = 200;
nSpaceWidth = 100;
}
else
{
nMinDashWidth = nDotWidth*4;
nMinSpaceWidth = (nDotWidth*150)/100;
nDashWidth = 100;
nSpaceWidth = 50;
}
nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
if ( nSpaceWidth < nMinSpaceWidth )
nSpaceWidth = nMinSpaceWidth;
long nTempWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDashWidth+nSpaceWidth;
}
}
break;
case UNDERLINE_DASHDOT:
case UNDERLINE_BOLDDASHDOT:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
break;
case UNDERLINE_DASHDOTDOT:
case UNDERLINE_BOLDDASHDOTDOT:
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth will be increased if the line is getting too thick
// in proportion to the line's length
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
break;
default:
break;
}
}
}
void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontStrikeout eStrikeout,
Color aColor )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight = 0;
long nLinePos = 0;
long nLinePos2 = 0;
long nY = nDistY;
if ( eStrikeout > STRIKEOUT_LAST )
eStrikeout = STRIKEOUT_SINGLE;
switch ( eStrikeout )
{
case STRIKEOUT_SINGLE:
nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
break;
case STRIKEOUT_BOLD:
nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
break;
case STRIKEOUT_DOUBLE:
nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
break;
default:
break;
}
if ( nLineHeight )
{
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = true;
}
mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
mbInitFillColor = true;
const long& nLeft = nDistX;
switch ( eStrikeout )
{
case STRIKEOUT_SINGLE:
case STRIKEOUT_BOLD:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
break;
case STRIKEOUT_DOUBLE:
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
break;
default:
break;
}
}
}
void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
long nDistX, long nDistY, long nWidth,
FontStrikeout eStrikeout,
Color aColor )
{
// See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
// to tweak this
if (!nWidth)
return;
// prepare string for strikeout measurement
static char cStrikeoutChar;
if ( eStrikeout == STRIKEOUT_SLASH )
cStrikeoutChar = '/';
else // ( eStrikeout == STRIKEOUT_X )
cStrikeoutChar = 'X';
static const int nTestStrLen = 4;
static const int nMaxStrikeStrLen = 2048;
sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
for( int i = 0; i < nTestStrLen; ++i)
aChars[i] = cStrikeoutChar;
const OUString aStrikeoutTest(aChars, nTestStrLen);
// calculate approximation of strikeout atom size
long nStrikeoutWidth = 0;
SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
if( pLayout )
{
nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
pLayout->Release();
}
if( nStrikeoutWidth <= 0 ) // sanity check
return;
int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
if( nStrikeStrLen > nMaxStrikeStrLen )
nStrikeStrLen = nMaxStrikeStrLen;
// build the strikeout string
for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
aChars[i] = cStrikeoutChar;
const OUString aStrikeoutText(aChars, nStrikeStrLen);
if( mpFontEntry->mnOrientation )
ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
nBaseX += nDistX;
nBaseY += nDistY;
// strikeout text has to be left aligned
sal_uLong nOrigTLM = mnTextLayoutMode;
mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
pLayout = ImplLayout( aStrikeoutText, 0, aStrikeoutText.getLength() );
mnTextLayoutMode = nOrigTLM;
if( !pLayout )
return;
// draw the strikeout text
const Color aOldColor = GetTextColor();
SetTextColor( aColor );
ImplInitTextColor();
pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
Rectangle aPixelRect;
aPixelRect.Left() = nBaseX+mnTextOffX;
aPixelRect.Right() = aPixelRect.Left()+nWidth;
aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
if (mpFontEntry->mnOrientation)
{
Polygon aPoly( aPixelRect );
aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
aPixelRect = aPoly.GetBoundRect();
}
Push( PUSH_CLIPREGION );
IntersectClipRegion( PixelToLogic(aPixelRect) );
if( mbInitClipRegion )
ImplInitClipRegion();
pLayout->DrawText( *mpGraphics );
pLayout->Release();
Pop();
SetTextColor( aOldColor );
ImplInitTextColor();
}
void OutputDevice::ImplDrawTextLine( long nX, long nY,
long nDistX, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline,
FontUnderline eOverline,
bool bUnderlineAbove )
{
if ( !nWidth )
return;
Color aStrikeoutColor = GetTextColor();
Color aUnderlineColor = GetTextLineColor();
Color aOverlineColor = GetOverlineColor();
bool bStrikeoutDone = false;
bool bUnderlineDone = false;
bool bOverlineDone = false;
if ( IsRTLEnabled() )
{
// --- RTL --- mirror at basex
long nXAdd = nWidth - nDistX;
if( mpFontEntry->mnOrientation )
nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
nX += nXAdd - 1;
}
if ( !IsTextLineColor() )
aUnderlineColor = GetTextColor();
if ( !IsOverlineColor() )
aOverlineColor = GetTextColor();
if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
(eUnderline == UNDERLINE_WAVE) ||
(eUnderline == UNDERLINE_DOUBLEWAVE) ||
(eUnderline == UNDERLINE_BOLDWAVE) )
{
ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
bUnderlineDone = true;
}
if ( (eOverline == UNDERLINE_SMALLWAVE) ||
(eOverline == UNDERLINE_WAVE) ||
(eOverline == UNDERLINE_DOUBLEWAVE) ||
(eOverline == UNDERLINE_BOLDWAVE) )
{
ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
bOverlineDone = true;
}
if ( (eStrikeout == STRIKEOUT_SLASH) ||
(eStrikeout == STRIKEOUT_X) )
{
ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
bStrikeoutDone = true;
}
if ( !bUnderlineDone )
ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
if ( !bOverlineDone )
ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
if ( !bStrikeoutDone )
ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
}
void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bWordLine, bool bUnderlineAbove )
{
if( bWordLine )
{
// draw everything relative to the layout base point
const Point aStartPt = rSalLayout.DrawBase();
// calculate distance of each word from the base point
Point aPos;
sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
for( int nStart = 0;;)
{
// iterate through the layouted glyphs
sal_GlyphId aGlyphId;
if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
break;
// calculate the boundaries of each word
if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
{
if( !nWidth )
{
// get the distance to the base point (as projected to baseline)
nDist = aPos.X() - aStartPt.X();
if( mpFontEntry->mnOrientation )
{
const long nDY = aPos.Y() - aStartPt.Y();
const double fRad = mpFontEntry->mnOrientation * F_PI1800;
nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
}
}
// update the length of the textline
nWidth += nAdvance;
}
else if( nWidth > 0 )
{
// draw the textline for each word
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
nWidth = 0;
}
}
// draw textline for the last word
if( nWidth > 0 )
{
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
}
else
{
Point aStartPt = rSalLayout.GetDrawPosition();
int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
}
void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
{
long nBaseX = nX;
if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
{
// --- RTL ---
// add some strange offset
nX += 2;
// revert the hack that will be done later in ImplDrawTextLine
nX = nBaseX - nWidth - (nX - nBaseX - 1);
}
ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, false );
}
void OutputDevice::SetTextLineColor()
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) );
maTextLineColor = Color( COL_TRANSPARENT );
if( mpAlphaVDev )
mpAlphaVDev->SetTextLineColor();
}
void OutputDevice::SetTextLineColor( const Color& rColor )
{
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
DRAWMODE_SETTINGSTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const sal_uInt8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
aColor = GetSettings().GetStyleSettings().GetFontColor();
if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
&& (aColor.GetColor() != COL_TRANSPARENT) )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) );
maTextLineColor = aColor;
if( mpAlphaVDev )
mpAlphaVDev->SetTextLineColor( COL_BLACK );
}
void OutputDevice::SetOverlineColor()
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) );
maOverlineColor = Color( COL_TRANSPARENT );
if( mpAlphaVDev )
mpAlphaVDev->SetOverlineColor();
}
void OutputDevice::SetOverlineColor( const Color& rColor )
{
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
DRAWMODE_SETTINGSTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const sal_uInt8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
aColor = GetSettings().GetStyleSettings().GetFontColor();
if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
&& (aColor.GetColor() != COL_TRANSPARENT) )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) );
maOverlineColor = aColor;
if( mpAlphaVDev )
mpAlphaVDev->SetOverlineColor( COL_BLACK );
}
void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline,
FontUnderline eOverline,
bool bUnderlineAbove )
{
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
return;
if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
return;
// we need a graphics
if( !mpGraphics && !ImplGetGraphics() )
return;
if( mbInitClipRegion )
ImplInitClipRegion();
if( mbOutputClipped )
return;
// initialize font if needed to get text offsets
// TODO: only needed for mnTextOff!=(0,0)
if( mbNewFont )
if( !ImplNewFont() )
return;
if( mbInitFont )
InitFont();
Point aPos = ImplLogicToDevicePixel( rPos );
nWidth = ImplLogicWidthToDevicePixel( nWidth );
aPos += Point( mnTextOffX, mnTextOffY );
ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
if( mpAlphaVDev )
mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
}
void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos )
{
if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
return;
// we need a graphics
if( !mpGraphics )
if( !ImplGetGraphics() )
return;
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
if( mbNewFont )
if( !ImplNewFont() )
return;
Point aStartPt = ImplLogicToDevicePixel( rStartPos );
Point aEndPt = ImplLogicToDevicePixel( rEndPos );
long nStartX = aStartPt.X();
long nStartY = aStartPt.Y();
long nEndX = aEndPt.X();
long nEndY = aEndPt.Y();
short nOrientation = 0;
// when rotated
if ( (nStartY != nEndY) || (nStartX > nEndX) )
{
long nDX = nEndX - nStartX;
double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
nO /= F_PI1800;
nOrientation = (short)nO;
ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
}
long nWaveHeight;
nWaveHeight = 3;
nStartY++;
nEndY++;
if (mnDPIScaleFactor > 1)
{
nWaveHeight *= mnDPIScaleFactor;
nStartY += mnDPIScaleFactor - 1; // Shift down additional pixel(s) to create more visual separation.
// odd heights look better than even
if (mnDPIScaleFactor % 2 == 0)
{
nWaveHeight--;
}
}
// #109280# make sure the waveline does not exceed the descent to avoid paint problems
ImplFontEntry* pFontEntry = mpFontEntry;
if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
ImplDrawWaveLine(nStartX, nStartY, 0, 0,
nEndX-nStartX, nWaveHeight,
mnDPIScaleFactor, nOrientation, GetLineColor());
if( mpAlphaVDev )
mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment