File: | home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx |
Warning: | line 994, column 28 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <memory> | |||
21 | #include <config_features.h> | |||
22 | #include <sal/log.hxx> | |||
23 | #if HAVE_FEATURE_OPENGL1 | |||
24 | #include <opengl/gdiimpl.hxx> | |||
25 | #include <opengl/zone.hxx> | |||
26 | #include <desktop/exithelper.h> | |||
27 | #ifdef _WIN32 | |||
28 | #include <svsys.h> | |||
29 | #endif | |||
30 | #endif | |||
31 | #include <PhysicalFontFace.hxx> | |||
32 | #include <fontsubset.hxx> | |||
33 | #include <salgdi.hxx> | |||
34 | #include <salframe.hxx> | |||
35 | #include <sft.hxx> | |||
36 | #include <basegfx/matrix/b2dhommatrix.hxx> | |||
37 | #include <basegfx/matrix/b2dhommatrixtools.hxx> | |||
38 | #include <FileDefinitionWidgetDraw.hxx> | |||
39 | ||||
40 | // The only common SalFrame method | |||
41 | ||||
42 | SalFrameGeometry SalFrame::GetGeometry() const | |||
43 | { | |||
44 | // mirror frame coordinates at parent | |||
45 | SalFrame *pParent = GetParent(); | |||
46 | if( pParent && AllSettings::GetLayoutRTL() ) | |||
47 | { | |||
48 | SalFrameGeometry aGeom = maGeometry; | |||
49 | int parent_x = aGeom.nX - pParent->maGeometry.nX; | |||
50 | aGeom.nX = pParent->maGeometry.nX + pParent->maGeometry.nWidth - maGeometry.nWidth - parent_x; | |||
51 | return aGeom; | |||
52 | } | |||
53 | else | |||
54 | return maGeometry; | |||
55 | } | |||
56 | ||||
57 | SalGraphics::SalGraphics() | |||
58 | : m_nLayout( SalLayoutFlags::NONE ), | |||
59 | m_aLastMirror(), | |||
60 | m_aLastMirrorW(0), | |||
61 | m_bAntiAlias(false) | |||
62 | { | |||
63 | // read global RTL settings | |||
64 | if( AllSettings::GetLayoutRTL() ) | |||
65 | m_nLayout = SalLayoutFlags::BiDiRtl; | |||
66 | } | |||
67 | ||||
68 | bool SalGraphics::initWidgetDrawBackends(bool bForce) | |||
69 | { | |||
70 | bool bFileDefinitionsWidgetDraw = !!getenv("VCL_DRAW_WIDGETS_FROM_FILE"); | |||
71 | ||||
72 | if (bFileDefinitionsWidgetDraw || bForce) | |||
73 | { | |||
74 | m_pWidgetDraw.reset(new vcl::FileDefinitionWidgetDraw(*this)); | |||
75 | auto pFileDefinitionWidgetDraw = static_cast<vcl::FileDefinitionWidgetDraw*>(m_pWidgetDraw.get()); | |||
76 | if (!pFileDefinitionWidgetDraw->isActive()) | |||
77 | { | |||
78 | m_pWidgetDraw.reset(); | |||
79 | return false; | |||
80 | } | |||
81 | return true; | |||
82 | } | |||
83 | return false; | |||
84 | } | |||
85 | ||||
86 | SalGraphics::~SalGraphics() COVERITY_NOEXCEPT_FALSE | |||
87 | { | |||
88 | // can't call ReleaseFonts here, as the destructor just calls this classes SetFont (pure virtual)! | |||
89 | } | |||
90 | ||||
91 | #if HAVE_FEATURE_OPENGL1 | |||
92 | ||||
93 | namespace | |||
94 | { | |||
95 | void disableOpenGLAndTerminateForRestart() | |||
96 | { | |||
97 | OpenGLZone::hardDisable(); | |||
98 | #ifdef _WIN32 | |||
99 | TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART); | |||
100 | #endif | |||
101 | } | |||
102 | } | |||
103 | ||||
104 | rtl::Reference<OpenGLContext> SalGraphics::GetOpenGLContext() const | |||
105 | { | |||
106 | OpenGLSalGraphicsImpl *pImpl = dynamic_cast<OpenGLSalGraphicsImpl*>(GetImpl()); | |||
107 | if (pImpl) | |||
108 | { | |||
109 | // If we notice that OpenGL is broken the first time being called, it is not too late to call | |||
110 | // disableOpenGLAndTerminateForRestart(). The first time this will be called is from displaying | |||
111 | // the splash screen, so if OpenGL is broken, it is "early enough" for us to be able to disable | |||
112 | // OpenGL and terminate bluntly with EXITHELPER_NORMAL_RESTART, thus causing the wrapper process | |||
113 | // to restart us, then without using OpenGL. | |||
114 | static bool bFirstCall = true; | |||
115 | rtl::Reference<OpenGLContext> xRet(pImpl->GetOpenGLContext()); | |||
116 | if (!xRet.is() && bFirstCall) | |||
117 | disableOpenGLAndTerminateForRestart(); | |||
118 | bFirstCall = false; | |||
119 | return xRet; | |||
120 | } | |||
121 | return nullptr; | |||
122 | } | |||
123 | ||||
124 | #endif | |||
125 | ||||
126 | bool SalGraphics::drawTransformedBitmap( | |||
127 | const basegfx::B2DPoint& /* rNull */, | |||
128 | const basegfx::B2DPoint& /* rX */, | |||
129 | const basegfx::B2DPoint& /* rY */, | |||
130 | const SalBitmap& /* rSourceBitmap */, | |||
131 | const SalBitmap* /* pAlphaBitmap */) | |||
132 | { | |||
133 | // here direct support for transformed bitmaps can be implemented | |||
134 | return false; | |||
135 | } | |||
136 | ||||
137 | long SalGraphics::mirror2( long x, const OutputDevice *pOutDev ) const | |||
138 | { | |||
139 | mirror(x, pOutDev); | |||
140 | return x; | |||
141 | } | |||
142 | ||||
143 | inline long SalGraphics::GetDeviceWidth(const OutputDevice* pOutDev) const | |||
144 | { | |||
145 | return (pOutDev && pOutDev->IsVirtual()) | |||
146 | ? pOutDev->GetOutputWidthPixel() : GetGraphicsWidth(); | |||
147 | } | |||
148 | ||||
149 | void SalGraphics::mirror( long& x, const OutputDevice *pOutDev ) const | |||
150 | { | |||
151 | const long w = GetDeviceWidth(pOutDev); | |||
152 | if( !w ) | |||
153 | return; | |||
154 | ||||
155 | if( pOutDev && pOutDev->ImplIsAntiparallel() ) | |||
156 | { | |||
157 | OutputDevice *pOutDevRef = const_cast<OutputDevice*>(pOutDev); | |||
158 | // mirror this window back | |||
159 | if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
160 | { | |||
161 | long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
162 | x = devX + (x - pOutDevRef->GetOutOffXPixel()); | |||
163 | } | |||
164 | else | |||
165 | { | |||
166 | long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
167 | x = pOutDevRef->GetOutputWidthPixel() - (x - devX) + pOutDevRef->GetOutOffXPixel() - 1; | |||
168 | } | |||
169 | } | |||
170 | else if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
171 | x = w-1-x; | |||
172 | } | |||
173 | ||||
174 | void SalGraphics::mirror( long& x, long nWidth, const OutputDevice *pOutDev, bool bBack ) const | |||
175 | { | |||
176 | const long w = GetDeviceWidth(pOutDev); | |||
177 | if( !w ) | |||
178 | return; | |||
179 | ||||
180 | if( pOutDev && pOutDev->ImplIsAntiparallel() ) | |||
181 | { | |||
182 | OutputDevice *pOutDevRef = const_cast<OutputDevice*>(pOutDev); | |||
183 | // mirror this window back | |||
184 | if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
185 | { | |||
186 | long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
187 | if( bBack ) | |||
188 | x = x - devX + pOutDevRef->GetOutOffXPixel(); | |||
189 | else | |||
190 | x = devX + (x - pOutDevRef->GetOutOffXPixel()); | |||
191 | } | |||
192 | else | |||
193 | { | |||
194 | long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
195 | if( bBack ) | |||
196 | x = devX + (pOutDevRef->GetOutputWidthPixel() + devX) - (x + nWidth); | |||
197 | else | |||
198 | x = pOutDevRef->GetOutputWidthPixel() - (x - devX) + pOutDevRef->GetOutOffXPixel() - nWidth; | |||
199 | } | |||
200 | } | |||
201 | else if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
202 | x = w-nWidth-x; | |||
203 | } | |||
204 | ||||
205 | bool SalGraphics::mirror( sal_uInt32 nPoints, const SalPoint *pPtAry, SalPoint *pPtAry2, const OutputDevice *pOutDev ) const | |||
206 | { | |||
207 | const long w = GetDeviceWidth(pOutDev); | |||
208 | if( w ) | |||
209 | { | |||
210 | sal_uInt32 i, j; | |||
211 | ||||
212 | if( pOutDev && pOutDev->ImplIsAntiparallel() ) | |||
213 | { | |||
214 | OutputDevice *pOutDevRef = const_cast<OutputDevice*>(pOutDev); | |||
215 | // mirror this window back | |||
216 | if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
217 | { | |||
218 | long devX = w-pOutDevRef->GetOutputWidthPixel()-pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
219 | for( i=0, j=nPoints-1; i<nPoints; i++,j-- ) | |||
220 | { | |||
221 | pPtAry2[j].mnX = devX + (pPtAry[i].mnX - pOutDevRef->GetOutOffXPixel()); | |||
222 | pPtAry2[j].mnY = pPtAry[i].mnY; | |||
223 | } | |||
224 | } | |||
225 | else | |||
226 | { | |||
227 | long devX = pOutDevRef->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
228 | for( i=0, j=nPoints-1; i<nPoints; i++,j-- ) | |||
229 | { | |||
230 | pPtAry2[j].mnX = pOutDevRef->GetOutputWidthPixel() - (pPtAry[i].mnX - devX) + pOutDevRef->GetOutOffXPixel() - 1; | |||
231 | pPtAry2[j].mnY = pPtAry[i].mnY; | |||
232 | } | |||
233 | } | |||
234 | } | |||
235 | else if( m_nLayout & SalLayoutFlags::BiDiRtl ) | |||
236 | { | |||
237 | for( i=0, j=nPoints-1; i<nPoints; i++,j-- ) | |||
238 | { | |||
239 | pPtAry2[j].mnX = w-1-pPtAry[i].mnX; | |||
240 | pPtAry2[j].mnY = pPtAry[i].mnY; | |||
241 | } | |||
242 | } | |||
243 | return true; | |||
244 | } | |||
245 | else | |||
246 | return false; | |||
247 | } | |||
248 | ||||
249 | void SalGraphics::mirror( vcl::Region& rRgn, const OutputDevice *pOutDev ) const | |||
250 | { | |||
251 | if( rRgn.HasPolyPolygonOrB2DPolyPolygon() ) | |||
252 | { | |||
253 | const basegfx::B2DPolyPolygon aPolyPoly(mirror(rRgn.GetAsB2DPolyPolygon(), pOutDev)); | |||
254 | ||||
255 | rRgn = vcl::Region(aPolyPoly); | |||
256 | } | |||
257 | else | |||
258 | { | |||
259 | RectangleVector aRectangles; | |||
260 | rRgn.GetRegionRectangles(aRectangles); | |||
261 | rRgn.SetEmpty(); | |||
262 | ||||
263 | for (auto & rectangle : aRectangles) | |||
264 | { | |||
265 | mirror(rectangle, pOutDev); | |||
266 | rRgn.Union(rectangle); | |||
267 | } | |||
268 | ||||
269 | //ImplRegionInfo aInfo; | |||
270 | //bool bRegionRect; | |||
271 | //Region aMirroredRegion; | |||
272 | //long nX, nY, nWidth, nHeight; | |||
273 | ||||
274 | //bRegionRect = rRgn.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); | |||
275 | //while ( bRegionRect ) | |||
276 | //{ | |||
277 | // Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); | |||
278 | // mirror( aRect, pOutDev, bBack ); | |||
279 | // aMirroredRegion.Union( aRect ); | |||
280 | // bRegionRect = rRgn.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); | |||
281 | //} | |||
282 | //rRgn = aMirroredRegion; | |||
283 | } | |||
284 | } | |||
285 | ||||
286 | void SalGraphics::mirror( tools::Rectangle& rRect, const OutputDevice *pOutDev, bool bBack ) const | |||
287 | { | |||
288 | long nWidth = rRect.GetWidth(); | |||
289 | long x = rRect.Left(); | |||
290 | long x_org = x; | |||
291 | ||||
292 | mirror( x, nWidth, pOutDev, bBack ); | |||
293 | rRect.Move( x - x_org, 0 ); | |||
294 | } | |||
295 | ||||
296 | basegfx::B2DPolyPolygon SalGraphics::mirror( const basegfx::B2DPolyPolygon& i_rPoly, const OutputDevice* i_pOutDev ) const | |||
297 | { | |||
298 | const basegfx::B2DHomMatrix& rMirror(getMirror(i_pOutDev)); | |||
299 | ||||
300 | if(rMirror.isIdentity()) | |||
301 | { | |||
302 | return i_rPoly; | |||
303 | } | |||
304 | else | |||
305 | { | |||
306 | basegfx::B2DPolyPolygon aRet(i_rPoly); | |||
307 | aRet.transform(rMirror); | |||
308 | aRet.flip(); | |||
309 | return aRet; | |||
310 | } | |||
311 | } | |||
312 | ||||
313 | const basegfx::B2DHomMatrix& SalGraphics::getMirror( const OutputDevice* i_pOutDev ) const | |||
314 | { | |||
315 | // get mirroring transformation | |||
316 | const long w = GetDeviceWidth(i_pOutDev); | |||
317 | SAL_WARN_IF( !w, "vcl", "missing graphics width" )do { if (true && (!w)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "missing graphics width" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "317" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "missing graphics width"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "missing graphics width"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "317" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "missing graphics width") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "317" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "missing graphics width"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "missing graphics width"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "317" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
318 | ||||
319 | if(w != m_aLastMirrorW) | |||
320 | { | |||
321 | const_cast<SalGraphics*>(this)->m_aLastMirrorW = w; | |||
322 | ||||
323 | if(w) | |||
324 | { | |||
325 | if(nullptr != i_pOutDev && !i_pOutDev->IsRTLEnabled()) | |||
326 | { | |||
327 | // Original code was (removed here already pOutDevRef->i_pOutDev): | |||
328 | // // mirror this window back | |||
329 | // double devX = w-i_pOutDev->GetOutputWidthPixel()-i_pOutDev->GetOutOffXPixel(); // re-mirrored mnOutOffX | |||
330 | // aRet.setX( devX + (i_rPoint.getX() - i_pOutDev->GetOutOffXPixel()) ); | |||
331 | // I do not really understand the comment 'mirror this window back', so cannot guarantee | |||
332 | // that this works as before, but I have reduced this (by re-placing and re-formatting) to | |||
333 | // a simple translation: | |||
334 | const_cast<SalGraphics*>(this)->m_aLastMirror = basegfx::utils::createTranslateB2DHomMatrix( | |||
335 | w - i_pOutDev->GetOutputWidthPixel() - (2 * i_pOutDev->GetOutOffXPixel()), | |||
336 | 0.0); | |||
337 | } | |||
338 | else | |||
339 | { | |||
340 | // Original code was: | |||
341 | // aRet.setX( w-1-i_rPoint.getX() ); | |||
342 | // -mirror X -> scale(-1.0, 1.0) | |||
343 | // -translate X -> translate(w-1, 0) | |||
344 | // Checked this one, works as expected. | |||
345 | const_cast<SalGraphics*>(this)->m_aLastMirror = basegfx::utils::createScaleTranslateB2DHomMatrix( | |||
346 | -1.0, | |||
347 | 1.0, | |||
348 | w-1, | |||
349 | 0.0); | |||
350 | } | |||
351 | } | |||
352 | else | |||
353 | { | |||
354 | const_cast<SalGraphics*>(this)->m_aLastMirror.identity(); | |||
355 | } | |||
356 | } | |||
357 | ||||
358 | return m_aLastMirror; | |||
359 | } | |||
360 | ||||
361 | bool SalGraphics::SetClipRegion( const vcl::Region& i_rClip, const OutputDevice *pOutDev ) | |||
362 | { | |||
363 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
364 | { | |||
365 | vcl::Region aMirror( i_rClip ); | |||
366 | mirror( aMirror, pOutDev ); | |||
367 | return setClipRegion( aMirror ); | |||
368 | } | |||
369 | return setClipRegion( i_rClip ); | |||
370 | } | |||
371 | ||||
372 | void SalGraphics::DrawPixel( long nX, long nY, const OutputDevice *pOutDev ) | |||
373 | { | |||
374 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
375 | mirror( nX, pOutDev ); | |||
376 | drawPixel( nX, nY ); | |||
377 | } | |||
378 | ||||
379 | void SalGraphics::DrawPixel( long nX, long nY, Color nColor, const OutputDevice *pOutDev ) | |||
380 | { | |||
381 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
382 | mirror( nX, pOutDev ); | |||
383 | drawPixel( nX, nY, nColor ); | |||
384 | } | |||
385 | ||||
386 | void SalGraphics::DrawLine( long nX1, long nY1, long nX2, long nY2, const OutputDevice *pOutDev ) | |||
387 | { | |||
388 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
389 | { | |||
390 | mirror( nX1, pOutDev ); | |||
391 | mirror( nX2, pOutDev ); | |||
392 | } | |||
393 | drawLine( nX1, nY1, nX2, nY2 ); | |||
394 | } | |||
395 | ||||
396 | void SalGraphics::DrawRect( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev ) | |||
397 | { | |||
398 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
399 | mirror( nX, nWidth, pOutDev ); | |||
400 | drawRect( nX, nY, nWidth, nHeight ); | |||
401 | } | |||
402 | ||||
403 | void SalGraphics::DrawPolyLine( sal_uInt32 nPoints, SalPoint const * pPtAry, const OutputDevice *pOutDev ) | |||
404 | { | |||
405 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
406 | { | |||
407 | std::unique_ptr<SalPoint[]> pPtAry2(new SalPoint[nPoints]); | |||
408 | bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), pOutDev ); | |||
409 | drawPolyLine( nPoints, bCopied ? pPtAry2.get() : pPtAry ); | |||
410 | } | |||
411 | else | |||
412 | drawPolyLine( nPoints, pPtAry ); | |||
413 | } | |||
414 | ||||
415 | void SalGraphics::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, const OutputDevice *pOutDev ) | |||
416 | { | |||
417 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
418 | { | |||
419 | std::unique_ptr<SalPoint[]> pPtAry2(new SalPoint[nPoints]); | |||
420 | bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), pOutDev ); | |||
421 | drawPolygon( nPoints, bCopied ? pPtAry2.get() : pPtAry ); | |||
422 | } | |||
423 | else | |||
424 | drawPolygon( nPoints, pPtAry ); | |||
425 | } | |||
426 | ||||
427 | void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry, const OutputDevice *pOutDev ) | |||
428 | { | |||
429 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
430 | { | |||
431 | // TODO: optimize, reduce new/delete calls | |||
432 | std::unique_ptr<SalPoint*[]> pPtAry2( new SalPoint*[nPoly] ); | |||
433 | sal_uLong i; | |||
434 | for(i=0; i<nPoly; i++) | |||
435 | { | |||
436 | sal_uLong nPoints = pPoints[i]; | |||
437 | pPtAry2[i] = new SalPoint[ nPoints ]; | |||
438 | mirror( nPoints, pPtAry[i], pPtAry2[i], pOutDev ); | |||
439 | } | |||
440 | ||||
441 | drawPolyPolygon( nPoly, pPoints, const_cast<PCONSTSALPOINT*>(pPtAry2.get()) ); | |||
442 | ||||
443 | for(i=0; i<nPoly; i++) | |||
444 | delete [] pPtAry2[i]; | |||
445 | } | |||
446 | else | |||
447 | drawPolyPolygon( nPoly, pPoints, pPtAry ); | |||
448 | } | |||
449 | ||||
450 | namespace | |||
451 | { | |||
452 | basegfx::B2DHomMatrix createTranslateToMirroredBounds(const basegfx::B2DRange &rBoundingBox, const basegfx::B2DHomMatrix& rMirror) | |||
453 | { | |||
454 | basegfx::B2DRange aRTLBoundingBox(rBoundingBox); | |||
455 | aRTLBoundingBox *= rMirror; | |||
456 | return basegfx::utils::createTranslateB2DHomMatrix(aRTLBoundingBox.getMinX() - rBoundingBox.getMinX(), 0); | |||
457 | } | |||
458 | } | |||
459 | ||||
460 | bool SalGraphics::DrawPolyPolygon( | |||
461 | const basegfx::B2DHomMatrix& rObjectToDevice, | |||
462 | const basegfx::B2DPolyPolygon& i_rPolyPolygon, | |||
463 | double i_fTransparency, | |||
464 | const OutputDevice* i_pOutDev) | |||
465 | { | |||
466 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) | |||
467 | { | |||
468 | // mirroring set | |||
469 | const basegfx::B2DHomMatrix& rMirror(getMirror(i_pOutDev)); | |||
470 | if(!rMirror.isIdentity()) | |||
471 | { | |||
472 | basegfx::B2DRange aBoundingBox(i_rPolyPolygon.getB2DRange()); | |||
473 | aBoundingBox *= rObjectToDevice; | |||
474 | auto aTranslateToMirroredBounds = createTranslateToMirroredBounds(aBoundingBox, rMirror); | |||
475 | ||||
476 | return drawPolyPolygon( | |||
477 | aTranslateToMirroredBounds * rObjectToDevice, | |||
478 | i_rPolyPolygon, | |||
479 | i_fTransparency); | |||
480 | } | |||
481 | } | |||
482 | ||||
483 | return drawPolyPolygon( | |||
484 | rObjectToDevice, | |||
485 | i_rPolyPolygon, | |||
486 | i_fTransparency); | |||
487 | } | |||
488 | ||||
489 | bool SalGraphics::DrawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry, const OutputDevice* pOutDev ) | |||
490 | { | |||
491 | bool bResult = false; | |||
492 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
493 | { | |||
494 | std::unique_ptr<SalPoint[]> pPtAry2(new SalPoint[nPoints]); | |||
495 | bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), pOutDev ); | |||
496 | bResult = drawPolyLineBezier( nPoints, bCopied ? pPtAry2.get() : pPtAry, pFlgAry ); | |||
497 | } | |||
498 | else | |||
499 | bResult = drawPolyLineBezier( nPoints, pPtAry, pFlgAry ); | |||
500 | return bResult; | |||
501 | } | |||
502 | ||||
503 | bool SalGraphics::DrawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry, const OutputDevice* pOutDev ) | |||
504 | { | |||
505 | bool bResult = false; | |||
506 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
507 | { | |||
508 | std::unique_ptr<SalPoint[]> pPtAry2(new SalPoint[nPoints]); | |||
509 | bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), pOutDev ); | |||
510 | bResult = drawPolygonBezier( nPoints, bCopied ? pPtAry2.get() : pPtAry, pFlgAry ); | |||
511 | } | |||
512 | else | |||
513 | bResult = drawPolygonBezier( nPoints, pPtAry, pFlgAry ); | |||
514 | return bResult; | |||
515 | } | |||
516 | ||||
517 | bool SalGraphics::DrawPolyPolygonBezier( sal_uInt32 i_nPoly, const sal_uInt32* i_pPoints, | |||
518 | const SalPoint* const* i_pPtAry, const PolyFlags* const* i_pFlgAry, const OutputDevice* i_pOutDev ) | |||
519 | { | |||
520 | bool bRet = false; | |||
521 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) | |||
522 | { | |||
523 | // TODO: optimize, reduce new/delete calls | |||
524 | std::unique_ptr<SalPoint*[]> pPtAry2( new SalPoint*[i_nPoly] ); | |||
525 | sal_uLong i; | |||
526 | for(i=0; i<i_nPoly; i++) | |||
527 | { | |||
528 | sal_uLong nPoints = i_pPoints[i]; | |||
529 | pPtAry2[i] = new SalPoint[ nPoints ]; | |||
530 | mirror( nPoints, i_pPtAry[i], pPtAry2[i], i_pOutDev ); | |||
531 | } | |||
532 | ||||
533 | bRet = drawPolyPolygonBezier( i_nPoly, i_pPoints, const_cast<PCONSTSALPOINT const *>(pPtAry2.get()), i_pFlgAry ); | |||
534 | ||||
535 | for(i=0; i<i_nPoly; i++) | |||
536 | delete [] pPtAry2[i]; | |||
537 | } | |||
538 | else | |||
539 | bRet = drawPolyPolygonBezier( i_nPoly, i_pPoints, i_pPtAry, i_pFlgAry ); | |||
540 | return bRet; | |||
541 | } | |||
542 | ||||
543 | bool SalGraphics::DrawPolyLine( | |||
544 | const basegfx::B2DHomMatrix& rObjectToDevice, | |||
545 | const basegfx::B2DPolygon& i_rPolygon, | |||
546 | double i_fTransparency, | |||
547 | double i_rLineWidth, | |||
548 | const std::vector< double >* i_pStroke, // MM01 | |||
549 | basegfx::B2DLineJoin i_eLineJoin, | |||
550 | css::drawing::LineCap i_eLineCap, | |||
551 | double i_fMiterMinimumAngle, | |||
552 | bool bPixelSnapHairline, | |||
553 | const OutputDevice* i_pOutDev) | |||
554 | { | |||
555 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) | |||
556 | { | |||
557 | // mirroring set | |||
558 | const basegfx::B2DHomMatrix& rMirror(getMirror(i_pOutDev)); | |||
559 | if(!rMirror.isIdentity()) | |||
560 | { | |||
561 | basegfx::B2DRange aBoundingBox(i_rPolygon.getB2DRange()); | |||
562 | aBoundingBox *= rObjectToDevice; | |||
563 | auto aTranslateToMirroredBounds = createTranslateToMirroredBounds(aBoundingBox, rMirror); | |||
564 | ||||
565 | return drawPolyLine( | |||
566 | aTranslateToMirroredBounds * rObjectToDevice, | |||
567 | i_rPolygon, | |||
568 | i_fTransparency, | |||
569 | i_rLineWidth, | |||
570 | i_pStroke, // MM01 | |||
571 | i_eLineJoin, | |||
572 | i_eLineCap, | |||
573 | i_fMiterMinimumAngle, | |||
574 | bPixelSnapHairline); | |||
575 | } | |||
576 | } | |||
577 | ||||
578 | // no mirroring set (or identity), use standard call | |||
579 | return drawPolyLine( | |||
580 | rObjectToDevice, | |||
581 | i_rPolygon, | |||
582 | i_fTransparency, | |||
583 | i_rLineWidth, | |||
584 | i_pStroke, // MM01 | |||
585 | i_eLineJoin, | |||
586 | i_eLineCap, | |||
587 | i_fMiterMinimumAngle, | |||
588 | bPixelSnapHairline); | |||
589 | } | |||
590 | ||||
591 | bool SalGraphics::DrawGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient ) | |||
592 | { | |||
593 | return drawGradient( rPolyPoly, rGradient ); | |||
594 | } | |||
595 | ||||
596 | bool SalGraphics::DrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rSalGradient) | |||
597 | { | |||
598 | return implDrawGradient(rPolyPolygon, rSalGradient); | |||
599 | } | |||
600 | ||||
601 | void SalGraphics::CopyArea( long nDestX, long nDestY, | |||
602 | long nSrcX, long nSrcY, | |||
603 | long nSrcWidth, long nSrcHeight, | |||
604 | const OutputDevice *pOutDev ) | |||
605 | { | |||
606 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
607 | { | |||
608 | mirror( nDestX, nSrcWidth, pOutDev ); | |||
609 | mirror( nSrcX, nSrcWidth, pOutDev ); | |||
610 | } | |||
611 | copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, true/*bWindowInvalidate*/ ); | |||
612 | } | |||
613 | ||||
614 | void SalGraphics::CopyBits( const SalTwoRect& rPosAry, | |||
615 | SalGraphics* pSrcGraphics, const OutputDevice *pOutDev, const OutputDevice *pSrcOutDev ) | |||
616 | { | |||
617 | if( ( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) || | |||
618 | (pSrcGraphics && ( (pSrcGraphics->GetLayout() & SalLayoutFlags::BiDiRtl) || (pSrcOutDev && pSrcOutDev->IsRTLEnabled()) ) ) ) | |||
619 | { | |||
620 | SalTwoRect aPosAry2 = rPosAry; | |||
621 | if( (pSrcGraphics && (pSrcGraphics->GetLayout() & SalLayoutFlags::BiDiRtl)) || (pSrcOutDev && pSrcOutDev->IsRTLEnabled()) ) | |||
622 | mirror( aPosAry2.mnSrcX, aPosAry2.mnSrcWidth, pSrcOutDev ); | |||
623 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
624 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
625 | copyBits( aPosAry2, pSrcGraphics ); | |||
626 | } | |||
627 | else | |||
628 | copyBits( rPosAry, pSrcGraphics ); | |||
629 | } | |||
630 | ||||
631 | void SalGraphics::DrawBitmap( const SalTwoRect& rPosAry, | |||
632 | const SalBitmap& rSalBitmap, const OutputDevice *pOutDev ) | |||
633 | { | |||
634 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
635 | { | |||
636 | SalTwoRect aPosAry2 = rPosAry; | |||
637 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
638 | drawBitmap( aPosAry2, rSalBitmap ); | |||
639 | } | |||
640 | else | |||
641 | drawBitmap( rPosAry, rSalBitmap ); | |||
642 | } | |||
643 | ||||
644 | void SalGraphics::DrawBitmap( const SalTwoRect& rPosAry, | |||
645 | const SalBitmap& rSalBitmap, | |||
646 | const SalBitmap& rTransparentBitmap, const OutputDevice *pOutDev ) | |||
647 | { | |||
648 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
649 | { | |||
650 | SalTwoRect aPosAry2 = rPosAry; | |||
651 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
652 | drawBitmap( aPosAry2, rSalBitmap, rTransparentBitmap ); | |||
653 | } | |||
654 | else | |||
655 | drawBitmap( rPosAry, rSalBitmap, rTransparentBitmap ); | |||
656 | } | |||
657 | ||||
658 | void SalGraphics::DrawMask( const SalTwoRect& rPosAry, | |||
659 | const SalBitmap& rSalBitmap, | |||
660 | Color nMaskColor, const OutputDevice *pOutDev ) | |||
661 | { | |||
662 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
663 | { | |||
664 | SalTwoRect aPosAry2 = rPosAry; | |||
665 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
666 | drawMask( aPosAry2, rSalBitmap, nMaskColor ); | |||
667 | } | |||
668 | else | |||
669 | drawMask( rPosAry, rSalBitmap, nMaskColor ); | |||
670 | } | |||
671 | ||||
672 | std::shared_ptr<SalBitmap> SalGraphics::GetBitmap( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev ) | |||
673 | { | |||
674 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
675 | mirror( nX, nWidth, pOutDev ); | |||
676 | return getBitmap( nX, nY, nWidth, nHeight ); | |||
677 | } | |||
678 | ||||
679 | Color SalGraphics::GetPixel( long nX, long nY, const OutputDevice *pOutDev ) | |||
680 | { | |||
681 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
682 | mirror( nX, pOutDev ); | |||
683 | return getPixel( nX, nY ); | |||
684 | } | |||
685 | ||||
686 | void SalGraphics::Invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags, const OutputDevice *pOutDev ) | |||
687 | { | |||
688 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
689 | mirror( nX, nWidth, pOutDev ); | |||
690 | invert( nX, nY, nWidth, nHeight, nFlags ); | |||
691 | } | |||
692 | ||||
693 | void SalGraphics::Invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags, const OutputDevice *pOutDev ) | |||
694 | { | |||
695 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
696 | { | |||
697 | std::unique_ptr<SalPoint[]> pPtAry2(new SalPoint[nPoints]); | |||
698 | bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), pOutDev ); | |||
699 | invert( nPoints, bCopied ? pPtAry2.get() : pPtAry, nFlags ); | |||
700 | } | |||
701 | else | |||
702 | invert( nPoints, pPtAry, nFlags ); | |||
703 | } | |||
704 | ||||
705 | bool SalGraphics::DrawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uInt32 nSize, const OutputDevice *pOutDev ) | |||
706 | { | |||
707 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
708 | mirror( nX, nWidth, pOutDev ); | |||
709 | return drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize ); | |||
710 | } | |||
711 | ||||
712 | bool SalGraphics::HitTestNativeScrollbar( ControlPart nPart, const tools::Rectangle& rControlRegion, | |||
713 | const Point& aPos, bool& rIsInside, const OutputDevice *pOutDev ) | |||
714 | { | |||
715 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
716 | { | |||
717 | Point pt( aPos ); | |||
718 | tools::Rectangle rgn( rControlRegion ); | |||
719 | pt.setX( mirror2( pt.X(), pOutDev ) ); | |||
720 | mirror( rgn, pOutDev ); | |||
721 | return forWidget()->hitTestNativeControl( ControlType::Scrollbar, nPart, rgn, pt, rIsInside ); | |||
722 | } | |||
723 | else | |||
724 | return forWidget()->hitTestNativeControl( ControlType::Scrollbar, nPart, rControlRegion, aPos, rIsInside ); | |||
725 | } | |||
726 | ||||
727 | void SalGraphics::mirror( ImplControlValue& rVal, const OutputDevice* pOutDev ) const | |||
728 | { | |||
729 | switch( rVal.getType() ) | |||
730 | { | |||
731 | case ControlType::Slider: | |||
732 | { | |||
733 | SliderValue* pSlVal = static_cast<SliderValue*>(&rVal); | |||
734 | mirror(pSlVal->maThumbRect,pOutDev); | |||
735 | } | |||
736 | break; | |||
737 | case ControlType::Scrollbar: | |||
738 | { | |||
739 | ScrollbarValue* pScVal = static_cast<ScrollbarValue*>(&rVal); | |||
740 | mirror(pScVal->maThumbRect,pOutDev); | |||
741 | mirror(pScVal->maButton1Rect,pOutDev); | |||
742 | mirror(pScVal->maButton2Rect,pOutDev); | |||
743 | } | |||
744 | break; | |||
745 | case ControlType::Spinbox: | |||
746 | case ControlType::SpinButtons: | |||
747 | { | |||
748 | SpinbuttonValue* pSpVal = static_cast<SpinbuttonValue*>(&rVal); | |||
749 | mirror(pSpVal->maUpperRect,pOutDev); | |||
750 | mirror(pSpVal->maLowerRect,pOutDev); | |||
751 | } | |||
752 | break; | |||
753 | case ControlType::Toolbar: | |||
754 | { | |||
755 | ToolbarValue* pTVal = static_cast<ToolbarValue*>(&rVal); | |||
756 | mirror(pTVal->maGripRect,pOutDev); | |||
757 | } | |||
758 | break; | |||
759 | default: break; | |||
760 | } | |||
761 | } | |||
762 | ||||
763 | bool SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, | |||
764 | ControlState nState, const ImplControlValue& aValue, | |||
765 | const OUString& aCaption, const OutputDevice *pOutDev, | |||
766 | const Color& rBackgroundColor) | |||
767 | { | |||
768 | bool bRet = false; | |||
769 | tools::Rectangle aControlRegion(rControlRegion); | |||
770 | if (aControlRegion.IsEmpty() || aControlRegion.GetWidth() <= 0 || aControlRegion.GetHeight() <= 0) | |||
771 | return bRet; | |||
772 | ||||
773 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
774 | { | |||
775 | mirror(aControlRegion, pOutDev); | |||
776 | std::unique_ptr< ImplControlValue > mirrorValue( aValue.clone()); | |||
777 | mirror( *mirrorValue, pOutDev ); | |||
778 | bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, *mirrorValue, aCaption, rBackgroundColor); | |||
779 | } | |||
780 | else | |||
781 | bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, aValue, aCaption, rBackgroundColor); | |||
782 | ||||
783 | if (bRet && m_pWidgetDraw) | |||
784 | handleDamage(aControlRegion); | |||
785 | return bRet; | |||
786 | } | |||
787 | ||||
788 | bool SalGraphics::GetNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, | |||
789 | const ImplControlValue& aValue, | |||
790 | tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion, const OutputDevice *pOutDev ) | |||
791 | { | |||
792 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
793 | { | |||
794 | tools::Rectangle rgn( rControlRegion ); | |||
795 | mirror( rgn, pOutDev ); | |||
796 | std::unique_ptr< ImplControlValue > mirrorValue( aValue.clone()); | |||
797 | mirror( *mirrorValue, pOutDev ); | |||
798 | if (forWidget()->getNativeControlRegion(nType, nPart, rgn, nState, *mirrorValue, OUString(), rNativeBoundingRegion, rNativeContentRegion)) | |||
799 | { | |||
800 | mirror( rNativeBoundingRegion, pOutDev, true ); | |||
801 | mirror( rNativeContentRegion, pOutDev, true ); | |||
802 | return true; | |||
803 | } | |||
804 | return false; | |||
805 | } | |||
806 | else | |||
807 | return forWidget()->getNativeControlRegion(nType, nPart, rControlRegion, nState, aValue, OUString(), rNativeBoundingRegion, rNativeContentRegion); | |||
808 | } | |||
809 | ||||
810 | bool SalGraphics::BlendBitmap( const SalTwoRect& rPosAry, | |||
811 | const SalBitmap& rBitmap, | |||
812 | const OutputDevice *pOutDev ) | |||
813 | { | |||
814 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
815 | { | |||
816 | SalTwoRect aPosAry2 = rPosAry; | |||
817 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
818 | return blendBitmap( aPosAry2, rBitmap ); | |||
819 | } | |||
820 | else | |||
821 | return blendBitmap( rPosAry, rBitmap ); | |||
822 | } | |||
823 | ||||
824 | bool SalGraphics::BlendAlphaBitmap( const SalTwoRect& rPosAry, | |||
825 | const SalBitmap& rSrcBitmap, | |||
826 | const SalBitmap& rMaskBitmap, | |||
827 | const SalBitmap& rAlphaBitmap, | |||
828 | const OutputDevice *pOutDev ) | |||
829 | { | |||
830 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
831 | { | |||
832 | SalTwoRect aPosAry2 = rPosAry; | |||
833 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
834 | return blendAlphaBitmap( aPosAry2, rSrcBitmap, rMaskBitmap, rAlphaBitmap ); | |||
835 | } | |||
836 | else | |||
837 | return blendAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap, rAlphaBitmap ); | |||
838 | } | |||
839 | ||||
840 | bool SalGraphics::DrawAlphaBitmap( const SalTwoRect& rPosAry, | |||
841 | const SalBitmap& rSourceBitmap, | |||
842 | const SalBitmap& rAlphaBitmap, | |||
843 | const OutputDevice *pOutDev ) | |||
844 | { | |||
845 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
846 | { | |||
847 | SalTwoRect aPosAry2 = rPosAry; | |||
848 | mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, pOutDev ); | |||
849 | return drawAlphaBitmap( aPosAry2, rSourceBitmap, rAlphaBitmap ); | |||
850 | } | |||
851 | else | |||
852 | return drawAlphaBitmap( rPosAry, rSourceBitmap, rAlphaBitmap ); | |||
853 | } | |||
854 | ||||
855 | bool SalGraphics::DrawTransformedBitmap( | |||
856 | const basegfx::B2DPoint& rNull, | |||
857 | const basegfx::B2DPoint& rX, | |||
858 | const basegfx::B2DPoint& rY, | |||
859 | const SalBitmap& rSourceBitmap, | |||
860 | const SalBitmap* pAlphaBitmap, | |||
861 | const OutputDevice* pOutDev) | |||
862 | { | |||
863 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
864 | { | |||
865 | // mirroring set | |||
866 | const basegfx::B2DHomMatrix& rMirror(getMirror(pOutDev)); | |||
867 | if (!rMirror.isIdentity()) | |||
868 | { | |||
869 | basegfx::B2DPolygon aPoints({rNull, rX, rY}); | |||
870 | basegfx::B2DRange aBoundingBox(aPoints.getB2DRange()); | |||
871 | auto aTranslateToMirroredBounds = createTranslateToMirroredBounds(aBoundingBox, rMirror); | |||
872 | ||||
873 | basegfx::B2DPoint aNull = aTranslateToMirroredBounds * rNull; | |||
874 | basegfx::B2DPoint aX = aTranslateToMirroredBounds * rX; | |||
875 | basegfx::B2DPoint aY = aTranslateToMirroredBounds * rY; | |||
876 | ||||
877 | return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap); | |||
878 | } | |||
879 | } | |||
880 | ||||
881 | return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap); | |||
882 | } | |||
883 | ||||
884 | bool SalGraphics::DrawAlphaRect( long nX, long nY, long nWidth, long nHeight, | |||
885 | sal_uInt8 nTransparency, const OutputDevice *pOutDev ) | |||
886 | { | |||
887 | if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (pOutDev && pOutDev->IsRTLEnabled()) ) | |||
888 | mirror( nX, nWidth, pOutDev ); | |||
889 | ||||
890 | return drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency ); | |||
891 | } | |||
892 | ||||
893 | OUString SalGraphics::getRenderBackendName() const | |||
894 | { | |||
895 | if (GetImpl()) | |||
896 | return GetImpl()->getRenderBackendName(); | |||
897 | return OUString(); | |||
898 | } | |||
899 | ||||
900 | void SalGraphics::GetGlyphWidths(const vcl::AbstractTrueTypeFont& rTTF, | |||
901 | const PhysicalFontFace& rFontFace, const bool bVertical, | |||
902 | std::vector<sal_Int32>& rWidths, Ucs2UIntMap& rUnicodeEnc) | |||
903 | { | |||
904 | rWidths.clear(); | |||
905 | rUnicodeEnc.clear(); | |||
906 | ||||
907 | const int nGlyphCount = rTTF.glyphCount(); | |||
908 | if (nGlyphCount <= 0) | |||
909 | return; | |||
910 | ||||
911 | FontCharMapRef xFCMap = rFontFace.GetFontCharMap(); | |||
912 | if (!xFCMap.is() || !xFCMap->GetCharCount()) | |||
913 | { | |||
914 | SAL_WARN("vcl.fonts", "no charmap")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.fonts")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "no charmap") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "914" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "no charmap"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "no charmap"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "914" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "no charmap") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "914" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "no charmap"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "no charmap"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "914" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
915 | return; | |||
916 | } | |||
917 | ||||
918 | rWidths.resize(nGlyphCount); | |||
919 | std::vector<sal_uInt16> aGlyphIds(nGlyphCount); | |||
920 | for (int i = 0; i < nGlyphCount; i++) | |||
921 | aGlyphIds[i] = static_cast<sal_uInt16>(i); | |||
922 | ||||
923 | std::unique_ptr<sal_uInt16[]> pGlyphMetrics | |||
924 | = GetTTSimpleGlyphMetrics(&rTTF, aGlyphIds.data(), nGlyphCount, bVertical); | |||
925 | if (pGlyphMetrics) | |||
926 | { | |||
927 | for (int i = 0; i < nGlyphCount; ++i) | |||
928 | rWidths[i] = pGlyphMetrics[i]; | |||
929 | pGlyphMetrics.reset(); | |||
930 | } | |||
931 | ||||
932 | int nCharCount = xFCMap->GetCharCount(); | |||
933 | sal_uInt32 nChar = xFCMap->GetFirstChar(); | |||
934 | for (; --nCharCount >= 0; nChar = xFCMap->GetNextChar(nChar)) | |||
935 | { | |||
936 | if (nChar > 0xFFFF) | |||
937 | continue; | |||
938 | ||||
939 | sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar); | |||
940 | sal_uInt32 nGlyph = xFCMap->GetGlyphIndex(nUcsChar); | |||
941 | if (nGlyph > 0) | |||
942 | rUnicodeEnc[nUcsChar] = nGlyph; | |||
943 | } | |||
944 | } | |||
945 | ||||
946 | bool SalGraphics::CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, const OString& rSysPath, | |||
947 | const bool bVertical, const sal_GlyphId* pGlyphIds, | |||
948 | const sal_uInt8* pEncoding, sal_Int32* pGlyphWidths, | |||
949 | const int nOrigGlyphCount) | |||
950 | { | |||
951 | // Multiple questions: | |||
952 | // - Why is there a glyph limit? | |||
953 | // MacOS used to handle 257 glyphs... | |||
954 | // Also the much more complex PrintFontManager variant has this limit. | |||
955 | // Also the very first implementation has the limit in | |||
956 | // commit 8789ed701e98031f2a1657ea0dfd6f7a0b050992 | |||
957 | // - Why doesn't the PrintFontManager care about the fake glyph? It | |||
958 | // is used on all unx platforms to create the subset font. | |||
959 | // - Should the SAL_WARN actually be asserts, like on MacOS? | |||
960 | if (nOrigGlyphCount > 256) | |||
| ||||
961 | { | |||
962 | SAL_WARN("vcl.fonts", "too many glyphs for subsetting")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.fonts")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "too many glyphs for subsetting" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "962" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "too many glyphs for subsetting"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "too many glyphs for subsetting"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "962" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "too many glyphs for subsetting") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "962" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "too many glyphs for subsetting"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "too many glyphs for subsetting"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "962" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
963 | return false; | |||
964 | } | |||
965 | ||||
966 | int nGlyphCount = nOrigGlyphCount; | |||
967 | sal_uInt16 aShortIDs[256]; | |||
968 | sal_uInt8 aTempEncs[256]; | |||
969 | ||||
970 | // handle the undefined / first font glyph | |||
971 | int nNotDef = -1, i; | |||
972 | for (i = 0; i < nGlyphCount; ++i) | |||
973 | { | |||
974 | aTempEncs[i] = pEncoding[i]; | |||
975 | aShortIDs[i] = static_cast<sal_uInt16>(pGlyphIds[i]); | |||
976 | if (!aShortIDs[i]) | |||
977 | if (nNotDef < 0) | |||
978 | nNotDef = i; | |||
979 | } | |||
980 | ||||
981 | // nNotDef glyph must be in pos 0 => swap glyphids | |||
982 | if (nNotDef
| |||
983 | { | |||
984 | if (nNotDef
| |||
985 | { | |||
986 | if (nGlyphCount
| |||
987 | { | |||
988 | SAL_WARN("vcl.fonts", "too many glyphs for subsetting")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.fonts")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "too many glyphs for subsetting" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts" ), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "988" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "too many glyphs for subsetting"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "too many glyphs for subsetting"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "988" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "too many glyphs for subsetting") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "988" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "too many glyphs for subsetting"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "too many glyphs for subsetting"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.fonts"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/salgdilayout.cxx" ":" "988" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
989 | return false; | |||
990 | } | |||
991 | nNotDef = nGlyphCount++; | |||
992 | } | |||
993 | ||||
994 | aShortIDs[nNotDef] = aShortIDs[0]; | |||
| ||||
995 | aTempEncs[nNotDef] = aTempEncs[0]; | |||
996 | aShortIDs[0] = 0; | |||
997 | aTempEncs[0] = 0; | |||
998 | } | |||
999 | ||||
1000 | std::unique_ptr<sal_uInt16[]> pMetrics | |||
1001 | = GetTTSimpleGlyphMetrics(&rTTF, aShortIDs, nGlyphCount, bVertical); | |||
1002 | if (!pMetrics) | |||
1003 | return false; | |||
1004 | ||||
1005 | sal_uInt16 nNotDefAdv = pMetrics[0]; | |||
1006 | pMetrics[0] = pMetrics[nNotDef]; | |||
1007 | pMetrics[nNotDef] = nNotDefAdv; | |||
1008 | for (i = 0; i < nOrigGlyphCount; ++i) | |||
1009 | pGlyphWidths[i] = pMetrics[i]; | |||
1010 | pMetrics.reset(); | |||
1011 | ||||
1012 | // write subset into destination file | |||
1013 | return (CreateTTFromTTGlyphs(&rTTF, rSysPath.getStr(), aShortIDs, aTempEncs, nGlyphCount) | |||
1014 | == vcl::SFErrCodes::Ok); | |||
1015 | } | |||
1016 | ||||
1017 | bool SalGraphics::CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, | |||
1018 | const OString& rSysPath, const sal_GlyphId* pGlyphIds, | |||
1019 | const sal_uInt8* pEncoding, sal_Int32* pGlyphWidths, | |||
1020 | int nGlyphCount, FontSubsetInfo& rInfo) | |||
1021 | { | |||
1022 | FILE* pOutFile = fopen(rSysPath.getStr(), "wb"); | |||
1023 | if (!pOutFile) | |||
1024 | return false; | |||
1025 | rInfo.LoadFont(FontType::CFF_FONT, pFontBytes, nByteLength); | |||
1026 | bool bRet = rInfo.CreateFontSubset(FontType::TYPE1_PFB, pOutFile, nullptr, pGlyphIds, pEncoding, | |||
1027 | nGlyphCount, pGlyphWidths); | |||
1028 | fclose(pOutFile); | |||
1029 | return bRet; | |||
1030 | } | |||
1031 | ||||
1032 | void SalGraphics::FillFontSubsetInfo(const vcl::TTGlobalFontInfo& rTTInfo, const OUString& pPSName, | |||
1033 | FontSubsetInfo& rInfo) | |||
1034 | { | |||
1035 | rInfo.m_aPSName = pPSName; | |||
1036 | rInfo.m_nFontType = FontType::SFNT_TTF; | |||
1037 | rInfo.m_aFontBBox | |||
1038 | = tools::Rectangle(Point(rTTInfo.xMin, rTTInfo.yMin), Point(rTTInfo.xMax, rTTInfo.yMax)); | |||
1039 | rInfo.m_nCapHeight = rTTInfo.yMax; // Well ... | |||
1040 | rInfo.m_nAscent = rTTInfo.winAscent; | |||
1041 | rInfo.m_nDescent = rTTInfo.winDescent; | |||
1042 | ||||
1043 | // mac fonts usually do not have an OS2-table | |||
1044 | // => get valid ascent/descent values from other tables | |||
1045 | if (!rInfo.m_nAscent) | |||
1046 | rInfo.m_nAscent = +rTTInfo.typoAscender; | |||
1047 | if (!rInfo.m_nAscent) | |||
1048 | rInfo.m_nAscent = +rTTInfo.ascender; | |||
1049 | if (!rInfo.m_nDescent) | |||
1050 | rInfo.m_nDescent = +rTTInfo.typoDescender; | |||
1051 | if (!rInfo.m_nDescent) | |||
1052 | rInfo.m_nDescent = -rTTInfo.descender; | |||
1053 | } | |||
1054 | ||||
1055 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |