xref: /aoo41x/main/vcl/source/gdi/textlayout.cxx (revision 79aad27f)
1*9f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*9f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*9f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*9f62ea84SAndrew Rist  * distributed with this work for additional information
6*9f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*9f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*9f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
9*9f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*9f62ea84SAndrew Rist  *
11*9f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*9f62ea84SAndrew Rist  *
13*9f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*9f62ea84SAndrew Rist  * software distributed under the License is distributed on an
15*9f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*9f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
17*9f62ea84SAndrew Rist  * specific language governing permissions and limitations
18*9f62ea84SAndrew Rist  * under the License.
19*9f62ea84SAndrew Rist  *
20*9f62ea84SAndrew Rist  *************************************************************/
21*9f62ea84SAndrew Rist 
22*9f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "vcl/ctrl.hxx"
28cdf0e10cSrcweir #include "vcl/outdev.hxx"
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #include "outfont.hxx"
31cdf0e10cSrcweir #include "textlayout.hxx"
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptDirection.hpp>
34cdf0e10cSrcweir 
35cdf0e10cSrcweir #include <tools/diagnose_ex.h>
36cdf0e10cSrcweir 
37cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
38cdf0e10cSrcweir #include <rtl/strbuf.hxx>
39cdf0e10cSrcweir #endif
40cdf0e10cSrcweir 
41cdf0e10cSrcweir //........................................................................
42cdf0e10cSrcweir namespace vcl
43cdf0e10cSrcweir {
44cdf0e10cSrcweir //........................................................................
45cdf0e10cSrcweir 
46cdf0e10cSrcweir     using ::com::sun::star::uno::Reference;
47cdf0e10cSrcweir     using ::com::sun::star::uno::Exception;
48cdf0e10cSrcweir     namespace ScriptDirection = ::com::sun::star::i18n::ScriptDirection;
49cdf0e10cSrcweir 
50cdf0e10cSrcweir 	//====================================================================
51cdf0e10cSrcweir 	//= DefaultTextLayout
52cdf0e10cSrcweir 	//====================================================================
53cdf0e10cSrcweir 	//--------------------------------------------------------------------
~DefaultTextLayout()54cdf0e10cSrcweir     DefaultTextLayout::~DefaultTextLayout()
55cdf0e10cSrcweir     {
56cdf0e10cSrcweir     }
57cdf0e10cSrcweir 
58cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetTextWidth(const XubString & _rText,xub_StrLen _nStartIndex,xub_StrLen _nLength) const59cdf0e10cSrcweir     long DefaultTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
60cdf0e10cSrcweir     {
61cdf0e10cSrcweir         return m_rTargetDevice.GetTextWidth( _rText, _nStartIndex, _nLength );
62cdf0e10cSrcweir     }
63cdf0e10cSrcweir 
64cdf0e10cSrcweir 	//--------------------------------------------------------------------
DrawText(const Point & _rStartPoint,const XubString & _rText,xub_StrLen _nStartIndex,xub_StrLen _nLength,MetricVector * _pVector,String * _pDisplayText)65cdf0e10cSrcweir     void DefaultTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex,
66cdf0e10cSrcweir         xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
67cdf0e10cSrcweir     {
68cdf0e10cSrcweir         m_rTargetDevice.DrawText( _rStartPoint, _rText, _nStartIndex, _nLength, _pVector, _pDisplayText );
69cdf0e10cSrcweir     }
70cdf0e10cSrcweir 
71cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetCaretPositions(const XubString & _rText,sal_Int32 * _pCaretXArray,xub_StrLen _nStartIndex,xub_StrLen _nLength) const72cdf0e10cSrcweir     bool DefaultTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
73cdf0e10cSrcweir         xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
74cdf0e10cSrcweir     {
75cdf0e10cSrcweir         return m_rTargetDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength );
76cdf0e10cSrcweir     }
77cdf0e10cSrcweir 
78cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetTextBreak(const XubString & _rText,long _nMaxTextWidth,xub_StrLen _nStartIndex,xub_StrLen _nLength) const79cdf0e10cSrcweir     xub_StrLen DefaultTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
80cdf0e10cSrcweir     {
81cdf0e10cSrcweir         return m_rTargetDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
82cdf0e10cSrcweir     }
83cdf0e10cSrcweir 
84cdf0e10cSrcweir 	//--------------------------------------------------------------------
DecomposeTextRectAction() const85cdf0e10cSrcweir     bool DefaultTextLayout::DecomposeTextRectAction() const
86cdf0e10cSrcweir     {
87cdf0e10cSrcweir         return false;
88cdf0e10cSrcweir     }
89cdf0e10cSrcweir 
90cdf0e10cSrcweir 	//====================================================================
91cdf0e10cSrcweir 	//= ReferenceDeviceTextLayout
92cdf0e10cSrcweir 	//====================================================================
93cdf0e10cSrcweir     class ReferenceDeviceTextLayout : public ITextLayout
94cdf0e10cSrcweir     {
95cdf0e10cSrcweir     public:
96cdf0e10cSrcweir         ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice );
97cdf0e10cSrcweir         virtual ~ReferenceDeviceTextLayout();
98cdf0e10cSrcweir 
99cdf0e10cSrcweir         // ITextLayout
100cdf0e10cSrcweir         virtual long        GetTextWidth( const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const;
101cdf0e10cSrcweir         virtual void        DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText );
102cdf0e10cSrcweir         virtual bool        GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
103cdf0e10cSrcweir         virtual xub_StrLen  GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
104cdf0e10cSrcweir         virtual bool        DecomposeTextRectAction() const;
105cdf0e10cSrcweir 
106cdf0e10cSrcweir     public:
107cdf0e10cSrcweir         // equivalents to the respective OutputDevice methods, which take the reference device into account
108cdf0e10cSrcweir         long        GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const;
109cdf0e10cSrcweir         Rectangle   DrawText( const Rectangle& _rRect, const XubString& _rText, sal_uInt16 _nStyle, MetricVector* _pVector, String* _pDisplayText );
110cdf0e10cSrcweir 
111cdf0e10cSrcweir     protected:
onBeginDrawText()112cdf0e10cSrcweir         void onBeginDrawText()
113cdf0e10cSrcweir         {
114cdf0e10cSrcweir             m_aCompleteTextRect.SetEmpty();
115cdf0e10cSrcweir         }
onEndDrawText()116cdf0e10cSrcweir         Rectangle onEndDrawText()
117cdf0e10cSrcweir         {
118cdf0e10cSrcweir             return m_aCompleteTextRect;
119cdf0e10cSrcweir         }
120cdf0e10cSrcweir 
121cdf0e10cSrcweir     private:
122cdf0e10cSrcweir         OutputDevice&   m_rTargetDevice;
123cdf0e10cSrcweir         OutputDevice&   m_rReferenceDevice;
124cdf0e10cSrcweir         Font            m_aUnzoomedPointFont;
125cdf0e10cSrcweir         const Fraction  m_aZoom;
126cdf0e10cSrcweir         const bool      m_bRTLEnabled;
127cdf0e10cSrcweir 
128cdf0e10cSrcweir         Rectangle       m_aCompleteTextRect;
129cdf0e10cSrcweir     };
130cdf0e10cSrcweir 
131cdf0e10cSrcweir 	//====================================================================
132cdf0e10cSrcweir 	//= ControlTextRenderer
133cdf0e10cSrcweir 	//====================================================================
ReferenceDeviceTextLayout(const Control & _rControl,OutputDevice & _rTargetDevice,OutputDevice & _rReferenceDevice)134cdf0e10cSrcweir     ReferenceDeviceTextLayout::ReferenceDeviceTextLayout( const Control& _rControl, OutputDevice& _rTargetDevice,
135cdf0e10cSrcweir         OutputDevice& _rReferenceDevice )
136cdf0e10cSrcweir         :m_rTargetDevice( _rTargetDevice )
137cdf0e10cSrcweir         ,m_rReferenceDevice( _rReferenceDevice )
138cdf0e10cSrcweir         ,m_aUnzoomedPointFont( _rControl.GetUnzoomedControlPointFont() )
139cdf0e10cSrcweir         ,m_aZoom( _rControl.GetZoom() )
140cdf0e10cSrcweir         ,m_bRTLEnabled( _rControl.IsRTLEnabled() )
141cdf0e10cSrcweir     {
142cdf0e10cSrcweir         m_rTargetDevice.Push( PUSH_MAPMODE | PUSH_FONT | PUSH_TEXTLAYOUTMODE );
143cdf0e10cSrcweir 
144cdf0e10cSrcweir         MapMode aTargetMapMode( m_rTargetDevice.GetMapMode() );
145cdf0e10cSrcweir         OSL_ENSURE( aTargetMapMode.GetOrigin() == Point(), "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: uhm, the code below won't work here ..." );
146cdf0e10cSrcweir 
147cdf0e10cSrcweir         // normally, controls simulate "zoom" by "zooming" the font. This is responsible for (part of) the discrepancies
148cdf0e10cSrcweir         // between text in Writer and text in controls in Writer, though both have the same font.
149cdf0e10cSrcweir         // So, if we have a zoom set at the control, then we do not scale the font, but instead modify the map mode
150cdf0e10cSrcweir         // to accomodate for the zoom.
151cdf0e10cSrcweir         aTargetMapMode.SetScaleX( m_aZoom );    // TODO: shouldn't this be "current_scale * zoom"?
152cdf0e10cSrcweir         aTargetMapMode.SetScaleY( m_aZoom );
153cdf0e10cSrcweir 
154cdf0e10cSrcweir         // also, use a higher-resolution map unit than "pixels", which should save us some rounding errors when
155cdf0e10cSrcweir         // translating coordinates between the reference device and the target device.
156cdf0e10cSrcweir         OSL_ENSURE( aTargetMapMode.GetMapUnit() == MAP_PIXEL,
157cdf0e10cSrcweir             "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: this class is not expected to work with such target devices!" );
158cdf0e10cSrcweir             // we *could* adjust all the code in this class to handle this case, but at the moment, it's not necessary
159cdf0e10cSrcweir         const MapUnit eTargetMapUnit = m_rReferenceDevice.GetMapMode().GetMapUnit();
160cdf0e10cSrcweir         aTargetMapMode.SetMapUnit( eTargetMapUnit );
161cdf0e10cSrcweir         OSL_ENSURE( aTargetMapMode.GetMapUnit() != MAP_PIXEL,
162cdf0e10cSrcweir             "ReferenceDeviceTextLayout::ReferenceDeviceTextLayout: a reference device which has map mode PIXEL?!" );
163cdf0e10cSrcweir 
164cdf0e10cSrcweir         m_rTargetDevice.SetMapMode( aTargetMapMode );
165cdf0e10cSrcweir 
166cdf0e10cSrcweir         // now that the Zoom is part of the map mode, reset the target device's font to the "unzoomed" version
167cdf0e10cSrcweir         Font aDrawFont( m_aUnzoomedPointFont );
168cdf0e10cSrcweir         aDrawFont.SetSize( m_rTargetDevice.LogicToLogic( aDrawFont.GetSize(), MAP_POINT, eTargetMapUnit ) );
169cdf0e10cSrcweir         _rTargetDevice.SetFont( aDrawFont );
170cdf0e10cSrcweir 
171cdf0e10cSrcweir         // transfer font to the reference device
172cdf0e10cSrcweir         m_rReferenceDevice.Push( PUSH_FONT | PUSH_TEXTLAYOUTMODE );
173cdf0e10cSrcweir         Font aRefFont( m_aUnzoomedPointFont );
174cdf0e10cSrcweir         aRefFont.SetSize( OutputDevice::LogicToLogic(
175cdf0e10cSrcweir             aRefFont.GetSize(), MAP_POINT, m_rReferenceDevice.GetMapMode().GetMapUnit() ) );
176cdf0e10cSrcweir         m_rReferenceDevice.SetFont( aRefFont );
177cdf0e10cSrcweir     }
178cdf0e10cSrcweir 
179cdf0e10cSrcweir 	//--------------------------------------------------------------------
~ReferenceDeviceTextLayout()180cdf0e10cSrcweir     ReferenceDeviceTextLayout::~ReferenceDeviceTextLayout()
181cdf0e10cSrcweir     {
182cdf0e10cSrcweir         m_rReferenceDevice.Pop();
183cdf0e10cSrcweir         m_rTargetDevice.Pop();
184cdf0e10cSrcweir     }
185cdf0e10cSrcweir 
186cdf0e10cSrcweir 	//--------------------------------------------------------------------
187cdf0e10cSrcweir     namespace
188cdf0e10cSrcweir     {
189cdf0e10cSrcweir 	    //................................................................
lcl_normalizeLength(const XubString & _rText,const xub_StrLen _nStartIndex,xub_StrLen & _io_nLength)190cdf0e10cSrcweir         bool lcl_normalizeLength( const XubString& _rText, const xub_StrLen _nStartIndex, xub_StrLen& _io_nLength )
191cdf0e10cSrcweir         {
192cdf0e10cSrcweir             xub_StrLen nTextLength = _rText.Len();
193cdf0e10cSrcweir             if ( _nStartIndex > nTextLength )
194cdf0e10cSrcweir                 return false;
195cdf0e10cSrcweir             if ( _nStartIndex + _io_nLength > nTextLength )
196cdf0e10cSrcweir                 _io_nLength = nTextLength - _nStartIndex;
197cdf0e10cSrcweir             return true;
198cdf0e10cSrcweir         }
199cdf0e10cSrcweir     }
200cdf0e10cSrcweir 
201cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetTextArray(const XubString & _rText,sal_Int32 * _pDXAry,xub_StrLen _nStartIndex,xub_StrLen _nLength) const202cdf0e10cSrcweir     long ReferenceDeviceTextLayout::GetTextArray( const XubString& _rText, sal_Int32* _pDXAry, xub_StrLen _nStartIndex,
203cdf0e10cSrcweir         xub_StrLen _nLength ) const
204cdf0e10cSrcweir     {
205cdf0e10cSrcweir         if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
206cdf0e10cSrcweir             return 0;
207cdf0e10cSrcweir 
208cdf0e10cSrcweir         // retrieve the character widths from the reference device
209cdf0e10cSrcweir         long nTextWidth = m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength );
210cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
211cdf0e10cSrcweir         if ( _pDXAry )
212cdf0e10cSrcweir         {
213cdf0e10cSrcweir             ::rtl::OStringBuffer aTrace;
214cdf0e10cSrcweir             aTrace.append( "ReferenceDeviceTextLayout::GetTextArray( " );
215cdf0e10cSrcweir             aTrace.append( ::rtl::OUStringToOString( _rText, RTL_TEXTENCODING_UTF8 ) );
216cdf0e10cSrcweir             aTrace.append( " ): " );
217cdf0e10cSrcweir             aTrace.append( nTextWidth );
218cdf0e10cSrcweir             aTrace.append( " = ( " );
219cdf0e10cSrcweir             for ( size_t i=0; i<_nLength; )
220cdf0e10cSrcweir             {
221cdf0e10cSrcweir                 aTrace.append( _pDXAry[i] );
222cdf0e10cSrcweir                 if ( ++i < _nLength )
223cdf0e10cSrcweir                     aTrace.append( ", " );
224cdf0e10cSrcweir             }
225cdf0e10cSrcweir             aTrace.append( ")" );
226cdf0e10cSrcweir             OSL_TRACE( aTrace.makeStringAndClear().getStr() );
227cdf0e10cSrcweir         }
228cdf0e10cSrcweir #endif
229cdf0e10cSrcweir         return nTextWidth;
230cdf0e10cSrcweir     }
231cdf0e10cSrcweir 
232cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetTextWidth(const XubString & _rText,xub_StrLen _nStartIndex,xub_StrLen _nLength) const233cdf0e10cSrcweir     long ReferenceDeviceTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
234cdf0e10cSrcweir     {
235cdf0e10cSrcweir         return GetTextArray( _rText, NULL, _nStartIndex, _nLength );
236cdf0e10cSrcweir     }
237cdf0e10cSrcweir 
238cdf0e10cSrcweir 	//--------------------------------------------------------------------
DrawText(const Point & _rStartPoint,const XubString & _rText,xub_StrLen _nStartIndex,xub_StrLen _nLength,MetricVector * _pVector,String * _pDisplayText)239cdf0e10cSrcweir     void ReferenceDeviceTextLayout::DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength, MetricVector* _pVector, String* _pDisplayText )
240cdf0e10cSrcweir     {
241cdf0e10cSrcweir         if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
242cdf0e10cSrcweir             return;
243cdf0e10cSrcweir 
244cdf0e10cSrcweir         if ( _pVector && _pDisplayText )
245cdf0e10cSrcweir         {
246cdf0e10cSrcweir             MetricVector aGlyphBounds;
247cdf0e10cSrcweir             m_rReferenceDevice.GetGlyphBoundRects( _rStartPoint, _rText, _nStartIndex, _nLength, _nStartIndex, aGlyphBounds );
248cdf0e10cSrcweir             ::std::copy(
249cdf0e10cSrcweir                 aGlyphBounds.begin(), aGlyphBounds.end(),
250cdf0e10cSrcweir                 ::std::insert_iterator< MetricVector > ( *_pVector, _pVector->end() ) );
251cdf0e10cSrcweir             _pDisplayText->Append( _rText.Copy( _nStartIndex, _nLength ) );
252cdf0e10cSrcweir             return;
253cdf0e10cSrcweir         }
254cdf0e10cSrcweir 
255cdf0e10cSrcweir         sal_Int32* pCharWidths = new sal_Int32[ _nLength ];
256cdf0e10cSrcweir         long nTextWidth = GetTextArray( _rText, pCharWidths, _nStartIndex, _nLength );
257cdf0e10cSrcweir         m_rTargetDevice.DrawTextArray( _rStartPoint, _rText, pCharWidths, _nStartIndex, _nLength );
258cdf0e10cSrcweir         delete[] pCharWidths;
259cdf0e10cSrcweir 
260cdf0e10cSrcweir         m_aCompleteTextRect.Union( Rectangle( _rStartPoint, Size( nTextWidth, m_rTargetDevice.GetTextHeight() ) ) );
261cdf0e10cSrcweir     }
262cdf0e10cSrcweir 
263cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetCaretPositions(const XubString & _rText,sal_Int32 * _pCaretXArray,xub_StrLen _nStartIndex,xub_StrLen _nLength) const264cdf0e10cSrcweir     bool ReferenceDeviceTextLayout::GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray,
265cdf0e10cSrcweir         xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
266cdf0e10cSrcweir     {
267cdf0e10cSrcweir         if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
268cdf0e10cSrcweir             return false;
269cdf0e10cSrcweir 
270cdf0e10cSrcweir         // retrieve the caret positions from the reference device
271cdf0e10cSrcweir         if ( !m_rReferenceDevice.GetCaretPositions( _rText, _pCaretXArray, _nStartIndex, _nLength ) )
272cdf0e10cSrcweir             return false;
273cdf0e10cSrcweir 
274cdf0e10cSrcweir         return true;
275cdf0e10cSrcweir     }
276cdf0e10cSrcweir 
277cdf0e10cSrcweir 	//--------------------------------------------------------------------
GetTextBreak(const XubString & _rText,long _nMaxTextWidth,xub_StrLen _nStartIndex,xub_StrLen _nLength) const278cdf0e10cSrcweir     xub_StrLen ReferenceDeviceTextLayout::GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const
279cdf0e10cSrcweir     {
280cdf0e10cSrcweir         if ( !lcl_normalizeLength( _rText, _nStartIndex, _nLength ) )
281cdf0e10cSrcweir             return 0;
282cdf0e10cSrcweir 
283cdf0e10cSrcweir         return m_rReferenceDevice.GetTextBreak( _rText, _nMaxTextWidth, _nStartIndex, _nLength );
284cdf0e10cSrcweir     }
285cdf0e10cSrcweir 
286cdf0e10cSrcweir 	//--------------------------------------------------------------------
DecomposeTextRectAction() const287cdf0e10cSrcweir     bool ReferenceDeviceTextLayout::DecomposeTextRectAction() const
288cdf0e10cSrcweir     {
289cdf0e10cSrcweir         return true;
290cdf0e10cSrcweir     }
291cdf0e10cSrcweir 
292cdf0e10cSrcweir 	//--------------------------------------------------------------------
293cdf0e10cSrcweir     namespace
294cdf0e10cSrcweir     {
zoomBy(long _value,const Fraction & _zoom)295cdf0e10cSrcweir         long zoomBy( long _value, const Fraction& _zoom )
296cdf0e10cSrcweir         {
297cdf0e10cSrcweir             double n = (double)_value;
298cdf0e10cSrcweir             n *= (double)_zoom.GetNumerator();
299cdf0e10cSrcweir             n /= (double)_zoom.GetDenominator();
300cdf0e10cSrcweir             return (long)::rtl::math::round( n );
301cdf0e10cSrcweir         }
unzoomBy(long _value,const Fraction & _zoom)302cdf0e10cSrcweir         long unzoomBy( long _value, const Fraction& _zoom )
303cdf0e10cSrcweir         {
304cdf0e10cSrcweir             return zoomBy( _value, Fraction( _zoom.GetDenominator(), _zoom.GetNumerator() ) );
305cdf0e10cSrcweir         }
306cdf0e10cSrcweir     }
307cdf0e10cSrcweir 
308cdf0e10cSrcweir 	//--------------------------------------------------------------------
DrawText(const Rectangle & _rRect,const XubString & _rText,sal_uInt16 _nStyle,MetricVector * _pVector,String * _pDisplayText)309cdf0e10cSrcweir     Rectangle ReferenceDeviceTextLayout::DrawText( const Rectangle& _rRect, const XubString& _rText, sal_uInt16 _nStyle, MetricVector* _pVector, String* _pDisplayText )
310cdf0e10cSrcweir     {
311cdf0e10cSrcweir         if ( !_rText.Len() )
312cdf0e10cSrcweir             return Rectangle();
313cdf0e10cSrcweir 
314cdf0e10cSrcweir         // determine text layout mode from the RTL-ness of the control whose text we render
315cdf0e10cSrcweir         sal_uLong nTextLayoutMode = m_bRTLEnabled ? TEXT_LAYOUT_BIDI_RTL : TEXT_LAYOUT_BIDI_LTR;
316cdf0e10cSrcweir         m_rReferenceDevice.SetLayoutMode( nTextLayoutMode );
317cdf0e10cSrcweir         m_rTargetDevice.SetLayoutMode( nTextLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
318cdf0e10cSrcweir             // TEXT_LAYOUT_TEXTORIGIN_LEFT is because when we do actually draw the text (in DrawText( Point, ... )), then
319cdf0e10cSrcweir             // our caller gives us the left border of the draw position, regardless of script type, text layout,
320cdf0e10cSrcweir             // and the like
321cdf0e10cSrcweir 
322cdf0e10cSrcweir         // in our ctor, we set the map mode of the target device from pixel to twip, but our caller doesn't know this,
323cdf0e10cSrcweir         // but passed pixel coordinates. So, adjust the rect.
324cdf0e10cSrcweir         Rectangle aRect( m_rTargetDevice.PixelToLogic( _rRect ) );
325cdf0e10cSrcweir 
326cdf0e10cSrcweir         onBeginDrawText();
327cdf0e10cSrcweir         m_rTargetDevice.DrawText( aRect, _rText, _nStyle, _pVector, _pDisplayText, this );
328cdf0e10cSrcweir         Rectangle aTextRect = onEndDrawText();
329cdf0e10cSrcweir 
330cdf0e10cSrcweir         if ( aTextRect.IsEmpty() && !aRect.IsEmpty() )
331cdf0e10cSrcweir         {
332cdf0e10cSrcweir             // this happens for instance if we're in a PaintToDevice call, where only a MetaFile is recorded,
333cdf0e10cSrcweir             // but no actual painting happens, so our "DrawText( Point, ... )" is never called
334cdf0e10cSrcweir             // In this case, calculate the rect from what OutputDevice::GetTextRect would give us. This has
335cdf0e10cSrcweir             // the disadvantage of less accuracy, compared with the approach to calculate the rect from the
336cdf0e10cSrcweir             // single "DrawText( Point, ... )" calls, since more intermediate arithmetics will translate
337cdf0e10cSrcweir             // from ref- to target-units.
338cdf0e10cSrcweir             aTextRect = m_rTargetDevice.GetTextRect( aRect, _rText, _nStyle, NULL, this );
339cdf0e10cSrcweir         }
340cdf0e10cSrcweir 
341cdf0e10cSrcweir         // similar to above, the text rect now contains TWIPs (or whatever unit the ref device has), but the caller
342cdf0e10cSrcweir         // expects pixel coordinates
343cdf0e10cSrcweir         aTextRect = m_rTargetDevice.LogicToPixel( aTextRect );
344cdf0e10cSrcweir 
345cdf0e10cSrcweir         // convert the metric vector
346cdf0e10cSrcweir         if ( _pVector )
347cdf0e10cSrcweir         {
348cdf0e10cSrcweir             for (   MetricVector::iterator charRect = _pVector->begin();
349cdf0e10cSrcweir                     charRect != _pVector->end();
350cdf0e10cSrcweir                     ++charRect
351cdf0e10cSrcweir                 )
352cdf0e10cSrcweir             {
353cdf0e10cSrcweir                 *charRect = m_rTargetDevice.LogicToPixel( *charRect );
354cdf0e10cSrcweir             }
355cdf0e10cSrcweir         }
356cdf0e10cSrcweir 
357cdf0e10cSrcweir         return aTextRect;
358cdf0e10cSrcweir     }
359cdf0e10cSrcweir 
360cdf0e10cSrcweir 	//====================================================================
361cdf0e10cSrcweir 	//= ControlTextRenderer
362cdf0e10cSrcweir 	//====================================================================
363cdf0e10cSrcweir 	//--------------------------------------------------------------------
ControlTextRenderer(const Control & _rControl,OutputDevice & _rTargetDevice,OutputDevice & _rReferenceDevice)364cdf0e10cSrcweir     ControlTextRenderer::ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice )
365cdf0e10cSrcweir         :m_pImpl( new ReferenceDeviceTextLayout( _rControl, _rTargetDevice, _rReferenceDevice ) )
366cdf0e10cSrcweir     {
367cdf0e10cSrcweir     }
368cdf0e10cSrcweir 
369cdf0e10cSrcweir     //--------------------------------------------------------------------
~ControlTextRenderer()370cdf0e10cSrcweir     ControlTextRenderer::~ControlTextRenderer()
371cdf0e10cSrcweir     {
372cdf0e10cSrcweir     }
373cdf0e10cSrcweir 
374cdf0e10cSrcweir 	//--------------------------------------------------------------------
DrawText(const Rectangle & _rRect,const XubString & _rText,sal_uInt16 _nStyle,MetricVector * _pVector,String * _pDisplayText)375cdf0e10cSrcweir     Rectangle ControlTextRenderer::DrawText( const Rectangle& _rRect, const XubString& _rText, sal_uInt16 _nStyle,
376cdf0e10cSrcweir         MetricVector* _pVector, String* _pDisplayText )
377cdf0e10cSrcweir     {
378cdf0e10cSrcweir         return m_pImpl->DrawText( _rRect, _rText, _nStyle, _pVector, _pDisplayText );
379cdf0e10cSrcweir     }
380cdf0e10cSrcweir 
381cdf0e10cSrcweir //........................................................................
382cdf0e10cSrcweir } // namespace vcl
383cdf0e10cSrcweir //........................................................................
384