summaryrefslogtreecommitdiff
path: root/vcl/source/gdi
diff options
context:
space:
mode:
authorVladimir Glazunov <vg@openoffice.org>2009-11-25 13:27:22 +0100
committerVladimir Glazunov <vg@openoffice.org>2009-11-25 13:27:22 +0100
commitb31166829b6c56b963e6ca58cd1af8c746e8ab6a (patch)
treee1388c4167ffd7aa349415ead49a37f5590afac1 /vcl/source/gdi
parent6bdea9f670a5bcc270324013995c00390f146588 (diff)
parent53c9c396125833bbfce4aa376637b96239826cc7 (diff)
CWS-TOOLING: integrate CWS controltextrendering
Notes
Notes: split repo tag: libs-gui_ooo/DEV300_m66
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r--vcl/source/gdi/makefile.mk82
-rw-r--r--vcl/source/gdi/outdev3.cxx182
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx5
-rwxr-xr-xvcl/source/gdi/textlayout.cxx384
4 files changed, 518 insertions, 135 deletions
diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk
index a09ae92dcb5e..c77508ea159e 100644
--- a/vcl/source/gdi/makefile.mk
+++ b/vcl/source/gdi/makefile.mk
@@ -51,7 +51,34 @@ CDEFS+=-DENABLE_GRAPHITE
# --- Files --------------------------------------------------------
-SLOFILES= $(SLO)$/salmisc.obj \
+EXCEPTIONSFILES= $(SLO)$/salmisc.obj \
+ $(SLO)$/outdev.obj \
+ $(SLO)$/outdev3.obj \
+ $(SLO)$/gfxlink.obj \
+ $(SLO)$/print.obj \
+ $(SLO)$/print2.obj \
+ $(SLO)$/sallayout.obj \
+ $(SLO)$/image.obj \
+ $(SLO)$/impimage.obj \
+ $(SLO)$/impgraph.obj \
+ $(SLO)$/metric.obj \
+ $(SLO)$/pdfwriter_impl.obj \
+ $(SLO)$/pdffontcache.obj\
+ $(SLO)$/fontcfg.obj \
+ $(SLO)$/bmpconv.obj \
+ $(SLO)$/pdfextoutdevdata.obj \
+ $(SLO)$/fontcvt.obj \
+ $(SLO)$/jobset.obj \
+ $(SLO)$/impimagetree.obj \
+ $(SLO)$/pngread.obj \
+ $(SLO)$/pngwrite.obj \
+ $(SLO)$/virdev.obj \
+ $(SLO)$/impprn.obj \
+ $(SLO)$/gdimtf.obj \
+ $(SLO)$/graphictools.obj \
+ $(SLO)$/textlayout.obj
+
+SLOFILES= $(EXCEPTIONSFILES) \
$(SLO)$/animate.obj \
$(SLO)$/impanmvw.obj \
$(SLO)$/bitmap.obj \
@@ -68,81 +95,30 @@ SLOFILES= $(SLO)$/salmisc.obj \
$(SLO)$/cvtsvm.obj \
$(SLO)$/cvtgrf.obj \
$(SLO)$/font.obj \
- $(SLO)$/gdimtf.obj \
- $(SLO)$/gfxlink.obj \
$(SLO)$/gradient.obj \
$(SLO)$/hatch.obj \
$(SLO)$/graph.obj \
- $(SLO)$/image.obj \
- $(SLO)$/impimage.obj \
$(SLO)$/impbmp.obj \
- $(SLO)$/impgraph.obj \
- $(SLO)$/impimagetree.obj \
$(SLO)$/imagerepository.obj \
- $(SLO)$/impprn.obj \
$(SLO)$/impvect.obj \
$(SLO)$/implncvt.obj \
- $(SLO)$/jobset.obj \
$(SLO)$/lineinfo.obj \
$(SLO)$/mapmod.obj \
$(SLO)$/metaact.obj \
- $(SLO)$/metric.obj \
$(SLO)$/octree.obj \
$(SLO)$/outmap.obj \
- $(SLO)$/outdev.obj \
$(SLO)$/outdev2.obj \
- $(SLO)$/outdev3.obj \
$(SLO)$/outdev4.obj \
$(SLO)$/outdev5.obj \
$(SLO)$/outdev6.obj \
- $(SLO)$/virdev.obj \
- $(SLO)$/fontcvt.obj \
- $(SLO)$/print.obj \
- $(SLO)$/print2.obj \
$(SLO)$/regband.obj \
$(SLO)$/region.obj \
$(SLO)$/wall.obj \
- $(SLO)$/fontcfg.obj \
$(SLO)$/base14.obj \
$(SLO)$/pdfwriter.obj \
- $(SLO)$/pdfwriter_impl.obj \
- $(SLO)$/pdffontcache.obj\
- $(SLO)$/sallayout.obj \
$(SLO)$/salgdilayout.obj \
$(SLO)$/extoutdevdata.obj \
- $(SLO)$/pdfextoutdevdata.obj \
- $(SLO)$/salnativewidgets-none.obj \
- $(SLO)$/bmpconv.obj \
- $(SLO)$/pngread.obj \
- $(SLO)$/pngwrite.obj \
- $(SLO)$/graphictools.obj
-
-EXCEPTIONSFILES= $(SLO)$/salmisc.obj \
- $(SLO)$/outdev.obj \
- $(SLO)$/outdev3.obj \
- $(SLO)$/gfxlink.obj \
- $(SLO)$/print.obj \
- $(SLO)$/print2.obj \
- $(SLO)$/sallayout.obj \
- $(SLO)$/image.obj \
- $(SLO)$/impimage.obj \
- $(SLO)$/impgraph.obj \
- $(SLO)$/metric.obj \
- $(SLO)$/pdfwriter_impl.obj \
- $(SLO)$/pdffontcache.obj\
- $(SLO)$/fontcfg.obj \
- $(SLO)$/bmpconv.obj \
- $(SLO)$/pdfextoutdevdata.obj \
- $(SLO)$/fontcvt.obj \
- $(SLO)$/jobset.obj \
- $(SLO)$/impimagetree.obj \
- $(SLO)$/pngread.obj \
- $(SLO)$/pngwrite.obj \
- $(SLO)$/virdev.obj \
- $(SLO)$/impprn.obj \
- $(SLO)$/gdimtf.obj \
- $(SLO)$/graphictools.obj
-
+ $(SLO)$/salnativewidgets-none.obj
# --- Targets ------------------------------------------------------
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index 8a057b3f3c7b..b6e0e1b8d441 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -61,6 +61,7 @@
#include <vcl/edit.hxx>
#include <vcl/fontcfg.hxx>
#include <vcl/sysdata.hxx>
+#include <vcl/textlayout.hxx>
#ifndef _OSL_FILE_H
#include <osl/file.h>
#endif
@@ -5257,7 +5258,7 @@ void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
long nWidth, const XubString& rStr,
- USHORT nStyle ) const
+ USHORT nStyle, const ::vcl::ITextLayout& _rLayout )
{
DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
@@ -5295,7 +5296,7 @@ long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
nBreakPos++;
- long nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
{
if ( !xBI.is() )
@@ -5304,7 +5305,7 @@ long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
if ( xBI.is() )
{
const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILocale());
- xub_StrLen nSoftBreak = GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
+ xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
//aHyphOptions.hyphenIndex = nSoftBreak;
i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
@@ -5408,7 +5409,7 @@ long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
} // if ( xHyph.is() )
} // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
}
- nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
}
else
{
@@ -5422,14 +5423,14 @@ long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
{
if( nSpacePos > nPos )
nSpacePos--;
- nW = GetTextWidth( rStr, nPos, nSpacePos-nPos );
+ nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
}
} while( nW > nWidth );
if( nSpacePos != STRING_NOTFOUND )
{
nBreakPos = nSpacePos;
- nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
+ nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
if( nBreakPos < rStr.Len()-1 )
nBreakPos++;
}
@@ -6159,6 +6160,10 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
if ( !IsDeviceOutputNecessary() )
return;
+ if( mbInitClipRegion )
+ ImplInitClipRegion();
+ if( mbOutputClipped )
+ return;
SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
if( pSalLayout )
@@ -6771,9 +6776,10 @@ xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
// -----------------------------------------------------------------------
-void OutputDevice::ImplDrawText( const Rectangle& rRect,
+void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
const String& rOrigStr, USHORT nStyle,
- MetricVector* pVector, String* pDisplayText )
+ MetricVector* pVector, String* pDisplayText,
+ ::vcl::ITextLayout& _rLayout )
{
Color aOldTextColor;
Color aOldTextFillColor;
@@ -6782,12 +6788,12 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
{
BOOL bHighContrastBlack = FALSE;
BOOL bHighContrastWhite = FALSE;
- const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
+ const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
if( rStyleSettings.GetHighContrastMode() )
{
Color aCol;
- if( IsBackground() )
- aCol = GetBackground().GetColor();
+ if( rTargetDevice.IsBackground() )
+ aCol = rTargetDevice.GetBackground().GetColor();
else
// best guess is the face color here
// but it may be totally wrong. the background color
@@ -6798,16 +6804,16 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
bHighContrastWhite = aCol.IsBright();
}
- aOldTextColor = GetTextColor();
- if ( IsTextFillColor() )
+ aOldTextColor = rTargetDevice.GetTextColor();
+ if ( rTargetDevice.IsTextFillColor() )
{
bRestoreFillColor = TRUE;
- aOldTextFillColor = GetTextFillColor();
+ aOldTextFillColor = rTargetDevice.GetTextFillColor();
}
if( bHighContrastBlack )
- SetTextColor( COL_GREEN );
+ rTargetDevice.SetTextColor( COL_GREEN );
else if( bHighContrastWhite )
- SetTextColor( COL_LIGHTGREEN );
+ rTargetDevice.SetTextColor( COL_LIGHTGREEN );
else
{
// draw disabled text always without shadow
@@ -6818,7 +6824,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
aRect.Move( 1, 1 );
DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
*/
- SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
+ rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
}
}
@@ -6830,14 +6836,16 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
Point aPos = rRect.TopLeft();
- long nTextHeight = GetTextHeight();
- TextAlign eAlign = GetTextAlign();
+ long nTextHeight = rTargetDevice.GetTextHeight();
+ TextAlign eAlign = rTargetDevice.GetTextAlign();
xub_StrLen nMnemonicPos = STRING_NOTFOUND;
String aStr = rOrigStr;
if ( nStyle & TEXT_DRAW_MNEMONIC )
aStr = GetNonMnemonicString( aStr, nMnemonicPos );
+ const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
+
// Mehrzeiligen Text behandeln wir anders
if ( nStyle & TEXT_DRAW_MULTILINE )
{
@@ -6852,7 +6860,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
if ( nTextHeight )
{
- nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle );
+ nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
nLines = (xub_StrLen)(nHeight/nTextHeight);
nFormatLines = aMultiLineInfo.Count();
if ( !nLines )
@@ -6874,7 +6882,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
if ( aLastLine.GetChar( i ) == _LF )
aLastLine.SetChar( i, ' ' );
}
- aLastLine = GetEllipsisString( aLastLine, nWidth, nStyle );
+ aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
nStyle |= TEXT_DRAW_TOP;
}
@@ -6892,8 +6900,8 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
// Clipping setzen
if ( nStyle & TEXT_DRAW_CLIP )
{
- Push( PUSH_CLIPREGION );
- IntersectClipRegion( rRect );
+ rTargetDevice.Push( PUSH_CLIPREGION );
+ rTargetDevice.IntersectClipRegion( rRect );
}
// Vertikales Alignment
@@ -6906,7 +6914,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += nTextHeight;
else if ( eAlign == ALIGN_BASELINE )
- aPos.Y() += GetFontMetric().GetAscent();
+ aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
// Alle Zeilen ausgeben, bis auf die letzte
for ( i = 0; i < nFormatLines; i++ )
@@ -6918,8 +6926,8 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
xub_StrLen nIndex = pLineInfo->GetIndex();
xub_StrLen nLineLen = pLineInfo->GetLen();
- DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
- if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
+ _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
+ if ( bDrawMnemonics )
{
if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
{
@@ -6928,16 +6936,16 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
long nMnemonicWidth;
sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
- /*BOOL bRet =*/ GetCaretPositions( aStr, pCaretXArray,
- nIndex, nLineLen);
+ /*BOOL bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
+ nIndex, nLineLen );
long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
- nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
+ nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
- Point aTempPos = LogicToPixel( aPos );
- nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
- nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
- ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ Point aTempPos = rTargetDevice.LogicToPixel( aPos );
+ nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
+ nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
}
}
aPos.Y() += nTextHeight;
@@ -6948,26 +6956,26 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
// Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
// da die Zeile gekuerzt wurde
if ( aLastLine.Len() )
- DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
+ _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
// Clipping zuruecksetzen
if ( nStyle & TEXT_DRAW_CLIP )
- Pop();
+ rTargetDevice.Pop();
}
}
else
{
- long nTextWidth = GetTextWidth( aStr );
+ long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
// Evt. Text kuerzen
if ( nTextWidth > nWidth )
{
if ( nStyle & TEXT_DRAW_ELLIPSIS )
{
- aStr = GetEllipsisString( aStr, nWidth, nStyle );
+ aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
nStyle |= TEXT_DRAW_LEFT;
- nTextWidth = GetTextWidth( aStr );
+ nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
}
}
else
@@ -6986,7 +6994,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += nTextHeight;
else if ( eAlign == ALIGN_BASELINE )
- aPos.Y() += GetFontMetric().GetAscent();
+ aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
if ( nStyle & TEXT_DRAW_BOTTOM )
aPos.Y() += nHeight-nTextHeight;
@@ -6999,44 +7007,44 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect,
if ( nMnemonicPos != STRING_NOTFOUND )
{
sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
- /*BOOL bRet =*/ GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
+ /*BOOL bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
- nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
+ nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
- Point aTempPos = LogicToPixel( aPos );
- nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
- nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
+ Point aTempPos = rTargetDevice.LogicToPixel( aPos );
+ nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
+ nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
}
if ( nStyle & TEXT_DRAW_CLIP )
{
- Push( PUSH_CLIPREGION );
- IntersectClipRegion( rRect );
- DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
- if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
+ rTargetDevice.Push( PUSH_CLIPREGION );
+ rTargetDevice.IntersectClipRegion( rRect );
+ _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
+ if ( bDrawMnemonics )
{
if ( nMnemonicPos != STRING_NOTFOUND )
- ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
}
- Pop();
+ rTargetDevice.Pop();
}
else
{
- DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
- if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
+ _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
+ if ( bDrawMnemonics )
{
if ( nMnemonicPos != STRING_NOTFOUND )
- ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
+ rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
}
}
}
if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
{
- SetTextColor( aOldTextColor );
+ rTargetDevice.SetTextColor( aOldTextColor );
if ( bRestoreFillColor )
- SetTextFillColor( aOldTextFillColor );
+ rTargetDevice.SetTextFillColor( aOldTextFillColor );
}
}
@@ -7069,7 +7077,8 @@ void OutputDevice::AddTextRectActions( const Rectangle& rRect,
// #i47157# Factored out to ImplDrawTextRect(), to be shared
// between us and DrawText()
- ImplDrawText( rRect, rOrigStr, nStyle, NULL, NULL );
+ DefaultTextLayout aLayout( *this );
+ ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
// and restore again
EnableOutput( bOutputEnabled );
@@ -7078,10 +7087,9 @@ void OutputDevice::AddTextRectActions( const Rectangle& rRect,
// -----------------------------------------------------------------------
-void OutputDevice::DrawText( const Rectangle& rRect,
- const String& rOrigStr, USHORT nStyle,
- MetricVector* pVector, String* pDisplayText )
-
+void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle,
+ MetricVector* pVector, String* pDisplayText,
+ ::vcl::ITextLayout* _pTextLayout )
{
if( mpOutDevData && mpOutDevData->mpRecordLayout )
{
@@ -7092,10 +7100,11 @@ void OutputDevice::DrawText( const Rectangle& rRect,
DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
- if ( mpMetaFile )
+ bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
+ if ( mpMetaFile && !bDecomposeTextRectAction )
mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
- if ( ( !IsDeviceOutputNecessary() && ! pVector ) || !rOrigStr.Len() || rRect.IsEmpty() )
+ if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
return;
// we need a graphics
@@ -7103,17 +7112,19 @@ void OutputDevice::DrawText( const Rectangle& rRect,
return;
if( mbInitClipRegion )
ImplInitClipRegion();
- if( mbOutputClipped )
+ if( mbOutputClipped && !bDecomposeTextRectAction )
return;
// temporarily disable mtf action generation (ImplDrawText _does_
// create META_TEXT_ACTIONs otherwise)
GDIMetaFile* pMtf = mpMetaFile;
- mpMetaFile = NULL;
+ if ( !bDecomposeTextRectAction )
+ mpMetaFile = NULL;
- // #i47157# Factored out to ImplDrawTextRect(), to be used also
+ // #i47157# Factored out to ImplDrawText(), to be used also
// from AddTextRectActions()
- ImplDrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
+ DefaultTextLayout aDefaultLayout( *this );
+ ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
// and enable again
mpMetaFile = pMtf;
@@ -7125,8 +7136,9 @@ void OutputDevice::DrawText( const Rectangle& rRect,
// -----------------------------------------------------------------------
Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
- const String& rOrigStr, USHORT nStyle,
- TextRectInfo* pInfo ) const
+ const XubString& rStr, USHORT nStyle,
+ TextRectInfo* pInfo,
+ const ::vcl::ITextLayout* _pTextLayout ) const
{
DBG_TRACE( "OutputDevice::GetTextRect()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
@@ -7137,7 +7149,7 @@ Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
long nMaxWidth;
long nTextHeight = GetTextHeight();
- String aStr = rOrigStr;
+ String aStr = rStr;
if ( nStyle & TEXT_DRAW_MNEMONIC )
aStr = GetNonMnemonicString( aStr );
@@ -7149,7 +7161,8 @@ Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
xub_StrLen i;
nMaxWidth = 0;
- ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle );
+ DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
+ ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
nFormatLines = aMultiLineInfo.Count();
if ( !nTextHeight )
nTextHeight = 1;
@@ -7197,7 +7210,7 @@ Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
else
{
nLines = 1;
- nMaxWidth = GetTextWidth( aStr );
+ nMaxWidth = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
if ( pInfo )
{
@@ -7256,11 +7269,20 @@ static BOOL ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
USHORT nStyle ) const
{
- DBG_TRACE( "OutputDevice::GetEllipsisString()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+ DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
+ return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
+}
+
+// -----------------------------------------------------------------------
+
+String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
+ USHORT nStyle, const ::vcl::ITextLayout& _rLayout )
+{
+ DBG_TRACE( "OutputDevice::ImplGetEllipsisString()" );
String aStr = rOrigStr;
- xub_StrLen nIndex = GetTextBreak( aStr, nMaxWidth );
+ xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
if ( nIndex != STRING_LEN )
@@ -7271,7 +7293,7 @@ String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
if ( nIndex > 1 )
{
aStr.AppendAscii( "..." );
- while ( aStr.Len() && (GetTextWidth( aStr ) > nMaxWidth) )
+ while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
{
if ( (nIndex > 1) || (nIndex == aStr.Len()) )
nIndex--;
@@ -7307,8 +7329,8 @@ String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
XubString aLastStr( aStr, nLastContent, aStr.Len() );
XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
aTempLastStr1 += aLastStr;
- if ( GetTextWidth( aTempLastStr1 ) > nMaxWidth )
- aStr = GetEllipsisString( aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
+ if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
else
{
USHORT nFirstContent = 0;
@@ -7323,7 +7345,7 @@ String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
nFirstContent++;
if ( nFirstContent >= nLastContent )
- aStr = GetEllipsisString( aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
else
{
if ( nFirstContent > 4 )
@@ -7332,8 +7354,8 @@ String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
aFirstStr.AppendAscii( "..." );
XubString aTempStr = aFirstStr;
aTempStr += aLastStr;
- if ( GetTextWidth( aTempStr ) > nMaxWidth )
- aStr = GetEllipsisString( aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
+ if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
+ aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
else
{
do
@@ -7357,7 +7379,7 @@ String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
aTempStr = aFirstStr;
aTempStr += aTempLastStr;
- if ( GetTextWidth( aTempStr ) > nMaxWidth )
+ if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
break;
}
}
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index dc3ead5d2d6f..d4fc6fa27117 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -41,7 +41,6 @@
#include <tools/debug.hxx>
#include <tools/zcodec.hxx>
#include <tools/stream.hxx>
-#include <tools/urlobj.hxx> //for relative url
#include <i18npool/mslangid.hxx>
#include <vcl/virdev.hxx>
#include <vcl/bmpacc.hxx>
@@ -51,6 +50,7 @@
#include <vcl/sallayout.hxx>
#include <vcl/metric.hxx>
#include <vcl/fontsubset.hxx>
+#include <vcl/textlayout.hxx>
#include <svsys.h>
#include <vcl/salgdi.hxx>
#include <vcl/svapp.hxx>
@@ -7310,7 +7310,8 @@ void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, US
if ( nTextHeight )
{
- nMaxTextWidth = m_pReferenceDevice->ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle );
+ ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
+ nMaxTextWidth = OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
nLines = (xub_StrLen)(nHeight/nTextHeight);
nFormatLines = aMultiLineInfo.Count();
if ( !nLines )
diff --git a/vcl/source/gdi/textlayout.cxx b/vcl/source/gdi/textlayout.cxx
new file mode 100755
index 000000000000..67a30c351b7a
--- /dev/null
+++ b/vcl/source/gdi/textlayout.cxx
@@ -0,0 +1,384 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* OpenOffice.org - a multi-platform office productivity suite
+*
+* This file is part of OpenOffice.org.
+*
+* OpenOffice.org is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License version 3
+* only, as published by the Free Software Foundation.
+*
+* OpenOffice.org is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License version 3 for more details
+* (a copy is included in the LICENSE file that accompanied this code).
+*
+* You should have received a copy of the GNU Lesser General Public License
+* version 3 along with OpenOffice.org. If not, see
+* <http://www.openoffice.org/license.html>
+* for a copy of the LGPLv3 License.
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/ctrl.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/textlayout.hxx"
+
+#include <com/sun/star/i18n/ScriptDirection.hpp>
+
+#include <tools/diagnose_ex.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <rtl/strbuf.hxx>
+#endif
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Exception;
+ namespace ScriptDirection = ::com::sun::star::i18n::ScriptDirection;
+
+ //====================================================================
+ //= DefaultTextLayout
+ //====================================================================
+ //--------------------------------------------------------------------
+ DefaultTextLayout::~DefaultTextLayout()
+ {
+ }
+
+ //--------------------------------------------------------------------
+ long DefaultTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetTextWidth( _rText, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ void DefaultTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex,
+ xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
+ {
+ m_rTargetDevice.DrawText( _rStartPoint, _rText, _nStartIndex, _nLength, _pVector, _pDisplayText );
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
+ xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ xub_StrLen DefaultTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return m_rTargetDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultTextLayout::DecomposeTextRectAction() const
+ {
+ return false;
+ }
+
+ //====================================================================
+ //= ReferenceDeviceTextLayout
+ //====================================================================
+ class ReferenceDeviceTextLayout : public ITextLayout
+ {
+ public:
+ ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice );
+ virtual ~ReferenceDeviceTextLayout();
+
+ // ITextLayout
+ virtual long GetTextWidth( const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const;
+ virtual void DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText );
+ virtual bool GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ virtual xub_StrLen GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ virtual bool DecomposeTextRectAction() const;
+
+ public:
+ // equivalents to the respective OutputDevice methods, which take the reference device into account
+ long GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
+ Rectangle DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText );
+
+ protected:
+ void onBeginDrawText()
+ {
+ m_aCompleteTextRect.SetEmpty();
+ }
+ Rectangle onEndDrawText()
+ {
+ return m_aCompleteTextRect;
+ }
+
+ private:
+ OutputDevice& m_rTargetDevice;
+ OutputDevice& m_rReferenceDevice;
+ Font m_aUnzoomedPointFont;
+ const Fraction m_aZoom;
+ const bool m_bRTLEnabled;
+
+ Rectangle m_aCompleteTextRect;
+ };
+
+ //====================================================================
+ //= ControlTextRenderer
+ //====================================================================
+ ReferenceDeviceTextLayout::ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice,
+ OutputDevice& _rReferenceDevice )
+ :m_rTargetDevice( _rTargetDevice )
+ ,m_rReferenceDevice( _rReferenceDevice )
+ ,m_aUnzoomedPointFont( _rControl.GetUnzoomedControlPointFont() )
+ ,m_aZoom( _rControl.GetZoom() )
+ ,m_bRTLEnabled( _rControl.IsRTLEnabled() )
+ {
+ m_rTargetDevice.Push( PUSH_MAPMODE | PUSH_FONT | PUSH_TEXTLAYOUTMODE );
+
+ MapMode aTargetMapMode( m_rTargetDevice.GetMapMode() );
+ OSL_ENSURE( aTargetMapMode.GetOrigin() == Point(), "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: uhm, the code below won't work here ..." );
+
+ // normally, controls simulate "zoom" by "zooming" the font. This is responsible for (part of) the discrepancies
+ // between text in Writer and text in controls in Writer, though both have the same font.
+ // So, if we have a zoom set at the control, then we do not scale the font, but instead modify the map mode
+ // to accomodate for the zoom.
+ aTargetMapMode.SetScaleX( m_aZoom ); // TODO: shouldn't this be "current_scale * zoom"?
+ aTargetMapMode.SetScaleY( m_aZoom );
+
+ // also, use a higher-resolution map unit than "pixels", which should save us some rounding errors when
+ // translating coordinates between the reference device and the target device.
+ OSL_ENSURE( aTargetMapMode.GetMapUnit() == MAP_PIXEL,
+ "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: this class is not expected to work with such target devices!" );
+ // we *could* adjust all the code in this class to handle this case, but at the moment, it's not necessary
+ const MapUnit eTargetMapUnit = m_rReferenceDevice.GetMapMode().GetMapUnit();
+ aTargetMapMode.SetMapUnit( eTargetMapUnit );
+ OSL_ENSURE( aTargetMapMode.GetMapUnit() != MAP_PIXEL,
+ "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: a reference device which has map mode PIXEL?!" );
+
+ m_rTargetDevice.SetMapMode( aTargetMapMode );
+
+ // now that the Zoom is part of the map mode, reset the target device's font to the "unzoomed" version
+ Font aDrawFont( m_aUnzoomedPointFont );
+ aDrawFont.SetSize( m_rTargetDevice.LogicToLogic( aDrawFont.GetSize(), MAP_POINT, eTargetMapUnit ) );
+ _rTargetDevice.SetFont( aDrawFont );
+
+ // transfer font to the reference device
+ m_rReferenceDevice.Push( PUSH_FONT | PUSH_TEXTLAYOUTMODE );
+ Font aRefFont( m_aUnzoomedPointFont );
+ aRefFont.SetSize( OutputDevice::LogicToLogic(
+ aRefFont.GetSize(), MAP_POINT, m_rReferenceDevice.GetMapMode().GetMapUnit() ) );
+ m_rReferenceDevice.SetFont( aRefFont );
+ }
+
+ //--------------------------------------------------------------------
+ ReferenceDeviceTextLayout::~ReferenceDeviceTextLayout()
+ {
+ m_rReferenceDevice.Pop();
+ m_rTargetDevice.Pop();
+ }
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ //................................................................
+ bool lcl_normalizeLength( const XubString& _rText, const xub_StrLen _nStartIndex, xub_StrLen& _io_nLength )
+ {
+ xub_StrLen nTextLength = _rText.Len();
+ if ( _nStartIndex > nTextLength )
+ return false;
+ if ( _nStartIndex + _io_nLength > nTextLength )
+ _io_nLength = nTextLength - _nStartIndex;
+ return true;
+ }
+ }
+
+ //--------------------------------------------------------------------
+ long ReferenceDeviceTextLayout::GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex,
+ xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return 0;
+
+ // retrieve the character widths from the reference device
+ long nTextWidth = m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength );
+#if OSL_DEBUG_LEVEL > 1
+ if ( _pDXAry )
+ {
+ ::rtl::OStringBuffer aTrace;
+ aTrace.append( "ReferenceDeviceTextLayout::GetTextArray( " );
+ aTrace.append( ::rtl::OUStringToOString( _rText, RTL_TEXTENCODING_UTF8 ) );
+ aTrace.append( " ): " );
+ aTrace.append( nTextWidth );
+ aTrace.append( " = ( " );
+ for ( size_t i=0; i<_nLength; )
+ {
+ aTrace.append( _pDXAry[i] );
+ if ( ++i < _nLength )
+ aTrace.append( ", " );
+ }
+ aTrace.append( ")" );
+ OSL_TRACE( aTrace.makeStringAndClear().getStr() );
+ }
+#endif
+ return nTextWidth;
+ }
+
+ //--------------------------------------------------------------------
+ long ReferenceDeviceTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ return GetTextArray( _rText, NULL, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ void ReferenceDeviceTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return;
+
+ if ( _pVector && _pDisplayText )
+ {
+ MetricVector aGlyphBounds;
+ m_rReferenceDevice.GetGlyphBoundRects( _rStartPoint, _rText, _nStartIndex, _nLength, _nStartIndex, aGlyphBounds );
+ ::std::copy(
+ aGlyphBounds.begin(), aGlyphBounds.end(),
+ ::std::insert_iterator< MetricVector > ( *_pVector, _pVector->end() ) );
+ _pDisplayText->Append( _rText.Copy( _nStartIndex, _nLength ) );
+ return;
+ }
+
+ sal_Int32* pCharWidths = new sal_Int32[ _nLength ];
+ long nTextWidth = GetTextArray( _rText, pCharWidths, _nStartIndex, _nLength );
+ m_rTargetDevice.DrawTextArray( _rStartPoint, _rText, pCharWidths, _nStartIndex, _nLength );
+ delete[] pCharWidths;
+
+ m_aCompleteTextRect.Union( Rectangle( _rStartPoint, Size( nTextWidth, m_rTargetDevice.GetTextHeight() ) ) );
+ }
+
+ //--------------------------------------------------------------------
+ bool ReferenceDeviceTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
+ xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return false;
+
+ // retrieve the caret positions from the reference device
+ if ( !m_rReferenceDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength ) )
+ return false;
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ xub_StrLen ReferenceDeviceTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
+ {
+ if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
+ return 0;
+
+ return m_rReferenceDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
+ }
+
+ //--------------------------------------------------------------------
+ bool ReferenceDeviceTextLayout::DecomposeTextRectAction() const
+ {
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ long zoomBy( long _value, const Fraction& _zoom )
+ {
+ double n = (double)_value;
+ n *= (double)_zoom.GetNumerator();
+ n /= (double)_zoom.GetDenominator();
+ return (long)::rtl::math::round( n );
+ }
+ long unzoomBy( long _value, const Fraction& _zoom )
+ {
+ return zoomBy( _value, Fraction( _zoom.GetDenominator(), _zoom.GetNumerator() ) );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle ReferenceDeviceTextLayout::DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText )
+ {
+ if ( !_rText.Len() )
+ return Rectangle();
+
+ // determine text layout mode from the RTL-ness of the control whose text we render
+ ULONG nTextLayoutMode = m_bRTLEnabled ? TEXT_LAYOUT_BIDI_RTL : TEXT_LAYOUT_BIDI_LTR;
+ m_rReferenceDevice.SetLayoutMode( nTextLayoutMode );
+ m_rTargetDevice.SetLayoutMode( nTextLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
+ // TEXT_LAYOUT_TEXTORIGIN_LEFT is because when we do actually draw the text (in DrawText( Point, ... )), then
+ // our caller gives us the left border of the draw position, regardless of script type, text layout,
+ // and the like
+
+ // in our ctor, we set the map mode of the target device from pixel to twip, but our caller doesn't know this,
+ // but passed pixel coordinates. So, adjust the rect.
+ Rectangle aRect( m_rTargetDevice.PixelToLogic( _rRect ) );
+
+ onBeginDrawText();
+ m_rTargetDevice.DrawText( aRect, _rText, _nStyle, _pVector, _pDisplayText, this );
+ Rectangle aTextRect = onEndDrawText();
+
+ if ( aTextRect.IsEmpty() && !aRect.IsEmpty() )
+ {
+ // this happens for instance if we're in a PaintToDevice call, where only a MetaFile is recorded,
+ // but no actual painting happens, so our "DrawText( Point, ... )" is never called
+ // In this case, calculate the rect from what OutputDevice::GetTextRect would give us. This has
+ // the disadvantage of less accuracy, compared with the approach to calculate the rect from the
+ // single "DrawText( Point, ... )" calls, since more intermediate arithmetics will translate
+ // from ref- to target-units.
+ aTextRect = m_rTargetDevice.GetTextRect( aRect, _rText, _nStyle, NULL, this );
+ }
+
+ // similar to above, the text rect now contains TWIPs (or whatever unit the ref device has), but the caller
+ // expects pixel coordinates
+ aTextRect = m_rTargetDevice.LogicToPixel( aTextRect );
+
+ // convert the metric vector
+ if ( _pVector )
+ {
+ for ( MetricVector::iterator charRect = _pVector->begin();
+ charRect != _pVector->end();
+ ++charRect
+ )
+ {
+ *charRect = m_rTargetDevice.LogicToPixel( *charRect );
+ }
+ }
+
+ return aTextRect;
+ }
+
+ //====================================================================
+ //= ControlTextRenderer
+ //====================================================================
+ //--------------------------------------------------------------------
+ ControlTextRenderer::ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice )
+ :m_pImpl( new ReferenceDeviceTextLayout( _rControl, _rTargetDevice, _rReferenceDevice ) )
+ {
+ }
+
+ //--------------------------------------------------------------------
+ ControlTextRenderer::~ControlTextRenderer()
+ {
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle ControlTextRenderer::DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle,
+ MetricVector* _pVector, String* _pDisplayText )
+ {
+ return m_pImpl->DrawText( _rRect, _rText, _nStyle, _pVector, _pDisplayText );
+ }
+
+//........................................................................
+} // namespace vcl
+//........................................................................