1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: textlayout.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <canvas/canvastools.hxx>
38 #include <com/sun/star/rendering/TextDirection.hpp>
40 #include <vcl/metric.hxx>
41 #include <vcl/virdev.hxx>
43 #include <basegfx/matrix/b2dhommatrix.hxx>
44 #include <basegfx/numeric/ftools.hxx>
46 #include "impltools.hxx"
47 #include "textlayout.hxx"
49 #include <boost/scoped_array.hpp>
52 using namespace ::com::sun::star
;
58 void setupLayoutMode( OutputDevice
& rOutDev
,
59 sal_Int8 nTextDirection
)
61 // TODO(P3): avoid if already correctly set
63 switch( nTextDirection
)
68 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT
:
69 nLayoutMode
= TEXT_LAYOUT_BIDI_LTR
;
71 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT
:
72 nLayoutMode
= TEXT_LAYOUT_BIDI_LTR
| TEXT_LAYOUT_BIDI_STRONG
;
74 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT
:
75 nLayoutMode
= TEXT_LAYOUT_BIDI_RTL
;
77 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT
:
78 nLayoutMode
= TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_BIDI_STRONG
;
82 // set calculated layout mode. Origin is always the left edge,
83 // as required at the API spec
84 rOutDev
.SetLayoutMode( nLayoutMode
| TEXT_LAYOUT_TEXTORIGIN_LEFT
);
88 TextLayout::TextLayout( const rendering::StringContext
& aText
,
90 sal_Int64 nRandomSeed
,
91 const CanvasFont::Reference
& rFont
,
92 const uno::Reference
<rendering::XGraphicDevice
>& xDevice
,
93 const OutDevProviderSharedPtr
& rOutDev
) :
94 TextLayout_Base( m_aMutex
),
96 maLogicalAdvancements(),
99 mpOutDevProvider( rOutDev
),
100 mnTextDirection( nDirection
)
105 void SAL_CALL
TextLayout::disposing()
107 tools::LocalGuard aGuard
;
109 mpOutDevProvider
.reset();
115 uno::Sequence
< uno::Reference
< rendering::XPolyPolygon2D
> > SAL_CALL
TextLayout::queryTextShapes( ) throw (uno::RuntimeException
)
117 tools::LocalGuard aGuard
;
120 return uno::Sequence
< uno::Reference
< rendering::XPolyPolygon2D
> >();
123 uno::Sequence
< geometry::RealRectangle2D
> SAL_CALL
TextLayout::queryInkMeasures( ) throw (uno::RuntimeException
)
125 tools::LocalGuard aGuard
;
128 return uno::Sequence
< geometry::RealRectangle2D
>();
131 uno::Sequence
< geometry::RealRectangle2D
> SAL_CALL
TextLayout::queryMeasures( ) throw (uno::RuntimeException
)
133 tools::LocalGuard aGuard
;
136 return uno::Sequence
< geometry::RealRectangle2D
>();
139 uno::Sequence
< double > SAL_CALL
TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException
)
141 tools::LocalGuard aGuard
;
143 return maLogicalAdvancements
;
146 void SAL_CALL
TextLayout::applyLogicalAdvancements( const uno::Sequence
< double >& aAdvancements
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
148 tools::LocalGuard aGuard
;
150 ENSURE_ARG_OR_THROW( aAdvancements
.getLength() == maText
.Length
,
151 "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" );
153 maLogicalAdvancements
= aAdvancements
;
156 geometry::RealRectangle2D SAL_CALL
TextLayout::queryTextBounds( ) throw (uno::RuntimeException
)
158 tools::LocalGuard aGuard
;
160 if( !mpOutDevProvider
)
161 return geometry::RealRectangle2D();
163 OutputDevice
& rOutDev
= mpOutDevProvider
->getOutDev();
165 VirtualDevice
aVDev( rOutDev
);
166 aVDev
.SetFont( mpFont
->getVCLFont() );
168 // need metrics for Y offset, the XCanvas always renders
169 // relative to baseline
170 const ::FontMetric
& aMetric( aVDev
.GetFontMetric() );
172 setupLayoutMode( aVDev
, mnTextDirection
);
174 const sal_Int32
nAboveBaseline( -aMetric
.GetIntLeading() - aMetric
.GetAscent() );
175 const sal_Int32
nBelowBaseline( aMetric
.GetDescent() );
177 if( maLogicalAdvancements
.getLength() )
179 return geometry::RealRectangle2D( 0, nAboveBaseline
,
180 maLogicalAdvancements
[ maLogicalAdvancements
.getLength()-1 ],
185 return geometry::RealRectangle2D( 0, nAboveBaseline
,
188 ::canvas::tools::numeric_cast
<USHORT
>(maText
.StartPosition
),
189 ::canvas::tools::numeric_cast
<USHORT
>(maText
.Length
) ),
194 double SAL_CALL
TextLayout::justify( double nSize
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
196 tools::LocalGuard aGuard
;
204 double SAL_CALL
TextLayout::combinedJustify( const uno::Sequence
< uno::Reference
< rendering::XTextLayout
> >& aNextLayouts
,
205 double nSize
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
207 tools::LocalGuard aGuard
;
216 rendering::TextHit SAL_CALL
TextLayout::getTextHit( const geometry::RealPoint2D
& aHitPoint
) throw (uno::RuntimeException
)
218 tools::LocalGuard aGuard
;
223 return rendering::TextHit();
226 rendering::Caret SAL_CALL
TextLayout::getCaret( sal_Int32 nInsertionIndex
, sal_Bool bExcludeLigatures
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
)
228 tools::LocalGuard aGuard
;
230 (void)nInsertionIndex
;
231 (void)bExcludeLigatures
;
234 return rendering::Caret();
237 sal_Int32 SAL_CALL
TextLayout::getNextInsertionIndex( sal_Int32 nStartIndex
, sal_Int32 nCaretAdvancement
, sal_Bool bExcludeLigatures
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
)
239 tools::LocalGuard aGuard
;
242 (void)nCaretAdvancement
;
243 (void)bExcludeLigatures
;
249 uno::Reference
< rendering::XPolyPolygon2D
> SAL_CALL
TextLayout::queryVisualHighlighting( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
)
251 tools::LocalGuard aGuard
;
257 return uno::Reference
< rendering::XPolyPolygon2D
>();
260 uno::Reference
< rendering::XPolyPolygon2D
> SAL_CALL
TextLayout::queryLogicalHighlighting( sal_Int32 nStartIndex
, sal_Int32 nEndIndex
) throw (lang::IndexOutOfBoundsException
, uno::RuntimeException
)
262 tools::LocalGuard aGuard
;
268 return uno::Reference
< rendering::XPolyPolygon2D
>();
271 double SAL_CALL
TextLayout::getBaselineOffset( ) throw (uno::RuntimeException
)
273 tools::LocalGuard aGuard
;
279 sal_Int8 SAL_CALL
TextLayout::getMainTextDirection( ) throw (uno::RuntimeException
)
281 tools::LocalGuard aGuard
;
283 return mnTextDirection
;
286 uno::Reference
< rendering::XCanvasFont
> SAL_CALL
TextLayout::getFont( ) throw (uno::RuntimeException
)
288 tools::LocalGuard aGuard
;
290 return mpFont
.getRef();
293 rendering::StringContext SAL_CALL
TextLayout::getText( ) throw (uno::RuntimeException
)
295 tools::LocalGuard aGuard
;
300 bool TextLayout::draw( OutputDevice
& rOutDev
,
301 const Point
& rOutpos
,
302 const rendering::ViewState
& viewState
,
303 const rendering::RenderState
& renderState
) const
305 tools::LocalGuard aGuard
;
307 setupLayoutMode( rOutDev
, mnTextDirection
);
309 if( maLogicalAdvancements
.getLength() )
311 // TODO(P2): cache that
312 ::boost::scoped_array
< sal_Int32
> aOffsets(new sal_Int32
[maLogicalAdvancements
.getLength()]);
313 setupTextOffsets( aOffsets
.get(), maLogicalAdvancements
, viewState
, renderState
);
315 // TODO(F3): ensure correct length and termination for DX
316 // array (last entry _must_ contain the overall width)
318 rOutDev
.DrawTextArray( rOutpos
,
321 ::canvas::tools::numeric_cast
<USHORT
>(maText
.StartPosition
),
322 ::canvas::tools::numeric_cast
<USHORT
>(maText
.Length
) );
326 rOutDev
.DrawText( rOutpos
,
328 ::canvas::tools::numeric_cast
<USHORT
>(maText
.StartPosition
),
329 ::canvas::tools::numeric_cast
<USHORT
>(maText
.Length
) );
337 class OffsetTransformer
340 OffsetTransformer( const ::basegfx::B2DHomMatrix
& rMat
) :
345 sal_Int32
operator()( const double& rOffset
)
347 // This is an optimization of the normal rMat*[x,0]
348 // transformation of the advancement vector (in x
349 // direction), followed by a length calculation of the
350 // resulting vector: advancement' =
351 // ||rMat*[x,0]||. Since advancements are vectors, we
352 // can ignore translational components, thus if [x,0],
353 // it follows that rMat*[x,0]=[x',0] holds. Thus, we
354 // just have to calc the transformation of the x
357 // TODO(F2): Handle non-horizontal advancements!
358 return ::basegfx::fround( hypot(maMatrix
.get(0,0)*rOffset
,
359 maMatrix
.get(1,0)*rOffset
) );
363 ::basegfx::B2DHomMatrix maMatrix
;
367 void TextLayout::setupTextOffsets( sal_Int32
* outputOffsets
,
368 const uno::Sequence
< double >& inputOffsets
,
369 const rendering::ViewState
& viewState
,
370 const rendering::RenderState
& renderState
) const
372 ENSURE_OR_THROW( outputOffsets
!=NULL
,
373 "TextLayout::setupTextOffsets offsets NULL" );
375 ::basegfx::B2DHomMatrix aMatrix
;
377 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
,
381 // fill integer offsets
382 ::std::transform( const_cast< uno::Sequence
< double >& >(inputOffsets
).getConstArray(),
383 const_cast< uno::Sequence
< double >& >(inputOffsets
).getConstArray()+inputOffsets
.getLength(),
385 OffsetTransformer( aMatrix
) );
389 #define IMPLEMENTATION_NAME "VCLCanvas::TextLayout"
390 #define SERVICE_NAME "com.sun.star.rendering.TextLayout"
392 ::rtl::OUString SAL_CALL
TextLayout::getImplementationName() throw( uno::RuntimeException
)
394 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME
) );
397 sal_Bool SAL_CALL
TextLayout::supportsService( const ::rtl::OUString
& ServiceName
) throw( uno::RuntimeException
)
399 return ServiceName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME
) );
402 uno::Sequence
< ::rtl::OUString
> SAL_CALL
TextLayout::getSupportedServiceNames() throw( uno::RuntimeException
)
404 uno::Sequence
< ::rtl::OUString
> aRet(1);
405 aRet
[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME
) );