Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / gdi / graph.cxx
blobec2de64a74fe10b9403d2efa3fea488acb63b040
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
34 namespace
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 );
48 pOutDev->Push();
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 );
55 else
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;
98 if ( !nStep )
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 );
108 if ( nTextHeight )
110 // The approximation does not respect imprecisions caused
111 // by word wraps
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;
118 sal_Int32 nLen = 0;
120 while( nStart < pText->getLength() && (*pText)[nStart] == ' ' )
121 nStart++;
122 while( nStart+nLen < pText->getLength() && (*pText)[nStart+nLen] != ' ' )
123 nLen++;
124 while( nStart < pText->getLength() && nLines-- )
126 sal_Int32 nNext = nLen;
129 while ( nStart+nNext < pText->getLength() && (*pText)[nStart+nNext] == ' ' )
130 nNext++;
131 while ( nStart+nNext < pText->getLength() && (*pText)[nStart+nNext] != ' ' )
132 nNext++;
133 nTextWidth = pOutDev->GetTextWidth( *pText, nStart, nNext );
134 if ( nTextWidth > aSize.Width() )
135 break;
136 nLen = nNext;
138 while ( nStart+nNext < pText->getLength() );
140 sal_Int32 n = nLen;
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);
148 nLen = nNext-nLen;
149 while( nStart < pText->getLength() && (*pText)[nStart] == ' ' )
151 nStart++;
152 nLen--;
155 break;
158 else
159 break;
163 // If the default graphic does not have content, we draw a red rectangle
164 if( !bFilled )
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() );
176 pOutDev->Pop();
179 } // end anonymous namespace
181 Graphic::Graphic()
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);
190 else
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);
244 if( pGraphic )
246 if (pGraphic->IsAnimated())
247 mxImpGraphic = vcl::graphic::Manager::get().copy(pGraphic->mxImpGraphic);
248 else
249 mxImpGraphic = pGraphic->mxImpGraphic;
251 else
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);
279 else
280 mxImpGraphic = rGraphic.mxImpGraphic;
283 return *this;
286 Graphic& Graphic::operator=(Graphic&& rGraphic) noexcept
288 mxImpGraphic = std::move(rGraphic.mxImpGraphic);
289 return *this;
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()
309 ImplTestRefCount();
310 mxImpGraphic->ImplClear();
313 GraphicType Graphic::GetType() const
315 return mxImpGraphic->ImplGetType();
318 void Graphic::SetDefaultType()
320 ImplTestRefCount();
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;
380 return xGraphic;
383 Size Graphic::GetPrefSize() const
385 return mxImpGraphic->ImplGetPrefSize();
388 void Graphic::SetPrefSize( const Size& rPrefSize )
390 ImplTestRefCount();
391 mxImpGraphic->ImplSetPrefSize( rPrefSize );
394 MapMode Graphic::GetPrefMapMode() const
396 return mxImpGraphic->ImplGetPrefMapMode();
399 void Graphic::SetPrefMapMode( const MapMode& rPrefMapMode )
401 ImplTestRefCount();
402 mxImpGraphic->ImplSetPrefMapMode( rPrefMapMode );
405 basegfx::B2DSize Graphic::GetPPI() const
407 double nGrfDPIx;
408 double nGrfDPIy;
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() );
418 else
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
431 Size aRet;
433 if( GraphicType::Bitmap == mxImpGraphic->ImplGetType() )
434 aRet = mxImpGraphic->ImplGetSizePixel();
435 else
436 aRet = ( pRefDevice ? pRefDevice : Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() );
438 return aRet;
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 );
456 else
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 )
471 ImplTestRefCount();
472 mxImpGraphic->ImplStartAnimation( pOutDev, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev );
475 void Graphic::StopAnimation( OutputDevice* pOutDev, long nExtraData )
477 ImplTestRefCount();
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 )
518 ImplTestRefCount();
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)
565 ImplTestRefCount();
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
592 if (mxImpGraphic)
594 return mxImpGraphic->getOriginURL();
596 return OUString();
599 void Graphic::setOriginURL(OUString const & rOriginURL)
601 if (mxImpGraphic)
603 mxImpGraphic->setOriginURL(rOriginURL);
607 OString Graphic::getUniqueID() const
609 OString aUniqueString;
610 if (mxImpGraphic)
611 aUniqueString = mxImpGraphic->getUniqueID();
612 return aUniqueString;
615 namespace {
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: */