fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / canvas / source / vcl / textlayout.cxx
blobd8a0b14fbed54c8e113c5395783be5368d81608d
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>
28 #include <vcl/metric.hxx>
29 #include <vcl/virdev.hxx>
31 #include <basegfx/matrix/b2dhommatrix.hxx>
32 #include <basegfx/numeric/ftools.hxx>
33 #include <basegfx/tools/canvastools.hxx>
35 #include "impltools.hxx"
36 #include "textlayout.hxx"
38 #include <boost/scoped_array.hpp>
40 using namespace ::com::sun::star;
42 namespace vclcanvas
44 namespace
46 void setupLayoutMode( OutputDevice& rOutDev,
47 sal_Int8 nTextDirection )
49 // TODO(P3): avoid if already correctly set
50 sal_uIntPtr nLayoutMode;
51 switch( nTextDirection )
53 default:
54 nLayoutMode = 0;
55 break;
56 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
57 nLayoutMode = TEXT_LAYOUT_BIDI_LTR;
58 break;
59 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
60 nLayoutMode = TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG;
61 break;
62 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
63 nLayoutMode = TEXT_LAYOUT_BIDI_RTL;
64 break;
65 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
66 nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
67 break;
70 // set calculated layout mode. Origin is always the left edge,
71 // as required at the API spec
72 rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
76 TextLayout::TextLayout( const rendering::StringContext& aText,
77 sal_Int8 nDirection,
78 sal_Int64 nRandomSeed,
79 const CanvasFont::Reference& rFont,
80 const uno::Reference<rendering::XGraphicDevice>& xDevice,
81 const OutDevProviderSharedPtr& rOutDev ) :
82 TextLayout_Base( m_aMutex ),
83 maText( aText ),
84 maLogicalAdvancements(),
85 mpFont( rFont ),
86 mxDevice( xDevice ),
87 mpOutDevProvider( rOutDev ),
88 mnTextDirection( nDirection )
90 (void)nRandomSeed;
93 void SAL_CALL TextLayout::disposing()
95 SolarMutexGuard aGuard;
97 mpOutDevProvider.reset();
98 mxDevice.clear();
99 mpFont.reset();
102 // XTextLayout
103 uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException)
105 SolarMutexGuard aGuard;
107 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
108 VirtualDevice aVDev( rOutDev );
109 aVDev.SetFont( mpFont->getVCLFont() );
111 setupLayoutMode( aVDev, mnTextDirection );
113 const rendering::ViewState aViewState(
114 geometry::AffineMatrix2D(1,0,0, 0,1,0),
115 NULL);
117 rendering::RenderState aRenderState (
118 geometry::AffineMatrix2D(1,0,0,0,1,0),
119 NULL,
120 uno::Sequence<double>(4),
121 rendering::CompositeOperation::SOURCE);
123 ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]);
124 setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState);
126 uno::Sequence< uno::Reference< rendering::XPolyPolygon2D> > aOutlineSequence;
127 ::basegfx::B2DPolyPolygonVector aOutlines;
128 if (aVDev.GetTextOutlines(
129 aOutlines,
130 maText.Text,
131 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
132 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
133 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length),
134 sal_False,
136 aOffsets.get()))
138 aOutlineSequence.realloc(aOutlines.size());
139 sal_Int32 nIndex (0);
140 for (::basegfx::B2DPolyPolygonVector::const_iterator
141 iOutline(aOutlines.begin()),
142 iEnd(aOutlines.end());
143 iOutline!=iEnd;
144 ++iOutline)
146 aOutlineSequence[nIndex++] = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
147 mxDevice,
148 *iOutline);
152 return aOutlineSequence;
155 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException)
157 SolarMutexGuard aGuard;
160 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
161 VirtualDevice aVDev( rOutDev );
162 aVDev.SetFont( mpFont->getVCLFont() );
164 setupLayoutMode( aVDev, mnTextDirection );
166 const rendering::ViewState aViewState(
167 geometry::AffineMatrix2D(1,0,0, 0,1,0),
168 NULL);
170 rendering::RenderState aRenderState (
171 geometry::AffineMatrix2D(1,0,0,0,1,0),
172 NULL,
173 uno::Sequence<double>(4),
174 rendering::CompositeOperation::SOURCE);
176 ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]);
177 setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState);
179 MetricVector aMetricVector;
180 uno::Sequence<geometry::RealRectangle2D> aBoundingBoxes;
181 if (aVDev.GetGlyphBoundRects(
182 Point(0,0),
183 maText.Text,
184 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
185 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length),
186 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
187 aMetricVector))
189 aBoundingBoxes.realloc(aMetricVector.size());
190 sal_Int32 nIndex (0);
191 for (MetricVector::const_iterator
192 iMetric(aMetricVector.begin()),
193 iEnd(aMetricVector.end());
194 iMetric!=iEnd;
195 ++iMetric)
197 aBoundingBoxes[nIndex++] = geometry::RealRectangle2D(
198 iMetric->getX(),
199 iMetric->getY(),
200 iMetric->getX() + iMetric->getWidth(),
201 iMetric->getY() + iMetric->getHeight());
204 return aBoundingBoxes;
207 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException)
209 SolarMutexGuard aGuard;
211 // TODO(F1)
212 return uno::Sequence< geometry::RealRectangle2D >();
215 uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException)
217 SolarMutexGuard aGuard;
219 return maLogicalAdvancements;
222 void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException)
224 SolarMutexGuard aGuard;
226 ENSURE_ARG_OR_THROW( aAdvancements.getLength() == maText.Length,
227 "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" );
229 maLogicalAdvancements = aAdvancements;
232 geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException)
234 SolarMutexGuard aGuard;
236 if( !mpOutDevProvider )
237 return geometry::RealRectangle2D();
239 OutputDevice& rOutDev = mpOutDevProvider->getOutDev();
241 VirtualDevice aVDev( rOutDev );
242 aVDev.SetFont( mpFont->getVCLFont() );
244 // need metrics for Y offset, the XCanvas always renders
245 // relative to baseline
246 const ::FontMetric& aMetric( aVDev.GetFontMetric() );
248 setupLayoutMode( aVDev, mnTextDirection );
250 const sal_Int32 nAboveBaseline( /*-aMetric.GetIntLeading()*/ - aMetric.GetAscent() );
251 const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
253 if( maLogicalAdvancements.getLength() )
255 return geometry::RealRectangle2D( 0, nAboveBaseline,
256 maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ],
257 nBelowBaseline );
259 else
261 return geometry::RealRectangle2D( 0, nAboveBaseline,
262 aVDev.GetTextWidth(
263 maText.Text,
264 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
265 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ),
266 nBelowBaseline );
270 double SAL_CALL TextLayout::justify( double nSize ) throw (lang::IllegalArgumentException, uno::RuntimeException)
272 SolarMutexGuard aGuard;
274 (void)nSize;
276 // TODO(F1)
277 return 0.0;
280 double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& aNextLayouts,
281 double nSize ) throw (lang::IllegalArgumentException, uno::RuntimeException)
283 SolarMutexGuard aGuard;
285 (void)aNextLayouts;
286 (void)nSize;
288 // TODO(F1)
289 return 0.0;
292 rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& aHitPoint ) throw (uno::RuntimeException)
294 SolarMutexGuard aGuard;
296 (void)aHitPoint;
298 // TODO(F1)
299 return rendering::TextHit();
302 rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
304 SolarMutexGuard aGuard;
306 (void)nInsertionIndex;
307 (void)bExcludeLigatures;
309 // TODO(F1)
310 return rendering::Caret();
313 sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
315 SolarMutexGuard aGuard;
317 (void)nStartIndex;
318 (void)nCaretAdvancement;
319 (void)bExcludeLigatures;
321 // TODO(F1)
322 return 0;
325 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
327 SolarMutexGuard aGuard;
329 (void)nStartIndex;
330 (void)nEndIndex;
332 // TODO(F1)
333 return uno::Reference< rendering::XPolyPolygon2D >();
336 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
338 SolarMutexGuard aGuard;
340 (void)nStartIndex;
341 (void)nEndIndex;
343 // TODO(F1)
344 return uno::Reference< rendering::XPolyPolygon2D >();
347 double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException)
349 SolarMutexGuard aGuard;
351 // TODO(F1)
352 return 0.0;
355 sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException)
357 SolarMutexGuard aGuard;
359 return mnTextDirection;
362 uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException)
364 SolarMutexGuard aGuard;
366 return mpFont.getRef();
369 rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException)
371 SolarMutexGuard aGuard;
373 return maText;
376 bool TextLayout::draw( OutputDevice& rOutDev,
377 const Point& rOutpos,
378 const rendering::ViewState& viewState,
379 const rendering::RenderState& renderState ) const
381 SolarMutexGuard aGuard;
383 setupLayoutMode( rOutDev, mnTextDirection );
385 if( maLogicalAdvancements.getLength() )
387 // TODO(P2): cache that
388 ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]);
389 setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState );
391 // TODO(F3): ensure correct length and termination for DX
392 // array (last entry _must_ contain the overall width)
394 rOutDev.DrawTextArray( rOutpos,
395 maText.Text,
396 aOffsets.get(),
397 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
398 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
400 else
402 rOutDev.DrawText( rOutpos,
403 maText.Text,
404 ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
405 ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
408 return true;
411 namespace
413 class OffsetTransformer
415 public:
416 OffsetTransformer( const ::basegfx::B2DHomMatrix& rMat ) :
417 maMatrix( rMat )
421 sal_Int32 operator()( const double& rOffset )
423 // This is an optimization of the normal rMat*[x,0]
424 // transformation of the advancement vector (in x
425 // direction), followed by a length calculation of the
426 // resulting vector: advancement' =
427 // ||rMat*[x,0]||. Since advancements are vectors, we
428 // can ignore translational components, thus if [x,0],
429 // it follows that rMat*[x,0]=[x',0] holds. Thus, we
430 // just have to calc the transformation of the x
431 // component.
433 // TODO(F2): Handle non-horizontal advancements!
434 return ::basegfx::fround( hypot(maMatrix.get(0,0)*rOffset,
435 maMatrix.get(1,0)*rOffset) );
438 private:
439 ::basegfx::B2DHomMatrix maMatrix;
443 void TextLayout::setupTextOffsets( sal_Int32* outputOffsets,
444 const uno::Sequence< double >& inputOffsets,
445 const rendering::ViewState& viewState,
446 const rendering::RenderState& renderState ) const
448 ENSURE_OR_THROW( outputOffsets!=NULL,
449 "TextLayout::setupTextOffsets offsets NULL" );
451 ::basegfx::B2DHomMatrix aMatrix;
453 ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
454 viewState,
455 renderState);
457 // fill integer offsets
458 ::std::transform( inputOffsets.getConstArray(),
459 inputOffsets.getConstArray()+inputOffsets.getLength(),
460 outputOffsets,
461 OffsetTransformer( aMatrix ) );
465 #define IMPLEMENTATION_NAME "VCLCanvas::TextLayout"
466 #define SERVICE_NAME "com.sun.star.rendering.TextLayout"
468 OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException )
470 return OUString( IMPLEMENTATION_NAME );
473 sal_Bool SAL_CALL TextLayout::supportsService( const OUString& ServiceName ) throw( uno::RuntimeException )
475 return ServiceName == SERVICE_NAME;
478 uno::Sequence< OUString > SAL_CALL TextLayout::getSupportedServiceNames() throw( uno::RuntimeException )
480 uno::Sequence< OUString > aRet(1);
481 aRet[0] = OUString( SERVICE_NAME );
483 return aRet;
487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */