Files
libreoffice/vcl/source/gdi/sallayout.cxx

799 lines
23 KiB
C++
Raw Normal View History

2002-02-18 08:08:18 +00:00
/*************************************************************************
*
* $RCSfile: sallayout.cxx,v $
*
* $Revision: 1.20 $
2002-02-18 08:08:18 +00:00
*
* last change: $Author: hdu $ $Date: 2002-08-16 07:14:56 $
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
#ifndef _SV_POLY_HXX
#include <poly.hxx>
#endif // _SV_POLY_HXX
2002-02-18 08:08:18 +00:00
#include <limits.h>
#ifdef REMOTE_APPSERVER
// TODO: cleanup
#define SalGraphics ImplServerGraphics
#endif
2002-02-18 08:08:18 +00:00
// =======================================================================
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 )
2002-02-18 08:08:18 +00:00
{}
// =======================================================================
SalLayout::SalLayout( const ImplLayoutArgs& rArgs )
: mnRefCount( 1 ),
mnFirstCharIndex( rArgs.mnFirstCharIndex ),
mnEndCharIndex( rArgs.mnEndCharIndex ),
maDrawPosition( rArgs.maDrawPosition ),
mnUnitsPerPixel( 1 ),
mnOrientation( rArgs.mnOrientation )
2002-02-18 08:08:18 +00:00
{}
// -----------------------------------------------------------------------
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;
}
// -----------------------------------------------------------------------
// 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;
}
// -----------------------------------------------------------------------
bool SalLayout::GetOutline( SalGraphics& rSalGraphics, PolyPolyVector& rVector ) const
{
bool bHasGlyphs = HasGlyphs();
for( int nStart = 0;;)
{
Point aPos;
long nLGlyph;
if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart, NULL, NULL ) )
break;
// get outline of individual glyph
PolyPolygon aGlyphOutline;
if( rSalGraphics.GetGlyphOutline( nLGlyph, bHasGlyphs, aGlyphOutline ) )
{
// insert outline at correct position
aGlyphOutline.Move( aPos.X(), aPos.Y() );
rVector.push_back( aGlyphOutline );
}
}
return (rVector.size() > 0);
}
// -----------------------------------------------------------------------
bool SalLayout::GetBoundRect( SalGraphics& rSalGraphics, Rectangle& rRectangle ) const
{
bool bRet = false;
rRectangle.SetEmpty();
bool bHasGlyphs = HasGlyphs();
for( int nStart = 0;;)
{
Point aPos;
long nLGlyph;
if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart, NULL, NULL ) )
break;
// get bounding rectangle of individual glyph
Rectangle aRectangle;
if( rSalGraphics.GetGlyphBoundRect( nLGlyph, bHasGlyphs, aRectangle ) )
bRet = true;
// merge rectangle
aRectangle += aPos;
rRectangle.Union( aRectangle );
}
return bRet;
}
2002-08-02 16:44:48 +00:00
// -----------------------------------------------------------------------
bool SalLayout::IsNotdefGlyph( long nGlyph ) const
{
bool bRet = false;
if( HasGlyphs() && nGlyph )
bRet = true;
return bRet;
}
// -----------------------------------------------------------------------
bool SalLayout::IsSpacingGlyph( long nGlyph ) const
{
bool bRet = false;
if( HasGlyphs() )
bRet = (nGlyph==3);
else
{
bRet = (nGlyph <= 0x0020)
//|| (nGlyph == 0x00A0) // non breaking space
|| (nGlyph >= 0x2000 && nGlyph <= 0x200F)
|| (nGlyph == 0x3000);
}
return bRet;
}
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;
}
// -----------------------------------------------------------------------
Point GenericSalLayout::GetCharPosition( int nCharIndex, bool bRTL ) const
2002-02-18 08:08:18 +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 )
{
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
// adjust start to cluster start
pG = mpGlyphItems + nStartIndex;
while( (pG > mpGlyphItems) && !pG->IsClusterStart() )
--pG;
nXPos -= pG->maLinearPos.X();
}
else // relative to right edge
{
2002-04-19 10:02:06 +00:00
// find end of last cluster
pG = mpGlyphItems + nMaxIndex;
const GlyphItem* pGLimit = mpGlyphItems + mnGlyphCount;
while( (++pG < pGLimit) && !pG->IsClusterStart() );
2002-04-19 10:02:06 +00:00
// adjust offset from start to last cluster
pGLimit = pG;
2002-04-19 10:02:06 +00:00
for( pG = mpGlyphItems + nStartIndex ; pG < pGLimit; ++pG )
nXPos -= pG->mnNewWidth;
}
return Point( nXPos, 0 );
}
// -----------------------------------------------------------------------
bool GenericSalLayout::GetCharWidths( long* pCharWidths ) const
{
2002-02-18 08:08:18 +00:00
// initialize character extents buffer
int nCharCapacity = mnEndCharIndex - mnFirstCharIndex;
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
if( !pG->IsClusterStart() )
continue;
2002-02-18 08:08:18 +00:00
int n = pG->mnCharIndex;
if( n >= mnEndCharIndex )
continue;
n -= mnFirstCharIndex;
if( n < 0 )
2002-02-18 08:08:18 +00:00
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
int j = i;
while( (--j >= 0) && !pG[i-j].IsClusterStart() ); // advance to next cluster
if( j >= 0 )
nXPos = pG[i-j].maLinearPos.X(); // left edge of next cluster
else if( pG->mnNewWidth > 0 )
nXPos += pG->mnNewWidth; // right edge of this glyph
2002-02-18 08:08:18 +00:00
if( pMaxPos[n] < nXPos )
pMaxPos[n] = nXPos;
}
// set char width array
// clusters (e.g. ligatures) correspond to more than one char index,
// so some character widths are still uninitialized. This is solved
// by setting the first charwidth of the cluster to the cluster width
// TODO: distribute the cluster width proportionally to the characters
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 )
{
// TODO: untouched chars of cluster get their share
2002-06-11 15:35:49 +00:00
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];
pCharWidths[i] = nClusterWidth;
}
2002-02-18 08:08:18 +00:00
}
return true;
2002-02-18 08:08:18 +00:00
}
// -----------------------------------------------------------------------
long GenericSalLayout::FillDXArray( long* pDXArray ) const
{
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;
}
// -----------------------------------------------------------------------
long GenericSalLayout::GetTextWidth() const
{
if( mnGlyphCount <= 0 )
return 0;
const GlyphItem* pG = mpGlyphItems;
long nMinPos = pG->maLinearPos.X();
long nMaxPos = nMinPos + pG->mnNewWidth;
for( int i = 1; i < mnGlyphCount; ++i )
{
++pG;
int n = pG->mnCharIndex;
if( (n<mnFirstCharIndex) || (n>=mnEndCharIndex) )
continue;
long nXPos = pG->maLinearPos.X();
if( nMinPos > nXPos )
nMinPos = nXPos;
nXPos += pG->mnNewWidth;
if( nMaxPos < nXPos )
nMaxPos = nXPos;
}
long nWidth = nMaxPos - nMinPos;
return nWidth;
}
// -----------------------------------------------------------------------
2002-02-18 08:08:18 +00:00
void GenericSalLayout::ApplyDXArray( const long* pDXArray )
{
// determine cluster boundaries and x base offset
2002-02-18 08:08:18 +00:00
int nChars = mnEndCharIndex - mnFirstCharIndex;
int* pLogCluster = (int*)alloca( nChars * sizeof(int) );
int i, n;
2002-02-18 08:08:18 +00:00
for( i = 0; i < nChars; ++i )
pLogCluster[ i ] = -1;
2002-02-18 08:08:18 +00:00
long nBasePointX = -1;
GlyphItem* pG = mpGlyphItems;
2002-02-18 08:08:18 +00:00
for( i = 0; i < mnGlyphCount; ++i, ++pG )
{
int n = pG->mnCharIndex;
if( n < mnEndCharIndex )
{
if( (n -= mnFirstCharIndex) >= 0 )
2002-02-18 08:08:18 +00:00
{
pLogCluster[ n ] = i;
if( nBasePointX < 0 )
nBasePointX = pG->maLinearPos.X();
2002-02-18 08:08:18 +00:00
}
}
}
// calculate adjusted cluster widths
long* pNewClusterWidths = (long*)alloca( mnGlyphCount * sizeof(long) );
for( i = 0; i < mnGlyphCount; ++i )
pNewClusterWidths[ i ] = 0;
2002-02-18 08:08:18 +00:00
for( i = 0; i < nChars; ++i )
if( (n = pLogCluster[i]) >= 0 )
break;
pNewClusterWidths[ n ] = pDXArray[i];
long nCurrPos = pDXArray[i];
while( ++i < nChars )
{
if( pLogCluster[i] >= 0 )
n = pLogCluster[ i ];
pNewClusterWidths[ n ] += pDXArray[i] - nCurrPos;
nCurrPos = pDXArray[i];
2002-02-18 08:08:18 +00:00
}
// move cluster positions using the adjusted widths
long nDelta = 0;
nCurrPos = 0;
pG = mpGlyphItems;
for( i = 0; i < mnGlyphCount; ++i, ++pG )
{
if( pG->IsClusterStart() )
{
long nNewDelta = nCurrPos;
nNewDelta += nBasePointX - pG->maLinearPos.X();
nDelta = nNewDelta;
}
nCurrPos += pNewClusterWidths[ i ];
pG->maLinearPos.X() += nDelta;
}
2002-08-15 15:33:15 +00:00
// adjust new glyph widths to results calculated above
pG = mpGlyphItems;
for( i = 1; i < mnGlyphCount; ++i, ++pG )
pG[0].mnNewWidth = pG[1].maLinearPos.X() - pG[0].maLinearPos.X();
2002-02-18 08:08:18 +00:00
}
// -----------------------------------------------------------------------
void GenericSalLayout::Justify( long nNewWidth )
{
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;
// find rightmost glyph, it won't get stretched
2002-02-18 08:08:18 +00:00
GlyphItem* pG = mpGlyphItems;
for( pG += mnGlyphCount; --pG > mpGlyphItems; )
{
int n = pG->mnCharIndex;
if( (n >= mnFirstCharIndex) || (n < mnEndCharIndex) )
break;
}
GlyphItem* pGRight = pG;
// move rightmost glyph to requested position, correct adjustment widths
nOldWidth -= pGRight->mnOrigWidth;
nNewWidth -= pGRight->mnOrigWidth;
if( (nOldWidth < 0) || (nNewWidth < 0) )
return;
2002-02-18 08:08:18 +00:00
const long nBasePos = maBasePoint.X();
pGRight->maLinearPos.X() = nBasePos + nNewWidth;
// interpolate inbetween glyph positions
double fFactor = (double)nNewWidth / nOldWidth;
for( pG = mpGlyphItems; pG < pGRight; ++pG )
2002-02-18 08:08:18 +00:00
{
2002-06-11 15:35:49 +00:00
int n = pG->mnCharIndex;
if( (n >= mnFirstCharIndex) || (n < mnEndCharIndex) )
{
long nOldPos = pG->maLinearPos.X();
long nNewPos = nBasePos + (long)(fFactor * (nOldPos - nBasePos) + 0.5);
2002-06-11 15:35:49 +00:00
pG->maLinearPos.X() += nNewPos - nOldPos;
}
2002-02-18 08:08:18 +00:00
}
// adjust new glyph advance widths to glyph movements above,
// the rightmost glyph keeps it's original advance width
for( pG = mpGlyphItems; pG < pGRight; ++pG )
pG[0].mnNewWidth = pG[1].maLinearPos.X() - pG[0].maLinearPos.X();
2002-02-18 08:08:18 +00:00
}
// -----------------------------------------------------------------------
int GenericSalLayout::GetTextBreak( long nMaxWidth, long nCharExtra ) const
2002-02-18 08:08:18 +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;
nWidth += nCharExtra;
2002-02-18 08:08:18 +00:00
}
return STRING_LEN;
}
// -----------------------------------------------------------------------
int GenericSalLayout::GetNextGlyphs( int nLen, long* pGlyphs, Point& rPos,
int& nStart, long* pGlyphAdvances, int* pCharIndexes ) 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;
// 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;
long nYPos = pG->maLinearPos.Y();
long nOldFlags = pG->mnGlyphIndex;
2002-02-18 08:08:18 +00:00
while( nCount < nLen )
{
*(pGlyphs++) = pG->mnGlyphIndex;
if( pGlyphAdvances )
*(pGlyphAdvances++) = pG->mnNewWidth;
if( pCharIndexes )
*(pCharIndexes++) = pG->mnCharIndex;
2002-02-18 08:08:18 +00:00
++nCount;
if( ++nStart >= mnGlyphCount )
break;
// stop when x-position is unexpected
if( !pGlyphAdvances && (pG->mnOrigWidth != pG->mnNewWidth) )
break;
2002-02-18 08:08:18 +00:00
++pG;
// stop when y-position is unexpected
if( nYPos != pG->maLinearPos.Y() )
break;
2002-05-17 11:17:45 +00:00
// stop when no longer in string
int n = pG->mnCharIndex;
if( (n < mnFirstCharIndex) || (n >= mnEndCharIndex) )
break;
// stop when glyph flags change
if( GetGlyphFlags( nOldFlags ^ pG->mnGlyphIndex ) )
break;
nOldFlags = pG->mnGlyphIndex;
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;
}
}
}
// =======================================================================