blob: 6ff292493f5687efe3321c39d29878c6951ec83a [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include <vcl/salbtype.hxx>
#include "wmfwr.hxx"
#include <unotools/fontcvt.hxx>
#include "emfwr.hxx"
#include <rtl/crc.h>
#include <rtl/tencinfo.h>
#include <tools/tenccvt.hxx>
#include <osl/endian.h>
#include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType
#include <vcl/metric.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <vcl/dibtools.hxx>
//====================== MS-Windows-defines ===============================
#define W_META_SETBKCOLOR 0x0201
#define W_META_SETBKMODE 0x0102
#define W_META_SETMAPMODE 0x0103
#define W_META_SETROP2 0x0104
#define W_META_SETRELABS 0x0105
#define W_META_SETPOLYFILLMODE 0x0106
#define W_META_SETSTRETCHBLTMODE 0x0107
#define W_META_SETTEXTCHAREXTRA 0x0108
#define W_META_SETTEXTCOLOR 0x0209
#define W_META_SETTEXTJUSTIFICATION 0x020A
#define W_META_SETWINDOWORG 0x020B
#define W_META_SETWINDOWEXT 0x020C
#define W_META_SETVIEWPORTORG 0x020D
#define W_META_SETVIEWPORTEXT 0x020E
#define W_META_OFFSETWINDOWORG 0x020F
#define W_META_SCALEWINDOWEXT 0x0410
#define W_META_OFFSETVIEWPORTORG 0x0211
#define W_META_SCALEVIEWPORTEXT 0x0412
#define W_META_LINETO 0x0213
#define W_META_MOVETO 0x0214
#define W_META_EXCLUDECLIPRECT 0x0415
#define W_META_INTERSECTCLIPRECT 0x0416
#define W_META_ARC 0x0817
#define W_META_ELLIPSE 0x0418
#define W_META_FLOODFILL 0x0419
#define W_META_PIE 0x081A
#define W_META_RECTANGLE 0x041B
#define W_META_ROUNDRECT 0x061C
#define W_META_PATBLT 0x061D
#define W_META_SAVEDC 0x001E
#define W_META_SETPIXEL 0x041F
#define W_META_OFFSETCLIPRGN 0x0220
#define W_META_TEXTOUT 0x0521
#define W_META_BITBLT 0x0922
#define W_META_STRETCHBLT 0x0B23
#define W_META_POLYGON 0x0324
#define W_META_POLYLINE 0x0325
#define W_META_ESCAPE 0x0626
#define W_META_RESTOREDC 0x0127
#define W_META_FILLREGION 0x0228
#define W_META_FRAMEREGION 0x0429
#define W_META_INVERTREGION 0x012A
#define W_META_PAINTREGION 0x012B
#define W_META_SELECTCLIPREGION 0x012C
#define W_META_SELECTOBJECT 0x012D
#define W_META_SETTEXTALIGN 0x012E
#define W_META_DRAWTEXT 0x062F
#define W_META_CHORD 0x0830
#define W_META_SETMAPPERFLAGS 0x0231
#define W_META_EXTTEXTOUT 0x0a32
#define W_META_SETDIBTODEV 0x0d33
#define W_META_SELECTPALETTE 0x0234
#define W_META_REALIZEPALETTE 0x0035
#define W_META_ANIMATEPALETTE 0x0436
#define W_META_SETPALENTRIES 0x0037
#define W_META_POLYPOLYGON 0x0538
#define W_META_RESIZEPALETTE 0x0139
#define W_META_DIBBITBLT 0x0940
#define W_META_DIBSTRETCHBLT 0x0b41
#define W_META_DIBCREATEPATTERNBRUSH 0x0142
#define W_META_STRETCHDIB 0x0f43
#define W_META_EXTFLOODFILL 0x0548
#define W_META_RESETDC 0x014C
#define W_META_STARTDOC 0x014D
#define W_META_STARTPAGE 0x004F
#define W_META_ENDPAGE 0x0050
#define W_META_ABORTDOC 0x0052
#define W_META_ENDDOC 0x005E
#define W_META_DELETEOBJECT 0x01f0
#define W_META_CREATEPALETTE 0x00f7
#define W_META_CREATEBRUSH 0x00F8
#define W_META_CREATEPATTERNBRUSH 0x01F9
#define W_META_CREATEPENINDIRECT 0x02FA
#define W_META_CREATEFONTINDIRECT 0x02FB
#define W_META_CREATEBRUSHINDIRECT 0x02FC
#define W_META_CREATEBITMAPINDIRECT 0x02FD
#define W_META_CREATEBITMAP 0x06FE
#define W_META_CREATEREGION 0x06FF
#define W_TRANSPARENT 1
#define W_OPAQUE 2
#define W_R2_BLACK 1
#define W_R2_NOTMERGEPEN 2
#define W_R2_MASKNOTPEN 3
#define W_R2_NOTCOPYPEN 4
#define W_R2_MASKPENNOT 5
#define W_R2_NOT 6
#define W_R2_XORPEN 7
#define W_R2_NOTMASKPEN 8
#define W_R2_MASKPEN 9
#define W_R2_NOTXORPEN 10
#define W_R2_NOP 11
#define W_R2_MERGENOTPEN 12
#define W_R2_COPYPEN 13
#define W_R2_MERGEPENNOT 14
#define W_R2_MERGEPEN 15
#define W_R2_WHITE 16
#define W_TA_NOUPDATECP 0x0000
#define W_TA_UPDATECP 0x0001
#define W_TA_LEFT 0x0000
#define W_TA_RIGHT 0x0002
#define W_TA_CENTER 0x0006
#define W_TA_TOP 0x0000
#define W_TA_BOTTOM 0x0008
#define W_TA_BASELINE 0x0018
#define W_TA_RTLREADING 0x0100
#define W_SRCCOPY 0x00CC0020L
#define W_SRCPAINT 0x00EE0086L
#define W_SRCAND 0x008800C6L
#define W_SRCINVERT 0x00660046L
#define W_SRCERASE 0x00440328L
#define W_NOTSRCCOPY 0x00330008L
#define W_NOTSRCERASE 0x001100A6L
#define W_MERGECOPY 0x00C000CAL
#define W_MERGEPAINT 0x00BB0226L
#define W_PATCOPY 0x00F00021L
#define W_PATPAINT 0x00FB0A09L
#define W_PATINVERT 0x005A0049L
#define W_DSTINVERT 0x00550009L
#define W_BLACKNESS 0x00000042L
#define W_WHITENESS 0x00FF0062L
#define W_PS_SOLID 0
#define W_PS_DASH 1
#define W_PS_DOT 2
#define W_PS_DASHDOT 3
#define W_PS_DASHDOTDOT 4
#define W_PS_NULL 5
#define W_PS_INSIDEFRAME 6
#define W_LF_FACESIZE 32
#define W_ANSI_CHARSET 0
#define W_DEFAULT_CHARSET 1
#define W_SYMBOL_CHARSET 2
#define W_SHIFTJIS_CHARSET 128
#define W_HANGEUL_CHARSET 129
#define W_GB2312_CHARSET 134
#define W_CHINESEBIG5_CHARSET 136
#define W_OEM_CHARSET 255
/*WINVER >= 0x0400*/
#define W_JOHAB_CHARSET 130
#define W_HEBREW_CHARSET 177
#define W_ARABIC_CHARSET 178
#define W_GREEK_CHARSET 161
#define W_TURKISH_CHARSET 162
#define W_VIETNAMESE_CHARSET 163
#define W_THAI_CHARSET 222
#define W_EASTEUROPE_CHARSET 238
#define W_RUSSIAN_CHARSET 204
#define W_MAC_CHARSET 77
#define W_BALTIC_CHARSET 186
#define W_DEFAULT_PITCH 0x00
#define W_FIXED_PITCH 0x01
#define W_VARIABLE_PITCH 0x02
#define W_FF_DONTCARE 0x00
#define W_FF_ROMAN 0x10
#define W_FF_SWISS 0x20
#define W_FF_MODERN 0x30
#define W_FF_SCRIPT 0x40
#define W_FF_DECORATIVE 0x50
#define W_FW_DONTCARE 0
#define W_FW_THIN 100
#define W_FW_EXTRALIGHT 200
#define W_FW_LIGHT 300
#define W_FW_NORMAL 400
#define W_FW_MEDIUM 500
#define W_FW_SEMIBOLD 600
#define W_FW_BOLD 700
#define W_FW_EXTRABOLD 800
#define W_FW_HEAVY 900
#define W_FW_ULTRALIGHT 200
#define W_FW_REGULAR 400
#define W_FW_DEMIBOLD 600
#define W_FW_ULTRABOLD 800
#define W_FW_BLACK 900
#define W_BS_SOLID 0
#define W_BS_HOLLOW 1
#define W_BS_HATCHED 2
#define W_BS_PATTERN 3
#define W_BS_INDEXED 4
#define W_BS_DIBPATTERN 5
#define W_HS_HORIZONTAL 0
#define W_HS_VERTICAL 1
#define W_HS_FDIAGONAL 2
#define W_HS_BDIAGONAL 3
#define W_HS_CROSS 4
#define W_HS_DIAGCROSS 5
#define W_MFCOMMENT 15
#define PRIVATE_ESCAPE_UNICODE 2
/// copied from writerwordglue.cxx
/*
Utility to categorize unicode characters into the best fit windows charset
range for exporting to ww6, or as a hint to non \u unicode token aware rtf
readers
*/
rtl_TextEncoding getScriptClass(sal_Unicode cChar)
{
using namespace com::sun::star::i18n;
static ScriptTypeList aScripts[] =
{
{ UnicodeScript_kBasicLatin, UnicodeScript_kBasicLatin, RTL_TEXTENCODING_MS_1252},
{ UnicodeScript_kLatin1Supplement, UnicodeScript_kLatin1Supplement, RTL_TEXTENCODING_MS_1252},
{ UnicodeScript_kLatinExtendedA, UnicodeScript_kLatinExtendedA, RTL_TEXTENCODING_MS_1250},
{ UnicodeScript_kLatinExtendedB, UnicodeScript_kLatinExtendedB, RTL_TEXTENCODING_MS_1257},
{ UnicodeScript_kGreek, UnicodeScript_kGreek, RTL_TEXTENCODING_MS_1253},
{ UnicodeScript_kCyrillic, UnicodeScript_kCyrillic, RTL_TEXTENCODING_MS_1251},
{ UnicodeScript_kHebrew, UnicodeScript_kHebrew, RTL_TEXTENCODING_MS_1255},
{ UnicodeScript_kArabic, UnicodeScript_kArabic, RTL_TEXTENCODING_MS_1256},
{ UnicodeScript_kThai, UnicodeScript_kThai, RTL_TEXTENCODING_MS_1258},
{ UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, RTL_TEXTENCODING_MS_1252}
};
return unicode::getUnicodeScriptType(cChar, aScripts,
RTL_TEXTENCODING_MS_1252);
}
//========================== Methoden von WMFWriter ==========================
void WMFWriter::MayCallback()
{
if ( xStatusIndicator.is() )
{
sal_uLong nPercent;
// Wir gehen mal einfach so davon aus, dass 16386 Actions einer Bitmap entsprechen
// (in der Regel wird ein Metafile entweder nur Actions oder einige Bitmaps und fast
// keine Actions enthalten. Dann ist das Verhaeltnis ziemlich unwichtig)
nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions)
*100
/((nNumberOfBitmaps<<14)+nNumberOfActions);
if ( nPercent >= nLastPercent + 3 )
{
nLastPercent = nPercent;
if( nPercent <= 100 )
xStatusIndicator->setValue( nPercent );
}
}
}
void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF )
{
sal_uLong nAction, nActionCount;
nActionCount = rMTF.GetActionCount();
for ( nAction=0; nAction<nActionCount; nAction++ )
{
MetaAction* pMA = rMTF.GetAction( nAction );
switch( pMA->GetType() )
{
case META_BMP_ACTION:
case META_BMPSCALE_ACTION:
case META_BMPSCALEPART_ACTION:
case META_BMPEX_ACTION:
case META_BMPEXSCALE_ACTION:
case META_BMPEXSCALEPART_ACTION:
nNumberOfBitmaps++;
break;
}
nNumberOfActions++;
}
}
void WMFWriter::WritePointXY(const Point & rPoint)
{
Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
*pWMF << ((short)aPt.X()) << ((short)aPt.Y());
}
void WMFWriter::WritePointYX(const Point & rPoint)
{
Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
*pWMF << ((short)aPt.Y()) << ((short)aPt.X());
}
sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX )
{
Size aSz( pVirDev->LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) );
return aSz.Width();
}
void WMFWriter::WriteSize(const Size & rSize)
{
Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
*pWMF << ((short)aSz.Width()) << ((short)aSz.Height());
}
void WMFWriter::WriteHeightWidth(const Size & rSize)
{
Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
*pWMF << ((short)aSz.Height()) << ((short)aSz.Width());
}
void WMFWriter::WriteRectangle(const Rectangle & rRect)
{
WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1));
WritePointYX(rRect.TopLeft());
}
void WMFWriter::WriteColor(const Color & rColor)
{
*pWMF << (sal_uInt8) rColor.GetRed() << (sal_uInt8) rColor.GetGreen() << (sal_uInt8) rColor.GetBlue() << (sal_uInt8) 0;
}
void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType)
{
nActRecordPos=pWMF->Tell();
if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords;
*pWMF << nSizeWords << nType;
}
void WMFWriter::UpdateRecordHeader()
{
sal_uLong nPos;
sal_uInt32 nSize;
nPos=pWMF->Tell(); nSize=nPos-nActRecordPos;
if ((nSize & 1)!=0) {
*pWMF << (sal_uInt8)0;
nPos++; nSize++;
}
nSize/=2;
if (nSize>nMaxRecordSize) nMaxRecordSize=nSize;
pWMF->Seek(nActRecordPos);
*pWMF << nSize;
pWMF->Seek(nPos);
}
void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
{
WriteRecordHeader(0x0000000b,W_META_ARC);
WritePointYX(rEndPt);
WritePointYX(rStartPt);
WriteRectangle(rRect);
}
void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
{
WriteRecordHeader(0x0000000b,W_META_CHORD);
WritePointYX(rEndPt);
WritePointYX(rStartPt);
WriteRectangle(rRect);
}
void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor)
{
WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT);
if( rColor==Color(COL_TRANSPARENT) )
*pWMF << (sal_uInt16) W_BS_HOLLOW;
else
*pWMF << (sal_uInt16) W_BS_SOLID;
WriteColor( rColor );
*pWMF << (sal_uInt16) 0;
}
void WMFWriter::WMFRecord_CreateFontIndirect(const Font & rFont)
{
sal_uInt16 nWeight,i;
sal_uInt8 nPitchFamily;
WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT);
WriteHeightWidth(Size(rFont.GetSize().Width(),-rFont.GetSize().Height()));
*pWMF << (short)rFont.GetOrientation() << (short)rFont.GetOrientation();
switch (rFont.GetWeight()) {
case WEIGHT_THIN: nWeight=W_FW_THIN; break;
case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break;
case WEIGHT_LIGHT: nWeight=W_FW_LIGHT; break;
case WEIGHT_SEMILIGHT: nWeight=W_FW_LIGHT; break;
case WEIGHT_NORMAL: nWeight=W_FW_NORMAL; break;
case WEIGHT_MEDIUM: nWeight=W_FW_MEDIUM; break;
case WEIGHT_SEMIBOLD: nWeight=W_FW_SEMIBOLD; break;
case WEIGHT_BOLD: nWeight=W_FW_BOLD; break;
case WEIGHT_ULTRABOLD: nWeight=W_FW_ULTRABOLD; break;
case WEIGHT_BLACK: nWeight=W_FW_BLACK; break;
default: nWeight=W_FW_DONTCARE;
}
*pWMF << nWeight;
if (rFont.GetItalic()==ITALIC_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1;
if (rFont.GetUnderline()==UNDERLINE_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1;
if (rFont.GetStrikeout()==STRIKEOUT_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1;
CharSet eFontNameEncoding = rFont.GetCharSet();
sal_uInt8 nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding );
if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL )
eFontNameEncoding = RTL_TEXTENCODING_MS_1252;
if ( nCharSet == 1 )
nCharSet = W_ANSI_CHARSET;
*pWMF << nCharSet;
*pWMF << (sal_uInt8)0 << (sal_uInt8)0 << (sal_uInt8)0;
switch (rFont.GetPitch()) {
case PITCH_FIXED: nPitchFamily=W_FIXED_PITCH; break;
case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break;
default: nPitchFamily=W_DEFAULT_PITCH;
}
switch (rFont.GetFamily()) {
case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break;
case FAMILY_MODERN: nPitchFamily|=W_FF_MODERN; break;
case FAMILY_ROMAN: nPitchFamily|=W_FF_ROMAN; break;
case FAMILY_SCRIPT: nPitchFamily|=W_FF_SCRIPT; break;
case FAMILY_SWISS: nPitchFamily|=W_FF_SWISS; break;
default: nPitchFamily|=W_FF_DONTCARE;
}
*pWMF << nPitchFamily;
ByteString aFontName( rFont.GetName(), eFontNameEncoding );
for ( i = 0; i < W_LF_FACESIZE; i++ )
{
sal_Char nChar = ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0;
*pWMF << nChar;
}
UpdateRecordHeader();
}
void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo )
{
WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT);
sal_uInt16 nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID;
switch( rLineInfo.GetStyle() )
{
case LINE_DASH :
{
if ( rLineInfo.GetDotCount() )
{
if ( !rLineInfo.GetDashCount() )
nStyle = W_PS_DOT;
else
{
if ( !rLineInfo.GetDotCount() == 1 )
nStyle = W_PS_DASHDOT;
else
nStyle = W_PS_DASHDOTDOT;
}
}
else
nStyle = W_PS_DASH;
}
break;
case LINE_NONE :
nStyle = W_PS_NULL;
break;
default:
break;
}
*pWMF << nStyle;
WriteSize( Size( rLineInfo.GetWidth(), 0 ) );
WriteColor( rColor );
}
void WMFWriter::WMFRecord_DeleteObject(sal_uInt16 nObjectHandle)
{
WriteRecordHeader(0x00000004,W_META_DELETEOBJECT);
*pWMF << nObjectHandle;
}
void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect)
{
WriteRecordHeader(0x00000007,W_META_ELLIPSE);
WriteRectangle(rRect);
}
bool IsStarSymbol(const String &rStr)
{
return rStr.EqualsIgnoreCaseAscii("starsymbol") ||
rStr.EqualsIgnoreCaseAscii("opensymbol");
}
void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData )
{
#ifdef OSL_BIGENDIAN
sal_uInt32 nTmp = SWAPLONG( nEsc );
sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
#else
sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
#endif
if ( nLen )
nCheckSum = rtl_crc32( nCheckSum, pData, nLen );
WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE );
*pWMF << (sal_uInt16)W_MFCOMMENT
<< (sal_uInt16)( nLen + 14 ) // we will always have a fourteen byte escape header:
<< (sal_uInt16)0x4f4f // OO
<< (sal_uInt32)0xa2c2a // evil magic number
<< (sal_uInt32)nCheckSum // crc32 checksum about nEsc & pData
<< (sal_uInt32)nEsc; // escape number
pWMF->Write( pData, nLen );
if ( nLen & 1 )
*pWMF << (sal_uInt8)0; // pad byte
}
/* if return value is true, then a complete unicode string and also a polygon replacement has been written,
so there is no more action necessary
*/
sal_Bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const String& rUniStr, const sal_Int32* pDXAry )
{
sal_Bool bEscapeUsed = sal_False;
sal_uInt32 i, nStringLen = rUniStr.Len();
if ( nStringLen )
{
// first we will check if a comment is necessary
if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) // symbol is always byte character, so there is no unicode loss
{
const sal_Unicode* pBuf = rUniStr.GetBuffer();
const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet();
ByteString aByteStr( rUniStr, aTextEncodingOrg );
String aUniStr2( aByteStr, aTextEncodingOrg );
const sal_Unicode* pConversion = aUniStr2.GetBuffer(); // this is the unicode array after bytestring <-> unistring conversion
for ( i = 0; i < nStringLen; i++ )
{
if ( *pBuf++ != *pConversion++ )
break;
}
if ( i != nStringLen ) // after conversion the characters are not original,
{ // try again, with determining a better charset from unicode char
pBuf = rUniStr.GetBuffer();
const sal_Unicode* pCheckChar = pBuf;
rtl_TextEncoding aTextEncoding = getScriptClass (*pCheckChar); // try the first character
for ( i = 1; i < nStringLen; i++)
{
if (aTextEncoding != aTextEncodingOrg) // found something
break;
pCheckChar++;
aTextEncoding = getScriptClass (*pCheckChar); // try the next character
}
aByteStr = ByteString ( rUniStr, aTextEncoding );
aUniStr2 = String ( aByteStr, aTextEncoding );
pConversion = aUniStr2.GetBuffer(); // this is the unicode array after bytestring <-> unistring conversion
for ( i = 0; i < nStringLen; i++ )
{
if ( *pBuf++ != *pConversion++ )
break;
}
if (i == nStringLen)
{
aSrcFont.SetCharSet (aTextEncoding);
SetAllAttr();
}
}
if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetName() ) ) // after conversion the characters are not original, so we
{ // will store the unicode string and a polypoly replacement
Color aOldFillColor( aSrcFillColor );
Color aOldLineColor( aSrcLineColor );
aSrcLineInfo = LineInfo();
aSrcFillColor = aSrcTextColor;
aSrcLineColor = Color( COL_TRANSPARENT );
SetLineAndFillAttr();
pVirDev->SetFont( aSrcFont );
std::vector<PolyPolygon> aPolyPolyVec;
if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) )
{
sal_uInt32 nDXCount = pDXAry ? nStringLen : 0;
sal_uInt32 nSkipActions = aPolyPolyVec.size();
sal_Int32 nStrmLen = 8 +
+ sizeof( nStringLen ) + ( nStringLen * 2 )
+ sizeof( nDXCount ) + ( nDXCount * 4 )
+ sizeof( nSkipActions );
SvMemoryStream aMemoryStream( nStrmLen );
Point aPt( pVirDev->LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) );
aMemoryStream << aPt.X()
<< aPt.Y()
<< nStringLen;
for ( i = 0; i < nStringLen; i++ )
aMemoryStream << rUniStr.GetChar( (sal_uInt16)i );
aMemoryStream << nDXCount;
for ( i = 0; i < nDXCount; i++ )
aMemoryStream << pDXAry[ i ];
aMemoryStream << nSkipActions;
WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, (const sal_Int8*)aMemoryStream.GetData() );
std::vector<PolyPolygon>::iterator aIter( aPolyPolyVec.begin() );
while ( aIter != aPolyPolyVec.end() )
{
PolyPolygon aPolyPoly( *aIter++ );
aPolyPoly.Move( rPoint.X(), rPoint.Y() );
WMFRecord_PolyPolygon( aPolyPoly );
}
aSrcFillColor = aOldFillColor;
aSrcLineColor = aOldLineColor;
bEscapeUsed = sal_True;
}
}
}
}
return bEscapeUsed;
}
void WMFWriter::WMFRecord_ExtTextOut( const Point & rPoint,
const String & rString, const sal_Int32 * pDXAry )
{
sal_uInt16 nOriginalTextLen = rString.Len();
if ( (nOriginalTextLen <= 1) || (pDXAry == NULL) )
{
WMFRecord_TextOut(rPoint, rString);
return;
}
rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
ByteString aByteString(rString, eChrSet);
TrueExtTextOut(rPoint,rString,aByteString,pDXAry);
}
void WMFWriter::TrueExtTextOut( const Point & rPoint, const String & rString,
const ByteString & rByteString, const sal_Int32 * pDXAry )
{
WriteRecordHeader( 0, W_META_EXTTEXTOUT );
WritePointYX( rPoint );
sal_uInt16 nNewTextLen = rByteString.Len();
*pWMF << nNewTextLen << (sal_uInt16)0;
sal_uInt16 i;
for ( i = 0; i < nNewTextLen; i++ )
*pWMF << (sal_uInt8)rByteString.GetChar( i );
if ( nNewTextLen & 1 )
*pWMF << (sal_uInt8)0;
sal_uInt16 nOriginalTextLen = rString.Len();
sal_Int16* pConvertedDXAry = new sal_Int16[ nOriginalTextLen ];
sal_Int32 j = 0;
pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] );
for ( i = 1; i < ( nOriginalTextLen - 1 ); i++ )
pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] );
pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) );
for ( i = 0; i < nOriginalTextLen; i++ )
{
sal_Int16 nDx = pConvertedDXAry[ i ];
*pWMF << nDx;
if ( nOriginalTextLen < nNewTextLen )
{
ByteString aTemp( rString.GetChar( i ), aSrcFont.GetCharSet());
j = aTemp.Len();
while ( --j > 0 )
*pWMF << (sal_uInt16)0;
}
}
delete[] pConvertedDXAry;
UpdateRecordHeader();
}
void WMFWriter::WMFRecord_LineTo(const Point & rPoint)
{
WriteRecordHeader(0x00000005,W_META_LINETO);
WritePointYX(rPoint);
}
void WMFWriter::WMFRecord_MoveTo(const Point & rPoint)
{
WriteRecordHeader(0x00000005,W_META_MOVETO);
WritePointYX(rPoint);
}
void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
{
WriteRecordHeader(0x0000000b,W_META_PIE);
WritePointYX(rEndPt);
WritePointYX(rStartPt);
WriteRectangle(rRect);
}
void WMFWriter::WMFRecord_Polygon(const Polygon & rPoly)
{
sal_uInt16 nSize,i;
Polygon aSimplePoly;
if ( rPoly.HasFlags() )
rPoly.AdaptiveSubdivide( aSimplePoly );
else
aSimplePoly = rPoly;
nSize = aSimplePoly.GetSize();
WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYGON);
*pWMF << nSize;
for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
}
void WMFWriter::WMFRecord_PolyLine(const Polygon & rPoly)
{
sal_uInt16 nSize,i;
Polygon aSimplePoly;
if ( rPoly.HasFlags() )
rPoly.AdaptiveSubdivide( aSimplePoly );
else
aSimplePoly = rPoly;
nSize=aSimplePoly.GetSize();
WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYLINE);
*pWMF << nSize;
for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
}
void WMFWriter::WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly)
{
const Polygon * pPoly;
sal_uInt16 nCount,nSize,i,j;
nCount=rPolyPoly.Count();
PolyPolygon aSimplePolyPoly( rPolyPoly );
for ( i = 0; i < nCount; i++ )
{
if ( aSimplePolyPoly[ i ].HasFlags() )
{
Polygon aSimplePoly;
aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
aSimplePolyPoly[ i ] = aSimplePoly;
}
}
WriteRecordHeader(0,W_META_POLYPOLYGON);
*pWMF << nCount;
for (i=0; i<nCount; i++) *pWMF << ((sal_uInt16)(aSimplePolyPoly.GetObject(i).GetSize()));
for (i=0; i<nCount; i++) {
pPoly=&(aSimplePolyPoly.GetObject(i));
nSize=pPoly->GetSize();
for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j));
}
UpdateRecordHeader();
}
void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect)
{
WriteRecordHeader( 0x00000007,W_META_RECTANGLE );
WriteRectangle( rRect );
}
void WMFWriter::WMFRecord_RestoreDC()
{
WriteRecordHeader(0x00000004,W_META_RESTOREDC);
*pWMF << (short)-1;
}
void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound)
{
WriteRecordHeader(0x00000009,W_META_ROUNDRECT);
WriteHeightWidth(Size(nHorzRound,nVertRound));
WriteRectangle(rRect);
}
void WMFWriter::WMFRecord_SaveDC()
{
WriteRecordHeader(0x00000003,W_META_SAVEDC);
}
void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle)
{
WriteRecordHeader(0x00000004,W_META_SELECTOBJECT);
*pWMF << nObjectHandle;
}
void WMFWriter::WMFRecord_SetBkColor(const Color & rColor)
{
WriteRecordHeader(0x00000005,W_META_SETBKCOLOR);
WriteColor(rColor);
}
void WMFWriter::WMFRecord_SetBkMode(sal_Bool bTransparent)
{
WriteRecordHeader(0x00000004,W_META_SETBKMODE);
if (bTransparent==sal_True) *pWMF << (sal_uInt16)W_TRANSPARENT;
else *pWMF << (sal_uInt16)W_OPAQUE;
}
void WMFWriter::WMFRecord_SetStretchBltMode()
{
WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE );
*pWMF << (sal_uInt16) 3; // STRETCH_DELETESCANS
}
void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor)
{
WriteRecordHeader(0x00000007,W_META_SETPIXEL);
WriteColor(rColor);
WritePointYX(rPoint);
}
void WMFWriter::WMFRecord_SetROP2(RasterOp eROP)
{
sal_uInt16 nROP2;
switch (eROP) {
case ROP_INVERT: nROP2=W_R2_NOT; break;
case ROP_XOR: nROP2=W_R2_XORPEN; break;
default: nROP2=W_R2_COPYPEN;
}
WriteRecordHeader(0x00000004,W_META_SETROP2);
*pWMF << nROP2;
}
void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt32 eHorTextAlign)
{
sal_uInt16 nAlign;
switch (eFontAlign) {
case ALIGN_TOP: nAlign=W_TA_TOP; break;
case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break;
default: nAlign=W_TA_BASELINE;
}
nAlign|=eHorTextAlign;
nAlign|=W_TA_NOUPDATECP;
WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN);
*pWMF << nAlign;
}
void WMFWriter::WMFRecord_SetTextColor(const Color & rColor)
{
WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR);
WriteColor(rColor);
}
void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize)
{
WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT);
WriteHeightWidth(rSize);
}
void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint)
{
WriteRecordHeader(0x00000005,W_META_SETWINDOWORG);
WritePointYX(rPoint);
}
void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize,
const Bitmap & rBitmap, sal_uInt32 nROP )
{
sal_uLong nPosAnf,nPosEnd;
nActBitmapPercent=50;
MayCallback();
WriteRecordHeader(0x00000000,W_META_STRETCHDIB);
// Die Reihenfolge im Metafile soll jetzt sein:
// einige Parameter (laenge 22), dann die Bitmap ohne FILEHEADER.
// Da aber *pWMF << rBitmap einen FILEHEADER der Laenge 14
// erzeugt, schreiben wir zuerst die Bitmap an die richtige Position
// Und ueberschreiben hinterher den FILEHEADER mit den Parametern.
nPosAnf=pWMF->Tell(); // Position merken, wo Parameter hin sollen
*pWMF << (long)0 << (long)0; // 8 bytes auffuellen (diese 8 bytes +
// 14 bytes ueberfluessigen FILEHEADER
// = 22 bytes Parameter)
// write bitmap
WriteDIB(rBitmap, *pWMF, false, true);
// Parameter schreiben:
nPosEnd=pWMF->Tell();
pWMF->Seek(nPosAnf);
// Raster-Op bestimmen, falls nichts uebergeben wurde
if( !nROP )
{
switch( eSrcRasterOp )
{
case ROP_INVERT: nROP = W_DSTINVERT; break;
case ROP_XOR: nROP = W_SRCINVERT; break;
default: nROP = W_SRCCOPY;
}
}
*pWMF << nROP <<
(short) 0 <<
(short) rBitmap.GetSizePixel().Height() <<
(short) rBitmap.GetSizePixel().Width() <<
(short) 0 <<
(short) 0;
WriteHeightWidth(rSize);
WritePointYX(rPoint);
pWMF->Seek(nPosEnd);
UpdateRecordHeader();
nWrittenBitmaps++;
nActBitmapPercent=0;
}
void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const String & rStr)
{
rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
ByteString aString( rStr, eChrSet );
TrueTextOut(rPoint, aString);
}
void WMFWriter::TrueTextOut(const Point & rPoint, const ByteString& rString)
{
sal_uInt16 nLen,i;
WriteRecordHeader(0,W_META_TEXTOUT);
nLen=rString.Len();
*pWMF << nLen;
for ( i = 0; i < nLen; i++ )
*pWMF << (sal_uInt8)rString.GetChar( i );
if ((nLen&1)!=0) *pWMF << (sal_uInt8)0;
WritePointYX(rPoint);
UpdateRecordHeader();
}
void WMFWriter::WMFRecord_EndOfFile()
{
WriteRecordHeader(0x00000003,0x0000);
}
void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect )
{
WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT );
WriteRectangle(rRect);
}
sal_uInt16 WMFWriter::AllocHandle()
{
sal_uInt16 i;
for (i=0; i<MAXOBJECTHANDLES; i++) {
if (bHandleAllocated[i]==sal_False) {
bHandleAllocated[i]=sal_True;
return i;
}
}
bStatus=sal_False;
return 0xffff;
}
void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle)
{
if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=sal_False;
}
void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo )
{
sal_uInt16 nOldHandle;
nOldHandle=nDstPenHandle;
nDstPenHandle=AllocHandle();
WMFRecord_CreatePenIndirect( rColor, rLineInfo );
WMFRecord_SelectObject(nDstPenHandle);
if (nOldHandle<MAXOBJECTHANDLES) {
WMFRecord_DeleteObject(nOldHandle);
FreeHandle(nOldHandle);
}
}
void WMFWriter::CreateSelectDeleteFont(const Font & rFont)
{
sal_uInt16 nOldHandle;
nOldHandle=nDstFontHandle;
nDstFontHandle=AllocHandle();
WMFRecord_CreateFontIndirect(rFont);
WMFRecord_SelectObject(nDstFontHandle);
if (nOldHandle<MAXOBJECTHANDLES) {
WMFRecord_DeleteObject(nOldHandle);
FreeHandle(nOldHandle);
}
}
void WMFWriter::CreateSelectDeleteBrush(const Color& rColor)
{
sal_uInt16 nOldHandle;
nOldHandle=nDstBrushHandle;
nDstBrushHandle=AllocHandle();
WMFRecord_CreateBrushIndirect(rColor);
WMFRecord_SelectObject(nDstBrushHandle);
if (nOldHandle<MAXOBJECTHANDLES) {
WMFRecord_DeleteObject(nOldHandle);
FreeHandle(nOldHandle);
}
}
void WMFWriter::SetLineAndFillAttr()
{
if ( eDstROP2 != eSrcRasterOp )
{
eDstROP2=eSrcRasterOp;
WMFRecord_SetROP2(eDstROP2);
}
if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) )
{
aDstLineColor = aSrcLineColor;
aDstLineInfo = aSrcLineInfo;
CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
}
if ( aDstFillColor != aSrcFillColor )
{
aDstFillColor = aSrcFillColor;
CreateSelectDeleteBrush( aDstFillColor );
}
if ( bDstIsClipping != bSrcIsClipping ||
(bSrcIsClipping==sal_True && aDstClipRegion!=aSrcClipRegion)) {
bDstIsClipping=bSrcIsClipping;
aDstClipRegion=aSrcClipRegion;
}
}
void WMFWriter::SetAllAttr()
{
SetLineAndFillAttr();
if ( aDstTextColor != aSrcTextColor )
{
aDstTextColor = aSrcTextColor;
WMFRecord_SetTextColor(aDstTextColor);
}
if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign )
{
eDstTextAlign = eSrcTextAlign;
eDstHorTextAlign = eSrcHorTextAlign;
WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
}
if ( aDstFont != aSrcFont )
{
pVirDev->SetFont(aSrcFont);
if ( aDstFont.GetName() != aSrcFont.GetName() )
{
FontCharMap aFontCharMap;
if ( pVirDev->GetFontCharMap( aFontCharMap ) )
{
if ( ( aFontCharMap.GetFirstChar() & 0xff00 ) == 0xf000 )
aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
}
}
aDstFont = aSrcFont;
CreateSelectDeleteFont(aDstFont);
}
}
void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
{
if(rLinePolygon.count())
{
basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
basegfx::B2DPolyPolygon aFillPolyPolygon;
rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
if(aLinePolyPolygon.count())
{
aSrcLineInfo = rInfo;
SetLineAndFillAttr();
for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
{
const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
WMFRecord_PolyLine(Polygon(aCandidate));
}
}
if(aFillPolyPolygon.count())
{
const Color aOldLineColor(aSrcLineColor);
const Color aOldFillColor(aSrcFillColor);
aSrcLineColor = Color( COL_TRANSPARENT );
aSrcFillColor = aOldLineColor;
SetLineAndFillAttr();
for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
{
const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
WMFRecord_Polygon(Polygon(aPolygon));
}
aSrcLineColor = aOldLineColor;
aSrcFillColor = aOldFillColor;
SetLineAndFillAttr();
}
}
}
void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
{
sal_uLong nA, nACount;
MetaAction* pMA;
if( bStatus )
{
nACount = rMTF.GetActionCount();
WMFRecord_SetStretchBltMode();
for( nA=0; nA<nACount; nA++ )
{
pMA = rMTF.GetAction( nA );
switch( pMA->GetType() )
{
case META_PIXEL_ACTION:
{
const MetaPixelAction* pA = (const MetaPixelAction *) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() );
}
break;
case META_POINT_ACTION:
{
const MetaPointAction* pA = (const MetaPointAction*) pMA;
const Point& rPt = pA->GetPoint();
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_MoveTo( rPt);
WMFRecord_LineTo( rPt );
}
break;
case META_LINE_ACTION:
{
const MetaLineAction* pA = (const MetaLineAction *) pMA;
if(pA->GetLineInfo().IsDefault())
{
aSrcLineInfo = pA->GetLineInfo();
SetLineAndFillAttr();
WMFRecord_MoveTo( pA->GetStartPoint() );
WMFRecord_LineTo( pA->GetEndPoint() );
}
else
{
// LineInfo used; handle Dash/Dot and fat lines
basegfx::B2DPolygon aPolygon;
aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
}
}
break;
case META_RECT_ACTION:
{
const MetaRectAction* pA = (const MetaRectAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Rectangle( pA->GetRect() );
}
break;
case META_ROUNDRECT_ACTION:
{
const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
}
break;
case META_ELLIPSE_ACTION:
{
const MetaEllipseAction* pA = (const MetaEllipseAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Ellipse( pA->GetRect() );
}
break;
case META_ARC_ACTION:
{
const MetaArcAction* pA = (const MetaArcAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() );
}
break;
case META_PIE_ACTION:
{
const MetaPieAction* pA = (const MetaPieAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
}
break;
case META_CHORD_ACTION:
{
const MetaChordAction* pA = (const MetaChordAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
}
break;
case META_POLYLINE_ACTION:
{
const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA;
const Polygon& rPoly = pA->GetPolygon();
if( rPoly.GetSize() )
{
if(pA->GetLineInfo().IsDefault())
{
aSrcLineInfo = pA->GetLineInfo();
SetLineAndFillAttr();
WMFRecord_PolyLine( rPoly );
}
else
{
// LineInfo used; handle Dash/Dot and fat lines
HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
}
}
}
break;
case META_POLYGON_ACTION:
{
const MetaPolygonAction* pA = (const MetaPolygonAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Polygon( pA->GetPolygon() );
}
break;
case META_POLYPOLYGON_ACTION:
{
const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pMA;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_PolyPolygon( pA->GetPolyPolygon() );
}
break;
case META_TEXTRECT_ACTION:
{
const MetaTextRectAction * pA = (const MetaTextRectAction*)pMA;
String aTemp( pA->GetText() );
aSrcLineInfo = LineInfo();
SetAllAttr();
Point aPos( pA->GetRect().TopLeft() );
if ( !WMFRecord_Escape_Unicode( aPos, aTemp, NULL ) )
WMFRecord_TextOut( aPos, aTemp );
}
break;
case META_TEXT_ACTION:
{
const MetaTextAction * pA = (const MetaTextAction*) pMA;
String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
aSrcLineInfo = LineInfo();
SetAllAttr();
if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, NULL ) )
WMFRecord_TextOut( pA->GetPoint(), aTemp );
}
break;
case META_TEXTARRAY_ACTION:
{
const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pMA;
String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
aSrcLineInfo = LineInfo();
SetAllAttr();
if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) )
WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() );
}
break;
case META_STRETCHTEXT_ACTION:
{
const MetaStretchTextAction* pA = (const MetaStretchTextAction *) pMA;
String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
sal_uInt16 nLen,i;
sal_Int32 nNormSize;
pVirDev->SetFont( aSrcFont );
nLen = aTemp.Len();
sal_Int32* pDXAry = nLen ? new sal_Int32[ nLen ] : NULL;
nNormSize = pVirDev->GetTextArray( aTemp, pDXAry );
for ( i = 0; i < ( nLen - 1 ); i++ )
pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize;
if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) )
delete[] pDXAry, pDXAry = NULL;
aSrcLineInfo = LineInfo();
SetAllAttr();
if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry ) )
WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry );
delete[] pDXAry;
}
break;
case META_BMP_ACTION:
{
const MetaBmpAction* pA = (const MetaBmpAction *) pMA;
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() );
}
break;
case META_BMPSCALE_ACTION:
{
const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pMA;
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() );
}
break;
case META_BMPSCALEPART_ACTION:
{
const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pMA;
Bitmap aTmp( pA->GetBitmap() );
if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp );
}
break;
case META_BMPEX_ACTION:
{
const MetaBmpExAction* pA = (const MetaBmpExAction *) pMA;
Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
Bitmap aMsk( pA->GetBitmapEx().GetMask() );
if( !!aMsk )
{
aBmp.Replace( aMsk, COL_WHITE );
aMsk.Invert();
WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
}
else
WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp );
}
break;
case META_BMPEXSCALE_ACTION:
{
const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pMA;
Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
Bitmap aMsk( pA->GetBitmapEx().GetMask() );
if( !!aMsk )
{
aBmp.Replace( aMsk, COL_WHITE );
aMsk.Invert();
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
}
else
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp );
}
break;
case META_BMPEXSCALEPART_ACTION:
{
const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pMA;
BitmapEx aBmpEx( pA->GetBitmapEx() );
aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
Bitmap aBmp( aBmpEx.GetBitmap() );
Bitmap aMsk( aBmpEx.GetMask() );
if( !!aMsk )
{
aBmp.Replace( aMsk, COL_WHITE );
aMsk.Invert();
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
}
else
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp );
}
break;
case META_GRADIENT_ACTION:
{
const MetaGradientAction* pA = (const MetaGradientAction*) pMA;
GDIMetaFile aTmpMtf;
pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
WriteRecords( aTmpMtf );
}
break;
case META_HATCH_ACTION:
{
const MetaHatchAction* pA = (const MetaHatchAction*) pMA;
GDIMetaFile aTmpMtf;
pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
WriteRecords( aTmpMtf );
}
break;
case META_WALLPAPER_ACTION:
{
const MetaWallpaperAction* pA = (const MetaWallpaperAction*) pMA;
const Color& rColor = pA->GetWallpaper().GetColor();
const Color aOldLineColor( aSrcLineColor );
const Color aOldFillColor( aSrcFillColor );
aSrcLineColor = rColor;
aSrcFillColor = rColor;
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_Rectangle( pA->GetRect() );
aSrcLineColor = aOldLineColor;
aSrcFillColor = aOldFillColor;
}
break;
case META_ISECTRECTCLIPREGION_ACTION:
{
const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA;
WMFRecord_IntersectClipRect( pA->GetRect() );
}
break;
case META_LINECOLOR_ACTION:
{
const MetaLineColorAction* pA = (const MetaLineColorAction*) pMA;
if( pA->IsSetting() )
aSrcLineColor = pA->GetColor();
else
aSrcLineColor = Color( COL_TRANSPARENT );
}
break;
case META_FILLCOLOR_ACTION:
{
const MetaFillColorAction* pA = (const MetaFillColorAction*) pMA;
if( pA->IsSetting() )
aSrcFillColor = pA->GetColor();
else
aSrcFillColor = Color( COL_TRANSPARENT );
}
break;
case META_TEXTCOLOR_ACTION:
{
const MetaTextColorAction* pA = (const MetaTextColorAction*) pMA;
aSrcTextColor = pA->GetColor();
}
break;
case META_TEXTFILLCOLOR_ACTION:
{
const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pMA;
if( pA->IsSetting() )
aSrcFont.SetFillColor( pA->GetColor() );
else
aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) );
}
break;
case META_TEXTALIGN_ACTION:
{
const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pMA;
eSrcTextAlign = pA->GetTextAlign();
}
break;
case META_MAPMODE_ACTION:
{
const MetaMapModeAction* pA = (const MetaMapModeAction*) pMA;
if (aSrcMapMode!=pA->GetMapMode())
{
if( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE )
{
MapMode aMM = pA->GetMapMode();
Fraction aScaleX = aMM.GetScaleX();
Fraction aScaleY = aMM.GetScaleY();
Point aOrigin = aSrcMapMode.GetOrigin();
BigInt aX( aOrigin.X() );
aX *= BigInt( aScaleX.GetDenominator() );
if( aOrigin.X() >= 0 )
if( aScaleX.GetNumerator() >= 0 )
aX += BigInt( aScaleX.GetNumerator()/2 );
else
aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
else
if( aScaleX.GetNumerator() >= 0 )
aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
else
aX += BigInt( aScaleX.GetNumerator()/2 );
aX /= BigInt( aScaleX.GetNumerator() );
aOrigin.X() = (long)aX + aMM.GetOrigin().X();
BigInt aY( aOrigin.Y() );
aY *= BigInt( aScaleY.GetDenominator() );
if( aOrigin.Y() >= 0 )
if( aScaleY.GetNumerator() >= 0 )
aY += BigInt( aScaleY.GetNumerator()/2 );
else
aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
else
if( aScaleY.GetNumerator() >= 0 )
aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
else
aY += BigInt( aScaleY.GetNumerator()/2 );
aY /= BigInt( aScaleY.GetNumerator() );
aOrigin.Y() = (long)aY + aMM.GetOrigin().Y();
aSrcMapMode.SetOrigin( aOrigin );
aScaleX *= aSrcMapMode.GetScaleX();
aScaleY *= aSrcMapMode.GetScaleY();
aSrcMapMode.SetScaleX( aScaleX );
aSrcMapMode.SetScaleY( aScaleY );
}
else
aSrcMapMode=pA->GetMapMode();
}
}
break;
case META_FONT_ACTION:
{
const MetaFontAction* pA = (const MetaFontAction*) pMA;
aSrcFont = pA->GetFont();
if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
aSrcFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) );
if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE )
aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
eSrcTextAlign = aSrcFont.GetAlign();
aSrcTextColor = aSrcFont.GetColor();
aSrcFont.SetAlign( ALIGN_BASELINE );
aSrcFont.SetColor( COL_WHITE );
}
break;
case META_PUSH_ACTION:
{
const MetaPushAction* pA = (const MetaPushAction*)pMA;
WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember;
pAt->nFlags = pA->GetFlags();
pAt->aClipRegion = aSrcClipRegion;
pAt->aLineColor=aSrcLineColor;
pAt->aFillColor=aSrcFillColor;
pAt->eRasterOp=eSrcRasterOp;
pAt->aFont=aSrcFont;
pAt->eTextAlign=eSrcTextAlign;
pAt->aTextColor=aSrcTextColor;
pAt->aMapMode=aSrcMapMode;
pAt->aLineInfo=aDstLineInfo;
pAt->pSucc=pAttrStack;
pAttrStack=pAt;
SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
WMFRecord_SaveDC();
}
break;
case META_POP_ACTION:
{
WMFWriterAttrStackMember * pAt=pAttrStack;
if( pAt )
{
aDstLineInfo = pAt->aLineInfo;
aDstLineColor = pAt->aLineColor;
if ( pAt->nFlags & PUSH_LINECOLOR )
aSrcLineColor = pAt->aLineColor;
aDstFillColor = pAt->aFillColor;
if ( pAt->nFlags & PUSH_FILLCOLOR )
aSrcFillColor = pAt->aFillColor;
eDstROP2 = pAt->eRasterOp;
if ( pAt->nFlags & PUSH_RASTEROP )
eSrcRasterOp = pAt->eRasterOp;
aDstFont = pAt->aFont;
if ( pAt->nFlags & PUSH_FONT )
aSrcFont = pAt->aFont;
eDstTextAlign = pAt->eTextAlign;
if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTALIGN ) )
eSrcTextAlign = pAt->eTextAlign;
aDstTextColor = pAt->aTextColor;
if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTCOLOR ) )
aSrcTextColor = pAt->aTextColor;
if ( pAt->nFlags & PUSH_MAPMODE )
aSrcMapMode = pAt->aMapMode;
aDstClipRegion = pAt->aClipRegion;
if ( pAt->nFlags & PUSH_CLIPREGION )
aSrcClipRegion = pAt->aClipRegion;
WMFRecord_RestoreDC();
pAttrStack = pAt->pSucc;
delete pAt;
}
}
break;
case META_EPS_ACTION :
{
const MetaEPSAction* pA = (const MetaEPSAction*)pMA;
const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
sal_Int32 nCount = aGDIMetaFile.GetActionCount();
for ( sal_Int32 i = 0; i < nCount; i++ )
{
const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
if ( pMetaAct->GetType() == META_BMPSCALE_ACTION )
{
const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct;
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() );
break;
}
}
}
break;
case META_RASTEROP_ACTION:
{
const MetaRasterOpAction* pA = (const MetaRasterOpAction*) pMA;
eSrcRasterOp=pA->GetRasterOp();
}
break;
case META_TRANSPARENT_ACTION:
{
aSrcLineInfo = LineInfo();
SetLineAndFillAttr();
WMFRecord_PolyPolygon( ( (MetaTransparentAction*) pMA )->GetPolyPolygon() );
}
break;
case META_FLOATTRANSPARENT_ACTION:
{
const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA;
GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
const Size aSrcSize( aTmpMtf.GetPrefSize() );
const Point aDestPt( pA->GetPoint() );
const Size aDestSize( pA->GetSize() );
const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
long nMoveX, nMoveY;
aSrcLineInfo = LineInfo();
SetAllAttr();
if( fScaleX != 1.0 || fScaleY != 1.0 )
{
aTmpMtf.Scale( fScaleX, fScaleY );
aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
}
nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
if( nMoveX || nMoveY )
aTmpMtf.Move( nMoveX, nMoveY );
WriteRecords( aTmpMtf );
}
break;
case( META_LAYOUTMODE_ACTION ):
{
sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pMA )->GetLayoutMode();
eSrcHorTextAlign = 0; // TA_LEFT
if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL)
{
eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING;
}
if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT)
eSrcHorTextAlign |= W_TA_RIGHT;
else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT)
eSrcHorTextAlign &= ~W_TA_RIGHT;
break;
}
// Unsupported Actions
case META_MASK_ACTION:
case META_MASKSCALE_ACTION:
case META_MASKSCALEPART_ACTION:
{
DBG_ERROR( "Unsupported action: MetaMask...Action!" );
}
break;
case META_CLIPREGION_ACTION:
break;
case META_ISECTREGIONCLIPREGION_ACTION:
{
DBG_ERROR( "Unsupported action: MetaISectRegionClipRegionAction!" );
}
break;
case META_MOVECLIPREGION_ACTION:
{
DBG_ERROR( "Unsupported action: MetaMoveClipRegionAction!" );
}
break;
default:
{
DBG_ERROR( "Unsupported meta action!" );
}
break;
}
nWrittenActions++;
MayCallback();
if (pWMF->GetError())
bStatus=sal_False;
if(bStatus==sal_False)
break;
}
}
}
// ------------------------------------------------------------------------
void WMFWriter::WriteHeader( const GDIMetaFile &, sal_Bool bPlaceable )
{
if( bPlaceable )
{
sal_uInt16 nCheckSum, nValue;
Size aSize( pVirDev->LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) );
sal_uInt16 nUnitsPerInch = (sal_uInt16) ( ( aSize.Width() + aSize.Height() ) >> 1 );
nCheckSum=0;
nValue=0xcdd7; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x9ac6; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue;
nValue=(sal_uInt16) aTargetSize.Width(); nCheckSum^=nValue; *pWMF << nValue;
nValue=(sal_uInt16) aTargetSize.Height(); nCheckSum^=nValue; *pWMF << nValue;
nValue=nUnitsPerInch; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue;
nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue;
*pWMF << nCheckSum;
}
nMetafileHeaderPos=pWMF->Tell();
*pWMF << (sal_uInt16)0x0001 // Typ: Datei
<< (sal_uInt16)0x0009 // Headerlaenge in Worten
<< (sal_uInt16)0x0300 // Version als BCD-Zahl
<< (sal_uInt32) 0x00000000 // Dateilaenge (ohne 1. Header), wird spaeter durch UpdateHeader() berichtigt
<< (sal_uInt16)MAXOBJECTHANDLES // Maximalezahl der gleichzeitigen Objekte
<< (sal_uInt32) 0x00000000 // Maximale Record-laenge, wird spaeter durch UpdateHeader() berichtigt
<< (sal_uInt16)0x0000; // Reserved
}
// ------------------------------------------------------------------------
void WMFWriter::UpdateHeader()
{
sal_uLong nPos;
sal_uInt32 nFileSize;
nPos=pWMF->Tell(); // Endposition = Gesammtgroesse der Datei
nFileSize=nPos-nMetafileHeaderPos; // Groesse des 1. Headers abziehen
if ((nFileSize&1)!=0) { // ggf. auf ganze Worte aufrunden
*pWMF << (sal_uInt8)0;
nPos++;
nFileSize++;
}
nFileSize>>=1; // In Anzahl Worte umrechnen
pWMF->Seek(nMetafileHeaderPos+6); // Zum Dateigroessen-Eintrag im zweiten Header
*pWMF << nFileSize; // Dateigroesse berichtigen
pWMF->SeekRel(2); // Zum Max-Record-Laenge-Eintrag im zweiten Header
*pWMF << nMaxRecordSize; // und berichtigen
pWMF->Seek(nPos);
}
// ------------------------------------------------------------------------
sal_Bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
FilterConfigItem* pFConfigItem, sal_Bool bPlaceable )
{
WMFWriterAttrStackMember * pAt;
bEmbedEMF = sal_True;
bStatus=sal_True;
pConvert = 0;
pVirDev = new VirtualDevice;
pFilterConfigItem = pFConfigItem;
if ( pFilterConfigItem )
{
xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
if ( xStatusIndicator.is() )
{
rtl::OUString aMsg;
xStatusIndicator->start( aMsg, 100 );
}
}
nLastPercent=0;
pWMF=&rTargetStream;
pWMF->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
nMaxRecordSize=0;
aSrcMapMode=rMTF.GetPrefMapMode();
if( bPlaceable )
{
aTargetMapMode = aSrcMapMode;
aTargetSize = rMTF.GetPrefSize();
nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize);
aTargetSize.Width() /= nTargetDivisor;
aTargetSize.Height() /= nTargetDivisor;
}
else
{
aTargetMapMode = MapMode( MAP_INCH );
const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width();
const Fraction aFrac( 1, nUnit );
aTargetMapMode.SetScaleX( aFrac );
aTargetMapMode.SetScaleY( aFrac );
aTargetSize = pVirDev->LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode );
}
pVirDev->SetMapMode( aTargetMapMode );
pAttrStack=NULL;
for (sal_uInt16 i=0; i<MAXOBJECTHANDLES; i++)
bHandleAllocated[i]=sal_False;
nDstPenHandle=0xffff;
nDstFontHandle=0xffff;
nDstBrushHandle=0xffff;
nNumberOfActions=0;
nNumberOfBitmaps=0;
nWrittenActions=0;
nWrittenBitmaps=0;
nActBitmapPercent=0;
CountActionsAndBitmaps(rMTF);
WriteHeader(rMTF,bPlaceable);
if( bEmbedEMF )
WriteEmbeddedEMF( rMTF );
WMFRecord_SetWindowOrg(Point(0,0));
WMFRecord_SetWindowExt(rMTF.GetPrefSize());
WMFRecord_SetBkMode( sal_True );
eDstROP2 = eSrcRasterOp = ROP_OVERPAINT;
WMFRecord_SetROP2(eDstROP2);
aDstLineInfo = LineInfo();
aDstLineColor = aSrcLineColor = Color( COL_BLACK );
CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
aDstFillColor = aSrcFillColor = Color( COL_WHITE );
CreateSelectDeleteBrush( aDstFillColor );
aDstClipRegion = aSrcClipRegion = Region();
bDstIsClipping = bSrcIsClipping = sal_False;
Font aFont;
aFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) );
aFont.SetColor( Color( COL_WHITE ) );
aFont.SetAlign( ALIGN_BASELINE );
aDstFont = aSrcFont = aFont;
CreateSelectDeleteFont(aDstFont);
eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE;
eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT;
WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
aDstTextColor = aSrcTextColor = Color( COL_WHITE );
WMFRecord_SetTextColor(aDstTextColor);
// Write records
WriteRecords(rMTF);
WMFRecord_EndOfFile();
UpdateHeader();
while(pAttrStack)
{
pAt=pAttrStack;
pAttrStack=pAt->pSucc;
delete pAt;
}
delete pVirDev;
delete pConvert;
if ( xStatusIndicator.is() )
xStatusIndicator->end();
return bStatus;
}
// ------------------------------------------------------------------------
sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
const Size& rPrefSize)
{
Fraction aDivFrac(2, 1);
sal_uInt16 nDivisor = 1;
Size aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) )
{
Fraction aFrac = rMapMode.GetScaleX();
aFrac *= aDivFrac;
rMapMode.SetScaleX(aFrac);
aFrac = rMapMode.GetScaleY();
aFrac *= aDivFrac;
rMapMode.SetScaleY(aFrac);
nDivisor <<= 1;
aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
}
return nDivisor;
}
// ------------------------------------------------------------------------
void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
{
EMFWriter aEMFWriter;
SvMemoryStream aStream;
if( aEMFWriter.WriteEMF( rMTF, aStream ) )
{
sal_Size nTotalSize = aStream.Tell();
if( nTotalSize > SAL_MAX_UINT32 )
return;
aStream.Seek( 0 );
sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
sal_uInt16 nCheckSum = 0, nWord;
sal_uInt32 nPos = 0;
while( nPos + 1 < nTotalSize )
{
aStream >> nWord;
nCheckSum ^= nWord;
nPos += 2;
}
nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
aStream.Seek( 0 );
while( nRemainingSize > 0 )
{
sal_uInt32 nCurSize;
if( nRemainingSize > 0x2000 )
{
nCurSize = 0x2000;
nRemainingSize -= 0x2000;
}
else
{
nCurSize = nRemainingSize;
nRemainingSize = 0;
}
WriteEMFRecord( aStream,
nCurSize,
nRemainingSize,
nTotalSize,
nRecCounts,
nCheckSum );
nCheckSum = 0;
}
}
}
// ------------------------------------------------------------------------
void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
{
// according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
WriteRecordHeader( 0, W_META_ESCAPE );
*pWMF << (sal_uInt16)W_MFCOMMENT // same as META_ESCAPE_ENHANCED_METAFILE
<< (sal_uInt16)( nCurSize + 34 ) // we will always have a 34 byte escape header:
<< (sal_uInt32) 0x43464D57 // WMFC
<< (sal_uInt32) 0x00000001 // Comment type
<< (sal_uInt32) 0x00010000 // version
<< nCheckSum // check sum
<< (sal_uInt32) 0 // flags = 0
<< nRecCounts // total number of records
<< nCurSize // size of this record's data
<< nRemainingSize // remaining size of data in following records, missing in MSDN documentation
<< nTotalSize; // total size of EMF stream
pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize );
rStream.SeekRel( nCurSize );
UpdateRecordHeader();
}