1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/fract.hxx>
21 #include <vcl/outdev.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/graph.hxx>
24 #include <vcl/image.hxx>
25 #include <impgraph.hxx>
26 #include <com/sun/star/graphic/XGraphic.hpp>
27 #include <comphelper/servicehelper.hxx>
28 #include <cppuhelper/typeprovider.hxx>
29 #include <graphic/UnoGraphic.hxx>
30 #include <vcl/GraphicExternalLink.hxx>
32 using namespace ::com::sun::star
;
37 void ImplDrawDefault(OutputDevice
& rOutDev
, const OUString
* pText
,
38 vcl::Font
* pFont
, const BitmapEx
* pBitmapEx
,
39 const Point
& rDestPt
, const Size
& rDestSize
)
41 sal_uInt16 nPixel
= static_cast<sal_uInt16
>(rOutDev
.PixelToLogic( Size( 1, 1 ) ).Width());
42 sal_uInt16 nPixelWidth
= nPixel
;
43 Point
aPoint( rDestPt
.X() + nPixelWidth
, rDestPt
.Y() + nPixelWidth
);
44 Size
aSize( rDestSize
.Width() - ( nPixelWidth
<< 1 ), rDestSize
.Height() - ( nPixelWidth
<< 1 ) );
45 bool bFilled
= ( pBitmapEx
!= nullptr || pFont
!= nullptr );
46 tools::Rectangle
aBorderRect( aPoint
, aSize
);
50 rOutDev
.SetFillColor();
52 // On the printer a black rectangle and on the screen one with 3D effect
53 rOutDev
.DrawBorder(aBorderRect
);
55 aPoint
.AdjustX(nPixelWidth
+ 2*nPixel
);
56 aPoint
.AdjustY(nPixelWidth
+ 2*nPixel
);
57 aSize
.AdjustWidth( -(2*nPixelWidth
+ 4*nPixel
) );
58 aSize
.AdjustHeight( -(2*nPixelWidth
+ 4*nPixel
) );
60 if( !aSize
.IsEmpty() && pBitmapEx
&& !pBitmapEx
->IsEmpty() )
62 Size
aBitmapSize( rOutDev
.PixelToLogic( pBitmapEx
->GetSizePixel() ) );
64 if( aSize
.Height() > aBitmapSize
.Height() && aSize
.Width() > aBitmapSize
.Width() )
66 rOutDev
.DrawBitmapEx( aPoint
, *pBitmapEx
);
67 aPoint
.AdjustX(aBitmapSize
.Width() + 2*nPixel
);
68 aSize
.AdjustWidth( -(aBitmapSize
.Width() + 2*nPixel
) );
72 if ( !aSize
.IsEmpty() && pFont
&& pText
&& pText
->getLength() && rOutDev
.IsOutputEnabled() )
74 MapMode
aMapMode( MapUnit::MapPoint
);
75 Size aSz
= rOutDev
.LogicToLogic( Size( 0, 12 ), &aMapMode
, nullptr );
76 tools::Long nThreshold
= aSz
.Height() / 2;
77 tools::Long nStep
= nThreshold
/ 3;
80 nStep
= aSz
.Height() - nThreshold
;
82 for(;; aSz
.AdjustHeight( -nStep
) )
84 pFont
->SetFontSize( aSz
);
85 rOutDev
.SetFont( *pFont
);
87 tools::Long nTextHeight
= rOutDev
.GetTextHeight();
88 tools::Long nTextWidth
= rOutDev
.GetTextWidth( *pText
);
91 // The approximation does not respect imprecisions caused
93 tools::Long nLines
= aSize
.Height() / nTextHeight
;
94 tools::Long nWidth
= aSize
.Width() * nLines
; // Approximation!!!
96 if ( nTextWidth
<= nWidth
|| aSz
.Height() <= nThreshold
)
101 while( nStart
< pText
->getLength() && (*pText
)[nStart
] == ' ' )
103 while( nStart
+nLen
< pText
->getLength() && (*pText
)[nStart
+nLen
] != ' ' )
105 while( nStart
< pText
->getLength() && nLines
-- )
107 sal_Int32 nNext
= nLen
;
110 while ( nStart
+nNext
< pText
->getLength() && (*pText
)[nStart
+nNext
] == ' ' )
112 while ( nStart
+nNext
< pText
->getLength() && (*pText
)[nStart
+nNext
] != ' ' )
114 nTextWidth
= rOutDev
.GetTextWidth( *pText
, nStart
, nNext
);
115 if ( nTextWidth
> aSize
.Width() )
119 while ( nStart
+nNext
< pText
->getLength() );
122 nTextWidth
= rOutDev
.GetTextWidth( *pText
, nStart
, n
);
123 while( nTextWidth
> aSize
.Width() )
124 nTextWidth
= rOutDev
.GetTextWidth( *pText
, nStart
, --n
);
125 rOutDev
.DrawText( aPoint
, *pText
, nStart
, n
);
127 aPoint
.AdjustY(nTextHeight
);
128 nStart
= sal::static_int_cast
<sal_uInt16
>(nStart
+ nLen
);
130 while( nStart
< pText
->getLength() && (*pText
)[nStart
] == ' ' )
144 // If the default graphic does not have content, we draw a red rectangle
147 aBorderRect
.AdjustLeft( 1 );
148 aBorderRect
.AdjustTop( 1 );
149 aBorderRect
.AdjustRight( -1 );
150 aBorderRect
.AdjustBottom( -1 );
152 rOutDev
.SetLineColor( COL_LIGHTRED
);
153 rOutDev
.DrawLine( aBorderRect
.TopLeft(), aBorderRect
.BottomRight() );
154 rOutDev
.DrawLine( aBorderRect
.TopRight(), aBorderRect
.BottomLeft() );
160 } // end anonymous namespace
163 : mxImpGraphic(vcl::graphic::Manager::get().newInstance())
167 Graphic::Graphic(const Graphic
& rGraphic
)
169 if( rGraphic
.IsAnimated() )
170 mxImpGraphic
= vcl::graphic::Manager::get().copy(rGraphic
.mxImpGraphic
);
172 mxImpGraphic
= rGraphic
.mxImpGraphic
;
175 Graphic::Graphic(Graphic
&& rGraphic
) noexcept
176 : mxImpGraphic(std::move(rGraphic
.mxImpGraphic
))
180 Graphic::Graphic(std::shared_ptr
<GfxLink
> const & rGfxLink
, sal_Int32 nPageIndex
)
181 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rGfxLink
, nPageIndex
))
185 Graphic::Graphic(GraphicExternalLink
const & rGraphicExternalLink
)
186 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rGraphicExternalLink
))
190 Graphic::Graphic(const BitmapEx
& rBmpEx
)
191 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rBmpEx
))
195 // We use XGraphic for passing toolbar images across app UNO aps
196 // and we need to be able to see and preserve 'stock' images too.
197 Graphic::Graphic(const Image
& rImage
)
198 // FIXME: should really defer the BitmapEx load.
199 : mxImpGraphic(std::make_shared
<ImpGraphic
>(rImage
.GetBitmapEx()))
201 OUString aStock
= rImage
.GetStock();
202 if (aStock
.getLength())
203 mxImpGraphic
->setOriginURL("private:graphicrepository/" + aStock
);
206 Graphic::Graphic(const std::shared_ptr
<VectorGraphicData
>& rVectorGraphicDataPtr
)
207 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rVectorGraphicDataPtr
))
211 Graphic::Graphic(const Animation
& rAnimation
)
212 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rAnimation
))
216 Graphic::Graphic(const GDIMetaFile
& rMtf
)
217 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rMtf
))
221 Graphic::Graphic( const css::uno::Reference
< css::graphic::XGraphic
>& rxGraphic
)
223 const ::Graphic
* pGraphic
= comphelper::getUnoTunnelImplementation
<::Graphic
>(rxGraphic
);
227 if (pGraphic
->IsAnimated())
228 mxImpGraphic
= vcl::graphic::Manager::get().copy(pGraphic
->mxImpGraphic
);
230 mxImpGraphic
= pGraphic
->mxImpGraphic
;
233 mxImpGraphic
= vcl::graphic::Manager::get().newInstance();
236 void Graphic::ImplTestRefCount()
238 if (mxImpGraphic
.use_count() > 1)
240 mxImpGraphic
= vcl::graphic::Manager::get().copy(mxImpGraphic
);
244 bool Graphic::isAvailable() const
246 return mxImpGraphic
->isAvailable();
249 bool Graphic::makeAvailable()
251 return mxImpGraphic
->makeAvailable();
254 Graphic
& Graphic::operator=( const Graphic
& rGraphic
)
256 if( &rGraphic
!= this )
258 if( rGraphic
.IsAnimated() )
259 mxImpGraphic
= vcl::graphic::Manager::get().copy(rGraphic
.mxImpGraphic
);
261 mxImpGraphic
= rGraphic
.mxImpGraphic
;
267 Graphic
& Graphic::operator=(Graphic
&& rGraphic
) noexcept
269 mxImpGraphic
= std::move(rGraphic
.mxImpGraphic
);
273 bool Graphic::operator==( const Graphic
& rGraphic
) const
275 return (*mxImpGraphic
== *rGraphic
.mxImpGraphic
);
278 bool Graphic::operator!=( const Graphic
& rGraphic
) const
280 return (*mxImpGraphic
!= *rGraphic
.mxImpGraphic
);
283 bool Graphic::IsNone() const
285 return GraphicType::NONE
== mxImpGraphic
->getType();
288 void Graphic::Clear()
291 mxImpGraphic
->clear();
294 GraphicType
Graphic::GetType() const
296 return mxImpGraphic
->getType();
299 void Graphic::SetDefaultType()
302 mxImpGraphic
->setDefaultType();
305 bool Graphic::IsSupportedGraphic() const
307 return mxImpGraphic
->isSupportedGraphic();
310 bool Graphic::IsTransparent() const
312 return mxImpGraphic
->isTransparent();
315 bool Graphic::IsAlpha() const
317 return mxImpGraphic
->isAlpha();
320 bool Graphic::IsAnimated() const
322 return mxImpGraphic
->isAnimated();
325 bool Graphic::IsEPS() const
327 return mxImpGraphic
->isEPS();
330 BitmapEx
Graphic::GetBitmapEx(const GraphicConversionParameters
& rParameters
) const
332 return mxImpGraphic
->getBitmapEx(rParameters
);
335 Animation
Graphic::GetAnimation() const
337 return mxImpGraphic
->getAnimation();
340 const GDIMetaFile
& Graphic::GetGDIMetaFile() const
342 return mxImpGraphic
->getGDIMetaFile();
345 const BitmapEx
& Graphic::GetBitmapExRef() const
347 return mxImpGraphic
->getBitmapExRef();
350 uno::Reference
<graphic::XGraphic
> Graphic::GetXGraphic() const
352 uno::Reference
<graphic::XGraphic
> xGraphic
;
354 if (GetType() != GraphicType::NONE
)
356 rtl::Reference
<unographic::Graphic
> pUnoGraphic
= new unographic::Graphic
;
357 pUnoGraphic
->init(*this);
358 xGraphic
= pUnoGraphic
;
364 Size
Graphic::GetPrefSize() const
366 return mxImpGraphic
->getPrefSize();
369 void Graphic::SetPrefSize( const Size
& rPrefSize
)
372 mxImpGraphic
->setPrefSize( rPrefSize
);
375 MapMode
Graphic::GetPrefMapMode() const
377 return mxImpGraphic
->getPrefMapMode();
380 void Graphic::SetPrefMapMode( const MapMode
& rPrefMapMode
)
383 mxImpGraphic
->setPrefMapMode( rPrefMapMode
);
386 basegfx::B2DSize
Graphic::GetPPI() const
391 const MapMode
aGrfMap(GetPrefMapMode());
392 const Size
aGrfPixelSize(GetSizePixel());
393 const Size
aGrfPrefMapModeSize(GetPrefSize());
394 if (aGrfMap
.GetMapUnit() == MapUnit::MapInch
)
396 nGrfDPIx
= aGrfPixelSize
.Width() / ( static_cast<double>(aGrfMap
.GetScaleX()) * aGrfPrefMapModeSize
.Width() );
397 nGrfDPIy
= aGrfPixelSize
.Height() / ( static_cast<double>(aGrfMap
.GetScaleY()) * aGrfPrefMapModeSize
.Height() );
401 const Size aGrf1000thInchSize
= OutputDevice::LogicToLogic(
402 aGrfPrefMapModeSize
, aGrfMap
, MapMode(MapUnit::Map1000thInch
));
403 nGrfDPIx
= 1000.0 * aGrfPixelSize
.Width() / aGrf1000thInchSize
.Width();
404 nGrfDPIy
= 1000.0 * aGrfPixelSize
.Height() / aGrf1000thInchSize
.Height();
407 return basegfx::B2DSize(nGrfDPIx
, nGrfDPIy
);
410 Size
Graphic::GetSizePixel( const OutputDevice
* pRefDevice
) const
414 if( GraphicType::Bitmap
== mxImpGraphic
->getType() )
415 aRet
= mxImpGraphic
->getSizePixel();
417 aRet
= ( pRefDevice
? pRefDevice
: Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() );
422 sal_uLong
Graphic::GetSizeBytes() const
424 return mxImpGraphic
->getSizeBytes();
427 void Graphic::Draw(OutputDevice
& rOutDev
, const Point
& rDestPt
) const
429 mxImpGraphic
->draw(rOutDev
, rDestPt
);
432 void Graphic::Draw(OutputDevice
& rOutDev
, const Point
& rDestPt
,
433 const Size
& rDestSz
) const
435 if( GraphicType::Default
== mxImpGraphic
->getType() )
436 ImplDrawDefault(rOutDev
, nullptr, nullptr, nullptr, rDestPt
, rDestSz
);
438 mxImpGraphic
->draw(rOutDev
, rDestPt
, rDestSz
);
441 void Graphic::DrawEx(OutputDevice
& rOutDev
, const OUString
& rText
,
442 vcl::Font
& rFont
, const BitmapEx
& rBitmap
,
443 const Point
& rDestPt
, const Size
& rDestSz
)
445 ImplDrawDefault(rOutDev
, &rText
, &rFont
, &rBitmap
, rDestPt
, rDestSz
);
448 void Graphic::StartAnimation(OutputDevice
& rOutDev
, const Point
& rDestPt
,
449 const Size
& rDestSz
, tools::Long nExtraData
,
450 OutputDevice
* pFirstFrameOutDev
)
453 mxImpGraphic
->startAnimation(rOutDev
, rDestPt
, rDestSz
, nExtraData
, pFirstFrameOutDev
);
456 void Graphic::StopAnimation( const OutputDevice
* pOutDev
, tools::Long nExtraData
)
459 mxImpGraphic
->stopAnimation( pOutDev
, nExtraData
);
462 void Graphic::SetAnimationNotifyHdl( const Link
<Animation
*,void>& rLink
)
464 mxImpGraphic
->setAnimationNotifyHdl( rLink
);
467 Link
<Animation
*,void> Graphic::GetAnimationNotifyHdl() const
469 return mxImpGraphic
->getAnimationNotifyHdl();
472 sal_uInt32
Graphic::GetAnimationLoopCount() const
474 return mxImpGraphic
->getAnimationLoopCount();
477 std::shared_ptr
<GraphicReader
>& Graphic::GetReaderContext()
479 return mxImpGraphic
->getContext();
482 void Graphic::SetReaderContext( const std::shared_ptr
<GraphicReader
> &pReader
)
484 mxImpGraphic
->setContext( pReader
);
487 void Graphic::SetDummyContext( bool value
)
489 mxImpGraphic
->setDummyContext( value
);
492 bool Graphic::IsDummyContext() const
494 return mxImpGraphic
->isDummyContext();
497 void Graphic::SetGfxLink( const std::shared_ptr
<GfxLink
>& rGfxLink
)
500 mxImpGraphic
->setGfxLink(rGfxLink
);
503 const std::shared_ptr
<GfxLink
> & Graphic::GetSharedGfxLink() const
505 return mxImpGraphic
->getSharedGfxLink();
508 GfxLink
Graphic::GetGfxLink() const
510 return mxImpGraphic
->getGfxLink();
513 bool Graphic::IsGfxLink() const
515 return mxImpGraphic
->isGfxLink();
518 BitmapChecksum
Graphic::GetChecksum() const
520 return mxImpGraphic
->getChecksum();
523 const std::shared_ptr
<VectorGraphicData
>& Graphic::getVectorGraphicData() const
525 return mxImpGraphic
->getVectorGraphicData();
528 sal_Int32
Graphic::getPageNumber() const
530 return mxImpGraphic
->getPageNumber();
533 OUString
Graphic::getOriginURL() const
537 return mxImpGraphic
->getOriginURL();
542 void Graphic::setOriginURL(OUString
const & rOriginURL
)
546 mxImpGraphic
->setOriginURL(rOriginURL
);
550 OString
Graphic::getUniqueID() const
552 OString aUniqueString
;
554 aUniqueString
= mxImpGraphic
->getUniqueID();
555 return aUniqueString
;
560 struct Id
: public rtl::Static
<cppu::OImplementationId
, Id
> {};
564 css::uno::Sequence
<sal_Int8
> Graphic::getUnoTunnelId() {
565 return Id::get().getImplementationId();
568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */