Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */