Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / vcl / textlayout.cxx
blob6cf534220e266149023082b28aacf458b4d5cc36
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <canvas/canvastools.hxx>
25 #include <com/sun/star/rendering/CompositeOperation.hpp>
26 #include <com/sun/star/rendering/TextDirection.hpp>
27 #include <cppuhelper/supportsservice.hxx>
29 #include <vcl/metric.hxx>
30 #include <vcl/virdev.hxx>
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <basegfx/numeric/ftools.hxx>
34 #include <basegfx/tools/canvastools.hxx>
36 #include "impltools.hxx"
37 #include "textlayout.hxx"
39 #include <boost/scoped_array.hpp>
41 using namespace ::com::sun::star;
43 namespace vclcanvas
45 namespace
47 void setupLayoutMode( OutputDevice& rOutDev,
48 sal_Int8 nTextDirection )
50 // TODO(P3): avoid if already correctly set
51 ComplexTextLayoutMode nLayoutMode = TEXT_LAYOUT_DEFAULT;
52 switch( nTextDirection )
54 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
55 break;
56 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
57 nLayoutMode = TEXT_LAYOUT_BIDI_STRONG;
58 break;
59 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
60 nLayoutMode = TEXT_LAYOUT_BIDI_RTL;
61 break;
62 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
63 nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
64 break;
65 default:
66 break;
69 // set calculated layout mode. Origin is always the left edge,
70 // as required at the API spec
71 rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
75 TextLayout::TextLayout( const rendering::StringContext& aText,
76 sal_Int8 nDirection,
77 sal_Int64 nRandomSeed,
78 const CanvasFont::Reference& rFont,
79 const uno::Reference<rendering::XGraphicDevice>& xDevice,
80 const OutDevProviderSharedPtr& rOutDev ) :
81 TextLayout_Base( m_aMutex ),
82 maText( aText ),
83 maLogicalAdvancements(),
84 mpFont( rFont ),
85 mxDevice( xDevice ),
86 mpOutDevProvider( rOutDev ),
87 mnTextDirection( nDirection )
89 (void)nRandomSeed;
92 void SAL_CALL TextLayout::disposing()
94 SolarMutexGuard aGuard;
96 mpOutDevProvider.reset();
97 mxDevice.clear();
98 mpFont.clear();
101 // XTextLayout
102 uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException, std::exception)
104 SolarMutexGuard aGuard;
106 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
107 ScopedVclPtrInstance< VirtualDevice > pVDev( rOutDev );
108 pVDev->SetFont( mpFont->getVCLFont() );
110 setupLayoutMode( *pVDev.get(), mnTextDirection );
112 const rendering::ViewState aViewState(
113 geometry::AffineMatrix2D(1,0,0, 0,1,0),
114 NULL);
116 rendering::RenderState aRenderState (
117 geometry::AffineMatrix2D(1,0,0,0,1,0),
118 NULL,
119 uno::Sequence<double>(4),
120 rendering::CompositeOperation::SOURCE);
122 ::boost::scoped_array< long > aOffsets(new long[maLogicalAdvancements.getLength()]);
123 setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState);
125 uno::Sequence< uno::Reference< rendering::XPolyPolygon2D> > aOutlineSequence;
126 ::basegfx::B2DPolyPolygonVector aOutlines;
127 if (pVDev->GetTextOutlines(
128 aOutlines,
129 maText.Text,
130 maText.StartPosition,
131 maText.StartPosition,
132 maText.Length,
133 false,
135 aOffsets.get()))
137 aOutlineSequence.realloc(aOutlines.size());
138 sal_Int32 nIndex (0);
139 for (::basegfx::B2DPolyPolygonVector::const_iterator
140 iOutline(aOutlines.begin()),
141 iEnd(aOutlines.end());
142 iOutline!=iEnd;
143 ++iOutline)
145 aOutlineSequence[nIndex++] = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
146 mxDevice,
147 *iOutline);
151 return aOutlineSequence;
154 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException, std::exception)
156 SolarMutexGuard aGuard;
159 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
160 ScopedVclPtrInstance< VirtualDevice > pVDev( rOutDev );
161 pVDev->SetFont( mpFont->getVCLFont() );
163 setupLayoutMode( *pVDev.get(), mnTextDirection );
165 const rendering::ViewState aViewState(
166 geometry::AffineMatrix2D(1,0,0, 0,1,0),
167 NULL);
169 rendering::RenderState aRenderState (
170 geometry::AffineMatrix2D(1,0,0,0,1,0),
171 NULL,
172 uno::Sequence<double>(4),
173 rendering::CompositeOperation::SOURCE);
175 ::boost::scoped_array< long > aOffsets(new long[maLogicalAdvancements.getLength()]);
176 setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState);
178 MetricVector aMetricVector;
179 uno::Sequence<geometry::RealRectangle2D> aBoundingBoxes;
180 if (pVDev->GetGlyphBoundRects(
181 Point(0,0),
182 maText.Text,
183 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
184 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length),
185 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
186 aMetricVector))
188 aBoundingBoxes.realloc(aMetricVector.size());
189 sal_Int32 nIndex (0);
190 for (MetricVector::const_iterator
191 iMetric(aMetricVector.begin()),
192 iEnd(aMetricVector.end());
193 iMetric!=iEnd;
194 ++iMetric)
196 aBoundingBoxes[nIndex++] = geometry::RealRectangle2D(
197 iMetric->getX(),
198 iMetric->getY(),
199 iMetric->getX() + iMetric->getWidth(),
200 iMetric->getY() + iMetric->getHeight());
203 return aBoundingBoxes;
206 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException, std::exception)
208 SolarMutexGuard aGuard;
210 // TODO(F1)
211 return uno::Sequence< geometry::RealRectangle2D >();
214 uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException, std::exception)
216 SolarMutexGuard aGuard;
218 return maLogicalAdvancements;
221 void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
223 SolarMutexGuard aGuard;
225 ENSURE_ARG_OR_THROW( aAdvancements.getLength() == maText.Length,
226 "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" );
228 maLogicalAdvancements = aAdvancements;
231 geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException, std::exception)
233 SolarMutexGuard aGuard;
235 if( !mpOutDevProvider )
236 return geometry::RealRectangle2D();
238 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
240 ScopedVclPtrInstance< VirtualDevice > pVDev( rOutDev );
241 pVDev->SetFont( mpFont->getVCLFont() );
243 // need metrics for Y offset, the XCanvas always renders
244 // relative to baseline
245 const ::FontMetric& aMetric( pVDev->GetFontMetric() );
247 setupLayoutMode( *pVDev.get(), mnTextDirection );
249 const sal_Int32 nAboveBaseline( /*-aMetric.GetIntLeading()*/ - aMetric.GetAscent() );
250 const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
252 if( maLogicalAdvancements.getLength() )
254 return geometry::RealRectangle2D( 0, nAboveBaseline,
255 maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ],
256 nBelowBaseline );
258 else
260 return geometry::RealRectangle2D( 0, nAboveBaseline,
261 pVDev->GetTextWidth(
262 maText.Text,
263 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
264 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ),
265 nBelowBaseline );
269 double SAL_CALL TextLayout::justify( double nSize ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
271 SolarMutexGuard aGuard;
273 (void)nSize;
275 // TODO(F1)
276 return 0.0;
279 double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& aNextLayouts,
280 double nSize ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
282 SolarMutexGuard aGuard;
284 (void)aNextLayouts;
285 (void)nSize;
287 // TODO(F1)
288 return 0.0;
291 rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& aHitPoint ) throw (uno::RuntimeException, std::exception)
293 SolarMutexGuard aGuard;
295 (void)aHitPoint;
297 // TODO(F1)
298 return rendering::TextHit();
301 rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
303 SolarMutexGuard aGuard;
305 (void)nInsertionIndex;
306 (void)bExcludeLigatures;
308 // TODO(F1)
309 return rendering::Caret();
312 sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
314 SolarMutexGuard aGuard;
316 (void)nStartIndex;
317 (void)nCaretAdvancement;
318 (void)bExcludeLigatures;
320 // TODO(F1)
321 return 0;
324 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
326 SolarMutexGuard aGuard;
328 (void)nStartIndex;
329 (void)nEndIndex;
331 // TODO(F1)
332 return uno::Reference< rendering::XPolyPolygon2D >();
335 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
337 SolarMutexGuard aGuard;
339 (void)nStartIndex;
340 (void)nEndIndex;
342 // TODO(F1)
343 return uno::Reference< rendering::XPolyPolygon2D >();
346 double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException, std::exception)
348 SolarMutexGuard aGuard;
350 // TODO(F1)
351 return 0.0;
354 sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException, std::exception)
356 SolarMutexGuard aGuard;
358 return mnTextDirection;
361 uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException, std::exception)
363 SolarMutexGuard aGuard;
365 return mpFont.get();
368 rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException, std::exception)
370 SolarMutexGuard aGuard;
372 return maText;
375 bool TextLayout::draw( OutputDevice& rOutDev,
376 const Point& rOutpos,
377 const rendering::ViewState& viewState,
378 const rendering::RenderState& renderState ) const
380 SolarMutexGuard aGuard;
382 setupLayoutMode( rOutDev, mnTextDirection );
384 if( maLogicalAdvancements.getLength() )
386 // TODO(P2): cache that
387 ::boost::scoped_array< long > aOffsets(new long[maLogicalAdvancements.getLength()]);
388 setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState );
390 // TODO(F3): ensure correct length and termination for DX
391 // array (last entry _must_ contain the overall width)
393 rOutDev.DrawTextArray( rOutpos,
394 maText.Text,
395 aOffsets.get(),
396 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
397 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
399 else
401 rOutDev.DrawText( rOutpos,
402 maText.Text,
403 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
404 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
407 return true;
410 namespace
412 class OffsetTransformer
414 public:
415 OffsetTransformer( const ::basegfx::B2DHomMatrix& rMat ) :
416 maMatrix( rMat )
420 sal_Int32 operator()( const double& rOffset )
422 // This is an optimization of the normal rMat*[x,0]
423 // transformation of the advancement vector (in x
424 // direction), followed by a length calculation of the
425 // resulting vector: advancement' =
426 // ||rMat*[x,0]||. Since advancements are vectors, we
427 // can ignore translational components, thus if [x,0],
428 // it follows that rMat*[x,0]=[x',0] holds. Thus, we
429 // just have to calc the transformation of the x
430 // component.
432 // TODO(F2): Handle non-horizontal advancements!
433 return ::basegfx::fround( hypot(maMatrix.get(0,0)*rOffset,
434 maMatrix.get(1,0)*rOffset) );
437 private:
438 ::basegfx::B2DHomMatrix maMatrix;
442 void TextLayout::setupTextOffsets( long* outputOffsets,
443 const uno::Sequence< double >& inputOffsets,
444 const rendering::ViewState& viewState,
445 const rendering::RenderState& renderState ) const
447 ENSURE_OR_THROW( outputOffsets!=NULL,
448 "TextLayout::setupTextOffsets offsets NULL" );
450 ::basegfx::B2DHomMatrix aMatrix;
452 ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
453 viewState,
454 renderState);
456 // fill integer offsets
457 ::std::transform( inputOffsets.getConstArray(),
458 inputOffsets.getConstArray()+inputOffsets.getLength(),
459 outputOffsets,
460 OffsetTransformer( aMatrix ) );
463 OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException, std::exception )
465 return OUString( "VCLCanvas::TextLayout" );
468 sal_Bool SAL_CALL TextLayout::supportsService( const OUString& ServiceName ) throw( uno::RuntimeException, std::exception )
470 return cppu::supportsService( this, ServiceName );
473 uno::Sequence< OUString > SAL_CALL TextLayout::getSupportedServiceNames() throw( uno::RuntimeException, std::exception )
475 uno::Sequence< OUString > aRet(1);
476 aRet[0] = "com.sun.star.rendering.TextLayout";
478 return aRet;
482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */