diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-20 13:10:09 +1000 |
---|---|---|
committer | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-20 13:10:09 +1000 |
commit | ffce13a5e48e193463be65b569af2e4f22d17926 (patch) | |
tree | dd65b29f0d61b6f37d54c9ef62c42beccd61eb4d /vcl | |
parent | 588bb542bebdee5a67bd4695253c70646fb8a303 (diff) |
Move VCL text line functions from text.cxx to textline.cxx
Change-Id: I3adea9cd08c86f676e6af525e5a7caf430c96d8d
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/Library_vcl.mk | 1 | ||||
-rw-r--r-- | vcl/source/outdev/text.cxx | 967 | ||||
-rw-r--r-- | vcl/source/outdev/textline.cxx | 1068 |
3 files changed, 1069 insertions, 967 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 72285c5811c3..989bf8e1069e 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -243,6 +243,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/outdev/bitmap \ vcl/source/outdev/font \ vcl/source/outdev/text \ + vcl/source/outdev/textline \ vcl/source/outdev/pixel \ vcl/source/outdev/rect \ vcl/source/outdev/line \ diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index 7063c32075b1..485033999ef3 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -135,19 +135,6 @@ void ImplMultiTextLineInfo::Clear() 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() { DBG_TESTSOLARMUTEX(); @@ -273,745 +260,6 @@ Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout ) 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 ) { int nX = rSalLayout.DrawBase().X(); @@ -1641,108 +889,6 @@ Color OutputDevice::GetTextFillColor() const 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 ) { @@ -1759,119 +905,6 @@ void OutputDevice::SetTextAlign( TextAlign 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, sal_Int32 nIndex, sal_Int32 nLen, MetricVector* pVector, OUString* pDisplayText diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx new file mode 100644 index 000000000000..7257eb087de0 --- /dev/null +++ b/vcl/source/outdev/textline.cxx @@ -0,0 +1,1068 @@ +/* -*- 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: */ |