mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
418 lines
10 KiB
C++
418 lines
10 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "MemoryUtils.h"
|
|
#include "SErrorCodes.h"
|
|
#include "SPath.h"
|
|
#include "SXPath.h"
|
|
#include "SXPathScanner.h"
|
|
#include "SBitmap.h"
|
|
#include "SClip.h"
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// SClip.nFlags
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#define ClipEOFlag 0x01 // Èñïîëüçóåì ïðàâèëî Even-odd
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// SClip
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
SClip::SClip(double dMinX, double dMinY, double dMaxX, double dMaxY, BOOL bAntialias)
|
|
{
|
|
m_bAntiAlias = bAntialias;
|
|
if ( dMinX < dMaxX )
|
|
{
|
|
m_dMinX = dMinX;
|
|
m_dMaxX = dMaxX;
|
|
}
|
|
else
|
|
{
|
|
m_dMinX = dMaxX;
|
|
m_dMaxX = dMinX;
|
|
}
|
|
if ( dMinY < dMaxY )
|
|
{
|
|
m_dMinY = dMinY;
|
|
m_dMaxY = dMaxY;
|
|
}
|
|
else
|
|
{
|
|
m_dMinY = dMaxY;
|
|
m_dMaxY = dMinY;
|
|
}
|
|
|
|
m_nMinX = (int)floor( m_dMinX );
|
|
m_nMinY = (int)floor( m_dMinY );
|
|
m_nMaxX = (int)floor( m_dMaxX );
|
|
m_nMaxY = (int)floor( m_dMaxY );
|
|
|
|
m_ppPaths = NULL;
|
|
m_pFlags = NULL;
|
|
m_pScanners = NULL;
|
|
|
|
m_nPathsCount = m_nSize = 0;
|
|
}
|
|
|
|
SClip::SClip(SClip *pClip)
|
|
{
|
|
m_bAntiAlias = pClip->m_bAntiAlias;
|
|
|
|
m_dMinX = pClip->m_dMinX;
|
|
m_dMinY = pClip->m_dMinY;
|
|
m_dMaxX = pClip->m_dMaxX;
|
|
m_dMaxY = pClip->m_dMaxY;
|
|
m_nMinX = pClip->m_nMinX;
|
|
m_nMinY = pClip->m_nMinY;
|
|
m_nMaxX = pClip->m_nMaxX;
|
|
m_nMaxY = pClip->m_nMaxY;
|
|
|
|
m_nPathsCount = pClip->m_nPathsCount;
|
|
m_nSize = pClip->m_nSize;
|
|
|
|
m_ppPaths = (SXPath **)MemUtilsMallocArray( m_nSize, sizeof(SXPath *));
|
|
m_pFlags = (unsigned char *)MemUtilsMallocArray( m_nSize, sizeof(unsigned char));
|
|
m_pScanners = (SXPathScanner **)MemUtilsMallocArray( m_nSize, sizeof(SXPathScanner *));
|
|
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
m_ppPaths[nIndex] = pClip->m_ppPaths[nIndex]->Copy();
|
|
m_pFlags[nIndex] = pClip->m_pFlags[nIndex];
|
|
m_pScanners[nIndex] = new SXPathScanner( m_ppPaths[nIndex], m_pFlags[nIndex] & ClipEOFlag );
|
|
}
|
|
}
|
|
|
|
SClip::~SClip()
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( m_ppPaths[nIndex] )
|
|
delete m_ppPaths[nIndex];
|
|
if ( m_pScanners[nIndex] )
|
|
delete m_pScanners[nIndex];
|
|
}
|
|
|
|
MemUtilsFree( m_ppPaths );
|
|
MemUtilsFree( m_pFlags );
|
|
MemUtilsFree( m_pScanners );
|
|
}
|
|
|
|
void SClip::Resize(int nPathsCount)
|
|
{
|
|
if ( m_nPathsCount + nPathsCount > m_nSize )
|
|
{
|
|
if ( m_nSize == 0 )
|
|
{
|
|
m_nSize = 32;
|
|
}
|
|
while ( m_nSize < m_nPathsCount + nPathsCount )
|
|
{
|
|
m_nSize *= 2;
|
|
}
|
|
|
|
m_ppPaths = (SXPath **)MemUtilsReallocArray( m_ppPaths, m_nSize, sizeof(SXPath *));
|
|
m_pFlags = (unsigned char *)MemUtilsReallocArray( m_pFlags, m_nSize, sizeof(unsigned char));
|
|
m_pScanners = (SXPathScanner **)MemUtilsReallocArray( m_pScanners, m_nSize, sizeof(SXPathScanner *));
|
|
}
|
|
}
|
|
|
|
void SClip::ResetToRect(double dX0, double dY0, double dX1, double dY1)
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( m_ppPaths[nIndex] )
|
|
delete m_ppPaths[nIndex];
|
|
if ( m_pScanners[nIndex] )
|
|
delete m_pScanners[nIndex];
|
|
}
|
|
|
|
MemUtilsFree( m_ppPaths );
|
|
MemUtilsFree( m_pFlags );
|
|
MemUtilsFree( m_pScanners );
|
|
|
|
m_ppPaths = NULL;
|
|
m_pFlags = NULL;
|
|
m_pScanners = NULL;
|
|
|
|
m_nPathsCount = m_nSize = 0;
|
|
|
|
if ( dX0 < dX1 )
|
|
{
|
|
m_dMinX = dX0;
|
|
m_dMaxX = dX1;
|
|
}
|
|
else
|
|
{
|
|
m_dMinX = dX1;
|
|
m_dMaxX = dX0;
|
|
}
|
|
|
|
if ( dY0 < dY1 )
|
|
{
|
|
m_dMinY = dY0;
|
|
m_dMaxY = dY1;
|
|
}
|
|
else
|
|
{
|
|
m_dMinY = dY1;
|
|
m_dMaxY = dY0;
|
|
}
|
|
|
|
m_nMinX = (int)floor(m_dMinX);
|
|
m_nMinY = (int)floor(m_dMinY);
|
|
m_nMaxX = (int)floor(m_dMaxX);
|
|
m_nMaxY = (int)floor(m_dMaxY);
|
|
}
|
|
|
|
int SClip::ClipToRect(double dX0, double dY0, double dX1, double dY1)
|
|
{
|
|
if ( dX0 < dX1 )
|
|
{
|
|
if ( dX0 > m_dMinX )
|
|
{
|
|
m_dMinX = dX0;
|
|
m_nMinX = (int)floor(m_dMinX);
|
|
}
|
|
if ( dX1 < m_dMaxX )
|
|
{
|
|
m_dMaxX = dX1;
|
|
m_nMaxX = (int)floor(m_dMaxX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dX1 > m_dMinX )
|
|
{
|
|
m_dMinX = dX1;
|
|
m_nMinX = (int)floor(m_dMinX);
|
|
}
|
|
if ( dX0 < m_dMaxX )
|
|
{
|
|
m_dMaxX = dX0;
|
|
m_nMaxX = (int)floor(m_dMaxX);
|
|
}
|
|
}
|
|
|
|
if ( dY0 < dY1 )
|
|
{
|
|
if ( dY0 > m_dMinY )
|
|
{
|
|
m_dMinY = dY0;
|
|
m_nMinY = (int)floor(m_dMinY);
|
|
}
|
|
if ( dY1 < m_dMaxY )
|
|
{
|
|
m_dMaxY = dY1;
|
|
m_nMaxY = (int)floor(m_dMaxY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dY1 > m_dMinY )
|
|
{
|
|
m_dMinY = dY1;
|
|
m_nMinY = (int)floor(m_dMinY);
|
|
}
|
|
if ( dY0 < m_dMaxY )
|
|
{
|
|
m_dMaxY = dY0;
|
|
m_nMaxY = (int)floor(m_dMaxY);
|
|
}
|
|
}
|
|
return SNoError;
|
|
}
|
|
|
|
int SClip::ClipToPath(SPath *pPath, double *pMatrix, double dFlatness, BOOL bEO)
|
|
{
|
|
SXPath *pXPath = new SXPath( pPath, pMatrix, dFlatness, TRUE );
|
|
|
|
// check for an empty path
|
|
if ( pXPath->m_nSegmentsCount == 0 )
|
|
{
|
|
m_dMaxX = m_dMinX - 1;
|
|
m_dMaxY = m_dMinY - 1;
|
|
m_nMaxX = (int)floor(m_dMaxX);
|
|
m_nMaxY = (int)floor(m_dMaxY);
|
|
delete pXPath;
|
|
}
|
|
else if ( pXPath->m_nSegmentsCount == 4 &&
|
|
( ( pXPath->m_pSegments[0].dFirstX == pXPath->m_pSegments[0].dSecondX && pXPath->m_pSegments[0].dFirstX == pXPath->m_pSegments[1].dFirstX &&
|
|
pXPath->m_pSegments[0].dFirstX == pXPath->m_pSegments[3].dSecondX && pXPath->m_pSegments[2].dFirstX == pXPath->m_pSegments[2].dSecondX &&
|
|
pXPath->m_pSegments[2].dFirstX == pXPath->m_pSegments[1].dSecondX && pXPath->m_pSegments[2].dFirstX == pXPath->m_pSegments[3].dFirstX &&
|
|
pXPath->m_pSegments[1].dFirstY == pXPath->m_pSegments[1].dSecondY && pXPath->m_pSegments[1].dFirstY == pXPath->m_pSegments[0].dSecondY &&
|
|
pXPath->m_pSegments[1].dFirstY == pXPath->m_pSegments[2].dFirstY && pXPath->m_pSegments[3].dFirstY == pXPath->m_pSegments[3].dSecondY &&
|
|
pXPath->m_pSegments[3].dFirstY == pXPath->m_pSegments[0].dFirstY && pXPath->m_pSegments[3].dFirstY == pXPath->m_pSegments[2].dSecondY
|
|
) ||
|
|
( pXPath->m_pSegments[0].dFirstY == pXPath->m_pSegments[0].dSecondY && pXPath->m_pSegments[0].dFirstY == pXPath->m_pSegments[1].dFirstY &&
|
|
pXPath->m_pSegments[0].dFirstY == pXPath->m_pSegments[3].dSecondY && pXPath->m_pSegments[2].dFirstY == pXPath->m_pSegments[2].dSecondY &&
|
|
pXPath->m_pSegments[2].dFirstY == pXPath->m_pSegments[1].dSecondY && pXPath->m_pSegments[2].dFirstY == pXPath->m_pSegments[3].dFirstY &&
|
|
pXPath->m_pSegments[1].dFirstX == pXPath->m_pSegments[1].dSecondX && pXPath->m_pSegments[1].dFirstX == pXPath->m_pSegments[0].dSecondX &&
|
|
pXPath->m_pSegments[1].dFirstX == pXPath->m_pSegments[2].dFirstX && pXPath->m_pSegments[3].dFirstX == pXPath->m_pSegments[3].dSecondX &&
|
|
pXPath->m_pSegments[3].dFirstX == pXPath->m_pSegments[0].dFirstX && pXPath->m_pSegments[3].dFirstX == pXPath->m_pSegments[2].dSecondX ) ) )
|
|
{
|
|
ClipToRect( pXPath->m_pSegments[0].dFirstX, pXPath->m_pSegments[0].dFirstY, pXPath->m_pSegments[2].dFirstX, pXPath->m_pSegments[2].dFirstY );
|
|
delete pXPath;
|
|
}
|
|
else
|
|
{
|
|
Resize(1);
|
|
if ( m_bAntiAlias )
|
|
{
|
|
pXPath->AntiAliasingScale();
|
|
}
|
|
pXPath->Sort();
|
|
|
|
m_ppPaths[m_nPathsCount] = pXPath;
|
|
m_pFlags[m_nPathsCount] = ( bEO ? ClipEOFlag : 0 );
|
|
m_pScanners[m_nPathsCount] = new SXPathScanner( pXPath, bEO );
|
|
++m_nPathsCount;
|
|
}
|
|
|
|
return SNoError;
|
|
}
|
|
|
|
BOOL SClip::IsInsideClip(int dX, int dY)
|
|
{
|
|
// Ïðîâåðÿåì ïîïàëà ëè òî÷êà â îáùèé ðåêò Clip'à.
|
|
if ( dX < m_nMinX || dX > m_nMaxX || dY < m_nMinY || dY > m_nMaxY )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Ïðîâåðÿåì äëÿ êàæäîãî Path.
|
|
if ( m_bAntiAlias )
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( !m_pScanners[nIndex]->IsInsidePath( dX * AntiAliasingSize, dY * AntiAliasingSize ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( !m_pScanners[nIndex]->IsInsidePath( dX, dY ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
SClipResult SClip::CheckRectangle(int dRectMinX, int dRectMinY, int dRectMaxX, int dRectMaxY)
|
|
{
|
|
if ( (double)(dRectMaxX + 1) <= m_dMinX || (double)dRectMinX > m_dMaxX || (double)(dRectMaxY + 1) <= m_dMinY || (double)dRectMinY > m_dMaxY )
|
|
{
|
|
return clipAllOutside;
|
|
}
|
|
|
|
if ( (double)dRectMinX >= m_dMinX && (double)(dRectMaxX + 1) <= m_dMaxX && (double)dRectMinY >= m_dMinY && (double)(dRectMaxY + 1) <= m_dMaxY && m_nPathsCount == 0 )
|
|
{
|
|
return clipAllInside;
|
|
}
|
|
|
|
return clipPartial;
|
|
}
|
|
|
|
SClipResult SClip::CheckSpan(int nSpanMinX, int nSpanMaxX, int nSpanY)
|
|
{
|
|
if ( (double)(nSpanMaxX + 1) <= m_dMinX || (double)nSpanMinX > m_dMaxX || (double)(nSpanY + 1) <= m_dMinY || (double)nSpanY > m_dMaxY )
|
|
{
|
|
return clipAllOutside;
|
|
}
|
|
if ( !( (double)nSpanMinX >= m_dMinX && (double)(nSpanMaxX + 1) <= m_dMaxX && (double)nSpanY >= m_dMinY && (double)(nSpanY + 1) <= m_dMaxY ) )
|
|
{
|
|
return clipPartial;
|
|
}
|
|
|
|
if ( m_bAntiAlias )
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( !m_pScanners[nIndex]->IsInsidePath( nSpanMinX * AntiAliasingSize, nSpanMaxX * AntiAliasingSize + ( AntiAliasingSize - 1 ), nSpanY * AntiAliasingSize ) )
|
|
{
|
|
return clipPartial;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
if ( !m_pScanners[nIndex]->IsInsidePath( nSpanMinX, nSpanMaxX, nSpanY ) )
|
|
{
|
|
return clipPartial;
|
|
}
|
|
}
|
|
}
|
|
return clipAllInside;
|
|
}
|
|
|
|
void SClip::ClipAALine(SBitmap *pAABuffer, int *pnX0, int *pnX1, int nY)
|
|
{
|
|
int nXX, nYY;
|
|
|
|
// Çàíóëÿåì ïèêñåëè äëÿ êîòîðûõ nX < m_dMinX
|
|
int nX0 = *pnX0 * AntiAliasingSize;
|
|
int nX1 = (int)floor(m_dMinX * AntiAliasingSize);
|
|
if ( nX1 > pAABuffer->GetWidth() )
|
|
{
|
|
nX1 = pAABuffer->GetWidth();
|
|
}
|
|
if ( nX0 < nX1 )
|
|
{
|
|
nX0 &= ~7;
|
|
for ( nYY = 0; nYY < AntiAliasingSize; ++nYY )
|
|
{
|
|
SColorPointer pColor = pAABuffer->GetData() + nYY * pAABuffer->GetStride() + (nX0 >> 3);
|
|
for ( nXX = nX0; nXX + 7 < nX1; nXX += 8 )
|
|
{
|
|
*pColor++ = 0;
|
|
}
|
|
if ( nXX < nX1 )
|
|
{
|
|
*pColor &= 0xff >> (nX1 & 7);
|
|
}
|
|
}
|
|
*pnX0 = (int)floor(m_dMinX);
|
|
}
|
|
|
|
// Çàíóëÿåì ïèêñåëè äëÿ êîòîðûõ nX > m_dMaxX
|
|
nX0 = (int)floor(m_dMaxX * AntiAliasingSize) + 1;
|
|
if ( nX0 < 0 )
|
|
{
|
|
nX0 = 0;
|
|
}
|
|
nX1 = (*pnX1 + 1) * AntiAliasingSize;
|
|
if ( nX0 < nX1 )
|
|
{
|
|
for ( nYY = 0; nYY < AntiAliasingSize; ++nYY )
|
|
{
|
|
SColorPointer pColor = pAABuffer->GetData() + nYY * pAABuffer->GetStride() + (nX0 >> 3);
|
|
nXX = nX0;
|
|
if ( nXX & 7 )
|
|
{
|
|
*pColor &= 0xff00 >> (nXX & 7);
|
|
nXX = (nXX & ~7) + 8;
|
|
++pColor;
|
|
}
|
|
for (; nXX < nX1; nXX += 8)
|
|
{
|
|
*pColor++ = 0;
|
|
}
|
|
}
|
|
*pnX1 = (int)floor(m_dMaxX);
|
|
}
|
|
|
|
for ( int nIndex = 0; nIndex < m_nPathsCount; ++nIndex )
|
|
{
|
|
m_pScanners[nIndex]->ClipAALine( pAABuffer, pnX0, pnX1, nY );
|
|
}
|
|
}
|