Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/draw/XMLShapeStyleContext.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 <tools/debug.hxx>
21
#include <sal/log.hxx>
22
#include <xmloff/XMLShapeStyleContext.hxx>
23
#include <XMLShapePropertySetContext.hxx>
24
#include <xmloff/contextid.hxx>
25
#include <com/sun/star/drawing/FillStyle.hpp>
26
#include <com/sun/star/drawing/XControlShape.hpp>
27
#include <com/sun/star/beans/XPropertySet.hpp>
28
#include <com/sun/star/beans/XPropertySetInfo.hpp>
29
#include <com/sun/star/lang/IllegalArgumentException.hpp>
30
#include <com/sun/star/container/XIndexReplace.hpp>
31
#include <xmloff/xmlimp.hxx>
32
#include <xmloff/xmlnumi.hxx>
33
#include <xmloff/xmlnamespace.hxx>
34
#include <xmloff/xmlprmap.hxx>
35
#include <xmloff/xmltoken.hxx>
36
#include <xmloff/xmlerror.hxx>
37
#include <xmloff/maptype.hxx>
38
#include <xmloff/xmlimppr.hxx>
39
40
#include <xmlsdtypes.hxx>
41
42
using namespace ::com::sun::star;
43
using namespace ::com::sun::star::uno;
44
using namespace ::com::sun::star::beans;
45
using namespace ::com::sun::star::drawing;
46
using namespace ::xmloff::token;
47
48
49
XMLShapeStyleContext::XMLShapeStyleContext(
50
    SvXMLImport& rImport,
51
    SvXMLStylesContext& rStyles,
52
    XmlStyleFamily nFamily)
53
5.47k
:   XMLPropStyleContext(rImport, rStyles, nFamily ),
54
5.47k
    m_bIsNumRuleAlreadyConverted( false )
55
5.47k
{
56
5.47k
}
57
58
XMLShapeStyleContext::~XMLShapeStyleContext()
59
5.47k
{
60
5.47k
}
61
62
void XMLShapeStyleContext::SetAttribute( sal_Int32 nElement, const OUString& rValue )
63
12.0k
{
64
12.0k
    if (m_sControlDataStyleName.isEmpty() && (nElement & TOKEN_MASK) == XML_DATA_STYLE_NAME)
65
0
    {
66
0
        m_sControlDataStyleName = rValue;
67
0
    }
68
12.0k
    else if( nElement == XML_ELEMENT(STYLE, XML_LIST_STYLE_NAME) )
69
0
    {
70
0
        m_sListStyleName = rValue;
71
0
    }
72
12.0k
    else
73
12.0k
    {
74
12.0k
        XMLPropStyleContext::SetAttribute( nElement, rValue );
75
76
12.0k
        if( nElement == XML_ELEMENT(STYLE, XML_NAME) || nElement == XML_ELEMENT(STYLE, XML_DISPLAY_NAME) )
77
5.40k
        {
78
5.40k
            if( !GetName().isEmpty() && !GetDisplayName().isEmpty() && GetName() != GetDisplayName() )
79
1
            {
80
1
                GetImport().
81
1
                    AddStyleDisplayName( GetFamily(), GetName(), GetDisplayName() );
82
1
            }
83
5.40k
        }
84
12.0k
    }
85
12.0k
}
86
87
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeStyleContext::createFastChildContext(
88
    sal_Int32 nElement,
89
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
90
509
{
91
509
    if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) ||
92
138
        IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) )
93
371
    {
94
371
        sal_Int32 nLocalName = nElement & TOKEN_MASK;
95
371
        sal_uInt32 nFamily = 0;
96
371
        if( nLocalName == XML_TEXT_PROPERTIES )
97
24
            nFamily = XML_TYPE_PROP_TEXT;
98
347
        else if( nLocalName == XML_PARAGRAPH_PROPERTIES )
99
16
            nFamily = XML_TYPE_PROP_PARAGRAPH;
100
331
        else if( nLocalName == XML_GRAPHIC_PROPERTIES )
101
200
            nFamily = XML_TYPE_PROP_GRAPHIC;
102
371
        if( nFamily )
103
240
        {
104
240
            SvXMLImportPropertyMapper* pImpPrMap =
105
240
                GetStyles()->GetImportPropertyMapper( GetFamily() );
106
240
            if( pImpPrMap )
107
240
                return new XMLShapePropertySetContext( GetImport(), nElement, xAttrList,
108
240
                                                        nFamily,
109
240
                                                        GetProperties(),
110
240
                                                        pImpPrMap );
111
240
        }
112
371
    }
113
114
269
    return XMLPropStyleContext::createFastChildContext( nElement, xAttrList );
115
509
}
116
117
void XMLShapeStyleContext::FillPropertySet( const Reference< beans::XPropertySet > & rPropSet )
118
4.75k
{
119
4.75k
    if( !m_bIsNumRuleAlreadyConverted )
120
3.69k
    {
121
3.69k
        m_bIsNumRuleAlreadyConverted = true;
122
123
        // for compatibility to beta files, search for CTF_SD_NUMBERINGRULES_NAME to
124
        // import numbering rules from the style:properties element
125
3.69k
        const rtl::Reference< XMLPropertySetMapper >&rMapper = GetStyles()->GetImportPropertyMapper( GetFamily() )->getPropertySetMapper();
126
127
3.69k
        ::std::vector< XMLPropertyState > &rProperties = GetProperties();
128
3.69k
        ::std::vector< XMLPropertyState >::iterator end( rProperties.end() );
129
130
        // first, look for the old format, where we had a text:list-style-name
131
        // attribute in the style:properties element
132
55.1k
        auto property = std::find_if(rProperties.begin(), end, [&rMapper](XMLPropertyState& rProp) {
133
            // find properties with context
134
55.1k
            return (rProp.mnIndex != -1) && (rMapper->GetEntryContextId( rProp.mnIndex ) == CTF_SD_NUMBERINGRULES_NAME); });
135
136
        // if we did not find an old list-style-name in the properties, and we need one
137
        // because we got a style:list-style attribute in the style-style element
138
        // we generate one
139
3.69k
        if( (property == end) && ( !m_sListStyleName.isEmpty() ) )
140
0
        {
141
0
            sal_Int32 nIndex = rMapper->FindEntryIndex( CTF_SD_NUMBERINGRULES_NAME );
142
0
            SAL_WARN_IF( -1 == nIndex, "xmloff", "can't find numbering rules property entry, can't set numbering rule!" );
143
144
0
            XMLPropertyState aNewState( nIndex );
145
0
            rProperties.push_back( aNewState );
146
0
            end = rProperties.end();
147
0
            property = end - 1;
148
0
        }
149
150
        // so, if we have an old or a new list style name, we set its value to
151
        // a numbering rule
152
3.69k
        if( property != end )
153
0
        {
154
0
            if( m_sListStyleName.isEmpty() )
155
0
            {
156
0
                property->maValue >>= m_sListStyleName;
157
0
            }
158
159
0
            const SvxXMLListStyleContext *pListStyle = GetImport().GetTextImport()->FindAutoListStyle( m_sListStyleName );
160
161
0
            SAL_WARN_IF( !pListStyle, "xmloff", "list-style not found for shape style" );
162
0
            if( pListStyle )
163
0
            {
164
0
                uno::Reference< container::XIndexReplace > xNumRule( SvxXMLListStyleContext::CreateNumRule( GetImport().GetModel() ) );
165
0
                pListStyle->FillUnoNumRule(xNumRule);
166
0
                property->maValue <<= xNumRule;
167
0
            }
168
0
            else
169
0
            {
170
0
                property->mnIndex = -1;
171
0
            }
172
0
        }
173
3.69k
    }
174
175
4.75k
    struct ContextID_Index_Pair aContextIDs[] =
176
4.75k
    {
177
4.75k
        { CTF_DASHNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
178
4.75k
        { CTF_LINESTARTNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
179
4.75k
        { CTF_LINEENDNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
180
4.75k
        { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
181
4.75k
        { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
182
4.75k
        { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
183
4.75k
        { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
184
4.75k
        { CTF_SD_OLE_VIS_AREA_IMPORT_LEFT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
185
4.75k
        { CTF_SD_OLE_VIS_AREA_IMPORT_TOP, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
186
4.75k
        { CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
187
4.75k
        { CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
188
4.75k
        { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }
189
4.75k
    };
190
4.75k
    static const XmlStyleFamily aFamilies[] =
191
4.75k
    {
192
4.75k
        XmlStyleFamily::SD_STROKE_DASH_ID,
193
4.75k
        XmlStyleFamily::SD_MARKER_ID,
194
4.75k
        XmlStyleFamily::SD_MARKER_ID,
195
4.75k
        XmlStyleFamily::SD_GRADIENT_ID,
196
4.75k
        XmlStyleFamily::SD_GRADIENT_ID,
197
4.75k
        XmlStyleFamily::SD_HATCH_ID,
198
4.75k
        XmlStyleFamily::SD_FILL_IMAGE_ID
199
4.75k
    };
200
201
4.75k
    SvXMLImportPropertyMapper* pImpPrMap =
202
4.75k
        GetStyles()->GetImportPropertyMapper( GetFamily() );
203
4.75k
    assert( pImpPrMap );
204
4.75k
    pImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs );
205
206
4.75k
    Reference< XPropertySetInfo > xInfo;
207
    // get property set mapper
208
4.75k
    rtl::Reference<XMLPropertySetMapper> xPropMapper( pImpPrMap->getPropertySetMapper() );
209
210
57.1k
    for( sal_uInt16 i=0; aContextIDs[i].nContextID != -1; i++ )
211
52.3k
    {
212
52.3k
        sal_Int32 nIndex = aContextIDs[i].nIndex;
213
52.3k
        if( nIndex != -1 ) switch( aContextIDs[i].nContextID )
214
481
        {
215
0
        case CTF_DASHNAME:
216
225
        case CTF_LINESTARTNAME:
217
445
        case CTF_LINEENDNAME:
218
445
        case CTF_FILLGRADIENTNAME:
219
445
        case CTF_FILLTRANSNAME:
220
445
        case CTF_FILLHATCHNAME:
221
445
        case CTF_FILLBITMAPNAME:
222
445
        {
223
445
            struct XMLPropertyState& rState = GetProperties()[nIndex];
224
445
            OUString sStyleName;
225
445
            rState.maValue >>= sStyleName;
226
445
            sStyleName = GetImport().GetStyleDisplayName( aFamilies[i], sStyleName );
227
            // All of these attributes refer to something with draw:name
228
            // of type styleName = NCName which is non-empty.
229
            // tdf#89802: for Writer frames there would be no exception here but
230
            // it will fail later on attach() and take out the entire frame
231
445
            if (sStyleName.isEmpty() &&
232
445
                (   CTF_FILLGRADIENTNAME == aContextIDs[i].nContextID
233
445
                 || CTF_FILLTRANSNAME    == aContextIDs[i].nContextID
234
445
                 || CTF_FILLHATCHNAME    == aContextIDs[i].nContextID
235
445
                 || CTF_FILLBITMAPNAME   == aContextIDs[i].nContextID))
236
0
            {
237
0
                Sequence<OUString> const seq{ sStyleName };
238
0
                GetImport().SetError(
239
0
                    XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING,
240
0
                    seq, u"empty style name reference"_ustr, nullptr );
241
0
                break;
242
0
            }
243
244
445
            if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, aContextIDs[i].nExpectedFillStyle))
245
0
            {
246
0
                SAL_INFO("xmloff.style", "ShapeStyleContext: dropping fill named item: " << sStyleName);
247
0
                break; // ignore it, it's not used
248
0
            }
249
250
445
            try
251
445
            {
252
253
                // set property
254
445
                const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex);
255
445
                if( !xInfo.is() )
256
225
                    xInfo = rPropSet->getPropertySetInfo();
257
445
                if ( xInfo->hasPropertyByName( rPropertyName ) )
258
443
                {
259
443
                    rPropSet->setPropertyValue( rPropertyName, Any( sStyleName ) );
260
443
                }
261
445
            }
262
445
            catch ( const css::lang::IllegalArgumentException& e )
263
445
            {
264
0
                Sequence<OUString> aSeq { sStyleName };
265
0
                GetImport().SetError(
266
0
                    XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING,
267
0
                    aSeq, e.Message, nullptr );
268
0
            }
269
445
            break;
270
445
        }
271
0
        case CTF_SD_OLE_VIS_AREA_IMPORT_LEFT:
272
0
        case CTF_SD_OLE_VIS_AREA_IMPORT_TOP:
273
3
        case CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH:
274
36
        case CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT:
275
36
        {
276
36
            struct XMLPropertyState& rState = GetProperties()[nIndex];
277
36
            const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex);
278
36
            try
279
36
            {
280
36
                if( !xInfo.is() )
281
36
                    xInfo = rPropSet->getPropertySetInfo();
282
36
                if ( xInfo->hasPropertyByName( rPropertyName ) )
283
0
                {
284
0
                    rPropSet->setPropertyValue( rPropertyName, rState.maValue );
285
0
                }
286
36
            }
287
36
            catch ( const css::lang::IllegalArgumentException& e )
288
36
            {
289
0
                Sequence<OUString> aSeq;
290
0
                GetImport().SetError(
291
0
                    XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING,
292
0
                    aSeq, e.Message, nullptr );
293
0
            }
294
36
            break;
295
36
        }
296
481
        }
297
52.3k
    }
298
299
4.75k
    if (m_sControlDataStyleName.isEmpty())
300
4.75k
        return;
301
302
    // we had a data-style-name attribute
303
304
    // set the formatting on the control model of the control shape
305
0
    uno::Reference< drawing::XControlShape > xControlShape(rPropSet, uno::UNO_QUERY);
306
0
    DBG_ASSERT(xControlShape.is(), "XMLShapeStyleContext::FillPropertySet: data style for a non-control shape!");
307
0
    if (xControlShape.is())
308
0
    {
309
0
        uno::Reference< beans::XPropertySet > xControlModel(xControlShape->getControl(), uno::UNO_QUERY);
310
0
        DBG_ASSERT(xControlModel.is(), "XMLShapeStyleContext::FillPropertySet: no control model for the shape!");
311
0
        if (xControlModel.is())
312
0
        {
313
0
            GetImport().GetFormImport()->applyControlNumberStyle(xControlModel, m_sControlDataStyleName);
314
0
        }
315
0
    }
316
0
}
317
318
void XMLShapeStyleContext::Finish( bool /*bOverwrite*/ )
319
0
{
320
0
}
321
322
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */