Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/oox/source/ppt/pptshape.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 <oox/ppt/pptshape.hxx>
21
#include <oox/core/xmlfilterbase.hxx>
22
#include <drawingml/customshapeproperties.hxx>
23
#include <drawingml/textbody.hxx>
24
#include <drawingml/textparagraph.hxx>
25
#include <drawingml/textfield.hxx>
26
#include <editeng/flditem.hxx>
27
28
#include <com/sun/star/text/XTextField.hpp>
29
#include <com/sun/star/style/XStyle.hpp>
30
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
31
#include <com/sun/star/container/XNamed.hpp>
32
#include <com/sun/star/frame/XModel.hpp>
33
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
34
#include <com/sun/star/drawing/XDrawPage.hpp>
35
#include <com/sun/star/drawing/XDrawPages.hpp>
36
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
37
#include <com/sun/star/drawing/XShapes.hpp>
38
#include <com/sun/star/text/XText.hpp>
39
#include <com/sun/star/document/XEventsSupplier.hpp>
40
#include <com/sun/star/container/XNameReplace.hpp>
41
#include <com/sun/star/presentation/ClickAction.hpp>
42
#include <basegfx/matrix/b2dhommatrix.hxx>
43
#include <sal/log.hxx>
44
#include <oox/ppt/slidepersist.hxx>
45
#include <oox/token/tokens.hxx>
46
#include <oox/token/properties.hxx>
47
#include <o3tl/string_view.hxx>
48
49
using namespace ::oox::core;
50
using namespace ::oox::drawingml;
51
using namespace ::com::sun::star;
52
using namespace ::com::sun::star::awt;
53
using namespace ::com::sun::star::uno;
54
using namespace ::com::sun::star::beans;
55
using namespace ::com::sun::star::text;
56
using namespace ::com::sun::star::drawing;
57
using namespace ::com::sun::star::document;
58
using namespace ::com::sun::star::container;
59
using namespace ::com::sun::star::presentation;
60
61
namespace oox::ppt {
62
63
PPTShape::PPTShape( const oox::ppt::ShapeLocation eShapeLocation, const OUString& rServiceName )
64
130k
: Shape( rServiceName )
65
130k
, meShapeLocation( eShapeLocation )
66
130k
, mbReferenced( false )
67
130k
, mbHasNoninheritedShapeProperties( false )
68
130k
{
69
130k
}
70
71
PPTShape::~PPTShape()
72
130k
{
73
130k
}
74
75
static const char* lclDebugSubType( sal_Int32 nType )
76
0
{
77
0
    switch (nType) {
78
0
        case XML_ctrTitle :
79
0
            return "ctrTitle";
80
0
        case XML_title :
81
0
            return "title";
82
0
        case XML_subTitle :
83
0
            return "subTitle";
84
0
        case XML_obj :
85
0
            return "obj";
86
0
        case XML_body :
87
0
            return "body";
88
0
        case XML_dt :
89
0
            return "dt";
90
0
        case XML_hdr :
91
0
            return "hdr";
92
0
        case XML_ftr :
93
0
            return "frt";
94
0
        case XML_sldNum :
95
0
            return "sldNum";
96
0
        case XML_sldImg :
97
0
            return "sldImg";
98
0
    }
99
100
0
    return "unknown - please extend lclDebugSubType";
101
0
}
102
103
namespace
104
{
105
bool ShapeHasNoVisualPropertiesOnImport(const oox::ppt::PPTShape& rPPTShape)
106
24
{
107
24
    return  !rPPTShape.hasNonInheritedShapeProperties()
108
19
            && !rPPTShape.hasShapeStyleRefs()
109
19
            && !rPPTShape.getTextBody()->hasVisualRunProperties()
110
0
            && !rPPTShape.getTextBody()->hasNoninheritedBodyProperties()
111
0
            && !rPPTShape.getTextBody()->hasListStyleOnImport()
112
0
            && !rPPTShape.getTextBody()->hasParagraphProperties();
113
24
}
114
}
115
116
oox::drawingml::TextListStylePtr PPTShape::getSubTypeTextListStyle( const SlidePersist& rSlidePersist, sal_Int32 nSubType )
117
90
{
118
90
    oox::drawingml::TextListStylePtr pTextListStyle;
119
120
90
    SAL_INFO("oox.ppt", "subtype style: " << lclDebugSubType( nSubType ) );
121
122
90
    switch( nSubType )
123
90
    {
124
0
        case XML_ctrTitle :
125
0
        case XML_title :
126
0
            pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
127
0
            break;
128
0
        case XML_subTitle :
129
0
        case XML_obj :
130
87
        case XML_body :
131
87
            if ( rSlidePersist.isNotesPage() )
132
0
                pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
133
87
            else
134
87
                pTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
135
87
            break;
136
90
    }
137
138
90
    return pTextListStyle;
139
90
}
140
141
bool PPTShape::IsPlaceHolderCandidate(const SlidePersist& rSlidePersist) const
142
31.3k
{
143
31.3k
    if (meShapeLocation != Slide)
144
31.2k
        return false;
145
34
    if (rSlidePersist.isNotesPage())
146
5
        return false;
147
29
    auto pTextBody = getTextBody();
148
29
    if (!pTextBody)
149
0
        return false;
150
29
    auto rParagraphs = pTextBody->getParagraphs();
151
29
    if (rParagraphs.size() != 1)
152
5
        return false;
153
24
    if (rParagraphs.front()->getRuns().size() != 1)
154
0
        return false;
155
    // If the placeholder has a shape other than rectangle,
156
    // we have to place it in the slide as a CustomShape.
157
24
    if (!mpCustomShapePropertiesPtr->representsDefaultShape())
158
0
        return false;
159
24
    return ShapeHasNoVisualPropertiesOnImport(*this);
160
24
}
161
162
void PPTShape::setTextMasterStyles( const SlidePersist& rSlidePersist, const oox::core::XmlFilterBase& rFilterBase, const std::u16string_view& sType )
163
48.4k
{
164
48.4k
    if (!rSlidePersist.isMasterPage())
165
0
        return;
166
167
48.4k
    try
168
48.4k
    {
169
48.4k
        Reference< style::XStyleFamiliesSupplier > aXStyleFamiliesSupplier(rFilterBase.getModel(), UNO_QUERY_THROW);
170
48.4k
        Reference< container::XNameAccess > aXNameAccess(aXStyleFamiliesSupplier->getStyleFamilies());
171
172
48.4k
        if (!aXNameAccess.is())
173
0
            return;
174
175
48.4k
        Reference< container::XNamed > aXNamed(rSlidePersist.getPage(), UNO_QUERY_THROW);
176
48.4k
        OUString aFamily = aXNamed->getName();
177
178
48.4k
        if (!aXNameAccess->hasByName(aFamily))
179
0
            return;
180
181
48.4k
        Reference< container::XNameAccess > xFamilies;
182
48.4k
        if (aXNameAccess->getByName(aFamily) >>= xFamilies)
183
48.4k
        {
184
48.4k
            OUString aStyle;
185
48.4k
            if (sType == u"com.sun.star.presentation.TitleTextShape") // title style
186
12.2k
                aStyle = u"title"_ustr;
187
36.1k
            else if (sType == u"com.sun.star.presentation.SubtitleShape") // subtitle
188
379
                aStyle = u"subtitle"_ustr;
189
35.7k
            else if (sType == u"com.sun.star.presentation.OutlinerShape") // body style
190
13.2k
                aStyle = u"outline1"_ustr;
191
22.5k
            else if (sType == u"com.sun.star.presentation.NotesShape") // notes style
192
0
                aStyle = u"title"_ustr;
193
194
48.4k
            if (!xFamilies->hasByName(aStyle))
195
22.5k
                return;
196
197
25.8k
            Reference< style::XStyle > aXStyle;
198
25.8k
            if (xFamilies->getByName(aStyle) >>= aXStyle)
199
25.8k
            {
200
25.8k
                TextCharacterProperties aCharStyleProperties;
201
25.8k
                getTextBody()->ApplyMasterTextStyle(rFilterBase, aXStyle, aCharStyleProperties,
202
25.8k
                                                    mpMasterTextListStyle, size_t(0));
203
25.8k
                if (aStyle.equals(u"outline1"_ustr)/* BodyStyle */)
204
13.2k
                {
205
118k
                    for (size_t nLevel = 2; nLevel < 10; nLevel++) // outline2 ... outline9
206
105k
                    {
207
105k
                        char pOutline[9] = "outline1";
208
105k
                        pOutline[7] = static_cast<char>('0' + nLevel);
209
105k
                        OUString sOutlineStyle(OUString::createFromAscii(pOutline));
210
105k
                        if (xFamilies->hasByName(sOutlineStyle))
211
105k
                        {
212
105k
                            if (aXStyle.is())
213
105k
                                aXStyle.clear();
214
215
105k
                            xFamilies->getByName(sOutlineStyle) >>= aXStyle;
216
105k
                            if (aXStyle.is())
217
105k
                            {
218
105k
                                TextCharacterProperties aCharStyleLvlProps;
219
105k
                                getTextBody()->ApplyMasterTextStyle(rFilterBase, aXStyle, aCharStyleLvlProps, mpMasterTextListStyle, nLevel - 1);
220
105k
                            }
221
105k
                        }
222
105k
                    }
223
13.2k
                }
224
25.8k
            }
225
25.8k
        }
226
48.4k
    }
227
48.4k
    catch (const Exception&)
228
48.4k
    {
229
0
    }
230
48.4k
}
231
232
void PPTShape::addShape(
233
        oox::core::XmlFilterBase& rFilterBase,
234
        const SlidePersist& rSlidePersist,
235
        const oox::drawingml::Theme* pTheme,
236
        const Reference< XShapes >& rxShapes,
237
        basegfx::B2DHomMatrix& aTransformation,
238
        ::oox::drawingml::ShapeIdMap* pShapeMap )
239
88.6k
{
240
88.6k
    SAL_INFO("oox.ppt","add shape id: " << msId << " location: " << ((meShapeLocation == Master) ? "master" : ((meShapeLocation == Slide) ? "slide" : ((meShapeLocation == Layout) ? "layout" : "other"))) << " subtype: " << mnSubType << " service: " << msServiceName);
241
242
88.6k
    OUString sServiceName( msServiceName );
243
88.6k
    if (sServiceName.isEmpty())
244
0
        return;
245
88.6k
    try
246
88.6k
    {
247
88.6k
        oox::drawingml::TextListStylePtr aMasterTextListStyle;
248
88.6k
        Reference<lang::XMultiServiceFactory> xServiceFact(rFilterBase.getModel(), UNO_QUERY_THROW);
249
88.6k
        bool bClearText = false;
250
251
88.6k
        if (sServiceName != "com.sun.star.drawing.GraphicObjectShape" &&
252
87.3k
            sServiceName != "com.sun.star.drawing.OLE2Shape")
253
87.2k
        {
254
87.2k
            static constexpr OUString sOutlinerShapeService(u"com.sun.star.presentation.OutlinerShape"_ustr);
255
87.2k
            SAL_INFO("oox.ppt","has master: " << std::hex << rSlidePersist.getMasterPersist().get());
256
87.2k
            switch (mnSubType)
257
87.2k
            {
258
609
                case XML_ctrTitle :
259
16.9k
                case XML_title :
260
16.9k
                {
261
16.9k
                    sServiceName = "com.sun.star.presentation.TitleTextShape";
262
16.9k
                    aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getTitleTextStyle() : rSlidePersist.getTitleTextStyle();
263
16.9k
                }
264
16.9k
                break;
265
1.37k
                case XML_subTitle :
266
1.37k
                {
267
1.37k
                    sServiceName = "com.sun.star.presentation.SubtitleShape";
268
1.37k
                    aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
269
1.37k
                }
270
1.37k
                break;
271
2.41k
                   case XML_obj :
272
2.41k
                {
273
2.41k
                    sServiceName = sOutlinerShapeService;
274
2.41k
                    if (getSubTypeIndex().has_value())
275
2.41k
                        aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
276
2.41k
                }
277
2.41k
                break;
278
20.4k
                case XML_body :
279
20.4k
                {
280
20.4k
                    if (rSlidePersist.isNotesPage())
281
95
                    {
282
95
                        sServiceName = "com.sun.star.presentation.NotesShape";
283
95
                        aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getNotesTextStyle() : rSlidePersist.getNotesTextStyle();
284
95
                    }
285
20.3k
                    else
286
20.3k
                    {
287
20.3k
                        sServiceName = sOutlinerShapeService;
288
20.3k
                        aMasterTextListStyle = rSlidePersist.getMasterPersist() ? rSlidePersist.getMasterPersist()->getBodyTextStyle() : rSlidePersist.getBodyTextStyle();
289
20.3k
                    }
290
20.4k
                }
291
20.4k
                break;
292
10.5k
                case XML_dt :
293
10.5k
                    if (IsPlaceHolderCandidate(rSlidePersist))
294
0
                    {
295
0
                        TextRunPtr& pTextRun = getTextBody()->getParagraphs().front()->getRuns().front();
296
0
                        oox::drawingml::TextField* pTextField = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
297
0
                        if (pTextField)
298
0
                        {
299
0
                            OUString aType = pTextField->getType();
300
0
                            if ( aType.startsWith("datetime") )
301
0
                            {
302
0
                                SvxDateFormat eDateFormat = drawingml::TextField::getLODateFormat(aType);
303
0
                                SvxTimeFormat eTimeFormat = drawingml::TextField::getLOTimeFormat(aType);
304
0
                                Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
305
306
0
                                if( eDateFormat != SvxDateFormat::AppDefault
307
0
                                    || eTimeFormat != SvxTimeFormat::AppDefault )
308
0
                                {
309
                                    // DateTimeFormat property looks for the date in 4 LSBs
310
                                    // and looks for time format in the 4 bits after that
311
0
                                    sal_Int32 nDateTimeFormat = static_cast<sal_Int32>(eDateFormat) |
312
0
                                                                static_cast<sal_Int32>(eTimeFormat) << 4;
313
0
                                    xPropertySet->setPropertyValue( u"IsDateTimeVisible"_ustr, Any(true) );
314
0
                                    xPropertySet->setPropertyValue( u"IsDateTimeFixed"_ustr, Any(false) );
315
0
                                    xPropertySet->setPropertyValue( u"DateTimeFormat"_ustr, Any(nDateTimeFormat) );
316
0
                                    return;
317
0
                                }
318
0
                            }
319
0
                        }
320
0
                    }
321
10.5k
                    sServiceName = "com.sun.star.presentation.DateTimeShape";
322
10.5k
                    bClearText = true;
323
10.5k
                break;
324
0
                case XML_hdr :
325
0
                    sServiceName = "com.sun.star.presentation.HeaderShape";
326
0
                    bClearText = true;
327
0
                break;
328
10.3k
                case XML_ftr :
329
10.3k
                    if (IsPlaceHolderCandidate(rSlidePersist))
330
0
                    {
331
0
                        const OUString aFooterText = getTextBody()->toString();
332
333
0
                        if( !aFooterText.isEmpty() )
334
0
                        {
335
                            // if it is possible to get the footer as a property the LO way,
336
                            // get it and discard the shape
337
0
                            Reference< XPropertySet > xPropertySet( rSlidePersist.getPage(), UNO_QUERY );
338
0
                            xPropertySet->setPropertyValue( u"IsFooterVisible"_ustr, Any( true ) );
339
0
                            xPropertySet->setPropertyValue( u"FooterText"_ustr, Any(aFooterText) );
340
0
                            return;
341
0
                        }
342
0
                    }
343
10.3k
                    sServiceName = "com.sun.star.presentation.FooterShape";
344
10.3k
                    bClearText = true;
345
10.3k
                break;
346
10.5k
                case XML_sldNum :
347
10.5k
                    if (IsPlaceHolderCandidate(rSlidePersist))
348
0
                    {
349
0
                        TextRunPtr& pTextRun
350
0
                            = getTextBody()->getParagraphs().front()->getRuns().front();
351
0
                        oox::drawingml::TextField* pTextField
352
0
                            = dynamic_cast<oox::drawingml::TextField*>(pTextRun.get());
353
0
                        if (pTextField && pTextField->getType() == "slidenum")
354
0
                        {
355
                            // if it is possible to get the slidenum placeholder as a property
356
                            // do that and discard the shape
357
0
                            Reference<XPropertySet> xPropertySet(rSlidePersist.getPage(),
358
0
                                                                 UNO_QUERY);
359
0
                            xPropertySet->setPropertyValue(u"IsPageNumberVisible"_ustr, Any(true));
360
0
                            return;
361
0
                        }
362
0
                    }
363
10.5k
                    sServiceName = "com.sun.star.presentation.SlideNumberShape";
364
10.5k
                    bClearText = true;
365
10.5k
                break;
366
31
                case XML_sldImg :
367
31
                    sServiceName = "com.sun.star.presentation.PageShape";
368
31
                break;
369
12
                case XML_chart :
370
12
                    if (meShapeLocation == Layout)
371
12
                        sServiceName = sOutlinerShapeService;
372
0
                    else
373
0
                        sServiceName = "com.sun.star.presentation.ChartShape";
374
12
                break;
375
0
                case XML_tbl :
376
0
                    if (meShapeLocation == Layout)
377
0
                        sServiceName = sOutlinerShapeService;
378
0
                    else
379
0
                        sServiceName = "com.sun.star.presentation.TableShape";
380
0
                break;
381
373
                case XML_pic :
382
                    // <p:ph type="pic"/> is a real picture placeholder on both
383
                    // slides and layouts, so the layout's type survives PPTX
384
                    // round-trip and slide-side inheritance can resolve it.
385
373
                    sServiceName = "com.sun.star.presentation.GraphicObjectShape";
386
373
                break;
387
0
                case XML_media :
388
0
                    if (meShapeLocation == Layout)
389
0
                        sServiceName = sOutlinerShapeService;
390
0
                    else
391
0
                        sServiceName = "com.sun.star.presentation.MediaShape";
392
0
                break;
393
14.4k
                default:
394
14.4k
                    if (mnSubType && meShapeLocation == Layout)
395
0
                        sServiceName = sOutlinerShapeService;
396
14.4k
                break;
397
87.2k
            }
398
87.2k
        }
399
400
        // Since it is not possible to represent custom shaped placeholders in Impress
401
        // Need to use service name css.drawing.CustomShape if they have a non default shape.
402
        // This workaround has the drawback of them not really being processed as placeholders
403
        // so it is done for slide footers and obj placeholder
404
88.6k
        bool convertInSlideMode
405
88.6k
            = meShapeLocation == Slide
406
5.40k
              && (mnSubType == XML_sldNum || mnSubType == XML_dt || mnSubType == XML_ftr
407
5.36k
                  || mnSubType == XML_body
408
5.25k
                  || (mnSubType == XML_obj
409
77
                      && sServiceName != "com.sun.star.drawing.GraphicObjectShape"));
410
411
88.6k
        bool convertInLayoutMode = meShapeLocation == Layout && (mnSubType == XML_body);
412
88.6k
        if ((convertInSlideMode || convertInLayoutMode) && !mpCustomShapePropertiesPtr->representsDefaultShape())
413
0
        {
414
0
            sServiceName = "com.sun.star.drawing.CustomShape";
415
0
        }
416
417
88.6k
        SAL_INFO("oox.ppt","shape service: " << sServiceName);
418
419
88.6k
        if (mnSubType && getSubTypeIndex().has_value() && meShapeLocation == Layout)
420
18.7k
        {
421
18.7k
            oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex( getSubTypeIndex().value(), rSlidePersist.getShapes()->getChildren(), true );
422
18.7k
            if (!pPlaceholder)
423
15.1k
                pPlaceholder = PPTShape::findPlaceholder( mnSubType, 0, getSubTypeIndex(), rSlidePersist.getShapes()->getChildren(), true );
424
425
18.7k
            if (pPlaceholder) {
426
11.7k
                if (maSize.Width == 0 || maSize.Height == 0) {
427
0
                    awt::Size aSize = maSize;
428
0
                    if (maSize.Width == 0)
429
0
                        aSize.Width = pPlaceholder->getSize().Width;
430
0
                    if (maSize.Height == 0)
431
0
                        aSize.Height = pPlaceholder->getSize().Height;
432
0
                    setSize( aSize );
433
0
                    if (maPosition.X == 0 || maPosition.Y == 0) {
434
0
                        awt::Point aPosition = maPosition;
435
0
                        if (maPosition.X == 0)
436
0
                            aPosition.X = pPlaceholder->getPosition().X;
437
0
                        if (maPosition.Y == 0)
438
0
                            aPosition.Y = pPlaceholder->getPosition().Y;
439
0
                        setPosition( aPosition );
440
0
                    }
441
0
                }
442
11.7k
            }
443
18.7k
        }
444
445
        // use placeholder index if possible
446
88.6k
        if (mnSubType && getSubTypeIndex().has_value() && rSlidePersist.getMasterPersist())
447
256
        {
448
256
            oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex(getSubTypeIndex().value(), rSlidePersist.getMasterPersist()->getShapes()->getChildren());
449
            // TODO: Check if this is required for non-notes slides as well...
450
256
            if (rSlidePersist.isNotesPage() && pPlaceholder && pPlaceholder->getSubType() != getSubType())
451
16
                pPlaceholder.reset();
452
453
256
            if (pPlaceholder) {
454
178
                SAL_INFO("oox.ppt","found placeholder with index: " << getSubTypeIndex().value() << " and type: " << lclDebugSubType( mnSubType ));
455
178
                PPTShape* pPPTPlaceholder = dynamic_cast< PPTShape* >( pPlaceholder.get() );
456
178
                TextListStylePtr pNewTextListStyle = std::make_shared<TextListStyle>();
457
458
178
                if (pPlaceholder->getTextBody()) {
459
460
178
                    pNewTextListStyle->apply( pPlaceholder->getTextBody()->getTextListStyle() );
461
178
                    if (pPlaceholder->getMasterTextListStyle())
462
178
                        pNewTextListStyle->apply( *pPlaceholder->getMasterTextListStyle() );
463
464
                    // SAL_INFO("oox.ppt","placeholder body style");
465
                    // pPlaceholder->getTextBody()->getTextListStyle().dump();
466
                    // SAL_INFO("oox.ppt","master text list style");
467
                    // pPlaceholder->getMasterTextListStyle()->dump();
468
469
178
                    aMasterTextListStyle = pNewTextListStyle;
470
                    // SAL_INFO("oox.ppt","combined master text list style");
471
                    // aMasterTextListStyle->dump();
472
178
                }
473
178
                if (pPPTPlaceholder && pPPTPlaceholder->mpPlaceholder) {
474
90
                    SAL_INFO("oox.ppt","placeholder has parent placeholder: " << pPPTPlaceholder->mpPlaceholder->getId() << " type: " << lclDebugSubType( pPPTPlaceholder->mpPlaceholder->getSubType() ) << " index: " << pPPTPlaceholder->mpPlaceholder->getSubTypeIndex().value() );
475
90
                    SAL_INFO("oox.ppt","has textbody " << (pPPTPlaceholder->mpPlaceholder->getTextBody() != nullptr) );
476
90
                    TextListStylePtr pPlaceholderStyle = getSubTypeTextListStyle( rSlidePersist, pPPTPlaceholder->mpPlaceholder->getSubType() );
477
90
                    if (pPPTPlaceholder->mpPlaceholder->getTextBody())
478
90
                        pNewTextListStyle->apply( pPPTPlaceholder->mpPlaceholder->getTextBody()->getTextListStyle() );
479
90
                    if (pPlaceholderStyle) {
480
87
                        pNewTextListStyle->apply( *pPlaceholderStyle );
481
                        //pPlaceholderStyle->dump();
482
87
                    }
483
90
                }
484
178
            } else if (!mpPlaceholder) {
485
58
                aMasterTextListStyle.reset();
486
58
            }
487
256
            SAL_INFO("oox.ppt","placeholder id: " << (pPlaceholder ? pPlaceholder->getId() : u"not found"_ustr));
488
256
        }
489
490
88.6k
        if (!sServiceName.isEmpty())
491
88.6k
        {
492
88.6k
            if (!aMasterTextListStyle)
493
47.5k
            {
494
47.5k
                bool isOther = !getTextBody() && sServiceName != "com.sun.star.drawing.GroupShape";
495
47.5k
                TextListStylePtr aSlideStyle = isOther ? rSlidePersist.getOtherTextStyle() : rSlidePersist.getDefaultTextStyle();
496
                // Combine from MasterSlide details as well.
497
47.5k
                if (rSlidePersist.getMasterPersist())
498
2.87k
                {
499
2.87k
                    aMasterTextListStyle = isOther ? rSlidePersist.getMasterPersist()->getOtherTextStyle() : rSlidePersist.getMasterPersist()->getDefaultTextStyle();
500
2.87k
                    if (aSlideStyle)
501
2.87k
                        aMasterTextListStyle->apply( *aSlideStyle );
502
2.87k
                }
503
44.6k
                else
504
44.6k
                {
505
44.6k
                    aMasterTextListStyle = std::move(aSlideStyle);
506
44.6k
                }
507
47.5k
            }
508
509
88.6k
            if( aMasterTextListStyle && getTextBody() ) {
510
80.5k
                TextListStylePtr aCombinedTextListStyle = std::make_shared<TextListStyle>();
511
512
80.5k
                aCombinedTextListStyle->apply( *aMasterTextListStyle );
513
514
80.5k
                if( mpPlaceholder && mpPlaceholder->getTextBody() )
515
21.3k
                    aCombinedTextListStyle->apply( mpPlaceholder->getTextBody()->getTextListStyle() );
516
80.5k
                aCombinedTextListStyle->apply( getTextBody()->getTextListStyle() );
517
518
80.5k
                setMasterTextListStyle( aCombinedTextListStyle );
519
80.5k
            } else
520
8.14k
                setMasterTextListStyle( aMasterTextListStyle );
521
522
88.6k
            if (mnSubType && meShapeLocation == Master)
523
34.7k
            {
524
34.7k
                if (getTextBody() && !getTextBody()->isEmpty())
525
30.5k
                    setTextMasterStyles(rSlidePersist, rFilterBase, sServiceName);
526
34.7k
                return;
527
34.7k
            }
528
529
53.8k
            Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, bClearText, mpPlaceholder, aTransformation, getFillProperties() ) );
530
531
            // Apply text properties on placeholder text inside this placeholder shape
532
53.8k
            if (meShapeLocation == Slide && mpPlaceholder && getTextBody() && getTextBody()->isEmpty())
533
252
            {
534
252
                Reference < XText > xText(mxShape, UNO_QUERY);
535
252
                if (xText.is())
536
236
                {
537
236
                    TextCharacterProperties aCharStyleProperties;
538
236
                    getTextBody()->ApplyStyleEmpty(rFilterBase, xText, aCharStyleProperties, mpMasterTextListStyle);
539
236
                }
540
252
            }
541
            // Apply text properties on master placeholder styles
542
53.8k
            if (meShapeLocation == Layout && getTextBody() && !getTextBody()->isEmpty())
543
17.8k
            {
544
17.8k
                setTextMasterStyles(rSlidePersist, rFilterBase, sServiceName);
545
17.8k
            }
546
53.8k
            if (pShapeMap)
547
53.8k
            {
548
                // bnc#705982 - if optional model id reference is
549
                // there, use that to obtain target shape
550
53.8k
                if (!msModelId.isEmpty())
551
0
                {
552
0
                    (*pShapeMap)[ msModelId ] = shared_from_this();
553
0
                }
554
53.8k
                else if (!msId.isEmpty())
555
53.8k
                {
556
53.8k
                    (*pShapeMap)[ msId ] = shared_from_this();
557
53.8k
                }
558
53.8k
            }
559
560
            // we will be losing whatever information there is in the footer placeholder on master/layout slides
561
            // since they should have the "<footer>" textfield in them in order to make LibreOffice process them as expected
562
            // likewise DateTime placeholder data on master/layout slides will be lost and replaced
563
53.8k
            if( (mnSubType == XML_ftr || mnSubType == XML_dt) && meShapeLocation != Slide )
564
8.63k
            {
565
8.63k
                OUString aFieldType;
566
8.63k
                if( mnSubType == XML_ftr )
567
4.31k
                    aFieldType = "com.sun.star.presentation.TextField.Footer";
568
4.31k
                else
569
4.31k
                    aFieldType = "com.sun.star.presentation.TextField.DateTime";
570
8.63k
                Reference < XTextField > xField( xServiceFact->createInstance( aFieldType ), UNO_QUERY );
571
8.63k
                Reference < XText > xText(mxShape, UNO_QUERY);
572
8.63k
                if(xText.is())
573
8.63k
                {
574
8.63k
                    xText->setString(u""_ustr);
575
8.63k
                    Reference < XTextCursor > xTextCursor = xText->createTextCursor();
576
8.63k
                    xText->insertTextContent( xTextCursor, xField, false);
577
8.63k
                }
578
8.63k
            }
579
580
53.8k
            OUString sURL;
581
53.8k
            std::vector<std::pair<OUString, Reference<XShape>>> aURLShapes;
582
            // if this is a group shape, we have to add also each child shape
583
53.8k
            Reference<XShapes> xShapes(xShape, UNO_QUERY);
584
53.8k
            if (xShapes.is())
585
8
            {
586
                // temporarily remember setting
587
8
                NamedShapePairs* pDiagramFontHeights(rFilterBase.getDiagramFontHeights());
588
589
                // for shapes unequal to FRAMETYPE_DIAGRAM do
590
                // disable DiagramFontHeights recording
591
8
                if (meFrameType != FRAMETYPE_DIAGRAM)
592
8
                    rFilterBase.setDiagramFontHeights(nullptr);
593
594
8
                addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aTransformation );
595
596
                // restore remembered setting
597
8
                rFilterBase.setDiagramFontHeights(pDiagramFontHeights);
598
599
24
                for (size_t i = 0; i < this->getChildren().size(); i++)
600
16
                {
601
16
                    this->getChildren()[i]->getShapeProperties().getProperty(PROP_URL) >>= sURL;
602
16
                    if (!sURL.isEmpty())
603
0
                    {
604
0
                        Reference<XShape> xChild = this->getChildren()[i]->getXShape();
605
0
                        aURLShapes.push_back({ sURL, xChild });
606
0
                    }
607
16
                }
608
8
            }
609
610
            // Support advanced DiagramHelper
611
53.8k
            if (FRAMETYPE_DIAGRAM == meFrameType)
612
0
            {
613
0
                propagateDiagramHelper();
614
0
            }
615
616
53.8k
            getShapeProperties().getProperty(PROP_URL) >>= sURL;
617
53.8k
            if (!sURL.isEmpty() && !xShapes.is())
618
0
                aURLShapes.push_back({ sURL, xShape });
619
620
53.8k
            if (!aURLShapes.empty())
621
0
            {
622
0
                for (auto const& URLShape : aURLShapes)
623
0
                {
624
0
                    Reference<XEventsSupplier> xEventsSupplier(URLShape.second, UNO_QUERY);
625
0
                    if (!xEventsSupplier.is())
626
0
                        return;
627
628
0
                    Reference<XNameReplace> xEvents(xEventsSupplier->getEvents());
629
0
                    if (!xEvents.is())
630
0
                        return;
631
632
0
                    OUString sAPIEventName;
633
0
                    sal_Int32 nPropertyCount = 2;
634
0
                    css::presentation::ClickAction meClickAction;
635
0
                    uno::Sequence<beans::PropertyValue> aProperties;
636
637
0
                    std::map<OUString, css::presentation::ClickAction> ActionMap = {
638
0
                        { "#action?jump=nextslide", ClickAction_NEXTPAGE },
639
0
                        { "#action?jump=previousslide", ClickAction_PREVPAGE },
640
0
                        { "#action?jump=firstslide", ClickAction_FIRSTPAGE },
641
0
                        { "#action?jump=lastslide", ClickAction_LASTPAGE },
642
0
                        { "#action?jump=endshow", ClickAction_STOPPRESENTATION },
643
0
                    };
644
645
0
                    sURL = URLShape.first;
646
0
                    std::map<OUString, css::presentation::ClickAction>::const_iterator aIt
647
0
                        = ActionMap.find(sURL);
648
0
                    aIt != ActionMap.end() ? meClickAction = aIt->second
649
0
                                           : meClickAction = ClickAction_BOOKMARK;
650
651
                    // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same event
652
                    // so check here if it's a bookmark or a document
653
0
                    if (meClickAction == ClickAction_BOOKMARK)
654
0
                    {
655
0
                        if (!sURL.startsWith("#"))
656
0
                            meClickAction = ClickAction_DOCUMENT;
657
0
                        else
658
0
                        {
659
0
                            sURL = OUString::Concat("page")
660
0
                                   + sURL.subView(sURL.lastIndexOf(' ') + 1);
661
0
                        }
662
0
                        nPropertyCount += 1;
663
0
                    }
664
665
0
                    aProperties.realloc(nPropertyCount);
666
0
                    beans::PropertyValue* pProperties = aProperties.getArray();
667
668
0
                    pProperties->Name = "EventType";
669
0
                    pProperties->Handle = -1;
670
0
                    pProperties->Value <<= u"Presentation"_ustr;
671
0
                    pProperties->State = beans::PropertyState_DIRECT_VALUE;
672
0
                    pProperties++;
673
674
0
                    pProperties->Name = "ClickAction";
675
0
                    pProperties->Handle = -1;
676
0
                    pProperties->Value <<= meClickAction;
677
0
                    pProperties->State = beans::PropertyState_DIRECT_VALUE;
678
0
                    pProperties++;
679
680
0
                    switch (meClickAction)
681
0
                    {
682
0
                        case ClickAction_BOOKMARK:
683
0
                        case ClickAction_DOCUMENT:
684
0
                            pProperties->Name = "Bookmark";
685
0
                            pProperties->Handle = -1;
686
0
                            pProperties->Value <<= sURL;
687
0
                            pProperties->State = beans::PropertyState_DIRECT_VALUE;
688
0
                            break;
689
0
                        default:
690
0
                            break;
691
0
                    }
692
693
0
                    sAPIEventName = "OnClick";
694
0
                    xEvents->replaceByName(sAPIEventName, uno::Any(aProperties));
695
0
                }
696
0
            }
697
53.8k
        }
698
88.6k
    }
699
88.6k
    catch (const Exception&)
700
88.6k
    {
701
0
    }
702
88.6k
}
703
704
namespace
705
{
706
    bool ShapeLocationIsMaster(oox::drawingml::Shape *pInShape)
707
427k
    {
708
427k
        PPTShape* pShape = dynamic_cast<PPTShape*>(pInShape);
709
427k
        return pShape && pShape->getShapeLocation() == Master;
710
427k
    }
711
}
712
713
// Function to find placeholder (ph) for a shape. No idea how MSO implements this, but
714
// this order seems to work quite well
715
// (probably it's unnecessary complicated / wrong. i.e. tdf#104202):
716
// 1. ph with nFirstSubType and the same oSubTypeIndex
717
// 2. ph with nFirstSubType
718
// 3. ph with nSecondSubType and the same oSubTypeIndex
719
// 4. ph with nSecondSubType
720
// 5. ph with the same oSubTypeIndex
721
722
oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType,
723
    const std::optional< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
724
135k
{
725
135k
    class Placeholders
726
135k
    {
727
135k
    public:
728
135k
        Placeholders()
729
135k
            : aChoice(5) // resize to 5
730
135k
        {
731
135k
        }
732
733
135k
        void add(const oox::drawingml::ShapePtr& aShape, sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, const std::optional< sal_Int32 >& oSubTypeIndex)
734
195k
        {
735
195k
            if (!aShape)
736
0
                return;
737
738
            // get flags
739
195k
            const bool bSameFirstSubType = aShape->getSubType() == nFirstSubType;
740
195k
            const bool bSameSecondSubType = aShape->getSubType() == nSecondSubType;
741
195k
            const bool bSameIndex = aShape->getSubTypeIndex() == oSubTypeIndex;
742
743
            // get prio
744
195k
            int aPrioIndex = -1;
745
195k
            if (bSameIndex && bSameFirstSubType)
746
20.1k
                aPrioIndex = 0;
747
174k
            else if (!bSameIndex && bSameFirstSubType)
748
33.8k
                aPrioIndex = 1;
749
141k
            else if (bSameIndex && bSameSecondSubType)
750
12.4k
                aPrioIndex = 2;
751
128k
            else if (!bSameIndex && bSameSecondSubType)
752
19.8k
                aPrioIndex = 3;
753
108k
            else if (bSameIndex)
754
18.8k
                aPrioIndex = 4;
755
756
            // add
757
195k
            if (aPrioIndex != -1)
758
105k
            {
759
105k
                if (!aChoice.at(aPrioIndex))
760
94.2k
                {
761
94.2k
                    aChoice.at(aPrioIndex) = aShape;
762
94.2k
                }
763
105k
            }
764
195k
        }
765
766
        // return according to prio
767
135k
        oox::drawingml::ShapePtr getByPrio() const
768
135k
        {
769
135k
            for (const oox::drawingml::ShapePtr& aShape : aChoice)
770
486k
            {
771
486k
                if (aShape)
772
59.7k
                {
773
59.7k
                    return aShape;
774
59.7k
                }
775
486k
            }
776
777
75.7k
            return oox::drawingml::ShapePtr();
778
135k
        }
779
780
135k
        bool hasByPrio(size_t aIndex) const
781
407k
        {
782
407k
            return bool(aChoice.at(aIndex));
783
407k
        }
784
785
135k
    private:
786
135k
        std::vector< oox::drawingml::ShapePtr > aChoice;
787
788
135k
    } aPlaceholders;
789
790
    // check all shapes
791
135k
    std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
792
522k
    for (; aRevIter != rShapes.rend(); ++aRevIter)
793
407k
    {
794
        // check shape
795
407k
        if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
796
165k
        {
797
165k
            const oox::drawingml::ShapePtr& aShape = *aRevIter;
798
165k
            aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
799
165k
        }
800
801
        // check children
802
407k
        std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
803
407k
        if (!rChildren.empty())
804
82.4k
        {
805
82.4k
            const oox::drawingml::ShapePtr aShape = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
806
82.4k
            if (aShape)
807
29.8k
            {
808
29.8k
                aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
809
29.8k
            }
810
82.4k
        }
811
812
407k
        if (aPlaceholders.hasByPrio(0))
813
20.1k
        {
814
20.1k
            break;
815
20.1k
        }
816
407k
    }
817
818
    // return something according to prio
819
135k
    return aPlaceholders.getByPrio();
820
135k
}
821
822
oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
823
203k
{
824
203k
    oox::drawingml::ShapePtr aShapePtr;
825
826
203k
    std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
827
383k
    while( aRevIter != rShapes.rend() )
828
187k
    {
829
187k
        if ( (*aRevIter)->getSubTypeIndex().has_value() && (*aRevIter)->getSubTypeIndex().value() == nIdx &&
830
22.6k
             ( !bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()) ) )
831
3.86k
        {
832
3.86k
            aShapePtr = *aRevIter;
833
3.86k
            break;
834
3.86k
        }
835
184k
        std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
836
184k
        aShapePtr = findPlaceholderByIndex( nIdx, rChildren, bMasterOnly );
837
184k
        if ( aShapePtr )
838
3.86k
            break;
839
180k
        ++aRevIter;
840
180k
    }
841
203k
    return aShapePtr;
842
203k
}
843
844
}
845
846
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */