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 "drawingbase.hxx"
22 #include <com/sun/star/awt/Rectangle.hpp>
23 #include <osl/diagnose.h>
24 #include <oox/helper/attributelist.hxx>
25 #include <oox/helper/binaryinputstream.hxx>
26 #include "unitconverter.hxx"
27 #include <oox/helper/propertyset.hxx>
28 #include <oox/token/properties.hxx>
33 using namespace ::com::sun::star::table
;
34 using namespace ::oox::drawingml
;
38 /** Converts the passed 32-bit integer value from 1/100 mm to EMUs. */
39 inline sal_Int64
lclHmmToEmu( sal_Int32 nValue
)
41 return (nValue
< 0) ? -1 : convertHmmToEmu( nValue
);
44 /** Converts the passed 64-bit integer value from EMUs to 1/100 mm. */
45 inline sal_Int32
lclEmuToHmm( sal_Int64 nValue
)
47 return (nValue
< 0) ? -1 : convertEmuToHmm( nValue
);
52 CellAnchorModel::CellAnchorModel() :
60 AnchorClientDataModel::AnchorClientDataModel() :
61 mbLocksWithSheet( true ),
62 mbPrintsWithSheet( true )
66 ShapeAnchor::ShapeAnchor( const WorksheetHelper
& rHelper
) :
67 WorksheetHelper( rHelper
),
68 meAnchorType( ANCHOR_INVALID
),
69 meCellAnchorType( CELLANCHOR_EMU
),
70 meEditAs( ANCHOR_TWOCELL
)
74 void ShapeAnchor::importAnchor( sal_Int32 nElement
, const AttributeList
& rAttribs
)
78 case XDR_TOKEN( absoluteAnchor
):
79 meAnchorType
= ANCHOR_ABSOLUTE
;
81 case XDR_TOKEN( oneCellAnchor
):
82 meAnchorType
= ANCHOR_ONECELL
;
84 case XDR_TOKEN( twoCellAnchor
):
86 meAnchorType
= ANCHOR_TWOCELL
;
87 OUString sEditAs
= rAttribs
.getXString( XML_editAs
, OUString() );
88 if ( !sEditAs
.isEmpty() )
90 if ( sEditAs
.equalsIgnoreAsciiCase("absolute" ) )
91 meEditAs
= ANCHOR_ABSOLUTE
;
92 else if ( sEditAs
.equalsIgnoreAsciiCase("oneCell") )
93 meEditAs
= ANCHOR_ONECELL
;
98 OSL_ENSURE( false, "ShapeAnchor::importAnchor - unexpected element" );
100 meCellAnchorType
= CELLANCHOR_EMU
;
103 void ShapeAnchor::importPos( const AttributeList
& rAttribs
)
105 OSL_ENSURE( meAnchorType
== ANCHOR_ABSOLUTE
, "ShapeAnchor::importPos - unexpected 'xdr:pos' element" );
106 maPos
.X
= rAttribs
.getHyper( XML_x
, 0 );
107 maPos
.Y
= rAttribs
.getHyper( XML_y
, 0 );
110 void ShapeAnchor::importExt( const AttributeList
& rAttribs
)
112 OSL_ENSURE( (meAnchorType
== ANCHOR_ABSOLUTE
) || (meAnchorType
== ANCHOR_ONECELL
), "ShapeAnchor::importExt - unexpected 'xdr:ext' element" );
113 maSize
.Width
= rAttribs
.getHyper( XML_cx
, 0 );
114 maSize
.Height
= rAttribs
.getHyper( XML_cy
, 0 );
117 void ShapeAnchor::importClientData( const AttributeList
& rAttribs
)
119 maClientData
.mbLocksWithSheet
= rAttribs
.getBool( XML_fLocksWithSheet
, true );
120 maClientData
.mbPrintsWithSheet
= rAttribs
.getBool( XML_fPrintsWithSheet
, true );
123 void ShapeAnchor::setCellPos( sal_Int32 nElement
, sal_Int32 nParentContext
, const OUString
& rValue
)
125 CellAnchorModel
* pCellAnchor
= 0;
126 switch( nParentContext
)
128 case XDR_TOKEN( from
):
129 OSL_ENSURE( (meAnchorType
== ANCHOR_ONECELL
) || (meAnchorType
== ANCHOR_TWOCELL
), "ShapeAnchor::setCellPos - unexpected 'xdr:from' element" );
130 pCellAnchor
= &maFrom
;
132 case XDR_TOKEN( to
):
133 OSL_ENSURE( meAnchorType
== ANCHOR_TWOCELL
, "ShapeAnchor::setCellPos - unexpected 'xdr:to' element" );
137 OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected parent element" );
139 if( pCellAnchor
) switch( nElement
)
141 case XDR_TOKEN( col
): pCellAnchor
->mnCol
= rValue
.toInt32(); break;
142 case XDR_TOKEN( row
): pCellAnchor
->mnRow
= rValue
.toInt32(); break;
143 case XDR_TOKEN( colOff
): pCellAnchor
->mnColOffset
= rValue
.toInt64(); break;
144 case XDR_TOKEN( rowOff
): pCellAnchor
->mnRowOffset
= rValue
.toInt64(); break;
145 default: OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected element" );
149 void ShapeAnchor::importVmlAnchor( const OUString
& rAnchor
)
151 meAnchorType
= ANCHOR_VML
;
152 meCellAnchorType
= CELLANCHOR_PIXEL
;
154 ::std::vector
< OUString
> aTokens
;
155 sal_Int32 nIndex
= 0;
157 aTokens
.push_back( rAnchor
.getToken( 0, ',', nIndex
).trim() );
159 OSL_ENSURE( aTokens
.size() >= 8, "ShapeAnchor::importVmlAnchor - missing anchor tokens" );
160 if( aTokens
.size() >= 8 )
162 maFrom
.mnCol
= aTokens
[ 0 ].toInt32();
163 maFrom
.mnColOffset
= aTokens
[ 1 ].toInt32();
164 maFrom
.mnRow
= aTokens
[ 2 ].toInt32();
165 maFrom
.mnRowOffset
= aTokens
[ 3 ].toInt32();
166 maTo
.mnCol
= aTokens
[ 4 ].toInt32();
167 maTo
.mnColOffset
= aTokens
[ 5 ].toInt32();
168 maTo
.mnRow
= aTokens
[ 6 ].toInt32();
169 maTo
.mnRowOffset
= aTokens
[ 7 ].toInt32();
173 EmuRectangle
ShapeAnchor::calcAnchorRectEmu( const css::awt::Size
& rPageSizeHmm
) const
175 AddressConverter
& rAddrConv
= getAddressConverter();
176 EmuSize
aPageSize( lclHmmToEmu( rPageSizeHmm
.Width
), lclHmmToEmu( rPageSizeHmm
.Height
) );
177 EmuRectangle
aAnchorRect( -1, -1, -1, -1 );
179 // calculate shape position
180 switch( meAnchorType
)
182 case ANCHOR_ABSOLUTE
:
183 OSL_ENSURE( maPos
.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
184 if( maPos
.isValid() && (maPos
.X
< aPageSize
.Width
) && (maPos
.Y
< aPageSize
.Height
) )
185 aAnchorRect
.setPos( maPos
);
190 OSL_ENSURE( maFrom
.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
191 if( maFrom
.isValid() && rAddrConv
.checkCol( maFrom
.mnCol
, true ) && rAddrConv
.checkRow( maFrom
.mnRow
, true ) )
193 EmuPoint aPoint
= calcCellAnchorEmu( maFrom
);
194 if( (aPoint
.X
< aPageSize
.Width
) && (aPoint
.Y
< aPageSize
.Height
) )
195 aAnchorRect
.setPos( aPoint
);
199 OSL_ENSURE( false, "ShapeAnchor::calcAnchorRectEmu - invalid anchor" );
203 // calculate shape size
204 if( (aAnchorRect
.X
>= 0) && (aAnchorRect
.Y
>= 0) ) switch( meAnchorType
)
206 case ANCHOR_ABSOLUTE
:
208 OSL_ENSURE( maSize
.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid size" );
209 if( maSize
.isValid() )
211 aAnchorRect
.Width
= ::std::min
< sal_Int64
>( maSize
.Width
, aPageSize
.Width
- aAnchorRect
.X
);
212 aAnchorRect
.Height
= ::std::min
< sal_Int64
>( maSize
.Height
, aPageSize
.Height
- aAnchorRect
.Y
);
217 OSL_ENSURE( maTo
.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
220 /* Pass a valid cell address to calcCellAnchorEmu(), otherwise
221 nothing useful is returned, even if either row or column is valid. */
222 CellAddress aToCell
= rAddrConv
.createValidCellAddress( BinAddress( maTo
.mnCol
, maTo
.mnRow
), getSheetIndex(), true );
223 CellAnchorModel aValidTo
= maTo
;
224 aValidTo
.mnCol
= aToCell
.Column
;
225 aValidTo
.mnRow
= aToCell
.Row
;
226 EmuPoint aPoint
= calcCellAnchorEmu( aValidTo
);
227 // width (if column index is valid, use the calculated offset, otherwise stretch to maximum available X position)
228 aAnchorRect
.Width
= aPageSize
.Width
- aAnchorRect
.X
;
229 if( aToCell
.Column
== maTo
.mnCol
)
230 aAnchorRect
.Width
= ::std::min
< sal_Int64
>( aPoint
.X
- aAnchorRect
.X
+ 1, aAnchorRect
.Width
);
231 // height (if row index is valid, use the calculated offset, otherwise stretch to maximum available Y position)
232 aAnchorRect
.Height
= aPageSize
.Height
- aAnchorRect
.Y
;
233 if( aToCell
.Row
== maTo
.mnRow
)
234 aAnchorRect
.Height
= ::std::min
< sal_Int64
>( aPoint
.Y
- aAnchorRect
.Y
+ 1, aAnchorRect
.Height
);
241 // add 0.75 mm (27,000 EMUs) in X direction to correct display error
242 if( aAnchorRect
.X
>= 0 )
243 aAnchorRect
.X
+= 27000;
244 // remove 0.25 mm (9,000 EMUs) in Y direction to correct display error
245 if( aAnchorRect
.Y
>= 9000 )
246 aAnchorRect
.Y
-= 9000;
251 css::awt::Rectangle
ShapeAnchor::calcAnchorRectHmm( const css::awt::Size
& rPageSizeHmm
) const
253 EmuRectangle aAnchorRect
= calcAnchorRectEmu( rPageSizeHmm
);
254 return css::awt::Rectangle( lclEmuToHmm( aAnchorRect
.X
), lclEmuToHmm( aAnchorRect
.Y
), lclEmuToHmm( aAnchorRect
.Width
), lclEmuToHmm( aAnchorRect
.Height
) );
257 EmuPoint
ShapeAnchor::calcCellAnchorEmu( const CellAnchorModel
& rModel
) const
259 // calculate position of top-left edge of the cell
260 css::awt::Point aPoint
= getCellPosition( rModel
.mnCol
, rModel
.mnRow
);
261 EmuPoint
aEmuPoint( lclHmmToEmu( aPoint
.X
), lclHmmToEmu( aPoint
.Y
) );
263 // add the offset inside the cell
264 switch( meCellAnchorType
)
267 aEmuPoint
.X
+= rModel
.mnColOffset
;
268 aEmuPoint
.Y
+= rModel
.mnRowOffset
;
271 case CELLANCHOR_PIXEL
:
273 const UnitConverter
& rUnitConv
= getUnitConverter();
274 aEmuPoint
.X
+= static_cast< sal_Int64
>( rUnitConv
.scaleValue( static_cast< double >( rModel
.mnColOffset
), UNIT_SCREENX
, UNIT_EMU
) );
275 aEmuPoint
.Y
+= static_cast< sal_Int64
>( rUnitConv
.scaleValue( static_cast< double >( rModel
.mnRowOffset
), UNIT_SCREENY
, UNIT_EMU
) );
279 case CELLANCHOR_COLROW
:
281 css::awt::Size aCellSize
= getCellSize( rModel
.mnCol
, rModel
.mnRow
);
282 EmuSize
aEmuSize( lclHmmToEmu( aCellSize
.Width
), lclHmmToEmu( aCellSize
.Height
) );
283 // X offset is given in 1/1024 of column width
284 aEmuPoint
.X
+= static_cast< sal_Int64
>( aEmuSize
.Width
* getLimitedValue
< double >( static_cast< double >( rModel
.mnColOffset
) / 1024.0, 0.0, 1.0 ) + 0.5 );
285 // Y offset is given in 1/256 of row height
286 aEmuPoint
.Y
+= static_cast< sal_Int64
>( aEmuSize
.Height
* getLimitedValue
< double >( static_cast< double >( rModel
.mnRowOffset
) / 256.0, 0.0, 1.0 ) + 0.5 );
297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */