1772 lines
56 KiB
C
1772 lines
56 KiB
C
#include <windows.h>
|
|
#include <commdlg.h>
|
|
|
|
#include <malloc.h>
|
|
#include <memory.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
|
|
#include "dialogs.h"
|
|
#include "fonttest.h"
|
|
#include "glyph.h"
|
|
#include "resource.h"
|
|
|
|
#define ASCENDERCOLOR PALETTERGB( 128, 0, 0 )
|
|
#define DESCENDERCOLOR PALETTERGB( 0, 128, 0 )
|
|
|
|
int Margin;
|
|
|
|
#define MAX_TEXT 128
|
|
char szText[MAX_TEXT];
|
|
|
|
void DrawBezier( HWND hwnd, HDC hdc );
|
|
|
|
// gGGO is a global structure that keeps the state of the GGO
|
|
// options.
|
|
|
|
// gray can hold one of the following:
|
|
|
|
// GGO_BITMAP;
|
|
// GGO_GRAY2_BITMAP
|
|
// GGO_GRAY4_BITMAP
|
|
// GGO_GRAY8_BITMAP
|
|
|
|
typedef struct {
|
|
unsigned int gray;
|
|
unsigned int flags;
|
|
} GGOSTRUCT;
|
|
|
|
GGOSTRUCT gGGO = {GGO_BITMAP,0};
|
|
|
|
|
|
DWORD dwxFlags = 0L;
|
|
HDC hdcTest; // DC to Test Metrics, Bitmaps, etc... on
|
|
HFONT hFont, hFontOld;
|
|
int xVE, yVE, xWE, yWE, xLPI, yLPI;
|
|
|
|
//*****************************************************************************
|
|
//************************ G L Y P H D A T A ****************************
|
|
//*****************************************************************************
|
|
|
|
HPEN hPenOutline;
|
|
HPEN hPenA;
|
|
HPEN hPenB;
|
|
HPEN hPenC;
|
|
HPEN hPenBox;
|
|
HBRUSH hBrushAscend;
|
|
HBRUSH hBrushDescend;
|
|
WORD wChar = '1';
|
|
int iWidth;
|
|
double deM11, deM12, deM21, deM22;
|
|
MAT2 mat2 = {{0,1},{0,0},{0,0},{0,1}};
|
|
GLYPHMETRICS gm;
|
|
|
|
#define MAX_BOX 260
|
|
#define MARGIN 50
|
|
|
|
int Scale = 1;
|
|
int xBase = 0;
|
|
int yBase = 0;
|
|
int cxClient, cyClient;
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
//*****************************************************************************
|
|
//********************* C R E A T E T E S T D C ***********************
|
|
//*****************************************************************************
|
|
|
|
HDC CreateTestDC( void )
|
|
{
|
|
DWORD dwVE, dwWE;
|
|
SIZE size;
|
|
|
|
// hdcTest = CreateDC( "DISPLAY", NULL, NULL, NULL );
|
|
// if( !hdcTest ) return hdcTest;
|
|
|
|
hdcTest = CreateTestIC();
|
|
if( !hdcTest ) {
|
|
return NULL;
|
|
}
|
|
SetDCMapMode( hdcTest, wMappingMode );
|
|
GetViewportExtEx(hdcTest,&size);
|
|
dwVE = (DWORD) (65536 * size.cy + size.cx);
|
|
|
|
GetWindowExtEx(hdcTest, &size);
|
|
dwWE = (DWORD) (65536 * size.cy + size.cx);
|
|
|
|
xVE = abs( (int)LOWORD(dwVE) );
|
|
yVE = abs( (int)HIWORD(dwVE) );
|
|
xWE = abs( (int)LOWORD(dwWE) );
|
|
yWE = abs( (int)HIWORD(dwWE) );
|
|
|
|
xLPI = GetDeviceCaps( hdcTest, LOGPIXELSX );
|
|
yLPI = GetDeviceCaps( hdcTest, LOGPIXELSY );
|
|
|
|
if (!isCharCodingUnicode)
|
|
hFont = CreateFontIndirectWrapperA( &elfdvA );
|
|
else
|
|
hFont = CreateFontIndirectWrapperW( &elfdvW );
|
|
hFontOld = SelectObject( hdcTest, hFont );
|
|
|
|
SetTextColor( hdcTest, dwRGB );
|
|
return hdcTest;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//******************* D E S T R O Y T E S T D C ***********************
|
|
//*****************************************************************************
|
|
|
|
void DestroyTestDC( void )
|
|
{
|
|
SelectObject( hdcTest, hFontOld );
|
|
DeleteObject( hFont );
|
|
// DeleteDC( hdcTest );
|
|
DeleteTestIC( hdcTest );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************************** M A P X **********************************
|
|
//*****************************************************************************
|
|
|
|
int MapX( int x )
|
|
{
|
|
return Scale * x;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************************** M A P Y **********************************
|
|
//*****************************************************************************
|
|
|
|
int MapY( int y )
|
|
{
|
|
return MulDiv( Scale * y, xLPI, yLPI );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************ F I L L P I X E L ****************************
|
|
//*****************************************************************************
|
|
|
|
void FillPixel( HDC hdc, int x, int y, int xBrush )
|
|
{
|
|
if( Scale > 1 ) {
|
|
SelectObject( hdc, GetStockObject(xBrush) );
|
|
Rectangle( hdc, MapX(x), MapY(y)-1, MapX(x+1)+1, MapY(y+1) );
|
|
} else {
|
|
COLORREF cr;
|
|
|
|
switch( xBrush ) {
|
|
|
|
case BLACK_BRUSH:
|
|
cr = PALETTEINDEX( 0);
|
|
break;
|
|
|
|
case GRAY_BRUSH:
|
|
cr = PALETTEINDEX( 7);
|
|
break;
|
|
|
|
case LTGRAY_BRUSH:
|
|
cr = PALETTEINDEX( 8);
|
|
break;
|
|
|
|
default:
|
|
cr = PALETTEINDEX(15);
|
|
break;
|
|
}
|
|
SetPixel( hdc, MapX(x), MapY(y), cr );
|
|
}
|
|
}
|
|
|
|
void MyFillPixel( HDC hdc, int x, int y )
|
|
{
|
|
if ( Scale > 1 )
|
|
Rectangle( hdc, MapX(x), MapY(y)-1, MapX(x+1)+1, MapY(y+1) );
|
|
else
|
|
PatBlt( hdc, MapX(x), MapY(y), 1, 1, PATCOPY );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************** D R A W B O X ******************************
|
|
//*****************************************************************************
|
|
|
|
void DrawBox( HWND hwnd, HDC hdc )
|
|
{
|
|
int x, y, xSpace, ySpace, xScale, yScale;
|
|
RECT rcl;
|
|
|
|
//-------------------------- Draw Character Box -----------------------------
|
|
|
|
GetClientRect( hwnd, &rcl );
|
|
cxClient = rcl.right;
|
|
cyClient = rcl.bottom;
|
|
dprintf( "rcl.right, bottom = %d, %d", rcl.right, rcl.bottom );
|
|
|
|
Margin = min( rcl.bottom / 8, rcl.right / 8 );
|
|
xSpace = rcl.right - 2*Margin; // Available Box for Glyph
|
|
ySpace = rcl.bottom - 2*Margin;
|
|
|
|
GetTextMetrics( hdcTest, &tm );
|
|
dprintf( "tmMaxCharWidth = %d", tm.tmMaxCharWidth );
|
|
dprintf( "tmAscent, Descent = %d,%d", tm.tmAscent, tm.tmDescent );
|
|
|
|
tm.tmAscent = MulDiv( tm.tmAscent, yVE, yWE );
|
|
tm.tmDescent = MulDiv( tm.tmDescent, yVE, yWE );
|
|
tm.tmMaxCharWidth = MulDiv( tm.tmMaxCharWidth, xVE, xWE );
|
|
|
|
xScale = xSpace / (tm.tmAscent+tm.tmDescent);
|
|
yScale = ySpace / (tm.tmMaxCharWidth);
|
|
|
|
Scale = min( xScale, yScale ); // Choose smallest
|
|
if( Scale < 1 ) {
|
|
Scale = 1;
|
|
}
|
|
SetMapMode( hdc, MM_ANISOTROPIC );
|
|
SetViewportExtEx( hdc, 1, 1, 0); // Make y-axis go up
|
|
SetViewportOrgEx( hdc, 0, rcl.bottom, 0);
|
|
|
|
xBase = Margin;
|
|
yBase = Margin + Scale * tm.tmDescent;
|
|
dprintf( "xBase, yBase = %d, %d", xBase, yBase );
|
|
|
|
SetWindowExtEx(hdc, 1, -1, 0);
|
|
SetWindowOrgEx( hdc, -xBase, -yBase, 0);
|
|
SelectObject( hdc, hPenBox );
|
|
SelectObject( hdc, hBrushAscend );
|
|
Rectangle( hdc, 0, -1, MapX(tm.tmMaxCharWidth)+1, MapY(tm.tmAscent) );
|
|
SelectObject( hdc, hBrushDescend );
|
|
Rectangle( hdc, 0, 0, MapX(tm.tmMaxCharWidth)+1, MapY(-tm.tmDescent)-1 );
|
|
|
|
//------------------------------ Overlay Grid --------------------------------
|
|
|
|
SelectObject( hdc, hPenBox );
|
|
if( Scale > 1 ) {
|
|
for( x = 0; x <= tm.tmMaxCharWidth; x++ ) {
|
|
MoveToEx( hdc, MapX(x), MapY(-tm.tmDescent), 0);
|
|
LineTo( hdc, MapX(x), MapY(tm.tmAscent) );
|
|
}
|
|
for( y = -tm.tmDescent; y <= tm.tmAscent; y++ ) {
|
|
MoveToEx( hdc, 0,MapY(y), 0);
|
|
LineTo( hdc, MapX(tm.tmMaxCharWidth), MapY(y) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//*********************** D R A W B I T M A P ***************************
|
|
//*****************************************************************************
|
|
|
|
typedef BYTE *HPBYTE;
|
|
|
|
void DrawBitmap( HWND hwnd, HDC hdc )
|
|
{
|
|
int x, xOut, y, nx, ny, r, gox, goy, cbRaster;
|
|
BYTE m, b;
|
|
HPBYTE hpb;
|
|
DWORD dwrc;
|
|
unsigned uFormat; // to be passed to GetGlyphOutline
|
|
int cLevels; // number of levels in TT-bitmap
|
|
int D,Q,R,E;
|
|
int iLevel;
|
|
HBRUSH *pb, *pbOut, hbBlue, hbPixelOff;
|
|
|
|
HLOCAL hBrushHandleArray = 0;
|
|
HBRUSH *pBrushHandleArray = 0;
|
|
|
|
//------------------------- Query Size of BitMap ----------------------------
|
|
|
|
HPBYTE hStart = NULL;
|
|
HPBYTE hpbStart = NULL;
|
|
hbPixelOff = CreateSolidBrush(RGB(255,255,255));
|
|
if (hbPixelOff == 0) {
|
|
dprintf(" hbPixelOff == 0");
|
|
goto Exit;
|
|
}
|
|
hbBlue = CreateSolidBrush(RGB(0,0,255));
|
|
if ( hbBlue == 0 ) {
|
|
dprintf(" hbBlue == 0");
|
|
goto Exit;
|
|
}
|
|
|
|
dprintf( "GetGlyphOutline bitmap size '%c'", wChar );
|
|
dprintf( "flags = %u", gGGO.flags);
|
|
|
|
dprintf( "Character code: %x", (UINT) wChar);
|
|
|
|
uFormat = (gGGO.gray | gGGO.flags);
|
|
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest, // screen dc
|
|
wChar, // character to be queried
|
|
uFormat, // GGO_* stuff
|
|
&gm, // request GLYPHMETRICS to be returned
|
|
0L, // size request ==> size of buffer must be zero
|
|
NULL, // size request ==> no bitmap buffer provided
|
|
&mat2 // recieves extra transform matrix
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest, // screen dc
|
|
wChar, // character to be queried
|
|
uFormat, // GGO_* stuff
|
|
&gm, // request GLYPHMETRICS to be returned
|
|
0L, // size request ==> size of buffer must be zero
|
|
NULL, // size request ==> no bitmap buffer provided
|
|
&mat2 // recieves extra transform matrix
|
|
);
|
|
|
|
dprintf( " dwrc = %ld", dwrc );
|
|
dprintf( " gmBlackBoxX,Y = %u,%u", gm.gmBlackBoxX, gm.gmBlackBoxY );
|
|
dprintf( " gmptGlyphOrigin = %d,%d", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y );
|
|
dprintf( " gmCellIncX,Y = %d,%d", gm.gmCellIncX, gm.gmCellIncY );
|
|
|
|
if( (long)dwrc == -1L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
if( gm.gmBlackBoxX * gm.gmBlackBoxY / 8 > (WORD)dwrc ) {
|
|
dprintf( "BOGUS bitmap size!" );
|
|
dprintf( " BlackBoxX,Y says %u bytes", gm.gmBlackBoxX * gm.gmBlackBoxY / 8 );
|
|
dprintf( " GetGlyphOutline says %lu bytes", dwrc );
|
|
goto Exit;
|
|
}
|
|
hStart = GlobalAlloc( GMEM_MOVEABLE, dwrc );
|
|
dprintf( " hStart = 0x%.4X", hStart );
|
|
if( !hStart ) {
|
|
goto Exit;
|
|
}
|
|
hpbStart = (HPBYTE)GlobalLock( hStart );
|
|
dprintf( " hpbStart = 0x%.8lX", hpbStart );
|
|
if( !hpbStart ) {
|
|
goto Exit;
|
|
}
|
|
|
|
//------------------------- Actually Get Bitmap -----------------------------
|
|
|
|
dprintf( "Calling GetGlyphOutline for bitmap" );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
uFormat,
|
|
&gm,
|
|
dwrc,
|
|
hpbStart,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
uFormat,
|
|
&gm,
|
|
dwrc,
|
|
hpbStart,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %ld", dwrc );
|
|
|
|
if( (long)dwrc == -1L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
|
|
//------------------------ Draw Bitmap on Screen ----------------------------
|
|
|
|
nx = gm.gmBlackBoxX;
|
|
ny = gm.gmBlackBoxY;
|
|
|
|
switch ( gGGO.gray )
|
|
{
|
|
case GGO_BITMAP:
|
|
cbRaster = ( nx + 31 ) / 32;
|
|
cLevels = 2;
|
|
break;
|
|
case GGO_GRAY2_BITMAP:
|
|
cbRaster = ( nx + 3 ) / 4;
|
|
cLevels = 5;
|
|
break;
|
|
case GGO_GRAY4_BITMAP:
|
|
cbRaster = ( nx + 3 ) / 4;
|
|
cLevels = 17;
|
|
break;
|
|
case GGO_GRAY8_BITMAP:
|
|
cbRaster = ( nx + 3 ) / 4;
|
|
cLevels = 65;
|
|
break;
|
|
default:
|
|
dprintf(" bogus gGGO.gray");
|
|
goto Exit;
|
|
}
|
|
cbRaster *= sizeof(DWORD); // # bytes per scan
|
|
|
|
if ( gGGO.gray != GGO_BITMAP ) {
|
|
// set up a DDA for the colors
|
|
|
|
D = cLevels - 1; // denominator
|
|
Q = 255 / D; // quotient
|
|
R = 255 % D; // remainder
|
|
E = D - (D / 2) - 1; // error term
|
|
|
|
// allocate an array of brush handles
|
|
|
|
hBrushHandleArray = LocalAlloc(LMEM_FIXED, sizeof(HBRUSH) * cLevels);
|
|
if (hBrushHandleArray == 0) {
|
|
dprintf(" hBrushHandleArray == 0");
|
|
goto Exit;
|
|
}
|
|
pBrushHandleArray = (HBRUSH*) LocalLock(hBrushHandleArray);
|
|
if (pBrushHandleArray == 0) {
|
|
dprintf(" pBrushHandleArray == 0");
|
|
goto Exit;
|
|
}
|
|
|
|
// initialize loop variables
|
|
|
|
iLevel = 0;
|
|
pb = pBrushHandleArray;
|
|
pbOut = pb + cLevels;
|
|
|
|
for ( ; pb < pbOut; pb++ ) {
|
|
BYTE j;
|
|
const static BYTE GAMMA[256] = {
|
|
0, 0x03, 0x05, 0x07, 0x09, 0x0a, 0x0c, 0x0d
|
|
, 0x0f, 0x11, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19
|
|
, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24
|
|
, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b, 0x2c, 0x2d
|
|
, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x35, 0x36, 0x37
|
|
, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3e, 0x3f, 0x40
|
|
, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49
|
|
, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51
|
|
, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5a
|
|
, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62
|
|
, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a
|
|
, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72
|
|
, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x78, 0x79
|
|
, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81
|
|
, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89
|
|
, 0x8a, 0x8b, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90
|
|
, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98
|
|
, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
|
|
, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6
|
|
, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad
|
|
, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb3, 0xb4
|
|
, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbb
|
|
, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc1, 0xc2
|
|
, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc9
|
|
, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcf, 0xd0
|
|
, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7
|
|
, 0xd8, 0xd9, 0xda, 0xda, 0xdb, 0xdc, 0xdd, 0xde
|
|
, 0xdf, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4
|
|
, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xea, 0xeb
|
|
, 0xec, 0xed, 0xee, 0xef, 0xef, 0xf0, 0xf1, 0xf2
|
|
, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf8
|
|
, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfd, 0xfe, 0xff
|
|
};
|
|
|
|
// On the screen I want the background color
|
|
// to be white and the text color to be black.
|
|
// This means that iLevel = 0 corresponds to
|
|
// full luminance and iLevel = 255 corresponds
|
|
// to zero luminance.
|
|
//
|
|
// We must also gamma correct
|
|
|
|
j = GAMMA[255-iLevel];
|
|
|
|
*pb = CreateSolidBrush( RGB(j,j,j) );
|
|
if ( *pb ==0 ) {
|
|
dprintf( "CreateHatchBrush failed");
|
|
goto Exit;
|
|
}
|
|
iLevel += Q;
|
|
if ((E -= R) < 0) {
|
|
iLevel += 1;
|
|
E += D;
|
|
}
|
|
}
|
|
}
|
|
dprintf( " cbRaster = %d", cbRaster );
|
|
|
|
SelectObject( hdc, hPenBox );
|
|
gox = (gm.gmCellIncX >= 0 ? gm.gmptGlyphOrigin.x : 0);
|
|
goy = abs(gm.gmptGlyphOrigin.y) - 1;
|
|
for( r = 0; r < ny; r++ ) {
|
|
y = goy - r;
|
|
if( y > cyClient-yBase )
|
|
continue;
|
|
hpb = hpbStart + r * cbRaster;
|
|
x = gox;
|
|
xOut = min(gox + nx, cxClient - xBase + 1);
|
|
if ( gGGO.gray == GGO_BITMAP ) {
|
|
for( m = 0; x < xOut; x++ ) {
|
|
int xBrush;
|
|
|
|
if( m == 0 ) {
|
|
m = 0x0080;
|
|
b = *hpb;
|
|
hpb += 1;
|
|
}
|
|
if( m & b ) {
|
|
xBrush = BLACK_BRUSH;
|
|
} else {
|
|
if( y >= 0 ) {
|
|
xBrush = LTGRAY_BRUSH;
|
|
} else {
|
|
xBrush = GRAY_BRUSH;
|
|
}
|
|
}
|
|
FillPixel( hdc, x, y, xBrush );
|
|
m >>= 1;
|
|
}
|
|
} else {
|
|
// gray pixel case
|
|
for ( ; x < xOut; x++, hpb++ ) {
|
|
HBRUSH hb;
|
|
hb = pBrushHandleArray[*hpb];
|
|
hb = SelectObject(hdc, hb);
|
|
MyFillPixel(hdc,x,y);
|
|
SelectObject(hdc, hb);
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if( hpbStart ) {
|
|
GlobalUnlock( hStart );
|
|
}
|
|
if( hStart ) {
|
|
GlobalFree( hStart );
|
|
}
|
|
if ( pBrushHandleArray ) {
|
|
// delete brushes
|
|
pb = pBrushHandleArray + cLevels;
|
|
for ( pb = pBrushHandleArray; pb < pbOut + cLevels; pb++ ) {
|
|
if (*pb) {
|
|
DeleteObject(*pb);
|
|
}
|
|
}
|
|
}
|
|
if ( hBrushHandleArray ) {
|
|
LocalUnlock( hBrushHandleArray );
|
|
LocalFree( hBrushHandleArray );
|
|
}
|
|
if ( hbPixelOff ) {
|
|
DeleteObject( hbPixelOff );
|
|
}
|
|
if ( hbBlue ) {
|
|
DeleteObject( hbBlue );
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************ P R I N T F I X E D **************************
|
|
//*****************************************************************************
|
|
|
|
void PrintPointFX( LPSTR lpszIntro, POINTFX pfx )
|
|
{
|
|
// dprintf( "%Fs%d.%.3u, %d.%.3u", lpszIntro,
|
|
// pfx.x.value, (int)(((long)pfx.x.fract*1000L)/65536L),
|
|
// pfx.y.value, (int)(((long)pfx.y.fract*1000L)/65536L) );
|
|
|
|
long l1, l2;
|
|
|
|
l1 = *(LONG *)&pfx.x.fract;
|
|
l2 = *(LONG *)&pfx.y.fract;
|
|
dprintf( "%Fs%.3f,%.3f", lpszIntro, (double)(l1) / 65536.0, (double)(l2) / 65536.0 );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************************** M A P F X ********************************
|
|
//*****************************************************************************
|
|
|
|
double FixedToFloat( FIXED fx )
|
|
{
|
|
return (double)(*(long *)&fx) / 65536.0;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************************** M A P F X ********************************
|
|
//*****************************************************************************
|
|
|
|
double dxLPI, dyLPI, dxScale, dyScale;
|
|
|
|
int MapFX( FIXED fx )
|
|
{
|
|
return (int)(dxScale * FixedToFloat(fx));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************************** M A P F Y ********************************
|
|
//*****************************************************************************
|
|
|
|
int MapFY( FIXED fy )
|
|
{
|
|
return (int)(dyScale * FixedToFloat(fy));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************ D R A W X M A R K **************************
|
|
//*****************************************************************************
|
|
|
|
int xdx = 2;
|
|
int xdy = 2;
|
|
|
|
void DrawXMark( HDC hdc, POINTFX ptfx )
|
|
{
|
|
int x, y;
|
|
|
|
x = MapFX( ptfx.x );
|
|
y = MapFY( ptfx.y );
|
|
|
|
|
|
MoveToEx( hdc, x-xdx, y-xdy ,0);
|
|
LineTo( hdc, x+xdx, y+xdy );
|
|
MoveToEx( hdc, x-xdx, y+xdy , 0);
|
|
LineTo( hdc, x+xdx, y-xdy );
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//********************** D R A W T 2 C U R V E ************************
|
|
//*****************************************************************************
|
|
|
|
typedef struct _PTL
|
|
{
|
|
LONG x;
|
|
LONG y;
|
|
} PTL, FAR *LPPTL;
|
|
|
|
//
|
|
//
|
|
// Formula for the T2 B-Spline:
|
|
//
|
|
//
|
|
// f(t) = (A-2B+C)*t^2 + (2B-2A)*t + A
|
|
//
|
|
// where
|
|
//
|
|
// t = 0..1
|
|
//
|
|
//
|
|
|
|
void DrawT2Curve( HDC hdc, PTL ptlA, PTL ptlB, PTL ptlC )
|
|
{
|
|
double x, y;
|
|
double fax, fbx, fcx, fay, fby, fcy, ax, vx, x0, ay, vy, y0, t;
|
|
|
|
fax = (double)(ptlA.x) / 65536.0;
|
|
fbx = (double)(ptlB.x) / 65536.0;
|
|
fcx = (double)(ptlC.x) / 65536.0;
|
|
|
|
fay = (double)(ptlA.y) / 65536.0;
|
|
fby = (double)(ptlB.y) / 65536.0;
|
|
fcy = (double)(ptlC.y) / 65536.0;
|
|
|
|
ax = fax - 2*fbx + fcx;
|
|
vx = 2*fbx - 2*fax;
|
|
x0 = fax;
|
|
|
|
ay = fay - 2*fby + fcy;
|
|
vy = 2*fby - 2*fay;
|
|
y0 = fay;
|
|
|
|
MoveToEx( hdc, (int)(dxScale*x0), (int)(dyScale*y0) , 0);
|
|
|
|
for( t = 0.0; t < 1.0; t += 1.0/10.0 ) {
|
|
x = ax*t*t + vx*t + x0;
|
|
y = ay*t*t + vy*t + y0;
|
|
LineTo( hdc, (int)(dxScale*x), (int)(dyScale*y) );
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************ D R A W N A T I V E **************************
|
|
//*****************************************************************************
|
|
|
|
void DrawNative( HWND hwnd, HDC hdc )
|
|
{
|
|
DWORD dwrc;
|
|
LPBYTE lpb;
|
|
LPTTPOLYGONHEADER lpph, pTTPH;
|
|
HPEN hPen;
|
|
int nItem;
|
|
long cbOutline, cbTotal;
|
|
|
|
hPen = 0;
|
|
pTTPH = 0;
|
|
|
|
//------------------- Query Buffer Size and Allocate It ---------------------
|
|
|
|
dprintf( "GetGlyphOutline native size '%c'", wChar );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_NATIVE | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_NATIVE | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %ld", dwrc );
|
|
dprintf( " gmBlackBoxX,Y = %u,%u", gm.gmBlackBoxX, gm.gmBlackBoxY );
|
|
dprintf( " gmptGlyphOrigin = %d,%d", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y );
|
|
dprintf( " gmCellIncX,Y = %d,%d", gm.gmCellIncX, gm.gmCellIncY );
|
|
|
|
if( (long)dwrc == -1L || dwrc == 0L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
|
|
// font seals.ttf with glyph having 20K+ points goes over this limit
|
|
// if( dwrc > 16384L ) {
|
|
// dprintf( "Reported native size questionable (>16K), aborting" );
|
|
// goto Exit;
|
|
// }
|
|
|
|
pTTPH = lpph = (LPTTPOLYGONHEADER) calloc( 1, dwrc );
|
|
if( pTTPH == NULL ) {
|
|
dprintf( "*** Native calloc failed!" );
|
|
goto Exit;
|
|
}
|
|
|
|
//----------------------- Get Native Format Buffer --------------------------
|
|
|
|
lpph->cb = dwrc;
|
|
|
|
dprintf( "Calling GetGlyphOutline for native format" );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_NATIVE | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPPOINT)lpph,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_NATIVE | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPPOINT)lpph,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %lu", dwrc );
|
|
|
|
if( (long)dwrc == -1L || dwrc == 0L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
|
|
//-------------------- Print Out the Buffer Contents ------------------------
|
|
|
|
dxLPI = (double)xLPI;
|
|
dyLPI = (double)yLPI;
|
|
dxScale = (double)Scale;
|
|
dyScale = (double)Scale * dxLPI / dyLPI;
|
|
|
|
cbTotal = dwrc;
|
|
while( cbTotal > 0 ) {
|
|
HPEN hPenOld;
|
|
POINTFX ptfxLast;
|
|
|
|
dprintf( "Polygon Header:" );
|
|
dprintf( " cb = %lu", lpph->cb );
|
|
dprintf( " dwType = %d", lpph->dwType );
|
|
PrintPointFX( " pfxStart = ", lpph->pfxStart );
|
|
|
|
DrawXMark( hdc, lpph->pfxStart );
|
|
|
|
nItem = 0;
|
|
lpb = (LPBYTE)lpph + sizeof(TTPOLYGONHEADER);
|
|
|
|
//---- Calculate size of data ----
|
|
|
|
cbOutline = (long)lpph->cb - sizeof(TTPOLYGONHEADER);
|
|
ptfxLast = lpph->pfxStart; // Starting Point
|
|
while( cbOutline > 0 ) {
|
|
int n;
|
|
UINT u;
|
|
LPTTPOLYCURVE lpc;
|
|
|
|
dprintf( " cbOutline = %ld", cbOutline );
|
|
nItem++;
|
|
lpc = (LPTTPOLYCURVE)lpb;
|
|
switch( lpc->wType ) {
|
|
case TT_PRIM_LINE:
|
|
|
|
dprintf( " Item %d: Line", nItem );
|
|
break;
|
|
|
|
case TT_PRIM_QSPLINE:
|
|
|
|
dprintf( " Item %d: QSpline", nItem );
|
|
break;
|
|
|
|
default:
|
|
|
|
dprintf( " Item %d: unknown type %u", nItem, lpc->wType );
|
|
break;
|
|
}
|
|
dprintf( " # of points: %d", lpc->cpfx );
|
|
for( u = 0; u < lpc->cpfx; u++ ) {
|
|
PrintPointFX( " Point = ", lpc->apfx[u] );
|
|
DrawXMark( hdc, lpc->apfx[u] );
|
|
}
|
|
hPen = CreatePen(PS_SOLID, 2, RGB(255,255,0));
|
|
hPenOld = SelectObject( hdc, hPen );
|
|
switch( lpc->wType ) {
|
|
case TT_PRIM_LINE:
|
|
{
|
|
int x, y;
|
|
|
|
x = MapFX( ptfxLast.x );
|
|
y = MapFY( ptfxLast.y );
|
|
MoveToEx( hdc, x, y , 0);
|
|
for( u = 0; u < lpc->cpfx; u++ ) {
|
|
x = MapFX( lpc->apfx[u].x );
|
|
y = MapFY( lpc->apfx[u].y );
|
|
LineTo( hdc, x, y );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TT_PRIM_QSPLINE:
|
|
{
|
|
LPPTL lpptls;
|
|
PTL ptlA, ptlB, ptlC;
|
|
|
|
ptlA = *(LPPTL)&ptfxLast; // Convert to LONG POINT
|
|
lpptls = (LPPTL)lpc->apfx; // LONG POINT version
|
|
|
|
for( u = 0; u < (UINT) lpc->cpfx-1; u++ ) {
|
|
ptlB = lpptls[u];
|
|
|
|
// If not on last spline, compute C
|
|
|
|
if ( u < (UINT) lpc->cpfx-2 ) {
|
|
ptlC.x = (ptlB.x + lpptls[u+1].x) / 2;
|
|
ptlC.y = (ptlB.y + lpptls[u+1].y) / 2;
|
|
} else {
|
|
ptlC = lpptls[u+1];
|
|
}
|
|
DrawT2Curve( hdc, ptlA, ptlB, ptlC );
|
|
ptlA = ptlC;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
SelectObject( hdc, hPenOld );
|
|
ptfxLast = lpc->apfx[lpc->cpfx-1];
|
|
n = sizeof(TTPOLYCURVE) + sizeof(POINTFX) * (lpc->cpfx - 1);
|
|
lpb += n;
|
|
cbOutline -= n;
|
|
}
|
|
|
|
if( memcmp( &ptfxLast, &lpph->pfxStart, sizeof(ptfxLast) ) ) {
|
|
HPEN hPenOld;
|
|
int x, y;
|
|
|
|
hPenOld = SelectObject( hdc, hPen );
|
|
x = MapFX( ptfxLast.x );
|
|
y = MapFY( ptfxLast.y );
|
|
MoveToEx( hdc, x, y , 0);
|
|
x = MapFX( lpph->pfxStart.x );
|
|
y = MapFY( lpph->pfxStart.y );
|
|
LineTo( hdc, x, y );
|
|
SelectObject( hdc, hPenOld );
|
|
}
|
|
dprintf( "ended at cbOutline = %ld", cbOutline );
|
|
cbTotal -= lpph->cb;
|
|
lpph = (LPTTPOLYGONHEADER)lpb;
|
|
}
|
|
dprintf( "ended at cbTotal = %ld", cbTotal );
|
|
|
|
Exit:
|
|
if (hPen)
|
|
DeleteObject(hPen);
|
|
if( pTTPH )
|
|
free( pTTPH );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************** D R A W A B C ******************************
|
|
//*****************************************************************************
|
|
|
|
void DrawABC( HWND hwnd, HDC hdc )
|
|
{
|
|
int rc;
|
|
ABC abc;
|
|
|
|
abc.abcA = 0;
|
|
abc.abcB = 0;
|
|
abc.abcC = 0;
|
|
|
|
if (! isCharCodingUnicode)
|
|
dprintf( "Calling GetCharABCWidthsA" );
|
|
else
|
|
dprintf( "Calling GetCharABCWidthsW" );
|
|
|
|
if (! isCharCodingUnicode)
|
|
rc = lpfnGetCharABCWidthsA( hdcTest, wChar, wChar, (LPABC)&abc );
|
|
else
|
|
rc = lpfnGetCharABCWidthsW( hdcTest, wChar, wChar, (LPABC)&abc );
|
|
dprintf( " rc = %d", rc );
|
|
|
|
dprintf( " A = %d, B = %u, C = %d", abc.abcA, abc.abcB, abc.abcC );
|
|
|
|
abc.abcA = MulDiv( abc.abcA, xVE, xWE );
|
|
abc.abcB = MulDiv( abc.abcB, xVE, xWE );
|
|
abc.abcC = MulDiv( abc.abcC, xVE, xWE );
|
|
|
|
SelectObject( hdc, hPenA );
|
|
MoveToEx( hdc, MapX(abc.abcA), MapY(-tm.tmDescent) - Margin/4 , 0);
|
|
LineTo( hdc, MapX(abc.abcA), MapY(tm.tmAscent) );
|
|
|
|
SelectObject( hdc, hPenB );
|
|
MoveToEx( hdc, MapX(abc.abcA+abc.abcB), MapY(-tm.tmDescent) - Margin/2 ,0);
|
|
LineTo( hdc, MapX(abc.abcA+abc.abcB), MapY(tm.tmAscent) );
|
|
|
|
SelectObject( hdc, hPenC );
|
|
MoveToEx( hdc, MapX(abc.abcA+abc.abcB+abc.abcC), MapY(-tm.tmDescent) - (3*Margin)/4 ,0);
|
|
LineTo( hdc, MapX(abc.abcA+abc.abcB+abc.abcC), MapY(tm.tmAscent) );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//************************ D R A W G L Y P H ****************************
|
|
//*****************************************************************************
|
|
|
|
void DrawGlyph( HWND hwnd, HDC hdc )
|
|
{
|
|
dprintf( "DrawGlyph" );
|
|
if (!isCharCodingUnicode)
|
|
dprintf( " lfHeight, Width = %d,%d", elfdvA.elfEnumLogfontEx.elfLogFont.lfHeight,
|
|
elfdvA.elfEnumLogfontEx.elfLogFont.lfWidth );
|
|
else
|
|
dprintf( " lfHeight, Width = %d,%d", elfdvW.elfEnumLogfontEx.elfLogFont.lfHeight,
|
|
elfdvW.elfEnumLogfontEx.elfLogFont.lfWidth );
|
|
|
|
DrawBox( hwnd, hdc );
|
|
DrawBitmap( hwnd, hdc );
|
|
if( wMode == IDM_NATIVEMODE ) {
|
|
DrawNative( hwnd, hdc );
|
|
}
|
|
if( wMode == IDM_BEZIERMODE ) {
|
|
DrawBezier( hwnd, hdc );
|
|
}
|
|
DrawABC( hwnd, hdc );
|
|
dprintf( "Done drawing glyph" );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//*********************** W R I T E G L Y P H ***************************
|
|
//*****************************************************************************
|
|
|
|
#define MAX_BUFFER 8192
|
|
|
|
/*+++
|
|
|
|
WriteGlyph creates at bitmap file (.bmf) for the
|
|
current glyph in the current mode.
|
|
|
|
---*/
|
|
|
|
void WriteGlyph( LPSTR lpszFile )
|
|
{
|
|
int x, y, cbRaster, fh;
|
|
HANDLE hStart;
|
|
DWORD dwrc;
|
|
BITMAPFILEHEADER bfh;
|
|
BITMAPINFOHEADER bih;
|
|
HLOCAL hmemRGB;
|
|
RGBQUAD *argb, *prgb, *prgbLast;
|
|
unsigned cjRGB; // size of RGB array in BYTE's
|
|
BYTE i, E, Q, R, cLevels;
|
|
WORD wByte;
|
|
BYTE *lpBuffer, *lpb, *hpb, *hpbStart;
|
|
|
|
// ajGamma is a an array of gamma corrected
|
|
// color values. This is used to convert
|
|
// from color space to voltage space.
|
|
//
|
|
// ajGamma[i] = floor( ((i/255)^gamma - 1 + 1/2 )
|
|
//
|
|
// gamma = 2.33
|
|
//
|
|
// i = 0..255 (color value)
|
|
//
|
|
// ajGamma[i] (voltage value) = 0..255
|
|
|
|
static const BYTE ajGamma[256] = {
|
|
0, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03
|
|
, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08
|
|
, 0x09, 0x09, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d
|
|
, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13
|
|
, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a
|
|
, 0x1b, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x1f, 0x20
|
|
, 0x21, 0x22, 0x23, 0x24, 0x25, 0x25, 0x26, 0x27
|
|
, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e
|
|
, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35
|
|
, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d
|
|
, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45
|
|
, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c
|
|
, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54
|
|
, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c
|
|
, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64
|
|
, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d
|
|
, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75
|
|
, 0x76, 0x77, 0x78, 0x79, 0x7b, 0x7c, 0x7d, 0x7e
|
|
, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86
|
|
, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f
|
|
, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96, 0x97, 0x98
|
|
, 0x99, 0x9a, 0x9b, 0x9c, 0x9e, 0x9f, 0xa0, 0xa1
|
|
, 0xa2, 0xa3, 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xaa
|
|
, 0xab, 0xac, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3
|
|
, 0xb4, 0xb5, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc
|
|
, 0xbd, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc6
|
|
, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf
|
|
, 0xd0, 0xd1, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8
|
|
, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2
|
|
, 0xe3, 0xe4, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xec
|
|
, 0xed, 0xee, 0xef, 0xf0, 0xf2, 0xf3, 0xf4, 0xf5
|
|
, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xfd, 0xfe, 0xff
|
|
};
|
|
|
|
CreateTestDC();
|
|
hStart = 0;
|
|
dprintf( "GetGlyphOutline bitmap size '%c'", wChar );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BITMAP | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BITMAP | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %ld", dwrc );
|
|
dprintf( " gmBlackBoxX,Y = %u,%u", gm.gmBlackBoxX, gm.gmBlackBoxY );
|
|
dprintf( " gmptGlyphOrigin = %d,%d", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y );
|
|
dprintf( " gmCellIncX,Y = %d,%d", gm.gmCellIncX, gm.gmCellIncY );
|
|
|
|
if( dwrc == (unsigned) -1 || dwrc == 0 ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
if( gm.gmBlackBoxX * gm.gmBlackBoxY / 8 > (WORD)dwrc ) {
|
|
dprintf( "BOGUS bitmap size!" );
|
|
dprintf( " BlackBoxX,Y says %u bytes", gm.gmBlackBoxX * gm.gmBlackBoxY / 8 );
|
|
dprintf( " GetGlyphOutline says %lu bytes", dwrc );
|
|
goto Exit;
|
|
}
|
|
hStart = GlobalAlloc( GMEM_MOVEABLE, dwrc );
|
|
dprintf( " hStart = 0x%.4X", hStart );
|
|
if( !hStart ) {
|
|
goto Exit;
|
|
}
|
|
hpbStart = (HPBYTE)GlobalLock( hStart );
|
|
dprintf( " hpbStart = 0x%.8lX", hpbStart );
|
|
if( !hpbStart ) {
|
|
goto Exit;
|
|
}
|
|
dprintf( "Calling GetGlyphOutline for bitmap" );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(gGGO.gray | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPBYTE)hpbStart,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(gGGO.gray | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPBYTE)hpbStart,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %u", dwrc );
|
|
if( dwrc == (unsigned) -1 || dwrc == 0 ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
goto Exit;
|
|
}
|
|
fh = _lcreat( "GLYPH.BMP", 0 );
|
|
dprintf( " fh = %d", fh );
|
|
if( fh == HFILE_ERROR ) {
|
|
goto Exit;
|
|
}
|
|
|
|
// cLevels =: number of possible values in bitmap. The allowed values
|
|
// are 0..cLevels-1
|
|
// biClrUsed =: number of colors used in palette that follows immediately
|
|
// after the BITMAPINFOHEADER data. This number is equal to
|
|
// cLevels which is what you will find for all the gray
|
|
// bitmap cases. Monochrome is special, because we set biClrUsed
|
|
// to zero. This indicates that the number of colors used is
|
|
// equal to 2^biBitCount. In the case of monochrome biBitCount = 1
|
|
// and so 2^biBitCount = 2^1 = 2 = cLevels.
|
|
// biBitCount =: Number of bits assigned to each pixel = 1 (monochrome), 8 gray
|
|
|
|
switch ( gGGO.gray ) {
|
|
case GGO_BITMAP:
|
|
// monochrome to you and me
|
|
cLevels = 2;
|
|
bih.biClrUsed = 0;
|
|
bih.biBitCount = 1;
|
|
break;
|
|
case GGO_GRAY2_BITMAP:
|
|
bih.biClrUsed = cLevels = 5;
|
|
bih.biBitCount = 8;
|
|
break;
|
|
case GGO_GRAY4_BITMAP:
|
|
bih.biClrUsed = cLevels = 17;
|
|
bih.biBitCount = 8;
|
|
break;
|
|
case GGO_GRAY8_BITMAP:
|
|
bih.biClrUsed = cLevels = 65;
|
|
bih.biBitCount = 8;
|
|
break;
|
|
default:
|
|
dprintf( " gGGO = %-#x is bogus", (gGGO.gray | gGGO.flags));
|
|
goto Exit;
|
|
}
|
|
|
|
#define SIZEOFBMFH 14
|
|
|
|
cjRGB = cLevels * sizeof(RGBQUAD);
|
|
bfh.bfOffBits = SIZEOFBMFH + sizeof(bih) + cjRGB;
|
|
|
|
bfh.bfType = (((UINT)'M') << 8) + (UINT)'B';
|
|
bfh.bfSize = bfh.bfOffBits + dwrc;
|
|
bfh.bfReserved1 = 0;
|
|
bfh.bfReserved2 = 0;
|
|
|
|
// we have to write the header to the file just like a 16-bit
|
|
// x86 machine would have
|
|
|
|
dprintf(" Writing BITMAPFILEHEADER:");
|
|
|
|
dwrc = (DWORD) _lwrite((HFILE) fh,(const char*) &bfh.bfType, sizeof(bfh.bfType) );
|
|
if (dwrc != HFILE_ERROR)
|
|
dprintf(" bfType = %2x (%u bytes)", bfh.bfType, dwrc);
|
|
dwrc = (DWORD) _lwrite((HFILE) fh,(const char*) &bfh.bfSize, sizeof(bfh.bfSize) );
|
|
if (dwrc != HFILE_ERROR)
|
|
dprintf(" bfSize = %u (%u bytes)", bfh.bfSize, dwrc);
|
|
dwrc = (DWORD) _lwrite((HFILE) fh,(const char*) &bfh.bfReserved1, sizeof(bfh.bfReserved1));
|
|
if (dwrc != HFILE_ERROR)
|
|
dprintf(" bfReserved1 = %u (%u bytes)", bfh.bfReserved1, dwrc);
|
|
dwrc = (DWORD) _lwrite((HFILE) fh,(const char*) &bfh.bfReserved2, sizeof(bfh.bfReserved2));
|
|
if (dwrc != HFILE_ERROR)
|
|
dprintf(" bfReserved2 = %u (%u bytes)", bfh.bfReserved2, dwrc);
|
|
dwrc = (DWORD) _lwrite((HFILE) fh,(const char*) &bfh.bfOffBits, sizeof(bfh.bfOffBits) );
|
|
if (dwrc != HFILE_ERROR)
|
|
dprintf(" bfOffBits = %u (%u bytes)", bfh.bfOffBits, dwrc);
|
|
|
|
// the file pointer is now at byte number 14 in the file
|
|
|
|
// fortunately all the elements of the BITINFOHEADER are aligned
|
|
// so a straight forward copy to the file will produce something
|
|
// than an old 16-bit x86 machine would be happy with
|
|
|
|
bih.biSize = sizeof(bih);
|
|
bih.biWidth = gm.gmBlackBoxX;
|
|
bih.biHeight = gm.gmBlackBoxY;
|
|
bih.biPlanes = 1; // required value
|
|
//bih.biBitCount already set
|
|
bih.biCompression = BI_RGB; // uncompressed format
|
|
bih.biSizeImage = 0; // may be zero for BI_RGB bitmaps
|
|
bih.biXPelsPerMeter = 1; // nobody cares about this anyway
|
|
bih.biYPelsPerMeter = 1; // nobody cares about this anyway
|
|
//bih.biClrUsed already set
|
|
bih.biClrImportant = 0; // indicates that all colors are important
|
|
|
|
dprintf( " Writing BITMAPINFOHEADER: rc = %d", _lwrite( fh, (LPCSTR) &bih, sizeof(bih)));
|
|
dprintf( " biSize = %u", bih.biSize );
|
|
dprintf( " biWidth = %d", bih.biWidth );
|
|
dprintf( " biHeight = %d", bih.biHeight );
|
|
dprintf( " biPlanes = %d", bih.biPlanes );
|
|
dprintf( " biBitCount = %u", bih.biBitCount );
|
|
dprintf( " biCompression = %u", bih.biCompression );
|
|
dprintf( " biSizeImage = %u", bih.biSizeImage );
|
|
dprintf( " biXPelsPerMeter = %d", bih.biXPelsPerMeter);
|
|
dprintf( " biYPelsPerMeter = %d", bih.biYPelsPerMeter);
|
|
dprintf( " biClrUsed = %u", bih.biClrUsed );
|
|
dprintf( " biClrImportant = %u", bih.biClrImportant );
|
|
dprintf( " " );
|
|
|
|
// create a palette in memory corresponding to the
|
|
// voltages corresponding to the glyph in question
|
|
|
|
hmemRGB = LocalAlloc(LMEM_FIXED, cLevels * sizeof(*argb));
|
|
if ( hmemRGB == 0 ) {
|
|
dprintf(" LocalAlloc Failed");
|
|
goto Exit;
|
|
}
|
|
argb = (RGBQUAD*) LocalLock(hmemRGB);
|
|
if ( argb == 0 ) {
|
|
dprintf(" LocalLock Failed");
|
|
goto Exit;
|
|
}
|
|
|
|
Q = 256 / cLevels; // scaled level increment
|
|
R = 256 % cLevels; // error increment
|
|
E = cLevels - (cLevels / 2) - 1 ; // initialize error term
|
|
|
|
dprintf( "RGBQUAD array" );
|
|
prgb = argb;
|
|
prgbLast = argb + (unsigned) cLevels - 1;
|
|
for (i = 0; prgb < prgbLast; prgb++, i += Q, E -= R) {
|
|
if ( (char) E < 0 ) {
|
|
i += 1;
|
|
E += cLevels;
|
|
}
|
|
prgb->rgbRed = prgb->rgbGreen = prgb->rgbBlue = ajGamma[i];
|
|
prgb->rgbReserved = 0;
|
|
dprintf(" %2x", ajGamma[i]);
|
|
}
|
|
prgb->rgbRed = prgb->rgbGreen = prgb->rgbBlue = 255;
|
|
prgb->rgbReserved = 0;
|
|
dprintf(" %2x", 255);
|
|
// assert(prgb == prgbLast);
|
|
// assert(ajGamma[255] == 255);
|
|
|
|
// write the palette to the file
|
|
|
|
dwrc = _lwrite( fh,(LPCSTR) argb, cjRGB );
|
|
dprintf( " Writing RGBQUAD's rc = %u", dwrc);
|
|
if ( dwrc == HFILE_ERROR ) {
|
|
goto Exit;
|
|
}
|
|
|
|
// calculate the number of bytes per scan
|
|
|
|
cbRaster = gm.gmBlackBoxX;
|
|
cbRaster = gGGO.gray == GGO_BITMAP ? (cbRaster+31)/32 : (cbRaster+3)/4;
|
|
cbRaster *= sizeof(DWORD);
|
|
dprintf( " cbRaster = %d", cbRaster );
|
|
|
|
lpBuffer = (LPBYTE)malloc( MAX_BUFFER );
|
|
dprintf( " lpBuffer = 0x%.8lX", lpBuffer );
|
|
|
|
wByte = 0;
|
|
lpb = lpBuffer;
|
|
|
|
// the TrueType bitmap has the top of the image at the lowest address
|
|
// in memory whereas it is the windows convention that a bitmap
|
|
// is usually rasterized bottom to to top so we must reverse
|
|
// the scans when copying to file.
|
|
//
|
|
// MikeGi's strategy is to start at the last tt scan in memory and
|
|
// copy the bytes to a buffer checking each time to see if the buffer
|
|
// is full. Whenever the buffer is full it is flushed to the file.
|
|
// Upon the completion of a scan, the pointer to the source image is
|
|
// decremented to the start of previous scan in memory.
|
|
|
|
for ( y = gm.gmBlackBoxY-1; y >= 0; y-- ) {
|
|
hpb = hpbStart + (long)y * (long) cbRaster;
|
|
for ( x = 0; x < cbRaster; x++ ) {
|
|
*lpb++ = *hpb++; // write to buffer
|
|
wByte++; // inc buffer count
|
|
if ( wByte == MAX_BUFFER ) { // is buffer full?
|
|
dprintf( "Writing %u bytes", wByte ); // yes, flush
|
|
_lwrite( fh, lpBuffer, wByte );
|
|
wByte = 0;
|
|
lpb = lpBuffer; // reset pointer
|
|
} // into buffer
|
|
} // to point to start
|
|
}
|
|
if( wByte > 0 ) { // stuff left
|
|
dprintf( "Writing %u bytes", wByte ); // in buffer?
|
|
_lwrite( fh, lpBuffer, wByte ); // yes, flush
|
|
}
|
|
dprintf( "Closing .BMP file" );
|
|
_lclose( fh );
|
|
free( lpBuffer );
|
|
|
|
Exit:
|
|
if( hpbStart ) {
|
|
GlobalUnlock( hStart );
|
|
}
|
|
if( hStart ) {
|
|
GlobalFree( hStart );
|
|
}
|
|
if ( argb ) {
|
|
if ( hmemRGB ) {
|
|
LocalUnlock( hmemRGB );
|
|
LocalFree( hmemRGB );
|
|
}
|
|
}
|
|
DestroyTestDC();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//********************* G L Y P H W N D P R O C ***********************
|
|
//*****************************************************************************
|
|
|
|
LRESULT CALLBACK GlyphWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
HCURSOR hCursor;
|
|
|
|
switch( msg ) {
|
|
case WM_CREATE:
|
|
|
|
lstrcpy( szText, "Hello" );
|
|
hPenOutline = CreatePen( PS_SOLID, 1, RGB( 0, 255, 255 ) );
|
|
hPenA = CreatePen( PS_SOLID, 1, RGB( 255, 0, 0 ) );
|
|
hPenB = CreatePen( PS_SOLID, 1, RGB( 255, 0, 255 ) );
|
|
hPenC = CreatePen( PS_SOLID, 1, RGB( 0, 255, 0 ) );
|
|
hPenBox = CreatePen( PS_SOLID, 1, RGB( 32, 32, 32 ) );
|
|
hBrushAscend = CreateSolidBrush( ASCENDERCOLOR );
|
|
hBrushDescend = CreateSolidBrush( DESCENDERCOLOR );
|
|
deM11 = deM22 = 1.0;
|
|
deM12 = deM21 = 0.0;
|
|
return 0;
|
|
|
|
case WM_PAINT:
|
|
|
|
hCursor = SetCursor( LoadCursor( NULL, MAKEINTRESOURCE(IDC_WAIT) ) );
|
|
ShowCursor( TRUE );
|
|
ClearDebug();
|
|
dprintf( "Painting glyph window" );
|
|
hdc = BeginPaint( hwnd, &ps );
|
|
SetTextCharacterExtra( hdc, nCharExtra );
|
|
SetTextJustification( hdc, nBreakExtra, nBreakCount );
|
|
CreateTestDC();
|
|
DrawGlyph( hwnd, hdc );
|
|
DestroyTestDC();
|
|
SelectObject( hdc, GetStockObject( BLACK_PEN ) );
|
|
EndPaint( hwnd, &ps );
|
|
dprintf( "Finished painting" );
|
|
ShowCursor( FALSE );
|
|
SetCursor( hCursor );
|
|
return 0;
|
|
|
|
case WM_CHAR:
|
|
|
|
wChar = (WORD) wParam;
|
|
InvalidateRect( hwndGlyph, NULL, TRUE );
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
|
|
DeleteObject( hPenOutline );
|
|
DeleteObject( hPenA );
|
|
DeleteObject( hPenB );
|
|
DeleteObject( hPenC );
|
|
DeleteObject( hPenBox );
|
|
DeleteObject( hBrushAscend );
|
|
DeleteObject( hBrushDescend );
|
|
return 0;
|
|
}
|
|
return DefWindowProc( hwnd, msg, wParam, lParam );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//***************** S E T D L G I T E M F L O A T *******************
|
|
//*****************************************************************************
|
|
|
|
void SetDlgItemFloat( HWND hdlg, int id, double d )
|
|
{
|
|
char szText[32];
|
|
|
|
sprintf( szText, "%.3f", d );
|
|
SetDlgItemText( hdlg, id, szText );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//***************** G E T D L G I T E M F L O A T *******************
|
|
//*****************************************************************************
|
|
|
|
double GetDlgItemFloat( HWND hdlg, int id )
|
|
{
|
|
char szText[32];
|
|
|
|
szText[0] = 0;
|
|
GetDlgItemText( hdlg, id, szText, sizeof(szText) );
|
|
|
|
return atof( szText );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//********************* F L O A T T O F I X E D ***********************
|
|
//*****************************************************************************
|
|
|
|
FIXED FloatToFixed( double d )
|
|
{
|
|
long l;
|
|
|
|
l = (long)(d * 65536L);
|
|
return *(FIXED *)&l;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**************** G G O M A T R I X D L G P R O C ******************
|
|
//*****************************************************************************
|
|
|
|
INT_PTR CALLBACK GGOMatrixDlgProc( HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
int iCheck;
|
|
char szWchar[32];
|
|
|
|
switch( msg ) {
|
|
case WM_INITDIALOG:
|
|
|
|
wsprintf(szWchar, "%x", wChar);
|
|
SetDlgItemText( hdlg, IDD_WCHAR, szWchar );
|
|
|
|
SetDlgItemFloat( hdlg, IDD_M11, deM11 );
|
|
SetDlgItemFloat( hdlg, IDD_M12, deM12 );
|
|
SetDlgItemFloat( hdlg, IDD_M21, deM21 );
|
|
SetDlgItemFloat( hdlg, IDD_M22, deM22 );
|
|
|
|
// clear all the buttons
|
|
|
|
CheckDlgButton(hdlg, IDC_GGO_BITMAP, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_NATIVE, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_BEZIER, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_METRICS, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_GRAY2_BITMAP, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_GRAY4_BITMAP, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_GRAY8_BITMAP, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_GLYPH_INDEX, 0);
|
|
CheckDlgButton(hdlg, IDC_GGO_UNHINTED, 0);
|
|
|
|
// one or none of the following can be set
|
|
// GGO_BITMAP, GGO_NATIVE, GGO_METRICS, GGO_GRAY[248]
|
|
|
|
switch ( gGGO.gray ) {
|
|
case GGO_BITMAP: iCheck = IDC_GGO_BITMAP; break;
|
|
case GGO_GRAY2_BITMAP: iCheck = IDC_GGO_GRAY2_BITMAP; break;
|
|
case GGO_GRAY4_BITMAP: iCheck = IDC_GGO_GRAY4_BITMAP; break;
|
|
case GGO_GRAY8_BITMAP: iCheck = IDC_GGO_GRAY8_BITMAP; break;
|
|
default:
|
|
dprintf("bogus gray value");
|
|
}
|
|
CheckDlgButton( hdlg, iCheck, 1 );
|
|
|
|
// GGO_GLYPH_INDEX is set separately
|
|
|
|
if ( gGGO.flags & GGO_GLYPH_INDEX )
|
|
CheckDlgButton( hdlg, IDC_GGO_GLYPH_INDEX, 1 );
|
|
if ( gGGO.flags & GGO_UNHINTED )
|
|
CheckDlgButton( hdlg, IDC_GGO_UNHINTED, 1 );
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch( LOWORD( wParam ) ) {
|
|
case IDOK:
|
|
|
|
deM11 = GetDlgItemFloat( hdlg, IDD_M11 );
|
|
deM12 = GetDlgItemFloat( hdlg, IDD_M12 );
|
|
deM21 = GetDlgItemFloat( hdlg, IDD_M21 );
|
|
deM22 = GetDlgItemFloat( hdlg, IDD_M22 );
|
|
|
|
mat2.eM11 = FloatToFixed( deM11 );
|
|
mat2.eM12 = FloatToFixed( deM12 );
|
|
mat2.eM21 = FloatToFixed( deM21 );
|
|
mat2.eM22 = FloatToFixed( deM22 );
|
|
|
|
gGGO.gray = gGGO.flags = 0;
|
|
if (IsDlgButtonChecked(hdlg, IDC_GGO_BITMAP))
|
|
gGGO.gray = GGO_BITMAP;
|
|
else if (IsDlgButtonChecked(hdlg, IDC_GGO_GRAY2_BITMAP))
|
|
gGGO.gray = GGO_GRAY2_BITMAP;
|
|
else if (IsDlgButtonChecked(hdlg, IDC_GGO_GRAY4_BITMAP))
|
|
gGGO.gray = GGO_GRAY4_BITMAP;
|
|
else if (IsDlgButtonChecked(hdlg, IDC_GGO_GRAY8_BITMAP))
|
|
gGGO.gray = GGO_GRAY8_BITMAP;
|
|
else
|
|
gGGO.gray = GGO_BITMAP;
|
|
|
|
if (IsDlgButtonChecked(hdlg, IDC_GGO_GLYPH_INDEX)) {
|
|
gGGO.flags |= GGO_GLYPH_INDEX;
|
|
}
|
|
|
|
if (IsDlgButtonChecked(hdlg, IDC_GGO_UNHINTED)) {
|
|
gGGO.flags |= GGO_UNHINTED;
|
|
}
|
|
|
|
GetDlgItemText( hdlg, IDD_WCHAR, szWchar, sizeof(szWchar) );
|
|
wChar = (WORD) strtol(szWchar, 0, 16);
|
|
|
|
EndDialog( hdlg, TRUE );
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog( hdlg, FALSE );
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
|
|
EndDialog( hdlg, FALSE );
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DrawBezier( HWND hwnd, HDC hdc )
|
|
{
|
|
DWORD dwrc;
|
|
LPBYTE lpb;
|
|
LPTTPOLYGONHEADER lpph, pTTPH;
|
|
HPEN hPen;
|
|
int nItem;
|
|
long cbOutline, cbTotal;
|
|
POINT *pptStart;
|
|
|
|
hPen = 0;
|
|
pTTPH = 0;
|
|
|
|
if (!(hPen = CreatePen(PS_SOLID, 2, RGB(255,255,0))))
|
|
return;
|
|
|
|
|
|
//------------------- Query Buffer Size and Allocate It ---------------------
|
|
|
|
dprintf( "GetGlyphOutline, Bezier Mode, size '%c'", wChar );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BEZIER | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BEZIER | gGGO.flags),
|
|
&gm,
|
|
0,
|
|
0,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %ld", dwrc );
|
|
dprintf( " gmBlackBoxX,Y = %u,%u", gm.gmBlackBoxX, gm.gmBlackBoxY );
|
|
dprintf( " gmptGlyphOrigin = %d,%d", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y );
|
|
dprintf( " gmCellIncX,Y = %d,%d", gm.gmCellIncX, gm.gmCellIncY );
|
|
|
|
if ((long)dwrc == -1L || dwrc == 0L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
return;
|
|
}
|
|
|
|
|
|
pTTPH = lpph = (LPTTPOLYGONHEADER) calloc( 1, (WORD)dwrc );
|
|
if( pTTPH == NULL ) {
|
|
dprintf( "*** Native calloc failed!" );
|
|
return;
|
|
}
|
|
|
|
//----------------------- Get Native Format Buffer --------------------------
|
|
|
|
lpph->cb = dwrc;
|
|
|
|
dprintf( "Calling GetGlyphOutline for native format" );
|
|
if (! isCharCodingUnicode)
|
|
dwrc =
|
|
lpfnGetGlyphOutlineA(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BEZIER | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPPOINT)lpph,
|
|
&mat2
|
|
);
|
|
else
|
|
dwrc =
|
|
lpfnGetGlyphOutlineW(
|
|
hdcTest,
|
|
wChar,
|
|
(GGO_BEZIER | gGGO.flags),
|
|
&gm,
|
|
dwrc,
|
|
(LPPOINT)lpph,
|
|
&mat2
|
|
);
|
|
|
|
dprintf( " dwrc = %lu", dwrc );
|
|
|
|
if( (long)dwrc == -1L || dwrc == 0L ) {
|
|
dprintf( "*** GetGlyphOutline failed" );
|
|
if (pTTPH)
|
|
free( pTTPH );
|
|
return;
|
|
}
|
|
|
|
//-------------------- Print Out the Buffer Contents ------------------------
|
|
|
|
dxLPI = (double)xLPI;
|
|
dyLPI = (double)yLPI;
|
|
dxScale = (double)Scale;
|
|
dyScale = (double)Scale * dxLPI / dyLPI;
|
|
|
|
cbTotal = dwrc;
|
|
while( cbTotal > 0 )
|
|
{
|
|
HPEN hPenOld;
|
|
|
|
dprintf( "Polygon Header:" );
|
|
dprintf( " cb = %lu", lpph->cb );
|
|
dprintf( " dwType = %d", lpph->dwType );
|
|
PrintPointFX( " pfxStart = ", lpph->pfxStart );
|
|
|
|
DrawXMark( hdc, lpph->pfxStart );
|
|
|
|
nItem = 0;
|
|
lpb = (LPBYTE)lpph + sizeof(TTPOLYGONHEADER);
|
|
|
|
//---- Calculate size of data ----
|
|
|
|
cbOutline = (long)lpph->cb - sizeof(TTPOLYGONHEADER);
|
|
pptStart = (POINT *)&lpph->pfxStart; // Starting Point
|
|
|
|
pptStart->x = MapFX(lpph->pfxStart.x );
|
|
pptStart->y = MapFY(lpph->pfxStart.y );
|
|
|
|
|
|
while( cbOutline > 0 )
|
|
{
|
|
int n;
|
|
UINT u;
|
|
LPTTPOLYCURVE lpc;
|
|
|
|
dprintf( " cbOutline = %ld", cbOutline );
|
|
nItem++;
|
|
lpc = (LPTTPOLYCURVE)lpb;
|
|
switch( lpc->wType )
|
|
{
|
|
case TT_PRIM_LINE:
|
|
|
|
dprintf( " Item %d: Line", nItem );
|
|
break;
|
|
|
|
case TT_PRIM_CSPLINE:
|
|
|
|
dprintf( " Item %d: CSpline", nItem );
|
|
break;
|
|
|
|
default:
|
|
|
|
dprintf( " Item %d: unknown type %u", nItem, lpc->wType );
|
|
break;
|
|
}
|
|
dprintf( " # of points: %d", lpc->cpfx );
|
|
for( u = 0; u < lpc->cpfx; u++ )
|
|
{
|
|
PrintPointFX( " Point = ", lpc->apfx[u] );
|
|
DrawXMark( hdc, lpc->apfx[u] );
|
|
|
|
((POINT *)lpc->apfx)[u].x = MapFX( lpc->apfx[u].x );
|
|
((POINT *)lpc->apfx)[u].y = MapFY( lpc->apfx[u].y );
|
|
}
|
|
hPenOld = SelectObject( hdc, hPen );
|
|
|
|
MoveToEx( hdc, pptStart->x, pptStart->y , 0);
|
|
|
|
switch( lpc->wType )
|
|
{
|
|
case TT_PRIM_LINE:
|
|
|
|
PolylineTo(hdc, (POINT *)lpc->apfx, (DWORD)lpc->cpfx);
|
|
break;
|
|
|
|
case TT_PRIM_CSPLINE:
|
|
|
|
PolyBezierTo(hdc, (POINT *)lpc->apfx, (DWORD)lpc->cpfx);
|
|
break;
|
|
}
|
|
SelectObject( hdc, hPenOld );
|
|
pptStart = (POINT *)&lpc->apfx[lpc->cpfx - 1]; // Starting Point
|
|
n = sizeof(TTPOLYCURVE) + sizeof(POINTFX) * (lpc->cpfx - 1);
|
|
lpb += n;
|
|
cbOutline -= n;
|
|
}
|
|
|
|
hPenOld = SelectObject( hdc, hPen );
|
|
pptStart = (POINT *)&lpph->pfxStart; // Starting Point
|
|
LineTo( hdc, pptStart->x, pptStart->y);
|
|
SelectObject( hdc, hPenOld );
|
|
|
|
dprintf( "ended at cbOutline = %ld", cbOutline );
|
|
cbTotal -= lpph->cb;
|
|
lpph = (LPTTPOLYGONHEADER)lpb;
|
|
}
|
|
|
|
dprintf( "ended at cbTotal = %ld", cbTotal );
|
|
|
|
if (hPen)
|
|
DeleteObject(hPen);
|
|
|
|
if( pTTPH )
|
|
free( pTTPH );
|
|
}
|