ICU-1428 initial checkin of LayoutEngine sample

X-SVN-Rev: 6681
This commit is contained in:
Eric Mader 2001-11-07 23:48:17 +00:00
parent cd1ece982b
commit 3d90f8a272
37 changed files with 3840 additions and 4 deletions

View file

@ -4174,7 +4174,7 @@ trap 'rm -fr `echo "README icudefs.mk \
test/collperf/Makefile \
test/thaitest/Makefile \
test/letest/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile samples/layout/Makefile \
common/unicode/platform.h common/icucfg.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS <<EOF
@ -4347,7 +4347,7 @@ CONFIG_FILES=\${CONFIG_FILES-"README icudefs.mk \
test/collperf/Makefile \
test/thaitest/Makefile \
test/letest/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile samples/layout/Makefile \
common/unicode/platform.h"}
EOF
cat >> $CONFIG_STATUS <<\EOF

View file

@ -4,7 +4,7 @@ dnl Copyright (c) 1999-2000, International Business Machines Corporation and
dnl others. All Rights Reserved.
dnl Stephen F. Booth, heavily modified by Yves and others
dnl $Id: configure.in,v 1.134 2001/11/01 17:28:18 grhoten-oss Exp $
dnl $Id: configure.in,v 1.135 2001/11/07 23:48:17 emader-oss Exp $
dnl Process this file with autoconf to produce a configure script
AC_INIT(common/unicode/utypes.h)
@ -856,7 +856,7 @@ AC_OUTPUT([README icudefs.mk \
test/collperf/Makefile \
test/thaitest/Makefile \
test/letest/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile \
samples/Makefile samples/date/Makefile samples/cal/Makefile samples/layout/Makefile \
common/unicode/platform.h])
if test $ICU_USE_THREADS = 0; then

View file

@ -0,0 +1,8 @@
# This is a sample FontMap file for Windows.
# Fonts are specified by font name, as shown
# in the "Fonts" folder.
LATIN: Times New Roman
DEVANAGARI: Devanagari MT for IBM
ARABIC: Times New Roman
THAI: Thonburi

View file

@ -0,0 +1,7 @@
# This is a sample FontMap file for Linux.
# Fonts are specified by file names.
LATIN: Times.TTF
DEVANAGARI: Devamt.ttf
ARABIC: Times.TTF
THAI: THONBURI.TTF

View file

@ -0,0 +1,206 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "unicode/utypes.h"
#include "unicode/uscript.h"
#include "layout/LETypes.h"
#include "layout/LEScripts.h"
#include "RenderingFontInstance.h"
#include "GUISupport.h"
#include "FontMap.h"
FontMap::FontMap(const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status)
: fPointSize(pointSize), fFontCount(0), fGUISupport(guiSupport)
{
le_int32 i, script;
for (i = 0; i < scriptCodeCount; i += 1) {
fFontIndices[i] = -1;
fFontNames[i] = NULL;
fFontInstances[i] = NULL;
}
if (LE_FAILURE(status)) {
return;
}
char *c, *s, *line, buffer[BUFFER_SIZE];
FILE *file;
file = fopen(fileName, "r");
if (file == NULL) {
sprintf(errorMessage, "Could not open the font map file: %s.", fileName);
fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
status = RFI_FONT_FILE_NOT_FOUND_ERROR;
return;
}
while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
UScriptCode scriptCode;
UErrorCode scriptStatus = U_ZERO_ERROR;
line = strip(buffer);
if (line[0] == '#' || line[0] == 0) {
continue;
}
c = strchr(line, ':');
c[0] = 0;
s = strip(&c[1]);
uscript_getCode(strip(line), &scriptCode, 1, &scriptStatus);
if (U_FAILURE(scriptStatus) || scriptStatus == U_USING_FALLBACK_WARNING ||
scriptStatus == U_USING_DEFAULT_WARNING) {
sprintf(errorMessage, "The script name %s is invalid.", line);
fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
status = RFI_ILLEGAL_ARGUMENT_ERROR;
fclose(file);
return;
}
script = (le_int32) scriptCode;
if (fFontIndices[script] >= 0) {
// FIXME: complain that this is a duplicate entry and bail (?)
fFontIndices[script] = -1;
}
fFontIndices[script] = getFontIndex(s);
}
fclose(file);
}
FontMap::~FontMap()
{
le_int32 font;
for (font = 0; font < fFontCount; font += 1) {
if (fFontNames[font] != NULL) {
delete[] (char *) fFontNames[font];
}
}
for (font = 0; font < fFontCount; font += 1) {
if (fFontInstances[font] != NULL) {
delete fFontInstances[font];
}
}
}
le_int32 FontMap::getFontIndex(const char *fontName)
{
le_int32 index;
for (index = 0; index < fFontCount; index += 1) {
if (strcmp(fontName, fFontNames[index]) == 0) {
return index;
}
}
if (fFontCount < (le_int32) scriptCodeCount) {
index = fFontCount++;
} else {
// The font name table is full. Since there can
// only be scriptCodeCount fonts in use at once,
// there should be at least one that's not being
// reference; find it and resue it's index.
for (index = 0; index < fFontCount; index += 1) {
le_int32 script;
for (script = 0; script < scriptCodeCount; script += 1) {
if (fFontIndices[script] == index) {
break;
}
}
if (script >= scriptCodeCount) {
break;
}
}
}
if (index >= scriptCodeCount) {
return -1;
}
le_int32 len = strlen(fontName);
char *s = new char[len + 1];
fFontNames[index] = strcpy(s, fontName);
return index;
}
char *FontMap::strip(char *s)
{
le_int32 start, end, len;
start = 0;
len = strlen(s);
while (start < len && isspace(s[start])) {
start += 1;
}
end = len - 1;
while (end > start && isspace(s[end])) {
end -= 1;
}
if (end < len) {
s[end + 1] = '\0';
}
return &s[start];
}
const RenderingFontInstance *FontMap::getScriptFont(le_int32 scriptCode, RFIErrorCode &status)
{
if (LE_FAILURE(status)) {
return NULL;
}
if (scriptCode <= -1 || scriptCode >= scriptCodeCount) {
status = RFI_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
le_int32 fontIndex = fFontIndices[scriptCode];
if (fontIndex < 0) {
sprintf(errorMessage, "No font was set for script %s", uscript_getName((UScriptCode) scriptCode));
fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
status = RFI_FONT_FILE_NOT_FOUND_ERROR;
return NULL;
}
if (fFontInstances[fontIndex] == NULL) {
fFontInstances[fontIndex] = openFont(fFontNames[fontIndex], fPointSize, status);
if (LE_FAILURE(status)) {
sprintf(errorMessage, "Could not open font file %s", fFontNames[fontIndex]);
fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
return NULL;
}
}
return fFontInstances[fontIndex];
}

View file

@ -0,0 +1,48 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#ifndef __FONTMAP_H
#define __FONTMAP_H
#include "layout/LETypes.h"
#include "layout/LEScripts.h"
#include "RenderingFontInstance.h"
#include "GUISupport.h"
#define BUFFER_SIZE 128
class FontMap
{
public:
FontMap(const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status);
virtual ~FontMap();
virtual const RenderingFontInstance *getScriptFont(le_int32 scriptCode, RFIErrorCode &status);
protected:
virtual const RenderingFontInstance *openFont(const char *fontName, le_int16 pointSize, RFIErrorCode &status) = 0;
char errorMessage[256];
private:
static char *strip(char *s);
le_int32 getFontIndex(const char *fontName);
le_int16 fPointSize;
le_int32 fFontCount;
GUISupport *fGUISupport;
const RenderingFontInstance *fFontInstances[scriptCodeCount];
const char *fFontNames[scriptCodeCount];
le_int32 fFontIndices[scriptCodeCount];
};
#endif

View file

@ -0,0 +1,265 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GDIFontInstance.cpp
*
* created on: 08/09/2000
* created by: Eric R. Mader
*/
#include <windows.h>
#include "layout/LETypes.h"
#include "layout/LESwaps.h"
#include "RenderingFontInstance.h"
#include "GDIFontInstance.h"
#include "sfnt.h"
#include "cmaps.h"
GDIFontInstance::GDIFontInstance(HDC hdc, TCHAR *faceName, le_int16 pointSize, RFIErrorCode &status)
: fHdc(hdc), fFont(NULL), RenderingFontInstance(hdc, pointSize)
{
LOGFONT lf;
FLOAT dpiX, dpiY;
POINT pt;
OUTLINETEXTMETRIC otm;
if (LE_FAILURE(status)) {
return;
}
SaveDC(hdc);
SetGraphicsMode(hdc, GM_ADVANCED);
ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
SetViewportOrgEx(hdc, 0, 0, NULL);
SetWindowOrgEx(hdc, 0, 0, NULL);
dpiX = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSX);
dpiY = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSY);
#if 1
pt.x = (int) (pointSize * dpiX / 72);
pt.y = (int) (pointSize * dpiY / 72);
DPtoLP(hdc, &pt, 1);
#else
pt.x = pt.y = pointSize;
#endif
lf.lfHeight = - pt.y;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = 0;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = 0;
lf.lfClipPrecision = 0;
lf.lfQuality = 0;
lf.lfPitchAndFamily = 0;
lstrcpy(lf.lfFaceName, faceName);
fFont = CreateFontIndirect(&lf);
if (fFont == NULL) {
status = RFI_FONT_FILE_NOT_FOUND_ERROR;
return;
}
SelectObject(hdc, fFont);
UINT ret = GetOutlineTextMetrics(hdc, sizeof otm, &otm);
if (ret == 0) {
status = RFI_MISSING_FONT_TABLE_ERROR;
goto restore;
}
fUnitsPerEM = otm.otmEMSquare;
fAscent = otm.otmTextMetrics.tmAscent;
fDescent = otm.otmTextMetrics.tmDescent;
fLeading = otm.otmTextMetrics.tmExternalLeading;
status = initMapper();
if (LE_FAILURE(status)) {
goto restore;
}
status = initFontTableCache();
restore:
RestoreDC(hdc, -1);
}
GDIFontInstance::GDIFontInstance(HDC hdc, const char *faceName, le_int16 pointSize, RFIErrorCode &status)
: fHdc(hdc), fFont(NULL), RenderingFontInstance(hdc, pointSize)
{
LOGFONTA lf;
FLOAT dpiX, dpiY;
POINT pt;
OUTLINETEXTMETRIC otm;
if (LE_FAILURE(status)) {
return;
}
SaveDC(hdc);
SetGraphicsMode(hdc, GM_ADVANCED);
ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
SetViewportOrgEx(hdc, 0, 0, NULL);
SetWindowOrgEx(hdc, 0, 0, NULL);
dpiX = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSX);
dpiY = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSY);
#if 1
pt.x = (int) (pointSize * dpiX / 72);
pt.y = (int) (pointSize * dpiY / 72);
DPtoLP(hdc, &pt, 1);
#else
pt.x = pt.y = pointSize;
#endif
lf.lfHeight = - pt.y;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = 0;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = 0;
lf.lfClipPrecision = 0;
lf.lfQuality = 0;
lf.lfPitchAndFamily = 0;
strcpy(lf.lfFaceName, faceName);
fFont = CreateFontIndirectA(&lf);
if (fFont == NULL) {
status = RFI_FONT_FILE_NOT_FOUND_ERROR;
return;
}
SelectObject(hdc, fFont);
UINT ret = GetOutlineTextMetrics(hdc, sizeof otm, &otm);
if (ret == 0) {
status = RFI_MISSING_FONT_TABLE_ERROR;
goto restore;
}
fUnitsPerEM = otm.otmEMSquare;
fAscent = otm.otmTextMetrics.tmAscent;
fDescent = otm.otmTextMetrics.tmDescent;
fLeading = otm.otmTextMetrics.tmExternalLeading;
status = initMapper();
if (LE_FAILURE(status)) {
goto restore;
}
status = initFontTableCache();
restore:
RestoreDC(hdc, -1);
}
GDIFontInstance::~GDIFontInstance()
{
#if 0
flushFontTableCache();
delete[] fTableCache;
#endif
if (fFont != NULL) {
// FIXME: call RemoveObject first?
DeleteObject(fFont);
}
}
const void *GDIFontInstance::readFontTable(LETag tableTag) const
{
DWORD stag = SWAPL(tableTag);
DWORD len = GetFontData(fHdc, stag, 0, NULL, 0);
void *result = NULL;
if (len != GDI_ERROR) {
result = new char[len];
GetFontData(fHdc, stag, 0, result, len);
}
return result;
}
void GDIFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
{
advance.fX = 0;
advance.fY = 0;
if (glyph == 0xFFFE || glyph == 0xFFFF) {
return;
}
GLYPHMETRICS metrics;
DWORD result;
MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
result = GetGlyphOutline(fHdc, glyph, GGO_GLYPH_INDEX | GGO_METRICS, &metrics, 0, NULL, &identity);
if (result == GDI_ERROR) {
return;
}
advance.fX = metrics.gmCellIncX;
return;
}
le_bool GDIFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
{
#if 0
hsFixedPoint2 pt;
le_bool result;
result = fFontInstance->getGlyphPoint(glyph, pointNumber, pt);
if (result) {
point.fX = xUnitsToPoints(pt.fX);
point.fY = yUnitsToPoints(pt.fY);
}
return result;
#else
return false;
#endif
}
void GDIFontInstance::drawGlyphs(void *surface, LEGlyphID *glyphs, le_uint32 count, le_int32 *dx,
le_int32 x, le_int32 y, le_int32 width, le_int32 height) const
{
HDC hdc = (HDC) surface;
RECT clip;
clip.top = 0;
clip.left = 0;
clip.bottom = height;
clip.right = width;
ExtTextOut(hdc, x, y - fAscent, ETO_CLIPPED | ETO_GLYPH_INDEX, &clip, glyphs, count, (INT *) dx);
};

View file

@ -0,0 +1,55 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GDIFontInstance.h
*
* created on: 08/09/2000
* created by: Eric R. Mader
*/
#ifndef __GDIFONTINSTANCE_H
#define __GDIFONTINSTANCE_H
#include <windows.h>
#include "layout/LETypes.h"
#include "RenderingFontInstance.h"
#include "cmaps.h"
class GDIFontInstance : public RenderingFontInstance
{
protected:
HDC fHdc;
HFONT fFont;
virtual const void *readFontTable(LETag tableTag) const;
public:
GDIFontInstance(HDC theHDC, TCHAR *faceName, le_int16 pointSize, RFIErrorCode &status);
GDIFontInstance(HDC theHDC, const char *faceName, le_int16 pointSize, RFIErrorCode &status);
//GDIFontInstance(HDC theHDC, le_int16 pointSize);
virtual ~GDIFontInstance();
virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const;
virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const;
virtual const void setFont(void *surface) const
{
HDC hdc = (HDC) surface;
SelectObject(hdc, fFont);
};
virtual void drawGlyphs(void *surface, LEGlyphID *glyphs, le_uint32 count, le_int32 *dx,
le_int32 x, le_int32 y, le_int32 width, le_int32 height) const;
};
#endif

View file

@ -0,0 +1,31 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#include <windows.h>
#include "RenderingFontInstance.h"
#include "GDIFontInstance.h"
#include "GUISupport.h"
#include "FontMap.h"
#include "GDIFontMap.h"
GDIFontMap::GDIFontMap(HDC hdc, const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status)
: FontMap(fileName, pointSize, guiSupport, status), fHdc(hdc)
{
// nothing to do?
}
GDIFontMap::~GDIFontMap()
{
// anything?
}
const RenderingFontInstance *GDIFontMap::openFont(const char *fontName, le_int16 pointSize, RFIErrorCode &status)
{
return new GDIFontInstance(fHdc, fontName, pointSize, status);
}

View file

@ -0,0 +1,37 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#ifndef __GDIFONTMAP_H
#define __GDIFONTMAP_H
#include <windows.h>
#include "unicode/uscript.h"
#include "layout/LETypes.h"
#include "FontMap.h"
#include "GUISupport.h"
#include "RenderingFontInstance.h"
#define BUFFER_SIZE 128
class GDIFontMap : public FontMap
{
public:
GDIFontMap(HDC hdc, const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status);
virtual ~GDIFontMap();
protected:
virtual const RenderingFontInstance *openFont(const char *fontName, le_int16 pointSize, RFIErrorCode &status);
private:
HDC fHdc;
};
#endif

View file

@ -0,0 +1,22 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GDIGUISupport.h
*
* created on: 11/06/2001
* created by: Eric R. Mader
*/
#include <windows.h>
#include "GDIGUISupport.h"
void GDIGUISupport::postErrorMessage(const char *message, const char *title)
{
MessageBoxA(NULL, message, title, MB_ICONERROR);
}

View file

@ -0,0 +1,28 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GDIGUISupport.h
*
* created on: 11/06/2001
* created by: Eric R. Mader
*/
#ifndef __GDIGUISUPPORT_H
#define __GDIGUISUPPORT_H
#include "GUISupport.h"
class GDIGUISupport : public GUISupport
{
public:
GDIGUISupport() {};
~GDIGUISupport() {};
virtual void postErrorMessage(const char *message, const char *title);
};
#endif

View file

@ -0,0 +1,26 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GUISupport.h
*
* created on: 11/06/2001
* created by: Eric R. Mader
*/
#ifndef __GUISUPPORT_H
#define __GUISUPPORT_H
class GUISupport
{
public:
GUISupport() {};
~GUISupport() {};
virtual void postErrorMessage(const char *message, const char *title) = 0;
};
#endif

View file

@ -0,0 +1,276 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GnomeFontInstance.cpp
*
* created on: 08/30/2001
* created by: Eric R. Mader
*/
#include <gnome.h>
#include "freetype/freetype.h"
#include "layout/LETypes.h"
#include "layout/LESwaps.h"
#include "GnomeFontInstance.h"
#include "sfnt.h"
#include "cmaps.h"
GnomeFontInstance::GnomeFontInstance(TT_Engine engine, const TT_Text *fontPathName, le_int16 pointSize, RFIErrorCode &status)
: RenderingFontInstance(NULL, pointSize)
{
TT_Error error;
TT_Face_Properties faceProperties;
fFace.z = NULL;
error = TT_Open_Face(engine, fontPathName, &fFace);
if (error != 0) {
status = RFI_FONT_FILE_NOT_FOUND_ERROR;
return;
}
error = TT_New_Instance(fFace, &fInstance);
if (error != 0) {
status = RFI_OUT_OF_MEMORY_ERROR;
return;
}
// FIXME: what about the display resolution?
// TT_Set_Instance_Resolutions(fInstance, 72, 72);
TT_Set_Instance_CharSize(fInstance, pointSize << 6);
TT_Get_Face_Properties(fFace, &faceProperties);
fUnitsPerEM = faceProperties.header->Units_Per_EM;
fAscent = (le_int32) yUnitsToPoints(faceProperties.horizontal->Ascender);
fDescent = (le_int32) -yUnitsToPoints(faceProperties.horizontal->Descender);
fLeading = (le_int32) yUnitsToPoints(faceProperties.horizontal->Line_Gap);
// printf("Face = %s, unitsPerEM = %d, ascent = %d, descent = %d\n", fontPathName, fUnitsPerEM, fAscent, fDescent);
error = TT_New_Glyph(fFace, &fGlyph);
if (error != 0) {
status = RFI_OUT_OF_MEMORY_ERROR;
return;
}
status = initMapper();
if (LE_SUCCESS(status)) {
status = initFontTableCache();
}
}
GnomeFontInstance::~GnomeFontInstance()
{
if (fFace.z != NULL) {
TT_Close_Face(fFace);
}
}
const void *GnomeFontInstance::readFontTable(LETag tableTag) const
{
TT_Long len = 0;
void *result = NULL;
TT_Get_Font_Data(fFace, tableTag, 0, NULL, &len);
if (len > 0) {
result = new char[len];
TT_Get_Font_Data(fFace, tableTag, 0, result, &len);
}
return result;
}
void GnomeFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
{
advance.fX = 0;
advance.fY = 0;
if (glyph == 0xFFFF) {
return;
}
TT_Glyph_Metrics metrics;
TT_Error error;
error = TT_Load_Glyph(fInstance, fGlyph, glyph, TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
if (error != 0) {
return;
}
TT_Get_Glyph_Metrics(fGlyph, &metrics);
advance.fX = metrics.advance >> 6;
return;
}
le_bool GnomeFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
{
#if 1
TT_Outline outline;
TT_Error error;
error = TT_Load_Glyph(fInstance, fGlyph, glyph, TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
if (error != 0) {
return false;
}
error = TT_Get_Glyph_Outline(fGlyph, &outline);
if (error != 0 || pointNumber >= outline.n_points) {
return false;
}
point.fX = outline.points[pointNumber].x >> 6;
point.fY = outline.points[pointNumber].y >> 6;
return true;
#else
return false;
#endif
}
#define _R(b7,b6,b5,b4,b3,b2,b1,b0) ((b0<<7)|(b1<<6)|(b2<<5)|(b3<<4)|(b4<<3)|(b5<<2)|(b6<<1)|b7)
#define _B(b,n) ((b>>n)&1)
#define _H(b) _R(_B(b,7),_B(b,6),_B(b,5),_B(b,4),_B(b,3),_B(b,2),_B(b,1),_B(b,0))
const char bitReverse[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
// FIXME: this would be much faster if we cached the TT_Glyph objects based on the glyph ID...
void GnomeFontInstance::drawGlyphs(void *surface, LEGlyphID *glyphs, le_uint32 count, le_int32 *dx,
le_int32 x, le_int32 y, le_int32 width, le_int32 height) const
{
GtkWidget *widget = (GtkWidget *) surface;
le_int32 i, xx = 0, yy = 0, zz;
le_int32 minx = 0, maxx = 0, miny = 0, maxy = 0;
TT_Glyph_Metrics metrics;
TT_Error error;
//printf("drawGlyphs() - x = %d, y = %d, ", x, y);
for (i = 0; i < count; i += 1) {
error = TT_Load_Glyph(fInstance, fGlyph, glyphs[i], TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
if (error == 0) {
TT_Get_Glyph_Metrics(fGlyph, &metrics);
zz = xx + metrics.bbox.xMin;
if (minx > zz) {
minx = zz;
}
zz = xx + metrics.bbox.xMax;
if (maxx < zz) {
maxx = zz;
}
zz = yy + metrics.bbox.yMin;
if (miny > zz) {
miny = zz;
}
zz = yy + metrics.bbox.yMax;
if (maxy < zz) {
maxy = zz;
}
}
xx += (dx[i] * 64);
}
minx = (minx & -64) >> 6;
miny = (miny & -64) >> 6;
maxx = ((maxx + 63) & -64) >> 6;
maxy = ((maxy + 63) & -64) >> 6;
//printf("minx = %d, maxx = %d, miny = %d, maxy = %d\n", minx, maxx, miny, maxy);
TT_Raster_Map raster;
unsigned char *bits;
raster.flow = TT_Flow_Down;
raster.width = maxx - minx;
raster.rows = maxy - miny;
raster.cols = (raster.width + 7) / 8;
raster.size = raster.cols * raster.rows;
raster.bitmap = bits = new unsigned char[raster.size];
for (i = 0; i < raster.size; i += 1) {
bits[i] = 0;
}
xx = (-minx) * 64; yy = (-miny) * 64;
for (i = 0; i < count; i += 1) {
if (glyphs[i] < 0xFFFE) {
error = TT_Load_Glyph(fInstance, fGlyph, glyphs[i], TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
if (error == 0) {
TT_Get_Glyph_Bitmap(fGlyph, &raster, xx, yy);
}
}
xx += (dx[i] * 64);
}
for (i = 0; i < raster.size; i += 1) {
bits[i] = bitReverse[bits[i]];
}
if (raster.width > 0 && raster.rows > 0) {
GdkBitmap *bitmap = gdk_bitmap_create_from_data(NULL, (const gchar *) raster.bitmap, raster.width, raster.rows);
gint bitsx = x + minx;
gint bitsy = y - maxy;
gdk_gc_set_clip_origin(widget->style->black_gc, bitsx, bitsy);
gdk_gc_set_clip_mask(widget->style->black_gc, bitmap);
gdk_draw_rectangle(widget->window,
widget->style->black_gc,
TRUE,
bitsx, bitsy,
raster.width, raster.rows);
gdk_gc_set_clip_origin(widget->style->black_gc, 0, 0);
gdk_gc_set_clip_mask(widget->style->black_gc, NULL);
gdk_bitmap_unref(bitmap);
}
delete[] bits;
}

View file

@ -0,0 +1,49 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GnomeFontInstance.h
*
* created on: 08/30/2001
* created by: Eric R. Mader
*/
#ifndef __GNOMEFONTINSTANCE_H
#define __GNOMEFONTINSTANCE_H
#include <gnome.h>
#include "freetype/freetype.h"
#include "layout/LETypes.h"
#include "RenderingFontInstance.h"
#include "cmaps.h"
class GnomeFontInstance : public RenderingFontInstance
{
protected:
TT_Face fFace;
TT_Instance fInstance;
TT_Glyph fGlyph;
virtual const void *readFontTable(LETag tableTag) const;
public:
GnomeFontInstance(TT_Engine engine, const TT_Text *fontPathName, le_int16 pointSize, RFIErrorCode &status);
virtual ~GnomeFontInstance();
virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const;
virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const;
virtual void drawGlyphs(void *surface, LEGlyphID *glyphs, le_uint32 count, le_int32 *dx,
le_int32 x, le_int32 y, le_int32 width, le_int32 height) const;
};
#endif

View file

@ -0,0 +1,33 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#include <stdio.h>
#include "freetype/freetype.h"
#include "RenderingFontInstance.h"
#include "GnomeFontInstance.h"
#include "GUISupport.h"
#include "FontMap.h"
#include "GnomeFontMap.h"
GnomeFontMap::GnomeFontMap(TT_Engine engine, const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status)
: FontMap(fileName, pointSize, guiSupport, status), fEngine(engine)
{
// nothing to do?
}
GnomeFontMap::~GnomeFontMap()
{
// anything?
}
const RenderingFontInstance *GnomeFontMap::openFont(const char *fontName, le_int16 pointSize, RFIErrorCode &status)
{
return new GnomeFontInstance(fEngine, fontName, pointSize, status);
}

View file

@ -0,0 +1,37 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#ifndef __GNOMEFONTMAP_H
#define __GNOMEFONTMAP_H
#include "freetype/freetype.h"
#include "unicode/uscript.h"
#include "layout/LETypes.h"
#include "GUISupport.h"
#include "FontMap.h"
#include "RenderingFontInstance.h"
#define BUFFER_SIZE 128
class GnomeFontMap : public FontMap
{
public:
GnomeFontMap(TT_Engine engine, const char *fileName, le_int16 pointSize, GUISupport *guiSupport, RFIErrorCode &status);
virtual ~GnomeFontMap();
protected:
virtual const RenderingFontInstance *openFont(const char *fontName, le_int16 pointSize, RFIErrorCode &status);
private:
TT_Engine fEngine;
};
#endif

View file

@ -0,0 +1,23 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GnomeGUISupport.h
*
* created on: 11/06/2001
* created by: Eric R. Mader
*/
#include <stdio.h>
#include "GnomeGUISupport.h"
void GnomeGUISupport::postErrorMessage(const char *message, const char *title)
{
fprintf(stderr, "%s: %s\n", title, message);
}

View file

@ -0,0 +1,28 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: GnomeGUISupport.h
*
* created on: 11/06/2001
* created by: Eric R. Mader
*/
#ifndef __GNOMEGUISUPPORT_H
#define __GNOMEGUISUPPORT_H
#include "GUISupport.h"
class GnomeGUISupport : public GUISupport
{
public:
GnomeGUISupport() {};
~GnomeGUISupport() {};
virtual void postErrorMessage(const char *message, const char *title);
};
#endif

View file

@ -0,0 +1,88 @@
## Makefile.in for ICU - samples/layout
## Copyright (c) 2001, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../..
include $(top_builddir)/icudefs.mk
## Platform-specific setup
include @platform_make_fragment@
## Build directory information
subdir = samples/layout
## Extra files to remove for 'make clean'
CLEANFILES = *~ $(DEPS)
## Target information
TARGET = gnomelayout
DEFS = @DEFS@
CPPFLAGS = @CPPFLAGS@ `gnome-config --cflags gnomeui` -I$(top_builddir)/common -I$(top_srcdir)/common -I$(top_srcdir)/i18n -I$(top_srcdir)/layout -I$(top_srcdir)
CFLAGS = @CFLAGS@
CXXFLAGS = @CXXFLAGS@
ENABLE_RPATH = @ENABLE_RPATH@
ifeq ($(ENABLE_RPATH),YES)
RPATHLDFLAGS = $(LD_RPATH)$(LD_RPATH_PRE)$(libdir)
endif
LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)
INVOKE = $(LDLIBRARYPATH_ENVVAR)=$(top_builddir)/common:$(top_builddir)/i18n:$(top_builddir)/tools/toolutil:$$$(LDLIBRARYPATH_ENVVAR)
LIBS = $(LIBICULE) $(LIBICUUC) $(LIBICUI18N) @LIBS@ @LIB_M@ `gnome-config --libs gnomeui` -lttf
OBJECTS=cmaps.o scrptrun.o UnicodeReader.o GnomeGUISupport.o FontMap.o GnomeFontMap.o RenderingFontInstance.o GnomeFontInstance.o paragraph.o gnomelayout.o
DEPS = $(OBJECTS:.o=.d)
## List of phony targets
.PHONY : all all-local install install-local clean clean-local \
distclean distclean-local dist dist-local check check-local
## Clear suffix list
.SUFFIXES :
## List of standard targets
all: all-local
install: install-local
clean: clean-local
distclean : distclean-local
dist: dist-local
check: all check-local
all-local: $(TARGET)
install-local:
dist-local:
clean-local:
test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
$(RMV) $(OBJECTS) $(TARGET)
distclean-local: clean-local
$(RMV) Makefile
check-local: all-local
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
$(TARGET) : $(OBJECTS)
$(LINK.cc) -o $@ $^ $(LIBS)
invoke:
ICU_DATA=$${ICU_DATA:-$(top_builddir)/data/} TZ=PST8PDT $(INVOKE) $(INVOCATION)
ifeq (,$(MAKECMDGOALS))
-include $(DEPS)
else
ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),)
-include $(DEPS)
endif
endif

View file

@ -0,0 +1,164 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: RenderingFontInstance.cpp
*
* created on: 10/22/2001
* created by: Eric R. Mader
*/
#include "LETypes.h"
#include "LEFontInstance.h"
#include "RenderingFontInstance.h"
#include "LESwaps.h"
#include "sfnt.h"
#include "cmaps.h"
#include <string.h>
RenderingFontInstance::RenderingFontInstance(void *surface, le_int16 pointSize)
: fSurface(surface), fPointSize(pointSize), fUnitsPerEM(0), fAscent(0), fDescent(), fLeading(0),
fTableCache(NULL), fTableCacheCurr(0), fTableCacheSize(0), fMapper(NULL)
{
// we expect the subclass to call
// initMapper() and initFontTableCache
}
RenderingFontInstance::~RenderingFontInstance()
{
flushFontTableCache();
delete[] fTableCache;
delete fMapper;
}
void RenderingFontInstance::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count,
le_bool reverse, const LECharMapper *mapper, LEGlyphID glyphs[]) const
{
le_int32 i, out = 0, dir = 1;
if (reverse) {
out = count - 1;
dir = -1;
}
for (i = offset; i < offset + count; i += 1, out += dir) {
LEUnicode16 high = chars[i];
LEUnicode32 code = high;
if (i < offset + count - 1 && high >= 0xD800 && high <= 0xDBFF) {
LEUnicode16 low = chars[i + 1];
if (low >= 0xDC00 && low <= 0xDFFF) {
code = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;
}
}
glyphs[out] = mapCharToGlyph(code, mapper);
if (code >= 0x10000) {
i += 1;
glyphs[out += dir] = 0xFFFF;
}
}
}
LEGlyphID RenderingFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
{
LEUnicode32 mappedChar = mapper->mapChar(ch);
if (mappedChar == 0xFFFE || mappedChar == 0xFFFF) {
return 0xFFFF;
}
if (mappedChar == 0x200C || mappedChar == 0x200D) {
return 1;
}
return fMapper->unicodeToGlyph(mappedChar);
}
const void *RenderingFontInstance::getFontTable(LETag tableTag) const
{
for (int i = 0; i < fTableCacheCurr; i += 1) {
if (fTableCache[i].tag == tableTag) {
return fTableCache[i].table;
}
}
RenderingFontInstance *realThis = (RenderingFontInstance *) this;
if (realThis->fTableCacheCurr >= realThis->fTableCacheSize) {
le_int32 newSize = realThis->fTableCacheSize + TABLE_CACHE_GROW;
TableCacheEntry *newTable = new TableCacheEntry[newSize];
// FIXME: need a better strategy than this...
if (newTable == NULL) {
return NULL;
}
memcpy(newTable, realThis->fTableCache, realThis->fTableCacheSize * sizeof realThis->fTableCache[0]);
delete[] realThis->fTableCache;
for (int i = realThis->fTableCacheSize; i < newSize; i += 1) {
newTable[i].tag = 0;
newTable[i].table = NULL;
}
realThis->fTableCache = newTable;
realThis->fTableCacheSize = newSize;
}
realThis->fTableCache[realThis->fTableCacheCurr].tag = tableTag;
realThis->fTableCache[realThis->fTableCacheCurr].table = (void *) realThis->readFontTable(tableTag);
return fTableCache[realThis->fTableCacheCurr++].table;
};
RFIErrorCode RenderingFontInstance::initMapper()
{
LETag cmapTag = 0x636D6170; // 'cmap'
const CMAPTable *cmap = (const CMAPTable *) readFontTable(cmapTag);
if (cmap == NULL) {
return RFI_MISSING_FONT_TABLE_ERROR;
}
fMapper = CMAPMapper::createUnicodeMapper(cmap);
if (fMapper == NULL) {
return RFI_MISSING_FONT_TABLE_ERROR;
}
return RFI_NO_ERROR;
}
RFIErrorCode RenderingFontInstance::initFontTableCache()
{
fTableCacheSize = TABLE_CACHE_INIT;
fTableCache = new TableCacheEntry[fTableCacheSize];
if (fTableCache == 0) {
return RFI_OUT_OF_MEMORY_ERROR;
}
for (int i = 0; i < fTableCacheSize; i += 1) {
fTableCache[i].tag = 0;
fTableCache[i].table = NULL;
}
return RFI_NO_ERROR;
}
void RenderingFontInstance::flushFontTableCache()
{
for (int i = fTableCacheCurr - 1; i >= 0; i -= 1) {
delete[] (char *) fTableCache[i].table;
}
fTableCacheCurr = 0;
}

View file

@ -0,0 +1,175 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: RenderingFontInstance.h
*
* created on: 10/23/2001
* created by: Eric R. Mader
*/
#ifndef __RENDERINGFONTINSTANCE_H
#define __RENDERINGFONTINSTANCE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "cmaps.h"
#define TABLE_CACHE_INIT 5
#define TABLE_CACHE_GROW 5
struct TableCacheEntry
{
LETag tag;
void *table;
};
enum RFIErrorCode {
RFI_NO_ERROR = 0,
RFI_ILLEGAL_ARGUMENT_ERROR = 1,
RFI_FONT_FILE_NOT_FOUND_ERROR = 2,
RFI_MISSING_FONT_TABLE_ERROR = 3,
RFI_OUT_OF_MEMORY_ERROR = 4
};
class RenderingFontInstance : public LEFontInstance
{
protected:
void *fSurface;
le_int32 fPointSize;
le_int32 fUnitsPerEM;
le_int32 fAscent;
le_int32 fDescent;
le_int32 fLeading;
TableCacheEntry *fTableCache;
le_int32 fTableCacheCurr;
le_int32 fTableCacheSize;
CMAPMapper *fMapper;
virtual RFIErrorCode initMapper();
virtual RFIErrorCode initFontTableCache();
virtual void flushFontTableCache();
virtual const void *readFontTable(LETag tableTag) const = 0;
public:
RenderingFontInstance(void *surface, le_int16 pointSize);
virtual ~RenderingFontInstance();
virtual const void *getFontTable(LETag tableTag) const;
virtual le_bool canDisplay(LEUnicode32 ch) const
{
return fMapper->unicodeToGlyph(ch) != 0;
};
virtual le_int32 getUnitsPerEM() const
{
return fUnitsPerEM;
};
virtual le_int32 getLineHeight() const
{
return getAscent() + getDescent() + getLeading();
};
virtual le_int32 getAscent() const
{
return fAscent;
};
virtual le_int32 getDescent() const
{
return fDescent;
};
virtual le_int32 getLeading() const
{
return fLeading;
};
virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, const LECharMapper *mapper, LEGlyphID glyphs[]) const;
virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const;
virtual le_int32 getName(le_uint16 platformID, le_uint16 scriptID, le_uint16 languageID, le_uint16 nameID, LEUnicode *name) const
{
// This is only used for CDAC fonts, and we'll have to loose that support anyhow...
//return (le_int32) fFontObject->getName(platformID, scriptID, languageID, nameID, name);
if (name != NULL) {
*name = 0;
}
return 0;
};
virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const = 0;
virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const = 0;
virtual const void setFont(void *surface) const
{
// default implementation is to ignore this
};
virtual void drawGlyphs(void *surface, LEGlyphID *glyphs, le_uint32 count, le_int32 *dx,
le_int32 x, le_int32 y, le_int32 width, le_int32 height) const = 0;
float getXPixelsPerEm() const
{
return (float) fPointSize;
};
float getYPixelsPerEm() const
{
return (float) fPointSize;
};
float xUnitsToPoints(float xUnits) const
{
return (xUnits * fPointSize) / (float) fUnitsPerEM;
};
float yUnitsToPoints(float yUnits) const
{
return (yUnits * fPointSize) / (float) fUnitsPerEM;
};
void unitsToPoints(LEPoint &units, LEPoint &points) const
{
points.fX = xUnitsToPoints(units.fX);
points.fY = yUnitsToPoints(units.fY);
}
float xPixelsToUnits(float xPixels) const
{
return (xPixels * fUnitsPerEM) / (float) fPointSize;
};
float yPixelsToUnits(float yPixels) const
{
return (yPixels * fUnitsPerEM) / (float) fPointSize;
};
void pixelsToUnits(LEPoint &pixels, LEPoint &units) const
{
units.fX = xPixelsToUnits(pixels.fX);
units.fY = yPixelsToUnits(pixels.fY);
};
void transformFunits(float xFunits, float yFunits, LEPoint &pixels) const
{
pixels.fX = xUnitsToPoints(xFunits);
pixels.fY = yUnitsToPoints(yFunits);
}
};
#endif

View file

@ -0,0 +1,28 @@
The LayoutEngine does all the work necessary to display Unicode text written in languages with complex
writing systems such as Hindi (हिन्दी)
Thai (ไทย) and Arabic (العربية). Here's a sample of some text written in Sanskrit:
श्रीमद् भगवद्गीता
अध्याय अर्जुन विषाद
योग धृतराष्ट्र उवाचृ
धर्मक्षेत्रे
कुरुक्षेत्रे समवेता
युयुत्सवः मामकाः
पाण्डवाश्चैव किमकुर्वत
संजव Here's a sample of some text written in Arabic:
أساسًا، تتعامل
الحواسيب فقط مع
الأرقام، وتقوم ب
تخزين الأحرف والمحارف ال
أخرى بعد أن تُعطي رقما م
عينا لكل واحد من
ها. وقبل اختراع
"يونِكود"، كان ه
ناك مئات الأنظمة
للتشفير وتخصيص
هذه الأر
قام للمح
ارف، ولم يوجد نظ
ام تشفير واحد يح
توي على جميع المحارف الض
رورية and here's a sample of some text written in Thai:
บทที่๑พายุไซโคลนโดโรธีอาศัยอยู่ท่ามกลางทุ่งใหญ่ในแคนซัสกับลุงเฮนรีชาวไร่และป้าเอ็มภรรยาชาวไร่บ้านของพวกเขาหลังเล็กเพราะไม้สร้างบ้านต้องขนมาด้วยเกวียนเป็นระยะทางหลายไมล์

View file

@ -0,0 +1,116 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "unicode/utypes.h"
#include "unicode/unistr.h"
#include "GUISupport.h"
#include "UnicodeReader.h"
/*
* Read the text from a file. The text must start with a Unicode Byte
* Order Mark (BOM) so that we know what order to read the bytes in.
*/
const UChar *UnicodeReader::readFile(const char *fileName, GUISupport *guiSupport, int32_t &charCount)
{
FILE *f;
int32_t fileSize;
UChar *charBuffer;
char *byteBuffer;
char startBytes[4] = {'\xA5', '\xA5', '\xA5', '\xA5'};
char errorMessage[128];
char *cp = "";
int32_t signatureLength = 0;
f = fopen(fileName, "rb");
if( f == NULL ) {
sprintf(errorMessage,"Couldn't open %s: %s \n", fileName, strerror(errno));
guiSupport->postErrorMessage(errorMessage, "Text File Error");
return 0;
}
fseek(f, 0, SEEK_END);
fileSize = ftell(f);
fseek(f, 0, SEEK_SET);
fread(startBytes, sizeof(char), 4, f);
if (startBytes[0] == '\xFE' && startBytes[1] == '\xFF') {
cp = "UTF-16BE";
signatureLength = 2;
} else if (startBytes[0] == '\xFF' && startBytes[1] == '\xFE') {
if (startBytes[2] == '\x00' && startBytes[3] == '\x00') {
cp = "UTF-32LE";
signatureLength = 4;
} else {
cp = "UTF-16LE";
signatureLength = 2;
}
} else if (startBytes[0] == '\xEF' && startBytes[1] == '\xBB' && startBytes[2] == '\xBF') {
cp = "UTF-8";
signatureLength = 3;
} else if (startBytes[0] == '\x0E' && startBytes[1] == '\xFE' && startBytes[2] == '\xFF') {
cp = "SCSU";
signatureLength = 3;
} else if (startBytes[0] == '\x00' && startBytes[1] == '\x00' &&
startBytes[2] == '\xFE' && startBytes[3] == '\xFF') {
cp = "UTF-32BE";
signatureLength = 4;
} else {
sprintf(errorMessage, "Couldn't detect the encoding of %s: (%2.2X, %2.2X, %2.2X, %2.2X)\n", fileName,
startBytes[0], startBytes[1], startBytes[2], startBytes[3]);
guiSupport->postErrorMessage(errorMessage, "Text File Error");
fclose(f);
return 0;
}
fileSize -= signatureLength;
fseek(f, signatureLength, SEEK_SET);
byteBuffer = new char[fileSize];
if(byteBuffer == 0) {
sprintf(errorMessage,"Couldn't get memory for reading %s: %s \n", fileName, strerror(errno));
guiSupport->postErrorMessage(errorMessage, "Text File Error");
fclose(f);
return 0;
}
fread(byteBuffer, sizeof(char), fileSize, f);
if( ferror(f) ) {
sprintf(errorMessage,"Couldn't read %s: %s \n", fileName, strerror(errno));
guiSupport->postErrorMessage(errorMessage, "Text File Error");
fclose(f);
delete[] byteBuffer;
return 0;
}
fclose(f);
UnicodeString myText(byteBuffer, fileSize, cp);
delete[] byteBuffer;
charCount = myText.length();
charBuffer = new UChar[charCount];
if(charBuffer == 0) {
sprintf(errorMessage,"Couldn't get memory for reading %s: %s \n", fileName, strerror(errno));
guiSupport->postErrorMessage(errorMessage, "Text File Error");
return 0;
}
myText.extract(0, myText.length(), charBuffer);
charBuffer[charCount + 1] = 0; // NULL terminate for easier reading in the debugger
return charBuffer;
}

View file

@ -0,0 +1,32 @@
/*
******************************************************************************
* Copyright (C) 1998-2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
#ifndef __UNICODEREADER_H
#define __UNICODEREADER_H
#include "unicode/utypes.h"
#include "GUISupport.h"
class UnicodeReader
{
public:
UnicodeReader()
{
// nothing...
}
~UnicodeReader()
{
// nothing, too
}
static const UChar *readFile(const char *fileName, GUISupport *guiSupport, int32_t &charCount);
};
#endif

View file

@ -0,0 +1,203 @@
/*
****************************************************************************** *
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
****************************************************************************** *
* file name: cmaps.cpp
*
* created on: ??/??/2001
* created by: Eric R. Mader
*/
#include "layout/LETypes.h"
#include "layout/LESwaps.h"
#include "sfnt.h"
#include "cmaps.h"
//
// Finds the high bit by binary searching
// through the bits in value.
//
le_uint8 highBit(le_uint32 value)
{
le_uint8 bit = 0;
if (value >= 1 << 16) {
value >>= 16;
bit += 16;
}
if (value >= 1 << 8) {
value >>= 8;
bit += 8;
}
if (value >= 1 << 4) {
value >>= 4;
bit += 4;
}
if (value >= 1 << 2) {
value >>= 2;
bit += 2;
}
if (value >= 1 << 1) {
value >>= 1;
bit += 1;
}
return bit;
}
CMAPMapper *CMAPMapper::createUnicodeMapper(const CMAPTable *cmap)
{
le_uint16 i;
le_uint16 nSubtables = SWAPW(cmap->numberSubtables);
const CMAPEncodingSubtable *subtable = NULL;
le_uint32 offset1 = 0, offset10 = 0;
for (i = 0; i < nSubtables; i += 1) {
const CMAPEncodingSubtableHeader *esh = &cmap->encodingSubtableHeaders[i];
if (SWAPW(esh->platformID) == 3) {
switch (SWAPW(esh->platformSpecificID)) {
case 1:
offset1 = SWAPL(esh->encodingOffset);
break;
case 10:
offset10 = SWAPL(esh->encodingOffset);
break;
}
}
}
if (offset10 != 0)
{
subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset10);
} else if (offset1 != 0) {
subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset1);
} else {
return NULL;
}
switch (SWAPW(subtable->format)) {
case 4:
return new CMAPFormat4Mapper(cmap, (const CMAPFormat4Encoding *) subtable);
case 12:
{
const CMAPFormat12Encoding *encoding = (const CMAPFormat12Encoding *) subtable;
return new CMAPGroupMapper(cmap, encoding->groups, SWAPL(encoding->nGroups));
}
default:
break;
}
return NULL;
}
CMAPFormat4Mapper::CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header)
: CMAPMapper(cmap)
{
le_uint16 segCount = SWAPW(header->segCountX2) / 2;
fEntrySelector = SWAPW(header->entrySelector);
fRangeShift = SWAPW(header->rangeShift) / 2;
fEndCodes = &header->endCodes[0];
fStartCodes = &header->endCodes[segCount + 1]; // + 1 for reservedPad...
fIdDelta = &fStartCodes[segCount];
fIdRangeOffset = &fIdDelta[segCount];
}
LEGlyphID CMAPFormat4Mapper::unicodeToGlyph(LEUnicode32 unicode32) const
{
if (unicode32 >= 0x10000) {
return 0;
}
LEUnicode16 unicode = (LEUnicode16) unicode32;
le_uint16 index = 0;
le_uint16 probe = 1 << fEntrySelector;
LEGlyphID result = 0;
if (SWAPW(fStartCodes[fRangeShift]) <= unicode) {
index = fRangeShift;
}
while (probe > (1 << 0)) {
probe >>= 1;
if (SWAPW(fStartCodes[index + probe]) <= unicode) {
index += probe;
}
}
if (unicode >= SWAPW(fStartCodes[index]) && unicode <= SWAPW(fEndCodes[index])) {
if (fIdRangeOffset[index] == 0) {
result = (LEGlyphID) unicode;
} else {
le_uint16 offset = unicode - SWAPW(fStartCodes[index]);
le_uint16 rangeOffset = SWAPW(fIdRangeOffset[index]);
le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &fIdRangeOffset[index] + rangeOffset);
result = SWAPW(glyphIndexTable[offset]);
}
result += SWAPW(fIdDelta[index]);
} else {
result = 0;
}
return result;
}
CMAPFormat4Mapper::~CMAPFormat4Mapper()
{
// parent destructor does it all
}
CMAPGroupMapper::CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups)
: CMAPMapper(cmap), fGroups(groups)
{
le_uint8 bit = highBit(nGroups);
fPower = 1 << bit;
fRangeOffset = nGroups - fPower;
}
LEGlyphID CMAPGroupMapper::unicodeToGlyph(LEUnicode32 unicode32) const
{
le_int32 probe = fPower;
le_int32 range = 0;
if (SWAPL(fGroups[fRangeOffset].startCharCode) <= unicode32) {
range = fRangeOffset;
}
while (probe > (1 << 0)) {
probe >>= 1;
if (SWAPL(fGroups[range + probe].startCharCode) <= unicode32) {
range += probe;
}
}
if (SWAPL(fGroups[range].startCharCode) <= unicode32 && SWAPL(fGroups[range].endCharCode) >= unicode32) {
return (LEGlyphID) (SWAPL(fGroups[range].startGlyphCode) + unicode32 - SWAPL(fGroups[range].startCharCode));
}
return 0;
}
CMAPGroupMapper::~CMAPGroupMapper()
{
// parent destructor does it all
}

View file

@ -0,0 +1,89 @@
/*
****************************************************************************** *
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
****************************************************************************** *
* file name: cmaps.h
*
* created on: ??/??/2001
* created by: Eric R. Mader
*/
#ifndef __CMAPS_H
#define __CMAPS_H
#include "layout/LETypes.h"
#include "sfnt.h"
class CMAPMapper
{
public:
virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const = 0;
virtual ~CMAPMapper();
static CMAPMapper *createUnicodeMapper(const CMAPTable *cmap);
protected:
CMAPMapper(const CMAPTable *cmap);
CMAPMapper() {};
private:
const CMAPTable *fcmap;
};
class CMAPFormat4Mapper : public CMAPMapper
{
public:
CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header);
virtual ~CMAPFormat4Mapper();
virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const;
protected:
CMAPFormat4Mapper() {};
private:
le_uint16 fEntrySelector;
le_uint16 fRangeShift;
const le_uint16 *fEndCodes;
const le_uint16 *fStartCodes;
const le_uint16 *fIdDelta;
const le_uint16 *fIdRangeOffset;
};
class CMAPGroupMapper : public CMAPMapper
{
public:
CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups);
virtual ~CMAPGroupMapper();
virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const;
protected:
CMAPGroupMapper() {};
private:
le_int32 fPower;
le_int32 fRangeOffset;
const CMAPGroup *fGroups;
};
inline CMAPMapper::CMAPMapper(const CMAPTable *cmap)
: fcmap(cmap)
{
// nothing else to do
}
inline CMAPMapper::~CMAPMapper()
{
delete[] (char *) fcmap;
}
#endif

View file

@ -0,0 +1,201 @@
/*
****************************************************************************** *
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
****************************************************************************** *
* file name: gnomelayout.cpp
*
* created on: 09/04/2001
* created by: Eric R. Mader
*/
#include <gnome.h>
#include "freetype/freetype.h"
#include "unicode/ustring.h"
#include "unicode/uscript.h"
#include "unicode/loengine.h"
#include "GnomeFontInstance.h"
#include "paragraph.h"
#include "GnomeGUISupport.h"
#include "GnomeFontMap.h"
#include "UnicodeReader.h"
#include "scrptrun.h"
#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
void showabout(GtkWidget *widget, gpointer data)
{
GtkWidget *aboutBox;
const gchar *writtenBy[] = {
"Eric Mader",
NULL
};
aboutBox = gnome_about_new("Gnome Layout Demo",
"0.1",
"Copyright (C) 1998-2001 By International Business Machines Corporation and others. All Rights Reserved.",
writtenBy,
"A simple demo of the ICU LayoutEngine.",
NULL);
gtk_widget_show(aboutBox);
}
void notimpl(GtkObject *object, gpointer data)
{
gnome_ok_dialog("Not implemented...");
}
void shutdown(GtkObject *object, gpointer data)
{
gtk_main_quit();
}
GnomeUIInfo fileMenu[] =
{
GNOMEUIINFO_MENU_OPEN_ITEM(notimpl, NULL),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_EXIT_ITEM(shutdown, NULL),
GNOMEUIINFO_END
};
GnomeUIInfo helpMenu[] =
{
// GNOMEUIINFO_HELP("gnomelayout"),
GNOMEUIINFO_MENU_ABOUT_ITEM(showabout, NULL),
GNOMEUIINFO_END
};
GnomeUIInfo mainMenu[] =
{
GNOMEUIINFO_SUBTREE(N_("File"), fileMenu),
GNOMEUIINFO_SUBTREE(N_("Help"), helpMenu),
GNOMEUIINFO_END
};
struct Context
{
long width;
long height;
Paragraph *paragraph;
};
gint eventDelete(GtkWidget *widget, GdkEvent *event, gpointer data)
{
return FALSE;
}
gint eventDestroy(GtkWidget *widget, GdkEvent *event, Context *context)
{
shutdown(GTK_OBJECT(widget), context);
return 0;
}
gint eventConfigure(GtkWidget *widget, GdkEventConfigure *event, Context *context)
{
context->width = event->width;
context->height = event->height;
if (context->width > 0 && context->height > 0) {
context->paragraph->breakLines(context->width, context->height);
}
return TRUE;
}
gint eventExpose(GtkWidget *widget, GdkEvent *event, Context *context)
{
gint maxLines = context->paragraph->getLineCount() - 1;
gint firstLine = 0, lastLine = context->height / context->paragraph->getLineHeight();
context->paragraph->draw(widget, firstLine, (maxLines < lastLine)? maxLines : lastLine);
return TRUE;
}
int main (int argc, char *argv[])
{
GtkWidget *app;
GtkWidget *area;
GtkStyle *style;
unsigned short status = 0;
Context context = {600, 400, NULL};
TT_Engine engine;
TT_Init_FreeType(&engine);
RFIErrorCode fontStatus = RFI_NO_ERROR;
GnomeGUISupport *guiSupport = new GnomeGUISupport();
GnomeFontMap *fontMap = new GnomeFontMap(engine, "FontMap.Gnome", 24, guiSupport, fontStatus);
if (LE_FAILURE(fontStatus)) {
TT_Done_FreeType(engine);
return 1;
}
// FIXME: is it cheating to pass NULL for surface, since we know that
// GnomeFontInstance won't use it?
context.paragraph = Paragraph::paragraphFactory("Sample.utf8", fontMap, guiSupport, NULL);
if (context.paragraph != NULL) {
gnome_init("gnomelayout", "1.0", argc, argv);
app = gnome_app_new("gnomelayout", "Gnome Layout");
gtk_window_set_default_size(GTK_WINDOW(app), 600 - 24, 400);
gnome_app_create_menus(GNOME_APP(app), mainMenu);
gtk_signal_connect(GTK_OBJECT(app),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(app),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
&context);
area = gtk_drawing_area_new();
#if 1
style = gtk_style_copy(gtk_widget_get_style(area));
for (int i = 0; i < 5; i += 1) {
style->fg[i] =style->white;
}
gtk_widget_set_style(area, style);
#endif
gnome_app_set_contents(GNOME_APP(app), area);
gtk_signal_connect(GTK_OBJECT(area),
"expose_event",
GTK_SIGNAL_FUNC(eventExpose),
&context);
gtk_signal_connect(GTK_OBJECT(area),
"configure_event",
GTK_SIGNAL_FUNC(eventConfigure),
&context);
gtk_widget_show_all(app);
gtk_main();
delete context.paragraph;
}
delete fontMap;
TT_Done_FreeType(engine);
exit(0);
}

View file

@ -0,0 +1,246 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: Layout.cpp
*
* created on: 08/03/2000
* created by: Eric R. Mader
*/
#include <windows.h>
//#include "LETypes.h"
//#include "LEFontInstance.h"
//#include "LayoutEngine.h"
//#include "unicode/loengine.h"
#include "unicode/uscript.h"
//#include "LEScripts.h"
#include "GDIFontInstance.h"
#include "paragraph.h"
#include "GDIGUISupport.h"
#include "GDIFontMap.h"
#include "UnicodeReader.h"
#include "scrptrun.h"
#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
TCHAR szAppName[] = TEXT("LayoutDemo");
TCHAR szTitle[] = TEXT("LayoutDemo: Demo of LayoutEngine");
RFIErrorCode status = RFI_NO_ERROR;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(LONG);
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("This demo only runs on Windows 2000!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, szTitle,
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT,
600, 400,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
Paragraph *paragraph;
static le_int32 windowCount = 0;
static GDIFontMap *fontMap = NULL;
static GDIGUISupport *guiSupport = new GDIGUISupport();
switch (message) {
case WM_CREATE:
{
RFIErrorCode fontStatus = RFI_NO_ERROR;
hdc = GetDC(hwnd);
fontMap = new GDIFontMap(hdc, "FontMap.GDI", 24, guiSupport, fontStatus);
if (LE_FAILURE(fontStatus)) {
ReleaseDC(hwnd, hdc);
return 0;
}
paragraph = Paragraph::paragraphFactory("Sample.utf8", fontMap, guiSupport, hdc);
SetWindowLong(hwnd, 0, (LONG) paragraph);
windowCount += 1;
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_SIZE:
{
le_int32 width = LOWORD(lParam);
le_int32 height = HIWORD(lParam);
SCROLLINFO si;
paragraph = (Paragraph *) GetWindowLong(hwnd, 0);
if (paragraph != NULL) {
// FIXME: does it matter what we put in the ScrollInfo
// if the window's been minimized?
if (width > 0 && height > 0) {
paragraph->breakLines(width, height);
}
si.cbSize = sizeof si;
si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = paragraph->getLineCount() - 1;
si.nPage = height / paragraph->getLineHeight();
SetScrollInfo(hwnd, SB_VERT, &si, true);
}
return 0;
}
case WM_VSCROLL:
{
SCROLLINFO si;
le_int32 vertPos;
si.cbSize = sizeof si;
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, &si);
vertPos = si.nPos;
switch (LOWORD(wParam))
{
case SB_TOP:
si.nPos = si.nMin;
break;
case SB_BOTTOM:
si.nPos = si.nMax;
break;
case SB_LINEUP:
si.nPos -= 1;
break;
case SB_LINEDOWN:
si.nPos += 1;
break;
case SB_PAGEUP:
si.nPos -= si.nPage;
break;
case SB_PAGEDOWN:
si.nPos += si.nPage;
break;
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default:
break;
}
si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_VERT, &si, true);
GetScrollInfo(hwnd, SB_VERT, &si);
paragraph = (Paragraph *) GetWindowLong(hwnd, 0);
if (paragraph != NULL && si.nPos != vertPos) {
ScrollWindow(hwnd, 0, paragraph->getLineHeight() * (vertPos - si.nPos), NULL, NULL);
UpdateWindow(hwnd);
}
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
SCROLLINFO si;
le_int32 firstLine, lastLine;
hdc = BeginPaint(hwnd, &ps);
si.cbSize = sizeof si;
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, &si);
firstLine = si.nPos;
paragraph = (Paragraph *) GetWindowLong(hwnd, 0);
if (paragraph != NULL) {
// NOTE: si.nPos + si.nPage may include a partial line at the bottom
// of the window. We need this because scrolling assumes that the
// partial line has been painted.
lastLine = min (si.nPos + (le_int32) si.nPage, paragraph->getLineCount() - 1);
paragraph->draw(hdc, firstLine, lastLine);
}
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
{
paragraph = (Paragraph *) GetWindowLong(hwnd, 0);
if (paragraph != NULL) {
delete paragraph;
}
if (--windowCount <= 0) {
delete fontMap;
PostQuitMessage(0);
}
return 0;
}
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}

View file

@ -0,0 +1,184 @@
# Microsoft Developer Studio Project File - Name="layout" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=layout - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "layout.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "layout.mak" CFG="layout - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "layout - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "layout - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "layout - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\include" /I "..\..\..\include\layout" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "UNICODE" /D _WIN32_WINNT=0X500 /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 ..\..\..\lib\icule.lib ..\..\..\lib\icuuc.lib ..\..\..\lib\icuin.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "layout - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\include" /I "..\..\..\include\layout" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "UNICODE" /D _WIN32_WINNT=0X500 /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 ..\..\..\lib\iculed.lib ..\..\..\lib\icuucd.lib ..\..\..\lib\icuind.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "layout - Win32 Release"
# Name "layout - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\cmaps.cpp
# End Source File
# Begin Source File
SOURCE=.\FontMap.cpp
# End Source File
# Begin Source File
SOURCE=.\GDIFontInstance.cpp
# End Source File
# Begin Source File
SOURCE=.\GDIFontMap.cpp
# End Source File
# Begin Source File
SOURCE=.\GDIGUISupport.cpp
# End Source File
# Begin Source File
SOURCE=.\layout.cpp
# End Source File
# Begin Source File
SOURCE=.\paragraph.cpp
# End Source File
# Begin Source File
SOURCE=.\RenderingFontInstance.cpp
# End Source File
# Begin Source File
SOURCE=.\scrptrun.cpp
# End Source File
# Begin Source File
SOURCE=.\UnicodeReader.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\cmaps.h
# End Source File
# Begin Source File
SOURCE=.\FontMap.h
# End Source File
# Begin Source File
SOURCE=.\GDIFontInstance.h
# End Source File
# Begin Source File
SOURCE=.\GDIFontMap.h
# End Source File
# Begin Source File
SOURCE=.\GDIGUISupport.h
# End Source File
# Begin Source File
SOURCE=.\GUISupport.h
# End Source File
# Begin Source File
SOURCE=.\paragraph.h
# End Source File
# Begin Source File
SOURCE=.\RenderingFontInstance.h
# End Source File
# Begin Source File
SOURCE=.\scrptrun.h
# End Source File
# Begin Source File
SOURCE=.\sfnt.h
# End Source File
# Begin Source File
SOURCE=.\UnicodeReader.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View file

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "layout"=.\layout.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -0,0 +1,481 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: Paragraph.cpp
*
* created on: 09/06/2000
* created by: Eric R. Mader
*/
#include "unicode/loengine.h"
#include "RenderingFontInstance.h"
#include "unicode/utypes.h"
#include "unicode/unicode.h"
#include "unicode/uchriter.h"
#include "unicode/brkiter.h"
#include "unicode/locid.h"
#include "paragraph.h"
#include "scrptrun.h"
#include "UnicodeReader.h"
#include "FontMap.h"
#define MARGIN 10
Paragraph::Paragraph(void *surface, RunParams params[], int32_t count)
: fRunCount(count), fRunInfo(NULL), fCharCount(0), fText(NULL), fGlyphCount(0), fGlyphs(NULL),
fCharIndices(NULL), fGlyphIndices(NULL), fDX(NULL), fBreakArray(NULL), fBreakCount(0),
fLineHeight(-1), fAscent(-1)
{
int32_t i;
fWidth = fHeight = 0;
fRunInfo = new RunInfo[count + 1];
// Set charBase and rightToLeft for
// each run and count the total characters
for (i = 0; i < count; i += 1) {
fRunInfo[i].charBase = fCharCount;
fRunInfo[i].rightToLeft = params[i].rightToLeft;
fCharCount += params[i].count;
}
// Set charBase and rightToLeft for the
// fake run at the end.
fRunInfo[count].charBase = fCharCount;
fRunInfo[count].rightToLeft = false;
fBreakArray = new int32_t[fCharCount + 1];
fText = new LEUnicode[fCharCount];
// Copy the text runs into a single array
for (i = 0; i < count; i += 1) {
int32_t charBase = fRunInfo[i].charBase;
int32_t charCount = fRunInfo[i + 1].charBase - charBase;
LE_ARRAY_COPY(&fText[charBase], params[i].text, charCount);
}
Locale thai("th");
UCharCharacterIterator *iter = new UCharCharacterIterator(fText, fCharCount);
UErrorCode status = U_ZERO_ERROR;
Locale dummyLocale;
fBrkiter = BreakIterator::createLineInstance(thai, status);
fBrkiter->adoptText(iter);
ICULayoutEngine **engines = new ICULayoutEngine *[count];
int32_t maxAscent = -1, maxDescent = -1, maxLeading = -1;
float x = 0, y = 0;
// Layout each run, set glyphBase and glyphCount
// and count the total number of glyphs
for (i = 0; i < count; i += 1) {
int32_t charBase = fRunInfo[i].charBase;
int32_t charCount = fRunInfo[i + 1].charBase - charBase;
int32_t glyphCount = 0;
int32_t runAscent = 0, runDescent = 0, runLeading = 0;
UErrorCode success = U_ZERO_ERROR;
fRunInfo[i].fontInstance = params[i].fontInstance;
fRunInfo[i].fontInstance->setFont(surface);
runAscent = fRunInfo[i].fontInstance->getAscent();
runDescent = fRunInfo[i].fontInstance->getDescent();
runLeading = fRunInfo[i].fontInstance->getLeading();
if (runAscent > maxAscent) {
maxAscent = runAscent;
}
if (runDescent > maxDescent) {
maxDescent = runDescent;
}
if (runLeading > maxLeading) {
maxLeading = runLeading;
}
engines[i] = ICULayoutEngine::createInstance(fRunInfo[i].fontInstance, params[i].scriptCode, dummyLocale, success);
glyphCount = engines[i]->layoutChars(fText, charBase, charBase + charCount, fCharCount,
fRunInfo[i].rightToLeft, x, y, success);
engines[i]->getGlyphPosition(glyphCount, x, y, success);
fRunInfo[i].glyphBase = fGlyphCount;
fGlyphCount += glyphCount;
}
fLineHeight = maxAscent + maxDescent + maxLeading;
fAscent = maxAscent;
// Set glyphBase for the fake run at the end
fRunInfo[count].glyphBase = fGlyphCount;
fGlyphs = new LEGlyphID[fGlyphCount];
fCharIndices = new int32_t[fGlyphCount];
fGlyphIndices = new int32_t[fCharCount + 1];
fDX = new int32_t[fGlyphCount];
fDY = new int32_t[fGlyphCount];
float *positions = new float[fGlyphCount * 2 + 2];
// Build the glyph, charIndices and positions arrays
for (i = 0; i < count; i += 1) {
ICULayoutEngine *engine = engines[i];
int32_t charBase = fRunInfo[i].charBase;
int32_t glyphBase = fRunInfo[i].glyphBase;
UErrorCode success = U_ZERO_ERROR;
engine->getGlyphs(&fGlyphs[glyphBase], success);
engine->getCharIndices(&fCharIndices[glyphBase], charBase, success);
engine->getGlyphPositions(&positions[glyphBase * 2], success);
}
// Filter deleted glyphs, compute logical advances
// and set the char to glyph map
for (i = 0; i < fGlyphCount; i += 1) {
// Filter deleted glyphs
if (fGlyphs[i] == 0xFFFE || fGlyphs[i] == 0xFFFF) {
fGlyphs[i] = 0x0001;
}
// compute the logical advance
fDX[i] = (int32_t) (positions[i * 2 + 2] - positions[i * 2]);
// save the Y offset
fDY[i] = (int32_t) positions[i * 2 + 1];
// set char to glyph map
fGlyphIndices[fCharIndices[i]] = i;
}
if (fRunInfo[count - 1].rightToLeft) {
fGlyphIndices[fCharCount] = fRunInfo[count - 1].glyphBase - 1;
} else {
fGlyphIndices[fCharCount] = fGlyphCount;
}
delete[] positions;
// Get rid of the LayoutEngine's:
for (i = 0; i < count; i += 1) {
delete engines[i];
}
delete[] engines;
}
Paragraph::~Paragraph()
{
delete[] fDY;
delete[] fDX;
delete[] fGlyphIndices;
delete[] fCharIndices;
delete[] fGlyphs;
delete fBrkiter;
delete fText;
delete[] fBreakArray;
delete[] fRunInfo;
}
int32_t Paragraph::getLineHeight()
{
return fLineHeight;
}
int32_t Paragraph::getLineCount()
{
return fBreakCount;
}
int32_t Paragraph::getAscent()
{
return fAscent;
}
int32_t Paragraph::previousBreak(int32_t charIndex)
{
LEUnicode ch = fText[charIndex];
// skip over any whitespace or control
// characters, because they can hang in
// the margin.
while (charIndex < fCharCount &&
(Unicode::isWhitespace(ch) ||
Unicode::isControl(ch))) {
ch = fText[++charIndex];
}
// return the break location that's at or before
// the character we stopped on. Note: if we're
// on a break, the "+ 1" will cause preceding to
// back up to it.
return fBrkiter->preceding(charIndex + 1);
}
void Paragraph::breakLines(int32_t width, int32_t height)
{
int32_t lineWidth = width - (2 * MARGIN);
int32_t thisWidth = 0;
int32_t thisBreak = -1;
int32_t prevWidth = fWidth;
fWidth = width;
fHeight = height;
// don't re-break if the width hasn't changed
if (width == prevWidth) {
return;
}
fBreakArray[0] = 0;
fBreakCount = 1;
for (int32_t run = 0; run < fRunCount; run += 1) {
int32_t glyph = fRunInfo[run].glyphBase;
int32_t stop = fRunInfo[run + 1].glyphBase;
int32_t dir = 1;
if (fRunInfo[run].rightToLeft) {
glyph = stop - 1;
stop = fRunInfo[run].glyphBase - 1;
dir = -1;
}
while (glyph != stop) {
// Find the first glyph that doesn't fit on the line
while (thisWidth + fDX[glyph] <= lineWidth) {
thisWidth += fDX[glyph];
glyph += dir;
if (glyph == stop) {
break;
}
}
// Check to see if we fell off the
// end of the run
if (glyph == stop) {
break;
}
// Find a place before here to break,
thisBreak = previousBreak(fCharIndices[glyph]);
// If there wasn't one, force one
if (thisBreak <= fBreakArray[fBreakCount - 1]) {
thisBreak = fCharIndices[glyph];
}
// Save the break location.
fBreakArray[fBreakCount++] = thisBreak;
// Reset the accumulated width
thisWidth = 0;
// Map the character back to a glyph
glyph = fGlyphIndices[thisBreak];
// Check to see if the new glyph is off
// the end of the run.
if (glyph == stop) {
break;
}
// If the glyph's not in the run we stopped in, we
// have to re-synch to the new run
if (glyph < fRunInfo[run].glyphBase || glyph >= fRunInfo[run + 1].glyphBase) {
run = getGlyphRun(glyph, 0, 1);
if (fRunInfo[run].rightToLeft) {
stop = fRunInfo[run].glyphBase - 1;
dir = -1;
} else {
stop = fRunInfo[run + 1].glyphBase;
dir = 1;
}
}
}
}
// Make sure the last break is after the last character
if (fBreakArray[--fBreakCount] != fCharCount) {
fBreakArray[++fBreakCount] = fCharCount;
}
return;
}
int32_t Paragraph::getGlyphRun(int32_t glyph, int32_t startingRun, int32_t direction)
{
int32_t limit;
if (direction < 0) {
limit = -1;
} else {
limit = fRunCount;
}
for (int32_t run = startingRun; run != limit; run += direction) {
if (glyph >= fRunInfo[run].glyphBase && glyph < fRunInfo[run + 1].glyphBase) {
return run;
}
}
return limit;
}
int32_t Paragraph::getCharRun(int32_t ch, int32_t startingRun, int32_t direction)
{
int32_t limit;
if (direction < 0) {
limit = -1;
} else {
limit = fRunCount;
}
for (int32_t run = startingRun; run != limit; run += direction) {
if (ch >= fRunInfo[run].charBase && ch < fRunInfo[run + 1].charBase) {
return run;
}
}
return limit;
}
int32_t Paragraph::getRunWidth(int32_t startGlyph, int32_t endGlyph)
{
int32_t width = 0;
for (int32_t glyph = startGlyph; glyph <= endGlyph; glyph += 1) {
width += fDX[glyph];
}
return width;
}
int32_t Paragraph::drawRun(void *surface, const RenderingFontInstance *fontInstance, int32_t firstChar, int32_t lastChar,
int32_t x, int32_t y)
{
int32_t firstGlyph = fGlyphIndices[firstChar];
int32_t lastGlyph = fGlyphIndices[lastChar];
for (int32_t ch = firstChar; ch <= lastChar; ch += 1) {
int32_t glyph = fGlyphIndices[ch];
if (glyph < firstGlyph) {
firstGlyph = glyph;
}
if (glyph > lastGlyph) {
lastGlyph = glyph;
}
}
int32_t dyStart = firstGlyph, dyEnd = dyStart;
fontInstance->setFont(surface);
while (dyEnd <= lastGlyph) {
while (dyEnd <= lastGlyph && fDY[dyStart] == fDY[dyEnd]) {
dyEnd += 1;
}
fontInstance->drawGlyphs(surface, &fGlyphs[dyStart], dyEnd - dyStart,
&fDX[dyStart], x, y + fDY[dyStart], fWidth, fHeight);
dyStart = dyEnd;
}
return getRunWidth(firstGlyph, lastGlyph);
}
void Paragraph::draw(void *surface, int32_t firstLine, int32_t lastLine)
{
int32_t line, x, y;
int32_t prevRun = 0;
y = fAscent;
for (line = firstLine; line <= lastLine; line += 1) {
int32_t firstChar = fBreakArray[line];
int32_t lastChar = fBreakArray[line + 1] - 1;
int32_t firstRun = getCharRun(firstChar, prevRun, 1);
int32_t lastRun = getCharRun(lastChar, firstRun, 1);
x = MARGIN;
for (int32_t run = firstRun; run <= lastRun; run += 1) {
const RenderingFontInstance *fontInstance = fRunInfo[run].fontInstance;
int32_t nextBase;
if (run == lastRun) {
nextBase = lastChar + 1;
} else {
nextBase = fRunInfo[run + 1].charBase;
}
x += drawRun(surface, fontInstance, firstChar, nextBase - 1, x, y);
firstChar = nextBase;
}
y += fLineHeight;
prevRun = lastRun;
}
}
Paragraph *Paragraph::paragraphFactory(const char *fileName, FontMap *fontMap, GUISupport *guiSupport, void *surface)
{
RunParams params[64];
int32_t paramCount = 0;
int32_t charCount = 0;
RFIErrorCode fontStatus = RFI_NO_ERROR;
const UChar *text = UnicodeReader::readFile(fileName, guiSupport, charCount);
ScriptRun scriptRun(text, charCount);
if (text == NULL) {
return NULL;
}
while (scriptRun.next()) {
int32_t start = scriptRun.getScriptStart();
int32_t end = scriptRun.getScriptEnd();
UScriptCode code = scriptRun.getScriptCode();
params[paramCount].text = &((UChar *) text)[start];
params[paramCount].count = end - start;
params[paramCount].scriptCode = (UScriptCode) code;
params[paramCount].rightToLeft = false;
params[paramCount].fontInstance = fontMap->getScriptFont(code, fontStatus);
if (params[paramCount].fontInstance == NULL) {
return 0;
}
if (code == USCRIPT_ARABIC) {
params[paramCount].rightToLeft = true;
}
paramCount += 1;
}
return new Paragraph(surface, params, paramCount);
}

View file

@ -0,0 +1,96 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: Paragraph.h
*
* created on: 09/06/2000
* created by: Eric R. Mader
*/
#ifndef __PARAGRAPH_H
#define __PARAGRAPH_H
#include "unicode/utypes.h"
#include "unicode/uscript.h"
#include "unicode/brkiter.h"
#include "GUISupport.h"
#include "RenderingFontInstance.h"
#include "FontMap.h"
U_NAMESPACE_USE
#define MARGIN 10
struct RunParams
{
const RenderingFontInstance *fontInstance;
UChar *text;
int32_t count;
UScriptCode scriptCode;
UBool rightToLeft;
};
struct RunInfo
{
const RenderingFontInstance *fontInstance;
int32_t charBase;
int32_t glyphBase;
UBool rightToLeft;
};
class Paragraph
{
public:
Paragraph(void *surface,RunParams runs[], int32_t count);
~Paragraph();
int32_t getAscent();
int32_t getLineHeight();
int32_t getLineCount();
void breakLines(int32_t width, int32_t height);
void draw(void *surface, int32_t firstLine, int32_t lastLine);
static Paragraph *paragraphFactory(const char *fileName, FontMap *fontMap, GUISupport *guiSupport, void *surface);
protected:
int32_t previousBreak(int32_t charIndex);
int32_t getCharRun(int32_t ch, int32_t startingRun, int32_t direction);
int32_t getGlyphRun(int32_t glyph, int32_t startingRun, int32_t direction);
int32_t getRunWidth(int32_t startGlyph, int32_t endGlyph);
int32_t drawRun(void *surface, const RenderingFontInstance *fontInstance, int32_t firstChar, int32_t lastChar,
int32_t x, int32_t y);
private:
int32_t fRunCount;
RunInfo *fRunInfo;
int32_t fCharCount;
UChar *fText;
BreakIterator *fBrkiter;
int32_t fGlyphCount;
LEGlyphID *fGlyphs;
int32_t *fCharIndices;
int32_t *fGlyphIndices;
int32_t *fDX;
int32_t *fDY;
int32_t fBreakCount;
int32_t *fBreakArray;
int32_t fLineHeight;
int32_t fAscent;
int32_t fWidth;
int32_t fHeight;
};
#endif

View file

@ -0,0 +1,123 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Eric Mader">
<meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
<title>Readme file for letest and gendata</title>
</head>
<body>
<h2>
What is the layout demo?</h2>
The layout demo displays a paragraph of text that is laid out using the
LayoutEngine. There are two versions of this demo, "layout.exe" which runs
on Windows 2000, and "gnomelayout" which runs on Linux. Both programs read
a file containing the Unicode text to display, and a file that says which
font to use to display each script.
<br>&nbsp;
<h2>
How do I build the layout demo?</h2>
First, you need to build ICU, including the LayoutEngine.
<p>On Windows, the layout project should be listed as a dependency of all,
so layout will build when you build all. If it doesn't for some reason,
just select the layout project in the project toolbar and build it.
<p>On Linux systems, you need to add the "--enable-layout=yes" option when
you invoke the runConfigureICU script. When you've done that, layout should
build when you do "make all install"
<p>To build the demo on Windows, just open the layout project in &lt;icu>\source\samples\layout
and build it. On Linux systems, connect to &lt;top-build-dir>/samples/layout
and do "make all"
<br>&nbsp;
<h2>
How do I run the demo?</h2>
Before you can run the demo, you'll need to get the fonts it uses. For
legal reasons, we can't include these fonts with ICU, but you can get them
for free from the web. To do this, you'll need access to a computer running
Windows. Here's how to get the fonts:
<p>Download the 1.3 version of the JDK from the <a href="http://www7b.boulder.ibm.com/wsdd/wspvtindex.html">IBM
WebSphere preview technologies</a> page. From this page, follow the "Download"
link on the right had side. You'll need to register with them if you haven't
downloaded before. Download and install the "Runtime Environment Package."
You'll need three fonts from this package. If you've let the installer
use it's defaults, the fonts will be in C:\Program Files\IBM\Java13\jre\lib\fonts.
The files you want are "Devamt.ttf" "LucidaSansRegular.ttf" and "Thonburi.ttf"
On Windows, copy these font files to your Fonts folder, on LInux, copy
these font files to the directory from which you'll run the layout demo.
<p>There's still one more font to get. Go to the Microsoft <a href="http://www.microsoft.com/typography/fontpack/default.htm">TrueType
core fonts for the Web</a> page and download the "Times New Roman" font.
This will download an installer program, called "Times32.exe" which will
install the Times New Roman fonts in your fonts folder. (If you've already
got these fonts in you fonts folder, you may want to move them to another
folder before you install these fonts.)
<p>NOTE: this installer will display an End User License Agreement (EULA)
which you must accept before proceeding. Be sure that you read and understand
this agreement before you install the font.
<p>After you run the installer program, it will add the Times Roman fonts
to your fonts folder. If you're going to run the demo on Linux, open the
Fonts folder and copy the "Times New Roman" font (the file name will be
"Times.TTF") to the directory from which you'll run the demo.
<p>That's it! Now all you have to do is run letest (CTRL+F5 in Visual C++,
or "./gnomelayout" in Linux)
<h2>
How can I customize the layout demo?</h2>
The text that the layout demo displays is read from the file "Sample.utf8."
You can change the text by editing this file using a Unicode-aware text
editor. (it is in UTF8 format with a BOM as the first character; the demo
can also read UTF16 and UTF32 format files) Remember that the text will
be displayed in a single paragraph; you can include CR and LF characters
in the text, but they will be ignored.
<p>If you add scripts to the text other than Arabic, Devanagari, Latin
or Thai, you'll need to find a font which contains the characters in that
script, and add an entry to the FontMap file ("FontMap.GDI" on Windows,
"FontMap.Gnome" on Linux) This file contains a single entry per line. Each
entry contains a script name followed by a colon, and then a font name.
<p>Here is the list of legal script names:
<blockquote><tt>ARABIC</tt>
<br><tt>ARMENIAN</tt>
<br><tt>BENGALI</tt>
<br><tt>BOPOMOFO</tt>
<br><tt>CANADIAN-ABORIGINAL</tt>
<br><tt>CHEROKEE</tt>
<br><tt>CYRILLIC</tt>
<br><tt>DESERET</tt>
<br><tt>DEVANAGARI</tt>
<br><tt>ETHIOPIC</tt>
<br><tt>GEORGIAN</tt>
<br><tt>GOTHIC</tt>
<br><tt>GREEK</tt>
<br><tt>GUJARATI</tt>
<br><tt>GURMUKHI</tt>
<br><tt>HAN</tt>
<br><tt>HANGUL</tt>
<br><tt>HEBREW</tt>
<br><tt>HIRAGANA</tt>
<br><tt>KANNADA</tt>
<br><tt>KATAKANA</tt>
<br><tt>KHMER</tt>
<br><tt>LATIN</tt>
<br><tt>MALAYALAM</tt>
<br><tt>MONGOLIAN</tt>
<br><tt>MYANMAR</tt>
<br><tt>OGHAM</tt>
<br><tt>OLD-ITALIC</tt>
<br><tt>ORIYA</tt>
<br><tt>RUNIC</tt>
<br><tt>SINHALA</tt>
<br><tt>SYRIAC</tt>
<br><tt>TAMIL</tt>
<br><tt>TELUGU</tt>
<br><tt>THAANA</tt>
<br><tt>THAI</tt>
<br><tt>TIBETAN</tt>
<br><tt>UCAS</tt>
<br><tt>YI</tt></blockquote>
On Windows use the full name of the font as it appears in the Windows Fonts
folder (eg. "Times New Roman") On Linux, use the file name of the font
file (e.g. "Times.TTF") If you're running on Windows, you'll need to install
the new fonts in your Fonts folder. If you're running on Linux, put them
in the directory from which you'll run the demo.
<br>&nbsp;
<br>&nbsp;
</body>
</html>

View file

@ -0,0 +1,67 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: scrptrun.cpp
*
* created on: 10/17/2001
* created by: Eric R. Mader
*/
#include "unicode/utypes.h"
#include "unicode/uscript.h"
#include "scrptrun.h"
UBool ScriptRun::sameScript(int32_t scriptOne, int32_t scriptTwo)
{
return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo;
}
UBool ScriptRun::next()
{
UErrorCode error = U_ZERO_ERROR;
if (scriptEnd >= charLimit) {
return false;
}
scriptCode = USCRIPT_COMMON;
for (scriptStart = scriptEnd; scriptEnd < charLimit; scriptEnd += 1) {
UChar high = charArray[scriptEnd];
UChar32 ch = high;
if (scriptEnd < charLimit - 1 && high >= 0xD800 && high <= 0xDBFF)
{
UChar low = charArray[scriptEnd + 1];
if (low >= 0xDC00 && low <= 0xDFFF) {
ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000;
scriptEnd += 1;
}
}
UScriptCode sc = uscript_getScript(ch, &error);
if (sameScript(scriptCode, sc)) {
if (scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
scriptCode = sc;
}
} else {
// if the run broke on a surrogate pair,
// end it before the high surrogate
if (ch >= 0x10000) {
scriptEnd -= 1;
}
break;
}
}
return true;
}

View file

@ -0,0 +1,116 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: scrptrun.h
*
* created on: 10/17/2001
* created by: Eric R. Mader
*/
#ifndef __SCRPTRUN_H
#define __SCRPTRUN_H
#include "unicode/utypes.h"
#include "unicode/uscript.h"
struct ScriptRecord
{
UChar32 startChar;
UChar32 endChar;
UScriptCode scriptCode;
};
class ScriptRun
{
public:
ScriptRun();
ScriptRun(const UChar chars[], int32_t length);
ScriptRun(const UChar chars[], int32_t start, int32_t length);
void reset();
void reset(int32_t start, int32_t count);
void reset(const UChar chars[], int32_t start, int32_t length);
int32_t getScriptStart();
int32_t getScriptEnd();
UScriptCode getScriptCode();
UBool next();
private:
static UBool sameScript(int32_t scriptOne, int32_t scriptTwo);
int32_t charStart;
int32_t charLimit;
const UChar *charArray;
int32_t scriptStart;
int32_t scriptEnd;
UScriptCode scriptCode;
};
inline ScriptRun::ScriptRun()
{
reset(NULL, 0, 0);
}
inline ScriptRun::ScriptRun(const UChar chars[], int32_t length)
{
reset(chars, 0, length);
}
inline ScriptRun::ScriptRun(const UChar chars[], int32_t start, int32_t length)
{
reset(chars, start, length);
}
inline int32_t ScriptRun::getScriptStart()
{
return scriptStart;
}
inline int32_t ScriptRun::getScriptEnd()
{
return scriptEnd;
}
inline UScriptCode ScriptRun::getScriptCode()
{
return scriptCode;
}
inline void ScriptRun::reset()
{
scriptStart = charStart;
scriptEnd = charStart;
scriptCode = USCRIPT_INVALID_CODE;
}
inline void ScriptRun::reset(int32_t start, int32_t length)
{
charStart = start;
charLimit = start + length;
reset();
}
inline void ScriptRun::reset(const UChar chars[], int32_t start, int32_t length)
{
charArray = chars;
reset(start, length);
}
#endif

View file

@ -0,0 +1,219 @@
/*
****************************************************************************** *
*
* Copyright (C) 1999-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
****************************************************************************** *
* file name: sfnt.h
*
* created on: ??/??/2001
* created by: Eric R. Mader
*/
#ifndef __SFNT_H
#define __SFNT_H
#include "LETypes.h"
#ifndef ANY_NUMBER
#define ANY_NUMBER 1
#endif
struct DirectoryEntry
{
le_uint32 tag;
le_uint32 checksum;
le_uint32 offset;
le_uint32 length;
};
struct SFNTDirectory
{
le_uint32 scalerType;
le_uint16 numTables;
le_uint16 searchRange;
le_uint16 entrySelector;
le_uint16 rangeShift;
DirectoryEntry tableDirectory[ANY_NUMBER];
};
struct CMAPEncodingSubtableHeader
{
le_uint16 platformID;
le_uint16 platformSpecificID;
le_uint32 encodingOffset;
};
struct CMAPTable
{
le_uint16 version;
le_uint16 numberSubtables;
CMAPEncodingSubtableHeader encodingSubtableHeaders[ANY_NUMBER];
};
struct CMAPEncodingSubtable
{
le_uint16 format;
le_uint16 length;
le_uint16 language;
};
struct CMAPFormat0Encoding : CMAPEncodingSubtable
{
le_uint8 glyphIndexArray[256];
};
struct CMAPFormat2Subheader
{
le_uint16 firstCode;
le_uint16 entryCount;
le_int16 idDelta;
le_uint16 idRangeOffset;
};
struct CMAPFormat2Encoding : CMAPEncodingSubtable
{
le_uint16 subHeadKeys[256];
CMAPFormat2Subheader subheaders[ANY_NUMBER];
};
struct CMAPFormat4Encoding : CMAPEncodingSubtable
{
le_uint16 segCountX2;
le_uint16 searchRange;
le_uint16 entrySelector;
le_uint16 rangeShift;
le_uint16 endCodes[ANY_NUMBER];
// le_uint16 reservedPad;
// le_uint16 startCodes[ANY_NUMBER];
// le_uint16 idDelta[ANY_NUMBER];
// le_uint16 idRangeOffset[ANY_NUMBER];
// le_uint16 glyphIndexArray[ANY_NUMBER];
};
struct CMAPFormat6Encoding : CMAPEncodingSubtable
{
le_uint16 firstCode;
le_uint16 entryCount;
le_uint16 glyphIndexArray[ANY_NUMBER];
};
struct CMAPEncodingSubtable32
{
le_uint32 format;
le_uint32 length;
le_uint32 language;
};
struct CMAPGroup
{
le_uint32 startCharCode;
le_uint32 endCharCode;
le_uint32 startGlyphCode;
};
struct CMAPFormat8Encoding : CMAPEncodingSubtable32
{
le_uint32 is32[65536/32];
le_uint32 nGroups;
CMAPGroup groups[ANY_NUMBER];
};
struct CMAPFormat10Encoding : CMAPEncodingSubtable32
{
le_uint32 startCharCode;
le_uint32 numCharCodes;
le_uint16 glyphs[ANY_NUMBER];
};
struct CMAPFormat12Encoding : CMAPEncodingSubtable32
{
le_uint32 nGroups;
CMAPGroup groups[ANY_NUMBER];
};
typedef le_int32 fixed;
struct BigDate
{
le_uint32 bc;
le_uint32 ad;
};
struct HEADTable
{
fixed version;
fixed fontRevision;
le_uint32 checksumAdjustment;
le_uint32 magicNumber;
le_uint16 flags;
le_uint16 unitsPerEm;
BigDate created;
BigDate modified;
le_int16 xMin;
le_int16 yMin;
le_int16 xMax;
le_int16 yMax;
le_int16 lowestRecPPEM;
le_int16 fontDirectionHint;
le_int16 indexToLocFormat;
le_int16 glyphDataFormat;
};
struct MAXPTable
{
fixed version;
le_uint16 numGlyphs;
le_uint16 maxPoints;
le_uint16 maxContours;
le_uint16 maxComponentPoints;
le_uint16 maxComponentContours;
le_uint16 maxZones;
le_uint16 maxTwilightPoints;
le_uint16 maxStorage;
le_uint16 maxFunctionDefs;
le_uint16 maxInstructionDefs;
le_uint16 maxStackElements;
le_uint16 maxSizeOfInstructions;
le_uint16 maxComponentElements;
le_uint16 maxComponentDepth;
};
struct HHEATable
{
fixed version;
le_int16 ascent;
le_int16 descent;
le_int16 lineGap;
le_uint16 advanceWidthMax;
le_int16 minLeftSideBearing;
le_int16 minRightSideBearing;
le_int16 xMaxExtent;
le_int16 caretSlopeRise;
le_int16 caretSlopeRun;
le_int16 caretOffset;
le_int16 reserved1;
le_int16 reserved2;
le_int16 reserved3;
le_int16 reserved4;
le_int16 metricDataFormat;
le_uint16 numOfLongHorMetrics;
};
struct LongHorMetric
{
le_uint16 advanceWidth;
le_int16 leftSideBearing;
};
struct HMTXTable
{
LongHorMetric hMetrics[ANY_NUMBER]; // ANY_NUMBER = numOfLongHorMetrics from hhea table
// le_int16 leftSideBearing[ANY_NUMBER]; // ANY_NUMBER = numGlyphs - numOfLongHorMetrics
};
#endif