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
* pOutDev
, 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
>(pOutDev
->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 pOutDev
->SetFillColor();
52 // On the printer a black rectangle and on the screen one with 3D effect
53 if ( pOutDev
->GetOutDevType() == OUTDEV_PRINTER
)
54 pOutDev
->SetLineColor( COL_BLACK
);
57 aBorderRect
.AdjustLeft(nPixel
);
58 aBorderRect
.AdjustTop(nPixel
);
60 pOutDev
->SetLineColor( COL_LIGHTGRAY
);
61 pOutDev
->DrawRect( aBorderRect
);
63 aBorderRect
.AdjustLeft( -nPixel
);
64 aBorderRect
.AdjustTop( -nPixel
);
65 aBorderRect
.AdjustRight( -nPixel
);
66 aBorderRect
.AdjustBottom( -nPixel
);
67 pOutDev
->SetLineColor( COL_GRAY
);
70 pOutDev
->DrawRect( aBorderRect
);
72 aPoint
.AdjustX(nPixelWidth
+ 2*nPixel
);
73 aPoint
.AdjustY(nPixelWidth
+ 2*nPixel
);
74 aSize
.AdjustWidth( -(2*nPixelWidth
+ 4*nPixel
) );
75 aSize
.AdjustHeight( -(2*nPixelWidth
+ 4*nPixel
) );
77 if( aSize
.Width() > 0 && aSize
.Height() > 0
78 && ( pBitmapEx
&& !!*pBitmapEx
) )
80 Size
aBitmapSize( pOutDev
->PixelToLogic( pBitmapEx
->GetSizePixel() ) );
82 if( aSize
.Height() > aBitmapSize
.Height() && aSize
.Width() > aBitmapSize
.Width() )
84 pOutDev
->DrawBitmapEx( aPoint
, *pBitmapEx
);
85 aPoint
.AdjustX(aBitmapSize
.Width() + 2*nPixel
);
86 aSize
.AdjustWidth( -(aBitmapSize
.Width() + 2*nPixel
) );
90 if ( aSize
.Width() > 0 && aSize
.Height() > 0 && pFont
&& pText
&& pText
->getLength()
91 && pOutDev
->IsOutputEnabled() )
93 MapMode
aMapMode( MapUnit::MapPoint
);
94 Size aSz
= pOutDev
->LogicToLogic( Size( 0, 12 ), &aMapMode
, nullptr );
95 long nThreshold
= aSz
.Height() / 2;
96 long nStep
= nThreshold
/ 3;
99 nStep
= aSz
.Height() - nThreshold
;
101 for(;; aSz
.AdjustHeight( -nStep
) )
103 pFont
->SetFontSize( aSz
);
104 pOutDev
->SetFont( *pFont
);
106 long nTextHeight
= pOutDev
->GetTextHeight();
107 long nTextWidth
= pOutDev
->GetTextWidth( *pText
);
110 // The approximation does not respect imprecisions caused
112 long nLines
= aSize
.Height() / nTextHeight
;
113 long nWidth
= aSize
.Width() * nLines
; // Approximation!!!
115 if ( nTextWidth
<= nWidth
|| aSz
.Height() <= nThreshold
)
117 sal_Int32 nStart
= 0;
120 while( nStart
< pText
->getLength() && (*pText
)[nStart
] == ' ' )
122 while( nStart
+nLen
< pText
->getLength() && (*pText
)[nStart
+nLen
] != ' ' )
124 while( nStart
< pText
->getLength() && nLines
-- )
126 sal_Int32 nNext
= nLen
;
129 while ( nStart
+nNext
< pText
->getLength() && (*pText
)[nStart
+nNext
] == ' ' )
131 while ( nStart
+nNext
< pText
->getLength() && (*pText
)[nStart
+nNext
] != ' ' )
133 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, nNext
);
134 if ( nTextWidth
> aSize
.Width() )
138 while ( nStart
+nNext
< pText
->getLength() );
141 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, n
);
142 while( nTextWidth
> aSize
.Width() )
143 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, --n
);
144 pOutDev
->DrawText( aPoint
, *pText
, nStart
, n
);
146 aPoint
.AdjustY(nTextHeight
);
147 nStart
= sal::static_int_cast
<sal_uInt16
>(nStart
+ nLen
);
149 while( nStart
< pText
->getLength() && (*pText
)[nStart
] == ' ' )
163 // If the default graphic does not have content, we draw a red rectangle
166 aBorderRect
.AdjustLeft( 1 );
167 aBorderRect
.AdjustTop( 1 );
168 aBorderRect
.AdjustRight( -1 );
169 aBorderRect
.AdjustBottom( -1 );
171 pOutDev
->SetLineColor( COL_LIGHTRED
);
172 pOutDev
->DrawLine( aBorderRect
.TopLeft(), aBorderRect
.BottomRight() );
173 pOutDev
->DrawLine( aBorderRect
.TopRight(), aBorderRect
.BottomLeft() );
179 } // end anonymous namespace
182 : mxImpGraphic(vcl::graphic::Manager::get().newInstance())
186 Graphic::Graphic(const Graphic
& rGraphic
)
188 if( rGraphic
.IsAnimated() )
189 mxImpGraphic
= vcl::graphic::Manager::get().copy(rGraphic
.mxImpGraphic
);
191 mxImpGraphic
= rGraphic
.mxImpGraphic
;
194 Graphic::Graphic(Graphic
&& rGraphic
) noexcept
195 : mxImpGraphic(std::move(rGraphic
.mxImpGraphic
))
199 Graphic::Graphic(GraphicExternalLink
const & rGraphicExternalLink
)
200 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rGraphicExternalLink
))
204 Graphic::Graphic(const Bitmap
& rBmp
)
205 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rBmp
))
209 Graphic::Graphic(const BitmapEx
& rBmpEx
)
210 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rBmpEx
))
214 // We use XGraphic for passing toolbar images across app UNO aps
215 // and we need to be able to see and preserve 'stock' images too.
216 Graphic::Graphic(const Image
& rImage
)
217 // FIXME: should really defer the BitmapEx load.
218 : mxImpGraphic(new ImpGraphic(rImage
.GetBitmapEx()))
220 OUString aStock
= rImage
.GetStock();
221 if (aStock
.getLength())
222 mxImpGraphic
->setOriginURL("private:graphicrepository/" + aStock
);
225 Graphic::Graphic(const VectorGraphicDataPtr
& rVectorGraphicDataPtr
)
226 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rVectorGraphicDataPtr
))
230 Graphic::Graphic(const Animation
& rAnimation
)
231 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rAnimation
))
235 Graphic::Graphic(const GDIMetaFile
& rMtf
)
236 : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rMtf
))
240 Graphic::Graphic( const css::uno::Reference
< css::graphic::XGraphic
>& rxGraphic
)
242 const ::Graphic
* pGraphic
= comphelper::getUnoTunnelImplementation
<::Graphic
>(rxGraphic
);
246 if (pGraphic
->IsAnimated())
247 mxImpGraphic
= vcl::graphic::Manager::get().copy(pGraphic
->mxImpGraphic
);
249 mxImpGraphic
= pGraphic
->mxImpGraphic
;
252 mxImpGraphic
= vcl::graphic::Manager::get().newInstance();
255 void Graphic::ImplTestRefCount()
257 if (mxImpGraphic
.use_count() > 1)
259 mxImpGraphic
= vcl::graphic::Manager::get().copy(mxImpGraphic
);
263 bool Graphic::isAvailable() const
265 return mxImpGraphic
->isAvailable();
268 bool Graphic::makeAvailable()
270 return mxImpGraphic
->makeAvailable();
273 Graphic
& Graphic::operator=( const Graphic
& rGraphic
)
275 if( &rGraphic
!= this )
277 if( rGraphic
.IsAnimated() )
278 mxImpGraphic
= vcl::graphic::Manager::get().copy(rGraphic
.mxImpGraphic
);
280 mxImpGraphic
= rGraphic
.mxImpGraphic
;
286 Graphic
& Graphic::operator=(Graphic
&& rGraphic
) noexcept
288 mxImpGraphic
= std::move(rGraphic
.mxImpGraphic
);
292 bool Graphic::operator==( const Graphic
& rGraphic
) const
294 return (*mxImpGraphic
== *rGraphic
.mxImpGraphic
);
297 bool Graphic::operator!=( const Graphic
& rGraphic
) const
299 return (*mxImpGraphic
!= *rGraphic
.mxImpGraphic
);
302 bool Graphic::IsNone() const
304 return GraphicType::NONE
== mxImpGraphic
->ImplGetType();
307 void Graphic::Clear()
310 mxImpGraphic
->ImplClear();
313 GraphicType
Graphic::GetType() const
315 return mxImpGraphic
->ImplGetType();
318 void Graphic::SetDefaultType()
321 mxImpGraphic
->ImplSetDefaultType();
324 bool Graphic::IsSupportedGraphic() const
326 return mxImpGraphic
->ImplIsSupportedGraphic();
329 bool Graphic::IsTransparent() const
331 return mxImpGraphic
->ImplIsTransparent();
334 bool Graphic::IsAlpha() const
336 return mxImpGraphic
->ImplIsAlpha();
339 bool Graphic::IsAnimated() const
341 return mxImpGraphic
->ImplIsAnimated();
344 bool Graphic::IsEPS() const
346 return mxImpGraphic
->ImplIsEPS();
349 BitmapEx
Graphic::GetBitmapEx(const GraphicConversionParameters
& rParameters
) const
351 return mxImpGraphic
->ImplGetBitmapEx(rParameters
);
354 Animation
Graphic::GetAnimation() const
356 return mxImpGraphic
->ImplGetAnimation();
359 const GDIMetaFile
& Graphic::GetGDIMetaFile() const
361 return mxImpGraphic
->ImplGetGDIMetaFile();
364 const BitmapEx
& Graphic::GetBitmapExRef() const
366 return mxImpGraphic
->ImplGetBitmapExRef();
369 uno::Reference
<graphic::XGraphic
> Graphic::GetXGraphic() const
371 uno::Reference
<graphic::XGraphic
> xGraphic
;
373 if (GetType() != GraphicType::NONE
)
375 unographic::Graphic
* pUnoGraphic
= new unographic::Graphic
;
376 pUnoGraphic
->init(*this);
377 xGraphic
= pUnoGraphic
;
383 Size
Graphic::GetPrefSize() const
385 return mxImpGraphic
->ImplGetPrefSize();
388 void Graphic::SetPrefSize( const Size
& rPrefSize
)
391 mxImpGraphic
->ImplSetPrefSize( rPrefSize
);
394 MapMode
Graphic::GetPrefMapMode() const
396 return mxImpGraphic
->ImplGetPrefMapMode();
399 void Graphic::SetPrefMapMode( const MapMode
& rPrefMapMode
)
402 mxImpGraphic
->ImplSetPrefMapMode( rPrefMapMode
);
405 basegfx::B2DSize
Graphic::GetPPI() const
410 const MapMode
aGrfMap(GetPrefMapMode());
411 const Size
aGrfPixelSize(GetSizePixel());
412 const Size
aGrfPrefMapModeSize(GetPrefSize());
413 if (aGrfMap
.GetMapUnit() == MapUnit::MapInch
)
415 nGrfDPIx
= aGrfPixelSize
.Width() / ( static_cast<double>(aGrfMap
.GetScaleX()) * aGrfPrefMapModeSize
.Width() );
416 nGrfDPIy
= aGrfPixelSize
.Height() / ( static_cast<double>(aGrfMap
.GetScaleY()) * aGrfPrefMapModeSize
.Height() );
420 const Size aGrf1000thInchSize
= OutputDevice::LogicToLogic(
421 aGrfPrefMapModeSize
, aGrfMap
, MapMode(MapUnit::Map1000thInch
));
422 nGrfDPIx
= 1000.0 * aGrfPixelSize
.Width() / aGrf1000thInchSize
.Width();
423 nGrfDPIy
= 1000.0 * aGrfPixelSize
.Height() / aGrf1000thInchSize
.Height();
426 return basegfx::B2DSize(nGrfDPIx
, nGrfDPIy
);
429 Size
Graphic::GetSizePixel( const OutputDevice
* pRefDevice
) const
433 if( GraphicType::Bitmap
== mxImpGraphic
->ImplGetType() )
434 aRet
= mxImpGraphic
->ImplGetSizePixel();
436 aRet
= ( pRefDevice
? pRefDevice
: Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() );
441 sal_uLong
Graphic::GetSizeBytes() const
443 return mxImpGraphic
->ImplGetSizeBytes();
446 void Graphic::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
448 mxImpGraphic
->ImplDraw( pOutDev
, rDestPt
);
451 void Graphic::Draw( OutputDevice
* pOutDev
,
452 const Point
& rDestPt
, const Size
& rDestSz
) const
454 if( GraphicType::Default
== mxImpGraphic
->ImplGetType() )
455 ImplDrawDefault( pOutDev
, nullptr, nullptr, nullptr, rDestPt
, rDestSz
);
457 mxImpGraphic
->ImplDraw( pOutDev
, rDestPt
, rDestSz
);
460 void Graphic::DrawEx( OutputDevice
* pOutDev
, const OUString
& rText
,
461 vcl::Font
& rFont
, const BitmapEx
& rBitmap
,
462 const Point
& rDestPt
, const Size
& rDestSz
)
464 ImplDrawDefault( pOutDev
, &rText
, &rFont
, &rBitmap
, rDestPt
, rDestSz
);
467 void Graphic::StartAnimation( OutputDevice
* pOutDev
, const Point
& rDestPt
,
468 const Size
& rDestSz
, long nExtraData
,
469 OutputDevice
* pFirstFrameOutDev
)
472 mxImpGraphic
->ImplStartAnimation( pOutDev
, rDestPt
, rDestSz
, nExtraData
, pFirstFrameOutDev
);
475 void Graphic::StopAnimation( OutputDevice
* pOutDev
, long nExtraData
)
478 mxImpGraphic
->ImplStopAnimation( pOutDev
, nExtraData
);
481 void Graphic::SetAnimationNotifyHdl( const Link
<Animation
*,void>& rLink
)
483 mxImpGraphic
->ImplSetAnimationNotifyHdl( rLink
);
486 Link
<Animation
*,void> Graphic::GetAnimationNotifyHdl() const
488 return mxImpGraphic
->ImplGetAnimationNotifyHdl();
491 sal_uInt32
Graphic::GetAnimationLoopCount() const
493 return mxImpGraphic
->ImplGetAnimationLoopCount();
496 std::shared_ptr
<GraphicReader
>& Graphic::GetContext()
498 return mxImpGraphic
->ImplGetContext();
501 void Graphic::SetContext( const std::shared_ptr
<GraphicReader
> &pReader
)
503 mxImpGraphic
->ImplSetContext( pReader
);
506 void Graphic::SetDummyContext( bool value
)
508 mxImpGraphic
->ImplSetDummyContext( value
);
511 bool Graphic::IsDummyContext() const
513 return mxImpGraphic
->ImplIsDummyContext();
516 void Graphic::SetGfxLink( const std::shared_ptr
<GfxLink
>& rGfxLink
)
519 mxImpGraphic
->ImplSetLink( rGfxLink
);
522 std::shared_ptr
<GfxLink
> Graphic::GetSharedGfxLink() const
524 return mxImpGraphic
->ImplGetSharedGfxLink();
527 GfxLink
Graphic::GetGfxLink() const
529 return mxImpGraphic
->ImplGetLink();
532 bool Graphic::IsGfxLink() const
534 return mxImpGraphic
->ImplIsLink();
537 BitmapChecksum
Graphic::GetChecksum() const
539 return mxImpGraphic
->ImplGetChecksum();
542 bool Graphic::ExportNative( SvStream
& rOStream
) const
544 return mxImpGraphic
->ImplExportNative( rOStream
);
547 void ReadGraphic(SvStream
& rIStream
, Graphic
& rGraphic
)
549 rGraphic
.ImplTestRefCount();
550 ReadImpGraphic(rIStream
, *rGraphic
.mxImpGraphic
);
553 void WriteGraphic( SvStream
& rOStream
, const Graphic
& rGraphic
)
555 WriteImpGraphic(rOStream
, *rGraphic
.mxImpGraphic
);
558 const VectorGraphicDataPtr
& Graphic::getVectorGraphicData() const
560 return mxImpGraphic
->getVectorGraphicData();
563 void Graphic::setPdfData(const std::shared_ptr
<std::vector
<sal_Int8
>>& rPdfData
)
566 mxImpGraphic
->setPdfData(rPdfData
);
569 const std::shared_ptr
<std::vector
<sal_Int8
>> & Graphic::getPdfData() const
571 return mxImpGraphic
->getPdfData();
574 bool Graphic::hasPdfData() const
576 std::shared_ptr
<std::vector
<sal_Int8
>> pPdfData(getPdfData());
577 return pPdfData
&& !pPdfData
->empty();
580 void Graphic::setPageNumber(sal_Int32 nPageNumber
)
582 mxImpGraphic
->mnPageNumber
= nPageNumber
;
585 sal_Int32
Graphic::getPageNumber() const
587 return mxImpGraphic
->mnPageNumber
;
590 OUString
Graphic::getOriginURL() const
594 return mxImpGraphic
->getOriginURL();
599 void Graphic::setOriginURL(OUString
const & rOriginURL
)
603 mxImpGraphic
->setOriginURL(rOriginURL
);
607 OString
Graphic::getUniqueID() const
609 OString aUniqueString
;
611 aUniqueString
= mxImpGraphic
->getUniqueID();
612 return aUniqueString
;
617 struct Id
: public rtl::Static
<cppu::OImplementationId
, Id
> {};
621 css::uno::Sequence
<sal_Int8
> Graphic::getUnoTunnelId() {
622 return Id::get().getImplementationId();
625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */