diff options
-rw-r--r-- | vcl/inc/vcl/ctrl.hxx | 13 | ||||
-rw-r--r-- | vcl/inc/vcl/outdev.hxx | 20 | ||||
-rwxr-xr-x | vcl/inc/vcl/textlayout.hxx | 92 | ||||
-rw-r--r-- | vcl/source/control/button.cxx | 6 | ||||
-rw-r--r-- | vcl/source/control/ctrl.cxx | 78 | ||||
-rw-r--r-- | vcl/source/control/fixed.cxx | 4 | ||||
-rw-r--r-- | vcl/source/gdi/makefile.mk | 3 | ||||
-rw-r--r-- | vcl/source/gdi/outdev3.cxx | 74 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 2 | ||||
-rwxr-xr-x | vcl/source/gdi/textlayout.cxx | 269 |
10 files changed, 460 insertions, 101 deletions
diff --git a/vcl/inc/vcl/ctrl.hxx b/vcl/inc/vcl/ctrl.hxx index 2508a58c005e..535f75549991 100644 --- a/vcl/inc/vcl/ctrl.hxx +++ b/vcl/inc/vcl/ctrl.hxx @@ -97,8 +97,11 @@ protected: If no reference device is set, the draw request will simply be forwarded to OutputDevice::DrawText. Otherwise, the text will be rendered according to the metrics at the reference device. + + Note that the given rectangle might be modified, it will contain the result of a GetTextRect call (either + directly at the target device, or taking the reference device into account) when returning. */ - void DrawControlText( OutputDevice& _rTargetDevice, const Rectangle& _rRect, + void DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText ) const; @@ -188,6 +191,14 @@ public: */ void SetReferenceDevice( OutputDevice* _referenceDevice ); OutputDevice* GetReferenceDevice() const; + + Font GetUnzoomedControlPointFont() const + { + Font aFont( GetCanonicalFont( GetSettings().GetStyleSettings() ) ); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + return aFont; + } }; #endif // _SV_CTRL_HXX diff --git a/vcl/inc/vcl/outdev.hxx b/vcl/inc/vcl/outdev.hxx index f4e42846dd5e..d056a26c0127 100644 --- a/vcl/inc/vcl/outdev.hxx +++ b/vcl/inc/vcl/outdev.hxx @@ -103,8 +103,12 @@ namespace awt { typedef std::vector< Rectangle > MetricVector; -namespace vcl { class PDFWriterImpl; } -namespace vcl { class ExtOutDevData; } +namespace vcl +{ + class PDFWriterImpl; + class ExtOutDevData; + class ITextLayout; +} #define OUTDEV_BUFFER_SIZE 128 @@ -433,7 +437,7 @@ public: SAL_DLLPRIVATE long ImplGetTextWidth( const SalLayout& ) const; SAL_DLLPRIVATE void ImplDrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, - MetricVector* pVector, String* pDisplayText ); + MetricVector* pVector, String* pDisplayText, ::vcl::ITextLayout* _pLayout ); SAL_DLLPRIVATE void ImplDrawTextBackground( const SalLayout& ); SAL_DLLPRIVATE void ImplDrawTextLines( SalLayout&, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, BOOL bWordLine, BOOL bUnderlineAbove ); SAL_DLLPRIVATE bool ImplDrawRotateText( SalLayout& ); @@ -456,7 +460,7 @@ public: SAL_DLLPRIVATE void ImplDrawMnemonicLine( long nX, long nY, long nWidth ); SAL_DLLPRIVATE void ImplGetEmphasisMark( PolyPolygon& rPolyPoly, BOOL& rPolyLine, Rectangle& rRect1, Rectangle& rRect2, long& rYOff, long& rWidth, FontEmphasisMark eEmphasis, long nHeight, short nOrient ); SAL_DLLPRIVATE void ImplDrawEmphasisMark( long nBaseX, long nX, long nY, const PolyPolygon& rPolyPoly, BOOL bPolyLine, const Rectangle& rRect1, const Rectangle& rRect2 ); - SAL_DLLPRIVATE long ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, long nWidth, const XubString& rStr, USHORT nStyle ) const; + SAL_DLLPRIVATE long ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, long nWidth, const XubString& rStr, USHORT nStyle, const ::vcl::ITextLayout* _pLayout ) const; SAL_DLLPRIVATE void ImplInitFontList() const; SAL_DLLPRIVATE void ImplUpdateFontData( bool bNewFontLists ); SAL_DLLPRIVATE static void ImplUpdateAllFontData( bool bNewFontLists ); @@ -650,9 +654,17 @@ public: void DrawText( const Rectangle& rRect, const XubString& rStr, USHORT nStyle = 0, MetricVector* pVector = NULL, String* pDisplayText = NULL ); + void DrawText( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle, + MetricVector* pVector, String* pDisplayText, + ::vcl::ITextLayout* _pTextLayout ); Rectangle GetTextRect( const Rectangle& rRect, const XubString& rStr, USHORT nStyle = TEXT_DRAW_WORDBREAK, TextRectInfo* pInfo = NULL ) const; + Rectangle GetTextRect( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle, + TextRectInfo* pInfo, + const ::vcl::ITextLayout* _pTextLayout ) const; XubString GetEllipsisString( const XubString& rStr, long nMaxWidth, USHORT nStyle = TEXT_DRAW_ENDELLIPSIS ) const; void DrawCtrlText( const Point& rPos, const XubString& rStr, diff --git a/vcl/inc/vcl/textlayout.hxx b/vcl/inc/vcl/textlayout.hxx new file mode 100755 index 000000000000..dbb7b2d17d77 --- /dev/null +++ b/vcl/inc/vcl/textlayout.hxx @@ -0,0 +1,92 @@ +/************************************************************************* +* 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. +************************************************************************/ +
+#ifndef VCL_TEXTLAYOUT_HXX +#define VCL_TEXTLAYOUT_HXX + +#include "vcl/outdev.hxx" + +#include <tools/solar.h> +#include <tools/string.hxx> + +#include <memory> + +class Control; + +//........................................................................ +namespace vcl +{ +//........................................................................ + + //==================================================================== + //= ITextLayout + //==================================================================== + class SAL_NO_VTABLE ITextLayout + { + public: + virtual long GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const = 0; + virtual void DrawText( + const Point& _rStartPoint, + const XubString& _rText, + xub_StrLen _nStartIndex, + xub_StrLen _nLength, + MetricVector* _pVector, + String* _pDisplayText + ) = 0; + }; + + //==================================================================== + //= ControlTextRenderer + //==================================================================== + class ReferenceDeviceTextLayout; + /** a class which allows rendering text onto a device, but calculating the metrics according to a reference device + + The class provides a number of methods which are equivalent to the same methods of the OutputDevice, except + that OutputDevice does not know about reference devices. + */ + class ControlTextRenderer + { + public: + ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice ); + virtual ~ControlTextRenderer(); + + Rectangle DrawText( const Rectangle& _rRect, + const XubString& _rText, USHORT _nStyle = 0, + MetricVector* _pVector = NULL, String* _pDisplayText = NULL ); + + private: + ControlTextRenderer(); // never implemented + ControlTextRenderer( const ControlTextRenderer& ); // never implemented + ControlTextRenderer& operator=( const ControlTextRenderer& ); // never implemented + + private: + ::std::auto_ptr< ReferenceDeviceTextLayout > m_pImpl; + }; + +//........................................................................ +} // namespace vcl +//........................................................................ + +#endif // VCL_TEXTLAYOUT_HXX diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx index 0f9a09cb17e7..6d6c7aae923a 100644 --- a/vcl/source/control/button.cxx +++ b/vcl/source/control/button.cxx @@ -406,12 +406,12 @@ void Button::ImplDrawAlignedImage( OutputDevice* pDev, Point& rPos, } else if ( bDrawText && !bDrawImage && !bHasSymbol ) { - aOutRect = pDev->GetTextRect( aOutRect, aText, nTextStyle ); + DrawControlText( *pDev, aOutRect, aText, nTextStyle, pVector, pDisplayText ); + + ImplSetFocusRect( aOutRect ); rSize = aOutRect.GetSize(); rPos = aOutRect.TopLeft(); - ImplSetFocusRect( aOutRect ); - DrawControlText( *pDev, aOutRect, aText, nTextStyle, pVector, pDisplayText ); return; } diff --git a/vcl/source/control/ctrl.cxx b/vcl/source/control/ctrl.cxx index 7ca2ff5ff8e5..cfffbe136204 100644 --- a/vcl/source/control/ctrl.cxx +++ b/vcl/source/control/ctrl.cxx @@ -41,6 +41,7 @@ #include <vcl/decoview.hxx> #include <vcl/controldata.hxx> #include <vcl/salnativewidgets.hxx> +#include <vcl/textlayout.hxx> namespace vcl @@ -549,82 +550,17 @@ void Control::ImplInitSettings( const BOOL _bFont, const BOOL _bForeground ) // ----------------------------------------------------------------- -void Control::DrawControlText( OutputDevice& _rTargetDevice, const Rectangle& _rRect, const XubString& _rStr, +void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText ) const { + if ( !mpControlData->mpReferenceDevice ) { - _rTargetDevice.DrawText( _rRect, _rStr, _nStyle, _pVector, _pDisplayText ); + _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle ); + _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText ); return; } - // TODO: - // - respect the style (word break, vert./horz. align, etc.) - // - respect _pVector and _pDisplayText, i.e. fill metric data if they're given - - sal_Int32* pCharWidths = new sal_Int32[ _rStr.Len() ]; - // retrieve unzoomed point font of the target device - Font aFont( GetCanonicalFont( GetSettings().GetStyleSettings() ) ); - if ( IsControlFont() ) - aFont.Merge( GetControlFont() ); - - // transfer font to the reference device - mpControlData->mpReferenceDevice->Push( PUSH_FONT ); - Font aRefFont( aFont ); - aRefFont.SetSize( LogicToLogic( - aRefFont.GetSize(), MAP_POINT, mpControlData->mpReferenceDevice->GetMapMode().GetMapUnit() ) ); - mpControlData->mpReferenceDevice->SetFont( aRefFont ); - - // retrieve the character widths from the reference device - mpControlData->mpReferenceDevice->GetTextArray( _rStr, pCharWidths ); - mpControlData->mpReferenceDevice->Pop(); - - // adjust the widths, which are in ref-device units, to the target device - const MapUnit eRefMapUnit( mpControlData->mpReferenceDevice->GetMapMode().GetMapUnit() ); - OSL_ENSURE( eRefMapUnit != MAP_PIXEL, "a reference device with MAP_PIXEL?" ); - - const MapMode& aTargetMapMode( _rTargetDevice.GetMapMode() ); - const MapUnit eTargetMapUnit( aTargetMapMode.GetMapUnit() ); - const bool bTargetIsPixel = ( eTargetMapUnit == MAP_PIXEL ); - { - for ( size_t i=0; i<_rStr.Len(); ++i ) - { - pCharWidths[i] = - bTargetIsPixel - ? _rTargetDevice.LogicToPixel( Size( pCharWidths[i], 0 ), eRefMapUnit ).Width() - : _rTargetDevice.LogicToLogic( Size( pCharWidths[i], 0 ), eRefMapUnit, eTargetMapUnit ).Width(); - } - } - - Point aDrawTextPosition( _rRect.TopLeft() ); - // translate our zoom into a map mode / font / origin at the target device - if ( IsZoom() ) - { - _rTargetDevice.Push( PUSH_MAPMODE | PUSH_FONT ); - - const Fraction& rZoom( GetZoom() ); - - MapMode aDrawMapMode( aTargetMapMode ); - aDrawMapMode.SetScaleX( rZoom ); - aDrawMapMode.SetScaleY( rZoom ); - _rTargetDevice.SetMapMode( aDrawMapMode ); - - Font aDrawFont( aFont ); - if ( bTargetIsPixel ) - aDrawFont.SetSize( _rTargetDevice.LogicToPixel( aDrawFont.GetSize(), MAP_POINT ) ); - else - aDrawFont.SetSize( _rTargetDevice.LogicToLogic( aDrawFont.GetSize(), MAP_POINT, eTargetMapUnit ) ); - _rTargetDevice.SetFont( aDrawFont ); - - aDrawTextPosition.X() = long(aDrawTextPosition.X() / (double)rZoom); - aDrawTextPosition.Y() = long(aDrawTextPosition.Y() / (double)rZoom); - } - - // draw the text - _rTargetDevice.DrawTextArray( aDrawTextPosition, _rStr, pCharWidths ); - - if ( IsZoom() ) - _rTargetDevice.Pop(); - - delete[] pCharWidths; + ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice ); + _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText ); } diff --git a/vcl/source/control/fixed.cxx b/vcl/source/control/fixed.cxx index 4b081c57e188..53029c8e3573 100644 --- a/vcl/source/control/fixed.cxx +++ b/vcl/source/control/fixed.cxx @@ -265,7 +265,8 @@ void FixedText::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags, if( bFillLayout ) mpControlData->mpLayoutData->m_aDisplayText = String(); - DrawControlText( *pDev, Rectangle( aPos, rSize ), aText, nTextStyle, + Rectangle aRect( Rectangle( aPos, rSize ) ); + DrawControlText( *pDev, aRect, aText, nTextStyle, bFillLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL, bFillLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL ); @@ -548,7 +549,6 @@ void FixedLine::ImplDraw( bool bLayout ) if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO ) nStyle |= TEXT_DRAW_MONO; - aRect = GetTextRect( aRect, aText, nStyle ); DrawControlText( *this, aRect, aText, nStyle, pVector, pDisplayText ); if( !pVector ) diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk index a09ae92dcb5e..b708346e45e4 100644 --- a/vcl/source/gdi/makefile.mk +++ b/vcl/source/gdi/makefile.mk @@ -115,7 +115,8 @@ SLOFILES= $(SLO)$/salmisc.obj \ $(SLO)$/bmpconv.obj \ $(SLO)$/pngread.obj \ $(SLO)$/pngwrite.obj \ - $(SLO)$/graphictools.obj + $(SLO)$/graphictools.obj \ + $(SLO)$/textlayout.obj EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/outdev.obj \ diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 0a6b778681e1..87a6659de51e 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* _pLayout ) const { DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" ); @@ -5295,7 +5296,8 @@ 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 = ( _pLayout != NULL ) ? _pLayout->GetTextWidth( rStr, nPos, nBreakPos-nPos ) + : GetTextWidth( rStr, nPos, nBreakPos-nPos ); if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) ) { if ( !xBI.is() ) @@ -5408,7 +5410,8 @@ 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 = ( _pLayout != NULL ) ? _pLayout->GetTextWidth( rStr, nPos, nBreakPos-nPos ) + : GetTextWidth( rStr, nPos, nBreakPos-nPos ); } else { @@ -5422,14 +5425,16 @@ long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, { if( nSpacePos > nPos ) nSpacePos--; - nW = GetTextWidth( rStr, nPos, nSpacePos-nPos ); + nW = ( _pLayout != NULL ) ? _pLayout->GetTextWidth( rStr, nPos, nSpacePos-nPos ) + : GetTextWidth( rStr, nPos, nSpacePos-nPos ); } } while( nW > nWidth ); if( nSpacePos != STRING_NOTFOUND ) { nBreakPos = nSpacePos; - nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos ); + nLineWidth = ( _pLayout != NULL ) ? _pLayout->GetTextWidth( rStr, nPos, nBreakPos-nPos ) + : GetTextWidth( rStr, nPos, nBreakPos-nPos ); if( nBreakPos < rStr.Len()-1 ) nBreakPos++; } @@ -6773,7 +6778,8 @@ xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth, void OutputDevice::ImplDrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, - MetricVector* pVector, String* pDisplayText ) + MetricVector* pVector, String* pDisplayText, + ::vcl::ITextLayout* _pLayout ) { Color aOldTextColor; Color aOldTextFillColor; @@ -6850,7 +6856,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, if ( nTextHeight ) { - nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle ); + nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pLayout ); nLines = (xub_StrLen)(nHeight/nTextHeight); nFormatLines = aMultiLineInfo.Count(); if ( !nLines ) @@ -6916,7 +6922,10 @@ 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 ( _pLayout ) + _pLayout->DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText ); + else + DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText ); if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector ) { if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) ) @@ -6946,7 +6955,10 @@ 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 ); + if ( _pLayout ) + _pLayout->DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText ); + else + DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText ); // Clipping zuruecksetzen if ( nStyle & TEXT_DRAW_CLIP ) @@ -6955,7 +6967,9 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, } else { - long nTextWidth = GetTextWidth( aStr ); + long nTextWidth = _pLayout + ? _pLayout->GetTextWidth( aStr, 0, STRING_LEN ) + : GetTextWidth( aStr ); // Evt. Text kuerzen if ( nTextWidth > nWidth ) @@ -7011,7 +7025,10 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, { Push( PUSH_CLIPREGION ); IntersectClipRegion( rRect ); - DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); + if ( _pLayout ) + _pLayout->DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); + else + DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector ) { if ( nMnemonicPos != STRING_NOTFOUND ) @@ -7021,7 +7038,10 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, } else { - DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); + if ( _pLayout ) + _pLayout->DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); + else + DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText ); if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector ) { if ( nMnemonicPos != STRING_NOTFOUND ) @@ -7067,7 +7087,7 @@ void OutputDevice::AddTextRectActions( const Rectangle& rRect, // #i47157# Factored out to ImplDrawTextRect(), to be shared // between us and DrawText() - ImplDrawText( rRect, rOrigStr, nStyle, NULL, NULL ); + ImplDrawText( rRect, rOrigStr, nStyle, NULL, NULL, NULL ); // and restore again EnableOutput( bOutputEnabled ); @@ -7079,7 +7099,15 @@ void OutputDevice::AddTextRectActions( const Rectangle& rRect, void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, MetricVector* pVector, String* pDisplayText ) +{ + DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText, NULL ); +} + +// ----------------------------------------------------------------------- +void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, + MetricVector* pVector, String* pDisplayText, + ::vcl::ITextLayout* _pTextLayout ) { if( mpOutDevData && mpOutDevData->mpRecordLayout ) { @@ -7109,9 +7137,9 @@ void OutputDevice::DrawText( const Rectangle& rRect, GDIMetaFile* pMtf = mpMetaFile; 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 ); + ImplDrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ); // and enable again mpMetaFile = pMtf; @@ -7126,6 +7154,16 @@ Rectangle OutputDevice::GetTextRect( const Rectangle& rRect, const String& rOrigStr, USHORT nStyle, TextRectInfo* pInfo ) const { + return GetTextRect( rRect, rOrigStr, nStyle, pInfo, NULL ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::GetTextRect( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle, + TextRectInfo* pInfo, + const ::vcl::ITextLayout* _pTextLayout ) const +{ DBG_TRACE( "OutputDevice::GetTextRect()" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); @@ -7135,7 +7173,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 ); @@ -7147,7 +7185,7 @@ Rectangle OutputDevice::GetTextRect( const Rectangle& rRect, xub_StrLen i; nMaxWidth = 0; - ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle ); + ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ); nFormatLines = aMultiLineInfo.Count(); if ( !nTextHeight ) nTextHeight = 1; @@ -7195,7 +7233,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 ) { diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index e7ee18ec7705..3eda6b5c929c 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -7307,7 +7307,7 @@ void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, US if ( nTextHeight ) { - nMaxTextWidth = m_pReferenceDevice->ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle ); + nMaxTextWidth = m_pReferenceDevice->ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, NULL ); 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..7ea72e8e12ea --- /dev/null +++ b/vcl/source/gdi/textlayout.cxx @@ -0,0 +1,269 @@ +/************************************************************************* +* 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" + +//........................................................................ +namespace vcl +{ +//........................................................................ + + //==================================================================== + //= 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 ); + + 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); + + + bool IsZoom() const; + + 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; + + 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() ) + { + if ( IsZoom() ) + { + m_rTargetDevice.Push( PUSH_MAPMODE | PUSH_FONT ); + + MapMode aDrawMapMode( m_rTargetDevice.GetMapMode() ); + aDrawMapMode.SetScaleX( m_aZoom ); // TODO: shouldn't this be "current_scale * zoom"? + aDrawMapMode.SetScaleY( m_aZoom ); + m_rTargetDevice.SetMapMode( aDrawMapMode ); + + MapUnit eTargetMapUnit = m_rTargetDevice.GetMapMode().GetMapUnit(); + Font aDrawFont( m_aUnzoomedPointFont ); + if ( eTargetMapUnit == MAP_PIXEL ) + aDrawFont.SetSize( m_rTargetDevice.LogicToPixel( aDrawFont.GetSize(), MAP_POINT ) ); + else + aDrawFont.SetSize( m_rTargetDevice.LogicToLogic( aDrawFont.GetSize(), MAP_POINT, eTargetMapUnit ) ); + _rTargetDevice.SetFont( aDrawFont ); + } + } + + //-------------------------------------------------------------------- + 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; + } + + //................................................................ + class DeviceUnitMapping + { + public: + DeviceUnitMapping( const OutputDevice& _rTargetDevice, const OutputDevice& _rReferenceDevice ) + :m_rTargetDevice( _rTargetDevice ) + ,m_eTargetMapUnit( _rTargetDevice.GetMapMode().GetMapUnit() ) + ,m_bTargetIsPixel( _rTargetDevice.GetMapMode().GetMapUnit() == MAP_PIXEL ) + ,m_eRefMapUnit( _rReferenceDevice.GetMapMode().GetMapUnit() ) + { + OSL_ENSURE( m_eRefMapUnit != MAP_PIXEL, "a reference device with MAP_PIXEL?" ); + } + + long mapToTarget( long _nWidth ) + { + return m_bTargetIsPixel + ? m_rTargetDevice.LogicToPixel( Size( _nWidth, 0 ), m_eRefMapUnit ).Width() + : m_rTargetDevice.LogicToLogic( Size( _nWidth, 0 ), m_eRefMapUnit, m_eTargetMapUnit ).Width(); + } + + private: + const OutputDevice& m_rTargetDevice; + const MapUnit m_eTargetMapUnit; + const bool m_bTargetIsPixel; + const MapUnit m_eRefMapUnit; + }; + } + + //-------------------------------------------------------------------- + ReferenceDeviceTextLayout::~ReferenceDeviceTextLayout() + { + if ( IsZoom() ) + m_rTargetDevice.Pop(); + } + + //-------------------------------------------------------------------- + bool ReferenceDeviceTextLayout::IsZoom() const + { + return m_aZoom.GetNumerator() != m_aZoom.GetDenominator(); + } + + //-------------------------------------------------------------------- + long ReferenceDeviceTextLayout::GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const + { + if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) ) + return 0; + + // transfer font to the reference device + m_rReferenceDevice.Push( PUSH_FONT ); + Font aRefFont( m_aUnzoomedPointFont ); + aRefFont.SetSize( OutputDevice::LogicToLogic( + aRefFont.GetSize(), MAP_POINT, m_rReferenceDevice.GetMapMode().GetMapUnit() ) ); + m_rReferenceDevice.SetFont( aRefFont ); + + // retrieve the character widths from the reference device + long nTextWidth = m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength ); + m_rReferenceDevice.Pop(); + + // adjust the widths, which are in ref-device units, to the target device + DeviceUnitMapping aMapping( m_rTargetDevice, m_rReferenceDevice ); + if ( _pDXAry ) + { + for ( size_t i=0; i<_nLength; ++i ) + _pDXAry[i] = aMapping.mapToTarget( _pDXAry[i] ); + } + nTextWidth = aMapping.mapToTarget( nTextWidth ); + + 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; + + 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() ) ) ); + + // TODO: use/fill those: + (void)_pVector; + (void)_pDisplayText; + } + + //-------------------------------------------------------------------- + Rectangle ReferenceDeviceTextLayout::DrawText( const Rectangle& _rRect, const XubString& _rText, USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText) + { + Rectangle aRect( _rRect ); + if ( IsZoom() ) + { + // if there's a zoom factor involved, then we tampered with the target device's map mode in the ctor. + // Need to adjust the rectangle to this + aRect.Left() = long( aRect.Left() / (double)m_aZoom ); + aRect.Right() = long( aRect.Right() / (double)m_aZoom ); + aRect.Top() = long( aRect.Top() / (double)m_aZoom ); + aRect.Bottom() = long( aRect.Bottom() / (double)m_aZoom ); + } + + onBeginDrawText(); + m_rTargetDevice.DrawText( aRect, _rText, _nStyle, _pVector, _pDisplayText, this ); + Rectangle aTextRect = onEndDrawText(); + + if ( IsZoom() ) + { + // similar to above, transform the to-be-returned rectanle to coordinates which are meaningful + // with the original map mode of the target device + aTextRect.Left() = long( aTextRect.Left() * (double)m_aZoom ); + aTextRect.Right() = long( aTextRect.Right() * (double)m_aZoom ); + aTextRect.Top() = long( aTextRect.Top() * (double)m_aZoom ); + aTextRect.Bottom() = long( aTextRect.Bottom() * (double)m_aZoom ); + } + + 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 +//........................................................................ |