Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/gallery2/galobj.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 <sal/config.h>
21
22
#include <com/sun/star/frame/XModel.hpp>
23
#include <com/sun/star/frame/XModel3.hpp>
24
#include <sfx2/objsh.hxx>
25
#include <comphelper/fileformat.h>
26
#include <comphelper/servicehelper.hxx>
27
#include <tools/vcompat.hxx>
28
#include <tools/helpers.hxx>
29
#include <tools/stream.hxx>
30
#include <vcl/virdev.hxx>
31
#include <svx/fmmodel.hxx>
32
#include <svx/fmview.hxx>
33
#include <svx/fmpage.hxx>
34
#include <svx/galmisc.hxx>
35
#include <galobj.hxx>
36
#include <vcl/dibtools.hxx>
37
#include <vcl/filter/SvmReader.hxx>
38
#include <vcl/filter/SvmWriter.hxx>
39
#include "gallerydrawmodel.hxx"
40
#include <bitmaps.hlst>
41
42
using namespace ::com::sun::star;
43
44
SgaObject::SgaObject()
45
0
:   bIsValid    ( false ),
46
0
    bIsThumbBmp ( true )
47
0
{
48
0
}
49
50
SgaObject::SgaObject(const SgaObject& aObject)
51
0
    : aThumbBmp(aObject.aThumbBmp)
52
0
    , aThumbMtf(aObject.aThumbMtf)
53
0
    , aURL(aObject.aURL)
54
0
    , aTitle(aObject.aTitle)
55
0
    , bIsValid(aObject.bIsValid)
56
0
    , bIsThumbBmp(aObject.bIsThumbBmp)
57
0
{
58
0
}
59
60
Bitmap SgaObject::createPreviewBitmap(const Size& rSizePixel) const
61
0
{
62
0
    Bitmap aRetval;
63
64
0
    if(rSizePixel.Width() && rSizePixel.Height())
65
0
    {
66
0
        if(SgaObjKind::Sound == GetObjKind())
67
0
        {
68
0
            aRetval = Bitmap(RID_SVXBMP_GALLERY_MEDIA);
69
0
        }
70
0
        else if(IsThumbBitmap())
71
0
        {
72
0
            aRetval = GetThumbBmp();
73
0
        }
74
0
        else
75
0
        {
76
0
            const Graphic aGraphic(GetThumbMtf());
77
78
0
            aRetval = aGraphic.GetBitmap();
79
0
        }
80
81
0
        if(!aRetval.IsEmpty())
82
0
        {
83
0
            const Size aCurrentSizePixel(aRetval.GetSizePixel());
84
0
            const double fScaleX(static_cast<double>(rSizePixel.Width()) / static_cast<double>(aCurrentSizePixel.Width()));
85
0
            const double fScaleY(static_cast<double>(rSizePixel.Height()) / static_cast<double>(aCurrentSizePixel.Height()));
86
0
            const double fScale(std::min(fScaleX, fScaleY));
87
88
            // only scale when need to decrease, no need to make bigger as original. Also
89
            // prevent scaling close to 1.0 which is not needed for pixel graphics
90
0
            if(fScale < 1.0 && fabs(1.0 - fScale) > 0.005)
91
0
            {
92
0
                aRetval.Scale(fScale, fScale, BmpScaleFlag::BestQuality);
93
0
            }
94
0
        }
95
0
    }
96
97
0
    return aRetval;
98
0
}
99
100
bool SgaObject::CreateThumb( const Graphic& rGraphic )
101
0
{
102
0
    bool bRet = false;
103
104
0
    if( rGraphic.GetType() == GraphicType::Bitmap )
105
0
    {
106
0
        Bitmap      aBmp( rGraphic.GetBitmap() );
107
0
        Size        aBmpSize( aBmp.GetSizePixel() );
108
109
0
        if( aBmpSize.Width() && aBmpSize.Height() )
110
0
        {
111
0
            if( aBmp.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel &&
112
0
                aBmp.GetPrefSize().Width() > 0 &&
113
0
                aBmp.GetPrefSize().Height() > 0 )
114
0
            {
115
0
                Size aLogSize( OutputDevice::LogicToLogic(aBmp.GetPrefSize(), aBmp.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
116
117
0
                if( !aLogSize.IsEmpty() )
118
0
                {
119
0
                    double  fFactorLog = static_cast< double >( aLogSize.Width() ) / aLogSize.Height();
120
0
                    double  fFactorPix = static_cast< double >( aBmpSize.Width() ) / aBmpSize.Height();
121
122
0
                    if( fFactorPix > fFactorLog )
123
0
                        aBmpSize.setWidth( basegfx::fround<tools::Long>( aBmpSize.Height() * fFactorLog ) );
124
0
                    else
125
0
                        aBmpSize.setHeight( basegfx::fround<tools::Long>( aBmpSize.Width() / fFactorLog ) );
126
127
0
                    aBmp.Scale(aBmpSize, BmpScaleFlag::BestQuality);
128
0
                }
129
0
            }
130
131
            // take over Bitmap
132
0
            aThumbBmp = std::move(aBmp);
133
134
0
            if( ( aBmpSize.Width() <= S_THUMB ) && ( aBmpSize.Height() <= S_THUMB ) )
135
0
            {
136
0
                aThumbBmp.Convert( BmpConversion::N8BitColors );
137
0
                bRet = true;
138
0
            }
139
0
            else
140
0
            {
141
0
                const float fFactor  = static_cast<float>(aBmpSize.Width()) / aBmpSize.Height();
142
0
                const Size  aNewSize( std::max( tools::Long(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), tools::Long(8) ),
143
0
                                      std::max( tools::Long(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), tools::Long(8) ) );
144
0
                if(aThumbBmp.Scale(
145
0
                    static_cast<double>(aNewSize.Width()) / aBmpSize.Width(),
146
0
                    static_cast<double>(aNewSize.Height()) / aBmpSize.Height(),
147
0
                    BmpScaleFlag::BestQuality ) )
148
0
                {
149
0
                    aThumbBmp.Convert( BmpConversion::N8BitColors );
150
0
                    bRet = true;
151
0
                }
152
0
            }
153
0
        }
154
0
    }
155
0
    else if( rGraphic.GetType() == GraphicType::GdiMetafile )
156
0
    {
157
0
        const Size aPrefSize( rGraphic.GetPrefSize() );
158
0
        const double fFactor  = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
159
0
        Size aSize( S_THUMB, S_THUMB );
160
0
        if ( fFactor < 1.0 )
161
0
            aSize.setWidth( static_cast<sal_Int32>( S_THUMB * fFactor ) );
162
0
        else
163
0
            aSize.setHeight( static_cast<sal_Int32>( S_THUMB / fFactor ) );
164
165
0
        const GraphicConversionParameters aParameters(aSize, false, true, true /*TODO: extra ", true" post-#i121194#*/);
166
0
        aThumbBmp = rGraphic.GetBitmap(aParameters);
167
168
0
        if( !aThumbBmp.IsEmpty() )
169
0
        {
170
0
            aThumbBmp.Convert( BmpConversion::N8BitColors );
171
0
            bRet = true;
172
0
        }
173
0
    }
174
175
0
    return bRet;
176
0
}
177
178
void SgaObject::WriteData( SvStream& rOut, const OUString& rDestDir ) const
179
0
{
180
0
    static const sal_uInt32 nInventor = COMPAT_FORMAT( 'S', 'G', 'A', '3' );
181
182
0
    rOut.WriteUInt32( nInventor ).WriteUInt16( 0x0004 ).WriteUInt16( GetVersion() ).WriteUInt16( static_cast<sal_uInt16>(GetObjKind()) );
183
0
    rOut.WriteBool( bIsThumbBmp );
184
185
0
    if( bIsThumbBmp )
186
0
    {
187
0
        const SvStreamCompressFlags nOldCompressMode = rOut.GetCompressMode();
188
0
        const sal_Int32           nOldVersion = rOut.GetVersion();
189
190
0
        rOut.SetCompressMode( SvStreamCompressFlags::ZBITMAP );
191
0
        rOut.SetVersion( SOFFICE_FILEFORMAT_50 );
192
193
0
        WriteDIBBitmapEx(aThumbBmp, rOut);
194
195
0
        rOut.SetVersion( nOldVersion );
196
0
        rOut.SetCompressMode( nOldCompressMode );
197
0
    }
198
0
    else
199
0
    {
200
0
        if(!rOut.GetError())
201
0
        {
202
0
            SvmWriter aWriter(rOut);
203
0
            aWriter.Write(aThumbMtf);
204
0
        }
205
0
    }
206
207
0
    OUString aURLWithoutDestDir = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
208
0
    aURLWithoutDestDir = aURLWithoutDestDir.replaceFirst(rDestDir, "");
209
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aURLWithoutDestDir, RTL_TEXTENCODING_UTF8);
210
0
}
211
212
void SgaObject::ReadData(SvStream& rIn, sal_uInt16& rReadVersion )
213
0
{
214
0
    sal_uInt32      nTmp32;
215
0
    sal_uInt16      nTmp16;
216
217
0
    rIn.ReadUInt32( nTmp32 ).ReadUInt16( nTmp16 ).ReadUInt16( rReadVersion ).ReadUInt16( nTmp16 ).ReadCharAsBool( bIsThumbBmp );
218
219
0
    if( bIsThumbBmp )
220
0
    {
221
0
        ReadDIBBitmapEx(aThumbBmp, rIn);
222
0
    }
223
0
    else
224
0
    {
225
0
        SvmReader aReader( rIn );
226
0
        aReader.Read( aThumbMtf );
227
0
    }
228
229
0
    OUString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
230
0
    aURL = INetURLObject(aTmpStr);
231
0
}
232
233
OUString const & SgaObject::GetTitle() const
234
0
{
235
0
    return aTitle;
236
0
}
237
238
void SgaObject::SetTitle( const OUString& rTitle )
239
0
{
240
0
    aTitle = rTitle;
241
0
}
242
243
SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj )
244
0
{
245
0
    rObj.WriteData( rOut, u""_ustr );
246
0
    return rOut;
247
0
}
248
249
SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj )
250
0
{
251
0
    sal_uInt16 nReadVersion;
252
253
0
    rObj.ReadData( rIn, nReadVersion );
254
0
    rObj.bIsValid = ( rIn.GetError() == ERRCODE_NONE );
255
256
0
    return rIn;
257
0
}
258
259
SgaObjectBmp::SgaObjectBmp()
260
0
{
261
0
}
262
263
SgaObjectBmp::SgaObjectBmp( const INetURLObject& rURL )
264
0
{
265
0
    Graphic aGraphic;
266
0
    OUString  aFilter;
267
268
0
    if ( GalleryGraphicImportRet::IMPORT_NONE != GalleryGraphicImport( rURL, aGraphic, aFilter ) )
269
0
        Init( aGraphic, rURL );
270
0
}
271
272
SgaObjectBmp::SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL )
273
0
{
274
0
    if( FileExists( rURL ) )
275
0
        Init( rGraphic, rURL );
276
0
}
277
278
void SgaObjectBmp::Init( const Graphic& rGraphic, const INetURLObject& rURL )
279
0
{
280
0
    aURL = rURL;
281
0
    bIsValid = CreateThumb( rGraphic );
282
0
}
283
284
void SgaObjectBmp::WriteData( SvStream& rOut, const OUString& rDestDir ) const
285
0
{
286
    // Set version
287
0
    SgaObject::WriteData( rOut, rDestDir );
288
0
    char const aDummy[ 10 ] = { 0 };
289
0
    rOut.WriteBytes(aDummy, 10);
290
0
    write_uInt16_lenPrefixed_uInt8s_FromOString(rOut, ""); //dummy
291
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
292
0
}
293
294
void SgaObjectBmp::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
295
0
{
296
297
0
    SgaObject::ReadData( rIn, rReadVersion );
298
0
    rIn.SeekRel( 10 ); // 16, 16, 32, 16
299
0
    read_uInt16_lenPrefixed_uInt8s_ToOString(rIn); //dummy
300
301
0
    if( rReadVersion >= 5 )
302
0
        aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
303
0
}
304
305
306
SgaObjectSound::SgaObjectSound() :
307
0
    eSoundType( SOUND_STANDARD )
308
0
{
309
0
}
310
311
SgaObjectSound::SgaObjectSound( const INetURLObject& rURL ) :
312
0
    eSoundType( SOUND_STANDARD )
313
0
{
314
315
0
    if( FileExists( rURL ) )
316
0
    {
317
0
        aURL = rURL;
318
0
        aThumbBmp = Bitmap(Size(1, 1), vcl::PixelFormat::N8_BPP);
319
0
        bIsValid = true;
320
0
    }
321
0
    else
322
0
        bIsValid = false;
323
0
}
324
325
SgaObjectSound::~SgaObjectSound()
326
0
{
327
0
}
328
329
Bitmap SgaObjectSound::GetThumbBmp() const
330
0
{
331
0
    OUString sId;
332
333
0
    switch( eSoundType )
334
0
    {
335
0
        case SOUND_COMPUTER: sId = RID_SVXBMP_GALLERY_SOUND_1; break;
336
0
        case SOUND_MISC: sId = RID_SVXBMP_GALLERY_SOUND_2; break;
337
0
        case SOUND_MUSIC: sId = RID_SVXBMP_GALLERY_SOUND_3; break;
338
0
        case SOUND_NATURE: sId = RID_SVXBMP_GALLERY_SOUND_4; break;
339
0
        case SOUND_SPEECH: sId = RID_SVXBMP_GALLERY_SOUND_5; break;
340
0
        case SOUND_TECHNIC: sId = RID_SVXBMP_GALLERY_SOUND_6; break;
341
0
        case SOUND_ANIMAL: sId = RID_SVXBMP_GALLERY_SOUND_7; break;
342
343
        // standard
344
0
        default:
345
0
             sId = RID_SVXBMP_GALLERY_MEDIA;
346
0
        break;
347
0
    }
348
349
0
    return Bitmap(sId);
350
0
}
351
352
void SgaObjectSound::WriteData( SvStream& rOut, const OUString& rDestDir ) const
353
0
{
354
0
    SgaObject::WriteData( rOut, rDestDir );
355
0
    rOut.WriteUInt16( eSoundType );
356
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
357
0
}
358
359
void SgaObjectSound::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
360
0
{
361
0
    SgaObject::ReadData( rIn, rReadVersion );
362
363
0
    if( rReadVersion >= 5 )
364
0
    {
365
0
        sal_uInt16      nTmp16;
366
367
0
        rIn.ReadUInt16( nTmp16 ); eSoundType = static_cast<GalSoundType>(nTmp16);
368
369
0
        if( rReadVersion >= 6 )
370
0
            aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
371
0
    }
372
0
}
373
374
SgaObjectAnim::SgaObjectAnim()
375
0
{
376
0
}
377
378
SgaObjectAnim::SgaObjectAnim( const Graphic& rGraphic,
379
                              const INetURLObject& rURL )
380
0
{
381
0
    aURL = rURL;
382
0
    bIsValid = CreateThumb( rGraphic );
383
0
}
384
385
SgaObjectINet::SgaObjectINet()
386
0
{
387
0
}
388
389
SgaObjectINet::SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL ) :
390
0
            SgaObjectAnim   ( rGraphic, rURL )
391
0
{
392
0
}
393
394
SgaObjectSvDraw::SgaObjectSvDraw()
395
0
{
396
0
}
397
398
SgaObjectSvDraw::SgaObjectSvDraw( const FmFormModel& rModel, const INetURLObject& rURL )
399
0
{
400
0
    aURL = rURL;
401
0
    bIsValid = CreateThumb( rModel );
402
0
}
403
404
405
SvxGalleryDrawModel::SvxGalleryDrawModel()
406
0
: mpFormModel( nullptr )
407
0
{
408
0
    mxDoc = SfxObjectShell::CreateObjectByFactoryName( u"sdraw"_ustr );
409
410
0
    if( !mxDoc.Is() )
411
0
        return;
412
413
0
    mxDoc->DoInitNew();
414
415
0
    mpFormModel
416
0
        = dynamic_cast<FmFormModel*>(comphelper::getFromUnoTunnel<SdrModel>(mxDoc->GetModel()));
417
0
    if (mpFormModel)
418
0
    {
419
0
        mpFormModel->InsertPage(mpFormModel->AllocPage(false).get());
420
0
    }
421
0
}
422
423
SvxGalleryDrawModel::~SvxGalleryDrawModel()
424
0
{
425
0
    if( mxDoc.Is() )
426
0
        mxDoc->DoClose();
427
428
0
}
429
430
SgaObjectSvDraw::SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL )
431
0
{
432
0
    SvxGalleryDrawModel aModel;
433
434
0
    if( aModel.GetModel() )
435
0
    {
436
0
        if( GallerySvDrawImport( rIStm, *aModel.GetModel()  ) )
437
0
        {
438
0
            aURL = rURL;
439
0
            bIsValid = CreateThumb( *aModel.GetModel()  );
440
0
        }
441
0
    }
442
0
}
443
444
bool SgaObjectSvDraw::CreateThumb( const FmFormModel& rModel )
445
0
{
446
0
    Graphic     aGraphic;
447
0
    ImageMap    aImageMap;
448
0
    bool        bRet = false;
449
450
0
    if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) )
451
0
    {
452
0
        bRet = SgaObject::CreateThumb( aGraphic );
453
0
    }
454
0
    else
455
0
    {
456
0
        const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0));
457
458
0
        if(pPage)
459
0
        {
460
0
            const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect());
461
462
0
            if(aObjRect.GetWidth() && aObjRect.GetHeight())
463
0
            {
464
0
                ScopedVclPtrInstance< VirtualDevice > pVDev;
465
0
                FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev);
466
467
0
                aView.ShowSdrPage(const_cast< FmFormPage* >(pPage));
468
0
                aView.MarkAllObj();
469
0
                aThumbBmp = aView.GetMarkedObjBitmap(true);
470
0
                aGraphic = Graphic(aThumbBmp);
471
0
                bRet = SgaObject::CreateThumb(aGraphic);
472
0
            }
473
0
        }
474
0
    }
475
476
0
    return bRet;
477
0
}
478
479
void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const
480
0
{
481
0
    SgaObject::WriteData( rOut, rDestDir );
482
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
483
0
}
484
485
void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
486
0
{
487
0
    SgaObject::ReadData( rIn, rReadVersion );
488
489
0
    if( rReadVersion >= 5 )
490
0
        aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
491
0
}
492
493
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */