mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-10 19:35:55 +08:00
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com> Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
289 lines
7.4 KiB
C++
289 lines
7.4 KiB
C++
/*
|
|
* Copyright (C) Ascensio System SIA, 2009-2026
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation, together with the
|
|
* additional terms provided in the LICENSE file.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA by email at info@onlyoffice.com
|
|
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
|
|
* LV-1050, Latvia, European Union.
|
|
*
|
|
* The interactive user interfaces in modified versions of the Program
|
|
* are required to display Appropriate Legal Notices in accordance with
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* No trademark rights are granted under this License.
|
|
*
|
|
* All non-code elements of the Product, including illustrations,
|
|
* icon sets, and technical writing content, are licensed under the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International License:
|
|
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
* This license applies only to such non-code elements and does not
|
|
* modify or replace the licensing terms applicable to the Program's
|
|
* source code, which remains licensed under the GNU Affero General
|
|
* Public License v3.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
#include "FontPath.h"
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// CPath
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Path can be in one of the following three states:
|
|
//
|
|
// 1. No current point -- zero or more finished SubPaths
|
|
// [m_nCurSubpath == m_nPointsCount]
|
|
//
|
|
// 2. One point in SubPaths
|
|
// [m_nCurSubpath == m_nPointsCount - 1]
|
|
//
|
|
// 3. Open SubPaths with two or more points
|
|
// [m_nCurSubpath < m_nPointsCount - 1]
|
|
|
|
CFontPath::CFontPath() : NSFonts::IFontPath()
|
|
{
|
|
m_pPoints = NULL;
|
|
m_pFlags = NULL;
|
|
m_nPointsCount = m_nSize = 0;
|
|
m_nCurSubpath = 0;
|
|
|
|
m_pHints = NULL;
|
|
m_nHintsCount = m_nHintsSize = 0;
|
|
}
|
|
|
|
CFontPath::CFontPath(CFontPath *pPath) : NSFonts::IFontPath()
|
|
{
|
|
m_nPointsCount = pPath->m_nPointsCount;
|
|
m_nSize = pPath->m_nSize;
|
|
m_pPoints = (TPathPoint *)malloc( m_nSize * sizeof(TPathPoint) );
|
|
m_pFlags = (unsigned char *)malloc( m_nSize * sizeof(unsigned char) );
|
|
|
|
memcpy( m_pPoints, pPath->m_pPoints, m_nPointsCount * sizeof(TPathPoint) );
|
|
memcpy( m_pFlags, pPath->m_pFlags, m_nPointsCount * sizeof(unsigned char) );
|
|
|
|
m_nCurSubpath = pPath->m_nCurSubpath;
|
|
|
|
if ( pPath->m_pHints )
|
|
{
|
|
m_nHintsCount = m_nHintsSize = pPath->m_nHintsCount;
|
|
m_pHints = (TPathHint *)malloc( m_nHintsSize * sizeof(TPathHint) );
|
|
memcpy( m_pHints, pPath->m_pHints, m_nHintsCount * sizeof(TPathHint) );
|
|
}
|
|
else
|
|
{
|
|
m_pHints = NULL;
|
|
}
|
|
}
|
|
|
|
CFontPath::~CFontPath()
|
|
{
|
|
free( m_pPoints );
|
|
free( m_pFlags );
|
|
free( m_pHints );
|
|
}
|
|
|
|
void CFontPath::Resize(int nPointsCount)
|
|
{
|
|
if ( m_nPointsCount + nPointsCount > m_nSize )
|
|
{
|
|
if ( m_nSize == 0 )
|
|
{
|
|
m_nSize = 32;
|
|
}
|
|
while ( m_nSize < m_nPointsCount + nPointsCount )
|
|
{
|
|
m_nSize *= 2;
|
|
}
|
|
m_pPoints = (TPathPoint *)realloc( m_pPoints, m_nSize * sizeof(TPathPoint) );
|
|
m_pFlags = (unsigned char *)realloc( m_pFlags, m_nSize * sizeof(unsigned char) );
|
|
}
|
|
}
|
|
|
|
void CFontPath::Append(CFontPath *pPath)
|
|
{
|
|
m_nCurSubpath = m_nPointsCount + pPath->m_nCurSubpath;
|
|
Resize( pPath->m_nPointsCount );
|
|
|
|
for ( int nIndex = 0; nIndex < pPath->m_nPointsCount; ++nIndex )
|
|
{
|
|
m_pPoints[m_nPointsCount] = pPath->m_pPoints[nIndex];
|
|
m_pFlags[m_nPointsCount] = pPath->m_pFlags[nIndex];
|
|
++m_nPointsCount;
|
|
}
|
|
}
|
|
|
|
int CFontPath::MoveTo(double dX, double dY)
|
|
{
|
|
if ( OnePointSubpath() )
|
|
{
|
|
return -1;
|
|
}
|
|
Resize(1);
|
|
m_pPoints[m_nPointsCount].dX = dX;
|
|
m_pPoints[m_nPointsCount].dY = dY;
|
|
m_pFlags[m_nPointsCount] = PathFirst | PathLast;
|
|
m_nCurSubpath = m_nPointsCount++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CFontPath::LineTo(double dX, double dY)
|
|
{
|
|
if ( NoCurrentPoint() )
|
|
{
|
|
return -1;
|
|
}
|
|
m_pFlags[m_nPointsCount - 1] &= ~PathLast;
|
|
Resize(1);
|
|
|
|
m_pPoints[m_nPointsCount].dX = dX;
|
|
m_pPoints[m_nPointsCount].dY = dY;
|
|
m_pFlags[m_nPointsCount] = PathLast;
|
|
++m_nPointsCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CFontPath::CurveTo(double dX1, double dY1, double dX2, double dY2, double dX3, double dY3)
|
|
{
|
|
if ( NoCurrentPoint() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
m_pFlags[m_nPointsCount-1] &= ~PathLast;
|
|
Resize(3);
|
|
|
|
m_pPoints[m_nPointsCount].dX = dX1;
|
|
m_pPoints[m_nPointsCount].dY = dY1;
|
|
m_pFlags[m_nPointsCount] = PathCurve;
|
|
++m_nPointsCount;
|
|
|
|
m_pPoints[m_nPointsCount].dX = dX2;
|
|
m_pPoints[m_nPointsCount].dY = dY2;
|
|
m_pFlags[m_nPointsCount] = PathCurve;
|
|
++m_nPointsCount;
|
|
|
|
m_pPoints[m_nPointsCount].dX = dX3;
|
|
m_pPoints[m_nPointsCount].dY = dY3;
|
|
m_pFlags[m_nPointsCount] = PathLast;
|
|
++m_nPointsCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CFontPath::Close()
|
|
{
|
|
if ( NoCurrentPoint() )
|
|
{
|
|
return -1;
|
|
}
|
|
if ( m_nCurSubpath == m_nPointsCount - 1 || m_pPoints[m_nPointsCount - 1].dX != m_pPoints[m_nCurSubpath].dX || m_pPoints[m_nPointsCount - 1].dY != m_pPoints[m_nCurSubpath].dY )
|
|
{
|
|
LineTo( m_pPoints[m_nCurSubpath].dX, m_pPoints[m_nCurSubpath].dY );
|
|
}
|
|
|
|
m_pFlags[m_nCurSubpath] |= PathClosed;
|
|
m_pFlags[m_nPointsCount - 1] |= PathClosed;
|
|
m_nCurSubpath = m_nPointsCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CFontPath::AddStrokeAdjustHint(int nFirstControl, int nSecondControl, int nFirstPoint, int nLastPoint)
|
|
{
|
|
if ( m_nHintsCount == m_nHintsSize )
|
|
{
|
|
m_nHintsSize = m_nHintsCount ? 2 * m_nHintsCount : 8;
|
|
m_pHints = (TPathHint *)realloc( m_pHints, m_nHintsSize * sizeof(TPathHint) );
|
|
}
|
|
m_pHints[m_nHintsCount].nFirstControl = nFirstControl;
|
|
m_pHints[m_nHintsCount].nSecondControl = nSecondControl;
|
|
m_pHints[m_nHintsCount].nFirstPoint = nFirstPoint;
|
|
m_pHints[m_nHintsCount].nLastPoint = nLastPoint;
|
|
|
|
++m_nHintsCount;
|
|
}
|
|
|
|
void CFontPath::Offset(double dDx, double dDy)
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
|
|
{
|
|
m_pPoints[nIndex].dX += dDx;
|
|
m_pPoints[nIndex].dY += dDy;
|
|
}
|
|
}
|
|
|
|
void CFontPath::Reverse()
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
|
|
{
|
|
m_pPoints[nIndex].dY = -m_pPoints[nIndex].dY;
|
|
}
|
|
}
|
|
|
|
void CFontPath::ToMM(double dHorDpi, double dVerDpi)
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
|
|
{
|
|
m_pPoints[nIndex].dX *= 25.4 / dHorDpi;
|
|
m_pPoints[nIndex].dY *= 25.4 / dVerDpi;
|
|
}
|
|
}
|
|
|
|
INT CFontPath::GetCurPoint(double *pdX, double *pdY)
|
|
{
|
|
if ( NoCurrentPoint() )
|
|
{
|
|
return FALSE;
|
|
}
|
|
*pdX = m_pPoints[m_nPointsCount - 1].dX;
|
|
*pdY = m_pPoints[m_nPointsCount - 1].dY;
|
|
return TRUE;
|
|
}
|
|
|
|
int CFontPath::ToInterface(NSFonts::ISimpleGraphicsPath* pPath)
|
|
{
|
|
if ( !pPath )
|
|
return FALSE;
|
|
|
|
for ( int nIndex = 0; nIndex < m_nPointsCount; )
|
|
{
|
|
TPathPoint oPoint = m_pPoints[nIndex];
|
|
unsigned char nFlag = m_pFlags[nIndex];
|
|
|
|
if ( nFlag & PathFirst )
|
|
{
|
|
pPath->_MoveTo( oPoint.dX, oPoint.dY );
|
|
nIndex++;
|
|
}
|
|
else if ( nFlag & PathCurve )
|
|
{
|
|
pPath->_CurveTo( m_pPoints[nIndex + 0].dX, m_pPoints[nIndex + 0].dY, m_pPoints[nIndex + 1].dX, m_pPoints[nIndex + 1].dY, m_pPoints[nIndex + 2].dX, m_pPoints[nIndex + 2].dY );
|
|
nIndex += 3;
|
|
}
|
|
else
|
|
{
|
|
pPath->_LineTo( oPoint.dX, oPoint.dY );
|
|
nIndex++;
|
|
}
|
|
|
|
if ( nFlag & PathClosed && nFlag & PathLast )
|
|
{
|
|
pPath->_Close();
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|