/src/libreoffice/vcl/source/gdi/gdimtf.cxx
Line | Count | Source |
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 <cstdlib> |
21 | | #include <memory> |
22 | | #include <sal/log.hxx> |
23 | | #include <osl/diagnose.h> |
24 | | #include <comphelper/diagnose_ex.hxx> |
25 | | #include <tools/helpers.hxx> |
26 | | #include <tools/stream.hxx> |
27 | | #include <tools/vcompat.hxx> |
28 | | #include <tools/fract.hxx> |
29 | | #include <vcl/alpha.hxx> |
30 | | #include <vcl/BitmapPalette.hxx> |
31 | | #include <vcl/metaact.hxx> |
32 | | #include <vcl/outdev.hxx> |
33 | | #include <vcl/window.hxx> |
34 | | #include <vcl/virdev.hxx> |
35 | | #include <vcl/svapp.hxx> |
36 | | #include <vcl/gdimtf.hxx> |
37 | | #include <vcl/graphictools.hxx> |
38 | | #include <basegfx/polygon/b2dpolygon.hxx> |
39 | | #include <vcl/canvastools.hxx> |
40 | | #include <vcl/mtfxmldump.hxx> |
41 | | |
42 | | #include <vcl/TypeSerializer.hxx> |
43 | | |
44 | | #include <com/sun/star/beans/XFastPropertySet.hpp> |
45 | | #include <com/sun/star/rendering/MtfRenderer.hpp> |
46 | | #include <com/sun/star/rendering/XBitmapCanvas.hpp> |
47 | | #include <com/sun/star/rendering/XCanvas.hpp> |
48 | | #include <comphelper/processfactory.hxx> |
49 | | |
50 | | using namespace com::sun::star; |
51 | | |
52 | | namespace { |
53 | | |
54 | | struct ImplColAdjustParam |
55 | | { |
56 | | std::unique_ptr<sal_uInt8[]> pMapR; |
57 | | std::unique_ptr<sal_uInt8[]> pMapG; |
58 | | std::unique_ptr<sal_uInt8[]> pMapB; |
59 | | }; |
60 | | |
61 | | struct ImplBmpAdjustParam |
62 | | { |
63 | | short nLuminancePercent; |
64 | | short nContrastPercent; |
65 | | short nChannelRPercent; |
66 | | short nChannelGPercent; |
67 | | short nChannelBPercent; |
68 | | double fGamma; |
69 | | bool bInvert; |
70 | | }; |
71 | | |
72 | | struct ImplColConvertParam |
73 | | { |
74 | | MtfConversion eConversion; |
75 | | }; |
76 | | |
77 | | struct ImplBmpConvertParam |
78 | | { |
79 | | BmpConversion eConversion; |
80 | | }; |
81 | | |
82 | | struct ImplColMonoParam |
83 | | { |
84 | | Color aColor; |
85 | | }; |
86 | | |
87 | | struct ImplBmpMonoParam |
88 | | { |
89 | | Color aColor; |
90 | | }; |
91 | | |
92 | | struct ImplColReplaceParam |
93 | | { |
94 | | std::unique_ptr<sal_uLong[]> pMinR; |
95 | | std::unique_ptr<sal_uLong[]> pMaxR; |
96 | | std::unique_ptr<sal_uLong[]> pMinG; |
97 | | std::unique_ptr<sal_uLong[]> pMaxG; |
98 | | std::unique_ptr<sal_uLong[]> pMinB; |
99 | | std::unique_ptr<sal_uLong[]> pMaxB; |
100 | | const Color * pDstCols; |
101 | | sal_uLong nCount; |
102 | | }; |
103 | | |
104 | | struct ImplBmpReplaceParam |
105 | | { |
106 | | const Color* pSrcCols; |
107 | | const Color* pDstCols; |
108 | | sal_uLong nCount; |
109 | | }; |
110 | | |
111 | | } |
112 | | |
113 | | GDIMetaFile::GDIMetaFile() : |
114 | 1.38M | m_nCurrentActionElement( 0 ), |
115 | 1.38M | m_aPrefSize ( 1, 1 ), |
116 | 1.38M | m_pPrev ( nullptr ), |
117 | 1.38M | m_pNext ( nullptr ), |
118 | 1.38M | m_pOutDev ( nullptr ), |
119 | 1.38M | m_bPause ( false ), |
120 | 1.38M | m_bRecord ( false ), |
121 | 1.38M | m_bUseCanvas ( false ), |
122 | 1.38M | m_bSVG ( false ) |
123 | 1.38M | { |
124 | 1.38M | } |
125 | | |
126 | | GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) : |
127 | 15.5k | m_nCurrentActionElement( rMtf.m_nCurrentActionElement ), |
128 | 15.5k | m_aPrefMapMode ( rMtf.m_aPrefMapMode ), |
129 | 15.5k | m_aPrefSize ( rMtf.m_aPrefSize ), |
130 | 15.5k | m_pPrev ( rMtf.m_pPrev ), |
131 | 15.5k | m_pNext ( rMtf.m_pNext ), |
132 | 15.5k | m_pOutDev ( nullptr ), |
133 | 15.5k | m_bPause ( false ), |
134 | 15.5k | m_bRecord ( false ), |
135 | 15.5k | m_bUseCanvas ( rMtf.m_bUseCanvas ), |
136 | 15.5k | m_bSVG ( rMtf.m_bSVG ) |
137 | 15.5k | { |
138 | 1.17M | for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i ) |
139 | 1.16M | { |
140 | 1.16M | m_aList.push_back( rMtf.GetAction( i ) ); |
141 | 1.16M | } |
142 | | |
143 | 15.5k | if( rMtf.m_bRecord ) |
144 | 0 | { |
145 | 0 | Record( rMtf.m_pOutDev ); |
146 | |
|
147 | 0 | if ( rMtf.m_bPause ) |
148 | 0 | Pause( true ); |
149 | 0 | } |
150 | 15.5k | } |
151 | | |
152 | | GDIMetaFile::~GDIMetaFile() |
153 | 1.40M | { |
154 | 1.40M | Clear(); |
155 | 1.40M | } |
156 | | |
157 | | bool GDIMetaFile::HasTransparentActions() const |
158 | 0 | { |
159 | 0 | MetaAction* pCurrAct; |
160 | | |
161 | | // watch for transparent drawing actions |
162 | 0 | for(pCurrAct = const_cast<GDIMetaFile*>(this)->FirstAction(); |
163 | 0 | pCurrAct; |
164 | 0 | pCurrAct = const_cast<GDIMetaFile*>(this)->NextAction()) |
165 | 0 | { |
166 | | // #i10613# determine if the action is transparency capable |
167 | | |
168 | | // #107169# Also examine metafiles with masked bitmaps in |
169 | | // detail. Further down, this is optimized in such a way |
170 | | // that there's no unnecessary painting of masked bitmaps |
171 | | // (which are _always_ subdivided into rectangular regions |
172 | | // of uniform opacity): if a masked bitmap is printed over |
173 | | // empty background, we convert to a plain bitmap with |
174 | | // white background. |
175 | 0 | if (pCurrAct->IsTransparent()) |
176 | 0 | return true; |
177 | 0 | } |
178 | | |
179 | 0 | return false; |
180 | 0 | } |
181 | | |
182 | | size_t GDIMetaFile::GetActionSize() const |
183 | 282k | { |
184 | 282k | return m_aList.size(); |
185 | 282k | } |
186 | | |
187 | | MetaAction* GDIMetaFile::GetAction( size_t nAction ) const |
188 | 15.3M | { |
189 | 15.3M | return (nAction < m_aList.size()) ? m_aList[ nAction ].get() : nullptr; |
190 | 15.3M | } |
191 | | |
192 | | MetaAction* GDIMetaFile::FirstAction() |
193 | 7.78k | { |
194 | 7.78k | m_nCurrentActionElement = 0; |
195 | 7.78k | return m_aList.empty() ? nullptr : m_aList[ 0 ].get(); |
196 | 7.78k | } |
197 | | |
198 | | MetaAction* GDIMetaFile::NextAction() |
199 | 8.46M | { |
200 | 8.46M | return ( m_nCurrentActionElement + 1 < m_aList.size() ) ? m_aList[ ++m_nCurrentActionElement ].get() : nullptr; |
201 | 8.46M | } |
202 | | |
203 | | void GDIMetaFile::ReplaceAction( rtl::Reference<MetaAction> pAction, size_t nAction ) |
204 | 0 | { |
205 | 0 | if ( nAction >= m_aList.size() ) |
206 | 0 | { |
207 | 0 | return; |
208 | 0 | } |
209 | 0 | m_aList[nAction] = std::move(pAction); |
210 | 0 | } |
211 | | |
212 | | GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf ) |
213 | 100k | { |
214 | 100k | if( this != &rMtf ) |
215 | 100k | { |
216 | 100k | Clear(); |
217 | | |
218 | | // Increment RefCount of MetaActions |
219 | 7.32M | for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i ) |
220 | 7.22M | { |
221 | 7.22M | m_aList.push_back( rMtf.GetAction( i ) ); |
222 | 7.22M | } |
223 | | |
224 | 100k | m_aPrefMapMode = rMtf.m_aPrefMapMode; |
225 | 100k | m_aPrefSize = rMtf.m_aPrefSize; |
226 | 100k | m_pPrev = rMtf.m_pPrev; |
227 | 100k | m_pNext = rMtf.m_pNext; |
228 | 100k | m_pOutDev = nullptr; |
229 | 100k | m_bPause = false; |
230 | 100k | m_bRecord = false; |
231 | 100k | m_bUseCanvas = rMtf.m_bUseCanvas; |
232 | 100k | m_bSVG = rMtf.m_bSVG; |
233 | | |
234 | 100k | if( rMtf.m_bRecord ) |
235 | 0 | { |
236 | 0 | Record( rMtf.m_pOutDev ); |
237 | |
|
238 | 0 | if( rMtf.m_bPause ) |
239 | 0 | Pause( true ); |
240 | 0 | } |
241 | 100k | } |
242 | | |
243 | 100k | return *this; |
244 | 100k | } |
245 | | |
246 | | bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const |
247 | 0 | { |
248 | 0 | const size_t nObjCount = m_aList.size(); |
249 | 0 | bool bRet = false; |
250 | |
|
251 | 0 | if( this == &rMtf ) |
252 | 0 | bRet = true; |
253 | 0 | else if( rMtf.GetActionSize() == nObjCount && |
254 | 0 | rMtf.GetPrefSize() == m_aPrefSize && |
255 | 0 | rMtf.GetPrefMapMode() == m_aPrefMapMode ) |
256 | 0 | { |
257 | 0 | bRet = true; |
258 | |
|
259 | 0 | for( size_t n = 0; n < nObjCount; n++ ) |
260 | 0 | { |
261 | 0 | if( m_aList[ n ] != rMtf.GetAction( n ) ) |
262 | 0 | { |
263 | 0 | bRet = false; |
264 | 0 | break; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | } |
268 | |
|
269 | 0 | return bRet; |
270 | 0 | } |
271 | | |
272 | | void GDIMetaFile::Clear() |
273 | 1.50M | { |
274 | 1.50M | if( m_bRecord ) |
275 | 428 | Stop(); |
276 | | |
277 | 1.50M | m_aList.clear(); |
278 | 1.50M | } |
279 | | |
280 | | void GDIMetaFile::Linker( OutputDevice* pOut, bool bLink ) |
281 | 150k | { |
282 | 150k | if( bLink ) |
283 | 75.1k | { |
284 | 75.1k | m_pNext = nullptr; |
285 | 75.1k | m_pPrev = pOut->GetConnectMetaFile(); |
286 | 75.1k | pOut->SetConnectMetaFile( this ); |
287 | | |
288 | 75.1k | if( m_pPrev ) |
289 | 0 | m_pPrev->m_pNext = this; |
290 | 75.1k | } |
291 | 75.1k | else |
292 | 75.1k | { |
293 | 75.1k | if( m_pNext ) |
294 | 0 | { |
295 | 0 | m_pNext->m_pPrev = m_pPrev; |
296 | |
|
297 | 0 | if( m_pPrev ) |
298 | 0 | m_pPrev->m_pNext = m_pNext; |
299 | 0 | } |
300 | 75.1k | else |
301 | 75.1k | { |
302 | 75.1k | if( m_pPrev ) |
303 | 0 | m_pPrev->m_pNext = nullptr; |
304 | | |
305 | 75.1k | pOut->SetConnectMetaFile( m_pPrev ); |
306 | 75.1k | } |
307 | | |
308 | 75.1k | m_pPrev = nullptr; |
309 | 75.1k | m_pNext = nullptr; |
310 | 75.1k | } |
311 | 150k | } |
312 | | |
313 | | void GDIMetaFile::Record( OutputDevice* pOut ) |
314 | 75.1k | { |
315 | 75.1k | if( m_bRecord ) |
316 | 0 | Stop(); |
317 | | |
318 | 75.1k | m_nCurrentActionElement = m_aList.empty() ? 0 : (m_aList.size() - 1); |
319 | 75.1k | m_pOutDev = pOut; |
320 | 75.1k | m_bRecord = true; |
321 | 75.1k | Linker( pOut, true ); |
322 | 75.1k | } |
323 | | |
324 | | void GDIMetaFile::Play( GDIMetaFile& rMtf ) |
325 | 26 | { |
326 | 26 | if (m_bRecord || rMtf.m_bRecord) |
327 | 0 | return; |
328 | | |
329 | 26 | MetaAction* pAction = GetCurAction(); |
330 | 26 | const size_t nObjCount = m_aList.size(); |
331 | | |
332 | 26 | rMtf.UseCanvas( rMtf.GetUseCanvas() || m_bUseCanvas ); |
333 | 26 | rMtf.setSVG( rMtf.getSVG() || m_bSVG ); |
334 | | |
335 | 1.54k | for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nObjCount; nCurPos++ ) |
336 | 1.51k | { |
337 | 1.51k | if( pAction ) |
338 | 1.51k | { |
339 | 1.51k | rMtf.AddAction( pAction ); |
340 | 1.51k | } |
341 | | |
342 | 1.51k | pAction = NextAction(); |
343 | 1.51k | } |
344 | 26 | } |
345 | | |
346 | | void GDIMetaFile::Play(OutputDevice& rOut, size_t nPos) |
347 | 11.3k | { |
348 | 11.3k | if( m_bRecord ) |
349 | 0 | return; |
350 | | |
351 | 11.3k | MetaAction* pAction = GetCurAction(); |
352 | 11.3k | const size_t nObjCount = m_aList.size(); |
353 | 11.3k | size_t nSyncCount = rOut.GetSyncCount(); |
354 | | |
355 | 11.3k | if( nPos > nObjCount ) |
356 | 11.3k | nPos = nObjCount; |
357 | | |
358 | | // #i23407# Set backwards-compatible text language and layout mode |
359 | | // This is necessary, since old metafiles don't even know of these |
360 | | // recent add-ons. Newer metafiles must of course explicitly set |
361 | | // those states. |
362 | 11.3k | auto popIt = rOut.ScopedPush(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE); |
363 | 11.3k | rOut.SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default); |
364 | 11.3k | rOut.SetDigitLanguage(LANGUAGE_SYSTEM); |
365 | | |
366 | 11.3k | SAL_INFO( "vcl.gdi", "GDIMetaFile::Play on device of size: " << rOut.GetOutputSizePixel().Width() << " " << rOut.GetOutputSizePixel().Height()); |
367 | | |
368 | 11.3k | if (!ImplPlayWithRenderer(rOut, Point(0,0), rOut.GetOutputSize())) { |
369 | 11.3k | size_t i = 0; |
370 | 2.40M | for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nPos; nCurPos++ ) |
371 | 2.39M | { |
372 | 2.39M | if( pAction ) |
373 | 2.39M | { |
374 | 2.39M | pAction->Execute(&rOut); |
375 | | |
376 | | // flush output from time to time |
377 | 2.39M | if( i++ > nSyncCount ) |
378 | 0 | { |
379 | 0 | rOut.Flush(); |
380 | 0 | i = 0; |
381 | 0 | } |
382 | 2.39M | } |
383 | | |
384 | 2.39M | pAction = NextAction(); |
385 | 2.39M | } |
386 | 11.3k | } |
387 | 11.3k | } |
388 | | |
389 | | bool GDIMetaFile::ImplPlayWithRenderer(OutputDevice& rOut, const Point& rPos, Size rLogicDestSize) |
390 | 12.1k | { |
391 | 12.1k | if (!m_bUseCanvas) |
392 | 12.1k | return false; |
393 | | |
394 | 4 | Size rDestSize(rOut.LogicToPixel(rLogicDestSize)); |
395 | | |
396 | 4 | const vcl::Window* win = rOut.GetOwnerWindow(); |
397 | | |
398 | 4 | if (!win) |
399 | 4 | win = Application::GetActiveTopWindow(); |
400 | 4 | if (!win) |
401 | 4 | win = Application::GetFirstTopLevelWindow(); |
402 | | |
403 | 4 | if (!win) |
404 | 0 | return false; |
405 | | |
406 | 4 | try |
407 | 4 | { |
408 | 4 | uno::Reference<rendering::XCanvas> xCanvas = win->GetOutDev()->GetCanvas (); |
409 | | |
410 | 4 | if (!xCanvas.is()) |
411 | 4 | return false; |
412 | | |
413 | 0 | Size aSize (rDestSize.Width () + 1, rDestSize.Height () + 1); |
414 | 0 | uno::Reference<rendering::XBitmap> xBitmap = xCanvas->getDevice ()->createCompatibleAlphaBitmap (vcl::unotools::integerSize2DFromSize( aSize)); |
415 | 0 | if( xBitmap.is () ) |
416 | 0 | { |
417 | 0 | uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( xBitmap, uno::UNO_QUERY ); |
418 | 0 | if( xBitmapCanvas.is() ) |
419 | 0 | { |
420 | 0 | const uno::Reference< uno::XComponentContext >& xContext = comphelper::getProcessComponentContext(); |
421 | 0 | uno::Reference< rendering::XMtfRenderer > xMtfRenderer = rendering::MtfRenderer::createWithBitmapCanvas( xContext, xBitmapCanvas ); |
422 | |
|
423 | 0 | xBitmapCanvas->clear(); |
424 | 0 | uno::Reference< beans::XFastPropertySet > xMtfFastPropertySet( xMtfRenderer, uno::UNO_QUERY ); |
425 | 0 | if( xMtfFastPropertySet.is() ) |
426 | | // set this metafile to the renderer to |
427 | | // speedup things (instead of copying data to |
428 | | // sequence of bytes passed to renderer) |
429 | 0 | xMtfFastPropertySet->setFastPropertyValue( 0, uno::Any( reinterpret_cast<sal_Int64>( this ) ) ); |
430 | |
|
431 | 0 | xMtfRenderer->draw( rDestSize.Width(), rDestSize.Height() ); |
432 | |
|
433 | 0 | Bitmap aBitmap; |
434 | 0 | if( aBitmap.Create( xBitmapCanvas, aSize ) ) |
435 | 0 | { |
436 | 0 | if (rOut.GetMapMode().GetMapUnit() == MapUnit::MapPixel) |
437 | 0 | rOut.DrawBitmap( rPos, aBitmap ); |
438 | 0 | else |
439 | 0 | rOut.DrawBitmap( rPos, rLogicDestSize, aBitmap ); |
440 | 0 | return true; |
441 | 0 | } |
442 | 0 | } |
443 | 0 | } |
444 | 0 | } |
445 | 4 | catch (const uno::RuntimeException& ) |
446 | 4 | { |
447 | 0 | throw; // runtime errors are fatal |
448 | 0 | } |
449 | 4 | catch (const uno::Exception&) |
450 | 4 | { |
451 | | // ignore errors, no way of reporting them here |
452 | 0 | TOOLS_WARN_EXCEPTION("vcl.gdi", "GDIMetaFile::ImplPlayWithRenderer"); |
453 | 0 | } |
454 | | |
455 | 0 | return false; |
456 | 4 | } |
457 | | |
458 | | void GDIMetaFile::Play(OutputDevice& rOut, const Point& rPos, |
459 | | const Size& rSize) |
460 | 978 | { |
461 | 978 | MapMode aDrawMap( GetPrefMapMode() ); |
462 | 978 | Size aDestSize(rOut.LogicToPixel(rSize)); |
463 | | |
464 | 978 | if (aDestSize.Width() <= 0 || aDestSize.Height() <= 0) |
465 | 96 | return; |
466 | | |
467 | 882 | if (aDestSize.Width() > std::numeric_limits<sal_Int32>::max() || |
468 | 861 | aDestSize.Height() > std::numeric_limits<sal_Int32>::max()) |
469 | 40 | return; |
470 | | |
471 | 842 | GDIMetaFile* pMtf = rOut.GetConnectMetaFile(); |
472 | | |
473 | 842 | if (ImplPlayWithRenderer(rOut, rPos, rSize)) |
474 | 0 | return; |
475 | | |
476 | 842 | Size aTmpPrefSize(rOut.LogicToPixel(GetPrefSize(), aDrawMap)); |
477 | | |
478 | 842 | if( !aTmpPrefSize.Width() ) |
479 | 436 | aTmpPrefSize.setWidth( aDestSize.Width() ); |
480 | | |
481 | 842 | if( !aTmpPrefSize.Height() ) |
482 | 285 | aTmpPrefSize.setHeight( aDestSize.Height() ); |
483 | | |
484 | 842 | Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() ); |
485 | 842 | Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() ); |
486 | | |
487 | 842 | aScaleX *= aDrawMap.GetScaleX(); |
488 | 842 | aScaleY *= aDrawMap.GetScaleY(); |
489 | | // try reducing inaccurary first and abandon if the scaling |
490 | | // still cannot be achieved |
491 | 842 | if (TooLargeScaleForMapMode(aScaleX, rOut.GetDPIX())) |
492 | 208 | aScaleX.ReduceInaccurate(10); |
493 | 842 | if (TooLargeScaleForMapMode(aScaleY, rOut.GetDPIY())) |
494 | 327 | aScaleY.ReduceInaccurate(10); |
495 | 842 | if (TooLargeScaleForMapMode(aScaleX, rOut.GetDPIX()) || |
496 | 838 | TooLargeScaleForMapMode(aScaleY, rOut.GetDPIY())) |
497 | 14 | { |
498 | 14 | SAL_WARN("vcl", "GDIMetaFile Scaling is too high"); |
499 | 14 | return; |
500 | 14 | } |
501 | | |
502 | 828 | aDrawMap.SetScaleX(aScaleX); |
503 | 828 | aDrawMap.SetScaleY(aScaleY); |
504 | | |
505 | | // #i47260# Convert logical output position to offset within |
506 | | // the metafile's mapmode. Therefore, disable pixel offset on |
507 | | // outdev, it's inverse mnOutOffLogicX/Y is calculated for a |
508 | | // different mapmode (the one currently set on rOut, that is) |
509 | | // - thus, aDrawMap's origin would generally be wrong. And |
510 | | // even _if_ aDrawMap is similar to pOutDev's current mapmode, |
511 | | // it's _still_ undesirable to have pixel offset unequal zero, |
512 | | // because one would still get round-off errors (the |
513 | | // round-trip error for LogicToPixel( PixelToLogic() ) was the |
514 | | // reason for having pixel offset in the first place). |
515 | 828 | const Size aOldOffset(rOut.GetPixelOffset()); |
516 | 828 | const Size aEmptySize; |
517 | 828 | rOut.SetPixelOffset(aEmptySize); |
518 | 828 | aDrawMap.SetOrigin(rOut.PixelToLogic(rOut.LogicToPixel(rPos), aDrawMap)); |
519 | 828 | rOut.SetPixelOffset(aOldOffset); |
520 | | |
521 | 828 | auto popIt = rOut.ScopedPush(); |
522 | | |
523 | 828 | bool bIsRecord = (pMtf && pMtf->IsRecord()); |
524 | 828 | rOut.SetMetafileMapMode(aDrawMap, bIsRecord); |
525 | | |
526 | | // #i23407# Set backwards-compatible text language and layout mode |
527 | | // This is necessary, since old metafiles don't even know of these |
528 | | // recent add-ons. Newer metafiles must of course explicitly set |
529 | | // those states. |
530 | 828 | rOut.SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default); |
531 | 828 | rOut.SetDigitLanguage(LANGUAGE_SYSTEM); |
532 | | |
533 | 828 | Play(rOut); |
534 | 828 | } |
535 | | |
536 | | void GDIMetaFile::Pause( bool _bPause ) |
537 | 0 | { |
538 | 0 | if( !m_bRecord ) |
539 | 0 | return; |
540 | | |
541 | 0 | if( _bPause ) |
542 | 0 | { |
543 | 0 | if( !m_bPause ) |
544 | 0 | Linker( m_pOutDev, false ); |
545 | 0 | } |
546 | 0 | else |
547 | 0 | { |
548 | 0 | if( m_bPause ) |
549 | 0 | Linker( m_pOutDev, true ); |
550 | 0 | } |
551 | |
|
552 | 0 | m_bPause = _bPause; |
553 | 0 | } |
554 | | |
555 | | void GDIMetaFile::Stop() |
556 | 96.6k | { |
557 | 96.6k | if( m_bRecord ) |
558 | 75.1k | { |
559 | 75.1k | m_bRecord = false; |
560 | | |
561 | 75.1k | if( !m_bPause ) |
562 | 75.1k | Linker( m_pOutDev, false ); |
563 | 0 | else |
564 | 0 | m_bPause = false; |
565 | 75.1k | } |
566 | 96.6k | } |
567 | | |
568 | | void GDIMetaFile::WindStart() |
569 | 81.6k | { |
570 | 81.6k | if( !m_bRecord ) |
571 | 81.6k | m_nCurrentActionElement = 0; |
572 | 81.6k | } |
573 | | |
574 | | void GDIMetaFile::WindPrev() |
575 | 0 | { |
576 | 0 | if( !m_bRecord ) |
577 | 0 | if ( m_nCurrentActionElement > 0 ) |
578 | 0 | --m_nCurrentActionElement; |
579 | 0 | } |
580 | | |
581 | | void GDIMetaFile::AddAction(const rtl::Reference<MetaAction>& pAction) |
582 | 16.6M | { |
583 | 16.6M | m_aList.push_back( pAction ); |
584 | | |
585 | 16.6M | if( m_pPrev ) |
586 | 0 | { |
587 | 0 | m_pPrev->AddAction( pAction ); |
588 | 0 | } |
589 | 16.6M | } |
590 | | |
591 | | void GDIMetaFile::AddAction(const rtl::Reference<MetaAction>& pAction, size_t nPos) |
592 | 0 | { |
593 | 0 | if ( nPos < m_aList.size() ) |
594 | 0 | { |
595 | 0 | m_aList.insert( m_aList.begin() + nPos, pAction ); |
596 | 0 | } |
597 | 0 | else |
598 | 0 | { |
599 | 0 | m_aList.push_back( pAction ); |
600 | 0 | } |
601 | |
|
602 | 0 | if( m_pPrev ) |
603 | 0 | { |
604 | 0 | m_pPrev->AddAction( pAction, nPos ); |
605 | 0 | } |
606 | 0 | } |
607 | | |
608 | | void GDIMetaFile::push_back(const rtl::Reference<MetaAction>& pAction) |
609 | 0 | { |
610 | 0 | m_aList.push_back( pAction ); |
611 | 0 | } |
612 | | |
613 | | void GDIMetaFile::Mirror( BmpMirrorFlags nMirrorFlags ) |
614 | 0 | { |
615 | 0 | const Size aOldPrefSize( GetPrefSize() ); |
616 | 0 | tools::Long nMoveX, nMoveY; |
617 | 0 | double fScaleX, fScaleY; |
618 | |
|
619 | 0 | if( nMirrorFlags & BmpMirrorFlags::Horizontal ) |
620 | 0 | { |
621 | 0 | nMoveX = std::abs( aOldPrefSize.Width() ) - 1; |
622 | 0 | fScaleX = -1.0; |
623 | 0 | } |
624 | 0 | else |
625 | 0 | { |
626 | 0 | nMoveX = 0; |
627 | 0 | fScaleX = 1.0; |
628 | 0 | } |
629 | |
|
630 | 0 | if( nMirrorFlags & BmpMirrorFlags::Vertical ) |
631 | 0 | { |
632 | 0 | nMoveY = std::abs( aOldPrefSize.Height() ) - 1; |
633 | 0 | fScaleY = -1.0; |
634 | 0 | } |
635 | 0 | else |
636 | 0 | { |
637 | 0 | nMoveY = 0; |
638 | 0 | fScaleY = 1.0; |
639 | 0 | } |
640 | |
|
641 | 0 | if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) ) |
642 | 0 | { |
643 | 0 | Scale( fScaleX, fScaleY ); |
644 | 0 | Move( nMoveX, nMoveY ); |
645 | 0 | SetPrefSize( aOldPrefSize ); |
646 | 0 | } |
647 | 0 | } |
648 | | |
649 | | void GDIMetaFile::Move( tools::Long nX, tools::Long nY ) |
650 | 7.52k | { |
651 | 7.52k | const Size aBaseOffset( nX, nY ); |
652 | 7.52k | Size aOffset( aBaseOffset ); |
653 | 7.52k | ScopedVclPtrInstance< VirtualDevice > aMapVDev; |
654 | | |
655 | 7.52k | aMapVDev->EnableOutput( false ); |
656 | 7.52k | aMapVDev->SetMapMode( GetPrefMapMode() ); |
657 | | |
658 | 6.04M | for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) |
659 | 6.04M | { |
660 | 6.04M | const MetaActionType nType = pAct->GetType(); |
661 | 6.04M | MetaAction* pModAct; |
662 | | |
663 | 6.04M | if( pAct->GetRefCount() > 1 ) |
664 | 0 | { |
665 | 0 | m_aList[ m_nCurrentActionElement ] = pAct->Clone(); |
666 | 0 | pModAct = m_aList[ m_nCurrentActionElement ].get(); |
667 | 0 | } |
668 | 6.04M | else |
669 | 6.04M | pModAct = pAct; |
670 | | |
671 | 6.04M | if( ( MetaActionType::MAPMODE == nType ) || |
672 | 6.04M | ( MetaActionType::PUSH == nType ) || |
673 | 5.01M | ( MetaActionType::POP == nType ) ) |
674 | 2.05M | { |
675 | 2.05M | pModAct->Execute( aMapVDev.get() ); |
676 | 2.05M | aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() ); |
677 | 2.05M | } |
678 | | |
679 | 6.04M | pModAct->Move( aOffset.Width(), aOffset.Height() ); |
680 | 6.04M | } |
681 | 7.52k | } |
682 | | |
683 | | void GDIMetaFile::Move( tools::Long nX, tools::Long nY, tools::Long nDPIX, tools::Long nDPIY ) |
684 | 0 | { |
685 | 0 | const Size aBaseOffset( nX, nY ); |
686 | 0 | Size aOffset( aBaseOffset ); |
687 | 0 | ScopedVclPtrInstance< VirtualDevice > aMapVDev; |
688 | |
|
689 | 0 | aMapVDev->EnableOutput( false ); |
690 | 0 | aMapVDev->SetReferenceDevice( nDPIX, nDPIY ); |
691 | 0 | aMapVDev->SetMapMode( GetPrefMapMode() ); |
692 | |
|
693 | 0 | for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) |
694 | 0 | { |
695 | 0 | const MetaActionType nType = pAct->GetType(); |
696 | 0 | MetaAction* pModAct; |
697 | |
|
698 | 0 | if( pAct->GetRefCount() > 1 ) |
699 | 0 | { |
700 | 0 | m_aList[ m_nCurrentActionElement ] = pAct->Clone(); |
701 | 0 | pModAct = m_aList[ m_nCurrentActionElement ].get(); |
702 | 0 | } |
703 | 0 | else |
704 | 0 | pModAct = pAct; |
705 | |
|
706 | 0 | if( ( MetaActionType::MAPMODE == nType ) || |
707 | 0 | ( MetaActionType::PUSH == nType ) || |
708 | 0 | ( MetaActionType::POP == nType ) ) |
709 | 0 | { |
710 | 0 | pModAct->Execute( aMapVDev.get() ); |
711 | 0 | if( aMapVDev->GetMapMode().GetMapUnit() == MapUnit::MapPixel ) |
712 | 0 | { |
713 | 0 | aOffset = aMapVDev->LogicToPixel( aBaseOffset, GetPrefMapMode() ); |
714 | 0 | MapMode aMap( aMapVDev->GetMapMode() ); |
715 | 0 | aOffset.setWidth( static_cast<tools::Long>(aOffset.Width() * static_cast<double>(aMap.GetScaleX())) ); |
716 | 0 | aOffset.setHeight( static_cast<tools::Long>(aOffset.Height() * static_cast<double>(aMap.GetScaleY())) ); |
717 | 0 | } |
718 | 0 | else |
719 | 0 | aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() ); |
720 | 0 | } |
721 | |
|
722 | 0 | pModAct->Move( aOffset.Width(), aOffset.Height() ); |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | | void GDIMetaFile::ScaleActions(double const fScaleX, double const fScaleY) |
727 | 132 | { |
728 | 13.3k | for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) |
729 | 13.1k | { |
730 | 13.1k | MetaAction* pModAct; |
731 | | |
732 | 13.1k | if( pAct->GetRefCount() > 1 ) |
733 | 13.1k | { |
734 | 13.1k | m_aList[ m_nCurrentActionElement ] = pAct->Clone(); |
735 | 13.1k | pModAct = m_aList[ m_nCurrentActionElement ].get(); |
736 | 13.1k | } |
737 | 0 | else |
738 | 0 | pModAct = pAct; |
739 | | |
740 | 13.1k | pModAct->Scale( fScaleX, fScaleY ); |
741 | 13.1k | } |
742 | 132 | } |
743 | | |
744 | | void GDIMetaFile::Scale( double fScaleX, double fScaleY ) |
745 | 132 | { |
746 | 132 | ScaleActions(fScaleX, fScaleY); |
747 | | |
748 | 132 | m_aPrefSize.setWidth(basegfx::fround<tools::Long>(m_aPrefSize.Width() * fScaleX)); |
749 | 132 | m_aPrefSize.setHeight(basegfx::fround<tools::Long>(m_aPrefSize.Height() * fScaleY)); |
750 | 132 | } |
751 | | |
752 | | void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY ) |
753 | 132 | { |
754 | 132 | Scale( static_cast<double>(rScaleX), static_cast<double>(rScaleY) ); |
755 | 132 | } |
756 | | |
757 | | void GDIMetaFile::Clip( const tools::Rectangle& i_rClipRect ) |
758 | 0 | { |
759 | 0 | tools::Rectangle aCurRect( i_rClipRect ); |
760 | 0 | ScopedVclPtrInstance< VirtualDevice > aMapVDev; |
761 | |
|
762 | 0 | aMapVDev->EnableOutput( false ); |
763 | 0 | aMapVDev->SetMapMode( GetPrefMapMode() ); |
764 | |
|
765 | 0 | for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) |
766 | 0 | { |
767 | 0 | const MetaActionType nType = pAct->GetType(); |
768 | |
|
769 | 0 | if( ( MetaActionType::MAPMODE == nType ) || |
770 | 0 | ( MetaActionType::PUSH == nType ) || |
771 | 0 | ( MetaActionType::POP == nType ) ) |
772 | 0 | { |
773 | 0 | pAct->Execute( aMapVDev.get() ); |
774 | 0 | aCurRect = OutputDevice::LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev->GetMapMode() ); |
775 | 0 | } |
776 | 0 | else if( nType == MetaActionType::CLIPREGION ) |
777 | 0 | { |
778 | 0 | MetaClipRegionAction* pOldAct = static_cast<MetaClipRegionAction*>(pAct); |
779 | 0 | vcl::Region aNewReg( aCurRect ); |
780 | 0 | if( pOldAct->IsClipping() ) |
781 | 0 | aNewReg.Intersect( pOldAct->GetRegion() ); |
782 | 0 | MetaClipRegionAction* pNewAct = new MetaClipRegionAction( std::move(aNewReg), true ); |
783 | 0 | m_aList[ m_nCurrentActionElement ] = pNewAct; |
784 | 0 | } |
785 | 0 | } |
786 | 0 | } |
787 | | |
788 | | Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt, |
789 | | const Size& rOffset, double fSin, double fCos ) |
790 | 0 | { |
791 | 0 | const tools::Long nX = rPt.X() - rRotatePt.X(); |
792 | 0 | const tools::Long nY = rPt.Y() - rRotatePt.Y(); |
793 | |
|
794 | 0 | return { basegfx::fround<tools::Long>(fCos * nX + fSin * nY) + rRotatePt.X() + rOffset.Width(), |
795 | 0 | basegfx::fround<tools::Long>(fCos * nY - fSin * nX) + rRotatePt.Y() + rOffset.Height() }; |
796 | 0 | } |
797 | | |
798 | | tools::Polygon GDIMetaFile::ImplGetRotatedPolygon( const tools::Polygon& rPoly, const Point& rRotatePt, |
799 | | const Size& rOffset, double fSin, double fCos ) |
800 | 0 | { |
801 | 0 | tools::Polygon aRet( rPoly ); |
802 | |
|
803 | 0 | aRet.Rotate( rRotatePt, fSin, fCos ); |
804 | 0 | aRet.Move( rOffset.Width(), rOffset.Height() ); |
805 | |
|
806 | 0 | return aRet; |
807 | 0 | } |
808 | | |
809 | | tools::PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const tools::PolyPolygon& rPolyPoly, const Point& rRotatePt, |
810 | | const Size& rOffset, double fSin, double fCos ) |
811 | 0 | { |
812 | 0 | tools::PolyPolygon aRet( rPolyPoly ); |
813 | |
|
814 | 0 | aRet.Rotate( rRotatePt, fSin, fCos ); |
815 | 0 | aRet.Move( rOffset.Width(), rOffset.Height() ); |
816 | |
|
817 | 0 | return aRet; |
818 | 0 | } |
819 | | |
820 | | void GDIMetaFile::ImplAddGradientEx( GDIMetaFile& rMtf, |
821 | | const OutputDevice& rMapDev, |
822 | | const tools::PolyPolygon& rPolyPoly, |
823 | | const Gradient& rGrad ) |
824 | 0 | { |
825 | | // Generate comment, GradientEx and Gradient actions (within DrawGradient) |
826 | 0 | ScopedVclPtrInstance< VirtualDevice > aVDev(rMapDev, DeviceFormat::WITHOUT_ALPHA); |
827 | 0 | aVDev->EnableOutput( false ); |
828 | 0 | GDIMetaFile aGradMtf; |
829 | |
|
830 | 0 | aGradMtf.Record( aVDev.get() ); |
831 | 0 | aVDev->DrawGradient( rPolyPoly, rGrad ); |
832 | 0 | aGradMtf.Stop(); |
833 | |
|
834 | 0 | size_t i, nAct( aGradMtf.GetActionSize() ); |
835 | 0 | for( i=0; i < nAct; ++i ) |
836 | 0 | { |
837 | 0 | MetaAction* pMetaAct = aGradMtf.GetAction( i ); |
838 | 0 | rMtf.AddAction( pMetaAct ); |
839 | 0 | } |
840 | 0 | } |
841 | | |
842 | | void GDIMetaFile::Rotate( Degree10 nAngle10 ) |
843 | 0 | { |
844 | 0 | nAngle10 %= 3600_deg10; |
845 | 0 | nAngle10 = ( nAngle10 < 0_deg10 ) ? ( Degree10(3599) + nAngle10 ) : nAngle10; |
846 | |
|
847 | 0 | if( !nAngle10 ) |
848 | 0 | return; |
849 | | |
850 | 0 | GDIMetaFile aMtf; |
851 | 0 | ScopedVclPtrInstance< VirtualDevice > aMapVDev(DeviceFormat::WITH_ALPHA); |
852 | 0 | const double fAngle = toRadians(nAngle10); |
853 | 0 | const double fSin = sin( fAngle ); |
854 | 0 | const double fCos = cos( fAngle ); |
855 | 0 | tools::Rectangle aRect( Point(), GetPrefSize() ); |
856 | 0 | tools::Polygon aPoly( aRect ); |
857 | |
|
858 | 0 | aPoly.Rotate( Point(), fSin, fCos ); |
859 | |
|
860 | 0 | aMapVDev->EnableOutput( false ); |
861 | 0 | aMapVDev->SetMapMode( GetPrefMapMode() ); |
862 | |
|
863 | 0 | const tools::Rectangle aNewBound( aPoly.GetBoundRect() ); |
864 | |
|
865 | 0 | const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() ); |
866 | 0 | const Size aOffset( -aNewBound.Left(), -aNewBound.Top() ); |
867 | |
|
868 | 0 | Point aRotAnchor( aOrigin ); |
869 | 0 | Size aRotOffset( aOffset ); |
870 | |
|
871 | 0 | for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() ) |
872 | 0 | { |
873 | 0 | const MetaActionType nActionType = pAction->GetType(); |
874 | |
|
875 | 0 | switch( nActionType ) |
876 | 0 | { |
877 | 0 | case MetaActionType::PIXEL: |
878 | 0 | { |
879 | 0 | MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction); |
880 | 0 | aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
881 | 0 | pAct->GetColor() ) ); |
882 | 0 | } |
883 | 0 | break; |
884 | | |
885 | 0 | case MetaActionType::POINT: |
886 | 0 | { |
887 | 0 | MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction); |
888 | 0 | aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
889 | 0 | } |
890 | 0 | break; |
891 | | |
892 | 0 | case MetaActionType::LINE: |
893 | 0 | { |
894 | 0 | MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction); |
895 | 0 | aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
896 | 0 | ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
897 | 0 | pAct->GetLineInfo() ) ); |
898 | 0 | } |
899 | 0 | break; |
900 | | |
901 | 0 | case MetaActionType::RECT: |
902 | 0 | { |
903 | 0 | MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction); |
904 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( tools::Polygon(pAct->GetRect()), aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
905 | 0 | } |
906 | 0 | break; |
907 | | |
908 | 0 | case MetaActionType::ROUNDRECT: |
909 | 0 | { |
910 | 0 | MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction); |
911 | 0 | const tools::Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() ); |
912 | |
|
913 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
914 | 0 | } |
915 | 0 | break; |
916 | | |
917 | 0 | case MetaActionType::ELLIPSE: |
918 | 0 | { |
919 | 0 | MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction); |
920 | 0 | const tools::Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 ); |
921 | |
|
922 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
923 | 0 | } |
924 | 0 | break; |
925 | | |
926 | 0 | case MetaActionType::ARC: |
927 | 0 | { |
928 | 0 | MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction); |
929 | 0 | const tools::Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Arc ); |
930 | |
|
931 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
932 | 0 | } |
933 | 0 | break; |
934 | | |
935 | 0 | case MetaActionType::PIE: |
936 | 0 | { |
937 | 0 | MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction); |
938 | 0 | const tools::Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Pie ); |
939 | |
|
940 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
941 | 0 | } |
942 | 0 | break; |
943 | | |
944 | 0 | case MetaActionType::CHORD: |
945 | 0 | { |
946 | 0 | MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction); |
947 | 0 | const tools::Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Chord ); |
948 | |
|
949 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
950 | 0 | } |
951 | 0 | break; |
952 | | |
953 | 0 | case MetaActionType::POLYLINE: |
954 | 0 | { |
955 | 0 | MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction); |
956 | 0 | aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) ); |
957 | 0 | } |
958 | 0 | break; |
959 | | |
960 | 0 | case MetaActionType::POLYGON: |
961 | 0 | { |
962 | 0 | MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction); |
963 | 0 | aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
964 | 0 | } |
965 | 0 | break; |
966 | | |
967 | 0 | case MetaActionType::POLYPOLYGON: |
968 | 0 | { |
969 | 0 | MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction); |
970 | 0 | aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); |
971 | 0 | } |
972 | 0 | break; |
973 | | |
974 | 0 | case MetaActionType::TEXT: |
975 | 0 | { |
976 | 0 | MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction); |
977 | 0 | aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
978 | 0 | pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) ); |
979 | 0 | } |
980 | 0 | break; |
981 | | |
982 | 0 | case MetaActionType::TEXTARRAY: |
983 | 0 | { |
984 | 0 | MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction); |
985 | 0 | aMtf.AddAction(new MetaTextArrayAction( |
986 | 0 | ImplGetRotatedPoint(pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos), |
987 | 0 | pAct->GetText(), pAct->GetDXArray(), pAct->GetKashidaArray(), pAct->GetIndex(), |
988 | 0 | pAct->GetLen(), pAct->GetLayoutContextIndex(), pAct->GetLayoutContextLen())); |
989 | 0 | } |
990 | 0 | break; |
991 | | |
992 | 0 | case MetaActionType::STRETCHTEXT: |
993 | 0 | { |
994 | 0 | MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction); |
995 | 0 | aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
996 | 0 | pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) ); |
997 | 0 | } |
998 | 0 | break; |
999 | | |
1000 | 0 | case MetaActionType::TEXTLINE: |
1001 | 0 | { |
1002 | 0 | MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction); |
1003 | 0 | aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ), |
1004 | 0 | pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) ); |
1005 | 0 | } |
1006 | 0 | break; |
1007 | | |
1008 | 0 | case MetaActionType::BMPSCALE: |
1009 | 0 | { |
1010 | 0 | MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction); |
1011 | 0 | tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetPoint(), pAct->GetSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1012 | 0 | tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); |
1013 | 0 | Bitmap aBmp( pAct->GetBitmap() ); |
1014 | |
|
1015 | 0 | aBmp.Rotate( nAngle10, COL_TRANSPARENT ); |
1016 | 0 | aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), |
1017 | 0 | aBmp ) ); |
1018 | 0 | } |
1019 | 0 | break; |
1020 | | |
1021 | 0 | case MetaActionType::BMPSCALEPART: |
1022 | 0 | { |
1023 | 0 | MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction); |
1024 | 0 | tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1025 | 0 | tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); |
1026 | 0 | Bitmap aBmp( pAct->GetBitmap() ); |
1027 | |
|
1028 | 0 | aBmp.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) ); |
1029 | 0 | aBmp.Rotate( nAngle10, COL_TRANSPARENT ); |
1030 | |
|
1031 | 0 | aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmp ) ); |
1032 | 0 | } |
1033 | 0 | break; |
1034 | | |
1035 | 0 | case MetaActionType::BMPEXSCALE: |
1036 | 0 | { |
1037 | 0 | MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction); |
1038 | 0 | tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetPoint(), pAct->GetSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1039 | 0 | tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); |
1040 | 0 | Bitmap aBmp( pAct->GetBitmap() ); |
1041 | |
|
1042 | 0 | aBmp.Rotate( nAngle10, COL_TRANSPARENT ); |
1043 | |
|
1044 | 0 | aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmp ) ); |
1045 | 0 | } |
1046 | 0 | break; |
1047 | | |
1048 | 0 | case MetaActionType::BMPEXSCALEPART: |
1049 | 0 | { |
1050 | 0 | MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction); |
1051 | 0 | tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1052 | 0 | tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); |
1053 | 0 | Bitmap aBmp( pAct->GetBitmap() ); |
1054 | |
|
1055 | 0 | aBmp.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) ); |
1056 | 0 | aBmp.Rotate( nAngle10, COL_TRANSPARENT ); |
1057 | |
|
1058 | 0 | aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmp ) ); |
1059 | 0 | } |
1060 | 0 | break; |
1061 | | |
1062 | 0 | case MetaActionType::GRADIENT: |
1063 | 0 | { |
1064 | 0 | MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction); |
1065 | |
|
1066 | 0 | ImplAddGradientEx( aMtf, *aMapVDev, |
1067 | 0 | tools::PolyPolygon(ImplGetRotatedPolygon( tools::Polygon(pAct->GetRect()), aRotAnchor, aRotOffset, fSin, fCos )), |
1068 | 0 | pAct->GetGradient() ); |
1069 | 0 | } |
1070 | 0 | break; |
1071 | | |
1072 | 0 | case MetaActionType::GRADIENTEX: |
1073 | 0 | { |
1074 | 0 | MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction); |
1075 | 0 | aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), |
1076 | 0 | pAct->GetGradient() ) ); |
1077 | 0 | } |
1078 | 0 | break; |
1079 | | |
1080 | | // Handle gradientex comment block correctly |
1081 | 0 | case MetaActionType::COMMENT: |
1082 | 0 | { |
1083 | 0 | MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction); |
1084 | 0 | if( pCommentAct->GetComment() == "XGRAD_SEQ_BEGIN" ) |
1085 | 0 | { |
1086 | 0 | int nBeginComments( 1 ); |
1087 | 0 | pAction = NextAction(); |
1088 | | |
1089 | | // skip everything, except gradientex action |
1090 | 0 | while( pAction ) |
1091 | 0 | { |
1092 | 0 | const MetaActionType nType = pAction->GetType(); |
1093 | |
|
1094 | 0 | if( MetaActionType::GRADIENTEX == nType ) |
1095 | 0 | { |
1096 | | // Add rotated gradientex |
1097 | 0 | MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction); |
1098 | 0 | ImplAddGradientEx( aMtf, *aMapVDev, |
1099 | 0 | ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), |
1100 | 0 | pAct->GetGradient() ); |
1101 | 0 | } |
1102 | 0 | else if( MetaActionType::COMMENT == nType) |
1103 | 0 | { |
1104 | 0 | MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pAction); |
1105 | 0 | if( pAct->GetComment() == "XGRAD_SEQ_END" ) |
1106 | 0 | { |
1107 | | // handle nested blocks |
1108 | 0 | --nBeginComments; |
1109 | | |
1110 | | // gradientex comment block: end reached, done. |
1111 | 0 | if( !nBeginComments ) |
1112 | 0 | break; |
1113 | 0 | } |
1114 | 0 | else if( pAct->GetComment() == "XGRAD_SEQ_BEGIN" ) |
1115 | 0 | { |
1116 | | // handle nested blocks |
1117 | 0 | ++nBeginComments; |
1118 | 0 | } |
1119 | |
|
1120 | 0 | } |
1121 | | |
1122 | 0 | pAction =NextAction(); |
1123 | 0 | } |
1124 | 0 | } |
1125 | 0 | else |
1126 | 0 | { |
1127 | 0 | bool bPathStroke = (pCommentAct->GetComment() == "XPATHSTROKE_SEQ_BEGIN"); |
1128 | 0 | if ( bPathStroke || pCommentAct->GetComment() == "XPATHFILL_SEQ_BEGIN" ) |
1129 | 0 | { |
1130 | 0 | if ( pCommentAct->GetDataSize() ) |
1131 | 0 | { |
1132 | 0 | SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pCommentAct->GetData()), pCommentAct->GetDataSize(), StreamMode::READ ); |
1133 | 0 | SvMemoryStream aDest; |
1134 | 0 | if ( bPathStroke ) |
1135 | 0 | { |
1136 | 0 | SvtGraphicStroke aStroke; |
1137 | 0 | ReadSvtGraphicStroke( aMemStm, aStroke ); |
1138 | 0 | tools::Polygon aPath; |
1139 | 0 | aStroke.getPath( aPath ); |
1140 | 0 | aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) ); |
1141 | 0 | WriteSvtGraphicStroke( aDest, aStroke ); |
1142 | 0 | aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN"_ostr, 0, |
1143 | 0 | static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) ); |
1144 | 0 | } |
1145 | 0 | else |
1146 | 0 | { |
1147 | 0 | SvtGraphicFill aFill; |
1148 | 0 | ReadSvtGraphicFill( aMemStm, aFill ); |
1149 | 0 | tools::PolyPolygon aPath; |
1150 | 0 | aFill.getPath( aPath ); |
1151 | 0 | aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) ); |
1152 | 0 | WriteSvtGraphicFill( aDest, aFill ); |
1153 | 0 | aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN"_ostr, 0, |
1154 | 0 | static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) ); |
1155 | 0 | } |
1156 | 0 | } |
1157 | 0 | } |
1158 | 0 | else if ( pCommentAct->GetComment() == "XPATHSTROKE_SEQ_END" |
1159 | 0 | || pCommentAct->GetComment() == "XPATHFILL_SEQ_END" ) |
1160 | 0 | { |
1161 | 0 | pAction->Execute( aMapVDev.get() ); |
1162 | 0 | aMtf.AddAction( pAction ); |
1163 | 0 | } |
1164 | 0 | } |
1165 | 0 | } |
1166 | 0 | break; |
1167 | | |
1168 | 0 | case MetaActionType::HATCH: |
1169 | 0 | { |
1170 | 0 | MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction); |
1171 | 0 | Hatch aHatch( pAct->GetHatch() ); |
1172 | |
|
1173 | 0 | aHatch.SetAngle( aHatch.GetAngle() + nAngle10 ); |
1174 | 0 | aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), |
1175 | 0 | aHatch ) ); |
1176 | 0 | } |
1177 | 0 | break; |
1178 | | |
1179 | 0 | case MetaActionType::Transparent: |
1180 | 0 | { |
1181 | 0 | MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction); |
1182 | 0 | aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), |
1183 | 0 | pAct->GetTransparence() ) ); |
1184 | 0 | } |
1185 | 0 | break; |
1186 | | |
1187 | 0 | case MetaActionType::FLOATTRANSPARENT: |
1188 | 0 | { |
1189 | 0 | MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction); |
1190 | 0 | GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() ); |
1191 | 0 | tools::Polygon aMtfPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetPoint(), pAct->GetSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1192 | 0 | tools::Rectangle aMtfRect( aMtfPoly.GetBoundRect() ); |
1193 | |
|
1194 | 0 | aTransMtf.Rotate( nAngle10 ); |
1195 | 0 | aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(), |
1196 | 0 | pAct->GetGradient() ) ); |
1197 | 0 | } |
1198 | 0 | break; |
1199 | | |
1200 | 0 | case MetaActionType::EPS: |
1201 | 0 | { |
1202 | 0 | MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction); |
1203 | 0 | GDIMetaFile aEPSMtf( pAct->GetSubstitute() ); |
1204 | 0 | tools::Polygon aEPSPoly( ImplGetRotatedPolygon( tools::Polygon(tools::Rectangle( pAct->GetPoint(), pAct->GetSize() )), aRotAnchor, aRotOffset, fSin, fCos ) ); |
1205 | 0 | tools::Rectangle aEPSRect( aEPSPoly.GetBoundRect() ); |
1206 | |
|
1207 | 0 | aEPSMtf.Rotate( nAngle10 ); |
1208 | 0 | aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(), |
1209 | 0 | pAct->GetLink(), aEPSMtf ) ); |
1210 | 0 | } |
1211 | 0 | break; |
1212 | | |
1213 | 0 | case MetaActionType::CLIPREGION: |
1214 | 0 | { |
1215 | 0 | MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction); |
1216 | |
|
1217 | 0 | if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygonOrB2DPolyPolygon() ) |
1218 | 0 | aMtf.AddAction( new MetaClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), true ) ); |
1219 | 0 | else |
1220 | 0 | { |
1221 | 0 | aMtf.AddAction( pAction ); |
1222 | 0 | } |
1223 | 0 | } |
1224 | 0 | break; |
1225 | | |
1226 | 0 | case MetaActionType::ISECTRECTCLIPREGION: |
1227 | 0 | { |
1228 | 0 | MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction); |
1229 | 0 | aMtf.AddAction( new MetaISectRegionClipRegionAction(vcl::Region( |
1230 | 0 | ImplGetRotatedPolygon( tools::Polygon(pAct->GetRect()), aRotAnchor, |
1231 | 0 | aRotOffset, fSin, fCos )) ) ); |
1232 | 0 | } |
1233 | 0 | break; |
1234 | | |
1235 | 0 | case MetaActionType::ISECTREGIONCLIPREGION: |
1236 | 0 | { |
1237 | 0 | MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction); |
1238 | 0 | const vcl::Region& rRegion = pAct->GetRegion(); |
1239 | |
|
1240 | 0 | if( rRegion.HasPolyPolygonOrB2DPolyPolygon() ) |
1241 | 0 | aMtf.AddAction( new MetaISectRegionClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) ); |
1242 | 0 | else |
1243 | 0 | { |
1244 | 0 | aMtf.AddAction( pAction ); |
1245 | 0 | } |
1246 | 0 | } |
1247 | 0 | break; |
1248 | | |
1249 | 0 | case MetaActionType::REFPOINT: |
1250 | 0 | { |
1251 | 0 | MetaRefPointAction* pAct = static_cast<MetaRefPointAction*>(pAction); |
1252 | 0 | aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) ); |
1253 | 0 | } |
1254 | 0 | break; |
1255 | | |
1256 | 0 | case MetaActionType::FONT: |
1257 | 0 | { |
1258 | 0 | MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction); |
1259 | 0 | vcl::Font aFont( pAct->GetFont() ); |
1260 | |
|
1261 | 0 | aFont.SetOrientation( aFont.GetOrientation() + nAngle10 ); |
1262 | 0 | aMtf.AddAction( new MetaFontAction( std::move(aFont) ) ); |
1263 | 0 | } |
1264 | 0 | break; |
1265 | | |
1266 | 0 | case MetaActionType::BMP: |
1267 | 0 | case MetaActionType::BMPEX: |
1268 | 0 | case MetaActionType::MASK: |
1269 | 0 | case MetaActionType::MASKSCALE: |
1270 | 0 | case MetaActionType::MASKSCALEPART: |
1271 | 0 | case MetaActionType::WALLPAPER: |
1272 | 0 | case MetaActionType::TEXTRECT: |
1273 | 0 | case MetaActionType::MOVECLIPREGION: |
1274 | 0 | { |
1275 | 0 | OSL_FAIL( "GDIMetaFile::Rotate(): unsupported action" ); |
1276 | 0 | } |
1277 | 0 | break; |
1278 | | |
1279 | 0 | default: |
1280 | 0 | { |
1281 | 0 | pAction->Execute( aMapVDev.get() ); |
1282 | 0 | aMtf.AddAction( pAction ); |
1283 | | |
1284 | | // update rotation point and offset, if necessary |
1285 | 0 | if( ( MetaActionType::MAPMODE == nActionType ) || |
1286 | 0 | ( MetaActionType::PUSH == nActionType ) || |
1287 | 0 | ( MetaActionType::POP == nActionType ) ) |
1288 | 0 | { |
1289 | 0 | aRotAnchor = OutputDevice::LogicToLogic( aOrigin, m_aPrefMapMode, aMapVDev->GetMapMode() ); |
1290 | 0 | aRotOffset = OutputDevice::LogicToLogic( aOffset, m_aPrefMapMode, aMapVDev->GetMapMode() ); |
1291 | 0 | } |
1292 | 0 | } |
1293 | 0 | break; |
1294 | 0 | } |
1295 | 0 | } |
1296 | | |
1297 | 0 | aMtf.m_aPrefMapMode = m_aPrefMapMode; |
1298 | 0 | aMtf.m_aPrefSize = aNewBound.GetSize(); |
1299 | |
|
1300 | 0 | *this = aMtf; |
1301 | |
|
1302 | 0 | } |
1303 | | |
1304 | | static void ImplActionBounds( tools::Rectangle& o_rOutBounds, |
1305 | | const tools::Rectangle& i_rInBounds, |
1306 | | const std::vector<tools::Rectangle>& i_rClipStack ) |
1307 | 0 | { |
1308 | 0 | tools::Rectangle aBounds( i_rInBounds ); |
1309 | 0 | if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() ) |
1310 | 0 | aBounds.Intersection( i_rClipStack.back() ); |
1311 | 0 | if( aBounds.IsEmpty() ) |
1312 | 0 | return; |
1313 | | |
1314 | 0 | if( ! o_rOutBounds.IsEmpty() ) |
1315 | 0 | o_rOutBounds.Union( aBounds ); |
1316 | 0 | else |
1317 | 0 | o_rOutBounds = aBounds; |
1318 | 0 | } |
1319 | | |
1320 | | tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference ) const |
1321 | 0 | { |
1322 | 0 | ScopedVclPtrInstance< VirtualDevice > aMapVDev( i_rReference, DeviceFormat::WITH_ALPHA ); |
1323 | |
|
1324 | 0 | aMapVDev->EnableOutput( false ); |
1325 | 0 | aMapVDev->SetMapMode( GetPrefMapMode() ); |
1326 | |
|
1327 | 0 | std::vector<tools::Rectangle> aClipStack( 1, tools::Rectangle() ); |
1328 | 0 | std::vector<vcl::PushFlags> aPushFlagStack; |
1329 | |
|
1330 | 0 | tools::Rectangle aBound; |
1331 | 0 | const sal_uLong nCount(GetActionSize()); |
1332 | |
|
1333 | 0 | for(sal_uLong a(0); a < nCount; a++) |
1334 | 0 | { |
1335 | 0 | MetaAction* pAction = GetAction(a); |
1336 | 0 | const MetaActionType nActionType = pAction->GetType(); |
1337 | |
|
1338 | 0 | switch( nActionType ) |
1339 | 0 | { |
1340 | 0 | case MetaActionType::PIXEL: |
1341 | 0 | { |
1342 | 0 | MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction); |
1343 | 0 | ImplActionBounds( aBound, |
1344 | 0 | tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ), |
1345 | 0 | aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ), |
1346 | 0 | aClipStack ); |
1347 | 0 | } |
1348 | 0 | break; |
1349 | | |
1350 | 0 | case MetaActionType::POINT: |
1351 | 0 | { |
1352 | 0 | MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction); |
1353 | 0 | ImplActionBounds( aBound, |
1354 | 0 | tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ), |
1355 | 0 | aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ), |
1356 | 0 | aClipStack ); |
1357 | 0 | } |
1358 | 0 | break; |
1359 | | |
1360 | 0 | case MetaActionType::LINE: |
1361 | 0 | { |
1362 | 0 | MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction); |
1363 | 0 | Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() ); |
1364 | 0 | tools::Rectangle aRect( aP1, aP2 ); |
1365 | 0 | aRect.Normalize(); |
1366 | |
|
1367 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1368 | 0 | } |
1369 | 0 | break; |
1370 | | |
1371 | 0 | case MetaActionType::RECT: |
1372 | 0 | { |
1373 | 0 | MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction); |
1374 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1375 | 0 | } |
1376 | 0 | break; |
1377 | | |
1378 | 0 | case MetaActionType::ROUNDRECT: |
1379 | 0 | { |
1380 | 0 | MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction); |
1381 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1382 | 0 | } |
1383 | 0 | break; |
1384 | | |
1385 | 0 | case MetaActionType::ELLIPSE: |
1386 | 0 | { |
1387 | 0 | MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction); |
1388 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1389 | 0 | } |
1390 | 0 | break; |
1391 | | |
1392 | 0 | case MetaActionType::ARC: |
1393 | 0 | { |
1394 | 0 | MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction); |
1395 | | // FIXME: this is imprecise |
1396 | | // e.g. for small arcs the whole rectangle is WAY too large |
1397 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1398 | 0 | } |
1399 | 0 | break; |
1400 | | |
1401 | 0 | case MetaActionType::PIE: |
1402 | 0 | { |
1403 | 0 | MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction); |
1404 | | // FIXME: this is imprecise |
1405 | | // e.g. for small arcs the whole rectangle is WAY too large |
1406 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1407 | 0 | } |
1408 | 0 | break; |
1409 | | |
1410 | 0 | case MetaActionType::CHORD: |
1411 | 0 | { |
1412 | 0 | MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction); |
1413 | | // FIXME: this is imprecise |
1414 | | // e.g. for small arcs the whole rectangle is WAY too large |
1415 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1416 | 0 | } |
1417 | 0 | break; |
1418 | | |
1419 | 0 | case MetaActionType::POLYLINE: |
1420 | 0 | { |
1421 | 0 | MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction); |
1422 | 0 | tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() ); |
1423 | |
|
1424 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1425 | 0 | } |
1426 | 0 | break; |
1427 | | |
1428 | 0 | case MetaActionType::POLYGON: |
1429 | 0 | { |
1430 | 0 | MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction); |
1431 | 0 | tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() ); |
1432 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1433 | 0 | } |
1434 | 0 | break; |
1435 | | |
1436 | 0 | case MetaActionType::POLYPOLYGON: |
1437 | 0 | { |
1438 | 0 | MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction); |
1439 | 0 | tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); |
1440 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1441 | 0 | } |
1442 | 0 | break; |
1443 | | |
1444 | 0 | case MetaActionType::TEXT: |
1445 | 0 | { |
1446 | 0 | MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction); |
1447 | 0 | tools::Rectangle aRect; |
1448 | | // hdu said base = index |
1449 | 0 | aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() ); |
1450 | 0 | Point aPt( pAct->GetPoint() ); |
1451 | 0 | aRect.Move( aPt.X(), aPt.Y() ); |
1452 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1453 | 0 | } |
1454 | 0 | break; |
1455 | | |
1456 | 0 | case MetaActionType::TEXTARRAY: |
1457 | 0 | { |
1458 | 0 | MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction); |
1459 | 0 | tools::Rectangle aRect; |
1460 | | // hdu said base = index |
1461 | 0 | aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(), |
1462 | 0 | 0, pAct->GetDXArray(), pAct->GetKashidaArray() ); |
1463 | 0 | Point aPt( pAct->GetPoint() ); |
1464 | 0 | aRect.Move( aPt.X(), aPt.Y() ); |
1465 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1466 | 0 | } |
1467 | 0 | break; |
1468 | | |
1469 | 0 | case MetaActionType::STRETCHTEXT: |
1470 | 0 | { |
1471 | 0 | MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction); |
1472 | 0 | tools::Rectangle aRect; |
1473 | | // hdu said base = index |
1474 | 0 | aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(), |
1475 | 0 | pAct->GetWidth() ); |
1476 | 0 | Point aPt( pAct->GetPoint() ); |
1477 | 0 | aRect.Move( aPt.X(), aPt.Y() ); |
1478 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1479 | 0 | } |
1480 | 0 | break; |
1481 | | |
1482 | 0 | case MetaActionType::TEXTLINE: |
1483 | 0 | { |
1484 | 0 | MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction); |
1485 | | // measure a test string to get ascend and descent right |
1486 | 0 | static constexpr OUStringLiteral pStr = u"\u00c4g"; |
1487 | 0 | OUString aStr( pStr ); |
1488 | |
|
1489 | 0 | tools::Rectangle aRect; |
1490 | 0 | aMapVDev->GetTextBoundRect( aRect, aStr, 0, 0, aStr.getLength() ); |
1491 | 0 | Point aPt( pAct->GetStartPoint() ); |
1492 | 0 | aRect.Move( aPt.X(), aPt.Y() ); |
1493 | 0 | aRect.SetRight( aRect.Left() + pAct->GetWidth() ); |
1494 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1495 | 0 | } |
1496 | 0 | break; |
1497 | | |
1498 | 0 | case MetaActionType::BMPSCALE: |
1499 | 0 | { |
1500 | 0 | MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction); |
1501 | 0 | tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); |
1502 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1503 | 0 | } |
1504 | 0 | break; |
1505 | | |
1506 | 0 | case MetaActionType::BMPSCALEPART: |
1507 | 0 | { |
1508 | 0 | MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction); |
1509 | 0 | tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); |
1510 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1511 | 0 | } |
1512 | 0 | break; |
1513 | | |
1514 | 0 | case MetaActionType::BMPEXSCALE: |
1515 | 0 | { |
1516 | 0 | MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction); |
1517 | 0 | tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); |
1518 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1519 | 0 | } |
1520 | 0 | break; |
1521 | | |
1522 | 0 | case MetaActionType::BMPEXSCALEPART: |
1523 | 0 | { |
1524 | 0 | MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction); |
1525 | 0 | tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); |
1526 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1527 | 0 | } |
1528 | 0 | break; |
1529 | | |
1530 | 0 | case MetaActionType::GRADIENT: |
1531 | 0 | { |
1532 | 0 | MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction); |
1533 | 0 | tools::Rectangle aRect( pAct->GetRect() ); |
1534 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1535 | 0 | } |
1536 | 0 | break; |
1537 | | |
1538 | 0 | case MetaActionType::GRADIENTEX: |
1539 | 0 | { |
1540 | 0 | MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction); |
1541 | 0 | tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); |
1542 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1543 | 0 | } |
1544 | 0 | break; |
1545 | | |
1546 | 0 | case MetaActionType::COMMENT: |
1547 | 0 | { |
1548 | | // nothing to do |
1549 | 0 | }; |
1550 | 0 | break; |
1551 | | |
1552 | 0 | case MetaActionType::HATCH: |
1553 | 0 | { |
1554 | 0 | MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction); |
1555 | 0 | tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); |
1556 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1557 | 0 | } |
1558 | 0 | break; |
1559 | | |
1560 | 0 | case MetaActionType::Transparent: |
1561 | 0 | { |
1562 | 0 | MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction); |
1563 | 0 | tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); |
1564 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1565 | 0 | } |
1566 | 0 | break; |
1567 | | |
1568 | 0 | case MetaActionType::FLOATTRANSPARENT: |
1569 | 0 | { |
1570 | 0 | MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction); |
1571 | | // MetaFloatTransparentAction is defined limiting its content Metafile |
1572 | | // to its geometry definition(Point, Size), so use these directly |
1573 | 0 | const tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); |
1574 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1575 | 0 | } |
1576 | 0 | break; |
1577 | | |
1578 | 0 | case MetaActionType::EPS: |
1579 | 0 | { |
1580 | 0 | MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction); |
1581 | 0 | tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); |
1582 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1583 | 0 | } |
1584 | 0 | break; |
1585 | | |
1586 | 0 | case MetaActionType::CLIPREGION: |
1587 | 0 | { |
1588 | 0 | MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction); |
1589 | 0 | if( pAct->IsClipping() ) |
1590 | 0 | aClipStack.back() = OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ); |
1591 | 0 | else |
1592 | 0 | aClipStack.back() = tools::Rectangle(); |
1593 | 0 | } |
1594 | 0 | break; |
1595 | | |
1596 | 0 | case MetaActionType::ISECTRECTCLIPREGION: |
1597 | 0 | { |
1598 | 0 | MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction); |
1599 | 0 | tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) ); |
1600 | 0 | if( aClipStack.back().IsEmpty() ) |
1601 | 0 | aClipStack.back() = aRect; |
1602 | 0 | else |
1603 | 0 | aClipStack.back().Intersection( aRect ); |
1604 | 0 | } |
1605 | 0 | break; |
1606 | | |
1607 | 0 | case MetaActionType::ISECTREGIONCLIPREGION: |
1608 | 0 | { |
1609 | 0 | MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction); |
1610 | 0 | tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) ); |
1611 | 0 | if( aClipStack.back().IsEmpty() ) |
1612 | 0 | aClipStack.back() = aRect; |
1613 | 0 | else |
1614 | 0 | aClipStack.back().Intersection( aRect ); |
1615 | 0 | } |
1616 | 0 | break; |
1617 | | |
1618 | 0 | case MetaActionType::BMP: |
1619 | 0 | { |
1620 | 0 | MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction); |
1621 | 0 | tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) ); |
1622 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1623 | 0 | } |
1624 | 0 | break; |
1625 | | |
1626 | 0 | case MetaActionType::BMPEX: |
1627 | 0 | { |
1628 | 0 | MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction); |
1629 | 0 | tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) ); |
1630 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1631 | 0 | } |
1632 | 0 | break; |
1633 | | |
1634 | 0 | case MetaActionType::MASK: |
1635 | 0 | { |
1636 | 0 | MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction); |
1637 | 0 | tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) ); |
1638 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1639 | 0 | } |
1640 | 0 | break; |
1641 | | |
1642 | 0 | case MetaActionType::MASKSCALE: |
1643 | 0 | { |
1644 | 0 | MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction); |
1645 | 0 | tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); |
1646 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1647 | 0 | } |
1648 | 0 | break; |
1649 | | |
1650 | 0 | case MetaActionType::MASKSCALEPART: |
1651 | 0 | { |
1652 | 0 | MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction); |
1653 | 0 | tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); |
1654 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1655 | 0 | } |
1656 | 0 | break; |
1657 | | |
1658 | 0 | case MetaActionType::WALLPAPER: |
1659 | 0 | { |
1660 | 0 | MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction); |
1661 | 0 | tools::Rectangle aRect( pAct->GetRect() ); |
1662 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1663 | 0 | } |
1664 | 0 | break; |
1665 | | |
1666 | 0 | case MetaActionType::TEXTRECT: |
1667 | 0 | { |
1668 | 0 | MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pAction); |
1669 | 0 | tools::Rectangle aRect( pAct->GetRect() ); |
1670 | 0 | ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); |
1671 | 0 | } |
1672 | 0 | break; |
1673 | | |
1674 | 0 | case MetaActionType::MOVECLIPREGION: |
1675 | 0 | { |
1676 | 0 | MetaMoveClipRegionAction* pAct = static_cast<MetaMoveClipRegionAction*>(pAction); |
1677 | 0 | if( ! aClipStack.back().IsEmpty() ) |
1678 | 0 | { |
1679 | 0 | Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() ); |
1680 | 0 | aDelta = OutputDevice::LogicToLogic( aDelta, aMapVDev->GetMapMode(), GetPrefMapMode() ); |
1681 | 0 | aClipStack.back().Move( aDelta.Width(), aDelta.Width() ); |
1682 | 0 | } |
1683 | 0 | } |
1684 | 0 | break; |
1685 | | |
1686 | 0 | default: |
1687 | 0 | { |
1688 | 0 | pAction->Execute( aMapVDev.get() ); |
1689 | |
|
1690 | 0 | if( nActionType == MetaActionType::PUSH ) |
1691 | 0 | { |
1692 | 0 | MetaPushAction* pAct = static_cast<MetaPushAction*>(pAction); |
1693 | 0 | aPushFlagStack.push_back( pAct->GetFlags() ); |
1694 | 0 | if( aPushFlagStack.back() & vcl::PushFlags::CLIPREGION ) |
1695 | 0 | { |
1696 | 0 | tools::Rectangle aRect( aClipStack.back() ); |
1697 | 0 | aClipStack.push_back( aRect ); |
1698 | 0 | } |
1699 | 0 | } |
1700 | 0 | else if( nActionType == MetaActionType::POP ) |
1701 | 0 | { |
1702 | | // sanity check |
1703 | 0 | if( ! aPushFlagStack.empty() ) |
1704 | 0 | { |
1705 | 0 | if( aPushFlagStack.back() & vcl::PushFlags::CLIPREGION ) |
1706 | 0 | { |
1707 | 0 | if( aClipStack.size() > 1 ) |
1708 | 0 | aClipStack.pop_back(); |
1709 | 0 | } |
1710 | 0 | aPushFlagStack.pop_back(); |
1711 | 0 | } |
1712 | 0 | } |
1713 | 0 | } |
1714 | 0 | break; |
1715 | 0 | } |
1716 | 0 | } |
1717 | 0 | return aBound; |
1718 | 0 | } |
1719 | | |
1720 | | Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam ) |
1721 | 0 | { |
1722 | 0 | return Color( ColorAlpha, rColor.GetAlpha(), |
1723 | 0 | static_cast<const ImplColAdjustParam*>(pColParam)->pMapR[ rColor.GetRed() ], |
1724 | 0 | static_cast<const ImplColAdjustParam*>(pColParam)->pMapG[ rColor.GetGreen() ], |
1725 | 0 | static_cast<const ImplColAdjustParam*>(pColParam)->pMapB[ rColor.GetBlue() ] ); |
1726 | |
|
1727 | 0 | } |
1728 | | |
1729 | | Bitmap GDIMetaFile::ImplBmpAdjustFnc( const Bitmap& rBmp, const void* pBmpParam ) |
1730 | 0 | { |
1731 | 0 | const ImplBmpAdjustParam* p = static_cast<const ImplBmpAdjustParam*>(pBmpParam); |
1732 | 0 | Bitmap aRet( rBmp ); |
1733 | |
|
1734 | 0 | aRet.Adjust( p->nLuminancePercent, p->nContrastPercent, |
1735 | 0 | p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent, |
1736 | 0 | p->fGamma, p->bInvert ); |
1737 | |
|
1738 | 0 | return aRet; |
1739 | 0 | } |
1740 | | |
1741 | | Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam ) |
1742 | 0 | { |
1743 | 0 | sal_uInt8 cLum = rColor.GetLuminance(); |
1744 | |
|
1745 | 0 | if( MtfConversion::N1BitThreshold == static_cast<const ImplColConvertParam*>(pColParam)->eConversion ) |
1746 | 0 | cLum = ( cLum < 128 ) ? 0 : 255; |
1747 | |
|
1748 | 0 | return Color( ColorAlpha, rColor.GetAlpha(), cLum, cLum, cLum ); |
1749 | 0 | } |
1750 | | |
1751 | | Bitmap GDIMetaFile::ImplBmpConvertFnc( const Bitmap& rBmp, const void* pBmpParam ) |
1752 | 0 | { |
1753 | 0 | Bitmap aRet( rBmp ); |
1754 | |
|
1755 | 0 | aRet.Convert( static_cast<const ImplBmpConvertParam*>(pBmpParam)->eConversion ); |
1756 | |
|
1757 | 0 | return aRet; |
1758 | 0 | } |
1759 | | |
1760 | | Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam ) |
1761 | 0 | { |
1762 | 0 | return static_cast<const ImplColMonoParam*>(pColParam)->aColor; |
1763 | 0 | } |
1764 | | |
1765 | | Bitmap GDIMetaFile::ImplBmpMonoFnc( const Bitmap& rBmp, const void* pBmpParam ) |
1766 | 0 | { |
1767 | 0 | BitmapPalette aPal( 3 ); |
1768 | 0 | aPal[ 0 ] = COL_BLACK; |
1769 | 0 | aPal[ 1 ] = COL_WHITE; |
1770 | 0 | aPal[ 2 ] = static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor; |
1771 | |
|
1772 | 0 | Bitmap aBmp(rBmp.GetSizePixel(), vcl::PixelFormat::N8_BPP, &aPal); |
1773 | 0 | aBmp.Erase( static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor ); |
1774 | |
|
1775 | 0 | if( rBmp.HasAlpha() ) |
1776 | 0 | return Bitmap( aBmp, rBmp.CreateAlphaMask() ); |
1777 | 0 | else |
1778 | 0 | return aBmp; |
1779 | 0 | } |
1780 | | |
1781 | | Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam ) |
1782 | 0 | { |
1783 | 0 | const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue(); |
1784 | |
|
1785 | 0 | for( sal_uLong i = 0; i < static_cast<const ImplColReplaceParam*>(pColParam)->nCount; i++ ) |
1786 | 0 | { |
1787 | 0 | if( ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinR[ i ] <= nR ) && |
1788 | 0 | ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxR[ i ] >= nR ) && |
1789 | 0 | ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinG[ i ] <= nG ) && |
1790 | 0 | ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxG[ i ] >= nG ) && |
1791 | 0 | ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinB[ i ] <= nB ) && |
1792 | 0 | ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxB[ i ] >= nB ) ) |
1793 | 0 | { |
1794 | 0 | return static_cast<const ImplColReplaceParam*>(pColParam)->pDstCols[ i ]; |
1795 | 0 | } |
1796 | 0 | } |
1797 | | |
1798 | 0 | return rColor; |
1799 | 0 | } |
1800 | | |
1801 | | Bitmap GDIMetaFile::ImplBmpReplaceFnc( const Bitmap& rBmp, const void* pBmpParam ) |
1802 | 0 | { |
1803 | 0 | const ImplBmpReplaceParam* p = static_cast<const ImplBmpReplaceParam*>(pBmpParam); |
1804 | 0 | Bitmap aRet( rBmp ); |
1805 | |
|
1806 | 0 | aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, nullptr ); |
1807 | |
|
1808 | 0 | return aRet; |
1809 | 0 | } |
1810 | | |
1811 | | void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam, |
1812 | | BmpExchangeFnc pFncBmp, const void* pBmpParam ) |
1813 | 0 | { |
1814 | 0 | GDIMetaFile aMtf; |
1815 | |
|
1816 | 0 | aMtf.m_aPrefSize = m_aPrefSize; |
1817 | 0 | aMtf.m_aPrefMapMode = m_aPrefMapMode; |
1818 | 0 | aMtf.m_bUseCanvas = m_bUseCanvas; |
1819 | 0 | aMtf.m_bSVG = m_bSVG; |
1820 | |
|
1821 | 0 | for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() ) |
1822 | 0 | { |
1823 | 0 | const MetaActionType nType = pAction->GetType(); |
1824 | |
|
1825 | 0 | switch( nType ) |
1826 | 0 | { |
1827 | 0 | case MetaActionType::PIXEL: |
1828 | 0 | { |
1829 | 0 | MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction); |
1830 | 0 | aMtf.push_back( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ) ); |
1831 | 0 | } |
1832 | 0 | break; |
1833 | | |
1834 | 0 | case MetaActionType::LINECOLOR: |
1835 | 0 | { |
1836 | 0 | MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction); |
1837 | |
|
1838 | 0 | if( pAct->IsSetting() ) |
1839 | 0 | pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true ); |
1840 | |
|
1841 | 0 | aMtf.push_back( pAct ); |
1842 | 0 | } |
1843 | 0 | break; |
1844 | | |
1845 | 0 | case MetaActionType::FILLCOLOR: |
1846 | 0 | { |
1847 | 0 | MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction); |
1848 | |
|
1849 | 0 | if( pAct->IsSetting() ) |
1850 | 0 | pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true ); |
1851 | |
|
1852 | 0 | aMtf.push_back( pAct ); |
1853 | 0 | } |
1854 | 0 | break; |
1855 | | |
1856 | 0 | case MetaActionType::TEXTCOLOR: |
1857 | 0 | { |
1858 | 0 | MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction); |
1859 | 0 | aMtf.push_back( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ) ); |
1860 | 0 | } |
1861 | 0 | break; |
1862 | | |
1863 | 0 | case MetaActionType::TEXTFILLCOLOR: |
1864 | 0 | { |
1865 | 0 | MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction); |
1866 | |
|
1867 | 0 | if( pAct->IsSetting() ) |
1868 | 0 | pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true ); |
1869 | |
|
1870 | 0 | aMtf.push_back( pAct ); |
1871 | 0 | } |
1872 | 0 | break; |
1873 | | |
1874 | 0 | case MetaActionType::TEXTLINECOLOR: |
1875 | 0 | { |
1876 | 0 | MetaTextLineColorAction* pAct = static_cast<MetaTextLineColorAction*>(pAction); |
1877 | |
|
1878 | 0 | if( pAct->IsSetting() ) |
1879 | 0 | pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true ); |
1880 | |
|
1881 | 0 | aMtf.push_back( pAct ); |
1882 | 0 | } |
1883 | 0 | break; |
1884 | | |
1885 | 0 | case MetaActionType::OVERLINECOLOR: |
1886 | 0 | { |
1887 | 0 | MetaOverlineColorAction* pAct = static_cast<MetaOverlineColorAction*>(pAction); |
1888 | |
|
1889 | 0 | if( pAct->IsSetting() ) |
1890 | 0 | pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), true ); |
1891 | |
|
1892 | 0 | aMtf.push_back( pAct ); |
1893 | 0 | } |
1894 | 0 | break; |
1895 | | |
1896 | 0 | case MetaActionType::FONT: |
1897 | 0 | { |
1898 | 0 | MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction); |
1899 | 0 | vcl::Font aFont( pAct->GetFont() ); |
1900 | |
|
1901 | 0 | aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) ); |
1902 | 0 | aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) ); |
1903 | 0 | aMtf.push_back( new MetaFontAction( std::move(aFont) ) ); |
1904 | 0 | } |
1905 | 0 | break; |
1906 | | |
1907 | 0 | case MetaActionType::WALLPAPER: |
1908 | 0 | { |
1909 | 0 | MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction); |
1910 | 0 | Wallpaper aWall( pAct->GetWallpaper() ); |
1911 | 0 | const tools::Rectangle& rRect = pAct->GetRect(); |
1912 | |
|
1913 | 0 | aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) ); |
1914 | |
|
1915 | 0 | if( aWall.IsBitmap() ) |
1916 | 0 | aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) ); |
1917 | |
|
1918 | 0 | if( aWall.IsGradient() ) |
1919 | 0 | { |
1920 | 0 | Gradient aGradient( aWall.GetGradient() ); |
1921 | |
|
1922 | 0 | aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); |
1923 | 0 | aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); |
1924 | 0 | aWall.SetGradient( aGradient ); |
1925 | 0 | } |
1926 | |
|
1927 | 0 | aMtf.push_back( new MetaWallpaperAction( rRect, std::move(aWall) ) ); |
1928 | 0 | } |
1929 | 0 | break; |
1930 | | |
1931 | 0 | case MetaActionType::BMP: |
1932 | 0 | case MetaActionType::BMPEX: |
1933 | 0 | case MetaActionType::MASK: |
1934 | 0 | { |
1935 | 0 | OSL_FAIL( "Don't use bitmap actions of this type in metafiles!" ); |
1936 | 0 | } |
1937 | 0 | break; |
1938 | | |
1939 | 0 | case MetaActionType::BMPSCALE: |
1940 | 0 | { |
1941 | 0 | MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction); |
1942 | 0 | aMtf.push_back( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), |
1943 | 0 | pFncBmp( pAct->GetBitmap(), pBmpParam ).CreateColorBitmap() ) ); |
1944 | 0 | } |
1945 | 0 | break; |
1946 | | |
1947 | 0 | case MetaActionType::BMPSCALEPART: |
1948 | 0 | { |
1949 | 0 | MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction); |
1950 | 0 | aMtf.push_back( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), |
1951 | 0 | pAct->GetSrcPoint(), pAct->GetSrcSize(), |
1952 | 0 | pFncBmp( pAct->GetBitmap(), pBmpParam ).CreateColorBitmap() ) |
1953 | 0 | ); |
1954 | 0 | } |
1955 | 0 | break; |
1956 | | |
1957 | 0 | case MetaActionType::BMPEXSCALE: |
1958 | 0 | { |
1959 | 0 | MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction); |
1960 | 0 | aMtf.push_back( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), |
1961 | 0 | pFncBmp( pAct->GetBitmap(), pBmpParam ) ) |
1962 | 0 | ); |
1963 | 0 | } |
1964 | 0 | break; |
1965 | | |
1966 | 0 | case MetaActionType::BMPEXSCALEPART: |
1967 | 0 | { |
1968 | 0 | MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction); |
1969 | 0 | aMtf.push_back( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), |
1970 | 0 | pAct->GetSrcPoint(), pAct->GetSrcSize(), |
1971 | 0 | pFncBmp( pAct->GetBitmap(), pBmpParam ) ) |
1972 | 0 | ); |
1973 | 0 | } |
1974 | 0 | break; |
1975 | | |
1976 | 0 | case MetaActionType::MASKSCALE: |
1977 | 0 | { |
1978 | 0 | MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction); |
1979 | 0 | aMtf.push_back( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(), |
1980 | 0 | pAct->GetBitmap(), |
1981 | 0 | pFncCol( pAct->GetColor(), pColParam ) ) |
1982 | 0 | ); |
1983 | 0 | } |
1984 | 0 | break; |
1985 | | |
1986 | 0 | case MetaActionType::MASKSCALEPART: |
1987 | 0 | { |
1988 | 0 | MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction); |
1989 | 0 | aMtf.push_back( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), |
1990 | 0 | pAct->GetSrcPoint(), pAct->GetSrcSize(), |
1991 | 0 | pAct->GetBitmap(), |
1992 | 0 | pFncCol( pAct->GetColor(), pColParam ) ) |
1993 | 0 | ); |
1994 | 0 | } |
1995 | 0 | break; |
1996 | | |
1997 | 0 | case MetaActionType::GRADIENT: |
1998 | 0 | { |
1999 | 0 | MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction); |
2000 | 0 | Gradient aGradient( pAct->GetGradient() ); |
2001 | |
|
2002 | 0 | aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); |
2003 | 0 | aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); |
2004 | 0 | aMtf.push_back( new MetaGradientAction( pAct->GetRect(), std::move(aGradient) ) ); |
2005 | 0 | } |
2006 | 0 | break; |
2007 | | |
2008 | 0 | case MetaActionType::GRADIENTEX: |
2009 | 0 | { |
2010 | 0 | MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction); |
2011 | 0 | Gradient aGradient( pAct->GetGradient() ); |
2012 | |
|
2013 | 0 | aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); |
2014 | 0 | aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); |
2015 | 0 | aMtf.push_back( new MetaGradientExAction( pAct->GetPolyPolygon(), std::move(aGradient) ) ); |
2016 | 0 | } |
2017 | 0 | break; |
2018 | | |
2019 | 0 | case MetaActionType::HATCH: |
2020 | 0 | { |
2021 | 0 | MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction); |
2022 | 0 | Hatch aHatch( pAct->GetHatch() ); |
2023 | |
|
2024 | 0 | aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) ); |
2025 | 0 | aMtf.push_back( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ) ); |
2026 | 0 | } |
2027 | 0 | break; |
2028 | | |
2029 | 0 | case MetaActionType::FLOATTRANSPARENT: |
2030 | 0 | { |
2031 | 0 | MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction); |
2032 | 0 | GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() ); |
2033 | |
|
2034 | 0 | aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); |
2035 | 0 | aMtf.push_back( new MetaFloatTransparentAction( aTransMtf, |
2036 | 0 | pAct->GetPoint(), pAct->GetSize(), |
2037 | 0 | pAct->GetGradient() ) |
2038 | 0 | ); |
2039 | 0 | } |
2040 | 0 | break; |
2041 | | |
2042 | 0 | case MetaActionType::EPS: |
2043 | 0 | { |
2044 | 0 | MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction); |
2045 | 0 | GDIMetaFile aSubst( pAct->GetSubstitute() ); |
2046 | |
|
2047 | 0 | aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); |
2048 | 0 | aMtf.push_back( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(), |
2049 | 0 | pAct->GetLink(), aSubst ) |
2050 | 0 | ); |
2051 | 0 | } |
2052 | 0 | break; |
2053 | | |
2054 | 0 | default: |
2055 | 0 | { |
2056 | 0 | aMtf.push_back( pAction ); |
2057 | 0 | } |
2058 | 0 | break; |
2059 | 0 | } |
2060 | 0 | } |
2061 | | |
2062 | 0 | *this = aMtf; |
2063 | 0 | } |
2064 | | |
2065 | | void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, |
2066 | | short nChannelRPercent, short nChannelGPercent, |
2067 | | short nChannelBPercent, double fGamma, bool bInvert, bool msoBrightness ) |
2068 | 0 | { |
2069 | | // nothing to do? => return quickly |
2070 | 0 | if( !(nLuminancePercent || nContrastPercent || |
2071 | 0 | nChannelRPercent || nChannelGPercent || nChannelBPercent || |
2072 | 0 | ( fGamma != 1.0 ) || bInvert) ) |
2073 | 0 | return; |
2074 | | |
2075 | 0 | double fM, fROff, fGOff, fBOff, fOff; |
2076 | 0 | ImplColAdjustParam aColParam; |
2077 | 0 | ImplBmpAdjustParam aBmpParam; |
2078 | |
|
2079 | 0 | aColParam.pMapR.reset(new sal_uInt8[ 256 ]); |
2080 | 0 | aColParam.pMapG.reset(new sal_uInt8[ 256 ]); |
2081 | 0 | aColParam.pMapB.reset(new sal_uInt8[ 256 ]); |
2082 | | |
2083 | | // calculate slope |
2084 | 0 | if( nContrastPercent >= 0 ) |
2085 | 0 | fM = 128.0 / ( 128.0 - 1.27 * std::clamp( nContrastPercent, short(0), short(100) ) ); |
2086 | 0 | else |
2087 | 0 | fM = ( 128.0 + 1.27 * std::clamp( nContrastPercent, short(-100), short(0) ) ) / 128.0; |
2088 | |
|
2089 | 0 | if(!msoBrightness) |
2090 | | // total offset = luminance offset + contrast offset |
2091 | 0 | fOff = std::clamp( nLuminancePercent, short(-100), short(100) ) * 2.55 + 128.0 - fM * 128.0; |
2092 | 0 | else |
2093 | 0 | fOff = std::clamp( nLuminancePercent, short(-100), short(100) ) * 2.55; |
2094 | | |
2095 | | // channel offset = channel offset + total offset |
2096 | 0 | fROff = nChannelRPercent * 2.55 + fOff; |
2097 | 0 | fGOff = nChannelGPercent * 2.55 + fOff; |
2098 | 0 | fBOff = nChannelBPercent * 2.55 + fOff; |
2099 | | |
2100 | | // calculate gamma value |
2101 | 0 | fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); |
2102 | 0 | const bool bGamma = ( fGamma != 1.0 ); |
2103 | | |
2104 | | // create mapping table |
2105 | 0 | for( tools::Long nX = 0; nX < 256; nX++ ) |
2106 | 0 | { |
2107 | 0 | if(!msoBrightness) |
2108 | 0 | { |
2109 | 0 | aColParam.pMapR[nX] = basegfx::fround<sal_uInt8>(nX * fM + fROff); |
2110 | 0 | aColParam.pMapG[nX] = basegfx::fround<sal_uInt8>(nX * fM + fGOff); |
2111 | 0 | aColParam.pMapB[nX] = basegfx::fround<sal_uInt8>(nX * fM + fBOff); |
2112 | 0 | } |
2113 | 0 | else |
2114 | 0 | { |
2115 | 0 | aColParam.pMapR[nX] = basegfx::fround<sal_uInt8>((nX+fROff/2-128) * fM + 128 + fROff/2); |
2116 | 0 | aColParam.pMapG[nX] = basegfx::fround<sal_uInt8>((nX+fGOff/2-128) * fM + 128 + fGOff/2); |
2117 | 0 | aColParam.pMapB[nX] = basegfx::fround<sal_uInt8>((nX+fBOff/2-128) * fM + 128 + fBOff/2); |
2118 | 0 | } |
2119 | 0 | if( bGamma ) |
2120 | 0 | { |
2121 | 0 | aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma ); |
2122 | 0 | aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma ); |
2123 | 0 | aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma ); |
2124 | 0 | } |
2125 | |
|
2126 | 0 | if( bInvert ) |
2127 | 0 | { |
2128 | 0 | aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ]; |
2129 | 0 | aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ]; |
2130 | 0 | aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ]; |
2131 | 0 | } |
2132 | 0 | } |
2133 | |
|
2134 | 0 | aBmpParam.nLuminancePercent = nLuminancePercent; |
2135 | 0 | aBmpParam.nContrastPercent = nContrastPercent; |
2136 | 0 | aBmpParam.nChannelRPercent = nChannelRPercent; |
2137 | 0 | aBmpParam.nChannelGPercent = nChannelGPercent; |
2138 | 0 | aBmpParam.nChannelBPercent = nChannelBPercent; |
2139 | 0 | aBmpParam.fGamma = fGamma; |
2140 | 0 | aBmpParam.bInvert = bInvert; |
2141 | | |
2142 | | // do color adjustment |
2143 | 0 | ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam ); |
2144 | 0 | } |
2145 | | |
2146 | | void GDIMetaFile::Convert( MtfConversion eConversion ) |
2147 | 0 | { |
2148 | 0 | ImplColConvertParam aColParam; |
2149 | 0 | ImplBmpConvertParam aBmpParam; |
2150 | |
|
2151 | 0 | aColParam.eConversion = eConversion; |
2152 | 0 | aBmpParam.eConversion = ( MtfConversion::N1BitThreshold == eConversion ) ? BmpConversion::N1BitThreshold : BmpConversion::N8BitGreys; |
2153 | |
|
2154 | 0 | ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam ); |
2155 | 0 | } |
2156 | | |
2157 | | void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount ) |
2158 | 0 | { |
2159 | 0 | ImplColReplaceParam aColParam; |
2160 | 0 | ImplBmpReplaceParam aBmpParam; |
2161 | |
|
2162 | 0 | aColParam.pMinR.reset(new sal_uLong[ nColorCount ]); |
2163 | 0 | aColParam.pMaxR.reset(new sal_uLong[ nColorCount ]); |
2164 | 0 | aColParam.pMinG.reset(new sal_uLong[ nColorCount ]); |
2165 | 0 | aColParam.pMaxG.reset(new sal_uLong[ nColorCount ]); |
2166 | 0 | aColParam.pMinB.reset(new sal_uLong[ nColorCount ]); |
2167 | 0 | aColParam.pMaxB.reset(new sal_uLong[ nColorCount ]); |
2168 | |
|
2169 | 0 | for( sal_uLong i = 0; i < nColorCount; i++ ) |
2170 | 0 | { |
2171 | 0 | tools::Long nVal; |
2172 | |
|
2173 | 0 | nVal = pSearchColors[ i ].GetRed(); |
2174 | 0 | aColParam.pMinR[ i ] = static_cast<sal_uLong>(std::max( nVal, tools::Long(0) )); |
2175 | 0 | aColParam.pMaxR[ i ] = static_cast<sal_uLong>(std::min( nVal, tools::Long(255) )); |
2176 | |
|
2177 | 0 | nVal = pSearchColors[ i ].GetGreen(); |
2178 | 0 | aColParam.pMinG[ i ] = static_cast<sal_uLong>(std::max( nVal, tools::Long(0) )); |
2179 | 0 | aColParam.pMaxG[ i ] = static_cast<sal_uLong>(std::min( nVal, tools::Long(255) )); |
2180 | |
|
2181 | 0 | nVal = pSearchColors[ i ].GetBlue(); |
2182 | 0 | aColParam.pMinB[ i ] = static_cast<sal_uLong>(std::max( nVal, tools::Long(0) )); |
2183 | 0 | aColParam.pMaxB[ i ] = static_cast<sal_uLong>(std::min( nVal, tools::Long(255) )); |
2184 | 0 | } |
2185 | |
|
2186 | 0 | aColParam.pDstCols = pReplaceColors; |
2187 | 0 | aColParam.nCount = nColorCount; |
2188 | |
|
2189 | 0 | aBmpParam.pSrcCols = pSearchColors; |
2190 | 0 | aBmpParam.pDstCols = pReplaceColors; |
2191 | 0 | aBmpParam.nCount = nColorCount; |
2192 | |
|
2193 | 0 | ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam ); |
2194 | 0 | }; |
2195 | | |
2196 | | GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const |
2197 | 0 | { |
2198 | 0 | GDIMetaFile aRet( *this ); |
2199 | |
|
2200 | 0 | ImplColMonoParam aColParam; |
2201 | 0 | ImplBmpMonoParam aBmpParam; |
2202 | |
|
2203 | 0 | aColParam.aColor = rColor; |
2204 | 0 | aBmpParam.aColor = rColor; |
2205 | |
|
2206 | 0 | aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam ); |
2207 | |
|
2208 | 0 | return aRet; |
2209 | 0 | } |
2210 | | |
2211 | | sal_uLong GDIMetaFile::GetSizeBytes() const |
2212 | 3.23k | { |
2213 | 3.23k | sal_uLong nSizeBytes = 0; |
2214 | | |
2215 | 394k | for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; ++i ) |
2216 | 391k | { |
2217 | 391k | MetaAction* pAction = GetAction( i ); |
2218 | | |
2219 | | // default action size is set to 32 (=> not the exact value) |
2220 | 391k | nSizeBytes += 32; |
2221 | | |
2222 | | // add sizes for large action content |
2223 | 391k | switch( pAction->GetType() ) |
2224 | 391k | { |
2225 | 0 | case MetaActionType::BMP: nSizeBytes += static_cast<MetaBmpAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2226 | 596 | case MetaActionType::BMPSCALE: nSizeBytes += static_cast<MetaBmpScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2227 | 797 | case MetaActionType::BMPSCALEPART: nSizeBytes += static_cast<MetaBmpScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2228 | | |
2229 | 213 | case MetaActionType::BMPEX: nSizeBytes += static_cast<MetaBmpExAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2230 | 229 | case MetaActionType::BMPEXSCALE: nSizeBytes += static_cast<MetaBmpExScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2231 | 553 | case MetaActionType::BMPEXSCALEPART: nSizeBytes += static_cast<MetaBmpExScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2232 | | |
2233 | 382 | case MetaActionType::MASK: nSizeBytes += static_cast<MetaMaskAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2234 | 754 | case MetaActionType::MASKSCALE: nSizeBytes += static_cast<MetaMaskScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2235 | 534 | case MetaActionType::MASKSCALEPART: nSizeBytes += static_cast<MetaMaskScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break; |
2236 | | |
2237 | 1.01k | case MetaActionType::POLYLINE: nSizeBytes += static_cast<MetaPolyLineAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break; |
2238 | 4.29k | case MetaActionType::POLYGON: nSizeBytes += static_cast<MetaPolygonAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break; |
2239 | 326 | case MetaActionType::POLYPOLYGON: |
2240 | 326 | { |
2241 | 326 | const tools::PolyPolygon& rPolyPoly = static_cast<MetaPolyPolygonAction*>( pAction )->GetPolyPolygon(); |
2242 | | |
2243 | 348 | for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n ) |
2244 | 22 | nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) ); |
2245 | 326 | } |
2246 | 326 | break; |
2247 | | |
2248 | 111 | case MetaActionType::TEXT: nSizeBytes += static_cast<MetaTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break; |
2249 | 18 | case MetaActionType::STRETCHTEXT: nSizeBytes += static_cast<MetaStretchTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break; |
2250 | 2.44k | case MetaActionType::TEXTRECT: nSizeBytes += static_cast<MetaTextRectAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break; |
2251 | 3.86k | case MetaActionType::TEXTARRAY: |
2252 | 3.86k | { |
2253 | 3.86k | MetaTextArrayAction* pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction); |
2254 | | |
2255 | 3.86k | nSizeBytes += ( pTextArrayAction->GetText().getLength() * sizeof( sal_Unicode ) ); |
2256 | | |
2257 | 3.86k | if( !pTextArrayAction->GetDXArray().empty() ) |
2258 | 2.74k | nSizeBytes += ( pTextArrayAction->GetLen() << 2 ); |
2259 | 3.86k | } |
2260 | 3.86k | break; |
2261 | 375k | default: break; |
2262 | 391k | } |
2263 | 391k | } |
2264 | | |
2265 | 3.23k | return nSizeBytes; |
2266 | 3.23k | } |
2267 | | |
2268 | | bool GDIMetaFile::CreateThumbnail(Bitmap& rBitmap, BmpConversion eColorConversion, BmpScaleFlag nScaleFlag) const |
2269 | 0 | { |
2270 | | // initialization seems to be complicated but is used to avoid rounding errors |
2271 | 0 | ScopedVclPtrInstance< VirtualDevice > aVDev; |
2272 | | // set Enable to tease the rendering down the code paths which use B2DPolygon and |
2273 | | // avoid integer overflows on scaling tools::Polygon, e.g. moz1545040-1.svg |
2274 | | // note: this is similar to DocumentToGraphicRenderer::renderToGraphic |
2275 | 0 | aVDev->SetAntialiasing(AntialiasingFlags::Enable | aVDev->GetAntialiasing()); |
2276 | 0 | const Point aNullPt; |
2277 | 0 | const Point aTLPix( aVDev->LogicToPixel( aNullPt, GetPrefMapMode() ) ); |
2278 | 0 | const Point aBRPix( aVDev->LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) ); |
2279 | 0 | Size aDrawSize( aVDev->LogicToPixel( GetPrefSize(), GetPrefMapMode() ) ); |
2280 | 0 | Size aSizePix( std::abs( aBRPix.X() - aTLPix.X() ) + 1, std::abs( aBRPix.Y() - aTLPix.Y() ) + 1 ); |
2281 | 0 | sal_uInt32 nMaximumExtent = 512; |
2282 | |
|
2283 | 0 | if (!rBitmap.IsEmpty()) |
2284 | 0 | rBitmap.SetEmpty(); |
2285 | | |
2286 | | // determine size that has the same aspect ratio as image size and |
2287 | | // fits into the rectangle determined by nMaximumExtent |
2288 | 0 | if ( aSizePix.Width() && aSizePix.Height() |
2289 | 0 | && ( sal::static_int_cast< tools::ULong >(aSizePix.Width()) > |
2290 | 0 | nMaximumExtent || |
2291 | 0 | sal::static_int_cast< tools::ULong >(aSizePix.Height()) > |
2292 | 0 | nMaximumExtent ) ) |
2293 | 0 | { |
2294 | 0 | const Size aOldSizePix( aSizePix ); |
2295 | 0 | double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height(); |
2296 | |
|
2297 | 0 | if ( fWH <= 1.0 ) |
2298 | 0 | { |
2299 | 0 | aSizePix.setWidth(basegfx::fround<tools::Long>(nMaximumExtent * fWH)); |
2300 | 0 | aSizePix.setHeight( nMaximumExtent ); |
2301 | 0 | } |
2302 | 0 | else |
2303 | 0 | { |
2304 | 0 | aSizePix.setWidth( nMaximumExtent ); |
2305 | 0 | aSizePix.setHeight(basegfx::fround<tools::Long>(nMaximumExtent / fWH)); |
2306 | 0 | } |
2307 | |
|
2308 | 0 | aDrawSize.setWidth( basegfx::fround<tools::Long>( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() ) ); |
2309 | 0 | aDrawSize.setHeight( basegfx::fround<tools::Long>( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() ) ); |
2310 | 0 | } |
2311 | | |
2312 | | // draw image(s) into VDev and get resulting image |
2313 | | // do it 4x larger to be able to scale it down & get beautiful antialias |
2314 | 0 | Size aAntialiasSize(aSizePix.Width() * 4, aSizePix.Height() * 4); |
2315 | 0 | if (aVDev->SetOutputSizePixel(aAntialiasSize)) |
2316 | 0 | { |
2317 | | // antialias: provide 4x larger size, and then scale down the result |
2318 | 0 | Size aAntialias(aDrawSize.Width() * 4, aDrawSize.Height() * 4); |
2319 | | |
2320 | | // draw metafile into VDev |
2321 | 0 | const_cast<GDIMetaFile *>(this)->WindStart(); |
2322 | 0 | const_cast<GDIMetaFile *>(this)->Play(*aVDev, Point(), aAntialias); |
2323 | | |
2324 | | // get paint bitmap |
2325 | 0 | Bitmap aBitmap( aVDev->GetBitmap( aNullPt, aVDev->GetOutputSizePixel() ) ); |
2326 | | |
2327 | | // scale down the image to the desired size - use the input scaler for the scaling operation |
2328 | 0 | aBitmap.Scale(aDrawSize, nScaleFlag); |
2329 | | |
2330 | | // convert to desired bitmap color format |
2331 | 0 | Size aSize(aBitmap.GetSizePixel()); |
2332 | 0 | if (aSize.Width() && aSize.Height()) |
2333 | 0 | aBitmap.Convert(eColorConversion); |
2334 | |
|
2335 | 0 | rBitmap = std::move(aBitmap); |
2336 | 0 | } |
2337 | |
|
2338 | 0 | return !rBitmap.IsEmpty(); |
2339 | 0 | } |
2340 | | |
2341 | | void GDIMetaFile::UseCanvas( bool _bUseCanvas ) |
2342 | 261 | { |
2343 | 261 | m_bUseCanvas = _bUseCanvas; |
2344 | 261 | } |
2345 | | |
2346 | | void GDIMetaFile::dumpAsXml(const char* pFileName) const |
2347 | 0 | { |
2348 | 0 | SvFileStream aStream(pFileName ? OUString::fromUtf8(pFileName) : u"file:///tmp/metafile.xml"_ustr, |
2349 | 0 | StreamMode::STD_READWRITE | StreamMode::TRUNC); |
2350 | | assert(aStream.good()); |
2351 | 0 | MetafileXmlDump aDumper; |
2352 | 0 | aDumper.dump(*this, aStream); |
2353 | 0 | } |
2354 | | |
2355 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |