1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
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*/ )
58 return uno::Sequence
< rendering::FontInfo
>();
62 setupFontTransform( ::OutputDevice
& rOutDev
,
64 vcl::Font
& io_rVCLFont
,
65 const rendering::ViewState
& rViewState
,
66 const rendering::RenderState
& rRenderState
)
68 ::basegfx::B2DHomMatrix aMatrix
;
70 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
,
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
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());
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
130 ::canvas::tools::clipOutDev(viewState
, renderState
, rOutDev
);
132 if( eColorType
!= IGNORE_COLOR
)
134 Color
aColor( COL_WHITE
);
136 if( renderState
.DeviceColor
.getLength() > 2 )
138 aColor
= vcl::unotools::stdColorSpaceSequenceToColor( renderState
.DeviceColor
);
141 // extract alpha, and make color opaque
142 // afterwards. Otherwise, OutputDevice won't draw anything
143 nTransparency
= aColor
.GetTransparency();
144 aColor
.SetTransparency(0);
149 rOutDev
.SetLineColor( aColor
);
150 rOutDev
.SetFillColor();
155 rOutDev
.SetFillColor( aColor
);
156 rOutDev
.SetLineColor();
161 rOutDev
.SetTextColor( aColor
);
166 ENSURE_OR_THROW( false,
167 "CanvasHelper::setupOutDevState(): Unexpected color type");
172 return nTransparency
;
175 class DeviceSettingsGuard
178 VclPtr
<OutputDevice
> mpVirtualDevice
;
180 bool mbMappingWasEnabled
;
182 DeviceSettingsGuard(OutputDevice
*pVirtualDevice
, cairo_t
*pCairo
)
183 : mpVirtualDevice(pVirtualDevice
)
185 , mbMappingWasEnabled(mpVirtualDevice
->IsMapModeEnabled())
188 mpVirtualDevice
->Push();
189 mpVirtualDevice
->EnableMapMode(false);
192 ~DeviceSettingsGuard()
194 mpVirtualDevice
->EnableMapMode(mbMappingWasEnabled
);
195 mpVirtualDevice
->Pop();
196 cairo_restore(mpCairo
);
200 bool setupTextOutput( OutputDevice
& rOutDev
,
201 const rendering::XCanvas
* pOwner
,
203 const rendering::ViewState
& viewState
,
204 const rendering::RenderState
& renderState
,
205 const uno::Reference
< rendering::XCanvasFont
>& xFont
)
207 setupOutDevState( rOutDev
, pOwner
, viewState
, renderState
, TEXT_COLOR
);
209 CanvasFont
* pFont
= dynamic_cast< CanvasFont
* >( xFont
.get() );
211 ENSURE_ARG_OR_THROW( pFont
,
212 "CanvasHelper::setupTextOutput(): Font not compatible with this canvas" );
214 vcl::Font aVCLFont
= pFont
->getVCLFont();
216 Color
aColor( COL_BLACK
);
218 if( renderState
.DeviceColor
.getLength() > 2 )
220 aColor
= vcl::unotools::stdColorSpaceSequenceToColor(renderState
.DeviceColor
);
224 aVCLFont
.SetColor( aColor
);
225 aVCLFont
.SetFillColor( aColor
);
227 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
228 if( !setupFontTransform( rOutDev
, o_rOutPos
, aVCLFont
, viewState
, renderState
) )
231 rOutDev
.SetFont( aVCLFont
);
236 //set the clip of the rOutDev to the cairo surface
237 void CanvasHelper::clip_cairo_from_dev(::OutputDevice
& rOutDev
)
239 vcl::Region
aRegion(rOutDev
.GetClipRegion());
240 if (!aRegion
.IsEmpty() && !aRegion
.IsNull())
242 doPolyPolygonImplementation(aRegion
.GetAsB2DPolyPolygon(), Clip
, mpCairo
.get(),
243 NULL
, mpSurfaceProvider
, rendering::FillRule_EVEN_ODD
);
247 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawText( const rendering::XCanvas
* pOwner
,
248 const rendering::StringContext
& text
,
249 const uno::Reference
< rendering::XCanvasFont
>& xFont
,
250 const rendering::ViewState
& viewState
,
251 const rendering::RenderState
& renderState
,
252 sal_Int8 textDirection
)
254 #ifdef CAIRO_CANVAS_PERF_TRACE
255 struct timespec aTimer
;
256 mxDevice
->startPerfTrace( &aTimer
);
259 ENSURE_ARG_OR_THROW( xFont
.is(),
260 "CanvasHelper::drawText(): font is NULL");
262 if( !mpVirtualDevice
)
263 mpVirtualDevice
= mpSurface
->createVirtualDevice();
265 if( mpVirtualDevice
)
267 DeviceSettingsGuard
aGuard(mpVirtualDevice
.get(), mpCairo
.get());
269 #if defined CAIRO_HAS_WIN32_SURFACE
270 // FIXME: Some kind of work-araound...
271 cairo_rectangle (mpCairo
.get(), 0, 0, 0, 0);
272 cairo_fill(mpCairo
.get());
275 if( !setupTextOutput( *mpVirtualDevice
.get(), pOwner
, aOutpos
, viewState
, renderState
, xFont
) )
276 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
278 // change text direction and layout mode
279 ComplexTextLayoutMode
nLayoutMode(TEXT_LAYOUT_DEFAULT
);
280 switch( textDirection
)
282 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT
:
283 // FALLTHROUGH intended
284 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT
:
285 nLayoutMode
|= TEXT_LAYOUT_BIDI_STRONG
;
286 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_LEFT
;
289 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT
:
290 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
;
291 // FALLTHROUGH intended
292 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT
:
293 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
| TEXT_LAYOUT_BIDI_STRONG
;
294 nLayoutMode
|= TEXT_LAYOUT_TEXTORIGIN_RIGHT
;
299 mpVirtualDevice
->SetLayoutMode( nLayoutMode
);
301 clip_cairo_from_dev(*mpVirtualDevice
);
303 OSL_TRACE(":cairocanvas::CanvasHelper::drawText(O,t,f,v,r,d): %s", OUStringToOString( text
.Text
.copy( text
.StartPosition
, text
.Length
),
304 RTL_TEXTENCODING_UTF8
).getStr());
306 rtl::Reference
< TextLayout
> pTextLayout( new TextLayout(text
, textDirection
, 0, CanvasFont::Reference(dynamic_cast< CanvasFont
* >( xFont
.get() )), mpSurfaceProvider
) );
307 pTextLayout
->draw(mpCairo
, *mpVirtualDevice
, aOutpos
, viewState
, renderState
);
310 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
313 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawTextLayout( const rendering::XCanvas
* pOwner
,
314 const uno::Reference
< rendering::XTextLayout
>& xLayoutedText
,
315 const rendering::ViewState
& viewState
,
316 const rendering::RenderState
& renderState
)
318 ENSURE_ARG_OR_THROW( xLayoutedText
.is(),
319 "CanvasHelper::drawTextLayout(): layout is NULL");
321 TextLayout
* pTextLayout
= dynamic_cast< TextLayout
* >( xLayoutedText
.get() );
325 if( !mpVirtualDevice
)
326 mpVirtualDevice
= mpSurface
->createVirtualDevice();
328 if( mpVirtualDevice
)
330 DeviceSettingsGuard
aGuard(mpVirtualDevice
.get(), mpCairo
.get());
332 #if defined CAIRO_HAS_WIN32_SURFACE
333 // FIXME: Some kind of work-araound...
334 cairo_rectangle(mpCairo
.get(), 0, 0, 0, 0);
335 cairo_fill(mpCairo
.get());
337 // TODO(T3): Race condition. We're taking the font
338 // from xLayoutedText, and then calling draw() at it,
339 // without exclusive access. Move setupTextOutput(),
340 // e.g. to impltools?
343 if( !setupTextOutput( *mpVirtualDevice
, pOwner
, aOutpos
, viewState
, renderState
, xLayoutedText
->getFont() ) )
344 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
); // no output necessary
346 clip_cairo_from_dev(*mpVirtualDevice
);
348 // TODO(F2): What about the offset scalings?
349 pTextLayout
->draw(mpCairo
, *mpVirtualDevice
, aOutpos
, viewState
, renderState
);
354 ENSURE_ARG_OR_THROW( false,
355 "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" );
358 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */