LibreOffice Module canvas (master) 1
cairo_canvashelper_text.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <com/sun/star/rendering/TextDirection.hpp>
23
24#include <rtl/math.hxx>
27#include <vcl/canvastools.hxx>
28#include <vcl/metric.hxx>
29#include <vcl/virdev.hxx>
30
32#include <verifyinput.hxx>
33
34#include "cairo_canvasfont.hxx"
36#include "cairo_textlayout.hxx"
37
38using namespace ::cairo;
39using namespace ::com::sun::star;
40
41namespace cairocanvas
42{
43 uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* ,
44 const rendering::FontRequest& fontRequest,
45 const uno::Sequence< beans::PropertyValue >& extraFontProperties,
46 const geometry::Matrix2D& fontMatrix )
47 {
48 return uno::Reference< rendering::XCanvasFont >( new CanvasFont( fontRequest, extraFontProperties, fontMatrix, mpSurfaceProvider ));
49 }
50
51 uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* ,
52 const rendering::FontInfo& /*aFilter*/,
53 const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ )
54 {
55 // TODO
56 return uno::Sequence< rendering::FontInfo >();
57 }
58
59 static bool
61 ::Point& o_rPoint,
62 vcl::Font& io_rVCLFont,
63 const rendering::ViewState& rViewState,
64 const rendering::RenderState& rRenderState )
65 {
67
69 rViewState,
70 rRenderState);
71
73 ::basegfx::B2DTuple aTranslate;
74 double nRotate, nShearX;
75
76 aMatrix.decompose( aScale, aTranslate, nRotate, nShearX );
77
78 // query font metric _before_ tampering with width and height
79 if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) )
80 {
81 // retrieve true font width
82 const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetAverageFontWidth() );
83
84 const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) );
85
86 if( !nScaledFontWidth )
87 {
88 // scale is smaller than one pixel - disable text
89 // output altogether
90 return false;
91 }
92
93 io_rVCLFont.SetAverageFontWidth( nScaledFontWidth );
94 }
95
96 if( !::rtl::math::approxEqual(aScale.getY(), 1.0) )
97 {
98 const sal_Int32 nFontHeight( io_rVCLFont.GetFontHeight() );
99 io_rVCLFont.SetFontHeight( ::basegfx::fround(nFontHeight * aScale.getY()) );
100 }
101
102 io_rVCLFont.SetOrientation( Degree10( ::basegfx::fround(-basegfx::rad2deg<10>(fmod(nRotate, 2*M_PI))) ) );
103
104 // TODO(F2): Missing functionality in VCL: shearing
105 o_rPoint.setX( ::basegfx::fround(aTranslate.getX()) );
106 o_rPoint.setY( ::basegfx::fround(aTranslate.getY()) );
107
108 return true;
109 }
110
111 static void
113 const rendering::XCanvas* pOwner,
114 const rendering::ViewState& viewState,
115 const rendering::RenderState& renderState )
116 {
117 ::canvas::tools::verifyInput( renderState,
118 __func__,
119 const_cast<rendering::XCanvas*>(pOwner), // only for refcount
120 2,
121 3 /* text */ );
122
123 // TODO(P2): Don't change clipping all the time, maintain current clip
124 // state and change only when update is necessary
125 ::canvas::tools::clipOutDev(viewState, renderState, rOutDev);
126
127 Color aColor( COL_WHITE );
128
129 if( renderState.DeviceColor.getLength() > 2 )
130 {
131 aColor = vcl::unotools::stdColorSpaceSequenceToColor( renderState.DeviceColor );
132 }
133
134 // extract alpha, and make color opaque
135 // afterwards. Otherwise, OutputDevice won't draw anything
136 aColor.SetAlpha(255);
137
138 rOutDev.SetTextColor( aColor );
139 }
140
141 namespace {
142
143 class DeviceSettingsGuard
144 {
145 private:
148 public:
149 DeviceSettingsGuard(OutputDevice *pVirtualDevice)
150 : mpVirtualDevice(pVirtualDevice)
151 , mbMappingWasEnabled(mpVirtualDevice->IsMapModeEnabled())
152 {
153 mpVirtualDevice->Push();
154 mpVirtualDevice->EnableMapMode(false);
155 }
156
157 ~DeviceSettingsGuard()
158 {
159 mpVirtualDevice->EnableMapMode(mbMappingWasEnabled);
160 mpVirtualDevice->Pop();
161 }
162 };
163
164 }
165
166 static bool setupTextOutput( OutputDevice& rOutDev,
167 const rendering::XCanvas* pOwner,
168 ::Point& o_rOutPos,
169 const rendering::ViewState& viewState,
170 const rendering::RenderState& renderState,
171 const uno::Reference< rendering::XCanvasFont >& xFont )
172 {
173 setupOutDevState( rOutDev, pOwner, viewState, renderState );
174
175 CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() );
176
177 ENSURE_ARG_OR_THROW( pFont,
178 "CanvasHelper::setupTextOutput(): Font not compatible with this canvas" );
179
180 vcl::Font aVCLFont = pFont->getVCLFont();
181
182 Color aColor( COL_BLACK );
183
184 if( renderState.DeviceColor.getLength() > 2 )
185 {
186 aColor = vcl::unotools::stdColorSpaceSequenceToColor(renderState.DeviceColor );
187 }
188
189 // setup font color
190 aVCLFont.SetColor( aColor );
191 aVCLFont.SetFillColor( aColor );
192
193 if (pFont->getEmphasisMark())
195
196 // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
197 if( !setupFontTransform( rOutDev, o_rOutPos, aVCLFont, viewState, renderState ) )
198 return false;
199
200 rOutDev.SetFont( aVCLFont );
201
202 return true;
203 }
204
205 uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* pOwner,
206 const rendering::StringContext& text,
207 const uno::Reference< rendering::XCanvasFont >& xFont,
208 const rendering::ViewState& viewState,
209 const rendering::RenderState& renderState,
210 sal_Int8 textDirection )
211 {
212#ifdef CAIRO_CANVAS_PERF_TRACE
213 struct timespec aTimer;
214 mxDevice->startPerfTrace( &aTimer );
215#endif
216
217 ENSURE_ARG_OR_THROW( xFont.is(),
218 "CanvasHelper::drawText(): font is NULL");
219
220 if( !mpVirtualDevice )
221 mpVirtualDevice = mpSurface->createVirtualDevice();
222
223 if( mpVirtualDevice )
224 {
225 DeviceSettingsGuard aGuard(mpVirtualDevice.get());
226
227 ::Point aOutpos;
228 if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xFont ) )
229 return uno::Reference< rendering::XCachedPrimitive >(nullptr); // no output necessary
230
231 // change text direction and layout mode
233 switch( textDirection )
234 {
235 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
236 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
239 break;
240
241 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
243 [[fallthrough]];
244 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
247 break;
248 }
249
250 // TODO(F2): alpha
251 mpVirtualDevice->SetLayoutMode( nLayoutMode );
252
253 rtl::Reference pTextLayout( new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider) );
254 pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState);
255 }
256
257 return uno::Reference< rendering::XCachedPrimitive >(nullptr);
258 }
259
260 uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* pOwner,
261 const uno::Reference< rendering::XTextLayout >& xLayoutedText,
262 const rendering::ViewState& viewState,
263 const rendering::RenderState& renderState )
264 {
265 ENSURE_ARG_OR_THROW( xLayoutedText.is(),
266 "CanvasHelper::drawTextLayout(): layout is NULL");
267
268 TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() );
269
270 if( pTextLayout )
271 {
272 if( !mpVirtualDevice )
273 mpVirtualDevice = mpSurface->createVirtualDevice();
274
275 if( mpVirtualDevice )
276 {
277 DeviceSettingsGuard aGuard(mpVirtualDevice.get());
278
279 // TODO(T3): Race condition. We're taking the font
280 // from xLayoutedText, and then calling draw() at it,
281 // without exclusive access. Move setupTextOutput(),
282 // e.g. to impltools?
283
284 ::Point aOutpos;
285 if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xLayoutedText->getFont() ) )
286 return uno::Reference< rendering::XCachedPrimitive >(nullptr); // no output necessary
287
288 // TODO(F2): What about the offset scalings?
289 pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState);
290 }
291 }
292 else
293 {
294 ENSURE_ARG_OR_THROW( false,
295 "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" );
296 }
297
298 return uno::Reference< rendering::XCachedPrimitive >(nullptr);
299 }
300
301}
302
303/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
VclPtr< OutputDevice > mpVirtualDevice
bool mbMappingWasEnabled
void SetAlpha(sal_uInt8 nAlpha)
void SetFont(const vcl::Font &rNewFont)
void SetTextColor(const Color &rColor)
FontMetric GetFontMetric() const
void setX(tools::Long nX)
void setY(tools::Long nY)
reference_type * get() const
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
TYPE getX() const
TYPE getY() const
rtl::Reference< CanvasFont > Reference
sal_uInt32 getEmphasisMark() const
vcl::Font const & getVCLFont() const
::cairo::SurfaceSharedPtr mpSurface
SurfaceProvider * mpSurfaceProvider
Surface provider.
VclPtr< VirtualDevice > mpVirtualDevice
css::uno::Sequence< css::rendering::FontInfo > queryAvailableFonts(const css::rendering::XCanvas *pCanvas, const css::rendering::FontInfo &aFilter, const css::uno::Sequence< css::beans::PropertyValue > &aFontProperties)
css::uno::Reference< css::rendering::XCachedPrimitive > drawText(const css::rendering::XCanvas *pCanvas, const css::rendering::StringContext &text, const css::uno::Reference< css::rendering::XCanvasFont > &xFont, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, sal_Int8 textDirection)
css::uno::Reference< css::rendering::XCanvasFont > createFont(const css::rendering::XCanvas *pCanvas, const css::rendering::FontRequest &fontRequest, const css::uno::Sequence< css::beans::PropertyValue > &extraFontProperties, const css::geometry::Matrix2D &fontMatrix)
css::uno::Reference< css::rendering::XCachedPrimitive > drawTextLayout(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XTextLayout > &laidOutText, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
tools::Long GetFontHeight() const
void SetOrientation(Degree10 nLineOrientation)
void SetAverageFontWidth(tools::Long nWidth)
void SetFillColor(const Color &)
void SetColor(const Color &)
void SetFontHeight(tools::Long nHeight)
void SetEmphasisMark(FontEmphasisMark)
tools::Long GetAverageFontWidth() const
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define ENSURE_ARG_OR_THROW(c, m)
FontEmphasisMark
SvLinkSource * pOwner
static void setupOutDevState(OutputDevice &rOutDev, const rendering::XCanvas *pOwner, const rendering::ViewState &viewState, const rendering::RenderState &renderState)
static bool setupFontTransform(::OutputDevice const &rOutDev, ::Point &o_rPoint, vcl::Font &io_rVCLFont, const rendering::ViewState &rViewState, const rendering::RenderState &rRenderState)
static bool setupTextOutput(OutputDevice &rOutDev, const rendering::XCanvas *pOwner, ::Point &o_rOutPos, const rendering::ViewState &viewState, const rendering::RenderState &renderState, const uno::Reference< rendering::XCanvasFont > &xFont)
::basegfx::B2DHomMatrix & mergeViewAndRenderTransform(::basegfx::B2DHomMatrix &combinedTransform, const rendering::ViewState &viewState, const rendering::RenderState &renderState)
void verifyInput(const geometry::RealPoint2D &rPoint, const char *pStr, const uno::Reference< uno::XInterface > &xIf, ::sal_Int16 nArgPos)
Definition: verifyinput.cxx:51
void clipOutDev(const rendering::ViewState &viewState, const rendering::RenderState &renderState, OutputDevice &rOutDev, OutputDevice *p2ndOutDev)
ComplexTextLayoutFlags
Color stdColorSpaceSequenceToColor(const uno::Sequence< double > &rColor)
signed char sal_Int8