fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / canvas / source / cairo / cairo_canvashelper_text.cxx
blobd65f2de34ab24c2f1cce0e749ac6bf16d34c7064
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 .
20 #include <canvas/debug.hxx>
21 #include <canvas/canvastools.hxx>
22 #include <tools/diagnose_ex.h>
24 #include <vcl/virdev.hxx>
25 #include <vcl/metric.hxx>
26 #include <vcl/canvastools.hxx>
28 #include <basegfx/polygon/b2dpolypolygon.hxx>
29 #include <basegfx/tools/canvastools.hxx>
31 #include "cairo_canvasfont.hxx"
32 #include "cairo_textlayout.hxx"
33 #include "cairo_canvashelper.hxx"
35 using namespace ::cairo;
36 using namespace ::com::sun::star;
38 namespace cairocanvas
40 enum ColorType
42 LINE_COLOR, FILL_COLOR, TEXT_COLOR, IGNORE_COLOR
45 uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* ,
46 const rendering::FontRequest& fontRequest,
47 const uno::Sequence< beans::PropertyValue >& extraFontProperties,
48 const geometry::Matrix2D& fontMatrix )
50 return uno::Reference< rendering::XCanvasFont >( new CanvasFont( fontRequest, extraFontProperties, fontMatrix, mpSurfaceProvider ));
53 uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* ,
54 const rendering::FontInfo& /*aFilter*/,
55 const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ )
57 // TODO
58 return uno::Sequence< rendering::FontInfo >();
61 static bool
62 setupFontTransform( ::OutputDevice& rOutDev,
63 ::Point& o_rPoint,
64 ::Font& io_rVCLFont,
65 const rendering::ViewState& rViewState,
66 const rendering::RenderState& rRenderState )
68 ::basegfx::B2DHomMatrix aMatrix;
70 ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
71 rViewState,
72 rRenderState);
74 ::basegfx::B2DTuple aScale;
75 ::basegfx::B2DTuple aTranslate;
76 double nRotate, nShearX;
78 aMatrix.decompose( aScale, aTranslate, nRotate, nShearX );
80 // query font metric _before_ tampering with width and height
81 if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) )
83 // retrieve true font width
84 const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() );
86 const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) );
88 if( !nScaledFontWidth )
90 // scale is smaller than one pixel - disable text
91 // output altogether
92 return false;
95 io_rVCLFont.SetWidth( nScaledFontWidth );
98 if( !::rtl::math::approxEqual(aScale.getY(), 1.0) )
100 const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() );
101 io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) );
104 io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) );
106 // TODO(F2): Missing functionality in VCL: shearing
107 o_rPoint.X() = ::basegfx::fround(aTranslate.getX());
108 o_rPoint.Y() = ::basegfx::fround(aTranslate.getY());
110 return true;
113 static int
114 setupOutDevState( OutputDevice& rOutDev,
115 const rendering::XCanvas* pOwner,
116 const rendering::ViewState& viewState,
117 const rendering::RenderState& renderState,
118 ColorType eColorType )
120 ::canvas::tools::verifyInput( renderState,
121 BOOST_CURRENT_FUNCTION,
122 const_cast<rendering::XCanvas*>(pOwner), // only for refcount
124 eColorType == IGNORE_COLOR ? 0 : 3 );
126 int nTransparency(0);
128 // TODO(P2): Don't change clipping all the time, maintain current clip
129 // state and change only when update is necessary
131 // accumulate non-empty clips into one region
132 // ==========================================
134 Region aClipRegion;
136 if( viewState.Clip.is() )
138 ::basegfx::B2DPolyPolygon aClipPoly(
139 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
140 viewState.Clip) );
142 if( aClipPoly.count() )
144 // setup non-empty clipping
145 ::basegfx::B2DHomMatrix aMatrix;
146 aClipPoly.transform(
147 ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix,
148 viewState.AffineTransform ) );
150 aClipRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
154 if( renderState.Clip.is() )
156 ::basegfx::B2DPolyPolygon aClipPoly(
157 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
158 renderState.Clip) );
160 ::basegfx::B2DHomMatrix aMatrix;
161 aClipPoly.transform(
162 ::canvas::tools::mergeViewAndRenderTransform( aMatrix,
163 viewState,
164 renderState ) );
166 if( aClipPoly.count() )
168 // setup non-empty clipping
169 Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
171 if( aClipRegion.IsEmpty() )
172 aClipRegion = aRegion;
173 else
174 aClipRegion.Intersect( aRegion );
176 else
178 // clip polygon is empty
179 aClipRegion.SetEmpty();
183 // setup accumulated clip region. Note that setting an
184 // empty clip region denotes "clip everything" on the
185 // OutputDevice (which is why we translate that into
186 // SetClipRegion() here). When both view and render clip
187 // are empty, aClipRegion remains default-constructed,
188 // i.e. empty, too.
189 if( aClipRegion.IsEmpty() )
191 rOutDev.SetClipRegion();
193 else
195 rOutDev.SetClipRegion( aClipRegion );
198 if( eColorType != IGNORE_COLOR )
200 Color aColor( COL_WHITE );
202 if( renderState.DeviceColor.getLength() > 2 )
204 aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( renderState.DeviceColor );
207 // extract alpha, and make color opaque
208 // afterwards. Otherwise, OutputDevice won't draw anything
209 nTransparency = aColor.GetTransparency();
210 aColor.SetTransparency(0);
212 switch( eColorType )
214 case LINE_COLOR:
215 rOutDev.SetLineColor( aColor );
216 rOutDev.SetFillColor();
218 break;
220 case FILL_COLOR:
221 rOutDev.SetFillColor( aColor );
222 rOutDev.SetLineColor();
224 break;
226 case TEXT_COLOR:
227 rOutDev.SetTextColor( aColor );
229 break;
231 default:
232 ENSURE_OR_THROW( false,
233 "CanvasHelper::setupOutDevState(): Unexpected color type");
234 break;
238 return nTransparency;
241 bool setupTextOutput( OutputDevice& rOutDev,
242 const rendering::XCanvas* pOwner,
243 ::Point& o_rOutPos,
244 const rendering::ViewState& viewState,
245 const rendering::RenderState& renderState,
246 const uno::Reference< rendering::XCanvasFont >& xFont )
248 setupOutDevState( rOutDev, pOwner, viewState, renderState, TEXT_COLOR );
250 ::Font aVCLFont;
252 CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() );
254 ENSURE_ARG_OR_THROW( pFont,
255 "CanvasHelper::setupTextOutput(): Font not compatible with this canvas" );
257 aVCLFont = pFont->getVCLFont();
259 Color aColor( COL_BLACK );
261 if( renderState.DeviceColor.getLength() > 2 )
263 aColor = ::vcl::unotools::stdColorSpaceSequenceToColor(renderState.DeviceColor );
266 // setup font color
267 aVCLFont.SetColor( aColor );
268 aVCLFont.SetFillColor( aColor );
270 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
271 if( !setupFontTransform( rOutDev, o_rOutPos, aVCLFont, viewState, renderState ) )
272 return false;
274 rOutDev.SetFont( aVCLFont );
277 return true;
280 uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* pOwner,
281 const rendering::StringContext& text,
282 const uno::Reference< rendering::XCanvasFont >& xFont,
283 const rendering::ViewState& viewState,
284 const rendering::RenderState& renderState,
285 sal_Int8 textDirection )
287 #ifdef CAIRO_CANVAS_PERF_TRACE
288 struct timespec aTimer;
289 mxDevice->startPerfTrace( &aTimer );
290 #endif
292 ENSURE_ARG_OR_THROW( xFont.is(),
293 "CanvasHelper::drawText(): font is NULL");
295 if( !mpVirtualDevice )
296 mpVirtualDevice = mpSurface->createVirtualDevice();
298 if( mpVirtualDevice )
300 #if defined CAIRO_HAS_WIN32_SURFACE
301 // FIXME: Some kind of work-araound...
302 cairo_rectangle (mpSurface->getCairo().get(), 0, 0, 0, 0);
303 cairo_fill(mpSurface->getCairo().get());
304 #endif
305 ::Point aOutpos;
306 if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xFont ) )
307 return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary
309 // change text direction and layout mode
310 sal_uLong nLayoutMode(0);
311 switch( textDirection )
313 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
314 nLayoutMode |= TEXT_LAYOUT_BIDI_LTR;
315 // FALLTHROUGH intended
316 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
317 nLayoutMode |= TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG;
318 nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_LEFT;
319 break;
321 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
322 nLayoutMode |= TEXT_LAYOUT_BIDI_RTL;
323 // FALLTHROUGH intended
324 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
325 nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
326 nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_RIGHT;
327 break;
330 // TODO(F2): alpha
331 mpVirtualDevice->SetLayoutMode( nLayoutMode );
333 OSL_TRACE(":cairocanvas::CanvasHelper::drawText(O,t,f,v,r,d): %s", OUStringToOString( text.Text.copy( text.StartPosition, text.Length ),
334 RTL_TEXTENCODING_UTF8 ).getStr());
336 TextLayout* pTextLayout = new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider);
337 pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState );
340 return uno::Reference< rendering::XCachedPrimitive >(NULL);
343 uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* pOwner,
344 const uno::Reference< rendering::XTextLayout >& xLayoutedText,
345 const rendering::ViewState& viewState,
346 const rendering::RenderState& renderState )
348 ENSURE_ARG_OR_THROW( xLayoutedText.is(),
349 "CanvasHelper::drawTextLayout(): layout is NULL");
351 TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() );
353 if( pTextLayout )
355 if( !mpVirtualDevice )
356 mpVirtualDevice = mpSurface->createVirtualDevice();
358 if( mpVirtualDevice )
360 #if defined CAIRO_HAS_WIN32_SURFACE
361 // FIXME: Some kind of work-araound...
362 cairo_rectangle( mpSurface->getCairo().get(), 0, 0, 0, 0);
363 cairo_fill(mpSurface->getCairo().get());
364 #endif
365 // TODO(T3): Race condition. We're taking the font
366 // from xLayoutedText, and then calling draw() at it,
367 // without exclusive access. Move setupTextOutput(),
368 // e.g. to impltools?
370 ::Point aOutpos;
371 if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xLayoutedText->getFont() ) )
372 return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary
374 // TODO(F2): What about the offset scalings?
375 pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState );
378 else
380 ENSURE_ARG_OR_THROW( false,
381 "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" );
384 return uno::Reference< rendering::XCachedPrimitive >(NULL);
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */