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 //-------------------------------------------------------------------- 54cdf0e10cSrcweir DefaultTextLayout::~DefaultTextLayout() 55cdf0e10cSrcweir { 56cdf0e10cSrcweir } 57cdf0e10cSrcweir 58cdf0e10cSrcweir //-------------------------------------------------------------------- 59cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 72cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 79cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 85cdf0e10cSrcweir 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: 112cdf0e10cSrcweir void onBeginDrawText() 113cdf0e10cSrcweir { 114cdf0e10cSrcweir m_aCompleteTextRect.SetEmpty(); 115cdf0e10cSrcweir } 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 //==================================================================== 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 //-------------------------------------------------------------------- 180cdf0e10cSrcweir ReferenceDeviceTextLayout::~ReferenceDeviceTextLayout() 181cdf0e10cSrcweir { 182cdf0e10cSrcweir m_rReferenceDevice.Pop(); 183cdf0e10cSrcweir m_rTargetDevice.Pop(); 184cdf0e10cSrcweir } 185cdf0e10cSrcweir 186cdf0e10cSrcweir //-------------------------------------------------------------------- 187cdf0e10cSrcweir namespace 188cdf0e10cSrcweir { 189cdf0e10cSrcweir //................................................................ 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 //-------------------------------------------------------------------- 202cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 233cdf0e10cSrcweir long ReferenceDeviceTextLayout::GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const 234cdf0e10cSrcweir { 235cdf0e10cSrcweir return GetTextArray( _rText, NULL, _nStartIndex, _nLength ); 236cdf0e10cSrcweir } 237cdf0e10cSrcweir 238cdf0e10cSrcweir //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 264cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 278cdf0e10cSrcweir 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 //-------------------------------------------------------------------- 287cdf0e10cSrcweir bool ReferenceDeviceTextLayout::DecomposeTextRectAction() const 288cdf0e10cSrcweir { 289cdf0e10cSrcweir return true; 290cdf0e10cSrcweir } 291cdf0e10cSrcweir 292cdf0e10cSrcweir //-------------------------------------------------------------------- 293cdf0e10cSrcweir namespace 294cdf0e10cSrcweir { 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 } 302cdf0e10cSrcweir long unzoomBy( long _value, const Fraction& _zoom ) 303cdf0e10cSrcweir { 304cdf0e10cSrcweir return zoomBy( _value, Fraction( _zoom.GetDenominator(), _zoom.GetNumerator() ) ); 305cdf0e10cSrcweir } 306cdf0e10cSrcweir } 307cdf0e10cSrcweir 308cdf0e10cSrcweir //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 364cdf0e10cSrcweir ControlTextRenderer::ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice ) 365cdf0e10cSrcweir :m_pImpl( new ReferenceDeviceTextLayout( _rControl, _rTargetDevice, _rReferenceDevice ) ) 366cdf0e10cSrcweir { 367cdf0e10cSrcweir } 368cdf0e10cSrcweir 369cdf0e10cSrcweir //-------------------------------------------------------------------- 370cdf0e10cSrcweir ControlTextRenderer::~ControlTextRenderer() 371cdf0e10cSrcweir { 372cdf0e10cSrcweir } 373cdf0e10cSrcweir 374cdf0e10cSrcweir //-------------------------------------------------------------------- 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