/src/libreoffice/vcl/source/graphic/GraphicObject.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 <sal/config.h> |
21 | | |
22 | | #include <algorithm> |
23 | | |
24 | | #include <o3tl/string_view.hxx> |
25 | | #include <osl/diagnose.h> |
26 | | #include <tools/fract.hxx> |
27 | | #include <tools/helpers.hxx> |
28 | | #include <tools/mapunit.hxx> |
29 | | #include <utility> |
30 | | #include <vcl/animate/Animation.hxx> |
31 | | #include <vcl/animate/AnimationFrame.hxx> |
32 | | #include <vcl/svapp.hxx> |
33 | | #include <vcl/metaact.hxx> |
34 | | #include <vcl/GraphicObject.hxx> |
35 | | #include <vcl/GraphicLoader.hxx> |
36 | | #include <vcl/outdev.hxx> |
37 | | #include <vcl/rendercontext/DrawModeFlags.hxx> |
38 | | |
39 | | #include <com/sun/star/container/XNameContainer.hpp> |
40 | | #include <com/sun/star/beans/XPropertySet.hpp> |
41 | | #include <com/sun/star/graphic/XGraphic.hpp> |
42 | | #include <memory> |
43 | | |
44 | | |
45 | | using namespace css; |
46 | | using com::sun::star::uno::Reference; |
47 | | using com::sun::star::uno::XInterface; |
48 | | using com::sun::star::uno::UNO_QUERY; |
49 | | using com::sun::star::uno::Sequence; |
50 | | using com::sun::star::container::XNameContainer; |
51 | | using com::sun::star::beans::XPropertySet; |
52 | | |
53 | 0 | #define WATERMARK_LUM_OFFSET 50 |
54 | 0 | #define WATERMARK_CON_OFFSET -70 |
55 | | |
56 | | namespace vcl::graphic |
57 | | { |
58 | | |
59 | | void SearchForGraphics(uno::Reference<uno::XInterface> const & xInterface, |
60 | | std::vector<uno::Reference<css::graphic::XGraphic>> & raGraphicList) |
61 | 0 | { |
62 | 0 | uno::Reference<beans::XPropertySet> xPropertySet(xInterface, UNO_QUERY); |
63 | 0 | if (xPropertySet.is()) |
64 | 0 | { |
65 | 0 | if (xPropertySet->getPropertySetInfo()->hasPropertyByName(u"ImageURL"_ustr)) |
66 | 0 | { |
67 | 0 | OUString sURL; |
68 | 0 | xPropertySet->getPropertyValue(u"ImageURL"_ustr) >>= sURL; |
69 | 0 | if (!sURL.isEmpty() && !GraphicObject::isGraphicObjectUniqueIdURL(sURL)) |
70 | 0 | { |
71 | 0 | Graphic aGraphic = vcl::graphic::loadFromURL(sURL); |
72 | 0 | if (!aGraphic.IsNone()) |
73 | 0 | { |
74 | 0 | raGraphicList.push_back(aGraphic.GetXGraphic()); |
75 | 0 | } |
76 | 0 | } |
77 | 0 | } else if (xPropertySet->getPropertySetInfo()->hasPropertyByName(u"Graphic"_ustr)) |
78 | 0 | { |
79 | 0 | uno::Reference<css::graphic::XGraphic> xGraphic; |
80 | 0 | xPropertySet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic; |
81 | 0 | if (xGraphic.is()) |
82 | 0 | { |
83 | 0 | raGraphicList.push_back(xGraphic); |
84 | 0 | } |
85 | 0 | } |
86 | 0 | } |
87 | 0 | Reference<XNameContainer> xContainer(xInterface, UNO_QUERY); |
88 | 0 | if (xContainer.is()) |
89 | 0 | { |
90 | 0 | const css::uno::Sequence<OUString> aElementNames = xContainer->getElementNames(); |
91 | 0 | for (OUString const & rName : aElementNames) |
92 | 0 | { |
93 | 0 | uno::Reference<XInterface> xInnerInterface; |
94 | 0 | xContainer->getByName(rName) >>= xInnerInterface; |
95 | 0 | SearchForGraphics(xInnerInterface, raGraphicList); |
96 | 0 | } |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | } // end namespace vcl::graphic |
101 | | |
102 | | namespace |
103 | | { |
104 | | |
105 | | bool lclDrawObj(OutputDevice& rOut, const Point& rPt, const Size& rSz, |
106 | | GraphicObject const & rObj, const GraphicAttr& rAttr) |
107 | 0 | { |
108 | 0 | Point aPt( rPt ); |
109 | 0 | Size aSz( rSz ); |
110 | 0 | bool bRet = false; |
111 | |
|
112 | 0 | if( ( rObj.GetType() == GraphicType::Bitmap ) || ( rObj.GetType() == GraphicType::GdiMetafile ) ) |
113 | 0 | { |
114 | | // simple output of transformed graphic |
115 | 0 | const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) ); |
116 | |
|
117 | 0 | if( aGraphic.IsSupportedGraphic() ) |
118 | 0 | { |
119 | 0 | const Degree10 nRot10 = rAttr.GetRotation() % 3600_deg10; |
120 | |
|
121 | 0 | if( nRot10 ) |
122 | 0 | { |
123 | 0 | tools::Polygon aPoly( tools::Rectangle( aPt, aSz ) ); |
124 | |
|
125 | 0 | aPoly.Rotate( aPt, nRot10 ); |
126 | 0 | const tools::Rectangle aRotBoundRect( aPoly.GetBoundRect() ); |
127 | 0 | aPt = aRotBoundRect.TopLeft(); |
128 | 0 | aSz = aRotBoundRect.GetSize(); |
129 | 0 | } |
130 | |
|
131 | 0 | aGraphic.Draw(rOut, aPt, aSz); |
132 | 0 | } |
133 | |
|
134 | 0 | bRet = true; |
135 | 0 | } |
136 | |
|
137 | 0 | return bRet; |
138 | 0 | } |
139 | | |
140 | | void lclImplAdjust( Bitmap& rBmp, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) |
141 | 0 | { |
142 | 0 | GraphicAttr aAttr( rAttr ); |
143 | |
|
144 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) |
145 | 0 | { |
146 | 0 | switch( aAttr.GetDrawMode() ) |
147 | 0 | { |
148 | 0 | case GraphicDrawMode::Mono: |
149 | 0 | rBmp.Convert( BmpConversion::N1BitThreshold ); |
150 | 0 | break; |
151 | | |
152 | 0 | case GraphicDrawMode::Greys: |
153 | 0 | rBmp.Convert( BmpConversion::N8BitGreys ); |
154 | 0 | break; |
155 | | |
156 | 0 | case GraphicDrawMode::Watermark: |
157 | 0 | { |
158 | 0 | aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); |
159 | 0 | aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); |
160 | 0 | } |
161 | 0 | break; |
162 | | |
163 | 0 | default: |
164 | 0 | break; |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) |
169 | 0 | { |
170 | 0 | rBmp.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), |
171 | 0 | aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), |
172 | 0 | aAttr.GetGamma(), aAttr.IsInvert() ); |
173 | 0 | } |
174 | |
|
175 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) |
176 | 0 | { |
177 | 0 | rBmp.Mirror( aAttr.GetMirrorFlags() ); |
178 | 0 | } |
179 | |
|
180 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) |
181 | 0 | { |
182 | 0 | rBmp.Rotate( aAttr.GetRotation(), COL_TRANSPARENT ); |
183 | 0 | } |
184 | |
|
185 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) |
186 | 0 | { |
187 | 0 | rBmp.AdjustTransparency(255 - aAttr.GetAlpha()); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | void lclImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) |
192 | 0 | { |
193 | 0 | GraphicAttr aAttr( rAttr ); |
194 | |
|
195 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) |
196 | 0 | { |
197 | 0 | switch( aAttr.GetDrawMode() ) |
198 | 0 | { |
199 | 0 | case GraphicDrawMode::Mono: |
200 | 0 | rMtf.Convert( MtfConversion::N1BitThreshold ); |
201 | 0 | break; |
202 | | |
203 | 0 | case GraphicDrawMode::Greys: |
204 | 0 | rMtf.Convert( MtfConversion::N8BitGreys ); |
205 | 0 | break; |
206 | | |
207 | 0 | case GraphicDrawMode::Watermark: |
208 | 0 | { |
209 | 0 | aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); |
210 | 0 | aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); |
211 | 0 | } |
212 | 0 | break; |
213 | | |
214 | 0 | default: |
215 | 0 | break; |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) |
220 | 0 | { |
221 | 0 | rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), |
222 | 0 | aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), |
223 | 0 | aAttr.GetGamma(), aAttr.IsInvert() ); |
224 | 0 | } |
225 | |
|
226 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) |
227 | 0 | { |
228 | 0 | rMtf.Mirror( aAttr.GetMirrorFlags() ); |
229 | 0 | } |
230 | |
|
231 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) |
232 | 0 | { |
233 | 0 | rMtf.Rotate( aAttr.GetRotation() ); |
234 | 0 | } |
235 | |
|
236 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) |
237 | 0 | { |
238 | 0 | OSL_FAIL( "Missing implementation: Mtf-Transparency" ); |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | | void lclImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags ) |
243 | 0 | { |
244 | 0 | GraphicAttr aAttr( rAttr ); |
245 | |
|
246 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() ) |
247 | 0 | { |
248 | 0 | switch( aAttr.GetDrawMode() ) |
249 | 0 | { |
250 | 0 | case GraphicDrawMode::Mono: |
251 | 0 | rAnimation.Convert( BmpConversion::N1BitThreshold ); |
252 | 0 | break; |
253 | | |
254 | 0 | case GraphicDrawMode::Greys: |
255 | 0 | rAnimation.Convert( BmpConversion::N8BitGreys ); |
256 | 0 | break; |
257 | | |
258 | 0 | case GraphicDrawMode::Watermark: |
259 | 0 | { |
260 | 0 | aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET ); |
261 | 0 | aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET ); |
262 | 0 | } |
263 | 0 | break; |
264 | | |
265 | 0 | default: |
266 | 0 | break; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() ) |
271 | 0 | { |
272 | 0 | rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(), |
273 | 0 | aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(), |
274 | 0 | aAttr.GetGamma(), aAttr.IsInvert() ); |
275 | 0 | } |
276 | |
|
277 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() ) |
278 | 0 | { |
279 | 0 | rAnimation.Mirror( aAttr.GetMirrorFlags() ); |
280 | 0 | } |
281 | |
|
282 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() ) |
283 | 0 | { |
284 | 0 | OSL_FAIL( "Missing implementation: Animation-Rotation" ); |
285 | 0 | } |
286 | |
|
287 | 0 | if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() ) |
288 | 0 | { |
289 | 0 | OSL_FAIL( "Missing implementation: Animation-Transparency" ); |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | | } // end anonymous namespace |
294 | | |
295 | | struct GrfSimpleCacheObj |
296 | | { |
297 | | Graphic maGraphic; |
298 | | GraphicAttr maAttr; |
299 | | |
300 | | GrfSimpleCacheObj( Graphic aGraphic, const GraphicAttr& rAttr ) : |
301 | 0 | maGraphic(std::move( aGraphic )), maAttr( rAttr ) {} |
302 | | }; |
303 | | |
304 | | GraphicObject::GraphicObject() |
305 | 216k | { |
306 | 216k | } |
307 | | |
308 | | GraphicObject::GraphicObject(Graphic aGraphic) |
309 | 188k | : maGraphic(std::move(aGraphic)) |
310 | 188k | { |
311 | 188k | } |
312 | | |
313 | | GraphicObject::GraphicObject(const GraphicObject& rGraphicObj) |
314 | 213k | : maGraphic(rGraphicObj.GetGraphic()) |
315 | 213k | , maAttr(rGraphicObj.maAttr) |
316 | 213k | , maUserData(rGraphicObj.maUserData) |
317 | 213k | { |
318 | 213k | } |
319 | | |
320 | | GraphicObject::~GraphicObject() |
321 | 618k | { |
322 | 618k | } |
323 | | |
324 | | GraphicType GraphicObject::GetType() const |
325 | 121k | { |
326 | 121k | return maGraphic.GetType(); |
327 | 121k | } |
328 | | |
329 | | Size GraphicObject::GetPrefSize() const |
330 | 0 | { |
331 | 0 | return maGraphic.GetPrefSize(); |
332 | 0 | } |
333 | | |
334 | | MapMode GraphicObject::GetPrefMapMode() const |
335 | 0 | { |
336 | 0 | return maGraphic.GetPrefMapMode(); |
337 | 0 | } |
338 | | |
339 | | bool GraphicObject::IsTransparent() const |
340 | 270 | { |
341 | 270 | return maGraphic.IsTransparent(); |
342 | 270 | } |
343 | | |
344 | | bool GraphicObject::IsAnimated() const |
345 | 4.13k | { |
346 | 4.13k | return maGraphic.IsAnimated(); |
347 | 4.13k | } |
348 | | |
349 | | bool GraphicObject::IsEPS() const |
350 | 0 | { |
351 | 0 | return maGraphic.IsEPS(); |
352 | 0 | } |
353 | | |
354 | | bool GraphicObject::ImplGetCropParams(const OutputDevice& rOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr, |
355 | | tools::PolyPolygon& rClipPolyPoly, bool& bRectClipRegion) const |
356 | 0 | { |
357 | 0 | bool bRet = false; |
358 | |
|
359 | 0 | if( GetType() != GraphicType::NONE ) |
360 | 0 | { |
361 | 0 | tools::Polygon aClipPoly( tools::Rectangle( rPt, rSz ) ); |
362 | 0 | const Degree10 nRot10 = pAttr->GetRotation() % 3600_deg10; |
363 | 0 | const Point aOldOrigin( rPt ); |
364 | 0 | const MapMode aMap100( MapUnit::Map100thMM ); |
365 | 0 | Size aSize100; |
366 | 0 | tools::Long nTotalWidth, nTotalHeight; |
367 | |
|
368 | 0 | if( nRot10 ) |
369 | 0 | { |
370 | 0 | aClipPoly.Rotate( rPt, nRot10 ); |
371 | 0 | bRectClipRegion = false; |
372 | 0 | } |
373 | 0 | else |
374 | 0 | bRectClipRegion = true; |
375 | |
|
376 | 0 | rClipPolyPoly = tools::PolyPolygon(aClipPoly); |
377 | |
|
378 | 0 | if (maGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel) |
379 | 0 | aSize100 = Application::GetDefaultDevice()->PixelToLogic( maGraphic.GetPrefSize(), aMap100 ); |
380 | 0 | else |
381 | 0 | { |
382 | 0 | MapMode m(maGraphic.GetPrefMapMode()); |
383 | 0 | aSize100 = rOut.LogicToLogic( maGraphic.GetPrefSize(), &m, &aMap100 ); |
384 | 0 | } |
385 | |
|
386 | 0 | nTotalWidth = aSize100.Width() - pAttr->GetLeftCrop() - pAttr->GetRightCrop(); |
387 | 0 | nTotalHeight = aSize100.Height() - pAttr->GetTopCrop() - pAttr->GetBottomCrop(); |
388 | |
|
389 | 0 | if( !aSize100.IsEmpty() && nTotalWidth > 0 && nTotalHeight > 0 ) |
390 | 0 | { |
391 | 0 | double fScale = static_cast<double>(aSize100.Width()) / nTotalWidth; |
392 | 0 | const tools::Long nNewLeft = basegfx::fround<tools::Long>( ( ( pAttr->GetMirrorFlags() & BmpMirrorFlags::Horizontal ) ? pAttr->GetRightCrop() : pAttr->GetLeftCrop() ) * -fScale ); |
393 | 0 | const tools::Long nNewRight = nNewLeft + basegfx::fround<tools::Long>( aSize100.Width() * fScale ) - 1; |
394 | |
|
395 | 0 | fScale = static_cast<double>(rSz.Width()) / aSize100.Width(); |
396 | 0 | rPt.AdjustX(basegfx::fround<tools::Long>(nNewLeft * fScale)); |
397 | 0 | rSz.setWidth(basegfx::fround<tools::Long>((nNewRight - nNewLeft + 1) * fScale)); |
398 | |
|
399 | 0 | fScale = static_cast<double>(aSize100.Height()) / nTotalHeight; |
400 | 0 | const tools::Long nNewTop = basegfx::fround<tools::Long>( ( ( pAttr->GetMirrorFlags() & BmpMirrorFlags::Vertical ) ? pAttr->GetBottomCrop() : pAttr->GetTopCrop() ) * -fScale ); |
401 | 0 | const tools::Long nNewBottom = nNewTop + basegfx::fround<tools::Long>( aSize100.Height() * fScale ) - 1; |
402 | |
|
403 | 0 | fScale = static_cast<double>(rSz.Height()) / aSize100.Height(); |
404 | 0 | rPt.AdjustY(basegfx::fround<tools::Long>(nNewTop * fScale)); |
405 | 0 | rSz.setHeight(basegfx::fround<tools::Long>((nNewBottom - nNewTop + 1) * fScale)); |
406 | |
|
407 | 0 | if( nRot10 ) |
408 | 0 | { |
409 | 0 | tools::Polygon aOriginPoly( 1 ); |
410 | |
|
411 | 0 | aOriginPoly[ 0 ] = rPt; |
412 | 0 | aOriginPoly.Rotate( aOldOrigin, nRot10 ); |
413 | 0 | rPt = aOriginPoly[ 0 ]; |
414 | 0 | } |
415 | |
|
416 | 0 | bRet = true; |
417 | 0 | } |
418 | 0 | } |
419 | |
|
420 | 0 | return bRet; |
421 | 0 | } |
422 | | |
423 | | GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) |
424 | 0 | { |
425 | 0 | if( &rGraphicObj != this ) |
426 | 0 | { |
427 | 0 | mxSimpleCache.reset(); |
428 | 0 | maGraphic = rGraphicObj.GetGraphic(); |
429 | 0 | maAttr = rGraphicObj.maAttr; |
430 | 0 | maUserData = rGraphicObj.maUserData; |
431 | 0 | } |
432 | |
|
433 | 0 | return *this; |
434 | 0 | } |
435 | | |
436 | | bool GraphicObject::operator==( const GraphicObject& rGraphicObj ) const |
437 | 78.5k | { |
438 | 78.5k | return rGraphicObj.maGraphic == maGraphic |
439 | 36.8k | && rGraphicObj.maAttr == maAttr; |
440 | 78.5k | } |
441 | | |
442 | | OString GraphicObject::GetUniqueID() const |
443 | 0 | { |
444 | 0 | return GetGraphic().getUniqueID(); |
445 | 0 | } |
446 | | |
447 | | void GraphicObject::SetAttr( const GraphicAttr& rAttr ) |
448 | 72 | { |
449 | 72 | maAttr = rAttr; |
450 | | |
451 | 72 | if (mxSimpleCache && (mxSimpleCache->maAttr != rAttr)) |
452 | 0 | mxSimpleCache.reset(); |
453 | 72 | } |
454 | | |
455 | | void GraphicObject::SetUserData() |
456 | 9.60k | { |
457 | 9.60k | maUserData.clear(); |
458 | 9.60k | } |
459 | | |
460 | | void GraphicObject::SetUserData( const OUString& rUserData ) |
461 | 0 | { |
462 | 0 | maUserData = rUserData; |
463 | 0 | } |
464 | | |
465 | | bool GraphicObject::Draw(OutputDevice& rOut, const Point& rPt, const Size& rSz, |
466 | | const GraphicAttr* pAttr) const |
467 | 0 | { |
468 | 0 | GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() ); |
469 | 0 | Point aPt( rPt ); |
470 | 0 | Size aSz( rSz ); |
471 | 0 | const DrawModeFlags nOldDrawMode = rOut.GetDrawMode(); |
472 | 0 | bool bCropped = aAttr.IsCropped(); |
473 | 0 | bool bRet; |
474 | |
|
475 | 0 | rOut.SetDrawMode(nOldDrawMode & ~DrawModeFlags( DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient )); |
476 | | |
477 | | // mirrored horizontally |
478 | 0 | if( aSz.Width() < 0 ) |
479 | 0 | { |
480 | 0 | aPt.AdjustX(aSz.Width() + 1 ); |
481 | 0 | aSz.setWidth( -aSz.Width() ); |
482 | 0 | aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BmpMirrorFlags::Horizontal ); |
483 | 0 | } |
484 | | |
485 | | // mirrored vertically |
486 | 0 | if( aSz.Height() < 0 ) |
487 | 0 | { |
488 | 0 | aPt.AdjustY(aSz.Height() + 1 ); |
489 | 0 | aSz.setHeight( -aSz.Height() ); |
490 | 0 | aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BmpMirrorFlags::Vertical ); |
491 | 0 | } |
492 | |
|
493 | 0 | if( bCropped ) |
494 | 0 | { |
495 | 0 | tools::PolyPolygon aClipPolyPoly; |
496 | 0 | bool bRectClip; |
497 | 0 | const bool bCrop = ImplGetCropParams(rOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip); |
498 | |
|
499 | 0 | rOut.Push(vcl::PushFlags::CLIPREGION); |
500 | |
|
501 | 0 | if( bCrop ) |
502 | 0 | { |
503 | 0 | if( bRectClip ) |
504 | 0 | { |
505 | | // #i29534# Store crop rect for later forwarding to |
506 | | // PDF writer |
507 | 0 | tools::Rectangle aCropRect = aClipPolyPoly.GetBoundRect(); |
508 | 0 | rOut.IntersectClipRegion(aCropRect); |
509 | 0 | } |
510 | 0 | else |
511 | 0 | { |
512 | 0 | rOut.IntersectClipRegion(vcl::Region(aClipPolyPoly)); |
513 | 0 | } |
514 | 0 | } |
515 | 0 | } |
516 | |
|
517 | 0 | bRet = lclDrawObj(rOut, aPt, aSz, *this, aAttr); |
518 | |
|
519 | 0 | if( bCropped ) |
520 | 0 | rOut.Pop(); |
521 | |
|
522 | 0 | rOut.SetDrawMode( nOldDrawMode ); |
523 | |
|
524 | 0 | return bRet; |
525 | 0 | } |
526 | | |
527 | | void GraphicObject::DrawTiled(OutputDevice& rOut, const tools::Rectangle& rArea, const Size& rSize, |
528 | | const Size& rOffset, int nTileCacheSize1D) |
529 | 0 | { |
530 | 0 | if (rSize.IsEmpty()) |
531 | 0 | return; |
532 | | |
533 | 0 | const MapMode aOutMapMode(rOut.GetMapMode()); |
534 | | // #106258# Clamp size to 1 for zero values. This is okay, since |
535 | | // logical size of zero is handled above already |
536 | 0 | const Size aOutTileSize( ::std::max( tools::Long(1), rOut.LogicToPixel( rSize, aOutMapMode ).Width() ), |
537 | 0 | ::std::max( tools::Long(1), rOut.LogicToPixel( rSize, aOutMapMode ).Height() ) ); |
538 | | |
539 | | //#i69780 clip final tile size to a sane max size |
540 | 0 | while ((static_cast<sal_Int64>(rSize.Width()) * nTileCacheSize1D) > SAL_MAX_UINT16) |
541 | 0 | nTileCacheSize1D /= 2; |
542 | 0 | while ((static_cast<sal_Int64>(rSize.Height()) * nTileCacheSize1D) > SAL_MAX_UINT16) |
543 | 0 | nTileCacheSize1D /= 2; |
544 | |
|
545 | 0 | ImplDrawTiled(rOut, rArea, aOutTileSize, rOffset, nullptr, nTileCacheSize1D); |
546 | 0 | } |
547 | | |
548 | | bool GraphicObject::StartAnimation(OutputDevice& rOut, const Point& rPt, const Size& rSz, |
549 | | tools::Long nRendererId, |
550 | | OutputDevice* pFirstFrameOutDev) |
551 | 0 | { |
552 | 0 | bool bRet = false; |
553 | |
|
554 | 0 | GetGraphic(); |
555 | |
|
556 | 0 | const GraphicAttr aAttr( GetAttr() ); |
557 | |
|
558 | 0 | if (IsAnimated()) |
559 | 0 | { |
560 | 0 | Point aPt( rPt ); |
561 | 0 | Size aSz( rSz ); |
562 | 0 | bool bCropped = aAttr.IsCropped(); |
563 | |
|
564 | 0 | if( bCropped ) |
565 | 0 | { |
566 | 0 | tools::PolyPolygon aClipPolyPoly; |
567 | 0 | bool bRectClip; |
568 | 0 | const bool bCrop = ImplGetCropParams(rOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip); |
569 | |
|
570 | 0 | rOut.Push(vcl::PushFlags::CLIPREGION); |
571 | |
|
572 | 0 | if( bCrop ) |
573 | 0 | { |
574 | 0 | if( bRectClip ) |
575 | 0 | rOut.IntersectClipRegion(aClipPolyPoly.GetBoundRect()); |
576 | 0 | else |
577 | 0 | rOut.IntersectClipRegion(vcl::Region(aClipPolyPoly)); |
578 | 0 | } |
579 | 0 | } |
580 | |
|
581 | 0 | if (!mxSimpleCache || (mxSimpleCache->maAttr != aAttr) || pFirstFrameOutDev) |
582 | 0 | { |
583 | 0 | mxSimpleCache.reset(new GrfSimpleCacheObj(GetTransformedGraphic(&aAttr), aAttr)); |
584 | 0 | mxSimpleCache->maGraphic.SetAnimationNotifyHdl(GetGraphic().GetAnimationNotifyHdl()); |
585 | 0 | } |
586 | |
|
587 | 0 | mxSimpleCache->maGraphic.StartAnimation(rOut, aPt, aSz, nRendererId, pFirstFrameOutDev); |
588 | |
|
589 | 0 | if( bCropped ) |
590 | 0 | rOut.Pop(); |
591 | |
|
592 | 0 | bRet = true; |
593 | 0 | } |
594 | 0 | else |
595 | 0 | bRet = Draw(rOut, rPt, rSz, &aAttr); |
596 | |
|
597 | 0 | return bRet; |
598 | 0 | } |
599 | | |
600 | | void GraphicObject::StopAnimation( const OutputDevice* pOut, tools::Long nRendererId ) |
601 | 0 | { |
602 | 0 | if (mxSimpleCache) |
603 | 0 | mxSimpleCache->maGraphic.StopAnimation(pOut, nRendererId); |
604 | 0 | } |
605 | | |
606 | | const Graphic& GraphicObject::GetGraphic() const |
607 | 442k | { |
608 | 442k | return maGraphic; |
609 | 442k | } |
610 | | |
611 | | void GraphicObject::SetGraphic( const Graphic& rGraphic) |
612 | 210k | { |
613 | 210k | maGraphic = rGraphic; |
614 | 210k | } |
615 | | |
616 | | Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMode& rDestMap, const GraphicAttr& rAttr ) const |
617 | 0 | { |
618 | | // #104550# Extracted from svx/source/svdraw/svdograf.cxx |
619 | 0 | Graphic aTransGraphic( GetGraphic() ); |
620 | 0 | const GraphicType eType = GetType(); |
621 | 0 | const Size aSrcSize( aTransGraphic.GetPrefSize() ); |
622 | | |
623 | | // #104115# Convert the crop margins to graphic object mapmode |
624 | 0 | const MapMode aMapGraph( aTransGraphic.GetPrefMapMode() ); |
625 | 0 | const MapMode aMap100( MapUnit::Map100thMM ); |
626 | |
|
627 | 0 | Size aCropLeftTop; |
628 | 0 | Size aCropRightBottom; |
629 | |
|
630 | 0 | if( GraphicType::GdiMetafile == eType ) |
631 | 0 | { |
632 | 0 | GDIMetaFile aMtf( aTransGraphic.GetGDIMetaFile() ); |
633 | |
|
634 | 0 | if (aMapGraph.GetMapUnit() == MapUnit::MapPixel) |
635 | 0 | { |
636 | | // crops are in 1/100th mm -> to aMapGraph -> to MapUnit::MapPixel |
637 | 0 | aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( |
638 | 0 | Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), |
639 | 0 | aMap100); |
640 | 0 | aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( |
641 | 0 | Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), |
642 | 0 | aMap100); |
643 | 0 | } |
644 | 0 | else |
645 | 0 | { |
646 | | // crops are in GraphicObject units -> to aMapGraph |
647 | 0 | aCropLeftTop = OutputDevice::LogicToLogic( |
648 | 0 | Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), |
649 | 0 | aMap100, |
650 | 0 | aMapGraph); |
651 | 0 | aCropRightBottom = OutputDevice::LogicToLogic( |
652 | 0 | Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), |
653 | 0 | aMap100, |
654 | 0 | aMapGraph); |
655 | 0 | } |
656 | | |
657 | | // #104115# If the metafile is cropped, give it a special |
658 | | // treatment: clip against the remaining area, scale up such |
659 | | // that this area later fills the desired size, and move the |
660 | | // origin to the upper left edge of that area. |
661 | 0 | if( rAttr.IsCropped() ) |
662 | 0 | { |
663 | 0 | const MapMode aMtfMapMode( aMtf.GetPrefMapMode() ); |
664 | |
|
665 | 0 | tools::Rectangle aClipRect( aMtfMapMode.GetOrigin().X() + aCropLeftTop.Width(), |
666 | 0 | aMtfMapMode.GetOrigin().Y() + aCropLeftTop.Height(), |
667 | 0 | aMtfMapMode.GetOrigin().X() + aSrcSize.Width() - aCropRightBottom.Width(), |
668 | 0 | aMtfMapMode.GetOrigin().Y() + aSrcSize.Height() - aCropRightBottom.Height() ); |
669 | | |
670 | | // #104115# To correctly crop rotated metafiles, clip by view rectangle |
671 | 0 | aMtf.AddAction( new MetaISectRectClipRegionAction( aClipRect ), 0 ); |
672 | | |
673 | | // #104115# To crop the metafile, scale larger than the output rectangle |
674 | 0 | aMtf.Scale( static_cast<double>(rDestSize.Width()) / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()), |
675 | 0 | static_cast<double>(rDestSize.Height()) / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) ); |
676 | | |
677 | | // #104115# Adapt the pref size by hand (scale changes it |
678 | | // proportionally, but we want it to be smaller than the |
679 | | // former size, to crop the excess out) |
680 | 0 | aMtf.SetPrefSize( Size( static_cast<tools::Long>(static_cast<double>(rDestSize.Width()) * (1.0 + (aCropLeftTop.Width() + aCropRightBottom.Width()) / aSrcSize.Width()) + .5), |
681 | 0 | static_cast<tools::Long>(static_cast<double>(rDestSize.Height()) * (1.0 + (aCropLeftTop.Height() + aCropRightBottom.Height()) / aSrcSize.Height()) + .5) ) ); |
682 | | |
683 | | // #104115# Adapt the origin of the new mapmode, such that it |
684 | | // is shifted to the place where the cropped output starts |
685 | 0 | Point aNewOrigin( static_cast<tools::Long>(static_cast<double>(aMtfMapMode.GetOrigin().X()) + rDestSize.Width() * aCropLeftTop.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()) + .5), |
686 | 0 | static_cast<tools::Long>(static_cast<double>(aMtfMapMode.GetOrigin().Y()) + rDestSize.Height() * aCropLeftTop.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) + .5) ); |
687 | 0 | MapMode aNewMap( rDestMap ); |
688 | 0 | aNewMap.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin, aMtfMapMode, rDestMap) ); |
689 | 0 | aMtf.SetPrefMapMode( aNewMap ); |
690 | 0 | } |
691 | 0 | else |
692 | 0 | { |
693 | 0 | aMtf.Scale( double(rDestSize.Width()) / aSrcSize.Width(), double(rDestSize.Height()) / aSrcSize.Height() ); |
694 | 0 | aMtf.SetPrefMapMode( rDestMap ); |
695 | 0 | } |
696 | |
|
697 | 0 | aTransGraphic = aMtf; |
698 | 0 | } |
699 | 0 | else if( GraphicType::Bitmap == eType ) |
700 | 0 | { |
701 | 0 | Bitmap aBitmap( aTransGraphic.GetBitmap() ); |
702 | 0 | tools::Rectangle aCropRect; |
703 | | |
704 | | // convert crops to pixel |
705 | 0 | if(rAttr.IsCropped()) |
706 | 0 | { |
707 | 0 | if (aMapGraph.GetMapUnit() == MapUnit::MapPixel) |
708 | 0 | { |
709 | | // crops are in 1/100th mm -> to MapUnit::MapPixel |
710 | 0 | aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( |
711 | 0 | Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), |
712 | 0 | aMap100); |
713 | 0 | aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( |
714 | 0 | Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), |
715 | 0 | aMap100); |
716 | 0 | } |
717 | 0 | else |
718 | 0 | { |
719 | | // crops are in GraphicObject units -> to MapUnit::MapPixel |
720 | 0 | aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( |
721 | 0 | Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), |
722 | 0 | aMapGraph); |
723 | 0 | aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( |
724 | 0 | Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), |
725 | 0 | aMapGraph); |
726 | 0 | } |
727 | | |
728 | | // convert from prefmapmode to pixel |
729 | 0 | Size aSrcSizePixel( |
730 | 0 | Application::GetDefaultDevice()->LogicToPixel( |
731 | 0 | aSrcSize, |
732 | 0 | aMapGraph)); |
733 | |
|
734 | 0 | if(rAttr.IsCropped() |
735 | 0 | && (aSrcSizePixel.Width() != aBitmap.GetSizePixel().Width() || aSrcSizePixel.Height() != aBitmap.GetSizePixel().Height()) |
736 | 0 | && aSrcSizePixel.Width()) |
737 | 0 | { |
738 | | // the size in pixels calculated from Graphic's internal MapMode (aTransGraphic.GetPrefMapMode()) |
739 | | // and its internal size (aTransGraphic.GetPrefSize()) is different from its real pixel size. |
740 | | // This can be interpreted as this values to be set wrong, but needs to be corrected since e.g. |
741 | | // existing cropping is calculated based on this logic values already. |
742 | | // aBitmapEx.Scale(aSrcSizePixel); |
743 | | |
744 | | // another possibility is to adapt the values created so far with a factor; this |
745 | | // will keep the original Bitmap untouched and thus quality will not change |
746 | | // caution: convert to double first, else pretty big errors may occur |
747 | 0 | const double fFactorX(static_cast<double>(aBitmap.GetSizePixel().Width()) / aSrcSizePixel.Width()); |
748 | 0 | const double fFactorY(static_cast<double>(aBitmap.GetSizePixel().Height()) / aSrcSizePixel.Height()); |
749 | |
|
750 | 0 | aCropLeftTop.setWidth( basegfx::fround<tools::Long>(aCropLeftTop.Width() * fFactorX) ); |
751 | 0 | aCropLeftTop.setHeight( basegfx::fround<tools::Long>(aCropLeftTop.Height() * fFactorY) ); |
752 | 0 | aCropRightBottom.setWidth( basegfx::fround<tools::Long>(aCropRightBottom.Width() * fFactorX) ); |
753 | 0 | aCropRightBottom.setHeight( basegfx::fround<tools::Long>(aCropRightBottom.Height() * fFactorY) ); |
754 | |
|
755 | 0 | aSrcSizePixel = aBitmap.GetSizePixel(); |
756 | 0 | } |
757 | | |
758 | | // setup crop rectangle in pixel |
759 | 0 | aCropRect = tools::Rectangle( aCropLeftTop.Width(), aCropLeftTop.Height(), |
760 | 0 | aSrcSizePixel.Width() - aCropRightBottom.Width(), |
761 | 0 | aSrcSizePixel.Height() - aCropRightBottom.Height() ); |
762 | 0 | } |
763 | | |
764 | | // #105641# Also crop animations |
765 | 0 | if( aTransGraphic.IsAnimated() ) |
766 | 0 | { |
767 | 0 | Animation aAnim( aTransGraphic.GetAnimation() ); |
768 | |
|
769 | 0 | for( size_t nFrame=0; nFrame<aAnim.Count(); ++nFrame ) |
770 | 0 | { |
771 | 0 | AnimationFrame aAnimationFrame( aAnim.Get( nFrame ) ); |
772 | |
|
773 | 0 | if( !aCropRect.Contains( tools::Rectangle(aAnimationFrame.maPositionPixel, aAnimationFrame.maSizePixel) ) ) |
774 | 0 | { |
775 | | // setup actual cropping (relative to frame position) |
776 | 0 | tools::Rectangle aCropRectRel( aCropRect ); |
777 | 0 | aCropRectRel.Move( -aAnimationFrame.maPositionPixel.X(), |
778 | 0 | -aAnimationFrame.maPositionPixel.Y() ); |
779 | | |
780 | | // cropping affects this frame, apply it then |
781 | | // do _not_ apply enlargement, this is done below |
782 | 0 | ImplTransformBitmap( aAnimationFrame.maBitmap, rAttr, Size(), Size(), |
783 | 0 | aCropRectRel, rDestSize, false ); |
784 | |
|
785 | 0 | aAnim.Replace( aAnimationFrame, nFrame ); |
786 | 0 | } |
787 | | // else: bitmap completely within crop area, |
788 | | // i.e. nothing is cropped away |
789 | 0 | } |
790 | | |
791 | | // now, apply enlargement (if any) through global animation size |
792 | 0 | if( aCropLeftTop.Width() < 0 || |
793 | 0 | aCropLeftTop.Height() < 0 || |
794 | 0 | aCropRightBottom.Width() < 0 || |
795 | 0 | aCropRightBottom.Height() < 0 ) |
796 | 0 | { |
797 | 0 | Size aNewSize( aAnim.GetDisplaySizePixel() ); |
798 | 0 | aNewSize.AdjustWidth(aCropRightBottom.Width() < 0 ? -aCropRightBottom.Width() : 0 ); |
799 | 0 | aNewSize.AdjustWidth(aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0 ); |
800 | 0 | aNewSize.AdjustHeight(aCropRightBottom.Height() < 0 ? -aCropRightBottom.Height() : 0 ); |
801 | 0 | aNewSize.AdjustHeight(aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 ); |
802 | 0 | aAnim.SetDisplaySizePixel( aNewSize ); |
803 | 0 | } |
804 | | |
805 | | // if topleft has changed, we must move all frames to the |
806 | | // right and bottom, resp. |
807 | 0 | if( aCropLeftTop.Width() < 0 || |
808 | 0 | aCropLeftTop.Height() < 0 ) |
809 | 0 | { |
810 | 0 | Point aPosOffset( aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0, |
811 | 0 | aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 ); |
812 | |
|
813 | 0 | for( size_t nFrame=0; nFrame<aAnim.Count(); ++nFrame ) |
814 | 0 | { |
815 | 0 | AnimationFrame aAnimationFrame( aAnim.Get( nFrame ) ); |
816 | |
|
817 | 0 | aAnimationFrame.maPositionPixel += aPosOffset; |
818 | |
|
819 | 0 | aAnim.Replace( aAnimationFrame, nFrame ); |
820 | 0 | } |
821 | 0 | } |
822 | |
|
823 | 0 | aTransGraphic = aAnim; |
824 | 0 | } |
825 | 0 | else |
826 | 0 | { |
827 | 0 | ImplTransformBitmap( aBitmap, rAttr, aCropLeftTop, aCropRightBottom, |
828 | 0 | aCropRect, rDestSize, true ); |
829 | |
|
830 | 0 | aTransGraphic = aBitmap; |
831 | 0 | } |
832 | |
|
833 | 0 | aTransGraphic.SetPrefSize( rDestSize ); |
834 | 0 | aTransGraphic.SetPrefMapMode( rDestMap ); |
835 | 0 | } |
836 | |
|
837 | 0 | GraphicObject aGrfObj( aTransGraphic ); |
838 | 0 | aTransGraphic = aGrfObj.GetTransformedGraphic( &rAttr ); |
839 | |
|
840 | 0 | return aTransGraphic; |
841 | 0 | } |
842 | | |
843 | | Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const |
844 | 0 | { |
845 | 0 | GetGraphic(); |
846 | |
|
847 | 0 | Graphic aGraphic; |
848 | 0 | GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() ); |
849 | |
|
850 | 0 | if (maGraphic.IsSupportedGraphic()) |
851 | 0 | { |
852 | 0 | if( aAttr.IsSpecialDrawMode() || aAttr.IsAdjusted() || aAttr.IsMirrored() || aAttr.IsRotated() || aAttr.IsTransparent() ) |
853 | 0 | { |
854 | 0 | if( GetType() == GraphicType::Bitmap ) |
855 | 0 | { |
856 | 0 | if( IsAnimated() ) |
857 | 0 | { |
858 | 0 | Animation aAnimation( maGraphic.GetAnimation() ); |
859 | 0 | lclImplAdjust( aAnimation, aAttr, GraphicAdjustmentFlags::ALL ); |
860 | 0 | aAnimation.SetLoopCount(maGraphic.GetAnimationLoopCount()); |
861 | 0 | aGraphic = aAnimation; |
862 | 0 | } |
863 | 0 | else |
864 | 0 | { |
865 | 0 | Bitmap aBmp( maGraphic.GetBitmap() ); |
866 | 0 | lclImplAdjust( aBmp, aAttr, GraphicAdjustmentFlags::ALL ); |
867 | 0 | aGraphic = aBmp; |
868 | 0 | } |
869 | 0 | } |
870 | 0 | else |
871 | 0 | { |
872 | 0 | GDIMetaFile aMtf( maGraphic.GetGDIMetaFile() ); |
873 | 0 | lclImplAdjust( aMtf, aAttr, GraphicAdjustmentFlags::ALL ); |
874 | 0 | aGraphic = aMtf; |
875 | 0 | } |
876 | 0 | } |
877 | 0 | else |
878 | 0 | { |
879 | 0 | if( ( GetType() == GraphicType::Bitmap ) && IsAnimated() ) |
880 | 0 | { |
881 | 0 | Animation aAnimation( maGraphic.GetAnimation() ); |
882 | 0 | aAnimation.SetLoopCount(maGraphic.GetAnimationLoopCount()); |
883 | 0 | aGraphic = aAnimation; |
884 | 0 | } |
885 | 0 | else |
886 | 0 | aGraphic = maGraphic; |
887 | 0 | } |
888 | 0 | } |
889 | |
|
890 | 0 | return aGraphic; |
891 | 0 | } |
892 | | |
893 | | bool GraphicObject::isGraphicObjectUniqueIdURL(std::u16string_view rURL) |
894 | 0 | { |
895 | 0 | return o3tl::starts_with(rURL, u"vnd.sun.star.GraphicObject:"); |
896 | 0 | } |
897 | | |
898 | | // calculate scalings between real image size and logic object size. This |
899 | | // is necessary since the crop values are relative to original bitmap size |
900 | | basegfx::B2DVector GraphicObject::calculateCropScaling( |
901 | | double fWidth, |
902 | | double fHeight, |
903 | | double fLeftCrop, |
904 | | double fTopCrop, |
905 | | double fRightCrop, |
906 | | double fBottomCrop) const |
907 | 0 | { |
908 | 0 | const MapMode aMapMode100thmm(MapUnit::Map100thMM); |
909 | 0 | Size aBitmapSize(GetPrefSize()); |
910 | 0 | double fFactorX(1.0); |
911 | 0 | double fFactorY(1.0); |
912 | |
|
913 | 0 | if(MapUnit::MapPixel == GetPrefMapMode().GetMapUnit()) |
914 | 0 | { |
915 | 0 | aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm); |
916 | 0 | } |
917 | 0 | else |
918 | 0 | { |
919 | 0 | aBitmapSize = OutputDevice::LogicToLogic(aBitmapSize, GetPrefMapMode(), aMapMode100thmm); |
920 | 0 | } |
921 | |
|
922 | 0 | const double fDivX(aBitmapSize.Width() - fLeftCrop - fRightCrop); |
923 | 0 | const double fDivY(aBitmapSize.Height() - fTopCrop - fBottomCrop); |
924 | |
|
925 | 0 | if(!basegfx::fTools::equalZero(fDivX)) |
926 | 0 | { |
927 | 0 | fFactorX = fabs(fWidth) / fDivX; |
928 | 0 | } |
929 | |
|
930 | 0 | if(!basegfx::fTools::equalZero(fDivY)) |
931 | 0 | { |
932 | 0 | fFactorY = fabs(fHeight) / fDivY; |
933 | 0 | } |
934 | |
|
935 | 0 | return basegfx::B2DVector(fFactorX,fFactorY); |
936 | 0 | } |
937 | | |
938 | | |
939 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |