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

6744 lines
219 KiB
C++
Raw Normal View History

2000-09-18 16:07:07 +00:00
/*************************************************************************
*
* $RCSfile: outdev3.cxx,v $
*
2001-02-23 15:13:58 +00:00
* $Revision: 1.18 $
2000-09-18 16:07:07 +00:00
*
2001-02-23 15:13:58 +00:00
* last change: $Author: th $ $Date: 2001-02-23 16:13:58 $
2000-09-18 16:07:07 +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 <math.h>
#include <string.h>
#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
#ifndef _RTL_TENCINFO_H
#include <rtl/tencinfo.h>
#endif
#ifndef _DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _SV_SVDATA_HXX
#include <svdata.hxx>
#endif
#ifndef _SV_METRIC_HXX
#include <metric.hxx>
#endif
#ifndef _SV_METAACT_HXX
#include <metaact.hxx>
#endif
#ifndef _SV_GDIMTF_HXX
#include <gdimtf.hxx>
#endif
#ifndef _SV_OUTDATA_HXX
#include <outdata.hxx>
#endif
#ifndef _SV_OUTFONT_HXX
#include <outfont.hxx>
#endif
#ifndef _SV_POLY_HXX
#include <poly.hxx>
#endif
#ifndef _SV_OUTDEV_H
#include <outdev.h>
#endif
#ifndef _SV_VIRDEV_HXX
#include <virdev.hxx>
#endif
#ifndef _SV_PRINT_HXX
#include <print.hxx>
#endif
#ifndef _SV_WINDOW_H
#include <window.h>
#endif
#ifndef _SV_WINDOW_HXX
#include <window.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <svapp.hxx>
#endif
#ifndef _SV_BMPACC_HXX
#include <bmpacc.hxx>
#endif
#ifndef _SV_OUTDEV_HXX
#include <outdev.hxx>
#endif
#ifndef _SV_EDIT_HXX
#include <edit.hxx>
#endif
#include <unohelp.hxx>
2000-11-20 16:45:23 +00:00
#ifndef _COM_SUN_STAR_I18N_XBREAKITERATOR_HPP_
#include <com/sun/star/i18n/XBreakIterator.hpp>
2000-09-18 16:07:07 +00:00
#endif
2000-11-20 16:45:23 +00:00
#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HPP_
#include <com/sun/star/i18n/WordType.hpp>
2000-09-18 16:07:07 +00:00
#endif
#if defined UNX
#define GLYPH_FONT_HEIGHT 128
#elif defined OS2
#define GLYPH_FONT_HEIGHT 176
#else
#define GLYPH_FONT_HEIGHT 256
#endif
#define WSstrcmp strcmp
// =======================================================================
DBG_NAMEEX( OutputDevice );
DBG_NAMEEX( Font );
// =======================================================================
#define OUTDEV_CHARCONVERT_REPLACE FALSE
using namespace ::com::sun::star;
using namespace ::rtl;
// =======================================================================
#define MAX_DX_WORDS 120
#define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
// =======================================================================
#define UNDERLINE_LAST UNDERLINE_BOLDWAVE
#define STRIKEOUT_LAST STRIKEOUT_X
// -----------------------------------------------------------------------
static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
short nOrientation )
{
double nRealOrientation = nOrientation*F_PI1800;
double nCos = cos( nRealOrientation );
double nSin = sin( nRealOrientation );
// Translation...
long nX = rX-nOriginX;
long nY = rY-nOriginY;
// Rotation...
rX = ((long) ( nCos*nX + nSin*nY )) + nOriginX;
rY = ((long) - ( nSin*nX - nCos*nY )) + nOriginY;
}
2000-09-18 16:07:07 +00:00
// =======================================================================
void OutputDevice::ImplUpdateFontData( BOOL bNewFontLists )
{
if ( mpFontEntry )
{
mpFontCache->Release( mpFontEntry );
mpFontEntry = NULL;
}
if ( bNewFontLists )
{
if ( mpGetDevFontList )
{
delete mpGetDevFontList;
mpGetDevFontList = NULL;
}
if ( mpGetDevSizeList )
{
delete mpGetDevSizeList;
mpGetDevSizeList = NULL;
}
}
if ( GetOutDevType() == OUTDEV_PRINTER )
{
mpFontCache->Clear();
if ( bNewFontLists )
{
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( ImplGetGraphics() )
#endif
{
mpFontList->Clear();
mpGraphics->GetDevFontList( mpFontList );
mpFontList->InitStdFonts();
}
}
}
mbInitFont = TRUE;
mbNewFont = TRUE;
// Bei Fenstern auch alle Child-Fenster mit updaten
if ( GetOutDevType() == OUTDEV_WINDOW )
{
Window* pChild = ((Window*)this)->mpFirstChild;
while ( pChild )
{
pChild->ImplUpdateFontData( TRUE );
pChild = pChild->mpNext;
}
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplUpdateAllFontData( BOOL bNewFontLists )
{
ImplSVData* pSVData = ImplGetSVData();
// Alle Fenster updaten
Window* pFrame = pSVData->maWinData.mpFirstFrame;
while ( pFrame )
{
pFrame->ImplUpdateFontData( bNewFontLists );
Window* pSysWin = pFrame->mpFrameData->mpFirstOverlap;
while ( pSysWin )
{
pSysWin->ImplUpdateFontData( bNewFontLists );
pSysWin = pSysWin->mpNextOverlap;
}
pFrame = pFrame->mpFrameData->mpNextFrame;
}
// Alle VirDev's updaten
VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
while ( pVirDev )
{
pVirDev->ImplUpdateFontData( bNewFontLists );
pVirDev = pVirDev->mpNext;
}
// Alle Printer updaten
Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
while ( pPrinter )
{
pPrinter->ImplUpdateFontData( bNewFontLists );
pPrinter = pPrinter->mpNext;
}
// Globale Fontlisten leeren, damit diese geupdatet werden
pSVData->maGDIData.mpScreenFontCache->Clear();
if ( bNewFontLists )
{
pSVData->maGDIData.mpScreenFontList->Clear();
pFrame = pSVData->maWinData.mpFirstFrame;
if ( pFrame )
{
#ifndef REMOTE_APPSERVER
if ( pFrame->ImplGetGraphics() )
#endif
{
pFrame->mpGraphics->GetDevFontList( pFrame->mpFrameData->mpFontList );
pFrame->mpFrameData->mpFontList->InitStdFonts();
}
}
}
}
// =======================================================================
struct ImplFontSubstEntry
{
XubString maName;
XubString maReplaceName;
XubString maMatchName;
XubString maMatchReplaceName;
USHORT mnFlags;
ImplFontSubstEntry* mpNext;
};
// =======================================================================
static void ImplStrEraseAllSymbols( XubString& rStr )
{
xub_StrLen i = 0;
xub_Unicode c = rStr.GetChar( i );
while ( c )
{
// Alle Zeichen kleiner 0 zwischen 9-A, Z-a und z-127 loeschen
if ( (c < 48) || ((c > 57) && (c < 65)) || ((c > 90) && (c < 97)) ||
((c > 122) && (c <= 127)) )
rStr.Erase( i, 1 );
else
i++;
c = rStr.GetChar( i );
}
}
// -----------------------------------------------------------------------
static xub_StrLen ImplStrMatch( const XubString& rStr1, const XubString& rStr2 )
{
xub_StrLen nMatch = 0;
const xub_Unicode* pStr1 = rStr1.GetBuffer();
const xub_Unicode* pStr2 = rStr2.GetBuffer();
while ( (*pStr1 == *pStr2) && *pStr1 )
{
pStr1++;
pStr2++;
nMatch++;
}
return nMatch;
}
// -----------------------------------------------------------------------
static int ImplStrFullMatch( const XubString& rStr1, const char* pStr2 )
{
const xub_Unicode* pStr1 = rStr1.GetBuffer();
while ( (*pStr1 == (xub_Unicode)(unsigned char)*pStr2) && *pStr1 )
{
pStr1++;
pStr2++;
}
return !(*pStr2);
2000-09-18 16:07:07 +00:00
}
// =======================================================================
#if 0
#define FONT_ATTR_SYMBOL ((ULONG)0x00000001)
#define FONT_ATTR_FIXED ((ULONG)0x00000002)
#define FONT_ATTR_ITALIC ((ULONG)0x00000004)
#define FONT_ATTR_NORMAL ((ULONG)0x00000008)
#define FONT_ATTR_STANDARD ((ULONG)0x00000010)
#define FONT_ATTR_SPECIAL ((ULONG)0x00000020)
#define FONT_ATTR_TITLING ((ULONG)0x00000040)
#define FONT_ATTR_SERIF ((ULONG)0x00000080)
#define FONT_ATTR_NONSERIF ((ULONG)0x00000100)
#define FONT_ATTR_ROUNDED ((ULONG)0x00000200)
#define FONT_ATTR_OUTLINE ((ULONG)0x00000400)
#define FONT_ATTR_SHADOW ((ULONG)0x00000800)
#define FONT_ATTR_SCRIPT ((ULONG)0x00001000)
#define FONT_ATTR_HANDWRITING ((ULONG)0x00002000)
#define FONT_ATTR_DECORATION ((ULONG)0x00004000)
#define FONT_ATTR_CHARSCRIPT ((ULONG)0x00008000)
#define FONT_ATTR_CHANCERY ((ULONG)0x00010000)
#define FONT_ATTR_OLDSTYLE ((ULONG)0x00020000)
#define FONT_ATTR_FAVOR1 ((ULONG)0x01000000)
#define FONT_ATTR_FAVOR2 ((ULONG)0x02000000)
#define FONT_ATTR_FAVOR3 ((ULONG)0x04000000)
#define FONT_ATTR_FAVOR4 ((ULONG)0x08000000)
#define FONT_ATTR_FOUND ((ULONG)0x80000000)
struct ImplFontAttrWidthSearchData
{
const char* mpStr;
FontWidth meWidth;
};
static ImplFontAttrWidthSearchData const aImplWidthAttrSearchList[] =
{
{ "narrow", WIDTH_CONDENSED },
{ "semicondensed", WIDTH_SEMI_CONDENSED },
{ "ultracondensed", WIDTH_ULTRA_CONDENSED },
{ "semiexpanded", WIDTH_SEMI_EXPANDED },
{ "ultraexpanded", WIDTH_ULTRA_EXPANDED },
{ "expanded", WIDTH_EXPANDED },
{ "wide", WIDTH_ULTRA_EXPANDED },
{ "condensed", WIDTH_CONDENSED },
{ "cond", WIDTH_CONDENSED },
{ "cn", WIDTH_CONDENSED },
{ NULL, WIDTH_DONTKNOW },
};
struct ImplFontAttrWeightSearchData
{
const char* mpStr;
FontWeight meWeight;
};
static ImplFontAttrWeightSearchData const aImplWeightAttrSearchList[] =
{
{ "extrablack", WEIGHT_BLACK },
{ "ultrablack", WEIGHT_BLACK },
{ "black", WEIGHT_BLACK },
{ "heavy", WEIGHT_BLACK },
{ "ultrabold", WEIGHT_ULTRABOLD },
{ "semibold", WEIGHT_SEMIBOLD },
{ "bold", WEIGHT_BOLD },
{ "ultralight", WEIGHT_ULTRALIGHT },
{ "semilight", WEIGHT_SEMILIGHT },
{ "light", WEIGHT_LIGHT },
{ "demi", WEIGHT_SEMIBOLD },
{ "medium", WEIGHT_MEDIUM },
{ NULL, WEIGHT_DONTKNOW },
};
struct ImplFontAttrTypeSearchData
{
const char* mpStr;
ULONG mnType;
};
static ImplFontAttrTypeSearchData const aImplTypeAttrSearchList[] =
{
{ "titling", FONT_ATTR_TITLING },
{ "outline", FONT_ATTR_OUTLINE },
{ "shadow", FONT_ATTR_SHADOW },
{ NULL, 0 },
};
// =======================================================================
struct ImplFontNameAttr
{
const char* mpName;
FontFamily meFamily;
FontWeight meWeight;
FontWidth meWidth;
ULONG mnType;
};
static const ImplFontNameAttr aImplFullList[] =
{
{ "Bookman", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NORMAL | FONT_ATTR_STANDARD | FONT_ATTR_SERIF },
{ NULL, FAMILY_DONTKNOW,WEIGHT_DONTKNOW,WIDTH_DONTKNOW, 0 }
};
static const ImplFontNameAttr aImplMatchList[] =
{
{ "bookman", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NORMAL | FONT_ATTR_STANDARD | FONT_ATTR_SERIF },
{ "comicsansms", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 },
{ "kristenitc", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 },
{ "maiandragd", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 },
{ "arioso", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_ITALIC | FONT_ATTR_DECORATION | FONT_ATTR_OLDSTYLE | FONT_ATTR_FAVOR3 },
{ "tempussansitc", FAMILY_SCRIPT, WEIGHT_LIGHT, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT },
{ "papyrus", FAMILY_SCRIPT, WEIGHT_LIGHT, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT },
{ "lucidashadowtitling", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW },
{ "lucidaopenboldtitling",FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE },
{ "lucidaopentitling", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE },
{ "lucidaopen", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE },
{ "lucidashadow", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW },
{ "chevara", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_EXPANDED, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE },
{ "colonnamt", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_SPECIAL | FONT_ATTR_OUTLINE },
{ "imprintmtshadow", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW },
{ "castellar", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE },
{ "algerian", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_SPECIAL | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW | FONT_ATTR_OLDSTYLE },
{ NULL, FAMILY_DONTKNOW,WEIGHT_DONTKNOW,WIDTH_DONTKNOW, 0 }
};
#endif
static const char* aImplSwissMatchList[] =
{
"arial",
"avantgarde",
"cgomega",
"centurygothic",
"charcoal",
"chicago",
"frutiger",
"geneva",
"haettenschweiler",
"helmet",
"helv",
"lucida",
"impact",
"tahoma",
"univers",
"vagrounded",
"verdana",
NULL
};
static const char* aImplSwissSearchList[] =
{
"sansserif",
"swiss",
NULL
};
static const char* aImplRomanMatchList[] =
{
"algerian",
"antiqua",
"caliso",
"clarendon",
"colonna",
"garamond",
"newyork",
"palatino",
"timmons",
"serif",
2000-09-18 16:07:07 +00:00
NULL
};
static const char* aImplRomanSearchList[] =
{
"book",
"times",
"roman",
"bright",
NULL
};
static const char* aImplFixedMatchList[] =
{
"lineprinter",
"monaco",
"typewriter",
NULL
};
static const char* aImplFixedSearchList[] =
{
"console",
"courier",
"fixed",
"letter",
"monospace",
"terminal",
NULL
};
static const char* aImplScriptMatchList[] =
{
"arioso",
"coronet",
"cursive",
"marigold",
"zapfchancery",
NULL
};
static const char* aImplScriptSearchList[] =
{
"script",
"signet",
"handwriting",
"calligraphy",
NULL
};
static const char* aImplSymbolMatchList[] =
{
"marlett",
"monotypesorts",
"msoutlook",
NULL
};
static const char* aImplSymbolSearchList[] =
{
"symbol",
"bats",
"dings",
"math",
NULL
};
static const char* aImplTypeList[] =
{
"black",
"bold",
"condensed",
"expanded",
"narrow",
"outline",
NULL
};
// =======================================================================
static const char* aImplSearchScriptList[] =
{
"ce",
"we",
"cyr",
"tur",
"wt",
"greek",
"wl",
NULL
};
// -----------------------------------------------------------------------
struct ImplScriptSearchList
{
const char* mpScript;
rtl_Script meScript;
};
static void ImplCutScriptAndSpaces( XubString& rName )
{
rName.EraseLeadingAndTrailingChars( ' ' );
USHORT nLen = rName.Len();
if ( nLen < 3 )
return;
// Scriptname must be the last part of the fontname and
// looks like "fontname (scriptname)". So there can only be a
// script name at the and of the fontname, when the last char is
// ')'.
if ( rName.GetChar( nLen-1 ) == ')' )
{
int nOpen = 1;
nLen -= 2;
while ( nLen )
{
if ( rName.GetChar( nLen ) == '(' )
{
nOpen--;
if ( !nOpen && nLen && (rName.GetChar( nLen-1 ) == ' ') )
{
XubString aScript = rName.Copy( nLen+1, rName.Len()-1-nLen-1 );
rName.Erase( nLen-1 );
return;
}
}
if ( rName.GetChar( nLen ) == ')' )
nOpen++;
nLen--;
}
}
// For compatibility with older version we must search for a
// script name at the end of a fontname without brakets
USHORT nSpacePos = rName.SearchBackward( ' ' );
if ( nSpacePos && (nSpacePos != STRING_NOTFOUND) )
{
XubString aScript = rName.Copy( nSpacePos+1 );
const char** pScript = aImplSearchScriptList;
while ( *pScript )
{
if ( aScript.EqualsAscii( *pScript ) )
{
rName.Erase( nSpacePos );
break;
}
pScript++;
}
}
}
// =======================================================================
#if 0
static const ImplFontNameAttr* ImplFindFontAttr( const XubString& rFontName )
{
const ImplFontNameAttr* pList;
pList = aImplFullList;
while ( pList->mpName )
{
if ( rFontName.EqualsAscii( pList->mpName ) )
return pList;
pList++;
}
pList = aImplMatchList;
while ( pList->mpName )
{
if ( ImplStrFullMatch( rFontName, pList->mpName ) )
return pList;
pList++;
}
return NULL;
}
// -----------------------------------------------------------------------
static void ImplGetFontAttr( const XubString& rFontName,
FontFamily& rFamily, CharSet& rCharSet,
FontPitch& rPitch )
{
if ( (rFamily == FAMILY_DONTKNOW) || (rPitch == PITCH_DONTKNOW) ||
(rCharSet == CHARSET_DONTKNOW) )
{
}
}
#endif
// =======================================================================
BOOL ImplTestFontName( const XubString& rName,
const sal_Char** pMatchList,
const sal_Char** pSearchList )
{
const char** pAlias;
pAlias = pMatchList;
while ( *pAlias )
{
if ( ImplStrFullMatch( rName, *pAlias ) )
return TRUE;
pAlias++;
}
pAlias = pSearchList;
while ( *pAlias )
{
if ( rName.SearchAscii( *pAlias ) != STRING_NOTFOUND )
return TRUE;
pAlias++;
}
return FALSE;
}
// =======================================================================
static void ImplFontAttrFromName( const XubString& rFontName,
FontFamily& rFamily, CharSet& rCharSet,
FontPitch& rPitch )
{
if ( rFamily == FAMILY_DONTKNOW )
{
if ( ImplTestFontName( rFontName, aImplRomanMatchList, aImplRomanSearchList ) )
rFamily = FAMILY_ROMAN;
else if ( ImplTestFontName( rFontName, aImplSwissMatchList, aImplSwissSearchList ) )
rFamily = FAMILY_SWISS;
else if ( ImplTestFontName( rFontName, aImplScriptMatchList, aImplScriptSearchList ) )
rFamily = FAMILY_SCRIPT;
}
if ( rPitch == PITCH_DONTKNOW )
{
if ( ImplTestFontName( rFontName, aImplFixedMatchList, aImplFixedSearchList ) )
rPitch = PITCH_FIXED;
}
if ( rCharSet == RTL_TEXTENCODING_DONTKNOW )
{
if ( ImplTestFontName( rFontName, aImplSymbolMatchList, aImplSymbolSearchList ) )
rCharSet = RTL_TEXTENCODING_SYMBOL;
}
}
// =======================================================================
static const char* aImplStdSwissList[] =
{
"helvetica",
"arial",
"lucida sans",
"lucidasans",
"lucida",
"geneva",
"helmet",
"sansserif",
2000-09-18 16:07:07 +00:00
NULL
};
static const char* aImplStdRomanList[] =
{
"times",
"times new roman",
"timesnewroman",
"roman",
"lucida serif",
"lucidaserif",
"lucida bright",
"lucidabright",
"bookman",
"garamond",
"timmons",
"serif",
2000-09-18 16:07:07 +00:00
NULL
};
static const char* aImplStdFixedList[] =
{
"courier",
"courier new",
"lucida typewriter",
"lucidatypewriter",
"lucida sans typewriter",
"lucidasanstypewriter",
"monospaced",
2000-09-18 16:07:07 +00:00
NULL
};
static const char* aImplStdScriptList[] =
{
"zapf chancery",
"zapfchancery",
"lucida calligraphy",
"lucidacalligraphy",
"lucida handwriting",
"lucidahandwriting",
"arioso",
"script",
"marigold",
NULL
};
static const char* aImplStdSymbolList[] =
{
"starbats",
"symbol",
"zapf dingbats",
"zapfdingbats",
"wingdings",
"lucida dingbats",
"lucidadingbats",
"lucida sans dingbats",
"lucidasansdingbats",
NULL
};
// =======================================================================
void ImplFreeOutDevFontData()
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst;
while ( pEntry )
{
ImplFontSubstEntry* pNext = pEntry->mpNext;
delete pEntry;
pEntry = pNext;
}
}
// =======================================================================
static ImplFontData* ImplFindScript( ImplDevFontListData* pData,
rtl_Script eScript )
{
// Testen, ob ein Font mit einem entsprechendem
// Script vorhanden ist
ImplFontData* pCurFontData = pData->mpFirst;
while ( pCurFontData )
{
// Detect Unicode Font !!!
if ( pData->maMatchName.EqualsAscii( "arial unicode ms" ) ||
pData->maMatchName.EqualsAscii( "andale wt ui" ) )
2000-09-18 16:07:07 +00:00
return pCurFontData;
if ( eScript == pCurFontData->meScript )
return pCurFontData;
pCurFontData = pCurFontData->mpNext;
}
return NULL;
}
// -----------------------------------------------------------------------
/* !!! UNICODE - Duerfte nicht mehr gebraucht werden !!!
static rtl_TextEncoding ImplGetFakeEncoding( rtl_TextEncoding eEncoding )
{
rtl_TextEncoding eSystemEncoding = GetSystemCharSet();
// MS_1252 und 8859_1 sind kompatible
if ( ((eEncoding == RTL_TEXTENCODING_MS_1252) ||
(eEncoding == RTL_TEXTENCODING_ISO_8859_1)) &&
((eSystemEncoding == RTL_TEXTENCODING_MS_1252) ||
(eSystemEncoding == RTL_TEXTENCODING_ISO_8859_1)) )
return eEncoding;
else
{
// Wir testen, ob beide Zeichensaetze dem gleichem Script
// entsprechen, um so der Applikation das gleiche Encoding
// vorzugaukeln. Dies ist beispielsweise bei Russisch wichtig
// da hier Fonts mit unterschiedlichem Encoding auftauchen
// koennen.
rtl_Script eSrcScript;
rtl_Script eSystemScript;
rtl_TextEncodingInfo aTEncInfo;
aTEncInfo.StructSize = sizeof( aTEncInfo );
aTEncInfo.Script = SCRIPT_DONTKNOW;
if ( !rtl_getTextEncodingInfo( eEncoding, &aTEncInfo ) )
return eEncoding;
else
eSrcScript = aTEncInfo.Script;
aTEncInfo.Script = SCRIPT_DONTKNOW;
if ( !rtl_getTextEncodingInfo( eSystemEncoding, &aTEncInfo ) )
return eEncoding;
else
eSystemScript = aTEncInfo.Script;
if ( eSrcScript == eSystemScript )
eEncoding = eSystemEncoding;
}
return eEncoding;
}
*/
// =======================================================================
void OutputDevice::BeginFontSubstitution()
{
ImplSVData* pSVData = ImplGetSVData();
pSVData->maGDIData.mbFontSubChanged = FALSE;
}
// -----------------------------------------------------------------------
void OutputDevice::EndFontSubstitution()
{
ImplSVData* pSVData = ImplGetSVData();
if ( pSVData->maGDIData.mbFontSubChanged )
{
ImplUpdateAllFontData( FALSE );
Application* pApp = GetpApp();
DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
pApp->DataChanged( aDCEvt );
pApp->NotifyAllWindows( aDCEvt );
pSVData->maGDIData.mbFontSubChanged = FALSE;
}
}
// -----------------------------------------------------------------------
void OutputDevice::AddFontSubstitute( const XubString& rFontName,
const XubString& rReplaceFontName,
USHORT nFlags )
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = new ImplFontSubstEntry;
pEntry->maName = rFontName;
pEntry->maReplaceName = rReplaceFontName;
pEntry->maMatchName = rFontName;
pEntry->maMatchReplaceName = rReplaceFontName;
pEntry->mnFlags = nFlags;
pEntry->mpNext = pSVData->maGDIData.mpFirstFontSubst;
pEntry->maMatchName.ToLowerAscii();
pEntry->maMatchReplaceName.ToLowerAscii();
ImplCutScriptAndSpaces( pEntry->maMatchName );
ImplCutScriptAndSpaces( pEntry->maMatchReplaceName );
pSVData->maGDIData.mpFirstFontSubst = pEntry;
pSVData->maGDIData.mbFontSubChanged = TRUE;
}
// -----------------------------------------------------------------------
void OutputDevice::RemoveFontSubstitute( USHORT n )
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst;
ImplFontSubstEntry* pPrev = NULL;
USHORT nCount = 0;
while ( pEntry )
{
if ( nCount == n )
{
pSVData->maGDIData.mbFontSubChanged = TRUE;
if ( pPrev )
pPrev->mpNext = pEntry->mpNext;
else
pSVData->maGDIData.mpFirstFontSubst = pEntry->mpNext;
delete pEntry;
break;
}
nCount++;
pPrev = pEntry;
pEntry = pEntry->mpNext;
}
}
// -----------------------------------------------------------------------
USHORT OutputDevice::GetFontSubstituteCount()
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst;
USHORT nCount = 0;
while ( pEntry )
{
nCount++;
pEntry = pEntry->mpNext;
}
return nCount;
}
// -----------------------------------------------------------------------
void OutputDevice::GetFontSubstitute( USHORT n,
XubString& rFontName,
XubString& rReplaceFontName,
USHORT& rFlags )
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst;
USHORT nCount = 0;
while ( pEntry )
{
if ( nCount == n )
{
rFontName = pEntry->maName;
rReplaceFontName = pEntry->maReplaceName;
rFlags = pEntry->mnFlags;
break;
}
nCount++;
pEntry = pEntry->mpNext;
}
}
// -----------------------------------------------------------------------
static BOOL ImplFontSubstitute( XubString& rFontName,
USHORT nFlags1, USHORT nFlags2 )
{
ImplSVData* pSVData = ImplGetSVData();
ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst;
while ( pEntry )
{
if ( ((pEntry->mnFlags & nFlags1) == nFlags2) &&
(pEntry->maMatchName == rFontName) )
{
rFontName = pEntry->maMatchReplaceName;
return TRUE;
}
pEntry = pEntry->mpNext;
}
return FALSE;
}
// =======================================================================
ImplDevFontList::ImplDevFontList() :
List( CONTAINER_MAXBLOCKSIZE, 96, 32 )
{
#if 0
mbIsInitMatchData = FALSE;
#endif
}
// -----------------------------------------------------------------------
ImplDevFontList::~ImplDevFontList()
{
// Alle Eintraege loeschen
ImplDevFontListData* pEntry = First();
while ( pEntry )
{
// Liste der Font loeschen
ImplFontData* pFontData = pEntry->mpFirst;
do
{
ImplFontData* pTempFontData = pFontData;
pFontData = pFontData->mpNext;
delete pTempFontData;
}
while ( pFontData );
// Entry loeschen
delete pEntry;
pEntry = Next();
}
}
// -----------------------------------------------------------------------
static StringCompare ImplCompareFontDataWithoutSize( const ImplFontData* pEntry1,
const ImplFontData* pEntry2 )
{
// Vergleichen nach CharSet, Groesse, Breite, Weight, Italic, StyleName
if ( pEntry1->meCharSet < pEntry2->meCharSet )
return COMPARE_LESS;
else if ( pEntry1->meCharSet > pEntry2->meCharSet )
return COMPARE_GREATER;
if ( pEntry1->meWidthType < pEntry2->meWidthType )
return COMPARE_LESS;
else if ( pEntry1->meWidthType > pEntry2->meWidthType )
return COMPARE_GREATER;
if ( pEntry1->meWeight < pEntry2->meWeight )
return COMPARE_LESS;
else if ( pEntry1->meWeight > pEntry2->meWeight )
return COMPARE_GREATER;
if ( pEntry1->meItalic < pEntry2->meItalic )
return COMPARE_LESS;
else if ( pEntry1->meItalic > pEntry2->meItalic )
return COMPARE_GREATER;
return pEntry1->maStyleName.CompareTo( pEntry2->maStyleName );
}
// -----------------------------------------------------------------------
static StringCompare ImplCompareFontData( const ImplFontData* pEntry1,
const ImplFontData* pEntry2 )
{
StringCompare eComp = ImplCompareFontDataWithoutSize( pEntry1, pEntry2 );
if ( eComp != COMPARE_EQUAL )
return eComp;
if ( pEntry1->mnHeight < pEntry2->mnHeight )
return COMPARE_LESS;
else if ( pEntry1->mnHeight > pEntry2->mnHeight )
return COMPARE_GREATER;
if ( pEntry1->mnWidth < pEntry2->mnWidth )
return COMPARE_LESS;
else if ( pEntry1->mnWidth > pEntry2->mnWidth )
return COMPARE_GREATER;
return COMPARE_EQUAL;
}
// -----------------------------------------------------------------------
void ImplDevFontList::Add( ImplFontData* pNewData )
{
XubString aSearchName = pNewData->maName;
aSearchName.ToLowerAscii();
// Query Script for FontTest
rtl_TextEncodingInfo aTEncInfo;
aTEncInfo.StructSize = sizeof( aTEncInfo );
aTEncInfo.Script = SCRIPT_DONTKNOW;
rtl_getTextEncodingInfo( pNewData->meCharSet, &aTEncInfo );
pNewData->meScript = aTEncInfo.Script;
// Add Font
ULONG nIndex;
ImplDevFontListData* pFoundData = ImplFind( aSearchName, &nIndex );
BOOL bDelete = FALSE;
if ( !pFoundData )
{
pFoundData = new ImplDevFontListData;
pFoundData->maName = pNewData->maName;
pFoundData->maMatchName = aSearchName;
pFoundData->maMatchName2 = aSearchName;
pFoundData->mpFirst = pNewData;
#if 0
pFoundData->mbScalable = FALSE;
ImplStrEraseAllSymbols( pFoundData->maMatchName2 );
/*
pFoundData->meMatchFamily = pNewData->meFamily;
pFoundData->meMatchPitch = pNewData->mePitch;
CharSet eCharSet = pNewData->meCharSet;
ImplFontAttrFromName( pFoundData->maMatchName2, pFoundData->meMatchFamily,
eCharSet, pFoundData->meMatchPitch );
pFoundData->mbSymbol = eCharSet == RTL_TEXTENCODING_SYMBOL;
*/
#else
pFoundData->meMatchFamily = pNewData->meFamily;
pFoundData->meMatchPitch = pNewData->mePitch;
pFoundData->mnMatch = 0;
CharSet eCharSet = pNewData->meCharSet;
ImplStrEraseAllSymbols( pFoundData->maMatchName2 );
ImplFontAttrFromName( pFoundData->maMatchName2, pFoundData->meMatchFamily,
eCharSet, pFoundData->meMatchPitch );
pFoundData->mbSymbol = eCharSet == RTL_TEXTENCODING_SYMBOL;
#endif
pNewData->mpNext = NULL;
Insert( pFoundData, nIndex );
}
else
{
// Name ersetzen (spart Speicherplatz)
pNewData->maName = pFoundData->maName;
BOOL bInsert = TRUE;
ImplFontData* pPrev = NULL;
ImplFontData* pTemp = pFoundData->mpFirst;
do
{
StringCompare eComp = ImplCompareFontData( pNewData, pTemp );
if ( eComp != COMPARE_GREATER )
{
// Wenn Font gleich ist, nehmen wir einen Devicefont,
// oder ignorieren den Font
if ( eComp == COMPARE_EQUAL )
{
// Wir nehmen den Font mit der besseren Quality,
// ansonsten ziehen wir den Device-Font vor
if ( (pNewData->mnQuality > pTemp->mnQuality) ||
((pNewData->mnQuality == pTemp->mnQuality) &&
(pNewData->mbDevice && !pTemp->mbDevice)) )
{
pNewData->mpNext = pTemp->mpNext;
if ( pPrev )
pPrev->mpNext = pNewData;
else
pFoundData->mpFirst = pNewData;
delete pTemp;
}
else
{
bDelete = TRUE;
delete pNewData;
}
bInsert = FALSE;
}
break;
}
pPrev = pTemp;
pTemp = pTemp->mpNext;
}
while ( pTemp );
if ( bInsert )
{
pNewData->mpNext = pTemp;
if ( pPrev )
pPrev->mpNext = pNewData;
else
pFoundData->mpFirst = pNewData;
}
}
// Match zusammenzaehlen
if ( !bDelete )
{
#if 0
if ( (pNewData->meType == TYPE_SCALABLE) && (pNewData->mnHeight == 0) )
pFoundData->mbScalable = TRUE;
#else
if ( (pNewData->meType == TYPE_SCALABLE) && (pNewData->mnHeight == 0) )
{
if ( pNewData->meWidthType == WIDTH_NORMAL )
pFoundData->mnMatch += 30;
else
pFoundData->mnMatch += 3;
if ( pNewData->meItalic == ITALIC_NONE )
pFoundData->mnMatch += 20;
else
pFoundData->mnMatch += 2;
if ( (pNewData->meWeight == WEIGHT_NORMAL) || (pNewData->meWeight == WEIGHT_MEDIUM) )
pFoundData->mnMatch += 10;
else
pFoundData->mnMatch += 1;
}
#endif
}
}
// -----------------------------------------------------------------------
ImplDevFontListData* ImplDevFontList::ImplFind( const XubString& rFontName, ULONG* pIndex ) const
{
ULONG nCount = Count();
if ( !nCount )
{
if ( pIndex )
*pIndex = LIST_APPEND;
return NULL;
}
// Fonts in der Liste suchen
ImplDevFontListData* pCompareData;
ImplDevFontListData* pFoundData = NULL;
ULONG nLow = 0;
ULONG nHigh = nCount-1;
ULONG nMid;
StringCompare eCompare;
do
{
nMid = (nLow + nHigh) / 2;
pCompareData = Get( nMid );
eCompare = rFontName.CompareTo( pCompareData->maMatchName );
if ( eCompare == COMPARE_LESS )
{
if ( !nMid )
break;
nHigh = nMid-1;
}
else
{
if ( eCompare == COMPARE_GREATER )
nLow = nMid + 1;
else
{
pFoundData = pCompareData;
break;
}
}
}
while ( nLow <= nHigh );
if ( pIndex )
{
eCompare = rFontName.CompareTo( pCompareData->maMatchName );
if ( eCompare == COMPARE_GREATER )
*pIndex = (nMid+1);
else
*pIndex = nMid;
}
return pFoundData;
}
// -----------------------------------------------------------------------
ImplDevFontListData* ImplDevFontList::FindFont( const XubString& rFontName ) const
{
XubString aName = rFontName;
aName.ToLowerAscii();
ImplCutScriptAndSpaces( aName );
return ImplFind( aName );
}
// -----------------------------------------------------------------------
ImplDevFontListData* ImplDevFontList::FindStdFont( const sal_Char** pStdFontNames,
rtl_Script eScript ) const
{
// We want a scalable font with a system script
ImplDevFontListData* pRasterFoundData = NULL;
ImplDevFontListData* pWrongScriptRasterData = NULL;
ImplDevFontListData* pWrongScriptData = NULL;
while ( *pStdFontNames )
{
XubString aStdName( *pStdFontNames, RTL_TEXTENCODING_ASCII_US );
ImplDevFontListData* pFoundData = ImplFind( aStdName );
if ( pFoundData )
{
if ( ((eScript != SCRIPT_LATIN) &&
(eScript != SCRIPT_EASTEUROPE) &&
(eScript != SCRIPT_CYRILLIC) &&
(eScript != SCRIPT_BALTIC) &&
(eScript != SCRIPT_TURKISH) &&
(eScript != SCRIPT_GREEK) &&
(eScript != SCRIPT_GEORGIEN)) ||
2000-09-18 16:07:07 +00:00
ImplFindScript( pFoundData, eScript ) )
{
if ( pFoundData->mpFirst->meType != TYPE_RASTER )
return pFoundData;
else if ( !pRasterFoundData )
pRasterFoundData = pFoundData;
}
else
{
if ( pFoundData->mpFirst->meType != TYPE_RASTER )
{
if ( !pWrongScriptData )
pWrongScriptData = pFoundData;
}
else
{
if ( !pWrongScriptRasterData )
pWrongScriptRasterData = pFoundData;
}
}
}
pStdFontNames++;
}
// Wenn keine passende Schrift, dann die Reihenfolge:
// - passender Zeichensatz
// - Skalierbar
// - eine passende Schrift die nicht skalierbar und den
// falschen Zeichensatz hat
// - keine
if ( pRasterFoundData )
return pRasterFoundData;
else if ( pWrongScriptData )
return pWrongScriptData;
else
return pWrongScriptRasterData;
}
// -----------------------------------------------------------------------
void ImplDevFontList::Clear()
{
// Alle Eintraege loeschen
ImplDevFontListData* pEntry = First();
while ( pEntry )
{
// Liste der Font loeschen
ImplFontData* pFontData = pEntry->mpFirst;
do
{
ImplFontData* pTempFontData = pFontData;
pFontData = pFontData->mpNext;
delete pTempFontData;
}
while ( pFontData );
// Entry loeschen
delete pEntry;
pEntry = Next();
}
List::Clear();
// Standard-Fonts loeschen
for ( USHORT i = 0; i < IMPL_STDFONT_COUNT; i++ )
mpStdFontAry[i] = NULL;
#if 0
mbIsInitMatchData = FALSE;
#endif
}
// -----------------------------------------------------------------------
#if 0
void ImplDevFontList::InitMatchData()
{
if ( mbIsInitMatchData )
return;
mbIsInitMatchData = TRUE;
/*
// Fuer alle Eintraege die Matchdaten ermitteln
ImplDevFontListData* pEntry = First();
while ( pEntry )
{
ImplFontData* pFontData = pEntry->mpFirst;
pEntry = Next();
}
*/
}
#endif
// -----------------------------------------------------------------------
void ImplDevFontList::InitStdFonts()
{
rtl_Script eSystemScript;
rtl_TextEncodingInfo aTextEncInfo;
aTextEncInfo.StructSize = sizeof( aTextEncInfo );
aTextEncInfo.Script = SCRIPT_DONTKNOW;
rtl_getTextEncodingInfo( gsl_getSystemTextEncoding(), &aTextEncInfo );
eSystemScript = aTextEncInfo.Script;
mpStdFontAry[IMPL_STDFONT_SWISS] = FindStdFont( aImplStdSwissList, eSystemScript );
mpStdFontAry[IMPL_STDFONT_ROMAN] = FindStdFont( aImplStdRomanList, eSystemScript );
mpStdFontAry[IMPL_STDFONT_FIXED] = FindStdFont( aImplStdFixedList, eSystemScript );
mpStdFontAry[IMPL_STDFONT_SCRIPT] = FindStdFont( aImplStdScriptList, eSystemScript );
mpStdFontAry[IMPL_STDFONT_SYMBOL] = FindStdFont( aImplStdSymbolList, SCRIPT_SYMBOL );
}
// =======================================================================
void ImplGetDevSizeList::Add( long nNewHeight )
{
ULONG n = Count();
if ( !n || (nNewHeight > Get( n-1 )) )
Insert( (void*)nNewHeight, LIST_APPEND );
else
{
for ( ULONG i=0 ; i < n; i++ )
{
long nHeight = Get( i );
if ( nNewHeight <= nHeight )
{
if ( nNewHeight != nHeight )
Insert( (void*)nNewHeight, i );
break;
}
}
}
}
// =======================================================================
ImplFontEntry::~ImplFontEntry()
{
if ( mpWidthAry )
delete mpWidthAry;
if ( mpKernPairs )
delete mpKernPairs;
if ( mpKernInfo )
delete mpKernInfo;
}
// =======================================================================
ImplFontCache::ImplFontCache( BOOL bPrinter )
{
mpFirstEntry = NULL;
mnRef0Count = 0;
mbPrinter = bPrinter;
}
// -----------------------------------------------------------------------
ImplFontCache::~ImplFontCache()
{
// Alle Eintraege loeschen
ImplFontEntry* pTemp;
ImplFontEntry* pEntry = mpFirstEntry;
while ( pEntry )
{
pTemp = pEntry->mpNext;
delete pEntry;
pEntry = pTemp;
}
}
// -----------------------------------------------------------------------
ImplFontEntry* ImplFontCache::Get( ImplDevFontList* pFontList,
const Font& rFont, const Size& rSize )
{
const XubString& rName = rFont.GetName();
const XubString& rStyleName = rFont.GetStyleName();
long nWidth = rSize.Width();
long nHeight = rSize.Height();
FontFamily eFamily = rFont.GetFamily();
CharSet eCharSet = rFont.GetCharSet();
FontWeight eWeight = rFont.GetWeight();
FontItalic eItalic = rFont.GetItalic();
FontPitch ePitch = rFont.GetPitch();
short nOrientation = (short)(rFont.GetOrientation() % 3600);
2000-11-03 14:10:35 +00:00
BOOL bVertical = rFont.IsVertical();
2000-09-18 16:07:07 +00:00
// Groesse anpassen
if ( nHeight < 0 )
nHeight = -nHeight;
if ( nWidth < 0 )
nWidth = -nWidth;
// Eintrag suchen
ImplFontEntry* pPrevEntry = NULL;
ImplFontEntry* pEntry = mpFirstEntry;
while ( pEntry )
{
ImplFontSelectData* pFontSelData = &(pEntry->maFontSelData);
if ( (nHeight == pFontSelData->mnHeight) &&
(eWeight == pFontSelData->meWeight) &&
(eItalic == pFontSelData->meItalic) &&
(rName == pFontSelData->maName) &&
(rStyleName == pFontSelData->maStyleName) &&
(eCharSet == pFontSelData->meCharSet) &&
(eFamily == pFontSelData->meFamily) &&
(ePitch == pFontSelData->mePitch) &&
(nWidth == pFontSelData->mnWidth) &&
2000-11-03 14:10:35 +00:00
(bVertical == pFontSelData->mbVertical) &&
2000-09-18 16:07:07 +00:00
(nOrientation == pFontSelData->mnOrientation) )
{
if ( !pEntry->mnRefCount )
mnRef0Count--;
pEntry->mnRefCount++;
// Entry nach vorne bringen
if ( pPrevEntry )
{
pPrevEntry->mpNext = pEntry->mpNext;
pEntry->mpNext = mpFirstEntry;
mpFirstEntry = pEntry;
}
return pEntry;
}
pPrevEntry = pEntry;
pEntry = pEntry->mpNext;
}
// Wir suchen zuerst ueber den Namen den passenden Font
XubString aLowerFontName = rName;
XubString aFirstName;
XubString aTempName;
XubString aTempName2;
ImplDevFontListData* pFoundData;
ImplDevFontListData* pTempFoundData;
xub_StrLen nFirstNameIndex = 0;
xub_StrLen nIndex = 0;
USHORT nSubstFlags1 = FONT_SUBSTITUTE_ALWAYS;
USHORT nSubstFlags2 = FONT_SUBSTITUTE_ALWAYS;
rtl_Script eScript = SCRIPT_DONTKNOW;
rtl_Script eCharSetScript;
rtl_TextEncodingInfo aTextEncInfo;
aTextEncInfo.StructSize = sizeof( aTextEncInfo );
aTextEncInfo.Script = SCRIPT_DONTKNOW;
rtl_getTextEncodingInfo( eCharSet, &aTextEncInfo );
eCharSetScript = aTextEncInfo.Script;
if ( mbPrinter )
nSubstFlags1 |= FONT_SUBSTITUTE_SCREENONLY;
aLowerFontName.ToLowerAscii();
pTempFoundData = NULL;
do
{
aTempName = aLowerFontName.GetToken( 0, ';', nIndex );
ImplCutScriptAndSpaces( aTempName );
if ( !aFirstName.Len() )
{
aFirstName = aTempName;
nFirstNameIndex = nIndex;
}
ImplFontSubstitute( aTempName, nSubstFlags1, nSubstFlags2 );
pFoundData = pFontList->ImplFind( aTempName );
if ( pFoundData )
{
if ( eCharSetScript != SCRIPT_DONTKNOW )
{
if ( !pTempFoundData )
{
aTempName2 = aTempName;
pTempFoundData = pFoundData;
}
// Testen, ob ein Font mit einem entsprechendem
// Script vorhanden ist
if ( ImplFindScript( pFoundData, eCharSetScript ) )
{
aLowerFontName = aTempName;
break;
}
else
pFoundData = NULL;
}
else
{
aLowerFontName = aTempName;
break;
}
}
}
while ( nIndex != STRING_NOTFOUND );
if ( !pFoundData && pTempFoundData )
{
pFoundData = pTempFoundData;
aLowerFontName = aTempName2;
}
// Danach versuchen wir es nocheinmal unter Beruecksichtigung
// der gloablen Fontersetzungstabelle, wobei wir jetzt auch
// die Fonts nehmen, die ersetzt werden sollen, wenn sie
// nicht vorhanden sind
if ( !pFoundData )
{
nSubstFlags1 &= ~FONT_SUBSTITUTE_ALWAYS;
nSubstFlags2 &= ~FONT_SUBSTITUTE_ALWAYS;
nIndex = 0;
do
{
aTempName = aLowerFontName.GetToken( 0, ';', nIndex );
ImplCutScriptAndSpaces( aTempName );
if ( ImplFontSubstitute( aTempName, nSubstFlags1, nSubstFlags2 ) )
{
pFoundData = pFontList->ImplFind( aTempName );
if ( pFoundData )
{
aLowerFontName = aTempName;
break;
}
}
}
while ( nIndex != STRING_NOTFOUND );
}
// Wenn kein Font mit dem entsprechenden Namen existiert, versuchen
// wir ueber den Namen und die Attribute einen passenden Font zu
// finden
ULONG nFontCount = pFontList->Count();
if ( !pFoundData && nFontCount )
{
#if 0
pFontList->InitMatchData();
// 1. Token vom Fontnamen nehmen und Sonderzeichen entfernen
XubString aNoSymbolName = aFirstName;
ImplCutScriptAndSpaces( aNoSymbolName );
ImplStrEraseAllSymbols( aNoSymbolName );
// Script evtl. aus CharSet gewinnen, wenn nicht ueber den Fontnamen
// ermittelt werden konnte
if ( eScript == SCRIPT_DONTKNOW )
eScript = eCharSetScript;
// wir versuchen zuerst einen Font zu finden, der ueber den Namen
// matched
ULONG nTestMatch;
ULONG nBestMatch = 0;
for ( ULONG i = 0; i < nFontCount; i++ )
{
ImplDevFontListData* pData = pFontList->Get( i );
nTestMatch = 0;
// Wir wollen schon Zeichen erkennen
if ( eScript != SCRIPT_DONTKNOW )
{
if ( ImplFindScript( pData, eScript ) )
nTestMatch += 1000000000;
}
// skalierbare Schriften haben schon einen echten Vorteil
// gegenueber nicht skalierbaren Schriften
if ( pData->mbScalable )
nTestMatch += 500000000;
/*
// Wir gehen davon aus, wenn der Name groesstenteils matcht,
// das er schon zur richtigen Familie gehoert
// Beim matchen ignorieren wir alle Sonderzeichen
ULONG nTestMatch = ImplStrMatch( aNoSymbolName, pData->maMatchName2 );
if ( nTestMatch >= nBestMatch )
{
// Match nur erlaubt, wenn auch die Attribute uebereinstimmen
BOOL bTestFamily = pData->meMatchFamily != FAMILY_DONTKNOW;
BOOL bTestSymbol = pData->mbSymbol;
BOOL bTestFixed = pData->meMatchPitch == PITCH_FIXED;
if ( (bFixed == bTestFixed) && (bSymbol == bTestSymbol) &&
(!bFamily || !bTestFamily || (eSearchFamily == pData->meMatchFamily)) )
{
xub_StrLen nAttrMatch = 0;
// Die Anzahl der uebereinstimmenden Attribute zaehlen
const char** pTypeList = aImplTypeList;
while ( *pTypeList )
{
if ( (aNoSymbolName.Search( *pTypeList ) != STRING_NOTFOUND) &&
(pData->maMatchName2.Search( *pTypeList ) != STRING_NOTFOUND) )
nAttrMatch++;
pTypeList++;
}
// Wenn beide Matches gleich gut sind,
// entscheiden die uebereinstimmenden Attribute
if ( nBestMatch == nTestMatch )
{
if ( (nAttrMatch > nBestAttrMatch) ||
((nAttrMatch == nBestAttrMatch) &&
(pData->maMatchName2.Len() < nBestStrLen)) )
{
pFoundData = pData;
nBestMatch = nTestMatch;
nBestAttrMatch = nAttrMatch;
nBestStrLen = pData->maMatchName2.Len();
}
}
else
{
pFoundData = pData;
nBestMatch = nTestMatch;
nBestAttrMatch = nAttrMatch;
nBestStrLen = pData->maMatchName2.Len();
}
}
}
*/
if ( nTestMatch > nBestMatch )
{
pFoundData = pData;
nBestMatch = nTestMatch;
}
}
if ( !pFoundData )
{
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN );
// Wenn alles nichts hilft, nehmen wir den ersten
if ( !pFoundData )
pFoundData = pFontList->Get( 0 );
2000-09-18 16:07:07 +00:00
}
#else
// 1. Token vom Fontnamen nehmen und Sonderzeichen entfernen
XubString aNoSymbolName = aFirstName;
ImplStrEraseAllSymbols( aNoSymbolName );
// Suchattribute ermitteln
BOOL bFamily;
BOOL bSymbol;
BOOL bFixed;
FontFamily eSearchFamily = eFamily;
CharSet eSearchCharSet = eCharSet;
FontPitch eSearchPitch = ePitch;
ImplFontAttrFromName( aNoSymbolName, eSearchFamily, eSearchCharSet, eSearchPitch );
bFamily = eSearchFamily != FAMILY_DONTKNOW;
bSymbol = eSearchCharSet == RTL_TEXTENCODING_SYMBOL;
bFixed = eSearchPitch == PITCH_FIXED;
// Solange in der Namesliste suchen, bis wir auswertbare
// Attribute gefunden haben
xub_StrLen nTempIndex = nFirstNameIndex;
while ( (nTempIndex != STRING_NOTFOUND) && !bFamily && !bFixed && !bSymbol )
{
aTempName = aLowerFontName.GetToken( 0, ';', nTempIndex );
ImplCutScriptAndSpaces( aTempName );
if ( !aTempName.Len() )
break;
ImplStrEraseAllSymbols( aTempName );
ImplFontAttrFromName( aTempName, eSearchFamily, eSearchCharSet, eSearchPitch );
bFamily = eSearchFamily != FAMILY_DONTKNOW;
bSymbol = eSearchCharSet == RTL_TEXTENCODING_SYMBOL;
bFixed = eSearchPitch == PITCH_FIXED;
}
aLowerFontName = aFirstName;
// wir versuchen zuerst einen Font zu finden, der ueber den Namen
// matched
ULONG i;
xub_StrLen nBestMatch = 5;
xub_StrLen nBestAttrMatch = 0;
xub_StrLen nBestStrLen = 0xFFFF;
for ( i = 0; i < nFontCount; i++ )
{
ImplDevFontListData* pData = pFontList->Get( i );
// Beim matchen ignorieren wir alle Sonderzeichen
xub_StrLen nTestMatch = ImplStrMatch( aNoSymbolName, pData->maMatchName2 );
if ( nTestMatch >= nBestMatch )
{
// Match nur erlaubt, wenn auch die Attribute uebereinstimmen
BOOL bTestFamily = pData->meMatchFamily != FAMILY_DONTKNOW;
BOOL bTestSymbol = pData->mbSymbol;
BOOL bTestFixed = pData->meMatchPitch == PITCH_FIXED;
if ( (bFixed == bTestFixed) && (bSymbol == bTestSymbol) &&
(!bFamily || !bTestFamily || (eSearchFamily == pData->meMatchFamily)) )
{
xub_StrLen nAttrMatch = 0;
// Die Anzahl der uebereinstimmenden Attribute zaehlen
const char** pTypeList = aImplTypeList;
while ( *pTypeList )
{
if ( (aNoSymbolName.SearchAscii( *pTypeList ) != STRING_NOTFOUND) &&
(pData->maMatchName2.SearchAscii( *pTypeList ) != STRING_NOTFOUND) )
nAttrMatch++;
pTypeList++;
}
// Wenn beide Matches gleich gut sind,
// entscheiden die uebereinstimmenden Attribute
if ( nBestMatch == nTestMatch )
{
if ( (nAttrMatch > nBestAttrMatch) ||
((nAttrMatch == nBestAttrMatch) &&
(pData->maMatchName2.Len() < nBestStrLen)) )
{
pFoundData = pData;
nBestMatch = nTestMatch;
nBestAttrMatch = nAttrMatch;
nBestStrLen = pData->maMatchName2.Len();
}
}
else
{
pFoundData = pData;
nBestMatch = nTestMatch;
nBestAttrMatch = nAttrMatch;
nBestStrLen = pData->maMatchName2.Len();
}
}
}
}
// Wenn wir immer noch keinen passenden Font gefunden haben, versuchen
// wir es ueber die Attribute
if ( !pFoundData )
{
if ( bFixed )
{
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_FIXED );
if ( !pFoundData )
{
nBestMatch = 0;
for ( i = 0; i < nFontCount; i++ )
{
ImplDevFontListData* pData = pFontList->Get( i );
if ( (pData->meMatchPitch == PITCH_FIXED) &&
!pData->mbSymbol &&
(pData->meMatchFamily != FAMILY_DECORATIVE) )
{
if ( pData->mnMatch > nBestMatch )
{
pFoundData = pData;
nBestMatch = pData->mnMatch;
}
}
}
}
}
if ( bFamily && !pFoundData )
{
if ( eSearchFamily == FAMILY_SWISS )
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SWISS );
else if ( eSearchFamily == FAMILY_ROMAN )
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN );
else if ( eSearchFamily == FAMILY_SCRIPT )
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SCRIPT );
if ( !pFoundData )
{
nBestMatch = 0;
for ( i = 0; i < nFontCount; i++ )
{
ImplDevFontListData* pData = pFontList->Get( i );
if ( (pData->meMatchFamily == eSearchFamily) &&
!pData->mbSymbol &&
(pData->meMatchPitch != PITCH_FIXED) )
{
if ( pData->mnMatch > nBestMatch )
{
pFoundData = pData;
nBestMatch = pData->mnMatch;
}
}
}
}
}
if ( bSymbol && !pFoundData )
{
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SYMBOL );
if ( !pFoundData )
{
nBestMatch = 0;
for ( i = 0; i < nFontCount; i++ )
{
ImplDevFontListData* pData = pFontList->Get( i );
if ( pData->mbSymbol )
{
if ( pData->mnMatch > nBestMatch )
{
pFoundData = pData;
nBestMatch = pData->mnMatch;
}
}
}
}
}
if ( !pFoundData )
{
pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN );
// Wenn alles nichts hilft, nehmen wir den ersten
if ( !pFoundData )
pFontList->Get( 0 );
}
}
#endif
}
// Script evtl. aus CharSet gewinnen, wenn nicht ueber den Fontnamen
// ermittelt werden konnte
if ( eScript == SCRIPT_DONTKNOW )
eScript = eCharSetScript;
// Jetzt suchen wir den Font ueber die Attribute
ImplFontData* pFontData = NULL;
if ( pFoundData )
{
ULONG nBestMatch = 0; // Der groessere Wert ist der bessere
ULONG nBestHeightMatch = 0; // Der kleinere Wert ist der bessere
ULONG nBestWidthMatch = 0; // Der kleinere Wert ist der bessere
ULONG nMatch;
ULONG nHeightMatch;
ULONG nWidthMatch;
ImplFontData* pCurFontData;
// !!!!! Wegen Office-Fehler !!!!
// XubString aCompareStyleName = rStyleName;
// aCompareStyleName.ToLowerAscii();
// Vorallem wegen OS2-System-Standard-Fonts vergleichen wir
// den FontNamen mit FontName + StyleName, damit
// WarpSans Bold auch einen fetten Font ergibt
const xub_Unicode* pCompareStyleName = NULL;
if ( (aLowerFontName.Len() > pFoundData->maMatchName.Len()) &&
aLowerFontName.Equals( pFoundData->maMatchName, 0, pFoundData->maMatchName.Len() ) )
pCompareStyleName = aLowerFontName.GetBuffer()+pFoundData->maMatchName.Len()+1;
pCurFontData = pFoundData->mpFirst;
while ( pCurFontData )
{
nMatch = 0;
nHeightMatch = 0;
nWidthMatch = 0;
// if ( aCompareStyleName.Len() &&
// aCompareStyleName.EqualsIgnoreCaseAscii( pCurFontData->maStyleName ) )
// nMatch += 120000;
if ( pCompareStyleName &&
pCurFontData->maStyleName.EqualsIgnoreCaseAscii( pCompareStyleName ) )
nMatch += 120000;
if ( eCharSet != RTL_TEXTENCODING_DONTKNOW )
{
if ( eCharSet == pCurFontData->meCharSet )
nMatch += 60000;
}
if ( eScript == pCurFontData->meScript )
nMatch += 30000;
if ( (ePitch != PITCH_DONTKNOW) && (ePitch == pCurFontData->mePitch) )
nMatch += 15000;
if ( (eFamily != FAMILY_DONTKNOW) && (eFamily == pCurFontData->meFamily) )
nMatch += 7500;
// Normale Schriftbreiten bevorzugen, da wir noch keine Daten
// von den Applikationen bekommen
if ( pCurFontData->meWidthType == WIDTH_NORMAL )
nMatch += 3750;
if ( eWeight != WEIGHT_DONTKNOW )
{
USHORT nReqWeight;
USHORT nGivenWeight;
USHORT nWeightDiff;
// schmale Fonts werden bei nicht Bold vor fetten
// Fonts bevorzugt
if ( eWeight > WEIGHT_MEDIUM )
nReqWeight = ((USHORT)eWeight)+100;
else
nReqWeight = (USHORT)eWeight;
if ( pCurFontData->meWeight > WEIGHT_MEDIUM )
nGivenWeight = ((USHORT)pCurFontData->meWeight)+100;
else
nGivenWeight = (USHORT)pCurFontData->meWeight;
if ( nReqWeight > nGivenWeight )
nWeightDiff = nReqWeight-nGivenWeight;
else
nWeightDiff = nGivenWeight-nReqWeight;
if ( nWeightDiff == 0 )
nMatch += 1000;
else if ( nWeightDiff == 1 )
nMatch += 700;
else if ( nWeightDiff < 50 )
nMatch += 200;
}
if ( eItalic == ITALIC_NONE )
{
if ( pCurFontData->meItalic == ITALIC_NONE )
nMatch += 900;
}
else
{
if ( eItalic == pCurFontData->meItalic )
nMatch += 900;
else if ( pCurFontData->meItalic != ITALIC_NONE )
nMatch += 600;
}
if ( pCurFontData->mbDevice )
nMatch += 40;
if ( pCurFontData->meType == TYPE_SCALABLE )
{
if ( nOrientation )
nMatch += 80;
else
{
if ( nWidth )
nMatch += 25;
else
nMatch += 5;
}
}
else
{
if ( nHeight == pCurFontData->mnHeight )
{
nMatch += 20;
if ( nWidth == pCurFontData->mnWidth )
nMatch += 10;
}
else
{
// Dann kommt die Size-Abweichung in die
// Bewertung rein. Hier bevorzugen wir
// nach Moeglichkeit den kleineren Font
if ( nHeight < pCurFontData->mnHeight )
nHeightMatch += pCurFontData->mnHeight-nHeight;
else
nHeightMatch += (nHeight-pCurFontData->mnHeight-nHeight)+10000;
if ( nWidth && pCurFontData->mnWidth && (nWidth != pCurFontData->mnWidth) )
{
if ( nWidth < pCurFontData->mnWidth )
nWidthMatch += pCurFontData->mnWidth-nWidth;
else
nWidthMatch += nWidth-pCurFontData->mnWidth-nWidth;
}
}
}
if ( nMatch > nBestMatch )
{
pFontData = pCurFontData;
nBestMatch = nMatch;
nBestHeightMatch = nHeightMatch;
nBestWidthMatch = nWidthMatch;
}
else if ( nMatch == nBestMatch )
{
// Wenn 2 gleichwertig sind, kommt die Size-Bewertung
// Hier gewinnt der jenige, der die niedrigere Abweichung
// in der Groesse hat (also den kleinsten Match)
if ( nHeightMatch < nBestHeightMatch )
{
pFontData = pCurFontData;
nBestHeightMatch = nHeightMatch;
nBestWidthMatch = nWidthMatch;
}
else if ( nHeightMatch == nBestHeightMatch )
{
if ( nWidthMatch < nBestWidthMatch )
{
pFontData = pCurFontData;
nBestWidthMatch = nWidthMatch;
}
}
}
pCurFontData = pCurFontData->mpNext;
}
}
// Daten initialisieren und in die Liste aufnehmen
pEntry = new ImplFontEntry;
pEntry->mbInit = FALSE;
pEntry->mnRefCount = 1;
pEntry->mpNext = mpFirstEntry;
pEntry->mnWidthAryCount = 0;
pEntry->mnWidthArySize = 0;
pEntry->mpWidthAry = NULL;
pEntry->mpKernPairs = NULL;
pEntry->mpKernInfo = NULL;
pEntry->mnOwnOrientation = 0;
pEntry->mnOrientation = 0;
mpFirstEntry = pEntry;
// Font-Selection-Daten setzen
ImplFontSelectData* pFontSelData = &(pEntry->maFontSelData);
pFontSelData->mpFontData = pFontData;
pFontSelData->mpSysSelData = NULL;
pFontSelData->maName = rName;
pFontSelData->maStyleName = rStyleName;
pFontSelData->mnWidth = nWidth;
pFontSelData->mnHeight = nHeight;
pFontSelData->meFamily = eFamily;
pFontSelData->meCharSet = eCharSet;
pFontSelData->meWidthType = WIDTH_DONTKNOW;
pFontSelData->meWeight = eWeight;
pFontSelData->meItalic = eItalic;
pFontSelData->mePitch = ePitch;
pFontSelData->mnOrientation = nOrientation;
2000-11-03 14:10:35 +00:00
pFontSelData->mbVertical = bVertical;
2000-09-18 16:07:07 +00:00
return pEntry;
}
// -----------------------------------------------------------------------
void ImplFontCache::Release( ImplFontEntry* pEntry )
{
pEntry->mnRefCount--;
if ( !pEntry->mnRefCount )
{
if ( mnRef0Count >= MAXFONT_CACHE )
{
// Letzten Entry mit RefCount 0 loeschen
ImplFontEntry* pPrevDelEntry = mpFirstEntry;
ImplFontEntry* pDelEntry = pPrevDelEntry->mpNext;
USHORT nCurRef0Count = !(pPrevDelEntry->mnRefCount);
while ( pDelEntry )
{
if ( !pDelEntry->mnRefCount )
nCurRef0Count++;
if ( nCurRef0Count >= MAXFONT_CACHE )
{
pPrevDelEntry->mpNext = pDelEntry->mpNext;
delete pDelEntry;
break;
}
pPrevDelEntry = pDelEntry;
pDelEntry = pDelEntry->mpNext;
}
}
else
mnRef0Count++;
}
}
// -----------------------------------------------------------------------
void ImplFontCache::Clear()
{
// Alle Eintraege loeschen
ImplFontEntry* pTemp;
ImplFontEntry* pEntry = mpFirstEntry;
while ( pEntry )
{
DBG_ASSERT( !pEntry->mnRefCount, "ImplFontCache::Clear() - Font in use" );
pTemp = pEntry->mpNext;
delete pEntry;
pEntry = pTemp;
}
mpFirstEntry = NULL;
mnRef0Count = 0;
}
// =======================================================================
class ImplTextLineInfo
{
private:
long mnWidth;
xub_StrLen mnIndex;
xub_StrLen mnLen;
public:
ImplTextLineInfo( long nWidth, xub_StrLen nIndex, xub_StrLen nLen )
{
mnWidth = nWidth;
mnIndex = nIndex;
mnLen = nLen;
}
long GetWidth() const { return mnWidth; }
xub_StrLen GetIndex() const { return mnIndex; }
xub_StrLen GetLen() const { return mnLen; }
};
#define MULTITEXTLINEINFO_RESIZE 16
typedef ImplTextLineInfo* PImplTextLineInfo;
class ImplMultiTextLineInfo
{
private:
PImplTextLineInfo* mpLines;
xub_StrLen mnLines;
xub_StrLen mnSize;
public:
ImplMultiTextLineInfo();
~ImplMultiTextLineInfo();
void AddLine( ImplTextLineInfo* pLine );
void Clear();
ImplTextLineInfo* GetLine( USHORT nLine ) const
{ return mpLines[nLine]; }
xub_StrLen Count() const { return mnLines; }
private:
ImplMultiTextLineInfo( const ImplMultiTextLineInfo& );
ImplMultiTextLineInfo& operator=( const ImplMultiTextLineInfo& );
};
ImplMultiTextLineInfo::ImplMultiTextLineInfo()
{
mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
mnLines = 0;
mnSize = MULTITEXTLINEINFO_RESIZE;
}
ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
{
for ( xub_StrLen i = 0; i < mnLines; i++ )
delete mpLines[i];
delete mpLines;
}
void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
{
if ( mnSize == mnLines )
{
mnSize += MULTITEXTLINEINFO_RESIZE;
PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
mpLines = pNewLines;
}
mpLines[mnLines] = pLine;
mnLines++;
}
void ImplMultiTextLineInfo::Clear()
{
for ( xub_StrLen i = 0; i < mnLines; i++ )
delete mpLines[i];
mnLines = 0;
}
// =======================================================================
2001-02-23 15:13:58 +00:00
static FontEmphasisMark ImplGetEmphasisMarkStyle( const Font& rFont )
{
FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
// If no Position is set, then calculate the default position, which
// depends on the language
if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
{
LanguageType eLang = rFont.GetLanguage();
// In Chinese Simplified the EmphasisMarks are below/left
if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) &&
(eLang == LANGUAGE_CHINESE_SINGAPORE) )
nEmphasisMark |= EMPHASISMARK_POS_BELOW;
else
{
eLang = rFont.GetCJKContextLanguage();
// In Chinese Simplified the EmphasisMarks are below/left
if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) &&
(eLang == LANGUAGE_CHINESE_SINGAPORE) )
nEmphasisMark |= EMPHASISMARK_POS_BELOW;
else
nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
}
}
return nEmphasisMark;
}
// =======================================================================
2000-09-18 16:07:07 +00:00
void OutputDevice::ImplInitFont()
{
DBG_TESTSOLARMUTEX();
if ( mbInitFont )
{
mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData) );
mbInitFont = FALSE;
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplInitTextColor()
{
DBG_TESTSOLARMUTEX();
if ( mbInitTextColor )
{
#ifndef REMOTE_APPSERVER
mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
#else
mpGraphics->SetTextColor( GetTextColor() );
#endif
mbInitTextColor = FALSE;
}
}
// -----------------------------------------------------------------------
int OutputDevice::ImplNewFont()
{
DBG_TESTSOLARMUTEX();
if ( !mbNewFont )
return TRUE;
mbNewFont = FALSE;
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return FALSE;
}
SalGraphics* pGraphics = mpGraphics;
#else
// Da wegen Clipping hier NULL zurueckkommen kann, koennen wir nicht
// den Rueckgabewert nehmen
ImplGetServerGraphics();
ImplServerGraphics* pGraphics = mpGraphics;
#endif
// Groesse umrechnen
Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
if ( !aSize.Height() )
{
// Nur dann Defaultgroesse setzen, wenn Fonthoehe auch in logischen
// Koordinaaten 0 ist
if ( maFont.GetSize().Height() )
aSize.Height() = 1;
else
aSize.Height() = (12*mnDPIY)/72;
}
// Neuen Font besorgen
ImplFontEntry* pOldEntry = mpFontEntry;
mpFontEntry = mpFontCache->Get( mpFontList, maFont, aSize );
ImplFontEntry* pFontEntry = mpFontEntry;
// Feststellen, ob Font neu selektiert werden muss
if ( pFontEntry != pOldEntry )
mbInitFont = TRUE;
// these two may be filled in remote version
ImplKernPairData* pKernPairs = NULL;
long nKernPairs = 0;
// Wenn Font nicht initialisiert ist, dann sofort selektieren
if ( !pFontEntry->mbInit )
{
ImplInitFont();
// und die Font-Daten besorgen
if ( pGraphics )
{
pFontEntry->mbInit = TRUE;
pFontEntry->maMetric.mnWidth = pFontEntry->maFontSelData.mnWidth;
pFontEntry->maMetric.meFamily = pFontEntry->maFontSelData.meFamily;
pFontEntry->maMetric.meCharSet = pFontEntry->maFontSelData.meCharSet;
pFontEntry->maMetric.meWeight = pFontEntry->maFontSelData.meWeight;
pFontEntry->maMetric.meItalic = pFontEntry->maFontSelData.meItalic;
pFontEntry->maMetric.mePitch = pFontEntry->maFontSelData.mePitch;
pFontEntry->maMetric.mnOrientation = pFontEntry->maFontSelData.mnOrientation;
if ( pFontEntry->maFontSelData.mpFontData )
{
pFontEntry->maMetric.meType = pFontEntry->maFontSelData.mpFontData->meType;
pFontEntry->maMetric.maName = pFontEntry->maFontSelData.mpFontData->maName;
pFontEntry->maMetric.maStyleName= pFontEntry->maFontSelData.mpFontData->maStyleName;
pFontEntry->maMetric.mbDevice = pFontEntry->maFontSelData.mpFontData->mbDevice;
}
else
{
pFontEntry->maMetric.meType = TYPE_DONTKNOW;
pFontEntry->maMetric.maName = pFontEntry->maFontSelData.maName.GetToken( 0 );
pFontEntry->maMetric.maStyleName= pFontEntry->maFontSelData.maStyleName;
pFontEntry->maMetric.mbDevice = FALSE;
}
pFontEntry->maMetric.mnSuperscriptSize = 0;
pFontEntry->maMetric.mnSuperscriptOffset = 0;
pFontEntry->maMetric.mnSubscriptSize = 0;
pFontEntry->maMetric.mnSubscriptOffset = 0;
pFontEntry->maMetric.mnUnderlineSize = 0;
pFontEntry->maMetric.mnUnderlineOffset = 0;
pFontEntry->maMetric.mnBUnderlineSize = 0;
pFontEntry->maMetric.mnBUnderlineOffset = 0;
pFontEntry->maMetric.mnDUnderlineSize = 0;
pFontEntry->maMetric.mnDUnderlineOffset1 = 0;
pFontEntry->maMetric.mnDUnderlineOffset2 = 0;
pFontEntry->maMetric.mnWUnderlineSize = 0;
pFontEntry->maMetric.mnWUnderlineOffset = 0;
pFontEntry->maMetric.mnStrikeoutSize = 0;
pFontEntry->maMetric.mnStrikeoutOffset = 0;
pFontEntry->maMetric.mnBStrikeoutSize = 0;
pFontEntry->maMetric.mnBStrikeoutOffset = 0;
pFontEntry->maMetric.mnDStrikeoutSize = 0;
pFontEntry->maMetric.mnDStrikeoutOffset1 = 0;
pFontEntry->maMetric.mnDStrikeoutOffset2 = 0;
#ifndef REMOTE_APPSERVER
pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
pFontEntry->mnWidthFactor = pGraphics->GetCharWidth( 0, CHARCACHE_STD-1, pFontEntry->maWidthAry );
#else
long nFactor = 0;
pGraphics->GetFontMetric(
pFontEntry->maMetric,
nFactor, 0, CHARCACHE_STD-1, pFontEntry->maWidthAry,
maFont.IsKerning(), &pKernPairs, nKernPairs
);
pFontEntry->mnWidthFactor = nFactor;
#endif
if ( !pFontEntry->mnWidthFactor )
{
memset( pFontEntry->maWidthAry, 0, sizeof(long)*(CHARCACHE_STD-1) );
pFontEntry->mnWidthFactor = 1;
}
pFontEntry->mbFixedFont = pFontEntry->maMetric.mePitch == PITCH_FIXED;
pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent+pFontEntry->maMetric.mnDescent;
pFontEntry->mbInitKernPairs = FALSE;
pFontEntry->mnKernPairs = nKernPairs;
if ( pFontEntry->maFontSelData.mnOrientation && !pFontEntry->maMetric.mnOrientation &&
(meOutDevType != OUTDEV_PRINTER) )
{
pFontEntry->mnOwnOrientation = pFontEntry->maFontSelData.mnOrientation;
pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
}
else
pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
}
}
// Wenn Kerning gewuenscht ist, die Kerning-Werte ermitteln
if ( maFont.IsKerning() )
{
ImplInitKerningPairs( pKernPairs, nKernPairs );
mbKerning = (pFontEntry->mnKernPairs) != 0;
}
else
mbKerning = FALSE;
2001-02-23 15:13:58 +00:00
// Calculate the EmphasisArea
mnEmphasisAscent = 0;
mnEmphasisDescent = 0;
if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
{
FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
long nEmphasisHeight = (pFontEntry->mnLineHeight*200)/1000;
if ( nEmphasisHeight < 1 )
nEmphasisHeight = 1;
if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
mnEmphasisDescent = nEmphasisHeight;
else
mnEmphasisAscent = nEmphasisHeight;
}
2000-09-18 16:07:07 +00:00
// Je nach TextAlign den TextOffset berechnen
TextAlign eAlign = maFont.GetAlign();
if ( eAlign == ALIGN_BASELINE )
{
mnTextOffX = 0;
mnTextOffY = 0;
}
else if ( eAlign == ALIGN_TOP )
{
if ( pFontEntry->mnOrientation )
2000-09-18 16:07:07 +00:00
{
mnTextOffX = 0;
2001-02-23 15:13:58 +00:00
mnTextOffY = pFontEntry->maMetric.mnAscent+mnEmphasisAscent;
ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
2000-09-18 16:07:07 +00:00
}
else
{
mnTextOffX = 0;
2001-02-23 15:13:58 +00:00
mnTextOffY = pFontEntry->maMetric.mnAscent+mnEmphasisAscent;
2000-09-18 16:07:07 +00:00
}
}
else // eAlign == ALIGN_BOTTOM
{
if ( pFontEntry->mnOrientation )
2000-09-18 16:07:07 +00:00
{
mnTextOffX = 0;
2001-02-23 15:13:58 +00:00
mnTextOffY = -pFontEntry->maMetric.mnDescent+mnEmphasisDescent;
ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
2000-09-18 16:07:07 +00:00
}
else
{
mnTextOffX = 0;
2001-02-23 15:13:58 +00:00
mnTextOffY = -pFontEntry->maMetric.mnDescent+mnEmphasisDescent;
2000-09-18 16:07:07 +00:00
}
}
mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
2001-02-23 15:13:58 +00:00
mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() ||
(maFont.GetRelief() != RELIEF_NONE);
2000-09-18 16:07:07 +00:00
if ( pOldEntry )
mpFontCache->Release( pOldEntry );
return TRUE;
}
// -----------------------------------------------------------------------
long OutputDevice::ImplGetCharWidth( sal_Unicode c ) const
{
USHORT nChar = (USHORT)c;
if ( nChar < CHARCACHE_STD )
return mpFontEntry->maWidthAry[nChar];
ImplFontEntry* pFontEntry = mpFontEntry;
ImplWidthInfoData* pInfo;
ImplWidthInfoData* pWidthAry = pFontEntry->mpWidthAry;
USHORT nWidthCount = pFontEntry->mnWidthAryCount;
USHORT nInsIndex;
if ( nWidthCount )
{
USHORT nLow;
USHORT nHigh;
USHORT nMid;
USHORT nCompareChar;
nLow = 0;
nHigh = nWidthCount-1;
do
{
nMid = (nLow+nHigh)/2;
pInfo = pWidthAry+nMid;
nCompareChar = pInfo->mnChar;
if ( nChar < nCompareChar )
{
if ( !nMid )
break;
nHigh = nMid-1;
}
else
{
if ( nChar > nCompareChar )
nLow = nMid+1;
else
return pInfo->mnWidth;
}
}
while ( nLow <= nHigh );
if ( nChar > nCompareChar )
nInsIndex = nMid+1;
else
nInsIndex = nMid;
}
else
{
pFontEntry->mnWidthArySize = WIDTHARY_INIT;
pFontEntry->mpWidthAry = new ImplWidthInfoData[pFontEntry->mnWidthArySize];
pWidthAry = pFontEntry->mpWidthAry;
nInsIndex = 0;
}
if ( nWidthCount == pFontEntry->mnWidthArySize )
{
USHORT nOldSize = pFontEntry->mnWidthArySize;
pFontEntry->mnWidthArySize += WIDTHARY_RESIZE;
pFontEntry->mpWidthAry = new ImplWidthInfoData[pFontEntry->mnWidthArySize];
memcpy( pFontEntry->mpWidthAry, pWidthAry, nOldSize*sizeof(ImplWidthInfoData) );
delete pWidthAry;
pWidthAry = pFontEntry->mpWidthAry;
}
// Um die Zeichenbreite zu ermitteln, brauchen wir einen Graphics und der
// Font muss natuerlich auch selektiert sein
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !((OutputDevice*)this)->ImplGetGraphics() )
return 0;
}
#else
// Da wegen Clipping hier NULL zurueckkommen kann, koennen wir nicht
// den Rueckgabewert nehmen
((OutputDevice*)this)->ImplGetServerGraphics();
#endif
if ( mbNewFont )
((OutputDevice*)this)->ImplNewFont();
if ( mbInitFont )
((OutputDevice*)this)->ImplInitFont();
long nWidth;
#ifndef REMOTE_APPSERVER
long nWidthFactor = mpGraphics->GetCharWidth( nChar, nChar, &nWidth );
#else
long nWidthFactor = pFontEntry->mnWidthFactor;
mpGraphics->GetCharWidth( nChar, nChar, &nWidth );
#endif
if ( !nWidthFactor )
return 0;
DBG_ASSERT( (nWidthFactor == pFontEntry->mnWidthFactor),
"OutputDevice::ImplGetCharWidth() - other WidthFactor" );
// Breite in Liste einfuegen und zurueckgeben
pInfo = pWidthAry+nInsIndex;
memmove( pInfo+1, pInfo, (nWidthCount-nInsIndex)*sizeof(ImplWidthInfoData) );
pFontEntry->mnWidthAryCount++;
pInfo->mnChar = nChar;
pInfo->mnWidth = nWidth;
return nWidth;
}
// -----------------------------------------------------------------------
void OutputDevice::ImplInitKerningPairs( ImplKernPairData* pKernPairs, long nKernPairs )
{
if ( mbNewFont )
{
if ( !ImplNewFont() )
return;
}
ImplFontEntry* pFontEntry = mpFontEntry;
if ( !pFontEntry->mbInitKernPairs )
{
if ( mbInitFont )
ImplInitFont();
pFontEntry->mbInitKernPairs = TRUE;
#ifndef REMOTE_APPSERVER
pFontEntry->mnKernPairs = mpGraphics->GetKernPairs( 0, NULL );
if ( pFontEntry->mnKernPairs )
{
ImplKernInfoData* pKernInfo = new ImplKernInfoData;
pKernPairs = new ImplKernPairData[pFontEntry->mnKernPairs];
memset( pKernPairs, 0, sizeof(ImplKernPairData)*pFontEntry->mnKernPairs );
pFontEntry->mnKernPairs = mpGraphics->GetKernPairs( pFontEntry->mnKernPairs, pKernPairs );
pFontEntry->mpKernInfo = pKernInfo;
pFontEntry->mpKernPairs = pKernPairs;
// Wir akzeptieren erstmal nur max. 65535-Paare
USHORT nMaxKernPairs;
if ( pFontEntry->mnKernPairs > 0xFFFF )
nMaxKernPairs = 0xFFFF;
else
nMaxKernPairs = (USHORT)pFontEntry->mnKernPairs;
memset( pKernInfo->maFirstAry, 0xFF, sizeof( pKernInfo->maFirstAry ) );
memset( pKernInfo->maLastAry, 0, sizeof( pKernInfo->maLastAry ) );
for ( USHORT i = 0; i < nMaxKernPairs; i++ )
{
USHORT nFirst = pKernPairs[i].mnChar1;
if ( nFirst < 0xFF )
{
if ( i < pKernInfo->maFirstAry[nFirst] )
pKernInfo->maFirstAry[nFirst] = i;
pKernInfo->maLastAry[nFirst] = i;
}
}
}
#else
// Wir arbeiten erstmal nur mit USHORT
if( ! pKernPairs )
nKernPairs = mpGraphics->GetKernPairs( &pKernPairs );
if ( nKernPairs )
{
ImplKernInfoData* pKernInfo = new ImplKernInfoData;
pFontEntry->mpKernInfo = pKernInfo;
pFontEntry->mpKernPairs = pKernPairs;
// Wir akzeptieren erstmal nur max. 65535-Paare
USHORT nMaxKernPairs;
if( ! pFontEntry->mnKernPairs )
pFontEntry->mnKernPairs = nKernPairs;
if ( pFontEntry->mnKernPairs > 0xFFFF )
nMaxKernPairs = 0xFFFF;
else
nMaxKernPairs = (USHORT)pFontEntry->mnKernPairs;
memset( pKernInfo->maFirstAry, 0xFF, sizeof( pKernInfo->maFirstAry ) );
memset( pKernInfo->maLastAry, 0, sizeof( pKernInfo->maLastAry ) );
for ( USHORT i = 0; i < nMaxKernPairs; i++ )
{
USHORT nFirst = pKernPairs[i].mnChar1;
if ( nFirst < 0xFF )
{
if ( i < pKernInfo->maFirstAry[nFirst] )
pKernInfo->maFirstAry[nFirst] = i;
pKernInfo->maLastAry[nFirst] = i;
}
}
}
#endif
}
}
// -----------------------------------------------------------------------
long OutputDevice::ImplCalcKerning( const sal_Unicode* pStr, xub_StrLen nLen,
long* pDXAry, xub_StrLen nAryLen ) const
{
if ( !nLen )
return 0;
ImplFontEntry* pEntry = mpFontEntry;
ImplKernPairData* pKernPairs = pEntry->mpKernPairs;
ImplKernInfoData* pKernInfo = pEntry->mpKernInfo;
long nWidth = 0;
#ifdef DBG_UTIL
{
ImplKernPairData aTestPair;
#ifdef __LITTLEENDIAN
ULONG nTestComp = ((ULONG)((USHORT)0xAABB) << 16) | (USHORT)0xCCDD;
#else
ULONG nTestComp = ((ULONG)((USHORT)0xCCDD) << 16) | (USHORT)0xAABB;
#endif
aTestPair.mnChar1 = 0xCCDD;
aTestPair.mnChar2 = 0xAABB;
DBG_ASSERT( nTestComp == *((ULONG*)&aTestPair), "Code doesn't work in this Version" );
}
#endif
for ( USHORT i = 0; i < nLen-1; i++ )
{
USHORT nIndex = (USHORT)(unsigned char)pStr[i];
USHORT nFirst = pKernInfo->maFirstAry[nIndex];
USHORT nLast = pKernInfo->maLastAry[nIndex];
#ifdef __LITTLEENDIAN
ULONG nComp = ((ULONG)((USHORT)(unsigned char)pStr[i+1]) << 16) | nIndex;
#else
ULONG nComp = ((ULONG)nIndex << 16) | ((USHORT)(unsigned char)pStr[i+1]);
#endif
for ( USHORT j = nFirst; j <= nLast; j++ )
{
if ( nComp == *((ULONG*)&(pKernPairs[j])) )
{
long nAmount = pKernPairs[j].mnKern;
nWidth += nAmount;
if ( pDXAry )
{
for ( USHORT n = i; n < nAryLen; n++ )
pDXAry[n] += nAmount;
}
}
}
}
return nWidth;
}
// -----------------------------------------------------------------------
long OutputDevice::ImplGetTextWidth( const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDX )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nFactor = pFontEntry->mnWidthFactor;
long nWidth = 0;
if ( nLen )
{
if ( pDX )
{
if ( nLen > 1 )
nWidth += pDX[nLen-2];
nWidth += ImplGetCharWidth( pStr[nLen-1] ) / nFactor;
}
else
{
// Bei Fixed-Fonts reicht eine Multiplikation
2000-11-06 19:45:53 +00:00
// Not TRUE for all Fonts, like CJK Fonts
// if ( pFontEntry->mbFixedFont )
// nWidth = ImplGetCharWidth( 'A' ) * nLen;
// else
2000-09-18 16:07:07 +00:00
{
const sal_Unicode* pTempStr = pStr;
xub_StrLen nTempLen = nLen;
while ( nTempLen )
{
nWidth += ImplGetCharWidth( *pTempStr );
nTempLen--;
pTempStr++;
}
}
nWidth /= nFactor;
// Kerning beruecksichtigen
if ( mbKerning )
nWidth += ImplCalcKerning( pStr, nLen, NULL, 0 );
}
}
return nWidth;
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
long nX, long nY, long nWidth, long nHeight )
{
if ( mpFontEntry->mnOrientation )
{
if ( !(mpFontEntry->mnOrientation % 900) )
{
long nX2 = nX+nWidth;
long nY2 = nY+nHeight;
ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
nWidth = nX2-nX;
nHeight = nY2-nY;
}
else
{
// Da Polygone kleiner gezeichnet werden
nHeight++;
nWidth++;
Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
Polygon aPoly( aRect );
aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
#ifndef REMOTE_APPSERVER
ImplDrawPolygon( aPoly );
#else
mpGraphics->DrawPolygon( aPoly );
#endif
return;
}
}
#ifndef REMOTE_APPSERVER
mpGraphics->DrawRect( nX, nY, nWidth, nHeight );
#else
Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
mpGraphics->DrawRect( aRect );
#endif
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawTextBackground( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry )
{
#ifndef REMOTE_APPSERVER
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = TRUE;
}
mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
mbInitFillColor = TRUE;
2001-02-23 15:13:58 +00:00
ImplDrawTextRect( nX, nY, nX, nY-mpFontEntry->maMetric.mnAscent-mnEmphasisAscent,
2000-09-18 16:07:07 +00:00
ImplGetTextWidth( pStr, nLen, pDXAry ),
2001-02-23 15:13:58 +00:00
mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
2000-09-18 16:07:07 +00:00
#else
Color aOldLineColor = GetLineColor();
Color aOldFillColor = GetFillColor();
SetLineColor();
SetFillColor( GetTextFillColor() );
if ( mbInitLineColor )
ImplInitLineColor();
if ( mbInitFillColor )
ImplInitFillColor();
2001-02-23 15:13:58 +00:00
ImplDrawTextRect( nX, nY, nX, nY-mpFontEntry->maMetric.mnAscent-mnEmphasisAscent,
2000-09-18 16:07:07 +00:00
ImplGetTextWidth( pStr, nLen, pDXAry ),
2001-02-23 15:13:58 +00:00
mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
2000-09-18 16:07:07 +00:00
SetLineColor( aOldLineColor );
SetFillColor( aOldFillColor );
#endif
}
// -----------------------------------------------------------------------
Rectangle OutputDevice::ImplGetTextBoundRect( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry )
{
2001-02-23 15:13:58 +00:00
if ( !nLen )
2000-09-18 16:07:07 +00:00
return Rectangle();
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
long nBaseX = nX, nBaseY = nY;
2001-02-23 15:13:58 +00:00
long nWidth = ImplGetTextWidth( pStr, nLen, pDXAry );
long nHeight = mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
nY -= mpFontEntry->maMetric.mnAscent+mnEmphasisAscent;
2000-09-18 16:07:07 +00:00
if ( mpFontEntry->mnOrientation )
{
if ( !(mpFontEntry->mnOrientation % 900) )
{
long nX2 = nX+nWidth;
long nY2 = nY+nHeight;
ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
nWidth = nX2-nX;
nHeight = nY2-nY;
}
else
{
// Da Polygone kleiner gezeichnet werden
nHeight++;
nWidth++;
Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
Polygon aPoly( aRect );
aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
return aPoly.GetBoundRect();
}
}
return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
}
// -----------------------------------------------------------------------
void OutputDevice::ImplInitTextLineSize()
{
ImplFontEntry* pFontEntry = mpFontEntry;
long nLineHeight;
long nLineHeight2;
long nBLineHeight;
long nBLineHeight2;
long n2LineHeight;
long n2LineDY;
long n2LineDY2;
long nUnderlineOffset;
long nStrikeoutOffset;
nLineHeight = ((mpFontEntry->maMetric.mnDescent*25)+50) / 100;
if ( !nLineHeight )
nLineHeight = 1;
nLineHeight2 = nLineHeight / 2;
if ( !nLineHeight2 )
nLineHeight2 = 1;
nBLineHeight = ((mpFontEntry->maMetric.mnDescent*50)+50) / 100;
if ( nBLineHeight == nLineHeight )
nBLineHeight++;
nBLineHeight2 = nBLineHeight/2;
if ( !nBLineHeight2 )
nBLineHeight2 = 1;
n2LineHeight = ((mpFontEntry->maMetric.mnDescent*16)+50) / 100;
if ( !n2LineHeight )
n2LineHeight = 1;
n2LineDY = n2LineHeight;
if ( n2LineDY <= 0 )
n2LineDY = 1;
n2LineDY2 = n2LineDY/2;
if ( !n2LineDY2 )
n2LineDY2 = 1;
2000-11-03 14:10:35 +00:00
BOOL bVertical = maFont.IsVertical();
2000-11-06 19:45:53 +00:00
long nLeading = mpFontEntry->maMetric.mnLeading;
2000-11-03 14:10:35 +00:00
if ( bVertical )
2000-11-06 19:45:53 +00:00
{
if ( !nLeading )
{
if ( mpFontEntry->maMetric.mnDescent )
nLeading = mpFontEntry->maMetric.mnDescent;
else
{
nLeading = mpFontEntry->maMetric.mnAscent*4/5;
if ( !nLeading )
nLeading = 1;
}
}
nUnderlineOffset = -(mpFontEntry->maMetric.mnAscent-nLeading/2);
}
2000-11-03 14:10:35 +00:00
else
nUnderlineOffset = mpFontEntry->maMetric.mnDescent/2 + 1;
2000-11-06 19:45:53 +00:00
nStrikeoutOffset = -((mpFontEntry->maMetric.mnAscent-mpFontEntry->maMetric.mnLeading)/3);
2000-09-18 16:07:07 +00:00
if ( !pFontEntry->maMetric.mnUnderlineSize )
{
pFontEntry->maMetric.mnUnderlineSize = nLineHeight;
pFontEntry->maMetric.mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
2000-11-06 19:45:53 +00:00
if ( bVertical && (nLeading < mpFontEntry->maMetric.mnDescent) )
{
if ( nLineHeight > 1 )
pFontEntry->maMetric.mnUnderlineSize--;
}
2000-09-18 16:07:07 +00:00
}
if ( !pFontEntry->maMetric.mnBUnderlineSize )
{
pFontEntry->maMetric.mnBUnderlineSize = nBLineHeight;
pFontEntry->maMetric.mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
}
if ( !pFontEntry->maMetric.mnDUnderlineSize )
{
pFontEntry->maMetric.mnDUnderlineSize = n2LineHeight;
pFontEntry->maMetric.mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
pFontEntry->maMetric.mnDUnderlineOffset2 = pFontEntry->maMetric.mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
}
if ( !pFontEntry->maMetric.mnWUnderlineSize )
{
2000-11-06 19:45:53 +00:00
long nWCalcSize = mpFontEntry->maMetric.mnDescent;
if ( bVertical )
nWCalcSize = nLeading;
if ( nWCalcSize < 6 )
2000-09-18 16:07:07 +00:00
{
2000-11-06 19:45:53 +00:00
if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
pFontEntry->maMetric.mnWUnderlineSize = nWCalcSize;
2000-09-18 16:07:07 +00:00
else
pFontEntry->maMetric.mnWUnderlineSize = 3;
}
else
2000-11-06 19:45:53 +00:00
pFontEntry->maMetric.mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
2000-09-18 16:07:07 +00:00
pFontEntry->maMetric.mnWUnderlineOffset = nUnderlineOffset;
}
if ( !pFontEntry->maMetric.mnStrikeoutSize )
{
pFontEntry->maMetric.mnStrikeoutSize = nLineHeight;
pFontEntry->maMetric.mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
}
if ( !pFontEntry->maMetric.mnBStrikeoutSize )
{
pFontEntry->maMetric.mnBStrikeoutSize = nBLineHeight;
pFontEntry->maMetric.mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
}
if ( !pFontEntry->maMetric.mnDStrikeoutSize )
{
pFontEntry->maMetric.mnDStrikeoutSize = n2LineHeight;
pFontEntry->maMetric.mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
pFontEntry->maMetric.mnDStrikeoutOffset2 = pFontEntry->maMetric.mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
}
}
// -----------------------------------------------------------------------
static void ImplDrawWavePixel( long nOriginX, long nOriginY,
long nCurX, long nCurY,
short nOrientation,
#ifndef REMOTE_APPSERVER
SalGraphics* pGraphics,
#else
ImplServerGraphics* pGraphics,
#endif
BOOL bDrawPixAsRect,
long nPixWidth, long nPixHeight )
{
if ( nOrientation )
ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
if ( bDrawPixAsRect )
{
#ifndef REMOTE_APPSERVER
pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight );
#else
Point aPos( nCurX, nCurY );
Size aSize( nPixWidth, nPixHeight );
Rectangle aRect( aPos, aSize );
pGraphics->DrawRect( aRect );
#endif
}
else
{
#ifndef REMOTE_APPSERVER
pGraphics->DrawPixel( nCurX, nCurY );
#else
Point aPos( nCurX, nCurY );
pGraphics->DrawPixel( aPos );
#endif
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
long nStartX, long nStartY,
long nWidth, long nHeight,
long nLineWidth, short nOrientation,
const Color& rColor )
{
if ( !nHeight )
return;
// Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
if ( (nLineWidth == 1) && (nHeight == 1) )
{
#ifndef REMOTE_APPSERVER
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = TRUE;
#else
Color aOldLineColor = GetLineColor();
SetLineColor( rColor );
if ( mbInitLineColor )
ImplInitLineColor();
#endif
long nEndX = nStartX+nWidth;
long nEndY = nStartY;
if ( nOrientation )
{
ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
}
#ifndef REMOTE_APPSERVER
mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY );
#else
mpGraphics->DrawLine( Point( nStartX, nStartY ), Point( nEndX, nEndY ) );
#endif
#ifdef REMOTE_APPSERVER
SetLineColor( aOldLineColor );
#endif
}
else
{
long nCurX = nStartX;
long nCurY = nStartY;
long nDiffX = 2;
long nDiffY = nHeight-1;
long nCount = nWidth;
long nOffY = -1;
long nFreq;
long i;
long nPixWidth;
long nPixHeight;
BOOL bDrawPixAsRect;
#ifdef REMOTE_APPSERVER
Color aOldLineColor = GetLineColor();
Color aOldFillColor = GetFillColor();
#endif
// Auf Druckern die Pixel per DrawRect() ausgeben
if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
{
#ifndef REMOTE_APPSERVER
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = TRUE;
}
mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
mbInitFillColor = TRUE;
#else
SetLineColor();
SetFillColor( rColor );
if ( mbInitLineColor )
ImplInitLineColor();
if ( mbInitFillColor )
ImplInitFillColor();
#endif
bDrawPixAsRect = TRUE;
nPixWidth = nLineWidth;
nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
}
else
{
#ifndef REMOTE_APPSERVER
mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
mbInitLineColor = TRUE;
#else
Color aOldLineColor = GetLineColor();
SetLineColor( rColor );
if ( mbInitLineColor )
ImplInitLineColor();
#endif
nPixWidth = 1;
nPixHeight = 1;
bDrawPixAsRect = FALSE;
}
if ( !nDiffY )
{
while ( nWidth )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nWidth--;
}
}
else
{
nCurY += nDiffY;
nFreq = nCount / (nDiffX+nDiffY);
while ( nFreq-- )
{
for( i = nDiffY; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i; --i )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
nOffY = -nOffY;
}
nFreq = nCount % (nDiffX+nDiffY);
if ( nFreq )
{
for( i = nDiffY; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
nCurY += nOffY;
}
for( i = nDiffX; i && nFreq; --i, --nFreq )
{
ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
mpGraphics,
bDrawPixAsRect, nPixWidth, nPixHeight );
nCurX++;
}
}
}
#ifdef REMOTE_APPSERVER
SetLineColor( aOldLineColor );
SetFillColor( aOldFillColor );
#endif
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawTextLine( long nBaseX,
long nX, long nY, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline )
{
if ( !nWidth )
return;
2000-09-18 16:07:07 +00:00
ImplFontEntry* pFontEntry = mpFontEntry;
Color aTextLineColor = GetTextLineColor();
long nBaseY = nY;
long nLineHeight;
long nLinePos;
long nLinePos2;
long nLeft;
BOOL bNormalLines = TRUE;
if ( !IsTextLineColor() )
aTextLineColor = GetTextColor();
if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
(eUnderline == UNDERLINE_WAVE) ||
(eUnderline == UNDERLINE_DOUBLEWAVE) ||
(eUnderline == UNDERLINE_BOLDWAVE) )
{
if ( !pFontEntry->maMetric.mnWUnderlineSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
if ( (eUnderline == UNDERLINE_SMALLWAVE) &&
(nLineHeight > 3) )
nLineHeight = 3;
long nLineWidth = (mnDPIX/300);
if ( !nLineWidth )
nLineWidth = 1;
if ( eUnderline == UNDERLINE_BOLDWAVE )
nLineWidth *= 2;
nLinePos = nY + pFontEntry->maMetric.mnWUnderlineOffset - (nLineHeight / 2);
long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
if ( eUnderline == UNDERLINE_DOUBLEWAVE )
{
long nOrgLineHeight = nLineHeight;
nLineHeight /= 3;
if ( nLineHeight < 2 )
{
if ( nOrgLineHeight > 1 )
nLineHeight = 2;
else
nLineHeight = 1;
}
long nLineDY = nOrgLineHeight-(nLineHeight*2);
if ( nLineDY < nLineWidthHeight )
nLineDY = nLineWidthHeight;
long nLineDY2 = nLineDY/2;
if ( !nLineDY2 )
nLineDY2 = 1;
nLinePos -= nLineWidthHeight-nLineDY2;
ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aTextLineColor );
nLinePos += nLineWidthHeight+nLineDY;
ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aTextLineColor );
}
else
{
nLinePos -= nLineWidthHeight/2;
ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight,
nLineWidth, mpFontEntry->mnOrientation, aTextLineColor );
}
if ( (eStrikeout == STRIKEOUT_NONE) ||
(eStrikeout == STRIKEOUT_DONTKNOW) )
bNormalLines = FALSE;
}
if ( bNormalLines &&
((eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X)) )
{
BOOL bOldMap = IsMapModeEnabled();
EnableMapMode( FALSE );
Color aOldColor = GetTextColor();
SetTextColor( aTextLineColor );
ImplInitTextColor();
xub_Unicode c;
if ( eStrikeout == STRIKEOUT_SLASH )
c = '/';
else /* ( eStrikeout == STRIKEOUT_X ) */
c = 'X';
// Strikeout-String zusammenbauen
XubString aStrikeoutText( c );
aStrikeoutText += aStrikeoutText.GetChar( 0 );
long nStrikeoutWidth = GetTextWidth( aStrikeoutText );
long nChars = nWidth/(nStrikeoutWidth/2);
aStrikeoutText.Fill( (USHORT)(nChars+1), c );
// String solange kuerzen, bis er nicht allzuweit uebersteht
long nMaxWidth = nStrikeoutWidth/4;
if ( nMaxWidth < 2 )
nMaxWidth = 2;
nMaxWidth += nWidth;
long nFullStrikeoutWidth = GetTextWidth( aStrikeoutText );
while ( (nFullStrikeoutWidth > nMaxWidth) && aStrikeoutText.Len() )
{
aStrikeoutText.Erase( aStrikeoutText.Len()-1 );
nFullStrikeoutWidth = GetTextWidth( aStrikeoutText );
}
if ( mpFontEntry->mnOrientation )
ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
ImplDrawTextDirect( nX, nY,
aStrikeoutText.GetBuffer(), aStrikeoutText.Len(),
NULL, FALSE );
SetTextColor( aOldColor );
ImplInitTextColor();
EnableMapMode( bOldMap );
if ( (eUnderline == UNDERLINE_NONE) ||
(eUnderline == UNDERLINE_DONTKNOW) ||
(eUnderline == UNDERLINE_SMALLWAVE) ||
(eUnderline == UNDERLINE_WAVE) ||
(eUnderline == UNDERLINE_DOUBLEWAVE) ||
(eUnderline == UNDERLINE_BOLDWAVE) )
bNormalLines = FALSE;
}
if ( bNormalLines )
{
#ifndef REMOTE_APPSERVER
if ( mbLineColor || mbInitLineColor )
{
mpGraphics->SetLineColor();
mbInitLineColor = TRUE;
}
mpGraphics->SetFillColor( ImplColorToSal( aTextLineColor ) );
mbInitFillColor = TRUE;
#else
Color aOldLineColor = GetLineColor();
Color aOldFillColor = GetFillColor();
SetLineColor();
SetFillColor( aTextLineColor );
if ( mbInitLineColor )
ImplInitLineColor();
if ( mbInitFillColor )
ImplInitFillColor();
#endif
if ( eUnderline > UNDERLINE_LAST )
eUnderline = UNDERLINE_SINGLE;
if ( (eUnderline == UNDERLINE_SINGLE) ||
(eUnderline == UNDERLINE_DOTTED) ||
(eUnderline == UNDERLINE_DASH) ||
(eUnderline == UNDERLINE_LONGDASH) ||
(eUnderline == UNDERLINE_DASHDOT) ||
(eUnderline == UNDERLINE_DASHDOTDOT) )
{
if ( !pFontEntry->maMetric.mnUnderlineSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
}
else if ( (eUnderline == UNDERLINE_BOLD) ||
(eUnderline == UNDERLINE_BOLDDOTTED) ||
(eUnderline == UNDERLINE_BOLDDASH) ||
(eUnderline == UNDERLINE_BOLDLONGDASH) ||
(eUnderline == UNDERLINE_BOLDDASHDOT) ||
(eUnderline == UNDERLINE_BOLDDASHDOTDOT) )
{
if ( !pFontEntry->maMetric.mnBUnderlineSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
}
else if ( eUnderline == UNDERLINE_DOUBLE )
{
if ( !pFontEntry->maMetric.mnDUnderlineSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
}
else
nLineHeight = 0;
if ( nLineHeight )
{
nLeft = nX;
if ( (eUnderline == UNDERLINE_SINGLE) ||
(eUnderline == UNDERLINE_BOLD) )
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
else if ( eUnderline == UNDERLINE_DOUBLE )
{
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
}
else if ( (eUnderline == UNDERLINE_DOTTED) ||
(eUnderline == UNDERLINE_BOLDDOTTED) )
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nTempWidth = nDotWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDotWidth*2;
}
}
else if ( (eUnderline == UNDERLINE_DASH) ||
(eUnderline == UNDERLINE_LONGDASH) ||
(eUnderline == UNDERLINE_BOLDDASH) ||
(eUnderline == UNDERLINE_BOLDLONGDASH) )
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nMinDashWidth;
long nMinSpaceWidth;
long nSpaceWidth;
long nDashWidth;
if ( (eUnderline == UNDERLINE_LONGDASH) ||
(eUnderline == UNDERLINE_BOLDLONGDASH) )
{
nMinDashWidth = nDotWidth*6;
nMinSpaceWidth = nDotWidth*2;
nDashWidth = 200;
nSpaceWidth = 100;
}
else
{
nMinDashWidth = nDotWidth*4;
nMinSpaceWidth = (nDotWidth*150)/100;
nDashWidth = 100;
nSpaceWidth = 50;
}
nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
// DashWidth wird gegebenenfalls verbreitert, wenn
// die dicke der Linie im Verhaeltnis zur Laenge
// zu dick wird
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
if ( nSpaceWidth < nMinSpaceWidth )
nSpaceWidth = nMinSpaceWidth;
long nTempWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempWidth > nEnd )
nTempWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
nLeft += nDashWidth+nSpaceWidth;
}
}
else if ( (eUnderline == UNDERLINE_DASHDOT) ||
(eUnderline == UNDERLINE_BOLDDASHDOT) )
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth wird gegebenenfalls verbreitert, wenn
// die dicke der Linie im Verhaeltnis zur Laenge
// zu dick wird
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
else if ( (eUnderline == UNDERLINE_DASHDOTDOT) ||
(eUnderline == UNDERLINE_BOLDDASHDOTDOT) )
{
long nDotWidth = nLineHeight*mnDPIY;
nDotWidth += mnDPIY/2;
nDotWidth /= mnDPIY;
long nDashWidth = ((100*mnDPIX)+1270)/2540;
long nMinDashWidth = nDotWidth*4;
// DashWidth wird gegebenenfalls verbreitert, wenn
// die dicke der Linie im Verhaeltnis zur Laenge
// zu dick wird
if ( nDashWidth < nMinDashWidth )
nDashWidth = nMinDashWidth;
long nTempDotWidth = nDotWidth;
long nTempDashWidth = nDashWidth;
long nEnd = nLeft+nWidth;
while ( nLeft < nEnd )
{
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDotWidth > nEnd )
nTempDotWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
nLeft += nDotWidth*2;
if ( nLeft > nEnd )
break;
if ( nLeft+nTempDashWidth > nEnd )
nTempDashWidth = nEnd-nLeft;
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
nLeft += nDashWidth+nDotWidth;
}
}
}
if ( eStrikeout > STRIKEOUT_LAST )
eStrikeout = STRIKEOUT_SINGLE;
if ( eStrikeout == STRIKEOUT_SINGLE )
{
if ( !pFontEntry->maMetric.mnStrikeoutSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
}
else if ( eStrikeout == STRIKEOUT_BOLD )
{
if ( !pFontEntry->maMetric.mnBStrikeoutSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
}
else if ( eStrikeout == STRIKEOUT_DOUBLE )
{
if ( !pFontEntry->maMetric.mnDStrikeoutSize )
ImplInitTextLineSize();
nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
}
else
nLineHeight = 0;
if ( nLineHeight )
{
nLeft = nX;
if ( (eStrikeout == STRIKEOUT_SINGLE) ||
(eStrikeout == STRIKEOUT_BOLD) )
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
else if ( eStrikeout == STRIKEOUT_DOUBLE )
{
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
}
}
#ifdef REMOTE_APPSERVER
SetLineColor( aOldLineColor );
SetFillColor( aOldFillColor );
#endif
}
}
// -----------------------------------------------------------------------
static BOOL ImplIsLineCharacter( sal_Unicode c )
{
// !(Control+Space, C1-Control+HardSpace, General Space Punctuation)
if ( ((c > 0x0020) && (c < 0x0080)) ||
((c > 0x00A0) && (c < 0x2000)) ||
2001-02-23 15:13:58 +00:00
(c > 0x200F) )
return TRUE;
return FALSE;
}
// -----------------------------------------------------------------------
2000-09-18 16:07:07 +00:00
void OutputDevice::ImplDrawTextLines( long nX, long nY,
const sal_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry,
FontStrikeout eStrikeout,
FontUnderline eUnderline,
BOOL bWordLine )
{
if ( bWordLine )
{
BOOL bLine = FALSE;
xub_StrLen nLineStart = 0;
xub_StrLen nLineEnd = 0;
while ( nLineEnd < nLen )
{
BOOL bCurLine = ImplIsLineCharacter( *(pStr+nLineEnd) );
2000-09-18 16:07:07 +00:00
// draw a new line?
if ( bLine && !bCurLine )
{
// Query Size to text start and draw the Line to text end
long nStartX = ImplGetTextWidth( pStr, nLineStart, pDXAry );
long nEndX = ImplGetTextWidth( pStr, nLineEnd, pDXAry );
ImplDrawTextLine( nX, nX+nStartX, nY, nEndX-nStartX, eStrikeout, eUnderline );
}
if ( bLine != bCurLine )
{
bLine = bCurLine;
nLineStart = nLineEnd;
}
nLineEnd++;
}
if ( bLine && nLen )
2000-09-18 16:07:07 +00:00
{
// Query Size to text start and draw the Line to text end
long nStartX = ImplGetTextWidth( pStr, nLineStart, pDXAry );
long nEndX = ImplGetTextWidth( pStr, nLineEnd, pDXAry );
ImplDrawTextLine( nX, nX+nStartX, nY, nEndX-nStartX, eStrikeout, eUnderline );
2000-09-18 16:07:07 +00:00
}
}
else
ImplDrawTextLine( nX, nX, nY, ImplGetTextWidth( pStr, nLen, pDXAry ), eStrikeout, eUnderline );
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, xub_Unicode c )
{
ImplDrawTextLine( nX, nX, nY, ImplGetTextWidth( &c, 1, NULL ), STRIKEOUT_NONE, UNDERLINE_SINGLE );
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
2001-02-23 15:13:58 +00:00
void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, BOOL& rPolyLine,
Rectangle& rRect1, Rectangle& rRect2,
long& rYOff, long& rWidth,
FontEmphasisMark eEmphasis,
long nHeight, short nOrient )
{
static const BYTE aAccentPolyFlags[24] =
{
0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
};
static const long aAccentPos[48] =
{
78, 0,
348, 79,
599, 235,
843, 469,
938, 574,
990, 669,
990, 773,
990, 843,
964, 895,
921, 947,
886, 982,
860, 999,
825, 999,
764, 999,
721, 964,
686, 895,
625, 791,
556, 660,
469, 504,
400, 400,
261, 252,
61, 61,
0, 27,
9, 0
};
rWidth = 0;
rYOff = 0;
rPolyLine = FALSE;
if ( !nHeight )
return;
FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
long nDotSize = 0;
switch ( nEmphasisStyle )
{
case EMPHASISMARK_DOT:
// Dot has 50% of the height
nDotSize = (nHeight*500)/1000;
if ( !nDotSize )
nDotSize = 1;
if ( nDotSize <= 2 )
rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
else
{
long nRad = nDotSize/2;
Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
rPolyPoly.Insert( aPoly );
}
rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
rWidth = nDotSize;
break;
case EMPHASISMARK_CIRCLE:
// Dot has 75% of the height
nDotSize = (nHeight*750)/1000;
if ( !nDotSize )
nDotSize = 1;
if ( nDotSize <= 2 )
rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
else
{
long nRad = nDotSize/2;
Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
rPolyPoly.Insert( aPoly );
// BorderWidth is 15%
long nBorder = (nDotSize*150)/1000;
if ( nBorder <= 1 )
rPolyLine = TRUE;
else
{
Polygon aPoly2( Point( nRad, nRad ),
nRad-nBorder, nRad-nBorder );
rPolyPoly.Insert( aPoly2 );
}
}
rWidth = nDotSize;
break;
case EMPHASISMARK_DISC:
// Dot has 75% of the height
nDotSize = (nHeight*750)/1000;
if ( !nDotSize )
nDotSize = 1;
if ( nDotSize <= 2 )
rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
else
{
long nRad = nDotSize/2;
Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
rPolyPoly.Insert( aPoly );
}
rWidth = nDotSize;
break;
case EMPHASISMARK_ACCENT:
// Dot has 75% of the height
nDotSize = (nHeight*750)/1000;
if ( !nDotSize )
nDotSize = 1;
if ( nDotSize <= 2 )
{
if ( nDotSize == 1 )
{
rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
rWidth = nDotSize;
}
else
{
rRect1 = Rectangle( Point(), Size( 1, 1 ) );
rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
}
}
else
{
Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
(const Point*)aAccentPos,
NULL ); // aAccentPolyFlags );
double dScale = ((double)nDotSize)/1000.0;
aPoly.Scale( dScale, dScale );
Rectangle aBoundRect = aPoly.GetBoundRect();
rWidth = aBoundRect.GetWidth();
nDotSize = aBoundRect.GetHeight();
if ( nOrient )
aPoly.Rotate( Point( 0, 0 ), nOrient );
rPolyPoly.Insert( aPoly );
}
break;
}
// Calculate Position
long nOffY = 1+(mnDPIY/300); // One visible pixel space
long nSpaceY = nHeight-nDotSize;
if ( nSpaceY >= nOffY*2 )
rYOff += nOffY;
if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
rYOff += nDotSize;
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawEmphasisMark( long nX, long nY,
const PolyPolygon& rPolyPoly, BOOL bPolyLine,
const Rectangle& rRect1, const Rectangle& rRect2 )
{
if ( rPolyPoly.Count() )
{
if ( bPolyLine )
{
Polygon aPoly = rPolyPoly.GetObject( 0 );
aPoly.Move( nX, nY );
DrawPolyLine( aPoly );
}
else
{
PolyPolygon aPolyPoly = rPolyPoly;
aPolyPoly.Move( nX, nY );
DrawPolyPolygon( aPolyPoly );
}
}
if ( !rRect1.IsEmpty() )
{
Rectangle aRect( Point( nX+rRect1.Left(),
nY+rRect1.Top() ), rRect1.GetSize() );
DrawRect( aRect );
}
if ( !rRect2.IsEmpty() )
{
Rectangle aRect( Point( nX+rRect2.Left(),
nY+rRect2.Top() ), rRect2.GetSize() );
DrawRect( aRect );
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawEmphasisMarks( long nX, long nY,
const sal_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry )
{
Color aOldColor = GetTextColor();
Color aOldLineColor = GetLineColor();
Color aOldFillColor = GetFillColor();
BOOL bOldMap = mbMap;
GDIMetaFile* pOldMetaFile = mpMetaFile;
mpMetaFile = NULL;
mbMap = FALSE;
FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
PolyPolygon aPolyPoly;
Rectangle aRect1;
Rectangle aRect2;
long nEmphasisYOff;
long nEmphasisWidth;
long nEmphasisHeight;
BOOL bPolyLine;
if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
nEmphasisHeight = mnEmphasisDescent;
else
nEmphasisHeight = mnEmphasisAscent;
ImplGetEmphasisMark( aPolyPoly, bPolyLine,
aRect1, aRect2,
nEmphasisYOff, nEmphasisWidth,
nEmphasisMark,
nEmphasisHeight, mpFontEntry->mnOrientation );
if ( bPolyLine )
{
SetLineColor( GetTextColor() );
SetFillColor();
}
else
{
SetLineColor();
SetFillColor( GetTextColor() );
}
long nOffX = nX - mnOutOffX;
long nOffY = nY - mnOutOffY;
long nBaseX = nOffX;
long nBaseY = nOffY;
xub_StrLen i = 0;
if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
nOffY += mpFontEntry->maMetric.mnDescent+nEmphasisYOff;
else
nOffY -= mpFontEntry->maMetric.mnAscent+nEmphasisYOff;
while ( i < nLen )
{
if ( ImplIsLineCharacter( *(pStr+i) ) )
{
long nStartX = ImplGetTextWidth( pStr, i, pDXAry );
long nEndX = ImplGetTextWidth( pStr, i+1, pDXAry );
long nOutX = nOffX + nStartX + ((nEndX-nStartX-nEmphasisWidth)/2);
long nOutY = nOffY;
if ( mpFontEntry->mnOrientation )
ImplRotatePos( nBaseX, nBaseY, nOutX, nOutY, mpFontEntry->mnOrientation );
ImplDrawEmphasisMark( nOutX, nOutY,
aPolyPoly, bPolyLine,
aRect1, aRect2 );
}
i++;
}
SetLineColor( aOldLineColor );
SetFillColor( aOldFillColor );
mbMap = bOldMap;
mpMetaFile = pOldMetaFile;
}
// -----------------------------------------------------------------------
2000-09-18 16:07:07 +00:00
BOOL OutputDevice::ImplDrawRotateText( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry )
{
if ( !mpOutDevData )
ImplInitOutDevData();
if ( !mpOutDevData->mpRotateDev )
mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
2001-02-23 15:13:58 +00:00
2000-09-18 16:07:07 +00:00
VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
long nWidth = ImplGetTextWidth( pStr, nLen, pDXAry );
2001-02-23 15:13:58 +00:00
long nHeight = mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
2000-09-18 16:07:07 +00:00
Size aSize( nWidth, nHeight );
if ( pVDev->SetOutputSizePixel( aSize ) )
{
Font aFont( GetFont() );
Bitmap aBmp;
long nOff;
nX -= mnTextOffX;
nY -= mnTextOffY;
if ( GetTextAlign() == ALIGN_TOP )
{
nOff = 0L;
nY += mpFontEntry->maMetric.mnAscent;
}
else if ( GetTextAlign() == ALIGN_BOTTOM )
{
nOff = mpFontEntry->maMetric.mnAscent;
nY += -mpFontEntry->maMetric.mnDescent;
}
else
nOff = mpFontEntry->maMetric.mnAscent;
aFont.SetShadow( FALSE );
aFont.SetOutline( FALSE );
2001-02-23 15:13:58 +00:00
aFont.SetRelief( RELIEF_NONE );
2000-09-18 16:07:07 +00:00
aFont.SetOrientation( 0 );
aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
pVDev->SetFont( aFont );
// Da Farben und Alignment noch im Font haengen, muessen diese jedesmal
// gesetzt werden
pVDev->SetTextAlign( ALIGN_TOP );
pVDev->SetTextColor( Color( COL_BLACK ) );
pVDev->SetTextFillColor();
pVDev->ImplNewFont();
pVDev->ImplInitFont();
pVDev->ImplInitTextColor();
pVDev->ImplDrawText( 0, 0, pStr, nLen, pDXAry );
aBmp = pVDev->GetBitmap( Point(), aSize );
if ( !!aBmp && aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
{
Point aTempPoint;
Polygon aPoly( Rectangle( aTempPoint, aSize ) );
long nOldOffX = mnOutOffX;
long nOldOffY = mnOutOffY;
GDIMetaFile* pOldMetaFile = mpMetaFile;
BOOL bOldMap = mbMap;
2000-09-18 16:07:07 +00:00
aTempPoint.Y() = nOff;
aPoly.Rotate( aTempPoint, mpFontEntry->mnOwnOrientation );
const Rectangle aBound( aPoly.GetBoundRect() );
mnOutOffX = 0L;
mnOutOffY = 0L;
mpMetaFile = NULL;
2000-09-18 16:07:07 +00:00
mbMap = FALSE;
DrawMask( Point( nX + aBound.Left(),
2001-02-23 15:13:58 +00:00
nY + aBound.Top() - (mpFontEntry->maMetric.mnAscent+mnEmphasisAscent) ),
2000-09-18 16:07:07 +00:00
aBmp, GetTextColor() );
mnOutOffX = nOldOffX;
mnOutOffY = nOldOffY;
mbMap = bOldMap;
mpMetaFile = pOldMetaFile;
2000-09-18 16:07:07 +00:00
}
return TRUE;
}
return FALSE;
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawTextDirect( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry,
BOOL bTextLines )
{
BOOL bDraw = FALSE;
ImplFontEntry* pFontEntry = mpFontEntry;
if ( pFontEntry->mnOwnOrientation )
bDraw = ImplDrawRotateText( nX, nY, pStr, nLen, pDXAry );
if ( !bDraw )
{
if ( !pDXAry )
{
#ifndef REMOTE_APPSERVER
if ( pFontEntry->mnSetFontFlags & SAL_SETFONT_USEDRAWTEXTARRAY )
{
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
long nOffset = 0;
long aStackAry[128];
long* pTempDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) );
for ( USHORT i = 0; i < nLen-1; i++ )
{
nOffset += ImplGetCharWidth( pStr[i] );
pTempDXAry[i] = nOffset / nFactor;
}
mpGraphics->DrawTextArray( nX, nY, pStr, nLen, pTempDXAry );
ImplReleaseStackBuffer( pTempDXAry, aStackAry );
}
else
#endif
mpGraphics->DrawText( nX, nY, pStr, nLen );
}
else
{
#ifndef REMOTE_APPSERVER
if ( pFontEntry->mnSetFontFlags & SAL_SETFONT_USEDRAWTEXT )
{
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
long nOffset = 0;
long nDiff;
long nTempX = nX;
const sal_Unicode* pTempStr = pStr;
xub_StrLen nCombineChars = 1;
for ( xub_StrLen i = 0; i < nLen-1; i++ )
{
nOffset += ImplGetCharWidth( pStr[i] );
nDiff = (nOffset/nFactor) - pDXAry[i];
if ( (nDiff < -1) || (nDiff > 0) )
{
mpGraphics->DrawText( nTempX, nY, pTempStr, nCombineChars );
nTempX = nX+pDXAry[i];
nOffset = pDXAry[i]*nFactor;
pTempStr += nCombineChars;
nCombineChars = 1;
}
else
nCombineChars++;
}
mpGraphics->DrawText( nTempX, nY, pTempStr, nCombineChars );
}
else
#endif
mpGraphics->DrawTextArray( nX, nY, pStr, nLen, pDXAry );
}
if ( bTextLines )
{
ImplDrawTextLines( nX, nY, pStr, nLen, pDXAry,
maFont.GetStrikeout(),
maFont.GetUnderline(),
maFont.IsWordLineMode() );
}
2001-02-23 15:13:58 +00:00
// EmphasisMark
if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
{
ImplDrawEmphasisMarks( nX, nY, pStr, nLen, pDXAry );
}
2000-09-18 16:07:07 +00:00
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawSpecialText( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen,
const long* pDXAry )
{
2001-02-23 15:13:58 +00:00
Color aOldColor = GetTextColor();
Color aOldTextLineColor = GetTextLineColor();
FontRelief eRelief = maFont.GetRelief();
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
if ( eRelief != RELIEF_NONE )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
Color aReliefColor( COL_LIGHTGRAY );
Color aTextColor( aOldColor );
Color aTextLineColor( aOldTextLineColor );
// We don't have a automatic Color, so Black is always drawn
// in White
if ( aTextColor.GetColor() == COL_BLACK )
aTextColor = Color( COL_WHITE );
if ( aTextLineColor.GetColor() == COL_BLACK )
aTextLineColor = Color( COL_WHITE );
// Relief-Color is Black for White Text, in all other cases
// we set this to LightGray
if ( aTextColor.GetColor() == COL_WHITE )
aReliefColor = Color( COL_BLACK );
SetTextLineColor( aReliefColor );
SetTextColor( aReliefColor );
2000-09-18 16:07:07 +00:00
ImplInitTextColor();
2001-02-23 15:13:58 +00:00
// Calculate Offset - for High resolution printers the offset
// should be greater so that the effect is visible
long nOff = 1;
nOff += mnDPIX/300;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
if ( eRelief == RELIEF_ENGRAVED )
nOff = -nOff;
ImplDrawTextDirect( nX+nOff, nY+nOff, pStr, nLen, pDXAry, mbTextLines );
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
SetTextLineColor( aTextLineColor );
SetTextColor( aTextColor );
2000-09-18 16:07:07 +00:00
ImplInitTextColor();
ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines );
2001-02-23 15:13:58 +00:00
2000-09-18 16:07:07 +00:00
SetTextLineColor( aOldTextLineColor );
2001-02-23 15:13:58 +00:00
if ( aTextColor != aOldColor )
{
SetTextColor( aOldColor );
ImplInitTextColor();
}
}
else
{
if ( maFont.IsShadow() )
{
long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
if ( maFont.IsOutline() )
nOff++;
SetTextLineColor();
if ( GetTextColor().GetColor() == COL_BLACK )
SetTextColor( Color( COL_LIGHTGRAY ) );
else
SetTextColor( Color( COL_BLACK ) );
ImplInitTextColor();
ImplDrawTextDirect( nX+nOff, nY+nOff, pStr, nLen, pDXAry, mbTextLines );
SetTextColor( aOldColor );
SetTextLineColor( aOldTextLineColor );
ImplInitTextColor();
if ( !maFont.IsOutline() )
ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines );
}
if ( maFont.IsOutline() )
{
ImplDrawTextDirect( nX-1, nY+1, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX, nY+1, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX+1, nY+1, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX-1, nY, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX+1, nY, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX-1, nY-1, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX, nY-1, pStr, nLen, pDXAry, mbTextLines );
ImplDrawTextDirect( nX+1, nY-1, pStr, nLen, pDXAry, mbTextLines );
SetTextColor( Color( COL_WHITE ) );
SetTextLineColor( Color( COL_WHITE ) );
ImplInitTextColor();
ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines );
SetTextColor( aOldColor );
SetTextLineColor( aOldTextLineColor );
ImplInitTextColor();
}
2000-09-18 16:07:07 +00:00
}
}
// -----------------------------------------------------------------------
void OutputDevice::ImplDrawText( long nX, long nY,
const xub_Unicode* pStr, xub_StrLen nLen, const long* pDXAry )
{
nX += mnTextOffX;
nY += mnTextOffY;
if ( IsTextFillColor() )
ImplDrawTextBackground( nX, nY, pStr, nLen, pDXAry );
if ( mbTextSpecial )
ImplDrawSpecialText( nX, nY, pStr, nLen, pDXAry );
else
ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines );
}
// -----------------------------------------------------------------------
void OutputDevice::ImplFillDXAry( long* pDXAry,
const xub_Unicode* pStr, xub_StrLen nLen, long nWidth )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
// Breiten-Array fuer errechnete Werte mit den Breiten der einzelnen
// Character fuellen
xub_StrLen i;
long nSum = 0;
for ( i = 0; i < nLen; i++ )
{
// Characterbreiten ueber Array holen
nSum += ImplGetCharWidth( pStr[i] );
pDXAry[i] = nSum / nFactor;
}
nSum /= nFactor;
// Differenz zwischen Soll- und Ist-Laenge errechnen
// Zusaetzliche Pixel per Character errechnen
// Anzahl der zusaetzlich verbliebenen Pixel errechnen
long nDelta = (long)nWidth - nSum;
long nDeltaPerChar = 0;
long nDeltaRest = 0;
if ( nLen > 1 )
{
nDeltaPerChar = nDelta / (long)(nLen-1);
nDeltaRest = nDelta % (long)(nLen-1);
}
long nDeltaRestAbs = Abs( nDeltaRest );
long nErrorSum = nDeltaRestAbs;
long nDeltaSum = 0;
for ( i = 0; i < nLen-1; i++, nErrorSum += nDeltaRestAbs )
{
nDeltaSum += nDeltaPerChar;
if ( nErrorSum >= nLen-1 )
{
nErrorSum -= nLen-1;
if ( nDeltaRest > 0 )
nDeltaSum++;
else if ( nDeltaRest < 0 )
nDeltaSum--;
}
pDXAry[i] += nDeltaSum;
}
}
// -----------------------------------------------------------------------
long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
long nWidth, const XubString& rStr,
USHORT nStyle ) const
{
DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
if ( nWidth <= 0 )
nWidth = 1;
2000-09-18 16:07:07 +00:00
long nMaxLineWidth = 0;
rLineInfo.Clear();
if ( rStr.Len() && (nWidth > 0) )
2000-09-18 16:07:07 +00:00
{
::rtl::OUString aText( rStr );
uno::Reference < i18n::XBreakIterator > xBI;
2000-11-06 19:48:36 +00:00
uno::Reference< linguistic2::XHyphenator > xHyph;
i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, 1 );
i18n::LineBreakUserOptions aUserOptions;
2000-09-18 16:07:07 +00:00
xub_StrLen nPos = 0;
xub_StrLen nLen = rStr.Len();
2000-09-18 16:07:07 +00:00
while ( nPos < nLen )
{
xub_StrLen nBreakPos = nPos;
while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
nBreakPos++;
long nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
{
if ( !xBI.is() )
xBI = vcl::unohelper::CreateBreakIterator();
xub_StrLen nSoftBreak = GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, GetSettings().GetLocale(), nPos, aHyphOptions, aUserOptions );
nBreakPos = (xub_StrLen)aLBR.breakIndex;
2000-09-18 16:07:07 +00:00
if ( nBreakPos <= nPos )
nBreakPos = nSoftBreak;
nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos );
}
if ( nLineWidth > nMaxLineWidth )
nMaxLineWidth = nLineWidth;
rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
if ( nBreakPos == nPos )
nBreakPos++;
2000-09-18 16:07:07 +00:00
nPos = nBreakPos;
if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
{
nPos++;
// CR/LF?
if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
nPos++;
}
2000-09-18 16:07:07 +00:00
}
}
return nMaxLineWidth;
}
// =======================================================================
2001-02-23 15:13:58 +00:00
void OutputDevice::SetAntialiasing( USHORT nMode )
{
mnAntialiasing = nMode;
}
// -----------------------------------------------------------------------
2000-09-18 16:07:07 +00:00
void OutputDevice::SetFont( const Font& rNewFont )
{
DBG_TRACE( "OutputDevice::SetFont()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
DBG_CHKOBJ( &rNewFont, Font, NULL );
Font aFont( rNewFont );
if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
DRAWMODE_GHOSTEDFILL) )
{
Color aTextColor( aFont.GetColor() );
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aTextColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aTextColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const UINT8 cLum = aTextColor.GetLuminance();
aTextColor = Color( cLum, cLum, cLum );
}
if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
{
aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
(aTextColor.GetGreen() >> 1 ) | 0x80,
(aTextColor.GetBlue() >> 1 ) | 0x80 );
}
aFont.SetColor( aTextColor );
BOOL bTransFill = aFont.IsTransparent();
if ( !bTransFill )
{
Color aTextFillColor( aFont.GetFillColor() );
if ( mnDrawMode & DRAWMODE_BLACKFILL )
aTextFillColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITEFILL )
aTextFillColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYFILL )
{
const UINT8 cLum = aTextFillColor.GetLuminance();
aTextFillColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_NOFILL )
{
aTextFillColor = Color( COL_TRANSPARENT );
bTransFill = TRUE;
}
if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
{
aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
(aTextFillColor.GetGreen() >> 1) | 0x80,
(aTextFillColor.GetBlue() >> 1) | 0x80 );
}
aFont.SetFillColor( aTextFillColor );
}
}
if ( mpMetaFile )
{
const Color& rTextFillColor = aFont.GetFillColor();
mpMetaFile->AddAction( new MetaFontAction( aFont ) );
mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
}
if ( !maFont.IsSameInstance( aFont ) )
{
if ( maFont.GetColor() != aFont.GetColor() )
mbInitTextColor = TRUE;
maFont = aFont;
mbNewFont = TRUE;
}
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextColor( const Color& rColor )
{
DBG_TRACE( "OutputDevice::SetTextColor()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const UINT8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
if ( maFont.GetColor() != aColor )
{
maFont.SetColor( aColor );
mbInitTextColor = TRUE;
}
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextFillColor()
{
DBG_TRACE( "OutputDevice::SetTextFillColor()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), FALSE ) );
if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
maFont.SetFillColor( Color( COL_TRANSPARENT ) );
if ( !maFont.IsTransparent() )
maFont.SetTransparent( TRUE );
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextFillColor( const Color& rColor )
{
DBG_TRACE( "OutputDevice::SetTextFillColor()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
Color aColor( rColor );
BOOL bTransFill = ImplIsColorTransparent( aColor );
if ( !bTransFill )
{
if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
DRAWMODE_GHOSTEDFILL ) )
{
if ( mnDrawMode & DRAWMODE_BLACKFILL )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITEFILL )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYFILL )
{
const UINT8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
else if ( mnDrawMode & DRAWMODE_NOFILL )
{
aColor = Color( COL_TRANSPARENT );
bTransFill = TRUE;
}
if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, TRUE ) );
if ( maFont.GetFillColor() != aColor )
maFont.SetFillColor( aColor );
if ( maFont.IsTransparent() != bTransFill )
maFont.SetTransparent( bTransFill );
}
// -----------------------------------------------------------------------
Color OutputDevice::GetTextFillColor() const
{
if ( maFont.IsTransparent() )
return Color( COL_TRANSPARENT );
else
return maFont.GetFillColor();
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextLineColor()
{
DBG_TRACE( "OutputDevice::SetTextLineColor()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), FALSE ) );
maTextLineColor = Color( COL_TRANSPARENT );
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextLineColor( const Color& rColor )
{
DBG_TRACE( "OutputDevice::SetTextLineColor()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
Color aColor( rColor );
if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT ) )
{
if ( mnDrawMode & DRAWMODE_BLACKTEXT )
aColor = Color( COL_BLACK );
else if ( mnDrawMode & DRAWMODE_WHITETEXT )
aColor = Color( COL_WHITE );
else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
{
const UINT8 cLum = aColor.GetLuminance();
aColor = Color( cLum, cLum, cLum );
}
if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
{
aColor = Color( (aColor.GetRed() >> 1) | 0x80,
(aColor.GetGreen() >> 1) | 0x80,
(aColor.GetBlue() >> 1) | 0x80 );
}
}
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, TRUE ) );
maTextLineColor = aColor;
}
// -----------------------------------------------------------------------
void OutputDevice::SetTextAlign( TextAlign eAlign )
{
DBG_TRACE( "OutputDevice::SetTextAlign()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
if ( maFont.GetAlign() != eAlign )
{
maFont.SetAlign( eAlign );
mbNewFont = TRUE;
}
}
// -----------------------------------------------------------------------
void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
FontStrikeout eStrikeout,
FontUnderline eUnderline )
{
DBG_TRACE( "OutputDevice::DrawTextLine()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline ) );
if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
return;
if ( !IsDeviceOutputNecessary() )
return;
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
if ( mbNewFont )
{
if ( !ImplNewFont() )
return;
}
Point aPos = ImplLogicToDevicePixel( rPos );
nWidth = ImplLogicWidthToDevicePixel( nWidth );
aPos.X() += mnTextOffX;
aPos.Y() += mnTextOffY;
ImplDrawTextLine( aPos.X(), aPos.X(), aPos.Y(), nWidth, eStrikeout, eUnderline );
}
// ------------------------------------------------------------------------
void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
USHORT nStyle )
{
DBG_TRACE( "OutputDevice::DrawWaveLine()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
#ifndef REMOTE_APPSERVER
if ( !IsDeviceOutputNecessary() )
return;
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
Point aStartPt = ImplLogicToDevicePixel( rStartPos );
Point aEndPt = ImplLogicToDevicePixel( rEndPos );
long nStartX = aStartPt.X();
long nStartY = aStartPt.Y();
long nEndX = aEndPt.X();
long nEndY = aEndPt.Y();
short nOrientation = 0;
if ( (nStartY != nEndY) || (nStartX > nEndX) )
{
long nDX = nEndX - nStartX;
double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
nO /= F_PI1800;
nOrientation = (short)nO;
ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
}
long nWaveHeight;
if ( nStyle == WAVE_NORMAL )
{
nWaveHeight = 3;
nStartY++;
nEndY++;
}
else if( nStyle == WAVE_SMALL )
{
nWaveHeight = 2;
nStartY++;
nEndY++;
}
else // WAVE_FLAT
nWaveHeight = 1;
ImplDrawWaveLine( nStartX, nStartY, nStartX, nStartY,
nEndX-nStartX, nWaveHeight, 1,
nOrientation, GetLineColor() );
#else
ImplServerGraphics* pGraphics = ImplGetServerGraphics();
if ( pGraphics )
{
if ( mbInitLineColor )
ImplInitLineColor();
Point aPos1 = ImplLogicToDevicePixel( rStartPos );
Point aPos2 = ImplLogicToDevicePixel( rEndPos );
pGraphics->DrawWaveLine( aPos1, aPos2, nStyle );
}
#endif
}
// -----------------------------------------------------------------------
void OutputDevice::DrawText( const Point& rStartPt, const XubString& rStr,
xub_StrLen nIndex, xub_StrLen nLen )
{
DBG_TRACE( "OutputDevice::DrawText()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
if ( !IsDeviceOutputNecessary() )
return;
// String-Laenge fuer die Ermittlung der Groesse setzen
if ( (ULONG)nLen+nIndex > rStr.Len() )
{
if ( nIndex < rStr.Len() )
nLen = rStr.Len()-nIndex;
else
nLen = 0;
}
// Ist die Ausgabe leer, dann mache nichts
if ( !nLen )
return;
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
if ( mbInitTextColor )
ImplInitTextColor();
Point aStartPt = ImplLogicToDevicePixel( rStartPt );
// Pointer auf den String-Buffer setzen und um den Index korrigieren
const sal_Unicode* pStr = rStr.GetBuffer();
pStr += nIndex;
if ( mbKerning )
{
ImplFontEntry* pFontEntry = mpFontEntry;
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
USHORT i;
// DX-Array berechnen
long nOffset = 0;
long aStackAry[128];
long* pDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) );
for ( i = 0; i < nLen-1; i++ )
{
nOffset += pCharWidthAry[(unsigned char)pStr[i]];
pDXAry[i] = nOffset / nFactor;
}
ImplCalcKerning( pStr, nLen, pDXAry, nLen-1 );
ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry );
ImplReleaseStackBuffer( pDXAry, aStackAry );
}
else
ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, NULL );
}
// -----------------------------------------------------------------------
long OutputDevice::GetTextWidth( const XubString& rStr,
xub_StrLen nIndex, xub_StrLen nLen ) const
{
DBG_TRACE( "OutputDevice::GetTextWidth()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return 0;
}
ImplFontEntry* pFontEntry = mpFontEntry;
long nWidth = 0;
if ( nIndex < rStr.Len() )
{
// String-Laenge fuer die Ermittlung der Groesse setzen
if ( (ULONG)nLen+nIndex > rStr.Len() )
nLen = rStr.Len()-nIndex;
if ( nLen )
{
long* pCharWidthAry = pFontEntry->maWidthAry;
// Bei Fixed-Fonts reicht eine Multiplikation
2000-11-06 19:45:53 +00:00
// Not TRUE for all Fonts, like CJK Fonts
// if ( pFontEntry->mbFixedFont )
// {
// nWidth = pCharWidthAry['A'] * nLen;
// nWidth /= pFontEntry->mnWidthFactor;
// }
// else
2000-09-18 16:07:07 +00:00
{
const sal_Unicode* pStr = rStr.GetBuffer();
const sal_Unicode* pTempStr;
USHORT nTempLen;
pStr += nIndex;
pTempStr = pStr;
nTempLen = nLen;
while ( nTempLen )
{
nWidth += ImplGetCharWidth( *pTempStr );
nTempLen--;
pTempStr++;
}
nWidth /= pFontEntry->mnWidthFactor;
// Kerning beruecksichtigen (tun wir nur bei Fonts ohne feste Breite)
if ( mbKerning )
nWidth += ImplCalcKerning( pStr, nLen, NULL, 0 );
}
}
}
if ( mbMap )
nWidth = ImplDevicePixelToLogicWidth( nWidth );
return nWidth;
}
// -----------------------------------------------------------------------
long OutputDevice::GetTextHeight() const
{
DBG_TRACE( "OutputDevice::GetTextHeight()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return 0;
}
2001-02-23 15:13:58 +00:00
long nHeight = mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
2000-09-18 16:07:07 +00:00
if ( mbMap )
nHeight = ImplDevicePixelToLogicHeight( nHeight );
return nHeight;
}
// -----------------------------------------------------------------------
void OutputDevice::DrawTextArray( const Point& rStartPt, const XubString& rStr,
const long* pDXAry,
xub_StrLen nIndex, xub_StrLen nLen )
{
DBG_TRACE( "OutputDevice::DrawTextArray()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
if ( !IsDeviceOutputNecessary() )
return;
// String-Laenge fuer die Ermittlung der Groesse setzen
if ( (ULONG)nLen+nIndex > rStr.Len() )
{
if ( nIndex < rStr.Len() )
nLen = rStr.Len()-nIndex;
else
nLen = 0;
}
// Ist die Ausgabe leer, dann mache nichts
if ( !nLen )
return;
// Bei keinem Pos-Array, DrawText benutzen
if ( !pDXAry || (nLen < 2) )
{
// hier Aufrufen, damit keine doppelte MetaFile Aufzeichnung
DrawText( rStartPt, rStr, nIndex, nLen );
return;
}
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
if ( mbNewFont )
{
if ( !ImplNewFont() )
return;
}
if ( mbInitFont )
ImplInitFont();
if ( mbInitTextColor )
ImplInitTextColor();
// Pointer auf den String-Buffer setzen und um den Index korrigieren
const sal_Unicode* pStr = rStr.GetBuffer();
pStr += nIndex;
Point aStartPt = ImplLogicToDevicePixel( rStartPt );
if ( mbMap )
{
long nLogStartX = rStartPt.X();
long nPixStartX = aStartPt.X();
long aStackAry[128];
long* pPixDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) );
for ( xub_StrLen i = 0; i < (nLen-1); i++ )
pPixDXAry[i] = ImplLogicXToDevicePixel( nLogStartX+pDXAry[i] )-nPixStartX;
ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pPixDXAry );
ImplReleaseStackBuffer( pPixDXAry, aStackAry );
}
else
ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry );
}
// -----------------------------------------------------------------------
long OutputDevice::GetTextArray( const UniString& rStr, long* pDXAry,
xub_StrLen nIndex, xub_StrLen nLen ) const
{
DBG_TRACE( "OutputDevice::GetTextArray()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( !pDXAry )
return GetTextWidth( rStr, nIndex, nLen );
// String-Laenge fuer die Ermittlung der Groesse setzen
if ( (ULONG)nLen+nIndex > rStr.Len() )
{
if ( nIndex < rStr.Len() )
nLen = rStr.Len()-nIndex;
else
nLen = 0;
}
if ( !nLen )
return 0;
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return 0;
}
ImplFontEntry* pFontEntry = mpFontEntry;
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
const sal_Unicode* pTempStr;
const sal_Unicode* pStr;
long nOffset = 0;
xub_StrLen i;
pStr = rStr.GetBuffer();
pStr += nIndex;
pTempStr = pStr;
// Breiten ermitteln
for ( i = 0; i < nLen; i++ )
{
nOffset += ImplGetCharWidth( *pTempStr );
pDXAry[i] = nOffset / nFactor;
pTempStr++;
}
// Kerning beruecksichtigen
if ( mbKerning )
ImplCalcKerning( pStr, nLen, pDXAry, nLen );
// Breite und Hoehe ermitteln
long nWidth = pDXAry[nLen-1];
// Wenn MapMode gesetzt, dann Werte umrechnen
if ( mbMap )
{
for ( i = 0; i < nLen; i++ )
pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
nWidth = ImplDevicePixelToLogicWidth( nWidth );
}
return nWidth;
}
// -----------------------------------------------------------------------
void OutputDevice::DrawStretchText( const Point& rStartPt, ULONG nWidth,
const UniString& rStr,
xub_StrLen nIndex, xub_StrLen nLen )
{
DBG_TRACE( "OutputDevice::DrawStretchText()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
if ( !IsDeviceOutputNecessary() )
return;
// String-Laenge fuer die Ermittlung der Groesse setzen
if ( (ULONG)nLen+nIndex > rStr.Len() )
{
if ( nIndex < rStr.Len() )
nLen = rStr.Len()-nIndex;
else
nLen = 0;
}
// Ist die Ausgabe leer, dann mache nichts
if ( !nLen )
return;
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
if ( mbNewFont )
{
if ( !ImplNewFont() )
return;
}
if ( mbInitFont )
ImplInitFont();
if ( mbInitTextColor )
ImplInitTextColor();
Point aStartPt = ImplLogicToDevicePixel( rStartPt );
nWidth = ImplLogicWidthToDevicePixel( nWidth );
// Pointer auf den String-Buffer setzen und um den Index korrigieren
const sal_Unicode* pStr = rStr.GetBuffer();
pStr += nIndex;
// Breiten-Array fuer errechnete Werte allocieren und
// mit den Breiten der einzelnen Character fuellen lassen
long aStackAry[128];
long* pDXAry = (long*)ImplGetStackBuffer( sizeof(long)*nLen, aStackAry, sizeof( aStackAry ) );
ImplFillDXAry( pDXAry, pStr, nLen, (long)nWidth );
ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry );
ImplReleaseStackBuffer( pDXAry, aStackAry );
}
// -----------------------------------------------------------------------
xub_StrLen OutputDevice::GetTextBreak( const XubString& rStr, long nTextWidth,
xub_StrLen nIndex, xub_StrLen nLen,
long nCharExtra ) const
{
DBG_TRACE( "OutputDevice::GetTextBreak()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( nIndex > rStr.Len() )
return 0;
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return 0;
}
ImplFontEntry* pFontEntry = mpFontEntry;
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
const sal_Unicode* pStr;
long nCalcWidth = 0;
xub_StrLen nLastIndex;
if ( mbMap )
{
nTextWidth = ImplLogicWidthToDevicePixel( nTextWidth*10 );
nTextWidth *= nFactor;
nTextWidth /= 10;
if ( nCharExtra )
{
nCharExtra = ImplLogicWidthToDevicePixel( nCharExtra*10 );
nCharExtra *= nFactor;
nCharExtra /= 10;
}
}
else
{
nCharExtra *= nFactor;
nTextWidth *= nFactor;
}
// Letzte Index-Position ermitteln
if ( (ULONG)nIndex+nLen > rStr.Len() )
nLastIndex = rStr.Len();
else
nLastIndex = nIndex + nLen;
pStr = rStr.GetBuffer();
pStr += nIndex;
while ( nIndex < nLastIndex )
{
nCalcWidth += ImplGetCharWidth( *pStr );
if ( nCalcWidth > nTextWidth )
return nIndex;
// Kerning beruecksichtigen
if ( mbKerning )
nCalcWidth += ImplCalcKerning( pStr, 2, NULL, 0 )*nFactor;
nCalcWidth += nCharExtra;
nIndex++;
pStr++;
}
return STRING_LEN;
}
// -----------------------------------------------------------------------
xub_StrLen OutputDevice::GetTextBreak( const XubString& rStr, long nTextWidth,
sal_Unicode nExtraChar, xub_StrLen& rExtraCharPos,
xub_StrLen nIndex, xub_StrLen nLen,
long nCharExtra ) const
{
DBG_TRACE( "OutputDevice::GetTextBreak()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( nIndex > rStr.Len() )
return 0;
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return 0;
}
ImplFontEntry* pFontEntry = mpFontEntry;
long* pCharWidthAry = pFontEntry->maWidthAry;
long nFactor = pFontEntry->mnWidthFactor;
const sal_Unicode* pStr;
long nTextWidth2;
long nCalcWidth = 0;
xub_StrLen nIndex2 = STRING_LEN;
xub_StrLen nLastIndex;
if ( mbMap )
{
nTextWidth = ImplLogicWidthToDevicePixel( nTextWidth*10 );
nTextWidth *= nFactor;
nTextWidth /= 10;
if ( nCharExtra )
{
nCharExtra = ImplLogicWidthToDevicePixel( nCharExtra*10 );
nCharExtra *= nFactor;
nCharExtra /= 10;
}
}
else
{
nCharExtra *= nFactor;
nTextWidth *= nFactor;
}
// Letzte Index-Position ermitteln
if ( (ULONG)nIndex+nLen > rStr.Len() )
nLastIndex = rStr.Len();
else
nLastIndex = nIndex + nLen;
nTextWidth2 = nTextWidth - ImplGetCharWidth( nExtraChar ) - nCharExtra;
if( nTextWidth2 < 0 )
nIndex2 = 0;
2000-09-18 16:07:07 +00:00
pStr = rStr.GetBuffer();
pStr += nIndex;
while ( nIndex < nLastIndex )
{
nCalcWidth += ImplGetCharWidth( *pStr );
if ( nCalcWidth > nTextWidth2 )
{
if ( nIndex2 == STRING_LEN )
nIndex2 = nIndex;
}
if ( nCalcWidth > nTextWidth )
{
if ( nIndex2 == STRING_LEN )
rExtraCharPos = nIndex;
else
rExtraCharPos = nIndex2;
return nIndex;
}
// Kerning beruecksichtigen
if ( mbKerning )
nCalcWidth += ImplCalcKerning( pStr, 2, NULL, 0 )*nFactor;
nCalcWidth += nCharExtra;
nIndex++;
pStr++;
}
rExtraCharPos = nIndex2;
return STRING_LEN;
}
// -----------------------------------------------------------------------
void OutputDevice::GetCharWidth( sal_Unicode nFirstChar, sal_Unicode nLastChar,
long* pWidthAry ) const
{
DBG_TRACE( "OutputDevice::GetCharWidth()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
DBG_ASSERT( nFirstChar <= nLastChar, "OutputDevice::GetCharWidth(): nFirst > nLast" );
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return;
}
long nFactor = mpFontEntry->mnWidthFactor;
sal_Unicode nCharCount = nLastChar-nFirstChar+1;
if ( mbMap )
{
while ( nCharCount )
{
*pWidthAry = ImplDevicePixelToLogicWidth( ImplGetCharWidth( nFirstChar ) ) / nFactor;
pWidthAry++;
nFirstChar++;
nCharCount--;
}
}
else
{
while ( nCharCount )
{
*pWidthAry = ImplGetCharWidth( nFirstChar ) / nFactor;
pWidthAry++;
nFirstChar++;
nCharCount--;
}
}
}
// -----------------------------------------------------------------------
void OutputDevice::DrawText( const Rectangle& rRect,
const XubString& rStr, USHORT nStyle )
{
DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( mpMetaFile )
mpMetaFile->AddAction( new MetaTextRectAction( rRect, rStr, nStyle ) );
if ( !IsDeviceOutputNecessary() || !rStr.Len() || rRect.IsEmpty() )
return;
// Vorsichtshalber hier auch schon Aufrufen, da ImplDrawMnemonicLine()
// dies nicht macht
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
Color aOldTextColor;
Color aOldTextFillColor;
BOOL bRestoreFillColor;
if ( nStyle & TEXT_DRAW_DISABLE )
{
aOldTextColor = GetTextColor();
if ( IsTextFillColor() )
{
bRestoreFillColor = TRUE;
aOldTextFillColor = GetTextFillColor();
}
else
bRestoreFillColor = FALSE;
SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
Rectangle aRect = rRect;
aRect.Move( 1, 1 );
DrawText( aRect, rStr, nStyle & ~TEXT_DRAW_DISABLE );
SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() );
}
long nWidth = rRect.GetWidth();
long nHeight = rRect.GetHeight();
if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
return;
XubString aStr = rStr;
Point aPos = rRect.TopLeft();
long nTextHeight = GetTextHeight();
TextAlign eAlign = GetTextAlign();
xub_StrLen nMnemonicPos = STRING_NOTFOUND;
if ( nStyle & TEXT_DRAW_MNEMONIC )
aStr = GetNonMnemonicString( aStr, nMnemonicPos );
// Mehrzeiligen Text behandeln wir anders
if ( nStyle & TEXT_DRAW_MULTILINE )
{
XubString aLastLine;
ImplMultiTextLineInfo aMultiLineInfo;
ImplTextLineInfo* pLineInfo;
long nMaxTextWidth;
xub_StrLen i;
xub_StrLen nLines;
xub_StrLen nFormatLines;
if ( nTextHeight )
{
nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle );
nLines = (xub_StrLen)(nHeight/nTextHeight);
nFormatLines = aMultiLineInfo.Count();
if ( !nLines )
nLines = 1;
if ( nFormatLines > nLines )
{
if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
{
// Letzte Zeile zusammenbauen und kuerzen
nFormatLines = nLines-1;
pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
aLastLine = aStr.Copy( pLineInfo->GetIndex() );
aLastLine.ConvertLineEnd( LINEEND_LF );
// Alle LineFeed's durch Spaces ersetzen
xub_StrLen nLastLineLen = aLastLine.Len();
for ( i = 0; i < nLastLineLen; i++ )
{
if ( aLastLine.GetChar( i ) == _LF )
aLastLine.SetChar( i, ' ' );
}
aLastLine = GetEllipsisString( aLastLine, nWidth, nStyle );
nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
nStyle |= TEXT_DRAW_TOP;
}
}
else
{
if ( nMaxTextWidth <= nWidth )
nStyle &= ~TEXT_DRAW_CLIP;
}
// Muss in der Hoehe geclippt werden?
if ( nFormatLines*nTextHeight > nHeight )
nStyle |= TEXT_DRAW_CLIP;
// Clipping setzen
if ( nStyle & TEXT_DRAW_CLIP )
{
Push( PUSH_CLIPREGION );
IntersectClipRegion( rRect );
}
// Vertikales Alignment
if ( nStyle & TEXT_DRAW_BOTTOM )
aPos.Y() += nHeight-(nFormatLines*nTextHeight);
else if ( nStyle & TEXT_DRAW_VCENTER )
aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
// Font Alignment
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += nTextHeight;
else if ( eAlign == ALIGN_BASELINE )
aPos.Y() += GetFontMetric().GetAscent();
// Alle Zeilen ausgeben, bis auf die letzte
for ( i = 0; i < nFormatLines; i++ )
{
pLineInfo = aMultiLineInfo.GetLine( i );
if ( nStyle & TEXT_DRAW_RIGHT )
aPos.X() += nWidth-pLineInfo->GetWidth();
else if ( nStyle & TEXT_DRAW_CENTER )
aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
xub_StrLen nIndex = pLineInfo->GetIndex();
xub_StrLen nLineLen = pLineInfo->GetLen();
DrawText( aPos, aStr, nIndex, nLineLen );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
{
long nMnemonicX;
long nMnemonicY;
xub_Unicode cMnemonic;
Point aTempPos = LogicToPixel( aPos );
cMnemonic = aStr.GetChar( nMnemonicPos );
nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, nIndex, nMnemonicPos-nIndex ) );
nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic );
}
}
aPos.Y() += nTextHeight;
aPos.X() = rRect.Left();
}
// Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
// da die Zeile gekuerzt wurde
if ( aLastLine.Len() )
DrawText( aPos, aLastLine );
// Clipping zuruecksetzen
if ( nStyle & TEXT_DRAW_CLIP )
Pop();
}
}
else
{
long nTextWidth = GetTextWidth( aStr );
// Evt. Text kuerzen
if ( nTextWidth > nWidth )
{
if ( nStyle & TEXT_DRAW_ELLIPSIS )
{
aStr = GetEllipsisString( aStr, nWidth, nStyle );
nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
nStyle |= TEXT_DRAW_LEFT;
nTextWidth = GetTextWidth( aStr );
}
}
else
{
if ( nTextHeight <= nHeight )
nStyle &= ~TEXT_DRAW_CLIP;
}
// Vertikales Alignment
if ( nStyle & TEXT_DRAW_RIGHT )
aPos.X() += nWidth-nTextWidth;
else if ( nStyle & TEXT_DRAW_CENTER )
aPos.X() += (nWidth-nTextWidth)/2;
// Font Alignment
if ( eAlign == ALIGN_BOTTOM )
aPos.Y() += nTextHeight;
else if ( eAlign == ALIGN_BASELINE )
aPos.Y() += GetFontMetric().GetAscent();
if ( nStyle & TEXT_DRAW_BOTTOM )
aPos.Y() += nHeight-nTextHeight;
else if ( nStyle & TEXT_DRAW_VCENTER )
aPos.Y() += (nHeight-nTextHeight)/2;
long nMnemonicX;
long nMnemonicY;
xub_Unicode cMnemonic;
if ( nMnemonicPos != STRING_NOTFOUND )
{
Point aTempPos = LogicToPixel( aPos );
cMnemonic = aStr.GetChar( nMnemonicPos );
nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, 0, nMnemonicPos ) );
nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
}
if ( nStyle & TEXT_DRAW_CLIP )
{
Push( PUSH_CLIPREGION );
IntersectClipRegion( rRect );
DrawText( aPos, aStr );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( nMnemonicPos != STRING_NOTFOUND )
ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic );
}
Pop();
}
else
{
DrawText( aPos, aStr );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( nMnemonicPos != STRING_NOTFOUND )
ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic );
}
}
}
if ( nStyle & TEXT_DRAW_DISABLE )
{
SetTextColor( aOldTextColor );
if ( bRestoreFillColor )
SetTextFillColor( aOldTextFillColor );
}
}
// -----------------------------------------------------------------------
Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
const XubString& rStr, USHORT nStyle,
TextRectInfo* pInfo ) const
{
DBG_TRACE( "OutputDevice::GetTextRect()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
Rectangle aRect = rRect;
XubString aStr = rStr;
xub_StrLen nLines;
long nWidth = rRect.GetWidth();
long nMaxWidth;
long nTextHeight = GetTextHeight();
if ( nStyle & TEXT_DRAW_MNEMONIC )
aStr = GetNonMnemonicString( aStr );
if ( nStyle & TEXT_DRAW_MULTILINE )
{
ImplMultiTextLineInfo aMultiLineInfo;
ImplTextLineInfo* pLineInfo;
xub_StrLen nFormatLines;
xub_StrLen i;
nMaxWidth = 0;
ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle );
nFormatLines = aMultiLineInfo.Count();
if ( !nTextHeight )
nTextHeight = 1;
nLines = (USHORT)(aRect.GetHeight()/nTextHeight);
if ( pInfo )
pInfo->mnLineCount = nFormatLines;
if ( !nLines )
nLines = 1;
if ( nFormatLines <= nLines )
nLines = nFormatLines;
else
{
if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
nLines = nFormatLines;
else
{
if ( pInfo )
pInfo->mbEllipsis = TRUE;
nMaxWidth = nWidth;
}
}
if ( pInfo )
{
BOOL bMaxWidth = nMaxWidth == 0;
pInfo->mnMaxWidth = 0;
for ( i = 0; i < nLines; i++ )
{
pLineInfo = aMultiLineInfo.GetLine( i );
if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
nMaxWidth = pLineInfo->GetWidth();
if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
pInfo->mnMaxWidth = pLineInfo->GetWidth();
}
}
else if ( !nMaxWidth )
{
for ( i = 0; i < nLines; i++ )
{
pLineInfo = aMultiLineInfo.GetLine( i );
if ( pLineInfo->GetWidth() > nMaxWidth )
nMaxWidth = pLineInfo->GetWidth();
}
}
}
else
{
nLines = 1;
nMaxWidth = GetTextWidth( aStr );
if ( pInfo )
{
pInfo->mnLineCount = 1;
pInfo->mnMaxWidth = nMaxWidth;
}
if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
{
if ( pInfo )
pInfo->mbEllipsis = TRUE;
nMaxWidth = nWidth;
}
}
if ( nStyle & TEXT_DRAW_RIGHT )
aRect.Left() = aRect.Right()-nMaxWidth+1;
else if ( nStyle & TEXT_DRAW_CENTER )
{
aRect.Left() += (nWidth-nMaxWidth)/2;
aRect.Right() = aRect.Left()+nMaxWidth-1;
}
else
aRect.Right() = aRect.Left()+nMaxWidth-1;
if ( nStyle & TEXT_DRAW_BOTTOM )
aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
else if ( nStyle & TEXT_DRAW_VCENTER )
{
aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2;
aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
}
else
aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
return aRect;
}
// -----------------------------------------------------------------------
static BOOL ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
{
while ( *pStr )
{
if ( *pStr == c )
return TRUE;
pStr++;
}
return FALSE;
}
// -----------------------------------------------------------------------
XubString OutputDevice::GetEllipsisString( const XubString& rStr, long nMaxWidth,
USHORT nStyle ) const
{
DBG_TRACE( "OutputDevice::GetEllipsisString()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
XubString aStr = rStr;
xub_StrLen nIndex = GetTextBreak( aStr, nMaxWidth );
if ( nIndex != STRING_LEN )
{
if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
{
aStr.Erase( nIndex );
if ( nIndex > 1 )
{
aStr.AppendAscii( "..." );
while ( aStr.Len() && (GetTextWidth( aStr ) > nMaxWidth) )
{
if ( (nIndex > 1) || (nIndex == aStr.Len()) )
nIndex--;
aStr.Erase( nIndex, 1 );
}
}
if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
aStr += rStr.GetChar( 0 );
}
else if ( nStyle & (TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) )
{
static sal_Char const aPathSepChars[] = "\\/:";
static sal_Char const aNewsSepChars[] = ".";
const sal_Char* pSepChars;
if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
pSepChars = aPathSepChars;
else
pSepChars = aNewsSepChars;
// Letztes Teilstueck ermitteln
xub_StrLen nLastContent = rStr.Len();
while ( nLastContent )
{
nLastContent--;
if ( ImplIsCharIn( rStr.GetChar( nLastContent ), pSepChars ) )
break;
}
while ( nLastContent &&
ImplIsCharIn( rStr.GetChar( nLastContent-1 ), pSepChars ) )
nLastContent--;
XubString aLastStr( rStr, nLastContent, rStr.Len() );
XubString aTempLastStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
aTempLastStr += aLastStr;
if ( GetTextWidth( aTempLastStr ) > nMaxWidth )
aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
else
{
USHORT nFirstContent = 0;
while ( nFirstContent < nLastContent )
{
nFirstContent++;
if ( ImplIsCharIn( rStr.GetChar( nFirstContent ), pSepChars ) )
break;
}
while ( (nFirstContent < nLastContent) &&
ImplIsCharIn( rStr.GetChar( nFirstContent ), pSepChars ) )
nFirstContent++;
if ( nFirstContent >= nLastContent )
aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
else
{
if ( nFirstContent > 4 )
nFirstContent = 4;
XubString aFirstStr( rStr, 0, nFirstContent );
aFirstStr.AppendAscii( "..." );
XubString aTempStr = aFirstStr;
aTempStr += aLastStr;
if ( GetTextWidth( aTempStr ) > nMaxWidth )
aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS );
else
{
do
{
aStr = aTempStr;
while ( nFirstContent < nLastContent )
{
nLastContent--;
if ( ImplIsCharIn( rStr.GetChar( nLastContent ), pSepChars ) )
break;
}
while ( (nFirstContent < nLastContent) &&
ImplIsCharIn( rStr.GetChar( nLastContent-1 ), pSepChars ) )
nLastContent--;
if ( nFirstContent < nLastContent )
{
XubString aTempLastStr( rStr, nLastContent, rStr.Len() );
aTempStr = aFirstStr;
aTempStr += aTempLastStr;
if ( GetTextWidth( aTempStr ) > nMaxWidth )
break;
}
}
while ( nFirstContent < nLastContent );
}
}
}
}
}
return aStr;
}
// -----------------------------------------------------------------------
void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
xub_StrLen nIndex, xub_StrLen nLen,
USHORT nStyle )
{
DBG_TRACE( "OutputDevice::DrawCtrlText()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
return;
// Vorsichtshalber hier auch schon Aufrufen, da ImplDrawMnemonicLine()
// dies nicht macht
#ifndef REMOTE_APPSERVER
// we need a graphics
if ( !mpGraphics )
{
if ( !ImplGetGraphics() )
return;
}
if ( mbInitClipRegion )
ImplInitClipRegion();
if ( mbOutputClipped )
return;
#else
if ( !ImplGetServerGraphics() )
return;
#endif
XubString aStr = rStr;
xub_StrLen nMnemonicPos = STRING_NOTFOUND;
long nMnemonicX;
long nMnemonicY;
xub_Unicode cMnemonic;
if ( nStyle & TEXT_DRAW_MNEMONIC )
{
aStr = GetNonMnemonicString( aStr, nMnemonicPos );
if ( nMnemonicPos != STRING_NOTFOUND )
{
if ( nMnemonicPos < nIndex )
nIndex--;
else if ( (nLen < STRING_LEN) &&
(nMnemonicPos >= nIndex) && (nMnemonicPos < (ULONG)(nIndex+nLen)) )
nLen--;
Point aTempPos = LogicToPixel( rPos );
cMnemonic = aStr.GetChar( nMnemonicPos );
nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, 0, nMnemonicPos ) );
nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
}
}
if ( nStyle & TEXT_DRAW_DISABLE )
{
Color aOldTextColor;
Color aOldTextFillColor;
BOOL bRestoreFillColor;
aOldTextColor = GetTextColor();
if ( IsTextFillColor() )
{
bRestoreFillColor = TRUE;
aOldTextFillColor = GetTextFillColor();
}
else
bRestoreFillColor = FALSE;
SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
DrawText( Point( rPos.X()+1, rPos.Y()+1 ), aStr, nIndex, nLen );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( nMnemonicPos != STRING_NOTFOUND )
ImplDrawMnemonicLine( nMnemonicX+1, nMnemonicY+1, cMnemonic );
}
SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() );
DrawText( rPos, aStr, nIndex, nLen );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( nMnemonicPos != STRING_NOTFOUND )
ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic );
}
SetTextColor( aOldTextColor );
if ( bRestoreFillColor )
SetTextFillColor( aOldTextFillColor );
}
else
{
DrawText( rPos, aStr, nIndex, nLen );
if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) )
{
if ( nMnemonicPos != STRING_NOTFOUND )
ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic );
}
}
}
// -----------------------------------------------------------------------
long OutputDevice::GetCtrlTextWidth( const XubString& rStr,
xub_StrLen nIndex, xub_StrLen nLen,
USHORT nStyle ) const
{
DBG_TRACE( "OutputDevice::GetCtrlTextSize()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
if ( nStyle & TEXT_DRAW_MNEMONIC )
{
xub_StrLen nMnemonicPos;
XubString aStr = GetNonMnemonicString( rStr, nMnemonicPos );
if ( nMnemonicPos != STRING_NOTFOUND )
{
if ( nMnemonicPos < nIndex )
nIndex--;
else if ( (nLen < STRING_LEN) &&
(nMnemonicPos >= nIndex) && (nMnemonicPos < (ULONG)(nIndex+nLen)) )
nLen--;
}
return GetTextWidth( aStr, nIndex, nLen );
}
else
return GetTextWidth( rStr, nIndex, nLen );
}
// -----------------------------------------------------------------------
XubString OutputDevice::GetNonMnemonicString( const XubString& rStr, xub_StrLen& rMnemonicPos )
{
XubString aStr = rStr;
xub_StrLen nLen = aStr.Len();
xub_StrLen i = 0;
rMnemonicPos = STRING_NOTFOUND;
while ( i < nLen )
{
if ( aStr.GetChar( i ) == '~' )
{
if ( aStr.GetChar( i+1 ) != '~' )
{
if ( rMnemonicPos == STRING_NOTFOUND )
rMnemonicPos = i;
aStr.Erase( i, 1 );
nLen--;
}
else
{
aStr.Erase( i, 1 );
nLen--;
i++;
}
}
else
i++;
}
return aStr;
}
// -----------------------------------------------------------------------
USHORT OutputDevice::GetDevFontCount() const
{
DBG_TRACE( "OutputDevice::GetDevFontCount()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
// Wenn wir schon eine Liste der Fonts haben, dann nicht iterieren
if ( mpGetDevFontList )
return (USHORT)mpGetDevFontList->Count();
((OutputDevice*)this)->mpGetDevFontList = new ImplGetDevFontList;
// Fill Fontlist
ImplDevFontListData* pFontListData = mpFontList->First();
while ( pFontListData )
{
ImplFontData* pLastData = NULL;
ImplFontData* pData = pFontListData->mpFirst;
while ( pData )
{
// Compare with the last font, because we wan't in the list
// only fonts, that have different attributes, but not
// different sizes
if ( !pLastData ||
(ImplCompareFontDataWithoutSize( pLastData, pData ) != 0) )
mpGetDevFontList->Add( pData );
pLastData = pData;
pData = pData->mpNext;
}
pFontListData = mpFontList->Next();
}
return (USHORT)mpGetDevFontList->Count();
}
// -----------------------------------------------------------------------
FontInfo OutputDevice::GetDevFont( USHORT nDevFont ) const
{
DBG_TRACE( "OutputDevice::GetDevFont()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
FontInfo aFontInfo;
USHORT nCount = GetDevFontCount();
// Wertebereich ueberpruefen
if ( nDevFont < nCount )
{
ImplFontData* pData = mpGetDevFontList->Get( nDevFont );
aFontInfo.SetName( pData->maName );
aFontInfo.SetStyleName( pData->maStyleName );
// !!! UNICODE !!! aFontInfo.SetCharSet( ImplGetFakeEncoding( pData->meCharSet ) );
aFontInfo.SetCharSet( pData->meCharSet );
aFontInfo.SetFamily( pData->meFamily );
aFontInfo.SetPitch( pData->mePitch );
aFontInfo.SetWeight( pData->meWeight );
aFontInfo.SetItalic( pData->meItalic );
aFontInfo.mpImplMetric->meType = pData->meType;
aFontInfo.mpImplMetric->mbDevice = pData->mbDevice;
}
return aFontInfo;
}
// -----------------------------------------------------------------------
USHORT OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
{
DBG_TRACE( "OutputDevice::GetDevFontSizeCount()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
XubString aFontName = rFont.GetName();
// Wenn die Liste schon existiert und der FontName sich nicht
// unterscheidet, dann brauchen wir Sie nicht neu erzeugen
if ( mpGetDevSizeList )
{
if ( mpGetDevSizeList->GetFontName() == aFontName )
return (USHORT)mpGetDevSizeList->Count();
else
{
mpGetDevSizeList->Clear();
mpGetDevSizeList->SetFontName( aFontName );
}
}
else
((OutputDevice*)this)->mpGetDevSizeList = new ImplGetDevSizeList( aFontName );
// Fonts aus unserer Fontliste in die GetDevFontSizeListe eintragen
ImplDevFontListData* pFontListData = mpFontList->FindFont( aFontName );
if ( pFontListData )
{
ImplFontData* pData = pFontListData->mpFirst;
do
{
mpGetDevSizeList->Add( pData->mnHeight );
pData = pData->mpNext;
}
while ( pData );
}
return (USHORT)mpGetDevSizeList->Count();
}
// -----------------------------------------------------------------------
Size OutputDevice::GetDevFontSize( const Font& rFont, USHORT nSize ) const
{
DBG_TRACE( "OutputDevice::GetDevFontSize()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
USHORT nCount = GetDevFontSizeCount( rFont );
// Wertebereich ueberpruefen
if ( nSize >= nCount )
return Size();
// Wenn MapMode gesetzt ist, wird auf ,5-Points gerundet
Size aSize( 0, mpGetDevSizeList->Get( nSize ) );
if ( mbMap )
{
aSize.Height() *= 10;
MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
aSize = PixelToLogic( aSize, aMap );
aSize.Height() += 5;
aSize.Height() /= 10;
long nRound = aSize.Height() % 5;
if ( nRound >= 3 )
aSize.Height() += (5-nRound);
else
aSize.Height() -= nRound;
aSize.Height() *= 10;
aSize = LogicToPixel( aSize, aMap );
aSize = PixelToLogic( aSize );
aSize.Height() += 5;
aSize.Height() /= 10;
}
return aSize;
}
// -----------------------------------------------------------------------
BOOL OutputDevice::IsFontAvailable( const XubString& rFontName ) const
{
DBG_TRACE( "OutputDevice::IsFontAvailable()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
return (mpFontList->FindFont( rFontName ) != 0);
}
// -----------------------------------------------------------------------
FontMetric OutputDevice::GetFontMetric() const
{
DBG_TRACE( "OutputDevice::GetFontMetric()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
FontMetric aMetric;
if ( mbNewFont )
{
if ( !((OutputDevice*)this)->ImplNewFont() )
return aMetric;
}
ImplFontEntry* pEntry = mpFontEntry;
ImplFontMetricData* pMetric = &(pEntry->maMetric);
// Mappen und StarView Struktur fuellen
aMetric.Font::operator=( maFont );
// Fontdaten ermitteln und setzen
aMetric.SetName( pMetric->maName );
aMetric.SetStyleName( pMetric->maStyleName );
aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnLeading ) ) );
aMetric.SetCharSet( pMetric->meCharSet );
aMetric.SetFamily( pMetric->meFamily );
aMetric.SetPitch( pMetric->mePitch );
aMetric.SetWeight( pMetric->meWeight );
aMetric.SetItalic( pMetric->meItalic );
if ( pEntry->mnOwnOrientation )
aMetric.SetOrientation( pEntry->mnOwnOrientation );
else
aMetric.SetOrientation( pMetric->mnOrientation );
if ( !mbKerning )
aMetric.SetKerning( FALSE );
// restliche Metricen setzen
aMetric.mpImplMetric->meType = pMetric->meType;
aMetric.mpImplMetric->mbDevice = pMetric->mbDevice;
2001-02-23 15:13:58 +00:00
aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
aMetric.mpImplMetric->mnLeading = ImplDevicePixelToLogicHeight( pMetric->mnLeading+mnEmphasisAscent );
aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
2000-09-18 16:07:07 +00:00
aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
aMetric.mpImplMetric->mnFirstChar = pMetric->mnFirstChar;
aMetric.mpImplMetric->mnLastChar = pMetric->mnLastChar;
return aMetric;
}
// -----------------------------------------------------------------------
FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
{
// Uebergebenen Font selektieren, Metric abfragen und alten wieder
// selektieren
Font aOldFont = GetFont();
((OutputDevice*)this)->SetFont( rFont );
FontMetric aMetric( GetFontMetric() );
((OutputDevice*)this)->SetFont( aOldFont );
return aMetric;
}
// -----------------------------------------------------------------------
ULONG OutputDevice::GetKerningPairCount() const
{
DBG_TRACE( "OutputDevice::GetKerningPairCount()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
((OutputDevice*)this)->ImplInitKerningPairs();
return mpFontEntry->mnKernPairs;
}
// -----------------------------------------------------------------------
void OutputDevice::GetKerningPairs( ULONG nPairs, KerningPair* pKernPairs ) const
{
DBG_TRACE( "OutputDevice::GetKerningPairs()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
((OutputDevice*)this)->ImplInitKerningPairs();
if ( nPairs > mpFontEntry->mnKernPairs )
nPairs = mpFontEntry->mnKernPairs;
if ( nPairs )
memcpy( pKernPairs, mpFontEntry->mpKernPairs, nPairs*sizeof( KerningPair ) );
}
// -----------------------------------------------------------------------
BOOL OutputDevice::GetGlyphBoundRect( xub_Unicode cChar, Rectangle& rRect, BOOL bOptimize )
{
DBG_TRACE( "OutputDevice::GetGlyphBoundRect()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
BOOL bRet = FALSE;
#ifndef REMOTE_APPSERVER
if ( mpGraphics || ImplGetGraphics() )
{
Font* pOldFont;
long nLeft, nTop, nWidth, nHeight;
long nFontWidth, nFontHeight;
long nOrgWidth, nOrgHeight;
if ( bOptimize )
{
pOldFont = new Font( GetFont() );
Font aFont( *pOldFont );
Size aFontSize( LogicToPixel( aFont.GetSize() ) );
if ( aFontSize.Width() && aFontSize.Height() )
{
const double fFactor = (double) aFontSize.Width() / aFontSize.Height();
if ( fFactor < 1.0 )
{
aFontSize.Width() = FRound( fFactor * 500. );
aFontSize.Height() = 500;
}
else
{
aFontSize.Width() = 500;
aFontSize.Height() = FRound( 500. / fFactor );
}
aFont.SetSize( PixelToLogic( aFontSize ) );
((OutputDevice*)this)->SetFont( aFont );
nFontWidth = aFont.GetSize().Width();
nFontHeight = aFont.GetSize().Height();
nOrgWidth = pOldFont->GetSize().Width();
nOrgHeight = pOldFont->GetSize().Height();
}
else
{
aFont.SetSize( PixelToLogic( Size( 0, 500 ) ) );
((OutputDevice*)this)->SetFont( aFont );
nFontWidth = nFontHeight = aFont.GetSize().Height();
nOrgWidth = nOrgHeight = pOldFont->GetSize().Height();
}
}
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
if ( mpGraphics->GetGlyphBoundRect( cChar, &nLeft, &nTop, &nWidth, &nHeight ) )
{
if ( bOptimize )
{
nLeft = ImplDevicePixelToLogicWidth( nLeft ) * nOrgWidth / nFontWidth;
nTop = ImplDevicePixelToLogicHeight( nTop ) * nOrgHeight / nFontHeight;
nWidth = ImplDevicePixelToLogicWidth( nWidth ) * nOrgWidth / nFontWidth;
nHeight = ImplDevicePixelToLogicHeight( nHeight ) * nOrgHeight / nFontHeight;
}
else
{
nLeft = ImplDevicePixelToLogicWidth( nLeft );
nTop = ImplDevicePixelToLogicHeight( nTop );
nWidth = ImplDevicePixelToLogicWidth( nWidth );
nHeight = ImplDevicePixelToLogicHeight( nHeight );
}
rRect = Rectangle( Point( nLeft, nTop ), Size( nWidth, nHeight ) );
bRet = TRUE;
}
if ( bOptimize )
{
((OutputDevice*)this)->SetFont( *pOldFont );
delete pOldFont;
}
2001-02-23 15:13:58 +00:00
}
#else
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
bRet = mpGraphics->GetGlyphBoundRect( cChar, rRect, bOptimize );
if ( bRet )
{
rRect = Rectangle( Point( ImplDevicePixelToLogicWidth( rRect.Left() ),
ImplDevicePixelToLogicHeight( rRect.Top() ) ),
Size( ImplDevicePixelToLogicWidth( rRect.GetWidth() ),
ImplDevicePixelToLogicHeight( rRect.GetHeight() ) ) );
}
#endif
if ( !bRet && (OUTDEV_PRINTER != meOutDevType) )
{
if ( bOptimize )
{
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
}
VirtualDevice* pVDev = new VirtualDevice( 1 );
long nWidth = ImplGetTextWidth( &cChar, 1, NULL );
long nHeight = mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
Point aOffset( nWidth >> 1, 8 );
Size aSize( nWidth + ( aOffset.X() << 1 ), nHeight + ( aOffset.Y() << 1 ) );
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
if ( pVDev->SetOutputSizePixel( aSize ) )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
Font aFont( GetFont() );
Bitmap aBmp;
aFont.SetShadow( FALSE );
aFont.SetOutline( FALSE );
aFont.SetRelief( RELIEF_NONE );
aFont.SetOrientation( 0 );
aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
pVDev->SetFont( aFont );
pVDev->SetTextAlign( ALIGN_TOP );
pVDev->SetTextColor( Color( COL_BLACK ) );
pVDev->SetTextFillColor();
pVDev->ImplNewFont();
pVDev->ImplInitFont();
pVDev->ImplInitTextColor();
pVDev->ImplDrawText( aOffset.X(), aOffset.Y(), &cChar, 1, NULL );
aBmp = pVDev->GetBitmap( Point(), aSize );
delete pVDev;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
if ( pAcc )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
const long nW = pAcc->Width();
const long nW1 = nW - 1L;
const long nH = pAcc->Height();
long nLeft, nTop, nRight, nBottom;
const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
BOOL bLineDone;
nLeft = nW;
nTop = nH;
nRight = nBottom = -1L;
for( long nY = 0L; nY < nH; nY++ )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
bLineDone = FALSE;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
for( long nX = 0L; ( nX < nW ) && !bLineDone; nX++ )
{
if( pAcc->GetPixel( nY, nX ) == aBlack )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
// find y minimum
if( nY < nTop )
nTop = nY;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
// find y maximum
if( nY > nBottom )
nBottom = nY;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
// find x minimum
if( nX < nLeft )
nLeft = nX;
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
// find x maximum (last pixel in line)
for( long nX2 = nW1; nX2 >= nX; nX2-- )
{
if( pAcc->GetPixel( nY, nX2 ) == aBlack )
2000-09-18 16:07:07 +00:00
{
2001-02-23 15:13:58 +00:00
if( nX2 > nRight )
nRight = nX2;
bLineDone = TRUE;
break;
2000-09-18 16:07:07 +00:00
}
}
}
}
2001-02-23 15:13:58 +00:00
}
2000-09-18 16:07:07 +00:00
2001-02-23 15:13:58 +00:00
if( nLeft < nW && nTop < nH && nRight > -1L && nBottom > -1L )
{
nLeft -= aOffset.X(), nTop -= aOffset.Y();
nRight -= aOffset.X(), nBottom -= aOffset.Y();
nWidth = ImplDevicePixelToLogicWidth( nRight - nLeft + 1L );
nHeight = ImplDevicePixelToLogicHeight( nBottom - nTop + 1L );
nLeft = ImplDevicePixelToLogicWidth( nLeft );
nTop = ImplDevicePixelToLogicHeight( nTop );
rRect = Rectangle( Point( nLeft, nTop ), Size( nWidth, nHeight ) );
bRet = TRUE;
2000-09-18 16:07:07 +00:00
}
2001-02-23 15:13:58 +00:00
aBmp.ReleaseAccess( pAcc );
2000-09-18 16:07:07 +00:00
}
}
2001-02-23 15:13:58 +00:00
else
delete pVDev;
2000-09-18 16:07:07 +00:00
}
if ( !bRet )
rRect.SetEmpty();
return bRet;
}
// -----------------------------------------------------------------------
BOOL OutputDevice::GetGlyphOutline( xub_Unicode cChar, PolyPolygon& rPolyPoly, BOOL bOptimize )
{
DBG_TRACE( "OutputDevice::GetGlyphOutline()" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
BOOL bRet = FALSE;
#ifndef REMOTE_APPSERVER
if ( mpGraphics || ImplGetGraphics() )
{
Font* pOldFont;
USHORT* pPolySizes = NULL;
SalPoint* pPoints = NULL;
BYTE* pFlags = NULL;
long nFontWidth, nFontHeight;
long nOrgWidth, nOrgHeight;
ULONG nPolyCount;
if ( bOptimize )
{
pOldFont = new Font( GetFont() );
Font aFont( *pOldFont );
Size aFontSize( LogicToPixel( aFont.GetSize() ) );
if ( aFontSize.Width() && aFontSize.Height() )
{
const double fFactor = (double) aFontSize.Width() / aFontSize.Height();
if ( fFactor < 1.0 )
{
aFontSize.Width() = FRound( fFactor * 500. );
aFontSize.Height() = 500;
}
else
{
aFontSize.Width() = 500;
aFontSize.Height() = FRound( 500. / fFactor );
}
aFont.SetSize( PixelToLogic( aFontSize ) );
((OutputDevice*)this)->SetFont( aFont );
nFontWidth = aFont.GetSize().Width();
nFontHeight = aFont.GetSize().Height();
nOrgWidth = pOldFont->GetSize().Width();
nOrgHeight = pOldFont->GetSize().Height();
}
else
{
aFont.SetSize( PixelToLogic( Size( 0, 500 ) ) );
((OutputDevice*)this)->SetFont( aFont );
nFontWidth = nFontHeight = aFont.GetSize().Height();
nOrgWidth = nOrgHeight = pOldFont->GetSize().Height();
}
}
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
nPolyCount = mpGraphics->GetGlyphOutline( cChar, &pPolySizes, &pPoints, &pFlags );
if ( nPolyCount && pPolySizes && pPoints && pFlags )
{
ULONG nTotalPos = 0UL;
rPolyPoly.Clear();
for( ULONG i = 0UL; i < nPolyCount; i++ )
{
const USHORT nSize = pPolySizes[ i ];
if( nSize )
{
Polygon aPoly( nSize );
Point* pPt = aPoly.ImplGetPointAry();
BYTE* pFl = aPoly.ImplGetFlagAry();
memcpy( pFl, pFlags + nTotalPos, nSize );
for( USHORT n = 0; n < nSize; n++ )
{
const SalPoint& rSalPt = pPoints[ nTotalPos++ ];
Point& rPt = pPt[ n ];
if( bOptimize )
{
rPt.X() = ImplDevicePixelToLogicWidth( rSalPt.mnX ) *
nOrgWidth / nFontWidth;
rPt.Y() = ImplDevicePixelToLogicHeight( rSalPt.mnY ) *
nOrgHeight / nFontHeight;
}
else
{
rPt.X() = ImplDevicePixelToLogicWidth( rSalPt.mnX );
rPt.Y() = ImplDevicePixelToLogicHeight( rSalPt.mnY );
}
}
rPolyPoly.Insert( aPoly );
}
}
bRet = TRUE;
}
delete[] pPolySizes;
delete[] pPoints;
delete[] pFlags;
if ( bOptimize )
{
((OutputDevice*)this)->SetFont( *pOldFont );
delete pOldFont;
}
}
#else
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
bRet = mpGraphics->GetGlyphOutline( cChar, rPolyPoly, bOptimize );
2001-02-23 15:13:58 +00:00
if ( bRet )
2000-09-18 16:07:07 +00:00
{
for( USHORT i = 0UL, nCount = rPolyPoly.Count(); i < nCount; i++ )
{
2001-02-23 15:13:58 +00:00
Polygon& rPoly = rPolyPoly[i];
2000-09-18 16:07:07 +00:00
for( USHORT n = 0, nSize = rPoly.GetSize(); n < nSize; n++ )
{
Point& rPt = rPoly[ n ];
rPt.X() = ImplDevicePixelToLogicWidth( rPt.X() );
rPt.Y() = ImplDevicePixelToLogicHeight( rPt.Y() );
}
}
}
#endif
2001-02-23 15:13:58 +00:00
if ( !bRet && (OUTDEV_PRINTER != meOutDevType) )
{
if ( bOptimize )
{
if ( mbNewFont )
ImplNewFont();
if ( mbInitFont )
ImplInitFont();
}
Font aFont( GetFont() );
VirtualDevice* pVDev = new VirtualDevice( 1 );
const Size aFontSize( pVDev->LogicToPixel( Size( 0, GLYPH_FONT_HEIGHT ), MAP_POINT ) );
const long nOrgWidth = ImplGetTextWidth( &cChar, 1, NULL );
const long nOrgHeight = mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
aFont.SetShadow( FALSE );
aFont.SetOutline( FALSE );
aFont.SetRelief( RELIEF_NONE );
aFont.SetOrientation( 0 );
aFont.SetSize( aFontSize );
pVDev->SetFont( aFont );
pVDev->SetTextAlign( ALIGN_TOP );
pVDev->SetTextColor( Color( COL_BLACK ) );
pVDev->SetTextFillColor();
pVDev->ImplNewFont();
pVDev->ImplInitFont();
pVDev->ImplInitTextColor();
const long nWidth = pVDev->ImplGetTextWidth( &cChar, 1, NULL );
const long nHeight = pVDev->mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent;
const Point aOffset( nWidth >> 1, 8 );
const Size aSize( nWidth + ( aOffset.X() << 1 ), nHeight + ( aOffset.Y() << 1 ) );
const double fScaleX = ( nOrgWidth && nWidth ) ? ( (double) nOrgWidth / nWidth ) : 0.0;
const double fScaleY = ( nOrgHeight && nHeight ) ? ( (double) nOrgHeight / nHeight ) : 0.0;
if ( pVDev->SetOutputSizePixel( aSize ) )
{
Bitmap aBmp;
pVDev->ImplDrawText( aOffset.X(), aOffset.Y(), &cChar, 1, NULL );
aBmp = pVDev->GetBitmap( Point(), aSize );
delete pVDev;
if( aBmp.Vectorize( rPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES ) )
{
const long nOffX = aOffset.X(), nOffY = aOffset.Y();
for( USHORT i = 0UL, nCount = rPolyPoly.Count(); i < nCount; i++ )
{
Polygon& rPoly = rPolyPoly[ i ];
for( USHORT n = 0, nSize = rPoly.GetSize(); n < nSize; n++ )
{
Point& rPt = rPoly[ n ];
rPt.X() = FRound( ImplDevicePixelToLogicWidth( rPt.X() - nOffX ) * fScaleX );
rPt.Y() = FRound( ImplDevicePixelToLogicHeight( rPt.Y() - nOffY ) * fScaleY );
}
}
bRet = TRUE;
}
}
else
delete pVDev;
}
2000-09-18 16:07:07 +00:00
if( !bRet )
rPolyPoly = PolyPolygon();
return bRet;
}