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 <cassert>
21 
22 #include <sal/types.h>
23 
24 #include <tools/poly.hxx>
25 #include <tools/helpers.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/virdev.hxx>
29 
30 #include <salgdi.hxx>
31 
DrawBorder(tools::Rectangle aBorderRect)32 void OutputDevice::DrawBorder(tools::Rectangle aBorderRect)
33 {
34     sal_uInt16 nPixel = static_cast<sal_uInt16>(PixelToLogic(Size(1, 1)).Width());
35 
36     aBorderRect.AdjustLeft(nPixel);
37     aBorderRect.AdjustTop(nPixel);
38 
39     SetLineColor(COL_LIGHTGRAY);
40     DrawRect(aBorderRect);
41 
42     aBorderRect.AdjustLeft(-nPixel);
43     aBorderRect.AdjustTop(-nPixel);
44     aBorderRect.AdjustRight(-nPixel);
45     aBorderRect.AdjustBottom(-nPixel);
46     SetLineColor(COL_GRAY);
47 
48     DrawRect(aBorderRect);
49 }
50 
DrawRect(const tools::Rectangle & rRect)51 void OutputDevice::DrawRect( const tools::Rectangle& rRect )
52 {
53     assert(!is_double_buffered_window());
54 
55     if ( mpMetaFile )
56         mpMetaFile->AddAction( new MetaRectAction( rRect ) );
57 
58     if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
59         return;
60 
61     tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
62 
63     if ( aRect.IsEmpty() )
64         return;
65 
66     aRect.Justify();
67 
68     if ( !mpGraphics && !AcquireGraphics() )
69         return;
70     assert(mpGraphics);
71 
72     if ( mbInitClipRegion )
73         InitClipRegion();
74 
75     if ( mbOutputClipped )
76         return;
77 
78     if ( mbInitLineColor )
79         InitLineColor();
80 
81     if ( mbInitFillColor )
82         InitFillColor();
83 
84     mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), *this );
85 
86     if( mpAlphaVDev )
87         mpAlphaVDev->DrawRect( rRect );
88 }
89 
DrawRect(const tools::Rectangle & rRect,sal_uLong nHorzRound,sal_uLong nVertRound)90 void OutputDevice::DrawRect( const tools::Rectangle& rRect,
91                              sal_uLong nHorzRound, sal_uLong nVertRound )
92 {
93     assert(!is_double_buffered_window());
94 
95     if ( mpMetaFile )
96         mpMetaFile->AddAction( new MetaRoundRectAction( rRect, nHorzRound, nVertRound ) );
97 
98     if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
99         return;
100 
101     const tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
102 
103     if ( aRect.IsEmpty() )
104         return;
105 
106     nHorzRound = ImplLogicWidthToDevicePixel( nHorzRound );
107     nVertRound = ImplLogicHeightToDevicePixel( nVertRound );
108 
109     // we need a graphics
110     if ( !mpGraphics && !AcquireGraphics() )
111         return;
112     assert(mpGraphics);
113 
114     if ( mbInitClipRegion )
115         InitClipRegion();
116 
117     if ( mbOutputClipped )
118         return;
119 
120     if ( mbInitLineColor )
121         InitLineColor();
122 
123     if ( mbInitFillColor )
124         InitFillColor();
125 
126     if ( !nHorzRound && !nVertRound )
127     {
128         mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), *this );
129     }
130     else
131     {
132         tools::Polygon aRoundRectPoly( aRect, nHorzRound, nVertRound );
133 
134         if ( aRoundRectPoly.GetSize() >= 2 )
135         {
136             Point* pPtAry = aRoundRectPoly.GetPointAry();
137 
138             if ( !mbFillColor )
139                 mpGraphics->DrawPolyLine( aRoundRectPoly.GetSize(), pPtAry, *this );
140             else
141                 mpGraphics->DrawPolygon( aRoundRectPoly.GetSize(), pPtAry, *this );
142         }
143     }
144 
145     if( mpAlphaVDev )
146         mpAlphaVDev->DrawRect( rRect, nHorzRound, nVertRound );
147 }
148 
Invert(const tools::Rectangle & rRect,InvertFlags nFlags)149 void OutputDevice::Invert( const tools::Rectangle& rRect, InvertFlags nFlags )
150 {
151     assert(!is_double_buffered_window());
152     if ( !IsDeviceOutputNecessary() )
153         return;
154 
155     tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
156 
157     if ( aRect.IsEmpty() )
158         return;
159     aRect.Justify();
160 
161     // we need a graphics
162     if ( !mpGraphics && !AcquireGraphics() )
163         return;
164     assert(mpGraphics);
165 
166     if ( mbInitClipRegion )
167         InitClipRegion();
168 
169     if ( mbOutputClipped )
170         return;
171 
172     SalInvert nSalFlags = SalInvert::NONE;
173     if ( nFlags & InvertFlags::N50 )
174         nSalFlags |= SalInvert::N50;
175     if ( nFlags & InvertFlags::TrackFrame )
176         nSalFlags |= SalInvert::TrackFrame;
177     mpGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), nSalFlags, *this );
178 }
179 
Invert(const tools::Polygon & rPoly,InvertFlags nFlags)180 void OutputDevice::Invert( const tools::Polygon& rPoly, InvertFlags nFlags )
181 {
182     assert(!is_double_buffered_window());
183     if ( !IsDeviceOutputNecessary() )
184         return;
185 
186     sal_uInt16 nPoints = rPoly.GetSize();
187 
188     if ( nPoints < 2 )
189         return;
190 
191     tools::Polygon aPoly( ImplLogicToDevicePixel( rPoly ) );
192 
193     // we need a graphics
194     if ( !mpGraphics && !AcquireGraphics() )
195         return;
196     assert(mpGraphics);
197 
198     if ( mbInitClipRegion )
199         InitClipRegion();
200 
201     if ( mbOutputClipped )
202         return;
203 
204     SalInvert nSalFlags = SalInvert::NONE;
205     if ( nFlags & InvertFlags::N50 )
206         nSalFlags |= SalInvert::N50;
207     if ( nFlags & InvertFlags::TrackFrame )
208         nSalFlags |= SalInvert::TrackFrame;
209     const Point* pPtAry = aPoly.GetConstPointAry();
210     mpGraphics->Invert( nPoints, pPtAry, nSalFlags, *this );
211 }
212 
DrawCheckered(const Point & rPos,const Size & rSize,sal_uInt32 nLen,Color aStart,Color aEnd)213 void OutputDevice::DrawCheckered(const Point& rPos, const Size& rSize, sal_uInt32 nLen, Color aStart, Color aEnd)
214 {
215     assert(!is_double_buffered_window());
216 
217     const sal_uInt32 nMaxX(rPos.X() + rSize.Width());
218     const sal_uInt32 nMaxY(rPos.Y() + rSize.Height());
219 
220     Push(PushFlags::LINECOLOR|PushFlags::FILLCOLOR);
221     SetLineColor();
222 
223     for(sal_uInt32 x(0), nX(rPos.X()); nX < nMaxX; x++, nX += nLen)
224     {
225         const sal_uInt32 nRight(std::min(nMaxX, nX + nLen));
226 
227         for(sal_uInt32 y(0), nY(rPos.Y()); nY < nMaxY; y++, nY += nLen)
228         {
229             const sal_uInt32 nBottom(std::min(nMaxY, nY + nLen));
230 
231             SetFillColor(((x & 0x0001) ^ (y & 0x0001)) ? aStart : aEnd);
232             DrawRect(tools::Rectangle(nX, nY, nRight, nBottom));
233         }
234     }
235 
236     Pop();
237 }
238 
DrawGrid(const tools::Rectangle & rRect,const Size & rDist,DrawGridFlags nFlags)239 void OutputDevice::DrawGrid( const tools::Rectangle& rRect, const Size& rDist, DrawGridFlags nFlags )
240 {
241     assert(!is_double_buffered_window());
242 
243     tools::Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() );
244     aDstRect.Intersection( rRect );
245 
246     if( aDstRect.IsEmpty() || ImplIsRecordLayout() )
247         return;
248 
249     if( !mpGraphics && !AcquireGraphics() )
250         return;
251     assert(mpGraphics);
252 
253     if( mbInitClipRegion )
254         InitClipRegion();
255 
256     if( mbOutputClipped )
257         return;
258 
259     const tools::Long nDistX = std::max( rDist.Width(), tools::Long(1) );
260     const tools::Long nDistY = std::max( rDist.Height(), tools::Long(1) );
261     tools::Long nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX );
262     tools::Long nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY );
263     const tools::Long nRight = aDstRect.Right();
264     const tools::Long nBottom = aDstRect.Bottom();
265     const tools::Long nStartX = ImplLogicXToDevicePixel( nX );
266     const tools::Long nEndX = ImplLogicXToDevicePixel( nRight );
267     const tools::Long nStartY = ImplLogicYToDevicePixel( nY );
268     const tools::Long nEndY = ImplLogicYToDevicePixel( nBottom );
269     tools::Long nHorzCount = 0;
270     tools::Long nVertCount = 0;
271 
272     std::vector< sal_Int32 > aVertBuf;
273     std::vector< sal_Int32 > aHorzBuf;
274 
275     if( ( nFlags & DrawGridFlags::Dots ) || ( nFlags & DrawGridFlags::HorzLines ) )
276     {
277         aVertBuf.resize( aDstRect.GetHeight() / nDistY + 2 );
278         aVertBuf[ nVertCount++ ] = nStartY;
279         while( ( nY += nDistY ) <= nBottom )
280         {
281             aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY );
282         }
283     }
284 
285     if( ( nFlags & DrawGridFlags::Dots ) || ( nFlags & DrawGridFlags::VertLines ) )
286     {
287         aHorzBuf.resize( aDstRect.GetWidth() / nDistX + 2 );
288         aHorzBuf[ nHorzCount++ ] = nStartX;
289         while( ( nX += nDistX ) <= nRight )
290         {
291             aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX );
292         }
293     }
294 
295     if( mbInitLineColor )
296         InitLineColor();
297 
298     if( mbInitFillColor )
299         InitFillColor();
300 
301     const bool bOldMap = mbMap;
302     EnableMapMode( false );
303 
304     if( nFlags & DrawGridFlags::Dots )
305     {
306         for( tools::Long i = 0; i < nVertCount; i++ )
307         {
308             for( tools::Long j = 0, Y = aVertBuf[ i ]; j < nHorzCount; j++ )
309             {
310                 mpGraphics->DrawPixel( aHorzBuf[ j ], Y, *this );
311             }
312         }
313     }
314     else
315     {
316         if( nFlags & DrawGridFlags::HorzLines )
317         {
318             for( tools::Long i = 0; i < nVertCount; i++ )
319             {
320                 nY = aVertBuf[ i ];
321                 mpGraphics->DrawLine( nStartX, nY, nEndX, nY, *this );
322             }
323         }
324 
325         if( nFlags & DrawGridFlags::VertLines )
326         {
327             for( tools::Long i = 0; i < nHorzCount; i++ )
328             {
329                 nX = aHorzBuf[ i ];
330                 mpGraphics->DrawLine( nX, nStartY, nX, nEndY, *this );
331             }
332         }
333     }
334 
335     EnableMapMode( bOldMap );
336 
337     if( mpAlphaVDev )
338         mpAlphaVDev->DrawGrid( rRect, rDist, nFlags );
339 }
340 
AdjustTwoRect(SalTwoRect & rTwoRect,const Size & rSizePix)341 BmpMirrorFlags AdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix )
342 {
343     BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
344 
345     if ( rTwoRect.mnDestWidth < 0 )
346     {
347         rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
348         rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
349         rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
350         nMirrFlags |= BmpMirrorFlags::Horizontal;
351     }
352 
353     if ( rTwoRect.mnDestHeight < 0 )
354     {
355         rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
356         rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
357         rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
358         nMirrFlags |= BmpMirrorFlags::Vertical;
359     }
360 
361     if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
362         ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
363         ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
364         ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
365     {
366         const tools::Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
367                                      Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
368         tools::Rectangle aCropRect( aSourceRect );
369 
370         aCropRect.Intersection( tools::Rectangle( Point(), rSizePix ) );
371 
372         if( aCropRect.IsEmpty() )
373         {
374             rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
375         }
376         else
377         {
378             const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? static_cast<double>( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
379             const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? static_cast<double>( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
380 
381             const tools::Long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
382             const tools::Long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
383             const tools::Long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
384             const tools::Long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
385 
386             rTwoRect.mnSrcX = aCropRect.Left();
387             rTwoRect.mnSrcY = aCropRect.Top();
388             rTwoRect.mnSrcWidth = aCropRect.GetWidth();
389             rTwoRect.mnSrcHeight = aCropRect.GetHeight();
390             rTwoRect.mnDestX = nDstX1;
391             rTwoRect.mnDestY = nDstY1;
392             rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
393             rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
394         }
395     }
396 
397     return nMirrFlags;
398 }
399 
AdjustTwoRect(SalTwoRect & rTwoRect,const tools::Rectangle & rValidSrcRect)400 void AdjustTwoRect( SalTwoRect& rTwoRect, const tools::Rectangle& rValidSrcRect )
401 {
402     if( !(( rTwoRect.mnSrcX < rValidSrcRect.Left() ) || ( rTwoRect.mnSrcX >= rValidSrcRect.Right() ) ||
403         ( rTwoRect.mnSrcY < rValidSrcRect.Top() ) || ( rTwoRect.mnSrcY >= rValidSrcRect.Bottom() ) ||
404         ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rValidSrcRect.Right() ) ||
405         ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rValidSrcRect.Bottom() )) )
406         return;
407 
408     const tools::Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
409                                  Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
410     tools::Rectangle aCropRect( aSourceRect );
411 
412     aCropRect.Intersection( rValidSrcRect );
413 
414     if( aCropRect.IsEmpty() )
415     {
416         rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
417     }
418     else
419     {
420         const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? static_cast<double>( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
421         const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? static_cast<double>( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
422 
423         const tools::Long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
424         const tools::Long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
425         const tools::Long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
426         const tools::Long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
427 
428         rTwoRect.mnSrcX = aCropRect.Left();
429         rTwoRect.mnSrcY = aCropRect.Top();
430         rTwoRect.mnSrcWidth = aCropRect.GetWidth();
431         rTwoRect.mnSrcHeight = aCropRect.GetHeight();
432         rTwoRect.mnDestX = nDstX1;
433         rTwoRect.mnDestY = nDstY1;
434         rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
435         rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
436     }
437 }
438 
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
440