CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / canvas / source / cairo / cairo_textlayout.cxx
blob725a6ae0f2a605db32f03ed1c6f51b7c5e371853
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
31 #include <math.h>
33 #include <canvas/debug.hxx>
34 #include <canvas/verbosetrace.hxx>
35 #include <tools/diagnose_ex.h>
37 #include <vcl/metric.hxx>
38 #include <vcl/virdev.hxx>
40 #ifdef WNT
41 #include <tools/prewin.h>
42 #include <windows.h>
43 #include <tools/postwin.h>
44 #ifdef max
45 #undef max
46 #endif
47 #ifdef min
48 #undef min
49 #endif
50 #endif
51 #include <vcl/sysdata.hxx>
53 #include <basegfx/matrix/b2dhommatrix.hxx>
54 #include <basegfx/numeric/ftools.hxx>
56 #include <boost/scoped_array.hpp>
58 #include "cairo_textlayout.hxx"
59 #include "cairo_spritecanvas.hxx"
61 #ifdef CAIRO_HAS_QUARTZ_SURFACE
62 # include "cairo_quartz_cairo.hxx"
63 #elif defined CAIRO_HAS_WIN32_SURFACE
64 # include "cairo_win32_cairo.hxx"
65 # include <cairo-win32.h>
66 #elif defined CAIRO_HAS_XLIB_SURFACE
67 # include "cairo_xlib_cairo.hxx"
68 # include <cairo-ft.h>
69 #else
70 # error Native API needed.
71 #endif
73 using namespace ::cairo;
74 using namespace ::com::sun::star;
76 namespace cairocanvas
78 namespace
80 void setupLayoutMode( OutputDevice& rOutDev,
81 sal_Int8 nTextDirection )
83 // TODO(P3): avoid if already correctly set
84 sal_uLong nLayoutMode;
85 switch( nTextDirection )
87 default:
88 nLayoutMode = 0;
89 break;
90 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
91 nLayoutMode = TEXT_LAYOUT_BIDI_LTR;
92 break;
93 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
94 nLayoutMode = TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG;
95 break;
96 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
97 nLayoutMode = TEXT_LAYOUT_BIDI_RTL;
98 break;
99 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
100 nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
101 break;
104 // set calculated layout mode. Origin is always the left edge,
105 // as required at the API spec
106 rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
109 bool compareFallbacks(const SystemGlyphData&rA, const SystemGlyphData &rB)
111 return rA.fallbacklevel < rB.fallbacklevel;
115 TextLayout::TextLayout( const rendering::StringContext& aText,
116 sal_Int8 nDirection,
117 sal_Int64 /*nRandomSeed*/,
118 const CanvasFont::Reference& rFont,
119 const SurfaceProviderRef& rRefDevice ) :
120 TextLayout_Base( m_aMutex ),
121 maText( aText ),
122 maLogicalAdvancements(),
123 mpFont( rFont ),
124 mpRefDevice( rRefDevice ),
125 mnTextDirection( nDirection )
129 TextLayout::~TextLayout()
133 void SAL_CALL TextLayout::disposing()
135 ::osl::MutexGuard aGuard( m_aMutex );
137 mpFont.reset();
138 mpRefDevice.clear();
141 // XTextLayout
142 uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException)
144 ::osl::MutexGuard aGuard( m_aMutex );
146 // TODO
147 return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >();
150 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException)
152 ::osl::MutexGuard aGuard( m_aMutex );
154 // TODO
155 return uno::Sequence< geometry::RealRectangle2D >();
158 uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException)
160 ::osl::MutexGuard aGuard( m_aMutex );
162 // TODO
163 return uno::Sequence< geometry::RealRectangle2D >();
166 uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException)
168 ::osl::MutexGuard aGuard( m_aMutex );
170 return maLogicalAdvancements;
173 void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException)
175 ::osl::MutexGuard aGuard( m_aMutex );
177 if( aAdvancements.getLength() != maText.Length )
179 OSL_TRACE( "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" );
180 throw lang::IllegalArgumentException();
183 maLogicalAdvancements = aAdvancements;
186 geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException)
188 ::osl::MutexGuard aGuard( m_aMutex );
190 OutputDevice* pOutDev = mpRefDevice->getOutputDevice();
191 if( !pOutDev )
192 return geometry::RealRectangle2D();
194 VirtualDevice aVDev( *pOutDev );
195 aVDev.SetFont( mpFont->getVCLFont() );
197 // need metrics for Y offset, the XCanvas always renders
198 // relative to baseline
199 const ::FontMetric& aMetric( aVDev.GetFontMetric() );
201 setupLayoutMode( aVDev, mnTextDirection );
203 const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() );
204 const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
206 if( maLogicalAdvancements.getLength() )
208 return geometry::RealRectangle2D( 0, nAboveBaseline,
209 maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ],
210 nBelowBaseline );
212 else
214 return geometry::RealRectangle2D( 0, nAboveBaseline,
215 aVDev.GetTextWidth(
216 maText.Text,
217 ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition),
218 ::canvas::tools::numeric_cast<USHORT>(maText.Length) ),
219 nBelowBaseline );
223 double SAL_CALL TextLayout::justify( double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
225 ::osl::MutexGuard aGuard( m_aMutex );
227 // TODO
228 return 0.0;
231 double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/,
232 double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
234 ::osl::MutexGuard aGuard( m_aMutex );
236 // TODO
237 return 0.0;
240 rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ ) throw (uno::RuntimeException)
242 ::osl::MutexGuard aGuard( m_aMutex );
244 // TODO
245 return rendering::TextHit();
248 rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/,
249 sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
251 ::osl::MutexGuard aGuard( m_aMutex );
253 // TODO
254 return rendering::Caret();
257 sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/,
258 sal_Int32 /*nCaretAdvancement*/,
259 sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
261 ::osl::MutexGuard aGuard( m_aMutex );
263 // TODO
264 return 0;
267 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/,
268 sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
270 ::osl::MutexGuard aGuard( m_aMutex );
272 // TODO
273 return uno::Reference< rendering::XPolyPolygon2D >();
276 uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/,
277 sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
279 ::osl::MutexGuard aGuard( m_aMutex );
281 // TODO
282 return uno::Reference< rendering::XPolyPolygon2D >();
285 double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException)
287 ::osl::MutexGuard aGuard( m_aMutex );
289 // TODO
290 return 0.0;
293 sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException)
295 ::osl::MutexGuard aGuard( m_aMutex );
297 return mnTextDirection;
300 uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException)
302 ::osl::MutexGuard aGuard( m_aMutex );
304 return mpFont.getRef();
307 rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException)
309 ::osl::MutexGuard aGuard( m_aMutex );
311 return maText;
314 void TextLayout::useFont( Cairo* pCairo )
316 rendering::FontRequest aFontRequest = mpFont->getFontRequest();
317 rendering::FontInfo aFontInfo = aFontRequest.FontDescription;
319 cairo_select_font_face( pCairo, ::rtl::OUStringToOString( aFontInfo.FamilyName, RTL_TEXTENCODING_UTF8 ), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL );
320 cairo_set_font_size( pCairo, aFontRequest.CellSize );
323 /** TextLayout:draw
325 * This function uses the "toy" api of the cairo library
328 bool TextLayout::draw( Cairo* pCairo )
330 ::osl::MutexGuard aGuard( m_aMutex );
332 ::rtl::OUString aSubText = maText.Text.copy( maText.StartPosition, maText.Length );
333 ::rtl::OString aUTF8String = ::rtl::OUStringToOString( aSubText, RTL_TEXTENCODING_UTF8 );
335 cairo_save( pCairo );
336 /* move to 0, 0 as cairo_show_text advances current point and current point is not restored by cairo_restore.
337 before we were depending on unmodified current point which I believed was preserved by save/restore */
338 cairo_move_to( pCairo, 0, 0 );
339 useFont( pCairo );
340 cairo_show_text( pCairo, aUTF8String );
341 cairo_restore( pCairo );
343 return true;
348 * TextLayout::isCairoRenderable
350 * Features currenly not supported by Cairo (VCL rendering is used as fallback):
351 * - vertical glyphs
353 * @return true, if text/font can be rendered with cairo
355 bool TextLayout::isCairoRenderable(SystemFontData aSysFontData) const
357 #if defined UNX && !defined QUARTZ
358 // is font usable?
359 if (!aSysFontData.nFontId) return false;
360 #endif
362 // vertical glyph rendering is not supported in cairo for now
363 if (aSysFontData.bVerticalCharacterType) {
364 OSL_TRACE(":cairocanvas::TextLayout::isCairoRenderable(): ***************** VERTICAL CHARACTER STYLE!!! ****************");
365 return false;
368 return true;
372 * TextLayout::draw
374 * Cairo-based text rendering. Draw text directly on the cairo surface with cairo fonts.
375 * Avoid using VCL VirtualDevices for that, bypassing VCL DrawText functions, when possible
377 * Note: some text effects are not rendered due to lacking generic canvas or cairo canvas
378 * implementation. See issues 92657, 92658, 92659, 92660, 97529
380 * @return true, if successful
382 bool TextLayout::draw( SurfaceSharedPtr& pSurface,
383 OutputDevice& rOutDev,
384 const Point& rOutpos,
385 const rendering::ViewState& viewState,
386 const rendering::RenderState& renderState ) const
388 ::osl::MutexGuard aGuard( m_aMutex );
389 SystemTextLayoutData aSysLayoutData;
390 #if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
391 LOGFONTW logfont;
392 #endif
393 setupLayoutMode( rOutDev, mnTextDirection );
395 // TODO(P2): cache that
396 ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]);
398 if( maLogicalAdvancements.getLength() )
400 setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState );
402 // TODO(F3): ensure correct length and termination for DX
403 // array (last entry _must_ contain the overall width)
406 aSysLayoutData = rOutDev.GetSysTextLayoutData(rOutpos, maText.Text,
407 ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition),
408 ::canvas::tools::numeric_cast<USHORT>(maText.Length),
409 maLogicalAdvancements.getLength() ? aOffsets.get() : NULL);
411 // Sort them so that all glyphs on the same glyph fallback level are consecutive
412 std::sort(aSysLayoutData.rGlyphData.begin(), aSysLayoutData.rGlyphData.end(), compareFallbacks);
413 bool bCairoRenderable = true;
415 //Pull all the fonts we need to render the text
416 typedef std::pair<SystemFontData,int> FontLevel;
417 typedef std::vector<FontLevel> FontLevelVector;
418 FontLevelVector aFontData;
419 SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
420 const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
421 for( ; aIter != aEnd; ++aIter )
423 if( aFontData.empty() || aIter->fallbacklevel != aFontData.back().second )
425 aFontData.push_back(FontLevel(rOutDev.GetSysFontData(aIter->fallbacklevel),
426 aIter->fallbacklevel));
427 if( !isCairoRenderable(aFontData.back().first) )
429 bCairoRenderable = false;
430 OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK %s%s%s%s - %s",
431 maLogicalAdvancements.getLength() ? "ADV " : "",
432 aFontData.back().first.bAntialias ? "AA " : "",
433 aFontData.back().first.bFakeBold ? "FB " : "",
434 aFontData.back().first.bFakeItalic ? "FI " : "",
435 ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ),
436 RTL_TEXTENCODING_UTF8 ).getStr());
437 break;
442 // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font being used.
443 // The fallback checks need to be done after final font is known.
444 if (!bCairoRenderable) // VCL FALLBACKS
446 if (maLogicalAdvancements.getLength()) // VCL FALLBACK - with glyph advances
448 rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(),
449 ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition),
450 ::canvas::tools::numeric_cast<USHORT>(maText.Length) );
451 return true;
453 else // VCL FALLBACK - without advances
455 rOutDev.DrawText( rOutpos, maText.Text,
456 ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition),
457 ::canvas::tools::numeric_cast<USHORT>(maText.Length) );
458 return true;
462 if (aSysLayoutData.rGlyphData.empty()) return false; //??? false?
465 * Setup platform independent glyph vector into cairo-based glyphs vector.
468 // Loop through the fonts used and render the matching glyphs for each
469 FontLevelVector::const_iterator aFontDataIter = aFontData.begin();
470 const FontLevelVector::const_iterator aFontDataEnd = aFontData.end();
471 for( ; aFontDataIter != aFontDataEnd; ++aFontDataIter )
473 const SystemFontData &rSysFontData = aFontDataIter->first;
475 // setup glyphs
476 std::vector<cairo_glyph_t> cairo_glyphs;
477 cairo_glyphs.reserve( 256 );
479 SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
480 const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
481 for( ; aIter != aEnd; ++aIter )
483 SystemGlyphData systemGlyph = *aIter;
484 if( systemGlyph.fallbacklevel != aFontDataIter->second )
485 continue;
487 cairo_glyph_t aGlyph;
488 aGlyph.index = systemGlyph.index;
489 #ifdef CAIRO_HAS_WIN32_SURFACE
490 // Cairo requires standard glyph indexes (ETO_GLYPH_INDEX), while vcl/win/* uses ucs4 chars.
491 // Convert to standard indexes
492 aGlyph.index = cairo::ucs4toindex((unsigned int) aGlyph.index, rSysFontData.hFont);
493 #endif
494 aGlyph.x = systemGlyph.x;
495 aGlyph.y = systemGlyph.y;
496 cairo_glyphs.push_back(aGlyph);
499 if (cairo_glyphs.empty())
500 continue;
503 * Setup font
505 cairo_font_face_t* font_face = NULL;
507 #ifdef CAIRO_HAS_QUARTZ_SURFACE
508 // TODO: use cairo_quartz_font_face_create_for_cgfont(cgFont)
509 // when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend.
510 font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) rSysFontData.aATSUFontID);
512 #elif defined CAIRO_HAS_WIN32_SURFACE
513 #if (OSL_DEBUG_LEVEL > 1)
514 GetObjectW( rSysFontData.hFont, sizeof(logfont), &logfont );
515 #endif
516 // Note: cairo library uses logfont fallbacks when lfEscapement, lfOrientation and lfWidth are not zero.
517 // VCL always has non-zero value for lfWidth
518 font_face = cairo_win32_font_face_create_for_hfont(rSysFontData.hFont);
520 #elif defined CAIRO_HAS_XLIB_SURFACE
521 font_face = cairo_ft_font_face_create_for_ft_face((FT_Face)rSysFontData.nFontId,
522 rSysFontData.nFontFlags);
523 #else
524 # error Native API needed.
525 #endif
527 CairoSharedPtr pSCairo = pSurface->getCairo();
529 cairo_set_font_face( pSCairo.get(), font_face);
531 // create default font options. cairo_get_font_options() does not retrieve the surface defaults,
532 // only what has been set before with cairo_set_font_options()
533 cairo_font_options_t* options = cairo_font_options_create();
534 if (rSysFontData.bAntialias) {
535 // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas,
536 // so we're not using CAIRO_ANTIALIAS_SUBPIXEL
537 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
539 cairo_set_font_options( pSCairo.get(), options);
541 // Font color
542 Color mTextColor = rOutDev.GetTextColor();
543 cairo_set_source_rgb(pSCairo.get(),
544 mTextColor.GetRed()/255.0,
545 mTextColor.GetGreen()/255.0,
546 mTextColor.GetBlue()/255.0);
548 // Font rotation and scaling
549 cairo_matrix_t m;
550 Font aFont = rOutDev.GetFont();
551 FontMetric aMetric( rOutDev.GetFontMetric(aFont) );
552 long nWidth = 0;
554 // width calculation is deep magic and platform/font dependant.
555 // width == 0 means no scaling, and usually width == height means the same.
556 // Other values mean horizontal scaling (narrow or stretching)
557 // see issue #101566
559 //proper scale calculation across platforms
560 if (aFont.GetWidth() == 0) {
561 nWidth = aFont.GetHeight();
562 } else {
563 // any scaling needs to be relative to the platform-dependent definition
564 // of height of the font
565 nWidth = aFont.GetWidth() * aFont.GetHeight() / aMetric.GetHeight();
568 cairo_matrix_init_identity(&m);
570 if (aSysLayoutData.orientation) cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0);
572 cairo_matrix_scale(&m, nWidth, aFont.GetHeight());
574 //faux italics
575 if (rSysFontData.bFakeItalic) m.xy = -m.xx * 0x6000L / 0x10000L;
577 cairo_set_font_matrix(pSCairo.get(), &m);
579 OSL_TRACE("\r\n:cairocanvas::TextLayout::draw(S,O,p,v,r): Size:(%d,%d), W:%d->%d, Pos (%d,%d), G(%d,%d,%d) %s%s%s%s || Name:%s - %s",
580 aFont.GetWidth(),
581 aFont.GetHeight(),
582 aMetric.GetWidth(),
583 nWidth,
584 (int) rOutpos.X(),
585 (int) rOutpos.Y(),
586 cairo_glyphs[0].index, cairo_glyphs[1].index, cairo_glyphs[2].index,
587 maLogicalAdvancements.getLength() ? "ADV " : "",
588 rSysFontData.bAntialias ? "AA " : "",
589 rSysFontData.bFakeBold ? "FB " : "",
590 rSysFontData.bFakeItalic ? "FI " : "",
591 #if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
592 ::rtl::OUStringToOString( reinterpret_cast<const sal_Unicode*> (logfont.lfFaceName), RTL_TEXTENCODING_UTF8 ).getStr(),
593 #else
594 ::rtl::OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
595 #endif
596 ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ),
597 RTL_TEXTENCODING_UTF8 ).getStr()
600 cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
602 //faux bold
603 if (rSysFontData.bFakeBold) {
604 double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetHeight() );
605 int total_steps = 2 * ((int) (bold_dx + 0.5));
607 // loop to draw the text for every half pixel of displacement
608 for (int nSteps = 0; nSteps < total_steps; nSteps++) {
609 for(int nGlyphIdx = 0; nGlyphIdx < (int) cairo_glyphs.size(); nGlyphIdx++) {
610 cairo_glyphs[nGlyphIdx].x += bold_dx * nSteps / total_steps;
612 cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
614 OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:%d", (int) bold_dx);
617 cairo_restore( pSCairo.get() );
618 cairo_font_face_destroy(font_face);
620 return true;
624 namespace
626 class OffsetTransformer
628 public:
629 OffsetTransformer( const ::basegfx::B2DHomMatrix& rMat ) :
630 maMatrix( rMat )
634 sal_Int32 operator()( const double& rOffset )
636 // This is an optimization of the normal rMat*[x,0]
637 // transformation of the advancement vector (in x
638 // direction), followed by a length calculation of the
639 // resulting vector: advancement' =
640 // ||rMat*[x,0]||. Since advancements are vectors, we
641 // can ignore translational components, thus if [x,0],
642 // it follows that rMat*[x,0]=[x',0] holds. Thus, we
643 // just have to calc the transformation of the x
644 // component.
646 // TODO(F2): Handle non-horizontal advancements!
647 return ::basegfx::fround( hypot(maMatrix.get(0,0)*rOffset,
648 maMatrix.get(1,0)*rOffset) );
651 private:
652 ::basegfx::B2DHomMatrix maMatrix;
656 void TextLayout::setupTextOffsets( sal_Int32* outputOffsets,
657 const uno::Sequence< double >& inputOffsets,
658 const rendering::ViewState& viewState,
659 const rendering::RenderState& renderState ) const
661 ENSURE_OR_THROW( outputOffsets!=NULL,
662 "TextLayout::setupTextOffsets offsets NULL" );
664 ::basegfx::B2DHomMatrix aMatrix;
666 ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
667 viewState,
668 renderState);
670 // fill integer offsets
671 ::std::transform( const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray(),
672 const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray()+inputOffsets.getLength(),
673 outputOffsets,
674 OffsetTransformer( aMatrix ) );
677 #define SERVICE_NAME "com.sun.star.rendering.TextLayout"
678 #define IMPLEMENTATION_NAME "CairoCanvas::TextLayout"
680 ::rtl::OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException )
682 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
685 sal_Bool SAL_CALL TextLayout::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException )
687 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
690 uno::Sequence< ::rtl::OUString > SAL_CALL TextLayout::getSupportedServiceNames() throw( uno::RuntimeException )
692 uno::Sequence< ::rtl::OUString > aRet(1);
693 aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
695 return aRet;