summaryrefslogtreecommitdiffstats
path: root/vcl/source/treelist/imap.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /vcl/source/treelist/imap.cxx
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/treelist/imap.cxx')
-rw-r--r--vcl/source/treelist/imap.cxx994
1 files changed, 994 insertions, 0 deletions
diff --git a/vcl/source/treelist/imap.cxx b/vcl/source/treelist/imap.cxx
new file mode 100644
index 000000000..3c08c220d
--- /dev/null
+++ b/vcl/source/treelist/imap.cxx
@@ -0,0 +1,994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <tools/urlobj.hxx>
+#include <tools/fract.hxx>
+#include <tools/GenericTypeSerializer.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/mapmod.hxx>
+#include <o3tl/numeric.hxx>
+#include <svl/urihelper.hxx>
+#include <vcl/imap.hxx>
+#include <vcl/imapobj.hxx>
+#include <vcl/imapcirc.hxx>
+#include <vcl/imaprect.hxx>
+#include <vcl/imappoly.hxx>
+
+#include <string.h>
+#include <math.h>
+#include <memory>
+#include <sal/log.hxx>
+
+
+#define SCALEPOINT(aPT,aFracX,aFracY) (aPT).setX(long((aPT).X()*aFracX)); \
+ (aPT).setY(long((aPT).Y()*aFracY));
+
+
+/******************************************************************************/
+
+
+IMapObject::IMapObject()
+ : bActive( false )
+ , nReadVersion( 0 )
+{
+}
+
+IMapObject::IMapObject( const OUString& rURL, const OUString& rAltText, const OUString& rDesc,
+ const OUString& rTarget, const OUString& rName, bool bURLActive )
+: aURL( rURL )
+, aAltText( rAltText )
+, aDesc( rDesc )
+, aTarget( rTarget )
+, aName( rName )
+, bActive( bURLActive )
+, nReadVersion( 0 )
+{
+}
+
+
+void IMapObject::Write( SvStream& rOStm ) const
+{
+ const rtl_TextEncoding eEncoding = osl_getThreadTextEncoding();
+
+ rOStm.WriteUInt16( GetType() );
+ rOStm.WriteUInt16( IMAP_OBJ_VERSION );
+ rOStm.WriteUInt16( eEncoding );
+
+ const OString aRelURL = OUStringToOString(
+ URIHelper::simpleNormalizedMakeRelative("", aURL), eEncoding);
+ write_uInt16_lenPrefixed_uInt8s_FromOString(rOStm, aRelURL);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aAltText, eEncoding);
+ rOStm.WriteBool( bActive );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aTarget, eEncoding);
+
+ IMapCompat aCompat( rOStm, StreamMode::WRITE );
+
+ WriteIMapObject( rOStm );
+ aEventList.Write( rOStm ); // V4
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aName, eEncoding); // V5
+}
+
+
+/******************************************************************************
+|*
+|* Binary import
+|*
+\******************************************************************************/
+
+void IMapObject::Read( SvStream& rIStm )
+{
+ rtl_TextEncoding nTextEncoding;
+
+ // read on type and version
+ rIStm.SeekRel( 2 );
+ rIStm.ReadUInt16( nReadVersion );
+ rIStm.ReadUInt16( nTextEncoding );
+ aURL = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIStm, nTextEncoding);
+ aAltText = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIStm, nTextEncoding);
+ rIStm.ReadCharAsBool( bActive );
+ aTarget = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIStm, nTextEncoding);
+
+ // make URL absolute
+ aURL = URIHelper::SmartRel2Abs( INetURLObject(""), aURL, URIHelper::GetMaybeFileHdl(), true, false, INetURLObject::EncodeMechanism::WasEncoded, INetURLObject::DecodeMechanism::Unambiguous );
+ IMapCompat aCompat( rIStm, StreamMode::READ );
+
+ ReadIMapObject( rIStm );
+
+ // from version 4 onwards we read an eventlist
+ if ( nReadVersion >= 0x0004 )
+ {
+ aEventList.Read(rIStm);
+
+ // from version 5 onwards an objectname could be available
+ if ( nReadVersion >= 0x0005 )
+ aName = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIStm, nTextEncoding);
+ }
+}
+
+bool IMapObject::IsEqual( const IMapObject& rEqObj )
+{
+ return ( ( aURL == rEqObj.aURL ) &&
+ ( aAltText == rEqObj.aAltText ) &&
+ ( aDesc == rEqObj.aDesc ) &&
+ ( aTarget == rEqObj.aTarget ) &&
+ ( aName == rEqObj.aName ) &&
+ ( bActive == rEqObj.bActive ) );
+}
+
+IMapRectangleObject::IMapRectangleObject( const tools::Rectangle& rRect,
+ const OUString& rURL,
+ const OUString& rAltText,
+ const OUString& rDesc,
+ const OUString& rTarget,
+ const OUString& rName,
+ bool bURLActive,
+ bool bPixelCoords ) :
+ IMapObject ( rURL, rAltText, rDesc, rTarget, rName, bURLActive )
+{
+ ImpConstruct( rRect, bPixelCoords );
+}
+
+void IMapRectangleObject::ImpConstruct( const tools::Rectangle& rRect, bool bPixel )
+{
+ if ( bPixel )
+ aRect = Application::GetDefaultDevice()->PixelToLogic( rRect, MapMode( MapUnit::Map100thMM ) );
+ else
+ aRect = rRect;
+}
+
+
+/******************************************************************************
+|*
+|* Binary export
+|*
+\******************************************************************************/
+
+void IMapRectangleObject::WriteIMapObject( SvStream& rOStm ) const
+{
+ tools::GenericTypeSerializer aSerializer(rOStm);
+ aSerializer.writeRectangle(aRect);
+}
+
+
+/******************************************************************************
+|*
+|* Binary import
+|*
+\******************************************************************************/
+
+void IMapRectangleObject::ReadIMapObject( SvStream& rIStm )
+{
+ tools::GenericTypeSerializer aSerializer(rIStm);
+ aSerializer.readRectangle(aRect);
+}
+
+
+/******************************************************************************
+|*
+|* return type
+|*
+\******************************************************************************/
+
+sal_uInt16 IMapRectangleObject::GetType() const
+{
+ return IMAP_OBJ_RECTANGLE;
+}
+
+
+/******************************************************************************
+|*
+|* Hit test
+|*
+\******************************************************************************/
+
+bool IMapRectangleObject::IsHit( const Point& rPoint ) const
+{
+ return aRect.IsInside( rPoint );
+}
+
+tools::Rectangle IMapRectangleObject::GetRectangle( bool bPixelCoords ) const
+{
+ tools::Rectangle aNewRect;
+
+ if ( bPixelCoords )
+ aNewRect = Application::GetDefaultDevice()->LogicToPixel( aRect, MapMode( MapUnit::Map100thMM ) );
+ else
+ aNewRect = aRect;
+
+ return aNewRect;
+}
+
+void IMapRectangleObject::Scale( const Fraction& rFracX, const Fraction& rFracY )
+{
+ Point aTL( aRect.TopLeft() );
+ Point aBR( aRect.BottomRight() );
+
+ if ( rFracX.GetDenominator() && rFracY.GetDenominator() )
+ {
+ SCALEPOINT( aTL, rFracX, rFracY );
+ SCALEPOINT( aBR, rFracX, rFracY );
+ }
+
+ aRect = tools::Rectangle( aTL, aBR );
+}
+
+bool IMapRectangleObject::IsEqual( const IMapRectangleObject& rEqObj )
+{
+ return ( IMapObject::IsEqual( rEqObj ) && ( aRect == rEqObj.aRect ) );
+}
+
+IMapCircleObject::IMapCircleObject( const Point& rCenter, sal_uLong nCircleRadius,
+ const OUString& rURL,
+ const OUString& rAltText,
+ const OUString& rDesc,
+ const OUString& rTarget,
+ const OUString& rName,
+ bool bURLActive,
+ bool bPixelCoords ) :
+ IMapObject ( rURL, rAltText, rDesc, rTarget, rName, bURLActive )
+{
+ ImpConstruct( rCenter, nCircleRadius, bPixelCoords );
+}
+
+void IMapCircleObject::ImpConstruct( const Point& rCenter, sal_uLong nRad, bool bPixel )
+{
+ if ( bPixel )
+ {
+ MapMode aMap100( MapUnit::Map100thMM );
+
+ aCenter = Application::GetDefaultDevice()->PixelToLogic( rCenter, aMap100 );
+ nRadius = Application::GetDefaultDevice()->PixelToLogic( Size( nRad, 0 ), aMap100 ).Width();
+ }
+ else
+ {
+ aCenter = rCenter;
+ nRadius = nRad;
+ }
+}
+
+
+/******************************************************************************
+|*
+|* Binary export
+|*
+\******************************************************************************/
+
+void IMapCircleObject::WriteIMapObject( SvStream& rOStm ) const
+{
+ sal_uInt32 nTmp = nRadius;
+ tools::GenericTypeSerializer aSerializer(rOStm);
+ aSerializer.writePoint(aCenter);
+ rOStm.WriteUInt32( nTmp );
+}
+
+
+/******************************************************************************
+|*
+|* Binary import
+|*
+\******************************************************************************/
+
+void IMapCircleObject::ReadIMapObject( SvStream& rIStm )
+{
+ sal_uInt32 nTmp;
+
+ tools::GenericTypeSerializer aSerializer(rIStm);
+ aSerializer.readPoint(aCenter);
+ rIStm.ReadUInt32( nTmp );
+
+ nRadius = nTmp;
+}
+
+
+/******************************************************************************
+|*
+|* return type
+|*
+\******************************************************************************/
+
+sal_uInt16 IMapCircleObject::GetType() const
+{
+ return IMAP_OBJ_CIRCLE;
+}
+
+
+/******************************************************************************
+|*
+|* Hit-Test
+|*
+\******************************************************************************/
+
+bool IMapCircleObject::IsHit( const Point& rPoint ) const
+{
+ const Point aPoint( aCenter - rPoint );
+ bool bRet = false;
+
+ if ( static_cast<sal_Int32>(sqrt( static_cast<double>(aPoint.X()) * aPoint.X() +
+ aPoint.Y() * aPoint.Y() )) <= nRadius )
+ {
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+Point IMapCircleObject::GetCenter( bool bPixelCoords ) const
+{
+ Point aNewPoint;
+
+ if ( bPixelCoords )
+ aNewPoint = Application::GetDefaultDevice()->LogicToPixel( aCenter, MapMode( MapUnit::Map100thMM ) );
+ else
+ aNewPoint = aCenter;
+
+ return aNewPoint;
+}
+
+sal_uLong IMapCircleObject::GetRadius( bool bPixelCoords ) const
+{
+ sal_uLong nNewRadius;
+
+ if ( bPixelCoords )
+ nNewRadius = Application::GetDefaultDevice()->LogicToPixel( Size( nRadius, 0 ), MapMode( MapUnit::Map100thMM ) ).Width();
+ else
+ nNewRadius = nRadius;
+
+ return nNewRadius;
+}
+
+void IMapCircleObject::Scale( const Fraction& rFracX, const Fraction& rFracY )
+{
+ Fraction aAverage( rFracX );
+
+ aAverage += rFracY;
+ aAverage *= Fraction( 1, 2 );
+
+ if ( rFracX.GetDenominator() && rFracY.GetDenominator() )
+ {
+ SCALEPOINT( aCenter, rFracX, rFracY );
+ }
+
+ if (!aAverage.GetDenominator())
+ throw o3tl::divide_by_zero();
+
+ nRadius = double(nRadius * aAverage);
+}
+
+bool IMapCircleObject::IsEqual( const IMapCircleObject& rEqObj )
+{
+ return ( IMapObject::IsEqual( rEqObj ) &&
+ ( aCenter == rEqObj.aCenter ) &&
+ ( nRadius == rEqObj.nRadius ) );
+}
+
+IMapPolygonObject::IMapPolygonObject( const tools::Polygon& rPoly,
+ const OUString& rURL,
+ const OUString& rAltText,
+ const OUString& rDesc,
+ const OUString& rTarget,
+ const OUString& rName,
+ bool bURLActive,
+ bool bPixelCoords ) :
+ IMapObject ( rURL, rAltText, rDesc, rTarget, rName, bURLActive ),
+ bEllipse ( false )
+{
+ ImpConstruct( rPoly, bPixelCoords );
+}
+
+void IMapPolygonObject::ImpConstruct( const tools::Polygon& rPoly, bool bPixel )
+{
+ if ( bPixel )
+ aPoly = Application::GetDefaultDevice()->PixelToLogic( rPoly, MapMode( MapUnit::Map100thMM ) );
+ else
+ aPoly = rPoly;
+}
+
+
+/******************************************************************************
+|*
+|* Binary export
+|*
+\******************************************************************************/
+
+void IMapPolygonObject::WriteIMapObject( SvStream& rOStm ) const
+{
+ tools::GenericTypeSerializer aSerializer(rOStm);
+ WritePolygon( rOStm, aPoly );
+ // Version 2
+ rOStm.WriteBool( bEllipse );
+ aSerializer.writeRectangle(aEllipse);
+}
+
+
+/******************************************************************************
+|*
+|* Binary import
+|*
+\******************************************************************************/
+
+void IMapPolygonObject::ReadIMapObject( SvStream& rIStm )
+{
+ ReadPolygon( rIStm, aPoly );
+
+ // Version >= 2 has additional ellipses information
+ if ( nReadVersion >= 2 )
+ {
+ rIStm.ReadCharAsBool( bEllipse );
+ tools::GenericTypeSerializer aSerializer(rIStm);
+ aSerializer.readRectangle(aEllipse);
+ }
+}
+
+
+/******************************************************************************
+|*
+|* return type
+|*
+\******************************************************************************/
+
+sal_uInt16 IMapPolygonObject::GetType() const
+{
+ return IMAP_OBJ_POLYGON;
+}
+
+
+/******************************************************************************
+|*
+|* hit test
+|*
+\******************************************************************************/
+
+bool IMapPolygonObject::IsHit( const Point& rPoint ) const
+{
+ return aPoly.IsInside( rPoint );
+}
+
+tools::Polygon IMapPolygonObject::GetPolygon( bool bPixelCoords ) const
+{
+ tools::Polygon aNewPoly;
+
+ if ( bPixelCoords )
+ aNewPoly = Application::GetDefaultDevice()->LogicToPixel( aPoly, MapMode( MapUnit::Map100thMM ) );
+ else
+ aNewPoly = aPoly;
+
+ return aNewPoly;
+}
+
+void IMapPolygonObject::SetExtraEllipse( const tools::Rectangle& rEllipse )
+{
+ if ( aPoly.GetSize() )
+ {
+ bEllipse = true;
+ aEllipse = rEllipse;
+ }
+}
+
+void IMapPolygonObject::Scale( const Fraction& rFracX, const Fraction& rFracY )
+{
+ sal_uInt16 nCount = aPoly.GetSize();
+
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ Point aScaledPt( aPoly[ i ] );
+
+ if ( rFracX.GetDenominator() && rFracY.GetDenominator() )
+ {
+ SCALEPOINT( aScaledPt, rFracX, rFracY );
+ }
+
+ aPoly[ i ] = aScaledPt;
+ }
+
+ if ( !bEllipse )
+ return;
+
+ Point aTL( aEllipse.TopLeft() );
+ Point aBR( aEllipse.BottomRight() );
+
+ if ( rFracX.GetDenominator() && rFracY.GetDenominator() )
+ {
+ SCALEPOINT( aTL, rFracX, rFracY );
+ SCALEPOINT( aBR, rFracX, rFracY );
+ }
+
+ aEllipse = tools::Rectangle( aTL, aBR );
+}
+
+bool IMapPolygonObject::IsEqual( const IMapPolygonObject& rEqObj )
+{
+ bool bRet = false;
+
+ if ( IMapObject::IsEqual( rEqObj ) )
+ {
+ const tools::Polygon& rEqPoly = rEqObj.aPoly;
+ const sal_uInt16 nCount = aPoly.GetSize();
+ const sal_uInt16 nEqCount = rEqPoly.GetSize();
+
+ if ( nCount == nEqCount )
+ {
+ bool bDifferent = false;
+
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ if ( aPoly[ i ] != rEqPoly[ i ] )
+ {
+ bDifferent = true;
+ break;
+ }
+ }
+
+ if ( !bDifferent )
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+/******************************************************************************
+|*
+|* Ctor
+|*
+\******************************************************************************/
+
+ImageMap::ImageMap( const OUString& rName )
+: aName( rName )
+{
+}
+
+
+/******************************************************************************
+|*
+|* Copy-Ctor
+|*
+\******************************************************************************/
+
+ImageMap::ImageMap( const ImageMap& rImageMap )
+{
+
+ size_t nCount = rImageMap.GetIMapObjectCount();
+
+ for ( size_t i = 0; i < nCount; i++ )
+ {
+ IMapObject* pCopyObj = rImageMap.GetIMapObject( i );
+
+ switch( pCopyObj->GetType() )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ maList.emplace_back( new IMapRectangleObject( *static_cast<IMapRectangleObject*>( pCopyObj ) ) );
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ maList.emplace_back( new IMapCircleObject( *static_cast<IMapCircleObject*>( pCopyObj ) ) );
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ maList.emplace_back( new IMapPolygonObject( *static_cast<IMapPolygonObject*>( pCopyObj ) ) );
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ aName = rImageMap.aName;
+}
+
+
+/******************************************************************************
+|*
+|* Dtor
+|*
+\******************************************************************************/
+
+ImageMap::~ImageMap()
+{
+}
+
+
+/******************************************************************************
+|*
+|* release internal memory
+|*
+\******************************************************************************/
+
+void ImageMap::ClearImageMap()
+{
+ maList.clear();
+
+ aName.clear();
+}
+
+
+/******************************************************************************
+|*
+|* assignment operator
+|*
+\******************************************************************************/
+
+ImageMap& ImageMap::operator=( const ImageMap& rImageMap )
+{
+ if (this != &rImageMap)
+ {
+ size_t nCount = rImageMap.GetIMapObjectCount();
+
+ ClearImageMap();
+
+ for ( size_t i = 0; i < nCount; i++ )
+ {
+ IMapObject* pCopyObj = rImageMap.GetIMapObject( i );
+
+ switch( pCopyObj->GetType() )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ maList.emplace_back( new IMapRectangleObject( *static_cast<IMapRectangleObject*>(pCopyObj) ) );
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ maList.emplace_back( new IMapCircleObject( *static_cast<IMapCircleObject*>(pCopyObj) ) );
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ maList.emplace_back( new IMapPolygonObject( *static_cast<IMapPolygonObject*>(pCopyObj) ) );
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ aName = rImageMap.aName;
+ }
+ return *this;
+}
+
+
+/******************************************************************************
+|*
+|* compare operator I
+|*
+\******************************************************************************/
+
+bool ImageMap::operator==( const ImageMap& rImageMap )
+{
+ const size_t nCount = maList.size();
+ const size_t nEqCount = rImageMap.GetIMapObjectCount();
+ bool bRet = false;
+
+ if ( nCount == nEqCount )
+ {
+ bool bDifferent = ( aName != rImageMap.aName );
+
+ for ( size_t i = 0; ( i < nCount ) && !bDifferent; i++ )
+ {
+ IMapObject* pObj = maList[ i ].get();
+ IMapObject* pEqObj = rImageMap.GetIMapObject( i );
+
+ if ( pObj->GetType() == pEqObj->GetType() )
+ {
+ switch( pObj->GetType() )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ {
+ if ( ! static_cast<IMapRectangleObject*>(pObj)->IsEqual( *static_cast<IMapRectangleObject*>(pEqObj) ) )
+ bDifferent = true;
+ }
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ {
+ if ( ! static_cast<IMapCircleObject*>(pObj)->IsEqual( *static_cast<IMapCircleObject*>(pEqObj) ) )
+ bDifferent = true;
+ }
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ {
+ if ( ! static_cast<IMapPolygonObject*>(pObj)->IsEqual( *static_cast<IMapPolygonObject*>(pEqObj) ) )
+ bDifferent = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ bDifferent = true;
+ }
+
+ if ( !bDifferent )
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+
+/******************************************************************************
+|*
+|* compare operator II
+|*
+\******************************************************************************/
+
+bool ImageMap::operator!=( const ImageMap& rImageMap )
+{
+ return !( *this == rImageMap );
+}
+
+
+/******************************************************************************
+|*
+|* insert new object
+|*
+\******************************************************************************/
+
+void ImageMap::InsertIMapObject( const IMapObject& rIMapObject )
+{
+ switch( rIMapObject.GetType() )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ maList.emplace_back( new IMapRectangleObject( static_cast<const IMapRectangleObject&>( rIMapObject ) ) );
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ maList.emplace_back( new IMapCircleObject( static_cast<const IMapCircleObject&>( rIMapObject ) ) );
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ maList.emplace_back( new IMapPolygonObject( static_cast<const IMapPolygonObject&>( rIMapObject ) ) );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ImageMap::InsertIMapObject( std::unique_ptr<IMapObject> pNewObject )
+{
+ maList.emplace_back( std::move(pNewObject) );
+}
+
+/******************************************************************************
+|*
+|* hit test
+|*
+\******************************************************************************/
+
+IMapObject* ImageMap::GetHitIMapObject( const Size& rTotalSize,
+ const Size& rDisplaySize,
+ const Point& rRelHitPoint,
+ sal_uLong nFlags )
+{
+ Point aRelPoint( rTotalSize.Width() * rRelHitPoint.X() / rDisplaySize.Width(),
+ rTotalSize.Height() * rRelHitPoint.Y() / rDisplaySize.Height() );
+
+ // transform point to check before checking if flags to mirror etc. are set,
+ if ( nFlags )
+ {
+ if ( nFlags & IMAP_MIRROR_HORZ )
+ aRelPoint.setX( rTotalSize.Width() - aRelPoint.X() );
+
+ if ( nFlags & IMAP_MIRROR_VERT )
+ aRelPoint.setY( rTotalSize.Height() - aRelPoint.Y() );
+ }
+
+ // walk over all objects and execute HitTest
+ IMapObject* pObj = nullptr;
+ for(const auto& i : maList) {
+ if ( i->IsHit( aRelPoint ) ) {
+ pObj = i.get();
+ break;
+ }
+ }
+
+ return( pObj ? ( pObj->IsActive() ? pObj : nullptr ) : nullptr );
+}
+
+void ImageMap::Scale( const Fraction& rFracX, const Fraction& rFracY )
+{
+ size_t nCount = maList.size();
+
+ for ( size_t i = 0; i < nCount; i++ )
+ {
+ IMapObject* pObj = maList[ i ].get();
+
+ switch( pObj->GetType() )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ static_cast<IMapRectangleObject*>( pObj )->Scale( rFracX, rFracY );
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ static_cast<IMapCircleObject*>( pObj )->Scale( rFracX, rFracY );
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ static_cast<IMapPolygonObject*>( pObj )->Scale( rFracX, rFracY );
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/******************************************************************************
+|*
+|* sequentially write objects
+|*
+\******************************************************************************/
+
+void ImageMap::ImpWriteImageMap( SvStream& rOStm ) const
+{
+ size_t nCount = maList.size();
+
+ for ( size_t i = 0; i < nCount; i++ )
+ {
+ auto& pObj = maList[ i ];
+ pObj->Write( rOStm );
+ }
+}
+
+
+/******************************************************************************
+|*
+|* sequentially read objects
+|*
+\******************************************************************************/
+
+void ImageMap::ImpReadImageMap( SvStream& rIStm, size_t nCount )
+{
+ const size_t nMinRecordSize = 12; //circle, three 32bit numbers
+ const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
+
+ if (nCount > nMaxRecords)
+ {
+ SAL_WARN("svtools.misc", "Parsing error: " << nMaxRecords << " max possible entries, but " <<
+ nCount << " claimed, truncating");
+ nCount = nMaxRecords;
+ }
+
+ // read new objects
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ sal_uInt16 nType;
+
+ rIStm.ReadUInt16( nType );
+ rIStm.SeekRel( -2 );
+
+ switch( nType )
+ {
+ case IMAP_OBJ_RECTANGLE:
+ {
+ IMapRectangleObject* pObj = new IMapRectangleObject;
+ pObj->Read( rIStm );
+ maList.emplace_back( pObj );
+ }
+ break;
+
+ case IMAP_OBJ_CIRCLE:
+ {
+ IMapCircleObject* pObj = new IMapCircleObject;
+ pObj->Read( rIStm );
+ maList.emplace_back( pObj );
+ }
+ break;
+
+ case IMAP_OBJ_POLYGON:
+ {
+ IMapPolygonObject* pObj = new IMapPolygonObject;
+ pObj->Read( rIStm );
+ maList.emplace_back( pObj );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/******************************************************************************
+|*
+|* store binary
+|*
+\******************************************************************************/
+
+void ImageMap::Write( SvStream& rOStm ) const
+{
+ IMapCompat* pCompat;
+ OUString aImageName( GetName() );
+ SvStreamEndian nOldFormat = rOStm.GetEndian();
+ sal_uInt16 nCount = static_cast<sal_uInt16>(GetIMapObjectCount());
+ const rtl_TextEncoding eEncoding = osl_getThreadTextEncoding(); //vomit!
+
+ rOStm.SetEndian( SvStreamEndian::LITTLE );
+
+ // write MagicCode
+ rOStm.WriteCharPtr( IMAPMAGIC );
+ rOStm.WriteUInt16( IMAGE_MAP_VERSION );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aImageName, eEncoding);
+ write_uInt16_lenPrefixed_uInt8s_FromOString(rOStm, OString()); //dummy
+ rOStm.WriteUInt16( nCount );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aImageName, eEncoding);
+
+ pCompat = new IMapCompat( rOStm, StreamMode::WRITE );
+
+ // here one can insert in newer versions
+
+ delete pCompat;
+
+ ImpWriteImageMap( rOStm );
+
+ rOStm.SetEndian( nOldFormat );
+}
+
+
+/******************************************************************************
+|*
+|* load binary
+|*
+\******************************************************************************/
+
+void ImageMap::Read( SvStream& rIStm )
+{
+ char cMagic[6];
+ SvStreamEndian nOldFormat = rIStm.GetEndian();
+ sal_uInt16 nCount;
+
+ rIStm.SetEndian( SvStreamEndian::LITTLE );
+ rIStm.ReadBytes(cMagic, sizeof(cMagic));
+
+ if ( !memcmp( cMagic, IMAPMAGIC, sizeof( cMagic ) ) )
+ {
+ IMapCompat* pCompat;
+
+ // delete old content
+ ClearImageMap();
+
+ // read on version
+ rIStm.SeekRel( 2 );
+
+ aName = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIStm, osl_getThreadTextEncoding());
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm); // Dummy
+ rIStm.ReadUInt16( nCount );
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm); // Dummy
+
+ pCompat = new IMapCompat( rIStm, StreamMode::READ );
+
+ // here one can read in newer versions
+
+ delete pCompat;
+ ImpReadImageMap( rIStm, nCount );
+
+ }
+ else
+ rIStm.SetError( SVSTREAM_GENERALERROR );
+
+ rIStm.SetEndian( nOldFormat );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */