/src/libreoffice/oox/source/drawingml/chart/chartdrawingfragment.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <drawingml/chart/chartdrawingfragment.hxx> |
21 | | |
22 | | #include <osl/diagnose.h> |
23 | | |
24 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
25 | | #include <com/sun/star/awt/Rectangle.hpp> |
26 | | #include <oox/core/xmlfilterbase.hxx> |
27 | | #include <oox/drawingml/connectorshapecontext.hxx> |
28 | | #include <oox/drawingml/graphicshapecontext.hxx> |
29 | | #include <oox/drawingml/shapecontext.hxx> |
30 | | #include <oox/drawingml/shapegroupcontext.hxx> |
31 | | #include <oox/helper/attributelist.hxx> |
32 | | #include <oox/token/namespaces.hxx> |
33 | | #include <oox/token/tokens.hxx> |
34 | | #include <o3tl/string_view.hxx> |
35 | | |
36 | | namespace oox::drawingml::chart { |
37 | | |
38 | | using namespace ::com::sun::star; |
39 | | using namespace ::com::sun::star::drawing; |
40 | | using namespace ::com::sun::star::uno; |
41 | | using namespace ::oox::core; |
42 | | |
43 | | ShapeAnchor::ShapeAnchor( bool bRelSize ) : |
44 | 0 | mbRelSize( bRelSize ) |
45 | 0 | { |
46 | 0 | } |
47 | | |
48 | | void ShapeAnchor::importExt( const AttributeList& rAttribs ) |
49 | 0 | { |
50 | 0 | OSL_ENSURE( !mbRelSize, "ShapeAnchor::importExt - unexpected 'cdr:ext' element" ); |
51 | 0 | maSize.Width = rAttribs.getHyper( XML_cx, 0 ); |
52 | 0 | maSize.Height = rAttribs.getHyper( XML_cy, 0 ); |
53 | 0 | } |
54 | | |
55 | | void ShapeAnchor::setPos( sal_Int32 nElement, sal_Int32 nParentContext, std::u16string_view rValue ) |
56 | 0 | { |
57 | 0 | AnchorPosModel* pAnchorPos = nullptr; |
58 | 0 | switch( nParentContext ) |
59 | 0 | { |
60 | 0 | case CDR_TOKEN( from ): |
61 | 0 | pAnchorPos = &maFrom; |
62 | 0 | break; |
63 | 0 | case CDR_TOKEN( to ): |
64 | 0 | OSL_ENSURE( mbRelSize, "ShapeAnchor::setPos - unexpected 'cdr:to' element" ); |
65 | 0 | pAnchorPos = &maTo; |
66 | 0 | break; |
67 | 0 | default: |
68 | 0 | OSL_FAIL( "ShapeAnchor::setPos - unexpected parent element" ); |
69 | 0 | } |
70 | 0 | if( pAnchorPos ) switch( nElement ) |
71 | 0 | { |
72 | 0 | case CDR_TOKEN( x ): pAnchorPos->mfX = o3tl::toDouble(rValue); break; |
73 | 0 | case CDR_TOKEN( y ): pAnchorPos->mfY = o3tl::toDouble(rValue); break; |
74 | 0 | default: OSL_FAIL( "ShapeAnchor::setPos - unexpected element" ); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | EmuRectangle ShapeAnchor::calcAnchorRectEmu( const EmuRectangle& rChartRect ) const |
79 | 0 | { |
80 | 0 | EmuRectangle aAnchorRect( -1, -1, -1, -1 ); |
81 | |
|
82 | 0 | OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid from position" ); |
83 | 0 | OSL_ENSURE( mbRelSize ? maTo.isValid() : maSize.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid to/size" ); |
84 | 0 | if( maFrom.isValid() && (mbRelSize ? maTo.isValid() : maSize.isValid()) ) |
85 | 0 | { |
86 | | // calculate shape position |
87 | 0 | aAnchorRect.X = static_cast< sal_Int64 >( maFrom.mfX * rChartRect.Width + 0.5 ); |
88 | 0 | aAnchorRect.Y = static_cast< sal_Int64 >( maFrom.mfY * rChartRect.Height + 0.5 ); |
89 | | |
90 | | // calculate shape size |
91 | 0 | if( mbRelSize ) |
92 | 0 | { |
93 | 0 | aAnchorRect.Width = static_cast< sal_Int64 >( maTo.mfX * rChartRect.Width + 0.5 ) - aAnchorRect.X; |
94 | 0 | if( aAnchorRect.Width < 0 ) |
95 | 0 | { |
96 | 0 | aAnchorRect.X += aAnchorRect.Width; |
97 | 0 | aAnchorRect.Width *= -1; |
98 | 0 | } |
99 | 0 | aAnchorRect.Height = static_cast< sal_Int64 >( maTo.mfY * rChartRect.Height + 0.5 ) - aAnchorRect.Y; |
100 | 0 | if( aAnchorRect.Height < 0 ) |
101 | 0 | { |
102 | 0 | aAnchorRect.Y += aAnchorRect.Height; |
103 | 0 | aAnchorRect.Height *= -1; |
104 | 0 | } |
105 | 0 | } |
106 | 0 | else |
107 | 0 | { |
108 | 0 | aAnchorRect.setSize( maSize ); |
109 | 0 | } |
110 | 0 | } |
111 | |
|
112 | 0 | return aAnchorRect; |
113 | 0 | } |
114 | | |
115 | | ChartDrawingFragment::ChartDrawingFragment( XmlFilterBase& rFilter, |
116 | | const OUString& rFragmentPath, const Reference< XShapes >& rxDrawPage, |
117 | | const awt::Size& rChartSize, const awt::Point& rShapesOffset, bool bOleSupport ) : |
118 | 0 | FragmentHandler2( rFilter, rFragmentPath ), |
119 | 0 | mxDrawPage( rxDrawPage ), |
120 | 0 | mbOleSupport( bOleSupport ) |
121 | 0 | { |
122 | 0 | maChartRectEmu.X = convertHmmToEmu( rShapesOffset.X ); |
123 | 0 | maChartRectEmu.Y = convertHmmToEmu( rShapesOffset.Y ); |
124 | 0 | maChartRectEmu.Width = convertHmmToEmu( rChartSize.Width ); |
125 | 0 | maChartRectEmu.Height = convertHmmToEmu( rChartSize.Height ); |
126 | 0 | } |
127 | | |
128 | | ChartDrawingFragment::~ChartDrawingFragment() |
129 | 0 | { |
130 | 0 | } |
131 | | |
132 | | ContextHandlerRef ChartDrawingFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) |
133 | 0 | { |
134 | 0 | switch( getCurrentElement() ) |
135 | 0 | { |
136 | 0 | case XML_ROOT_CONTEXT: |
137 | 0 | if( nElement == C_TOKEN( userShapes ) ) return this; |
138 | 0 | break; |
139 | | |
140 | 0 | case C_TOKEN( userShapes ): |
141 | 0 | switch( nElement ) |
142 | 0 | { |
143 | 0 | case CDR_TOKEN( absSizeAnchor ): |
144 | 0 | mxAnchor = std::make_shared<ShapeAnchor>( false ); |
145 | 0 | return this; |
146 | 0 | case CDR_TOKEN( relSizeAnchor ): |
147 | 0 | mxAnchor = std::make_shared<ShapeAnchor>( true ); |
148 | 0 | return this; |
149 | 0 | } |
150 | 0 | break; |
151 | | |
152 | 0 | case CDR_TOKEN( absSizeAnchor ): |
153 | 0 | case CDR_TOKEN( relSizeAnchor ): |
154 | 0 | switch( nElement ) |
155 | 0 | { |
156 | 0 | case CDR_TOKEN( sp ): |
157 | 0 | mxShape = std::make_shared<Shape>( "com.sun.star.drawing.CustomShape" ); |
158 | 0 | return new ShapeContext( *this, ShapePtr(), mxShape ); |
159 | 0 | case CDR_TOKEN( cxnSp ): |
160 | 0 | mxShape = std::make_shared<Shape>( "com.sun.star.drawing.ConnectorShape" ); |
161 | 0 | return new ConnectorShapeContext(*this, ShapePtr(), mxShape, |
162 | 0 | mxShape->getConnectorShapeProperties()); |
163 | 0 | case CDR_TOKEN( pic ): |
164 | 0 | mxShape = std::make_shared<Shape>( "com.sun.star.drawing.GraphicObjectShape" ); |
165 | 0 | return new GraphicShapeContext( *this, ShapePtr(), mxShape ); |
166 | 0 | case CDR_TOKEN( graphicFrame ): |
167 | 0 | if( !mbOleSupport ) |
168 | 0 | return nullptr; |
169 | 0 | mxShape = std::make_shared<Shape>( "com.sun.star.drawing.GraphicObjectShape" ); |
170 | 0 | return new GraphicalObjectFrameContext( *this, ShapePtr(), mxShape, true ); |
171 | 0 | case CDR_TOKEN( grpSp ): |
172 | 0 | mxShape = std::make_shared<Shape>( "com.sun.star.drawing.GroupShape" ); |
173 | 0 | return new ShapeGroupContext( *this, ShapePtr(), mxShape ); |
174 | | |
175 | 0 | case CDR_TOKEN( from ): |
176 | 0 | case CDR_TOKEN( to ): |
177 | 0 | return this; |
178 | | |
179 | 0 | case CDR_TOKEN( ext ): |
180 | 0 | if( mxAnchor ) mxAnchor->importExt( rAttribs ); |
181 | 0 | return nullptr; |
182 | 0 | } |
183 | 0 | break; |
184 | | |
185 | 0 | case CDR_TOKEN( from ): |
186 | 0 | case CDR_TOKEN( to ): |
187 | 0 | switch( nElement ) |
188 | 0 | { |
189 | 0 | case CDR_TOKEN( x ): |
190 | 0 | case CDR_TOKEN( y ): |
191 | 0 | return this; // collect value in onEndElement() |
192 | 0 | } |
193 | 0 | break; |
194 | 0 | } |
195 | 0 | return nullptr; |
196 | 0 | } |
197 | | |
198 | | void ChartDrawingFragment::onCharacters( const OUString& rChars ) |
199 | 0 | { |
200 | 0 | if( isCurrentElement( CDR_TOKEN( x ), CDR_TOKEN( y ) ) && mxAnchor ) |
201 | 0 | mxAnchor->setPos( getCurrentElement(), getParentElement(), rChars ); |
202 | 0 | } |
203 | | |
204 | | void ChartDrawingFragment::onEndElement() |
205 | 0 | { |
206 | 0 | if( !isCurrentElement( CDR_TOKEN( absSizeAnchor ), CDR_TOKEN( relSizeAnchor ) ) ) |
207 | 0 | return; |
208 | | |
209 | 0 | if( mxDrawPage.is() && mxShape && mxAnchor ) |
210 | 0 | { |
211 | 0 | EmuRectangle aShapeRectEmu = mxAnchor->calcAnchorRectEmu( maChartRectEmu ); |
212 | 0 | if( (aShapeRectEmu.X >= 0) && (aShapeRectEmu.Y >= 0) && (aShapeRectEmu.Width >= 0) && (aShapeRectEmu.Height >= 0) ) |
213 | 0 | { |
214 | 0 | const sal_Int32 aRotation = mxShape->getRotation(); |
215 | 0 | if( (aRotation >= 45 * PER_DEGREE && aRotation < 135 * PER_DEGREE) || (aRotation >= 225 * PER_DEGREE && aRotation < 315 * PER_DEGREE) ) |
216 | 0 | { |
217 | 0 | sal_Int64 nHalfWidth = aShapeRectEmu.Width / 2; |
218 | 0 | sal_Int64 nHalfHeight = aShapeRectEmu.Height / 2; |
219 | 0 | aShapeRectEmu.X = aShapeRectEmu.X + nHalfWidth - nHalfHeight; |
220 | 0 | aShapeRectEmu.Y = aShapeRectEmu.Y + nHalfHeight - nHalfWidth; |
221 | 0 | std::swap(aShapeRectEmu.Width, aShapeRectEmu.Height); |
222 | 0 | } |
223 | | // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle) |
224 | 0 | awt::Rectangle aShapeRectEmu32( |
225 | 0 | getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.X, 0, SAL_MAX_INT32 ), |
226 | 0 | getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Y, 0, SAL_MAX_INT32 ), |
227 | 0 | getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Width, 0, SAL_MAX_INT32 ), |
228 | 0 | getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Height, 0, SAL_MAX_INT32 ) ); |
229 | | |
230 | | // Set the position and size before calling addShape(). |
231 | 0 | mxShape->setPosition(awt::Point(aShapeRectEmu32.X, aShapeRectEmu32.Y)); |
232 | 0 | mxShape->setSize(awt::Size(aShapeRectEmu32.Width, aShapeRectEmu32.Height)); |
233 | |
|
234 | 0 | basegfx::B2DHomMatrix aMatrix; |
235 | 0 | mxShape->addShape( getFilter(), getFilter().getCurrentTheme(), mxDrawPage, aMatrix, mxShape->getFillProperties() ); |
236 | 0 | } |
237 | 0 | } |
238 | 0 | mxShape.reset(); |
239 | 0 | mxAnchor.reset(); |
240 | 0 | } |
241 | | |
242 | | } // namespace oox::drawingml::chart |
243 | | |
244 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |