Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/toolkit/source/awt/vclxgraphics.cxx
Line
Count
Source (jump to first uncovered line)
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
21
#include <memory>
22
#include <awt/vclxgraphics.hxx>
23
#include <toolkit/awt/vclxdevice.hxx>
24
#include <toolkit/helper/vclunohelper.hxx>
25
26
#include <vcl/svapp.hxx>
27
#include <vcl/outdev.hxx>
28
#include <vcl/image.hxx>
29
#include <vcl/kernarray.hxx>
30
#include <vcl/gradient.hxx>
31
#include <vcl/metric.hxx>
32
#include <vcl/unohelp.hxx>
33
#include <tools/debug.hxx>
34
35
using namespace com::sun::star;
36
37
38
39
VCLXGraphics::VCLXGraphics()
40
0
    : mpOutputDevice(nullptr)
41
0
    , meRasterOp(RasterOp::OverPaint)
42
0
{
43
0
}
44
45
VCLXGraphics::~VCLXGraphics()
46
0
{
47
0
    std::vector< VCLXGraphics* > *pLst = mpOutputDevice ? mpOutputDevice->GetUnoGraphicsList() : nullptr;
48
0
    if ( pLst )
49
0
    {
50
0
        auto it = std::find(pLst->begin(), pLst->end(), this);
51
0
        if (it != pLst->end())
52
0
            pLst->erase( it );
53
0
    }
54
55
0
    mpClipRegion.reset();
56
57
0
    SolarMutexGuard g;
58
0
    mpOutputDevice.reset();
59
0
}
60
61
void VCLXGraphics::SetOutputDevice( OutputDevice* pOutDev )
62
0
{
63
0
    mpOutputDevice = pOutDev;
64
0
    mxDevice = nullptr;
65
0
    initAttrs();
66
0
}
67
68
void VCLXGraphics::Init( OutputDevice* pOutDev )
69
0
{
70
0
    DBG_ASSERT( !mpOutputDevice, "VCLXGraphics::Init already has pOutDev !" );
71
0
    mpOutputDevice  = pOutDev;
72
73
0
    initAttrs();
74
0
    mpClipRegion    = nullptr;
75
76
    // Register at OutputDevice
77
0
    std::vector< VCLXGraphics* > *pLst = mpOutputDevice->GetUnoGraphicsList();
78
0
    if ( !pLst )
79
0
        pLst = mpOutputDevice->CreateUnoGraphicsList();
80
0
    pLst->push_back( this );
81
0
}
82
83
void VCLXGraphics::initAttrs()
84
0
{
85
0
    if ( !mpOutputDevice )
86
0
        return;
87
88
0
    maFont          = mpOutputDevice->GetFont();
89
0
    maTextColor     = mpOutputDevice->GetTextColor(); /* COL_BLACK */
90
0
    maTextFillColor = mpOutputDevice->GetTextFillColor(); /* COL_TRANSPARENT */
91
0
    maLineColor     = mpOutputDevice->GetLineColor(); /* COL_BLACK */
92
0
    maFillColor     = mpOutputDevice->GetFillColor(); /* COL_WHITE */
93
0
    meRasterOp      = mpOutputDevice->GetRasterOp(); /* RasterOp::OverPaint */
94
0
}
95
96
void VCLXGraphics::InitOutputDevice( InitOutDevFlags nFlags )
97
0
{
98
0
    if(!mpOutputDevice)
99
0
        return;
100
101
0
    SolarMutexGuard aVclGuard;
102
103
0
    if ( nFlags & InitOutDevFlags::FONT )
104
0
    {
105
0
        mpOutputDevice->SetFont( maFont );
106
0
        mpOutputDevice->SetTextColor( maTextColor );
107
0
        mpOutputDevice->SetTextFillColor( maTextFillColor );
108
0
    }
109
110
0
    if ( nFlags & InitOutDevFlags::COLORS )
111
0
    {
112
0
        mpOutputDevice->SetLineColor( maLineColor );
113
0
        mpOutputDevice->SetFillColor( maFillColor );
114
0
    }
115
116
0
    mpOutputDevice->SetRasterOp( meRasterOp );
117
118
0
    if( mpClipRegion )
119
0
        mpOutputDevice->SetClipRegion( *mpClipRegion );
120
0
    else
121
0
        mpOutputDevice->SetClipRegion();
122
0
}
123
124
uno::Reference< awt::XDevice > VCLXGraphics::getDevice()
125
0
{
126
0
    SolarMutexGuard aGuard;
127
128
0
    if( !mxDevice.is() && mpOutputDevice )
129
0
    {
130
0
        rtl::Reference<VCLXDevice> xDev = new VCLXDevice;
131
0
        xDev->SetOutputDevice( mpOutputDevice );
132
0
        mxDevice = std::move(xDev);
133
0
    }
134
0
    return mxDevice;
135
0
}
136
137
awt::SimpleFontMetric VCLXGraphics::getFontMetric()
138
0
{
139
0
    SolarMutexGuard aGuard;
140
141
0
    awt::SimpleFontMetric aM;
142
0
    if( mpOutputDevice )
143
0
    {
144
0
        mpOutputDevice->SetFont( maFont );
145
0
        aM = VCLUnoHelper::CreateFontMetric( mpOutputDevice->GetFontMetric() );
146
0
    }
147
0
    return aM;
148
0
}
149
150
void VCLXGraphics::setFont( const uno::Reference< awt::XFont >& rxFont )
151
0
{
152
0
    SolarMutexGuard aGuard;
153
154
0
    maFont = VCLUnoHelper::CreateFont( rxFont );
155
0
}
156
157
void VCLXGraphics::selectFont( const awt::FontDescriptor& rDescription )
158
0
{
159
0
    SolarMutexGuard aGuard;
160
161
0
    maFont = VCLUnoHelper::CreateFont( rDescription, vcl::Font() );
162
0
}
163
164
void VCLXGraphics::setTextColor( sal_Int32 nColor )
165
0
{
166
0
    SolarMutexGuard aGuard;
167
168
0
    maTextColor = Color( ColorTransparency, nColor );
169
0
}
170
171
void VCLXGraphics::setTextFillColor( sal_Int32 nColor )
172
0
{
173
0
    SolarMutexGuard aGuard;
174
175
0
    maTextFillColor = Color( ColorTransparency, nColor );
176
0
}
177
178
void VCLXGraphics::setLineColor( sal_Int32 nColor )
179
0
{
180
0
    SolarMutexGuard aGuard;
181
182
0
    maLineColor = Color( ColorTransparency, nColor );
183
0
}
184
185
void VCLXGraphics::setFillColor( sal_Int32 nColor )
186
0
{
187
0
    SolarMutexGuard aGuard;
188
189
0
    maFillColor = Color( ColorTransparency, nColor );
190
0
}
191
192
void VCLXGraphics::setRasterOp( awt::RasterOperation eROP )
193
0
{
194
0
    SolarMutexGuard aGuard;
195
196
0
    meRasterOp = static_cast<RasterOp>(eROP);
197
0
}
198
199
void VCLXGraphics::setClipRegion( const uno::Reference< awt::XRegion >& rxRegion )
200
0
{
201
0
    SolarMutexGuard aGuard;
202
203
0
    if ( rxRegion.is() )
204
0
        mpClipRegion.reset( new vcl::Region( VCLUnoHelper::GetRegion( rxRegion ) ) );
205
0
    else
206
0
        mpClipRegion.reset();
207
0
}
208
209
void VCLXGraphics::intersectClipRegion( const uno::Reference< awt::XRegion >& rxRegion )
210
0
{
211
0
    SolarMutexGuard aGuard;
212
213
0
    if ( rxRegion.is() )
214
0
    {
215
0
        vcl::Region aRegion( VCLUnoHelper::GetRegion( rxRegion ) );
216
0
        if ( !mpClipRegion )
217
0
            mpClipRegion.reset( new vcl::Region(std::move(aRegion)) );
218
0
        else
219
0
            mpClipRegion->Intersect( aRegion );
220
0
    }
221
0
}
222
223
void VCLXGraphics::push(  )
224
0
{
225
0
    SolarMutexGuard aGuard;
226
227
228
0
    if( mpOutputDevice )
229
0
        mpOutputDevice->Push();
230
0
}
231
232
void VCLXGraphics::pop(  )
233
0
{
234
0
    SolarMutexGuard aGuard;
235
236
237
0
    if( mpOutputDevice )
238
0
        mpOutputDevice->Pop();
239
0
}
240
241
void VCLXGraphics::clear(
242
    const awt::Rectangle& aRect )
243
0
{
244
0
    SolarMutexGuard aGuard;
245
246
0
    if( mpOutputDevice )
247
0
    {
248
0
        const ::tools::Rectangle aVCLRect = vcl::unohelper::ConvertToVCLRect( aRect );
249
0
        mpOutputDevice->Erase( aVCLRect );
250
0
    }
251
0
}
252
253
void VCLXGraphics::copy( const uno::Reference< awt::XDevice >& rxSource, sal_Int32 nSourceX, sal_Int32 nSourceY, sal_Int32 nSourceWidth, sal_Int32 nSourceHeight, sal_Int32 nDestX, sal_Int32 nDestY, sal_Int32 nDestWidth, sal_Int32 nDestHeight )
254
0
{
255
0
    SolarMutexGuard aGuard;
256
257
0
    if ( mpOutputDevice )
258
0
    {
259
0
        VCLXDevice* pFromDev = dynamic_cast<VCLXDevice*>( rxSource.get() );
260
0
        DBG_ASSERT( pFromDev, "VCLXGraphics::copy - invalid device" );
261
0
        if ( pFromDev )
262
0
        {
263
0
            InitOutputDevice( InitOutDevFlags::NONE );
264
0
            mpOutputDevice->DrawOutDev( Point( nDestX, nDestY ), Size( nDestWidth, nDestHeight ),
265
0
                                    Point( nSourceX, nSourceY ), Size( nSourceWidth, nSourceHeight ), *pFromDev->GetOutputDevice() );
266
0
        }
267
0
    }
268
0
}
269
270
void VCLXGraphics::draw( const uno::Reference< awt::XDisplayBitmap >& rxBitmapHandle, sal_Int32 nSourceX, sal_Int32 nSourceY, sal_Int32 nSourceWidth, sal_Int32 nSourceHeight, sal_Int32 nDestX, sal_Int32 nDestY, sal_Int32 nDestWidth, sal_Int32 nDestHeight )
271
0
{
272
0
    SolarMutexGuard aGuard;
273
274
0
    if( !mpOutputDevice )
275
0
        return;
276
277
0
    InitOutputDevice( InitOutDevFlags::NONE);
278
0
    uno::Reference< awt::XBitmap > xBitmap( rxBitmapHandle, uno::UNO_QUERY );
279
0
    BitmapEx aBmpEx = VCLUnoHelper::GetBitmap( xBitmap );
280
281
0
    Point aPos(nDestX - nSourceX, nDestY - nSourceY);
282
0
    Size aSz = aBmpEx.GetSizePixel();
283
284
0
    if(nDestWidth != nSourceWidth)
285
0
    {
286
0
        float zoomX = static_cast<float>(nDestWidth) / static_cast<float>(nSourceWidth);
287
0
        aSz.setWidth( static_cast<tools::Long>(static_cast<float>(aSz.Width()) * zoomX) );
288
0
    }
289
290
0
    if(nDestHeight != nSourceHeight)
291
0
    {
292
0
        float zoomY = static_cast<float>(nDestHeight) / static_cast<float>(nSourceHeight);
293
0
        aSz.setHeight( static_cast<tools::Long>(static_cast<float>(aSz.Height()) * zoomY) );
294
0
    }
295
296
0
    if(nSourceX || nSourceY || aSz.Width() != nSourceWidth || aSz.Height() != nSourceHeight)
297
0
        mpOutputDevice->IntersectClipRegion(vcl::Region(tools::Rectangle(nDestX, nDestY, nDestX + nDestWidth - 1, nDestY + nDestHeight - 1)));
298
299
0
    mpOutputDevice->DrawBitmapEx( aPos, aSz, aBmpEx );
300
0
}
301
302
void VCLXGraphics::drawPixel( sal_Int32 x, sal_Int32 y )
303
0
{
304
0
    SolarMutexGuard aGuard;
305
306
0
    if( mpOutputDevice )
307
0
    {
308
0
        InitOutputDevice( InitOutDevFlags::COLORS );
309
0
        mpOutputDevice->DrawPixel( Point( x, y ) );
310
0
    }
311
0
}
312
313
void VCLXGraphics::drawLine( sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 )
314
0
{
315
0
    SolarMutexGuard aGuard;
316
317
0
    if( mpOutputDevice )
318
0
    {
319
0
        InitOutputDevice( InitOutDevFlags::COLORS );
320
0
        mpOutputDevice->DrawLine( Point( x1, y1 ), Point( x2, y2 ) );
321
0
    }
322
0
}
323
324
void VCLXGraphics::drawRect( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height )
325
0
{
326
0
    SolarMutexGuard aGuard;
327
328
0
    if( mpOutputDevice )
329
0
    {
330
0
        InitOutputDevice( InitOutDevFlags::COLORS );
331
0
        mpOutputDevice->DrawRect( tools::Rectangle( Point( x, y ), Size( width, height ) ) );
332
0
    }
333
0
}
334
335
void VCLXGraphics::drawRoundedRect( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, sal_Int32 nHorzRound, sal_Int32 nVertRound )
336
0
{
337
0
    SolarMutexGuard aGuard;
338
339
0
    if( mpOutputDevice )
340
0
    {
341
0
        InitOutputDevice( InitOutDevFlags::COLORS );
342
0
        mpOutputDevice->DrawRect( tools::Rectangle( Point( x, y ), Size( width, height ) ), nHorzRound, nVertRound );
343
0
    }
344
0
}
345
346
void VCLXGraphics::drawPolyLine( const uno::Sequence< sal_Int32 >& DataX, const uno::Sequence< sal_Int32 >& DataY )
347
0
{
348
0
    SolarMutexGuard aGuard;
349
350
0
    if( mpOutputDevice )
351
0
    {
352
0
        InitOutputDevice( InitOutDevFlags::COLORS );
353
0
        mpOutputDevice->DrawPolyLine( VCLUnoHelper::CreatePolygon( DataX, DataY ) );
354
0
    }
355
0
}
356
357
void VCLXGraphics::drawPolygon( const uno::Sequence< sal_Int32 >& DataX, const uno::Sequence< sal_Int32 >& DataY )
358
0
{
359
0
    SolarMutexGuard aGuard;
360
361
0
    if( mpOutputDevice )
362
0
    {
363
0
        InitOutputDevice( InitOutDevFlags::COLORS );
364
0
        mpOutputDevice->DrawPolygon( VCLUnoHelper::CreatePolygon( DataX, DataY ) );
365
0
    }
366
0
}
367
368
void VCLXGraphics::drawPolyPolygon( const uno::Sequence< uno::Sequence< sal_Int32 > >& DataX, const uno::Sequence< uno::Sequence< sal_Int32 > >& DataY )
369
0
{
370
0
    SolarMutexGuard aGuard;
371
372
0
    if( mpOutputDevice )
373
0
    {
374
0
        InitOutputDevice( InitOutDevFlags::COLORS );
375
0
        sal_uInt16 nPolys = static_cast<sal_uInt16>(DataX.getLength());
376
0
        tools::PolyPolygon aPolyPoly( nPolys );
377
0
        for ( sal_uInt16 n = 0; n < nPolys; n++ )
378
0
            aPolyPoly[n] = VCLUnoHelper::CreatePolygon( DataX.getConstArray()[n], DataY.getConstArray()[n] );
379
380
0
        mpOutputDevice->DrawPolyPolygon( aPolyPoly );
381
0
    }
382
0
}
383
384
void VCLXGraphics::drawEllipse( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height )
385
0
{
386
0
    SolarMutexGuard aGuard;
387
388
0
    if( mpOutputDevice )
389
0
    {
390
0
        InitOutputDevice( InitOutDevFlags::COLORS );
391
0
        mpOutputDevice->DrawEllipse( tools::Rectangle( Point( x, y ), Size( width, height ) ) );
392
0
    }
393
0
}
394
395
void VCLXGraphics::drawArc( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 )
396
0
{
397
0
    SolarMutexGuard aGuard;
398
399
0
    if( mpOutputDevice )
400
0
    {
401
0
        InitOutputDevice( InitOutDevFlags::COLORS );
402
0
        mpOutputDevice->DrawArc( tools::Rectangle( Point( x, y ), Size( width, height ) ), Point( x1, y1 ), Point( x2, y2 ) );
403
0
    }
404
0
}
405
406
void VCLXGraphics::drawPie( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 )
407
0
{
408
0
    SolarMutexGuard aGuard;
409
410
0
    if( mpOutputDevice )
411
0
    {
412
0
        InitOutputDevice( InitOutDevFlags::COLORS );
413
0
        mpOutputDevice->DrawPie( tools::Rectangle( Point( x, y ), Size( width, height ) ), Point( x1, y1 ), Point( x2, y2 ) );
414
0
    }
415
0
}
416
417
void VCLXGraphics::drawChord( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 )
418
0
{
419
0
    SolarMutexGuard aGuard;
420
421
0
    if( mpOutputDevice )
422
0
    {
423
0
        InitOutputDevice( InitOutDevFlags::COLORS );
424
0
        mpOutputDevice->DrawChord( tools::Rectangle( Point( x, y ), Size( width, height ) ), Point( x1, y1 ), Point( x2, y2 ) );
425
0
    }
426
0
}
427
428
void VCLXGraphics::drawGradient( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, const awt::Gradient& rGradient )
429
0
{
430
0
    SolarMutexGuard aGuard;
431
432
0
    if( !mpOutputDevice )
433
0
        return;
434
435
0
    InitOutputDevice( InitOutDevFlags::COLORS );
436
0
    Gradient aGradient(rGradient.Style, Color(ColorTransparency, rGradient.StartColor), Color(ColorTransparency, rGradient.EndColor));
437
0
    aGradient.SetAngle(Degree10(rGradient.Angle));
438
0
    aGradient.SetBorder(rGradient.Border);
439
0
    aGradient.SetOfsX(rGradient.XOffset);
440
0
    aGradient.SetOfsY(rGradient.YOffset);
441
0
    aGradient.SetStartIntensity(rGradient.StartIntensity);
442
0
    aGradient.SetEndIntensity(rGradient.EndIntensity);
443
0
    aGradient.SetSteps(rGradient.StepCount);
444
0
    mpOutputDevice->DrawGradient( tools::Rectangle( Point( x, y ), Size( width, height ) ), aGradient );
445
0
}
446
447
void VCLXGraphics::drawText( sal_Int32 x, sal_Int32 y, const OUString& rText )
448
0
{
449
0
    SolarMutexGuard aGuard;
450
451
0
    if( mpOutputDevice )
452
0
    {
453
0
        InitOutputDevice( InitOutDevFlags::COLORS |InitOutDevFlags::FONT);
454
0
        mpOutputDevice->DrawText( Point( x, y ), rText );
455
0
    }
456
0
}
457
458
void VCLXGraphics::drawTextArray( sal_Int32 x, sal_Int32 y, const OUString& rText, const uno::Sequence< sal_Int32 >& rLongs )
459
0
{
460
0
    SolarMutexGuard aGuard;
461
462
0
    if( mpOutputDevice )
463
0
    {
464
0
        InitOutputDevice( InitOutDevFlags::COLORS|InitOutDevFlags::FONT );
465
0
        KernArray aDXA;
466
0
        aDXA.reserve(rText.getLength());
467
0
        for(int i = 0; i < rText.getLength(); ++i)
468
0
            aDXA.push_back(rLongs[i]);
469
0
        mpOutputDevice->DrawTextArray( Point( x, y ), rText, aDXA, {}, 0, rText.getLength());
470
0
    }
471
0
}
472
473
474
void VCLXGraphics::drawImage( sal_Int32 x, sal_Int32 y, sal_Int32 width, sal_Int32 height, sal_Int16 nStyle, const uno::Reference< graphic::XGraphic >& xGraphic )
475
0
{
476
0
    SolarMutexGuard aGuard;
477
478
0
    if( mpOutputDevice && xGraphic.is() )
479
0
    {
480
0
        Image aImage( xGraphic );
481
0
        if ( !!aImage )
482
0
        {
483
0
            InitOutputDevice( InitOutDevFlags::COLORS );
484
0
            mpOutputDevice->DrawImage( Point( x, y ), Size( width, height ), aImage, static_cast<DrawImageFlags>(nStyle) );
485
0
        }
486
0
    }
487
0
}
488
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */