2002-02-18 08:08:18 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* $RCSfile: sallayout.cxx,v $
|
|
|
|
*
|
2002-06-11 15:35:49 +00:00
|
|
|
* $Revision: 1.12 $
|
2002-02-18 08:08:18 +00:00
|
|
|
*
|
2002-06-11 15:35:49 +00:00
|
|
|
* last change: $Author: hdu $ $Date: 2002-06-11 16:35:49 $
|
2002-02-18 08:08:18 +00:00
|
|
|
*
|
|
|
|
* The Contents of this file are made available subject to the terms of
|
|
|
|
* either of the following licenses
|
|
|
|
*
|
|
|
|
* - GNU Lesser General Public License Version 2.1
|
|
|
|
* - Sun Industry Standards Source License Version 1.1
|
|
|
|
*
|
|
|
|
* Sun Microsystems Inc., October, 2000
|
|
|
|
*
|
|
|
|
* GNU Lesser General Public License Version 2.1
|
|
|
|
* =============================================
|
|
|
|
* Copyright 2000 by Sun Microsystems, Inc.
|
|
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Sun Industry Standards Source License Version 1.1
|
|
|
|
* =================================================
|
|
|
|
* The contents of this file are subject to the Sun Industry Standards
|
|
|
|
* Source License Version 1.1 (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.openoffice.org/license.html.
|
|
|
|
*
|
|
|
|
* Software provided under this License is provided on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
|
|
|
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
|
|
|
|
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
|
|
|
|
* See the License for the specific provisions governing your rights and
|
|
|
|
* obligations concerning the Software.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* Copyright: 2000 by Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): _______________________________________
|
|
|
|
*
|
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#if defined(WIN32)
|
|
|
|
#define M_PI 3.1415926536
|
|
|
|
#include <malloc.h>
|
|
|
|
#define alloca _alloca
|
2002-04-15 11:23:10 +00:00
|
|
|
#elif defined(SOLARIS)
|
|
|
|
#include <alloca.h>
|
2002-02-18 08:08:18 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
//#define _SV_OUTDEV_CXX
|
|
|
|
|
|
|
|
#ifndef REMOTE_APPSERVER
|
|
|
|
#ifndef _SV_SVSYS_HXX
|
|
|
|
#include <svsys.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef REMOTE_APPSERVER
|
|
|
|
#ifndef _SV_SALGDI_HXX
|
|
|
|
#include <salgdi.hxx>
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#ifndef _SV_RMOUTDEV_HXX
|
|
|
|
#include <rmoutdev.hxx>
|
|
|
|
#endif
|
|
|
|
#endif // REMOTE_APPSERVER
|
|
|
|
|
|
|
|
#ifndef _SV_SALLAYOUT_HXX
|
|
|
|
#include <sallayout.hxx>
|
|
|
|
#endif // _SV_SALLAYOUT_HXX
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
ImplLayoutArgs::ImplLayoutArgs( const xub_Unicode* pStr, int nLength,
|
|
|
|
int nFirstCharIndex, int nEndCharIndex )
|
|
|
|
: mpStr( pStr ),
|
|
|
|
mnLength( nLength ),
|
|
|
|
mnFirstCharIndex( nFirstCharIndex ),
|
|
|
|
mnEndCharIndex( nEndCharIndex ),
|
|
|
|
mnFlags( 0 ),
|
|
|
|
mnLayoutWidth( 0 ),
|
|
|
|
mpDXArray( NULL ),
|
|
|
|
maDrawPosition( 0, 0 ),
|
|
|
|
mnOrientation( 0 )
|
|
|
|
{}
|
|
|
|
|
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
SalLayout::SalLayout( const ImplLayoutArgs& rArgs )
|
|
|
|
: mnRefCount( 1 ),
|
|
|
|
mnFirstCharIndex( rArgs.mnFirstCharIndex ),
|
|
|
|
mnEndCharIndex( rArgs.mnEndCharIndex ),
|
|
|
|
maDrawPosition( rArgs.maDrawPosition ),
|
2002-02-26 12:18:51 +00:00
|
|
|
mnUnitsPerPixel( 1 ),
|
2002-02-18 08:08:18 +00:00
|
|
|
mnOrientation( rArgs.mnOrientation )
|
|
|
|
{}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
SalLayout::~SalLayout()
|
|
|
|
{}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void SalLayout::Reference() const
|
|
|
|
{
|
|
|
|
++mnRefCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void SalLayout::Release() const
|
|
|
|
{
|
|
|
|
if( --mnRefCount <= 0 )
|
|
|
|
{
|
|
|
|
// const_cast because some compilers violate ANSI C++ spec
|
|
|
|
delete const_cast<SalLayout*>(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
Point SalLayout::GetDrawPosition( const Point& rRelative ) const
|
|
|
|
{
|
|
|
|
Point aPos = maDrawPosition;
|
|
|
|
|
|
|
|
if( mnOrientation == 0 )
|
|
|
|
aPos += rRelative;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// cache trigonometric results
|
|
|
|
static int nOldOrientation = 0;
|
|
|
|
static double fCos = 1.0, fSin = 0.0;
|
|
|
|
if( nOldOrientation != mnOrientation )
|
|
|
|
{
|
|
|
|
nOldOrientation = mnOrientation;
|
|
|
|
double fRad = mnOrientation * (M_PI / 1800.0);
|
|
|
|
fCos = cos( fRad );
|
2002-05-08 11:30:51 +00:00
|
|
|
fSin = sin( fRad );
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
long nX0 = rRelative.X();
|
|
|
|
long nY0 = rRelative.Y();
|
2002-05-08 11:30:51 +00:00
|
|
|
long nX = static_cast<long>( +fCos * nX0 + fSin * nY0 );
|
|
|
|
long nY = static_cast<long>( +fCos * nY0 - fSin * nX0 );
|
2002-02-18 08:08:18 +00:00
|
|
|
aPos += Point( nX, nY );
|
|
|
|
}
|
|
|
|
|
|
|
|
return aPos;
|
|
|
|
}
|
|
|
|
|
2002-05-28 17:17:41 +00:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// returns asian kerning values in quarter of character width units
|
|
|
|
// to enable automatic halfwidth substitution for fullwidth punctuation
|
|
|
|
// return value is negative for l, positive for r, zero for neutral
|
|
|
|
|
|
|
|
// If the range doesn't match in 0x3000 and 0x30FB, please change
|
|
|
|
// also ImplCalcKerning.
|
|
|
|
|
|
|
|
int SalLayout::CalcAsianKerning( sal_Unicode c, bool bLeft, bool bVertical )
|
|
|
|
{
|
|
|
|
// http://www.asahi-net.or.jp/~sd5a-ucd/freetexts/jis/x4051/1995/appendix.html
|
|
|
|
static signed char nTable[0x30] =
|
|
|
|
{
|
|
|
|
0, -2, -2, 0, 0, 0, 0, 0, +2, -2, +2, -2, +2, -2, +2, -2,
|
|
|
|
+2, -2, 0, 0, +2, -2, +2, -2, 0, 0, 0, 0, 0, +2, -2, -2,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, +2, +2, -2, -2
|
|
|
|
};
|
|
|
|
|
|
|
|
int nResult = 0;
|
|
|
|
if( c>=0x3000 && c<0x3030 )
|
|
|
|
nResult = nTable[ c - 0x3000 ];
|
|
|
|
else switch( c )
|
|
|
|
{
|
|
|
|
case ':': case ';': case '!':
|
|
|
|
if( !bVertical )
|
|
|
|
nResult = bLeft ? -1 : +1; // 25% left and right
|
|
|
|
break;
|
|
|
|
case 0x30FB:
|
|
|
|
nResult = bLeft ? -1 : +1; // 25% left/right/top/bottom
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nResult;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2002-02-18 08:08:18 +00:00
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
GenericSalLayout::GenericSalLayout( const ImplLayoutArgs& rArgs )
|
|
|
|
: SalLayout( rArgs ),
|
|
|
|
mnGlyphCapacity(0), mnGlyphCount(0), mpGlyphItems( NULL )
|
|
|
|
{}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
GenericSalLayout::~GenericSalLayout()
|
|
|
|
{
|
|
|
|
delete[] mpGlyphItems ;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void GenericSalLayout::SetGlyphItems( GlyphItem* pGlyphItems, int nGlyphCount )
|
|
|
|
{
|
|
|
|
mpGlyphItems = pGlyphItems;
|
|
|
|
mnGlyphCount = nGlyphCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
2002-04-03 16:25:23 +00:00
|
|
|
Point GenericSalLayout::GetCharPosition( int nCharIndex, bool bRTL ) const
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
2002-04-03 16:25:23 +00:00
|
|
|
int nStartIndex = mnGlyphCount;
|
|
|
|
int nGlyphIndex = mnGlyphCount;
|
|
|
|
int nEndIndex = 0;
|
|
|
|
|
|
|
|
int nMaxIndex = 0;
|
|
|
|
const GlyphItem* pG = mpGlyphItems;
|
2002-04-19 10:02:06 +00:00
|
|
|
for( int i = 0; i < mnGlyphCount; ++i, ++pG )
|
2002-04-03 16:25:23 +00:00
|
|
|
{
|
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( n < mnFirstCharIndex || n >= mnEndCharIndex )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( nStartIndex > i )
|
|
|
|
nStartIndex = i;
|
|
|
|
nMaxIndex = i;
|
|
|
|
|
|
|
|
if( (n <= nCharIndex) && (nGlyphIndex > i) )
|
|
|
|
nGlyphIndex = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
long nXPos = 0;
|
|
|
|
|
|
|
|
if( !bRTL ) // relative to left edge
|
|
|
|
{
|
|
|
|
nXPos = mpGlyphItems[nGlyphIndex].maLinearPos.X();
|
2002-02-18 08:08:18 +00:00
|
|
|
|
2002-04-03 16:25:23 +00:00
|
|
|
// adjust start to cluster start
|
|
|
|
pG = mpGlyphItems + nStartIndex;
|
|
|
|
while( (pG > mpGlyphItems) && !(pG->mnFlags & GlyphItem::CLUSTER_START) )
|
|
|
|
--pG;
|
|
|
|
nXPos -= pG->maLinearPos.X();
|
|
|
|
}
|
|
|
|
else // relative to right edge
|
|
|
|
{
|
2002-04-19 10:02:06 +00:00
|
|
|
// find end of last cluster
|
2002-04-03 16:25:23 +00:00
|
|
|
pG = mpGlyphItems + nMaxIndex;
|
|
|
|
const GlyphItem* pGLimit = mpGlyphItems + mnGlyphCount;
|
2002-04-19 10:02:06 +00:00
|
|
|
while( (++pG < pGLimit) && !(pG->mnFlags & GlyphItem::CLUSTER_START) );
|
2002-04-03 16:25:23 +00:00
|
|
|
|
2002-04-19 10:02:06 +00:00
|
|
|
// adjust offset from start to last cluster
|
2002-04-03 16:25:23 +00:00
|
|
|
pGLimit = pG;
|
2002-04-19 10:02:06 +00:00
|
|
|
for( pG = mpGlyphItems + nStartIndex ; pG < pGLimit; ++pG )
|
2002-04-03 16:25:23 +00:00
|
|
|
nXPos -= pG->mnWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Point( nXPos, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
bool GenericSalLayout::GetCharWidths( long* pCharWidths ) const
|
|
|
|
{
|
2002-02-18 08:08:18 +00:00
|
|
|
// initialize character extents buffer
|
2002-04-03 16:25:23 +00:00
|
|
|
int nCharCapacity = mnEndCharIndex - mnFirstCharIndex;
|
2002-05-29 16:51:30 +00:00
|
|
|
long* pMinPos = (long*)alloca( 2*nCharCapacity * sizeof(long) );
|
|
|
|
long* pMaxPos = pMinPos + nCharCapacity;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < nCharCapacity; ++i )
|
|
|
|
{
|
|
|
|
pMinPos[i] = LONG_MAX;
|
|
|
|
pMaxPos[i] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine cluster extents
|
|
|
|
const GlyphItem* pG = mpGlyphItems;
|
|
|
|
int nClusterIndex = 0;
|
|
|
|
for( i = mnGlyphCount; --i >= 0; ++pG )
|
|
|
|
{
|
|
|
|
// use cluster start to get char index
|
2002-04-03 16:25:23 +00:00
|
|
|
if( 0 != (pG->mnFlags & GlyphItem::CLUSTER_START) )
|
2002-02-18 08:08:18 +00:00
|
|
|
nClusterIndex = pG->mnCharIndex;
|
|
|
|
|
|
|
|
int n = nClusterIndex - mnFirstCharIndex;
|
|
|
|
if( n < 0 || n >= nCharCapacity )
|
|
|
|
continue;
|
|
|
|
|
2002-06-11 15:35:49 +00:00
|
|
|
// minimum is left extent of cluster
|
2002-02-18 08:08:18 +00:00
|
|
|
long nXPos = pG->maLinearPos.X();
|
|
|
|
if( pMinPos[n] > nXPos )
|
|
|
|
pMinPos[n] = nXPos;
|
|
|
|
|
2002-06-11 15:35:49 +00:00
|
|
|
// maximum is right extent of cluster
|
|
|
|
if( i > 0 )
|
|
|
|
nXPos = pG[1].maLinearPos.X(); // left edge of next glyph
|
|
|
|
else if( pG->mnWidth > 0 )
|
|
|
|
nXPos += pG->mnWidth; // right edge of last glyph
|
2002-02-18 08:08:18 +00:00
|
|
|
if( pMaxPos[n] < nXPos )
|
|
|
|
pMaxPos[n] = nXPos;
|
|
|
|
|
|
|
|
// special case for zero width glyphs in cluster, e.g. in Thai
|
2002-05-29 16:51:30 +00:00
|
|
|
// => they are aligned to cluster start
|
2002-06-11 15:35:49 +00:00
|
|
|
if( pG->mnWidth <= 0 )
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
|
|
|
int m = nClusterIndex - mnFirstCharIndex;
|
|
|
|
if( n != m )
|
|
|
|
pMinPos[m] = pMaxPos[m] = nXPos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set char width array
|
2002-06-11 15:35:49 +00:00
|
|
|
long nCharWidth = 0;
|
|
|
|
for( i = 0; i < nCharCapacity; ++i )
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
2002-06-11 15:35:49 +00:00
|
|
|
if( pMaxPos[i] < 0 )
|
|
|
|
{
|
|
|
|
// untouched chars of cluster get their share
|
|
|
|
pCharWidths[i] = nCharWidth;
|
|
|
|
}
|
|
|
|
else
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
2002-06-11 15:35:49 +00:00
|
|
|
long nClusterWidth = pMaxPos[i] - pMinPos[i];
|
|
|
|
|
|
|
|
// ligature glyphs correspond to more than one sal_Unicode, so
|
|
|
|
// some character widths are still uninitialized. This is solved
|
|
|
|
// by distributing the cluster width to the involved characters
|
|
|
|
int j = i;
|
|
|
|
while( ++j<nCharCapacity && pMaxPos[j]<0 );
|
|
|
|
int nClusterSize = j - i;
|
|
|
|
if( nClusterSize > 1 )
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
2002-06-11 15:35:49 +00:00
|
|
|
nCharWidth = (nClusterWidth + (nClusterSize/2)) / nClusterSize;
|
|
|
|
nClusterWidth -= (nClusterSize - 1) * nCharWidth;
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
2002-06-11 15:35:49 +00:00
|
|
|
pCharWidths[i] = nClusterWidth;
|
|
|
|
}
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
2002-04-03 16:25:23 +00:00
|
|
|
return true;
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
long GenericSalLayout::FillDXArray( long* pDXArray ) const
|
|
|
|
{
|
2002-04-03 16:25:23 +00:00
|
|
|
int nCharCapacity = mnEndCharIndex - mnFirstCharIndex;
|
|
|
|
long* pCharWidths = (long*)alloca( nCharCapacity * sizeof(long) );
|
|
|
|
if( !GetCharWidths( pCharWidths ) )
|
|
|
|
return 0;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
long nWidth = 0;
|
|
|
|
for( int i = mnFirstCharIndex; i < mnEndCharIndex; ++i )
|
|
|
|
{
|
|
|
|
nWidth += pCharWidths[ i - mnFirstCharIndex ];
|
|
|
|
if( pDXArray )
|
|
|
|
pDXArray[ i - mnFirstCharIndex ] = nWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void GenericSalLayout::ApplyDXArray( const long* pDXArray )
|
|
|
|
{
|
|
|
|
// get reference positions
|
|
|
|
int nChars = mnEndCharIndex - mnFirstCharIndex;
|
2002-04-03 16:25:23 +00:00
|
|
|
long* pOldDX = (long*)alloca( nChars * sizeof(long) );
|
|
|
|
FillDXArray( pOldDX );
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
// initialize flags for touched character
|
|
|
|
int i;
|
|
|
|
char* pTouched = (char*)alloca( nChars );
|
|
|
|
for( i = 0; i < nChars; ++i )
|
|
|
|
pTouched[ i ] = 0;
|
|
|
|
|
|
|
|
// get x base offset
|
|
|
|
GlyphItem* pG = mpGlyphItems;
|
|
|
|
long nBasePointX = -1;
|
|
|
|
for( i = 0; i < mnGlyphCount; ++i, ++pG )
|
|
|
|
{
|
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( n < mnFirstCharIndex || n >= mnEndCharIndex )
|
|
|
|
continue;
|
2002-04-22 16:21:54 +00:00
|
|
|
// initialize x base offset with first matching glyph position
|
2002-02-18 08:08:18 +00:00
|
|
|
nBasePointX = pG->maLinearPos.X();
|
2002-04-22 16:21:54 +00:00
|
|
|
pTouched[ n - mnFirstCharIndex ] = 1;
|
|
|
|
break;
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// adjust to requested positions
|
|
|
|
long nDelta = 0;
|
|
|
|
for(; i < mnGlyphCount; ++i, ++pG )
|
|
|
|
{
|
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( n < mnEndCharIndex )
|
|
|
|
{
|
2002-06-06 13:46:43 +00:00
|
|
|
// move with cluster granularity only and inside substring
|
2002-02-18 08:08:18 +00:00
|
|
|
n -= mnFirstCharIndex;
|
2002-06-06 13:46:43 +00:00
|
|
|
if( (n > 0) && !pTouched[n] )
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
2002-04-22 16:21:54 +00:00
|
|
|
pTouched[n] = 1;
|
2002-06-06 13:46:43 +00:00
|
|
|
long nNewDelta = pDXArray[n-1];
|
2002-02-18 08:08:18 +00:00
|
|
|
nNewDelta += nBasePointX - pG->maLinearPos.X();
|
|
|
|
nDelta = nNewDelta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pG->maLinearPos += Point( nDelta, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust remaining glyphs
|
|
|
|
if( nDelta )
|
|
|
|
for(; i < mnGlyphCount; ++i, ++pG )
|
|
|
|
pG->maLinearPos += Point( nDelta, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void GenericSalLayout::Justify( long nNewWidth )
|
|
|
|
{
|
2002-04-03 16:25:23 +00:00
|
|
|
int nCharCapacity = mnEndCharIndex - mnFirstCharIndex;
|
|
|
|
long* pCharWidths = (long*)alloca( nCharCapacity * sizeof(long) );
|
|
|
|
if( !GetCharWidths( pCharWidths ) )
|
|
|
|
return;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
int nOldWidth = FillDXArray( NULL );
|
|
|
|
if( !nOldWidth || nNewWidth==nOldWidth )
|
|
|
|
return;
|
|
|
|
|
|
|
|
double fFactor = (double)nNewWidth / nOldWidth;
|
|
|
|
|
|
|
|
GlyphItem* pG = mpGlyphItems;
|
|
|
|
const long nBasePos = maBasePoint.X();
|
|
|
|
for( int i = mnGlyphCount; --i >= 0; ++pG )
|
|
|
|
{
|
2002-06-11 15:35:49 +00:00
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( n < mnFirstCharIndex || n >= mnEndCharIndex )
|
|
|
|
continue;
|
|
|
|
long nOldPos = pG->maLinearPos.X();
|
|
|
|
long nNewPos = nBasePos + (long)(fFactor * (nOldPos - nBasePos) + 0.5);
|
|
|
|
if( nNewPos != nOldPos )
|
|
|
|
pG->maLinearPos.X() += nNewPos - nOldPos;
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
int GenericSalLayout::GetTextBreak( long nMaxWidth ) const
|
|
|
|
{
|
2002-04-03 16:25:23 +00:00
|
|
|
int nCharCapacity = mnEndCharIndex - mnFirstCharIndex;
|
|
|
|
long* pCharWidths = (long*)alloca( nCharCapacity * sizeof(long) );
|
|
|
|
if( !GetCharWidths( pCharWidths ) )
|
|
|
|
return STRING_LEN;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
long nWidth = 0;
|
|
|
|
for( int i = mnFirstCharIndex; i < mnEndCharIndex; ++i )
|
|
|
|
{
|
|
|
|
nWidth += pCharWidths[ i - mnFirstCharIndex ];
|
|
|
|
if( nWidth >= nMaxWidth )
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STRING_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
2002-02-26 12:18:51 +00:00
|
|
|
int GenericSalLayout::GetNextGlyphs( int nLen, long* pGlyphs, Point& rPos,
|
|
|
|
int& nStart, sal_Int32* pXOffset ) const
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
|
|
|
const GlyphItem* pG = mpGlyphItems + nStart;
|
|
|
|
|
|
|
|
// find next glyph in substring
|
|
|
|
bool bFirst = (nStart == 0);
|
|
|
|
for(; nStart < mnGlyphCount; ++nStart, ++pG )
|
|
|
|
{
|
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( n < mnFirstCharIndex || n >= mnEndCharIndex )
|
|
|
|
continue;
|
|
|
|
if( bFirst ) // set base point if not yet initialized
|
|
|
|
maBasePoint = Point( pG->maLinearPos.X(), 0 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return zero if no more glyph found
|
|
|
|
if( nStart >= mnGlyphCount )
|
|
|
|
return 0;
|
|
|
|
|
2002-02-26 12:18:51 +00:00
|
|
|
// calculate absolute position in pixel units
|
|
|
|
Point aRelativePos = pG->maLinearPos - maBasePoint;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
// find more glyphs which can be merged into one drawing instruction
|
|
|
|
int nCount = 0;
|
|
|
|
while( nCount < nLen )
|
|
|
|
{
|
|
|
|
*(pGlyphs++) = pG->mnGlyphIndex;
|
2002-02-26 12:18:51 +00:00
|
|
|
if( pXOffset )
|
2002-06-11 15:35:49 +00:00
|
|
|
*(pXOffset++) = pG->maLinearPos.X() - aRelativePos.X();
|
2002-02-18 08:08:18 +00:00
|
|
|
++nCount;
|
|
|
|
|
|
|
|
if( ++nStart >= mnGlyphCount )
|
|
|
|
break;
|
|
|
|
|
2002-02-26 12:18:51 +00:00
|
|
|
Point aOldPos = pG->maLinearPos;
|
2002-05-17 11:17:45 +00:00
|
|
|
int nOldWidth = pG->mnWidth;
|
2002-02-18 08:08:18 +00:00
|
|
|
++pG;
|
2002-02-26 12:18:51 +00:00
|
|
|
|
2002-05-17 11:17:45 +00:00
|
|
|
// stop when no longer in string
|
|
|
|
int n = pG->mnCharIndex;
|
|
|
|
if( (n < mnFirstCharIndex) || (n >= mnEndCharIndex) )
|
|
|
|
break;
|
|
|
|
|
2002-02-26 12:18:51 +00:00
|
|
|
// stop when baseline changes
|
|
|
|
if( aOldPos.Y() != pG->maLinearPos.Y() )
|
2002-02-18 08:08:18 +00:00
|
|
|
break;
|
|
|
|
|
2002-02-26 12:18:51 +00:00
|
|
|
// stop when x-position is unexpected
|
|
|
|
if( !pXOffset )
|
2002-05-17 11:17:45 +00:00
|
|
|
if( aOldPos.X() + nOldWidth != pG->maLinearPos.X() )
|
2002-02-26 12:18:51 +00:00
|
|
|
break;
|
2002-02-18 08:08:18 +00:00
|
|
|
}
|
|
|
|
|
2002-06-11 15:35:49 +00:00
|
|
|
aRelativePos.X() /= mnUnitsPerPixel;
|
|
|
|
aRelativePos.Y() /= mnUnitsPerPixel;
|
|
|
|
rPos = GetDrawPosition( aRelativePos );
|
|
|
|
|
2002-02-18 08:08:18 +00:00
|
|
|
return nCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
2002-05-08 11:30:51 +00:00
|
|
|
GenericSalLayout* GenericSalLayout::ExtractLayout( int nXorFlags, int nAndFlags )
|
2002-02-18 08:08:18 +00:00
|
|
|
{
|
|
|
|
int nNewSize = 0;
|
|
|
|
int nUsableSize = 0;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
const GlyphItem* pSrc = mpGlyphItems;
|
|
|
|
for( i = mnGlyphCount; --i >= 0; ++pSrc )
|
|
|
|
{
|
|
|
|
if( ((pSrc->mnFlags ^ nXorFlags) & nAndFlags) != 0 )
|
|
|
|
continue;
|
|
|
|
++nUsableSize;
|
|
|
|
if( (pSrc->mnCharIndex >= mnFirstCharIndex)
|
|
|
|
&& (pSrc->mnCharIndex < mnEndCharIndex) )
|
|
|
|
++nNewSize;
|
|
|
|
}
|
|
|
|
|
2002-05-08 11:30:51 +00:00
|
|
|
GenericSalLayout* pDstLayout = NULL;
|
2002-02-18 08:08:18 +00:00
|
|
|
|
|
|
|
if( !nNewSize )
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
//### if( nUsableSize == mnGlyphCount )
|
|
|
|
{
|
|
|
|
pDstLayout = this;
|
|
|
|
Reference();
|
|
|
|
}
|
|
|
|
/*###
|
|
|
|
else
|
|
|
|
{
|
2002-05-08 11:30:51 +00:00
|
|
|
pDstLayout = new GenericSalLayout( nNewSize );
|
2002-02-18 08:08:18 +00:00
|
|
|
bool bWantFallback = false;
|
|
|
|
if( nNewSize > 0 )
|
|
|
|
{
|
|
|
|
GlyphItem* pDst = pDstLayout->mpGlyphItems;
|
|
|
|
pSrc = mpGlyphItems;
|
|
|
|
bool bFirst = true;
|
|
|
|
for( i = mnSize; --i >= 0; ++pSrc )
|
|
|
|
{
|
|
|
|
if( (pSrc->mnCharIndex >= mnFirstCharIndex)
|
|
|
|
&& (pSrc->mnCharIndex < mnEndCharIndex)
|
|
|
|
&& !((pSrc->mnFlags ^ nXorFlags) & nAndFlags) )
|
|
|
|
{
|
|
|
|
*(pDst++) = *pSrc;
|
|
|
|
if( !pSrc->mnGlyphIndex )
|
|
|
|
bWantFallback = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pDstLayout->maAdvance = maAdvance;
|
|
|
|
pDstLayout->maBasePoint = maBasePoint;
|
|
|
|
pDstLayout->mnFirstCharIndex= mnFirstCharIndex;
|
|
|
|
pDstLayout->mnEndCharIndex = mnEndCharIndex;
|
|
|
|
pDstLayout->mnOrientation = mnOrientation;
|
|
|
|
pDstLayout->mbWantFallback = bWantFallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
pDstLayout->SetDrawPosition( maDrawPosition );
|
|
|
|
###*/
|
|
|
|
|
|
|
|
return pDstLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void GenericSalLayout::MergeLayout( int nFlags, const GenericSalLayout& rSalLayout )
|
|
|
|
{
|
|
|
|
GlyphItem* pG = mpGlyphItems;
|
|
|
|
for( int i = mnGlyphCount; --i >= 0; ++pG )
|
|
|
|
{
|
|
|
|
// use only when we need glyph fallback
|
|
|
|
if( pG->mnGlyphIndex != 0 )
|
|
|
|
continue;
|
|
|
|
int nCharIndex = pG->mnCharIndex;
|
|
|
|
const GlyphItem* pSrc = rSalLayout.mpGlyphItems;
|
|
|
|
for( int j = rSalLayout.mnGlyphCount; --j >= 0; ++pSrc )
|
|
|
|
{
|
|
|
|
if( !pSrc->mnGlyphIndex )
|
|
|
|
continue;
|
|
|
|
if( nCharIndex != pSrc->mnCharIndex )
|
|
|
|
continue;
|
|
|
|
pG->mnGlyphIndex = pSrc->mnGlyphIndex;
|
|
|
|
pG->mnFlags = nFlags;
|
|
|
|
//### TODO: adjust position of following glyphs
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// =======================================================================
|