/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/types.h>
#include <tools/poly.hxx>
#include <tools/helpers.hxx>
#include <vcl/metaact.hxx>
#include <vcl/virdev.hxx>
#include <salgdi.hxx>
#include <cassert>
void OutputDevice::DrawBorder(tools::Rectangle aBorderRect)
{
sal_uInt16 nPixel = static_cast<sal_uInt16>(PixelToLogic(Size(1, 1)).Width());
aBorderRect.AdjustLeft(nPixel);
aBorderRect.AdjustTop(nPixel);
SetLineColor(COL_LIGHTGRAY);
DrawRect(aBorderRect);
aBorderRect.AdjustLeft(-nPixel);
aBorderRect.AdjustTop(-nPixel);
aBorderRect.AdjustRight(-nPixel);
aBorderRect.AdjustBottom(-nPixel);
SetLineColor(COL_GRAY);
DrawRect(aBorderRect);
}
void OutputDevice::DrawRect( const tools::Rectangle& rRect )
{
assert(!is_double_buffered_window());
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaRectAction( rRect ) );
if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
return;
tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
if ( aRect.IsEmpty() )
return;
aRect.Normalize();
if ( !mpGraphics && !AcquireGraphics() )
return;
assert(mpGraphics);
if ( mbInitClipRegion )
InitClipRegion();
if ( mbOutputClipped )
return;
if ( mbInitLineColor )
InitLineColor();
if ( mbInitFillColor )
InitFillColor();
mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), *this );
}
void OutputDevice::DrawRect( const tools::Rectangle& rRect,
sal_uLong nHorzRound, sal_uLong nVertRound )
{
assert(!is_double_buffered_window());
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaRoundRectAction( rRect, nHorzRound, nVertRound ) );
if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
return;
const tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
if ( aRect.IsEmpty() )
return;
nHorzRound = ImplLogicWidthToDevicePixel( nHorzRound );
nVertRound = ImplLogicHeightToDevicePixel( nVertRound );
// we need a graphics
if ( !mpGraphics && !AcquireGraphics() )
return;
assert(mpGraphics);
if ( mbInitClipRegion )
InitClipRegion();
if ( mbOutputClipped )
return;
if ( mbInitLineColor )
InitLineColor();
if ( mbInitFillColor )
InitFillColor();
if ( !nHorzRound && !nVertRound )
{
mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), *this );
}
else
{
tools::Polygon aRoundRectPoly( aRect, nHorzRound, nVertRound );
if ( aRoundRectPoly.GetSize() >= 2 )
{
Point* pPtAry = aRoundRectPoly.GetPointAry();
if ( !mbFillColor )
mpGraphics->DrawPolyLine( aRoundRectPoly.GetSize(), pPtAry, *this );
else
mpGraphics->DrawPolygon( aRoundRectPoly.GetSize(), pPtAry, *this );
}
}
}
void OutputDevice::Invert( const tools::Rectangle& rRect, InvertFlags nFlags )
{
assert(!is_double_buffered_window());
if ( !IsDeviceOutputNecessary() )
return;
tools::Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
if ( aRect.IsEmpty() )
return;
aRect.Normalize();
// we need a graphics
if ( !mpGraphics && !AcquireGraphics() )
return;
assert(mpGraphics);
if ( mbInitClipRegion )
InitClipRegion();
if ( mbOutputClipped )
return;
SalInvert nSalFlags = SalInvert::NONE;
if ( nFlags & InvertFlags::N50 )
nSalFlags |= SalInvert::N50;
if ( nFlags & InvertFlags::TrackFrame )
nSalFlags |= SalInvert::TrackFrame;
mpGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), nSalFlags, *this );
}
void OutputDevice::Invert( const tools::Polygon& rPoly, InvertFlags nFlags )
{
assert(!is_double_buffered_window());
if ( !IsDeviceOutputNecessary() )
return;
sal_uInt16 nPoints = rPoly.GetSize();
if ( nPoints < 2 )
return;
tools::Polygon aPoly( ImplLogicToDevicePixel( rPoly ) );
// we need a graphics
if ( !mpGraphics && !AcquireGraphics() )
return;
assert(mpGraphics);
if ( mbInitClipRegion )
InitClipRegion();
if ( mbOutputClipped )
return;
SalInvert nSalFlags = SalInvert::NONE;
if ( nFlags & InvertFlags::N50 )
nSalFlags |= SalInvert::N50;
if ( nFlags & InvertFlags::TrackFrame )
nSalFlags |= SalInvert::TrackFrame;
const Point* pPtAry = aPoly.GetConstPointAry();
mpGraphics->Invert( nPoints, pPtAry, nSalFlags, *this );
}
void OutputDevice::DrawCheckered(const Point& rPos, const Size& rSize, sal_uInt32 nLen, Color aStart, Color aEnd)
{
assert(!is_double_buffered_window());
const sal_uInt32 nMaxX(rPos.X() + rSize.Width());
const sal_uInt32 nMaxY(rPos.Y() + rSize.Height());
auto popIt = ScopedPush(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
SetLineColor();
for(sal_uInt32 x(0), nX(rPos.X()); nX < nMaxX; x++, nX += nLen)
{
const sal_uInt32 nRight(std::min(nMaxX, nX + nLen));
for(sal_uInt32 y(0), nY(rPos.Y()); nY < nMaxY; y++, nY += nLen)
{
const sal_uInt32 nBottom(std::min(nMaxY, nY + nLen));
SetFillColor(((x & 0x0001) ^ (y & 0x0001)) ? aStart : aEnd);
DrawRect(tools::Rectangle(nX, nY, nRight, nBottom));
}
}
}
void OutputDevice::DrawGrid( const tools::Rectangle& rRect, const Size& rDist, DrawGridFlags nFlags )
{
assert(!is_double_buffered_window());
tools::Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() );
aDstRect.Intersection( rRect );
if( aDstRect.IsEmpty() || ImplIsRecordLayout() )
return;
if( !mpGraphics && !AcquireGraphics() )
return;
assert(mpGraphics);
if( mbInitClipRegion )
InitClipRegion();
if( mbOutputClipped )
return;
const tools::Long nDistX = std::max( rDist.Width(), tools::Long(1) );
const tools::Long nDistY = std::max( rDist.Height(), tools::Long(1) );
tools::Long nX = ( rRect.Left() >= aDstRect.Left() ) ? rRect.Left() : ( rRect.Left() + ( ( aDstRect.Left() - rRect.Left() ) / nDistX ) * nDistX );
tools::Long nY = ( rRect.Top() >= aDstRect.Top() ) ? rRect.Top() : ( rRect.Top() + ( ( aDstRect.Top() - rRect.Top() ) / nDistY ) * nDistY );
const tools::Long nRight = aDstRect.Right();
const tools::Long nBottom = aDstRect.Bottom();
const tools::Long nStartX = ImplLogicXToDevicePixel( nX );
const tools::Long nEndX = ImplLogicXToDevicePixel( nRight );
const tools::Long nStartY = ImplLogicYToDevicePixel( nY );
const tools::Long nEndY = ImplLogicYToDevicePixel( nBottom );
tools::Long nHorzCount = 0;
tools::Long nVertCount = 0;
std::vector< sal_Int32 > aVertBuf;
std::vector< sal_Int32 > aHorzBuf;
if( ( nFlags & DrawGridFlags::Dots ) || ( nFlags & DrawGridFlags::HorzLines ) )
{
aVertBuf.resize( aDstRect.GetHeight() / nDistY + 2 );
aVertBuf[ nVertCount++ ] = nStartY;
while( ( nY += nDistY ) <= nBottom )
{
aVertBuf[ nVertCount++ ] = ImplLogicYToDevicePixel( nY );
}
}
if( ( nFlags & DrawGridFlags::Dots ) || ( nFlags & DrawGridFlags::VertLines ) )
{
aHorzBuf.resize( aDstRect.GetWidth() / nDistX + 2 );
aHorzBuf[ nHorzCount++ ] = nStartX;
while( ( nX += nDistX ) <= nRight )
{
aHorzBuf[ nHorzCount++ ] = ImplLogicXToDevicePixel( nX );
}
}
if( mbInitLineColor )
InitLineColor();
if( mbInitFillColor )
InitFillColor();
const bool bOldMap = mbMap;
EnableMapMode( false );
if( nFlags & DrawGridFlags::Dots )
{
for( tools::Long i = 0; i < nVertCount; i++ )
{
for( tools::Long j = 0, Y = aVertBuf[ i ]; j < nHorzCount; j++ )
{
mpGraphics->DrawPixel( aHorzBuf[ j ], Y, *this );
}
}
}
else
{
if( nFlags & DrawGridFlags::HorzLines )
{
for( tools::Long i = 0; i < nVertCount; i++ )
{
nY = aVertBuf[ i ];
mpGraphics->DrawLine( nStartX, nY, nEndX, nY, *this );
}
}
if( nFlags & DrawGridFlags::VertLines )
{
for( tools::Long i = 0; i < nHorzCount; i++ )
{
nX = aHorzBuf[ i ];
mpGraphics->DrawLine( nX, nStartY, nX, nEndY, *this );
}
}
}
EnableMapMode( bOldMap );
}
void OutputDevice::DrawGridOfCrosses(const tools::Rectangle& rGridArea, const Size& rGridDistance,
const tools::Rectangle& rDrawingArea)
{
assert(!is_double_buffered_window());
if (!mbLineColor || ImplIsRecordLayout())
{
return;
}
if (!mpGraphics && !AcquireGraphics())
{
return;
}
assert(mpGraphics);
if (mbInitClipRegion)
{
InitClipRegion();
}
if (mbOutputClipped)
{
return;
}
if (mbInitLineColor)
{
InitLineColor();
}
if (rDrawingArea.IsEmpty())
{
return;
}
const tools::Long nDistanceX = rGridDistance.Width();
const tools::Long nDistanceY = rGridDistance.Height();
tools::Long nX = rGridArea.Left();
tools::Long nY = rGridArea.Top();
// Collect horizontal positions of the grid points
std::vector<tools::Long> aHorzBuffer;
aHorzBuffer.reserve(rGridArea.GetWidth() / nDistanceX + 1);
while (nX <= rGridArea.Right())
{
aHorzBuffer.push_back(nX);
nX += nDistanceX;
}
// Collect vertical positions of the grid points
std::vector<tools::Long> aVertBuffer;
aVertBuffer.reserve(rGridArea.GetHeight() / nDistanceY + 1);
while (nY <= rGridArea.Bottom())
{
aVertBuffer.push_back(nY);
nY += nDistanceY;
}
const tools::Long nTopPixel = ImplLogicYToDevicePixel(rDrawingArea.Top());
const tools::Long nBottomPixel = ImplLogicYToDevicePixel(rDrawingArea.Bottom());
const tools::Long nLeftPixel = ImplLogicXToDevicePixel(rDrawingArea.Left());
const tools::Long nRightPixel = ImplLogicXToDevicePixel(rDrawingArea.Right());
// Draw 3x3 pixel crosses within the drawing area
const tools::Long nHalfCrossSize = 1;
for (const tools::Long nPositionX : aHorzBuffer)
{
const tools::Long nPositionXPixel = ImplLogicXToDevicePixel(nPositionX);
for (const tools::Long nPositionY : aVertBuffer)
{
const tools::Long nPositionYPixel = ImplLogicYToDevicePixel(nPositionY);
const tools::Long nStartXPixel = std::max(nPositionXPixel - nHalfCrossSize, nLeftPixel);
if (nStartXPixel > nRightPixel)
{
continue;
}
const tools::Long nEndXPixel
= std::min(nPositionXPixel + nHalfCrossSize + 1, nRightPixel);
if (nEndXPixel < nLeftPixel)
{
continue;
}
const tools::Long nStartYPixel = std::max(nPositionYPixel - nHalfCrossSize, nTopPixel);
if (nStartYPixel > nBottomPixel)
{
continue;
}
const tools::Long nEndYPixel
= std::min(nPositionYPixel + nHalfCrossSize + 1, nBottomPixel);
if (nEndYPixel < nTopPixel)
{
continue;
}
const bool bOldMap = mbMap;
EnableMapMode(false);
// Draw horizontal line if visible
if (nPositionY >= rDrawingArea.Top() && nPositionY <= rDrawingArea.Bottom())
{
mpGraphics->DrawLine(nStartXPixel, nPositionYPixel, nEndXPixel, nPositionYPixel,
*this);
}
// Draw vertical line if visible
if (nPositionX >= rDrawingArea.Left() && nPositionX <= rDrawingArea.Right())
{
mpGraphics->DrawLine(nPositionXPixel, nStartYPixel, nPositionXPixel, nEndYPixel,
*this);
}
EnableMapMode(bOldMap);
}
}
}
BmpMirrorFlags AdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix )
{
BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
if ( rTwoRect.mnDestWidth < 0 )
{
rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
nMirrFlags |= BmpMirrorFlags::Horizontal;
}
if ( rTwoRect.mnDestHeight < 0 )
{
rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
nMirrFlags |= BmpMirrorFlags::Vertical;
}
if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
{
const tools::Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
tools::Rectangle aCropRect( aSourceRect );
aCropRect.Intersection( tools::Rectangle( Point(), rSizePix ) );
if( aCropRect.IsEmpty() )
{
rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
}
else
{
const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? static_cast<double>( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? static_cast<double>( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
const tools::Long nDstX1 = rTwoRect.mnDestX + basegfx::fround<tools::Long>( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
const tools::Long nDstY1 = rTwoRect.mnDestY + basegfx::fround<tools::Long>( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
const tools::Long nDstX2 = rTwoRect.mnDestX + basegfx::fround<tools::Long>( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
const tools::Long nDstY2 = rTwoRect.mnDestY + basegfx::fround<tools::Long>( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
rTwoRect.mnSrcX = aCropRect.Left();
rTwoRect.mnSrcY = aCropRect.Top();
rTwoRect.mnSrcWidth = aCropRect.GetWidth();
rTwoRect.mnSrcHeight = aCropRect.GetHeight();
rTwoRect.mnDestX = nDstX1;
rTwoRect.mnDestY = nDstY1;
rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
}
}
return nMirrFlags;
}
void AdjustTwoRect( SalTwoRect& rTwoRect, const tools::Rectangle& rValidSrcRect )
{
if( !(( rTwoRect.mnSrcX < rValidSrcRect.Left() ) || ( rTwoRect.mnSrcX >= rValidSrcRect.Right() ) ||
( rTwoRect.mnSrcY < rValidSrcRect.Top() ) || ( rTwoRect.mnSrcY >= rValidSrcRect.Bottom() ) ||
( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rValidSrcRect.Right() ) ||
( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rValidSrcRect.Bottom() )) )
return;
const tools::Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
tools::Rectangle aCropRect( aSourceRect );
aCropRect.Intersection( rValidSrcRect );
if( aCropRect.IsEmpty() )
{
rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
}
else
{
const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? static_cast<double>( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? static_cast<double>( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
const tools::Long nDstX1 = rTwoRect.mnDestX + basegfx::fround<tools::Long>( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
const tools::Long nDstY1 = rTwoRect.mnDestY + basegfx::fround<tools::Long>( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
const tools::Long nDstX2 = rTwoRect.mnDestX + basegfx::fround<tools::Long>( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
const tools::Long nDstY2 = rTwoRect.mnDestY + basegfx::fround<tools::Long>( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
rTwoRect.mnSrcX = aCropRect.Left();
rTwoRect.mnSrcY = aCropRect.Top();
rTwoRect.mnSrcWidth = aCropRect.GetWidth();
rTwoRect.mnSrcHeight = aCropRect.GetHeight();
rTwoRect.mnDestX = nDstX1;
rTwoRect.mnDestY = nDstY1;
rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Intersection' is required to be utilized.
↑ V530 The return value of function 'Intersection' is required to be utilized.
↑ V530 The return value of function 'Intersection' is required to be utilized.