ICU-3979 Add automatic LayoutEngine tests.

X-SVN-Rev: 19523
This commit is contained in:
Eric Mader 2006-04-07 23:51:55 +00:00
parent cbac1432df
commit e4ae327eed
16 changed files with 1934 additions and 417 deletions

View file

@ -218,6 +218,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genctd", "..\tools\genctd\g
{73C0A65B-D1F2-4DE1-B3A6-15DAD2C23F3D} = {73C0A65B-D1F2-4DE1-B3A6-15DAD2C23F3D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "letest", "..\test\letest\letest.vcproj", "{67351485-4D18-4245-BE39-A7EF0675ACD2}"
ProjectSection(ProjectDependencies) = postProject
{0178B127-6269-407D-B112-93877BB62776} = {0178B127-6269-407D-B112-93877BB62776}
{C920062A-0647-4553-A3B2-37C58065664B} = {C920062A-0647-4553-A3B2-37C58065664B}
{6B231032-3CB5-4EED-9210-810D666A23A0} = {6B231032-3CB5-4EED-9210-810D666A23A0}
{ECA6B435-B4FA-4F9F-BF95-F451D078FC47} = {ECA6B435-B4FA-4F9F-BF95-F451D078FC47}
{73C0A65B-D1F2-4DE1-B3A6-15DAD2C23F3D} = {73C0A65B-D1F2-4DE1-B3A6-15DAD2C23F3D}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@ -352,6 +361,10 @@ Global
{9D4211F7-2C77-439C-82F0-30A4E43BA569}.Debug.Build.0 = Debug|Win32
{9D4211F7-2C77-439C-82F0-30A4E43BA569}.Release.ActiveCfg = Release|Win32
{9D4211F7-2C77-439C-82F0-30A4E43BA569}.Release.Build.0 = Release|Win32
{67351485-4D18-4245-BE39-A7EF0675ACD2}.Debug.ActiveCfg = Debug|Win32
{67351485-4D18-4245-BE39-A7EF0675ACD2}.Debug.Build.0 = Debug|Win32
{67351485-4D18-4245-BE39-A7EF0675ACD2}.Release.ActiveCfg = Release|Win32
{67351485-4D18-4245-BE39-A7EF0675ACD2}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection

View file

@ -1,6 +1,6 @@
/*
*
* (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
* (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
*
*/
@ -13,7 +13,7 @@ U_NAMESPACE_BEGIN
class LEGlyphStorage;
class CanonShaping /* not : public UObject because all members are static */
class U_LAYOUT_API CanonShaping /* not : public UObject because all members are static */
{
public:
static const le_uint8 glyphSubstitutionTable[];

View file

@ -1,7 +1,7 @@
/*
*
* (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
* (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
*
*/
@ -12,6 +12,7 @@
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "CharSubstitutionFilter.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
@ -76,7 +77,7 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l
const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag);
// todo: switch to more flags and bitfield rather than list of feature tags?
switch (typoFlags) {
switch (typoFlags & ~0x80000000L) {
case 0: break; // default
case 1: fFeatureMask = kernFeatures; break;
case 2: fFeatureMask = ligaFeatures; break;
@ -84,6 +85,10 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l
default: break;
}
if (typoFlags & 0x80000000L) {
fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
}
setScriptAndLanguageTags();
fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
@ -112,6 +117,10 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, l
OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
{
if (fTypoFlags & 0x80000000L) {
delete fSubstitutionFilter;
}
reset();
}

View file

@ -1,12 +1,13 @@
/*
**********************************************************************
* Copyright (C) 2003-2005, International Business Machines
* Copyright (C) 2003-2006, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
#include "layout/LETypes.h"
#include "letest.h"
#include "FontTableCache.h"
#define TABLE_CACHE_INIT 5
@ -21,7 +22,7 @@ struct FontTableCacheEntry
FontTableCache::FontTableCache()
: fTableCacheCurr(0), fTableCacheSize(TABLE_CACHE_INIT)
{
fTableCache = LE_NEW_ARRAY(FontTableCacheEntry, fTableCacheSize);
fTableCache = NEW_ARRAY(FontTableCacheEntry, fTableCacheSize);
if (fTableCache == NULL) {
fTableCacheSize = 0;
@ -37,7 +38,7 @@ FontTableCache::FontTableCache()
FontTableCache::~FontTableCache()
{
for (int i = fTableCacheCurr - 1; i >= 0; i -= 1) {
LE_DELETE_ARRAY(fTableCache[i].table);
DELETE_ARRAY(fTableCache[i].table);
fTableCache[i].tag = 0;
fTableCache[i].table = NULL;
@ -45,7 +46,7 @@ FontTableCache::~FontTableCache()
fTableCacheCurr = 0;
LE_DELETE_ARRAY(fTableCache);
DELETE_ARRAY(fTableCache);
}
const void *FontTableCache::find(LETag tableTag) const
@ -68,7 +69,7 @@ void FontTableCache::add(LETag tableTag, const void *table)
if (fTableCacheCurr >= fTableCacheSize) {
le_int32 newSize = fTableCacheSize + TABLE_CACHE_GROW;
fTableCache = (FontTableCacheEntry *) LE_GROW_ARRAY(fTableCache, newSize);
fTableCache = (FontTableCacheEntry *) GROW_ARRAY(fTableCache, newSize);
for (le_int32 i = fTableCacheSize; i < newSize; i += 1) {
fTableCache[i].tag = 0;

View file

@ -1,5 +1,5 @@
## Makefile.in for ICU - test/letest
## Copyright (c) 2001-2003, International Business Machines Corporation and
## Copyright (c) 2001-2006, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information
@ -23,11 +23,12 @@ CLEANFILES = *~ $(DEPS)
TESTTARGET = letest
GENTARGET = gendata
CPPFLAGS += -DLE_USE_CMEMORY -I$(top_builddir)/common -I$(top_srcdir)/common -I$(top_srcdir)/layout -I$(top_srcdir)
LIBS = $(LIBICULE) $(LIBICUUC) @LIBS@ @LIB_M@
CPPFLAGS += -I$(top_builddir)/common -I$(top_srcdir)/common -I$(top_srcdir)/i18n -I$(top_srcdir)/tools/ctestfw -I$(top_srcdir)/tools/toolutil -I$(top_srcdir)/layout -I$(top_srcdir)
DEFS += -D'U_TOPSRCDIR="$(top_srcdir)/"' -D'U_TOPBUILDDIR="$(BUILDDIR)"'
LIBS = $(LIBICULE) $(LIBICUUC) $(LIBICUI18N) $(LIBCTESTFW) $(LIBICUTOOLUTIL) @LIBS@ @LIB_M@
COMMONOBJECTS = cmaps.o FontTableCache.o PortableFontInstance.o
TESTOBJECTS = testdata.o letest.o
COMMONOBJECTS = cmaps.o FontTableCache.o SimpleFontInstance.o PortableFontInstance.o
TESTOBJECTS = letest.o
GENOBJECTS = gendata.o
OBJECTS = $(COMMONOBJECTS) $(TESTOBJECTS) $(GENOBJECTS)

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2005, International Business Machines
* Copyright (C) 1999-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -19,6 +19,7 @@
#include "PortableFontInstance.h"
#include "letest.h"
#include "sfnt.h"
#include <string.h>
@ -92,7 +93,7 @@ PortableFontInstance::PortableFontInstance(const char *fileName, float pointSize
// const NAMETable *nameTable = NULL;
le_uint16 numTables = 0;
fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize);
fDirectory = (const SFNTDirectory *) NEW_ARRAY(char, dirSize);
if (fDirectory == NULL) {
status = LE_MEMORY_ALLOCATION_ERROR;
@ -178,13 +179,13 @@ PortableFontInstance::~PortableFontInstance()
delete fCMAPMapper;
LE_DELETE_ARRAY(fDirectory);
DELETE_ARRAY(fDirectory);
}
}
void PortableFontInstance::deleteTable(const void *table) const
{
LE_DELETE_ARRAY(table);
DELETE_ARRAY(table);
}
const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const
@ -224,7 +225,7 @@ const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const
*length = SWAPL(entry->length);
void *table = LE_NEW_ARRAY(char, *length);
void *table = NEW_ARRAY(char, *length);
if (table != NULL) {
fseek(fFile, SWAPL(entry->offset), SEEK_SET);
@ -279,9 +280,9 @@ const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 plat
SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) {
char *name = ((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset);
le_uint16 length = SWAPW(nameRecord->length);
char *result = LE_NEW_ARRAY(char, length + 2);
char *result = NEW_ARRAY(char, length + 2);
LE_ARRAY_COPY(result, name, length);
ARRAY_COPY(result, name, length);
result[length] = result[length + 1] = 0;
return result;
@ -293,7 +294,7 @@ const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 plat
void PortableFontInstance::deleteNameString(const char *name) const
{
LE_DELETE_ARRAY(name);
DELETE_ARRAY(name);
}
void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const

View file

@ -0,0 +1,69 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: SimpleFontInstance.cpp
*
* created on: 03/30/2006
* created by: Eric R. Mader
*/
#include "unicode/utypes.h"
#include "unicode/uchar.h"
#include "layout/LETypes.h"
#include "layout/LEFontInstance.h"
#include "CanonShaping.h"
#include "SimpleFontInstance.h"
SimpleFontInstance::SimpleFontInstance(float pointSize, LEErrorCode &status)
: fPointSize(pointSize), fAscent(0), fDescent(0)
{
if (LE_FAILURE(status)) {
return;
}
fAscent = (le_int32) yUnitsToPoints(2000.0);
fDescent = (le_int32) yUnitsToPoints(600.0);
return;
}
SimpleFontInstance::~SimpleFontInstance()
{
// nothing to do...
}
const void *SimpleFontInstance::getFontTable(LETag tableTag) const
{
if (tableTag == LE_GSUB_TABLE_TAG) {
return CanonShaping::glyphSubstitutionTable;
}
if (tableTag == LE_GDEF_TABLE_TAG) {
return CanonShaping::glyphDefinitionTable;
}
return NULL;
}
void SimpleFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
{
if (u_getCombiningClass((UChar32) glyph) == 0) {
advance.fX = xUnitsToPoints(2048);
} else {
advance.fX = 0;
}
advance.fY = 0;
}
le_bool SimpleFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const
{
return FALSE;
}

View file

@ -0,0 +1,91 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: SimpleFontInstance.h
*
* created on: 03/30/2006
* created by: Eric R. Mader
*/
#ifndef __SIMPLEFONTINSTANCE_H
#define __SIMPLEFONTINSTANCE_H
#include <stdio.h>
#include "layout/LETypes.h"
#include "layout/LEFontInstance.h"
class SimpleFontInstance : public LEFontInstance
{
private:
float fPointSize;
le_int32 fAscent;
le_int32 fDescent;
protected:
const void *readFontTable(LETag tableTag) const;
public:
SimpleFontInstance(float pointSize, LEErrorCode &status);
virtual ~SimpleFontInstance();
virtual const void *getFontTable(LETag tableTag) const;
virtual le_int32 getUnitsPerEM() const
{
return 2048;
};
virtual le_int32 getAscent() const
{
return fAscent;
}
virtual le_int32 getDescent() const
{
return fDescent;
}
virtual le_int32 getLeading() const
{
return 0;
}
virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch) const
{
return (LEGlyphID) ch;
}
virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const;
virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const;
float getXPixelsPerEm() const
{
return fPointSize;
};
float getYPixelsPerEm() const
{
return fPointSize;
};
float getScaleFactorX() const
{
return 1.0;
}
float getScaleFactorY() const
{
return 1.0;
}
};
#endif

View file

@ -1,6 +1,6 @@
/***************************************************************************
*
* Copyright (C) 1998-2003, International Business Machines
* Copyright (C) 1998-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
************************************************************************/
@ -9,7 +9,8 @@
#ifndef __CMAPS_H
#define __CMAPS_H
#include "LETypes.h"
#include "layout/LETypes.h"
#include "letest.h"
#include "sfnt.h"
class CMAPMapper
@ -77,7 +78,7 @@ inline CMAPMapper::CMAPMapper(const CMAPTable *cmap)
inline CMAPMapper::~CMAPMapper()
{
LE_DELETE_ARRAY(fcmap);
DELETE_ARRAY(fcmap);
}
#endif

View file

@ -12,17 +12,22 @@
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "LETypes.h"
#include "LEScripts.h"
#include "LayoutEngine.h"
#include "sfnt.h"
#include "PortableFontInstance.h"
#include "unicode/utypes.h"
#include "unicode/unistr.h"
#include "unicode/uscript.h"
#include "unicode/ubidi.h"
#include "layout/LETypes.h"
#include "layout/LEScripts.h"
#include "layout/LayoutEngine.h"
#include "PortableFontInstance.h"
#include "SimpleFontInstance.h"
#include "xmlparser.h"
U_NAMESPACE_USE
@ -41,212 +46,31 @@ struct TestInput
* FIXME: should use the output file name and the current date.
*/
const char *header =
"/*\n"
" *******************************************************************************\n"
" *\n"
" * Copyright (C) 1999-%4.4d, International Business Machines\n"
" * Corporation and others. All Rights Reserved.\n"
" *\n"
" * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT\n"
" * UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.\n"
" *\n"
" *******************************************************************************\n"
" *\n"
" * file name: testdata.cpp\n"
" * generated on: %s\n"
" * generated by: gendata.cpp\n"
" */\n"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"\n"
"#include \"LETypes.h\"\n"
"#include \"LEScripts.h\"\n"
"#include \"letest.h\"\n"
"\n";
"<!--\n"
" Copyright (c) 1999-%4.4d International Business Machines\n"
" Corporation and others. All rights reserved.\n"
"\n"
" WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT\n"
" UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.\n"
"\n"
" file name: letest.xml\n"
" generated on: %s\n"
" generated by: gendata.cpp\n"
"-->\n"
"\n"
"<layout-tests>\n";
LEUnicode devaText[] =
{
0x0936, 0x094d, 0x0930, 0x0940, 0x092e, 0x0926, 0x094d, 0x0020,
0x092d, 0x0917, 0x0935, 0x0926, 0x094d, 0x0917, 0x0940, 0x0924,
0x093e, 0x0020, 0x0905, 0x0927, 0x094d, 0x092f, 0x093e, 0x092f,
0x0020, 0x0905, 0x0930, 0x094d, 0x091c, 0x0941, 0x0928, 0x0020,
0x0935, 0x093f, 0x0937, 0x093e, 0x0926, 0x0020, 0x092f, 0x094b,
0x0917, 0x0020, 0x0927, 0x0943, 0x0924, 0x0930, 0x093e, 0x0937,
0x094d, 0x091f, 0x094d, 0x0930, 0x0020, 0x0909, 0x0935, 0x093E,
0x091A, 0x0943, 0x0020, 0x0927, 0x0930, 0x094d, 0x092e, 0x0915,
0x094d, 0x0937, 0x0947, 0x0924, 0x094d, 0x0930, 0x0947, 0x0020,
0x0915, 0x0941, 0x0930, 0x0941, 0x0915, 0x094d, 0x0937, 0x0947,
0x0924, 0x094d, 0x0930, 0x0947, 0x0020, 0x0938, 0x092e, 0x0935,
0x0947, 0x0924, 0x093e, 0x0020, 0x092f, 0x0941, 0x092f, 0x0941,
0x0924, 0x094d, 0x0938, 0x0935, 0x0903, 0x0020, 0x092e, 0x093e,
0x092e, 0x0915, 0x093e, 0x0903, 0x0020, 0x092a, 0x093e, 0x0923,
0x094d, 0x0921, 0x0935, 0x093e, 0x0936, 0x094d, 0x091a, 0x0948,
0x0935, 0x0020, 0x0915, 0x093f, 0x092e, 0x0915, 0x0941, 0x0930,
0x094d, 0x0935, 0x0924, 0x0020, 0x0938, 0x0902, 0x091c, 0x0935
};
le_int32 devaTextLength = ARRAY_LENGTH(devaText);
LEUnicode arabText[] =
{
0x0623, 0x0633, 0x0627, 0x0633, 0x064B, 0x0627, 0x060C, 0x0020,
0x062A, 0x062A, 0x0639, 0x0627, 0x0645, 0x0644, 0x0020,
0x0627, 0x0644, 0x062D, 0x0648, 0x0627, 0x0633, 0x064A, 0x0628,
0x0020, 0x0641, 0x0642, 0x0637, 0x0020, 0x0645, 0x0639, 0x0020,
0x0627, 0x0644, 0x0623, 0x0631, 0x0642, 0x0627, 0x0645, 0x060C,
0x0020, 0x0648, 0x062A, 0x0642, 0x0648, 0x0645, 0x0020, 0x0628,
0x062A, 0x062E, 0x0632, 0x064A, 0x0646, 0x0020, 0x0627, 0x0644,
0x0623, 0x062D, 0x0631, 0x0641, 0x0020, 0x0648, 0x0627, 0x0644,
0x0645, 0x062D, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, 0x0644,
0x0623, 0x062E, 0x0631, 0x0649, 0x0020, 0x0628, 0x0639, 0x062F,
0x0020, 0x0623, 0x0646, 0x0020, 0x062A, 0x064F, 0x0639, 0x0637,
0x064A, 0x0020, 0x0631, 0x0642, 0x0645, 0x0627, 0x0020, 0x0645,
0x0639, 0x064A, 0x0646, 0x0627, 0x0020, 0x0644, 0x0643, 0x0644,
0x0020, 0x0648, 0x0627, 0x062D, 0x062F, 0x0020, 0x0645, 0x0646,
0x0647, 0x0627, 0x002E, 0x0020, 0x0648, 0x0642, 0x0628, 0x0644,
0x0020, 0x0627, 0x062E, 0x062A, 0x0631, 0x0627, 0x0639, 0x0020,
0x0022, 0x064A, 0x0648, 0x0646, 0x0650, 0x0643, 0x0648, 0x062F,
0x0022, 0x060C, 0x0020, 0x0643, 0x0627, 0x0646, 0x0020, 0x0647,
0x0646, 0x0627, 0x0643, 0x0020, 0x0645, 0x0626, 0x0627, 0x062A,
0x0020, 0x0627, 0x0644, 0x0623, 0x0646, 0x0638, 0x0645, 0x0629,
0x0020, 0x0644, 0x0644, 0x062A, 0x0634, 0x0641, 0x064A, 0x0631,
0x0020, 0x0648, 0x062A, 0x062E, 0x0635, 0x064A, 0x0635, 0x0020,
0x0647, 0x0630, 0x0647, 0x0020, 0x0627, 0x0644, 0x0623, 0x0631,
0x0642, 0x0627, 0x0645, 0x0020, 0x0644, 0x0644, 0x0645, 0x062D,
0x0627, 0x0631, 0x0641, 0x060C, 0x0020, 0x0648, 0x0644, 0x0645,
0x0020, 0x064A, 0x0648, 0x062C, 0x062F, 0x0020, 0x0646, 0x0638,
0x0627, 0x0645, 0x0020, 0x062A, 0x0634, 0x0641, 0x064A, 0x0631,
0x0020, 0x0648, 0x0627, 0x062D, 0x062F, 0x0020, 0x064A, 0x062D,
0x062A, 0x0648, 0x064A, 0x0020, 0x0639, 0x0644, 0x0649, 0x0020,
0x062C, 0x0645, 0x064A, 0x0639, 0x0020, 0x0627, 0x0644, 0x0645,
0x062D, 0x0627, 0x0631, 0x0641, 0x0020, 0x0627, 0x0644, 0x0636,
0x0631, 0x0648, 0x0631, 0x064A, 0x0629
/* The next few sentences...
0x002E, 0x0020, 0x0648,
0x0639, 0x0644, 0x0649, 0x0020, 0x0633, 0x0628, 0x064A, 0x0644,
0x0020, 0x0627, 0x0644, 0x0645, 0x062B, 0x0627, 0x0644, 0x060C,
0x0020, 0x0641, 0x0625, 0x0646, 0x0020, 0x0627, 0x0644, 0x0627,
0x062A, 0x062D, 0x0627, 0x062F, 0x0020, 0x0627, 0x0644, 0x0623,
0x0648, 0x0631, 0x0648, 0x0628, 0x064A, 0x0020, 0x0644, 0x0648,
0x062D, 0x062F, 0x0647, 0x060C, 0x0020, 0x0627, 0x062D, 0x062A,
0x0648, 0x0649, 0x0020, 0x0627, 0x0644, 0x0639, 0x062F, 0x064A,
0x062F, 0x0020, 0x0645, 0x0646, 0x0020, 0x0627, 0x0644, 0x0634,
0x0641, 0x0631, 0x0627, 0x062A, 0x0020, 0x0627, 0x0644, 0x0645,
0x062E, 0x062A, 0x0644, 0x0641, 0x0629, 0x0020, 0x0644, 0x064A,
0x063A, 0x0637, 0x064A, 0x0020, 0x062C, 0x0645, 0x064A, 0x0639,
0x0020, 0x0627, 0x0644, 0x0644, 0x063A, 0x0627, 0x062A, 0x0020,
0x0627, 0x0644, 0x0645, 0x0633, 0x062A, 0x062E, 0x062F, 0x0645,
0x0629, 0x0020, 0x0641, 0x064A, 0x0020, 0x0627, 0x0644, 0x0627,
0x062A, 0x062D, 0x0627, 0x062F, 0x002E, 0x0020, 0x0648, 0x062D,
0x062A, 0x0649, 0x0020, 0x0644, 0x0648, 0x0020, 0x0627, 0x0639,
0x062A, 0x0628, 0x0631, 0x0646, 0x0627, 0x0020, 0x0644, 0x063A,
0x0629, 0x0020, 0x0648, 0x0627, 0x062D, 0x062F, 0x0629, 0x060C,
0x0020, 0x0643, 0x0627, 0x0644, 0x0644, 0x063A, 0x0629, 0x0020,
0x0627, 0x0644, 0x0625, 0x0646, 0x062C, 0x0644, 0x064A, 0x0632,
0x064A, 0x0629, 0x060C, 0x0020, 0x0641, 0x0625, 0x0646, 0x0020,
0x062C, 0x062F, 0x0648, 0x0644, 0x0020, 0x0634, 0x0641, 0x0631,
0x0629, 0x0020, 0x0648, 0x0627, 0x062D, 0x062F, 0x0020, 0x0644,
0x0645, 0x0020, 0x064A, 0x0643, 0x0641, 0x0020, 0x0644, 0x0627,
0x0633, 0x062A, 0x064A, 0x0639, 0x0627, 0x0628, 0x0020, 0x062C,
0x0645, 0x064A, 0x0639, 0x0020, 0x0627, 0x0644, 0x0623, 0x062D,
0x0631, 0x0641, 0x0020, 0x0648, 0x0639, 0x0644, 0x0627, 0x0645,
0x0627, 0x062A, 0x0020, 0x0627, 0x0644, 0x062A, 0x0631, 0x0642,
0x064A, 0x0645, 0x0020, 0x0648, 0x0627, 0x0644, 0x0631, 0x0645,
0x0648, 0x0632, 0x0020, 0x0627, 0x0644, 0x0641, 0x0646, 0x064A,
0x0629, 0x0020, 0x0648, 0x0627, 0x0644, 0x0639, 0x0644, 0x0645,
0x064A, 0x0629, 0x0020, 0x0627, 0x0644, 0x0634, 0x0627, 0x0626,
0x0639, 0x0629, 0x0020, 0x0627, 0x0644, 0x0627, 0x0633, 0x062A,
0x0639, 0x0645, 0x0627, 0x0644, 0x002E */
};
le_int32 arabTextLength = ARRAY_LENGTH(arabText);
LEUnicode thaiSample[] =
{
0x0E1A, 0x0E17, 0x0E17, 0x0E35, 0x0E48, 0x0E51, 0x0E1E, 0x0E32,
0x0E22, 0x0E38, 0x0E44, 0x0E0B, 0x0E42, 0x0E04, 0x0E25, 0x0E19,
0x0E42, 0x0E14, 0x0E42, 0x0E23, 0x0E18, 0x0E35, 0x0E2D, 0x0E32,
0x0E28, 0x0E31, 0x0E22, 0x0E2D, 0x0E22, 0x0E39, 0x0E48, 0x0E17,
0x0E48, 0x0E32, 0x0E21, 0x0E01, 0x0E25, 0x0E32, 0x0E07, 0x0E17,
0x0E38, 0x0E48, 0x0E07, 0x0E43, 0x0E2B, 0x0E0D, 0x0E48, 0x0E43,
0x0E19, 0x0E41, 0x0E04, 0x0E19, 0x0E0B, 0x0E31, 0x0E2A, 0x0E01,
0x0E31, 0x0E1A, 0x0E25, 0x0E38, 0x0E07, 0x0E40, 0x0E2E, 0x0E19,
0x0E23, 0x0E35, 0x0E0A, 0x0E32, 0x0E27, 0x0E44, 0x0E23, 0x0E48,
0x0E41, 0x0E25, 0x0E30, 0x0E1B, 0x0E49, 0x0E32, 0x0E40, 0x0E2D,
0x0E47, 0x0E21, 0x0E20, 0x0E23, 0x0E23, 0x0E22, 0x0E32, 0x0E0A,
0x0E32, 0x0E27, 0x0E44, 0x0E23, 0x0E48, 0x0E1A, 0x0E49, 0x0E32,
0x0E19, 0x0E02, 0x0E2D, 0x0E07, 0x0E1E, 0x0E27, 0x0E01, 0x0E40,
0x0E02, 0x0E32, 0x0E2B, 0x0E25, 0x0E31, 0x0E07, 0x0E40, 0x0E25,
0x0E47, 0x0E01, 0x0E40, 0x0E1E, 0x0E23, 0x0E32, 0x0E30, 0x0E44,
0x0E21, 0x0E49, 0x0E2A, 0x0E23, 0x0E49, 0x0E32, 0x0E07, 0x0E1A,
0x0E49, 0x0E32, 0x0E19, 0x0E15, 0x0E49, 0x0E2D, 0x0E07, 0x0E02,
0x0E19, 0x0E21, 0x0E32, 0x0E14, 0x0E49, 0x0E27, 0x0E22, 0x0E40,
0x0E01, 0x0E27, 0x0E35, 0x0E22, 0x0E19, 0x0E40, 0x0E1B, 0x0E47,
0x0E19, 0x0E23, 0x0E30, 0x0E22, 0x0E30, 0x0E17, 0x0E32, 0x0E07,
0x0E2B, 0x0E25, 0x0E32, 0x0E22, 0x0E44, 0x0E21, 0x0E25, 0x0E4C
/* A few more lines...
0x0E1A, 0x0E49, 0x0E32, 0x0E19, 0x0E21, 0x0E35, 0x0E2A, 0x0E35,
0x0E48, 0x0E1D, 0x0E32, 0x0E21, 0x0E35, 0x0E1E, 0x0E37, 0x0E49,
0x0E19, 0x0E01, 0x0E31, 0x0E1A, 0x0E2B, 0x0E25, 0x0E31, 0x0E07,
0x0E04, 0x0E32, 0x0E23, 0x0E27, 0x0E21, 0x0E17, 0x0E33, 0x0E40,
0x0E1B, 0x0E47, 0x0E19, 0x0E2B, 0x0E49, 0x0E2D, 0x0E07, 0x0E40,
0x0E14, 0x0E35, 0x0E22, 0x0E27, 0x0E43, 0x0E19, 0x0E2B, 0x0E49,
0x0E2D, 0x0E07, 0x0E21, 0x0E35, 0x0E17, 0x0E31, 0x0E49, 0x0E07,
0x0E40, 0x0E15, 0x0E32, 0x0E2B, 0x0E38, 0x0E07, 0x0E15, 0x0E49,
0x0E21, 0x0E17, 0x0E35, 0x0E48, 0x0E2A, 0x0E19, 0x0E34, 0x0E21,
0x0E14, 0x0E39, 0x0E02, 0x0E36, 0x0E49, 0x0E19, 0x0E40, 0x0E25,
0x0E2D, 0x0E30, 0x0E21, 0x0E35, 0x0E15, 0x0E39, 0x0E49, 0x0E43,
0x0E2A, 0x0E48, 0x0E16, 0x0E49, 0x0E27, 0x0E22, 0x0E0A, 0x0E32,
0x0E21, 0x0E42, 0x0E15, 0x0E4A, 0x0E30, 0x0E40, 0x0E01, 0x0E49,
0x0E32, 0x0E2D, 0x0E35, 0x0E49, 0x0E2A, 0x0E32, 0x0E21, 0x0E2B,
0x0E23
*/
};
le_int32 thaiSampleLength = ARRAY_LENGTH(thaiSample);
TestInput testInputs[] = {
{"raghu.ttf", devaText, devaTextLength, devaScriptCode, FALSE},
{"CODE2000.TTF", arabText, arabTextLength, arabScriptCode, TRUE},
{"LucidaSansRegular.ttf", arabText, arabTextLength, arabScriptCode, TRUE},
{"angsd___.ttf", thaiSample, thaiSampleLength, thaiScriptCode, FALSE}
};
#define TEST_COUNT ARRAY_LENGTH(testInputs)
le_int32 testCount = TEST_COUNT;
void dumpShorts(FILE *file, const char *label, le_int32 id, le_uint16 *shorts, le_int32 count) {
char lineBuffer[8 * 8 + 2];
le_int32 bufp = 0;
fprintf(file, label, id);
for (int i = 0; i < count; i += 1) {
if (i % 8 == 0 && bufp != 0) {
fprintf(file, " %s\n", lineBuffer);
bufp = 0;
}
bufp += sprintf(&lineBuffer[bufp], "0x%4.4X, ", shorts[i]);
}
if (bufp != 0) {
lineBuffer[bufp - 2] = '\0';
fprintf(file, " %s\n", lineBuffer);
}
fprintf(file, "};\n\n");
}
void dumpLongs(FILE *file, const char *label, le_int32 id, le_int32 *longs, le_int32 count) {
void dumpLongs(FILE *file, const char *tag, le_int32 *longs, le_int32 count) {
char lineBuffer[8 * 12 + 2];
le_int32 bufp = 0;
fprintf(file, label, id);
fprintf(file, " <%s>\n", tag);
for (int i = 0; i < count; i += 1) {
if (i % 8 == 0 && bufp != 0) {
fprintf(file, " %s\n", lineBuffer);
fprintf(file, " %s\n", lineBuffer);
bufp = 0;
}
@ -255,52 +79,91 @@ void dumpLongs(FILE *file, const char *label, le_int32 id, le_int32 *longs, le_i
if (bufp != 0) {
lineBuffer[bufp - 2] = '\0';
fprintf(file, " %s\n", lineBuffer);
fprintf(file, " %s\n", lineBuffer);
}
fprintf(file, "};\n\n");
fprintf(file, " </%s>\n\n", tag);
}
void dumpFloats(FILE *file, const char *label, le_int32 id, float *floats, le_int32 count) {
void dumpFloats(FILE *file, const char *tag, float *floats, le_int32 count) {
char lineBuffer[8 * 16 + 2];
le_int32 bufp = 0;
fprintf(file, label, id);
fprintf(file, " <%s>\n", tag);
for (int i = 0; i < count; i += 1) {
if (i % 8 == 0 && bufp != 0) {
fprintf(file, " %s\n", lineBuffer);
fprintf(file, " %s\n", lineBuffer);
bufp = 0;
}
bufp += sprintf(&lineBuffer[bufp], "%fF, ", floats[i]);
bufp += sprintf(&lineBuffer[bufp], "%f, ", floats[i]);
}
if (bufp != 0) {
lineBuffer[bufp - 2] = '\0';
fprintf(file, " %s\n", lineBuffer);
fprintf(file, " %s\n", lineBuffer);
}
fprintf(file, "};\n\n");
fprintf(file, " </%s>\n", tag);
}
const char *getShortName(le_int32 scriptCode)
char *getCString(const UnicodeString *uString)
{
static char shortName[5];
const char *name = uscript_getShortName((UScriptCode) scriptCode);
if (uString == NULL) {
return NULL;
}
shortName[0] = tolower(name[0]);
shortName[1] = tolower(name[1]);
shortName[2] = tolower(name[2]);
shortName[3] = tolower(name[3]);
shortName[4] = '\0';
le_int32 uLength = uString->length();
le_int32 cLength = uString->extract(0, uLength, NULL, 0, US_INV);
char *cString = NEW_ARRAY(char, cLength + 1);
return shortName;
uString->extract(0, uLength, cString, cLength, US_INV);
cString[cLength] = '\0';
return cString;
}
char *getUTF8String(const UnicodeString *uString)
{
if (uString == NULL) {
return NULL;
}
le_int32 uLength = uString->length();
le_int32 cLength = uString->extract(0, uLength, NULL, 0, "UTF-8");
char *cString = NEW_ARRAY(char, cLength + 1);
uString->extract(0, uLength, cString, cLength, "UTF-8");
cString[cLength] = '\0';
return cString;
}
void freeCString(char *cString)
{
DELETE_ARRAY(cString);
}
le_bool getRTL(const UnicodeString &text)
{
UBiDiLevel paraLevel;
UErrorCode status = U_ZERO_ERROR;
le_int32 charCount = text.length();
UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
ubidi_setPara(ubidi, text.getBuffer(), charCount, UBIDI_DEFAULT_LTR, NULL, &status);
paraLevel = ubidi_getParaLevel(ubidi);
ubidi_close(ubidi);
return paraLevel & 1;
}
int main(int /*argc*/, char *argv[])
{
le_int32 test;
UErrorCode status = U_ZERO_ERROR;
FILE *outputFile = fopen(argv[1], "w");
time_t now = time(NULL);
struct tm *local = localtime(&now);
@ -310,81 +173,147 @@ int main(int /*argc*/, char *argv[])
strftime(tmString, 64, tmFormat, local);
fprintf(outputFile, header, local->tm_year + 1900, tmString);
for (test = 0; test < testCount; test += 1) {
LEErrorCode fontStatus = LE_NO_ERROR;
PortableFontInstance fontInstance(testInputs[test].fontName, 12, fontStatus);
UXMLParser *parser = UXMLParser::createParser(status);
UXMLElement *root = parser->parseFile("gendata.xml", status);
if (LE_FAILURE(fontStatus)) {
printf("ERROR: test case %d, could not get a font instance for %s\n", test, testInputs[test].fontName);
continue;
if (root == NULL) {
printf("Error: Could not open gendata.xml\n");
delete parser;
return -1;
}
UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case");
UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text");
UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font");
// test-case attributes
UnicodeString id_attr = UNICODE_STRING_SIMPLE("id");
UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
// test-font attributes
UnicodeString name_attr = UNICODE_STRING_SIMPLE("name");
const UXMLElement *testCase;
int32_t tc = 0;
while((testCase = root->nextChildElement(tc)) != NULL) {
if (testCase->getTagName().compare(test_case) == 0) {
char *id = getCString(testCase->getAttribute(id_attr));
char *script = getCString(testCase->getAttribute(script_attr));
LEFontInstance *font = NULL;
const UXMLElement *element;
int32_t ec = 0;
int32_t charCount = 0;
int32_t typoFlags = 3; // kerning + ligatures...
UScriptCode scriptCode;
UnicodeString text;
int32_t glyphCount = 0;
LEErrorCode leStatus = LE_NO_ERROR;
LayoutEngine *engine = NULL;
LEGlyphID *glyphs = NULL;
le_int32 *indices = NULL;
float *positions = NULL;
uscript_getCode(script, &scriptCode, 1, &status);
if (LE_FAILURE(status)) {
printf("Error: invalid script name: %s.\n", script);
goto free_c_strings;
}
fprintf(outputFile, " <test-case id=\"%s\" script=\"%s\">\n", id, script);
while((element = testCase->nextChildElement(ec)) != NULL) {
UnicodeString tag = element->getTagName();
// TODO: make sure that each element is only used once.
if (tag.compare(test_font) == 0) {
char *fontName = getCString(element->getAttribute(name_attr));
const char *version = NULL;
PortableFontInstance *pfi = new PortableFontInstance(fontName, 12, leStatus);
if (LE_FAILURE(leStatus)) {
printf("Error: could not open font: %s\n", fontName);
freeCString(fontName);
goto free_c_strings;
}
version = pfi->getNameString(NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
fprintf(outputFile, " <test-font name=\"%s\" version=\"%s\" checksum=\"0x%8.8X\"/>\n\n",
fontName, version, pfi->getFontChecksum());
pfi->deleteNameString(version);
freeCString(fontName);
font = pfi;
} else if (tag.compare(test_text) == 0) {
char *utf8 = NULL;
text = element->getText(TRUE);
charCount = text.length();
utf8 = getUTF8String(&text);
fprintf(outputFile, " <test-text>%s</test-text>\n\n", utf8);
freeCString(utf8);
} else {
// an unknown tag...
char *cTag = getCString(&tag);
printf("Test %s: unknown element with tag \"%s\"\n", id, cTag);
freeCString(cTag);
}
}
if (font == NULL) {
LEErrorCode fontStatus = LE_NO_ERROR;
font = new SimpleFontInstance(12, fontStatus);
typoFlags |= 0x80000000L; // use CharSubstitutionFilter...
}
engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, typoFlags, leStatus);
if (LE_FAILURE(leStatus)) {
printf("Error for test %s: could not create a LayoutEngine.\n", id);
goto delete_font;
}
glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, charCount, getRTL(text), 0, 0, leStatus);
glyphs = NEW_ARRAY(LEGlyphID, glyphCount);
indices = NEW_ARRAY(le_int32, glyphCount);
positions = NEW_ARRAY(float, glyphCount * 2 + 2);
engine->getGlyphs(glyphs, leStatus);
engine->getCharIndices(indices, leStatus);
engine->getGlyphPositions(positions, leStatus);
dumpLongs(outputFile, "result-glyphs", (le_int32 *) glyphs, glyphCount);
dumpLongs(outputFile, "result-indices", indices, glyphCount);
dumpFloats(outputFile, "result-positions", positions, glyphCount * 2 + 2);
fprintf(outputFile, " </test-case>\n\n");
DELETE_ARRAY(positions);
DELETE_ARRAY(indices);
DELETE_ARRAY(glyphs);
delete engine;
delete_font:
delete font;
free_c_strings:
freeCString(script);
freeCString(id);
}
const char *nameString = fontInstance.getNameString(NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
fprintf(outputFile, "const char *fontVersionString%d = \"%s\";\n", test, nameString);
fprintf(outputFile, "le_uint32 fontChecksum%d = 0x%8.8X;\n\n", test, fontInstance.getFontChecksum());
fontInstance.deleteNameString(nameString);
LEErrorCode success = LE_NO_ERROR;
LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fontInstance, testInputs[test].scriptCode, -1, success);
le_uint32 glyphCount;
LEGlyphID *glyphs;
le_int32 *indices;
float *positions;
if (LE_FAILURE(success)) {
printf("ERROR: test case %d, could not create a LayoutEngine for script %s.\n", test, uscript_getName((UScriptCode) testInputs[test].scriptCode));
continue;
}
glyphCount = engine->layoutChars(testInputs[test].text, 0, testInputs[test].textLength, testInputs[test].textLength, testInputs[test].rightToLeft, 0, 0, success);
glyphs = new LEGlyphID[glyphCount];
indices = new le_int32[glyphCount];
positions = new float[glyphCount * 2 + 2];
engine->getGlyphs(glyphs, success);
engine->getCharIndices(indices, success);
engine->getGlyphPositions(positions, success);
//fprintf(outputFile, "font: %s\n", testInputs[test].fontName);
dumpShorts(outputFile, "LEUnicode inputText%d[] =\n{\n", test, (le_uint16 *) testInputs[test].text, testInputs[test].textLength);
dumpLongs(outputFile, "LEGlyphID resultGlyphs%d[] =\n{\n", test, (le_int32 *) glyphs, glyphCount);
fprintf(outputFile, "le_int32 resultGlyphCount%d = %d;\n\n", test, glyphCount);
dumpLongs(outputFile, "le_int32 resultIndices%d[] =\n{\n", test, indices, glyphCount);
dumpFloats(outputFile, "float resultPositions%d[] =\n{\n", test, positions, glyphCount * 2 + 2);
fprintf(outputFile, "\n");
delete[] positions;
delete[] indices;
delete[] glyphs;
delete engine;
}
fprintf(outputFile, "TestInput testInputs[] = \n{\n");
delete root;
delete parser;
for (test = 0; test < testCount; test += 1) {
fprintf(outputFile, " {\"%s\", fontVersionString%d, fontChecksum%d, inputText%d, %d, %sScriptCode, %s},\n",
testInputs[test].fontName, test, test, test, testInputs[test].textLength, getShortName(testInputs[test].scriptCode),
testInputs[test].rightToLeft? "TRUE" : "FALSE");
}
fprintf(outputFile, "};\n\nle_int32 testCount = ARRAY_LENGTH(testInputs);\n\n");
fprintf(outputFile, "TestResult testResults[] = \n{\n");
for (test = 0; test < testCount; test += 1) {
fprintf(outputFile, " {resultGlyphCount%d, resultGlyphs%d, resultIndices%d, resultPositions%d},\n",
test, test, test, test);
}
fprintf(outputFile, "};\n\n");
fprintf(outputFile, "</layout-tests>\n");
fclose(outputFile);
return 0;
}

View file

@ -21,7 +21,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\include\layout,..\..\..\include,..\..\common"
AdditionalIncludeDirectories="..\..\..\include\layout;..\..\..\include;..\..\common;..\..\layout;..\..\tools\toolutil"
PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,LE_USE_CMEMORY"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
@ -40,7 +40,7 @@
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="..\..\..\lib\iculed.lib ..\..\..\lib\icuucd.lib odbc32.lib odbccp32.lib"
AdditionalDependencies="..\..\..\lib\iculed.lib ..\..\..\lib\icuucd.lib ..\..\..\lib\icutud.lib odbc32.lib odbccp32.lib"
OutputFile=".\Debug/gendata.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
@ -82,7 +82,7 @@
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\..\..\include\layout,..\..\..\include,..\..\common"
AdditionalIncludeDirectories="..\..\..\include\layout;..\..\..\include;..\..\common;..\..\layout;..\..\tools\toolutil"
PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE,LE_USE_CMEMORY"
StringPooling="TRUE"
RuntimeLibrary="4"
@ -101,7 +101,7 @@
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="..\..\..\lib\icule.lib ..\..\..\lib\icuuc.lib odbc32.lib odbccp32.lib"
AdditionalDependencies="..\..\..\lib\icule.lib ..\..\..\lib\icuuc.lib ..\..\..\lib\icutu.lib odbc32.lib odbccp32.lib"
OutputFile=".\Release/gendata.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
@ -150,6 +150,9 @@
<File
RelativePath=".\PortableFontInstance.cpp">
</File>
<File
RelativePath=".\SimpleFontInstance.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
@ -169,6 +172,9 @@
<File
RelativePath=".\sfnt.h">
</File>
<File
RelativePath=".\SimpleFontInstance.h">
</File>
</Filter>
<Filter
Name="Resource Files"

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 1999-2006 International Business Machines
Corporation and others. All rights reserved.
-->
<layout-tests>
<test-case id="Ghita" script="deva">
<test-font name="raghu.ttf"/>
<test-text>श्रीमद् भगवद्गीता अध्याय अर्जुन विषाद योग धृतराष्ट्र उवाचृ धर्मक्षेत्रे कुरुक्षेत्रे समवेता युयुत्सवः मामकाः पाण्डवाश्चैव किमकुर्वत संजव</test-text>
</test-case>
<test-case id="Arabic" script="arab">
<test-font name="CODE2000.TTF"/>
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
</test-case>
<test-case id="Unicode Arabic" script="arab">
<test-font name="LucidaSansRegular.ttf"/>
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
</test-case>
<test-case id="Thai" script="thai">
<test-font name="angsd___.ttf"/>
<test-text>บทที่๑พายุไซโคลนโดโรธีอาศัยอยู่ท่ามกลางทุ่งใหญ่ในแคนซัสกับลุงเฮนรีชาวไร่และป้าเอ็มภรรยาชาวไร่บ้านของพวกเขาหลังเล็กเพราะไม้สร้างบ้านต้องขนมาด้วยเกวียนเป็นระยะทางหลายไมล์</test-text>
</test-case>
<test-case id="Arabic Simple" script="arab">
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
</test-case>
</layout-tests>

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2005, International Business Machines
* Copyright (C) 1999-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -13,19 +13,315 @@
#include "math.h"
#include "LETypes.h"
#include "LayoutEngine.h"
#include "unicode/utypes.h"
#include "unicode/uclean.h"
#include "unicode/ucnv.h"
#include "unicode/uchar.h"
#include "unicode/unistr.h"
#include "unicode/uscript.h"
#include "unicode/ubidi.h"
#include "unicode/putil.h"
#include "unicode/ctest.h"
#include "layout/LETypes.h"
#include "layout/LEScripts.h"
#include "layout/LayoutEngine.h"
#include "PortableFontInstance.h"
#include "SimpleFontInstance.h"
#include "letest.h"
#include "xmlparser.h"
#include "putilimp.h" // for uprv_getUTCtime()
#include <stdlib.h>
#include <string.h>
U_NAMESPACE_USE
le_bool compareResults(le_int32 /*testNumber*/, TestResult *expected, TestResult *actual)
#define CH_COMMA 0x002C
U_CDECL_BEGIN
static void U_CALLCONV ParamTest(void)
{
LEErrorCode status = LE_NO_ERROR;
SimpleFontInstance *font = new SimpleFontInstance(12, status);
LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
LEGlyphID *glyphs = NULL;
le_int32 *indices = NULL;
float *positions = NULL;
le_int32 glyphCount = 0;
glyphCount = engine->getGlyphCount();
if (glyphCount != 0) {
log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount);
}
glyphs = NEW_ARRAY(LEGlyphID, glyphCount + 10);
indices = NEW_ARRAY(le_int32, glyphCount + 10);
positions = NEW_ARRAY(float, glyphCount + 10);
engine->getGlyphs(NULL, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphs(glyphs, status);
if (status != LE_NO_LAYOUT_ERROR) {
log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphs(NULL, 0xFF000000L, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling getGlyphs(NULL, 0xFF000000L, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphs(glyphs, 0xFF000000L, status);
if (status != LE_NO_LAYOUT_ERROR) {
log_err("Calling getGlyphs(glyphs, 0xFF000000L, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getCharIndices(NULL, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getCharIndices(indices, status);
if (status != LE_NO_LAYOUT_ERROR) {
log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getCharIndices(NULL, 1024, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getCharIndices(indices, 1024, status);
if (status != LE_NO_LAYOUT_ERROR) {
log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphPositions(NULL, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphPositions(positions, status);
if (status != LE_NO_LAYOUT_ERROR) {
log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
}
DELETE_ARRAY(positions);
DELETE_ARRAY(indices);
DELETE_ARRAY(glyphs);
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
LEUnicode chars[] = {
0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN
0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text."
};
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(chars, 8, 6, -1, TRUE, 0.0, 0.0, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status);
if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
}
float x = 0.0, y = 0.0;
status = LE_NO_ERROR;
glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
if (LE_FAILURE(status)) {
log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
goto bail;
}
engine->getGlyphPosition(-1, x, y, status);
if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
}
status = LE_NO_ERROR;
engine->getGlyphPosition(glyphCount + 1, x, y, status);
if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
}
bail:
delete engine;
delete font;
}
U_CDECL_END
U_CDECL_BEGIN
static void U_CALLCONV FactoryTest(void)
{
LEErrorCode status = LE_NO_ERROR;
SimpleFontInstance *font = new SimpleFontInstance(12, status);
LayoutEngine *engine = NULL;
for(le_int32 scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) {
status = LE_NO_ERROR;
engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, status);
if (LE_FAILURE(status)) {
log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode));
}
delete engine;
}
delete font;
}
U_CDECL_END
U_CDECL_BEGIN
static void U_CALLCONV AccessTest(void)
{
LEErrorCode status = LE_NO_ERROR;
SimpleFontInstance *font = new SimpleFontInstance(12, status);
LayoutEngine *engine = LayoutEngine::layoutEngineFactory(font, arabScriptCode, -1, status);
le_int32 glyphCount;
LEGlyphID glyphs[6], extraBitGlyphs[6];;
le_int32 biasedIndices[6], indices[6], glyph;
float positions[6 * 2 + 2];
LEUnicode chars[] = {
0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, // "English "
0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, // MEM ALIF KAF NOON TEH WAW SHEEN
0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E // " text."
};
if (LE_FAILURE(status)) {
log_err("Could not create LayoutEngine.\n");
goto bail;
}
glyphCount = engine->layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status);
if (LE_FAILURE(status) || glyphCount != 6) {
log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
goto bail;
}
engine->getGlyphs(glyphs, status);
engine->getCharIndices(indices, status);
engine->getGlyphPositions(positions, status);
if (LE_FAILURE(status)) {
log_err("Could not get glyph, indices and position arrays.\n");
goto bail;
}
engine->getGlyphs(extraBitGlyphs, 0xFF000000L, status);
if (LE_FAILURE(status)) {
log_err("getGlyphs(extraBitGlyphs, 0xFF000000L, status); failed.\n");
} else {
for(glyph = 0; glyph < glyphCount; glyph += 1) {
if (extraBitGlyphs[glyph] != (glyphs[glyph] | 0xFF000000L)) {
log_err("extraBigGlyphs[%d] != glyphs[%d] | 0xFF000000L: %8X, %8X\n",
glyph, glyph, extraBitGlyphs[glyph], glyphs[glyph]);
break;
}
}
}
status = LE_NO_ERROR;
engine->getCharIndices(biasedIndices, 1024, status);
if (LE_FAILURE(status)) {
log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
} else {
for (glyph = 0; glyph < glyphCount; glyph += 1) {
if (biasedIndices[glyph] != (indices[glyph] + 1024)) {
log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
glyph, glyph, biasedIndices[glyph], indices[glyph]);
break;
}
}
}
status = LE_NO_ERROR;
for (glyph = 0; glyph <= glyphCount; glyph += 1) {
float x = 0.0, y = 0.0;
engine->getGlyphPosition(glyph, x, y, status);
if (LE_FAILURE(status)) {
log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph);
break;
}
if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) {
log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]);
break;
}
}
bail:
delete engine;
delete font;
}
U_CDECL_END
le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
{
/* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
if (actual->glyphCount != expected->glyphCount) {
printf("incorrect glyph count: exptected %d, got %d\n", expected->glyphCount, actual->glyphCount);
log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
testID, expected->glyphCount, actual->glyphCount);
return FALSE;
}
@ -33,14 +329,16 @@ le_bool compareResults(le_int32 /*testNumber*/, TestResult *expected, TestResult
for (i = 0; i < actual->glyphCount; i += 1) {
if (actual->glyphs[i] != expected->glyphs[i]) {
printf("incorrect id for glyph %d: expected %4X, got %4X\n", i, expected->glyphs[i], actual->glyphs[i]);
log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
testID, i, expected->glyphs[i], actual->glyphs[i]);
return FALSE;
}
}
for (i = 0; i < actual->glyphCount; i += 1) {
if (actual->indices[i] != expected->indices[i]) {
printf("incorrect index for glyph %d: expected %8X, got %8X\n", i, expected->indices[i], actual->indices[i]);
log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
testID, i, expected->indices[i], actual->indices[i]);
return FALSE;
}
}
@ -49,7 +347,8 @@ le_bool compareResults(le_int32 /*testNumber*/, TestResult *expected, TestResult
double xError = fabs(actual->positions[i * 2] - expected->positions[i * 2]);
if (xError > 0.0001) {
printf("incorrect x position for glyph %d: expected %f, got %f\n", i, expected->positions[i * 2], actual->positions[i * 2]);
log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
testID, i, expected->positions[i * 2], actual->positions[i * 2]);
return FALSE;
}
@ -60,7 +359,8 @@ le_bool compareResults(le_int32 /*testNumber*/, TestResult *expected, TestResult
}
if (yError > 0.0001) {
printf("incorrect y position for glyph %d: expected %f, got %f\n", i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
return FALSE;
}
}
@ -68,77 +368,514 @@ le_bool compareResults(le_int32 /*testNumber*/, TestResult *expected, TestResult
return TRUE;
}
static void checkFontVersion(PortableFontInstance &fontInstance, const char *testVersionString, le_uint32 testChecksum)
static void checkFontVersion(PortableFontInstance *fontInstance, const char *testVersionString,
le_uint32 testChecksum, const char *testID)
{
le_uint32 fontChecksum = fontInstance.getFontChecksum();
le_uint32 fontChecksum = fontInstance->getFontChecksum();
if (fontChecksum != testChecksum) {
const char *fontVersionString = fontInstance.getNameString(NAME_VERSION_STRING,
const char *fontVersionString = fontInstance->getNameString(NAME_VERSION_STRING,
PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
printf("this may not be the same font used to generate the test data.\n");
printf("Your font's version string is \"%s\"\n", fontVersionString);
printf("The expected version string is \"%s\"\n", testVersionString);
printf("If you see errors, they may be due to the version of the font you're using.\n");
log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
log_info("Your font's version string is \"%s\"\n", fontVersionString);
log_info("The expected version string is \"%s\"\n", testVersionString);
log_info("If you see errors, they may be due to the version of the font you're using.\n");
}
}
int main(int /*argc*/, char * /*argv[]*/)
/* Returns the path to icu/source/test/testdata/ */
const char *getSourceTestData() {
const char *srcDataDir = NULL;
#ifdef U_TOPSRCDIR
srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
#else
srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
if (f != NULL) {
/* We're in icu/source/test/letest/ */
fclose(f);
} else {
/* We're in icu/source/test/letest/(Debug|Release) */
srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
}
#endif
return srcDataDir;
}
const char *getPath(char buffer[2048], const char *filename) {
const char *testDataDirectory = getSourceTestData();
strcpy(buffer, testDataDirectory);
strcat(buffer, filename);
return buffer;
}
le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
{
le_int32 failures = 0;
int32_t offset = -1;
for (le_int32 test = 0; test < testCount; test += 1) {
LEErrorCode fontStatus = LE_NO_ERROR;
printf("Test %d, font = %s... ", test, testInputs[test].fontName);
PortableFontInstance fontInstance(testInputs[test].fontName, 12, fontStatus);
if (LE_FAILURE(fontStatus)) {
printf("could not open font.\n");
continue;
}
checkFontVersion(fontInstance, testInputs[test].fontVersionString, testInputs[test].fontChecksum);
LEErrorCode success = LE_NO_ERROR;
LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fontInstance, testInputs[test].scriptCode, -1, success);
le_int32 textLength = testInputs[test].textLength;
le_bool result;
TestResult actual;
if (LE_FAILURE(success)) {
// would be nice to print the script name here, but
// don't want to maintain a table, and don't want to
// require ICU just for the script name...
printf("could not create a LayoutEngine.\n");
continue;
}
actual.glyphCount = engine->layoutChars(testInputs[test].text, 0, textLength, textLength, testInputs[test].rightToLeft, 0, 0, success);
actual.glyphs = new LEGlyphID[actual.glyphCount];
actual.indices = new le_int32[actual.glyphCount];
actual.positions = new float[actual.glyphCount * 2 + 2];
engine->getGlyphs(actual.glyphs, success);
engine->getCharIndices(actual.indices, success);
engine->getGlyphPositions(actual.positions, success);
result = compareResults(test, &testResults[test], &actual);
if (result) {
printf("passed.\n");
} else {
failures += 1;
printf("failed.\n");
}
delete[] actual.positions;
delete[] actual.indices;
delete[] actual.glyphs;
delete engine;
arraySize = 1;
while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
arraySize += 1;
}
return failures;
le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
char number[16];
le_int32 count = 0;
le_int32 start = 0, end = 0;
le_int32 len = 0;
// trim leading whitespace
while(u_isUWhiteSpace(numbers[start])) {
start += 1;
}
while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
number[len] = '\0';
start = end + 1;
sscanf(number, "%x", &array[count++]);
// trim whitespace following the comma
while(u_isUWhiteSpace(numbers[start])) {
start += 1;
}
}
// trim trailing whitespace
end = numbers.length();
while(u_isUWhiteSpace(numbers[end - 1])) {
end -= 1;
}
len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
number[len] = '\0';
sscanf(number, "%x", &array[count]);
return array;
}
float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
{
int32_t offset = -1;
arraySize = 1;
while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
arraySize += 1;
}
float *array = NEW_ARRAY(float, arraySize);
char number[32];
le_int32 count = 0;
le_int32 start = 0, end = 0;
le_int32 len = 0;
// trim leading whitespace
while(u_isUWhiteSpace(numbers[start])) {
start += 1;
}
while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
number[len] = '\0';
start = end + 1;
sscanf(number, "%f", &array[count++]);
// trim whiteapce following the comma
while(u_isUWhiteSpace(numbers[start])) {
start += 1;
}
}
while(u_isUWhiteSpace(numbers[start])) {
start += 1;
}
// trim trailing whitespace
end = numbers.length();
while(u_isUWhiteSpace(numbers[end - 1])) {
end -= 1;
}
len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
number[len] = '\0';
sscanf(number, "%f", &array[count]);
return array;
}
LEFontInstance *openFont(const char *fontName, const char *checksum, const char *version, const char *testID)
{
char path[2048];
PortableFontInstance *font;
LEErrorCode fontStatus = LE_NO_ERROR;
font = new PortableFontInstance(getPath(path, fontName), 12, fontStatus);
if (LE_FAILURE(fontStatus)) {
log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName);
return NULL;
} else {
le_uint32 cksum = 0;
sscanf(checksum, "%x", &cksum);
checkFontVersion(font, version, cksum, testID);
}
return font;
}
char *getCString(const UnicodeString *uString)
{
if (uString == NULL) {
return NULL;
}
le_int32 uLength = uString->length();
le_int32 cLength = uString->extract(0, uLength, NULL, 0, US_INV);
char *cString = NEW_ARRAY(char, cLength + 1);
uString->extract(0, uLength, cString, cLength, US_INV);
cString[cLength] = '\0';
return cString;
}
void freeCString(char *cString)
{
DELETE_ARRAY(cString);
}
le_bool getRTL(const UnicodeString &text)
{
UBiDiLevel paraLevel;
UErrorCode status = U_ZERO_ERROR;
le_int32 charCount = text.length();
UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
ubidi_setPara(ubidi, text.getBuffer(), charCount, UBIDI_DEFAULT_LTR, NULL, &status);
paraLevel = ubidi_getParaLevel(ubidi);
ubidi_close(ubidi);
return paraLevel & 1;
}
U_CDECL_BEGIN
static void U_CALLCONV DataDrivenTest(void)
{
UErrorCode status = U_ZERO_ERROR;
char path[2048];
const char *testFilePath = getPath(path, "letest.xml");
UXMLParser *parser = UXMLParser::createParser(status);
UXMLElement *root = parser->parseFile(testFilePath, status);
if (root == NULL) {
log_err("Could not open the test data file: %s\n", testFilePath);
delete parser;
return;
}
UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case");
UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text");
UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font");
UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs");
UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices");
UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
// test-case attributes
UnicodeString id_attr = UNICODE_STRING_SIMPLE("id");
UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
// test-font attributes
UnicodeString name_attr = UNICODE_STRING_SIMPLE("name");
UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version");
UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum");
const UXMLElement *testCase;
int32_t tc = 0;
while((testCase = root->nextChildElement(tc)) != NULL) {
if (testCase->getTagName().compare(test_case) == 0) {
char *id = getCString(testCase->getAttribute(id_attr));
char *script = getCString(testCase->getAttribute(script_attr));
LEFontInstance *font = NULL;
const UXMLElement *element;
int32_t ec = 0;
int32_t charCount = 0;
int32_t typoFlags = 3; // kerning + ligatures...
UScriptCode scriptCode;
UnicodeString text, glyphs, indices, positions;
int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
TestResult expected = {0, NULL, NULL, NULL};
TestResult actual = {0, NULL, NULL, NULL};
LEErrorCode success = LE_NO_ERROR;
LayoutEngine *engine = NULL;
uscript_getCode(script, &scriptCode, 1, &status);
if (LE_FAILURE(status)) {
log_err("invalid script name.\n");
goto free_c_strings;
}
while((element = testCase->nextChildElement(ec)) != NULL) {
UnicodeString tag = element->getTagName();
// TODO: make sure that each element is only used once.
if (tag.compare(test_font) == 0) {
char *fontName = getCString(element->getAttribute(name_attr));
char *fontVer = getCString(element->getAttribute(ver_attr));
char *fontCksum = getCString(element->getAttribute(cksum_attr));
font = openFont(fontName, fontCksum, fontVer, id);
freeCString(fontCksum);
freeCString(fontVer);
freeCString(fontName);
if (font == NULL) {
// warning message already displayed...
goto free_c_strings;
}
} else if (tag.compare(test_text) == 0) {
text = element->getText(TRUE);
charCount = text.length();
} else if (tag.compare(result_glyphs) == 0) {
glyphs = element->getText(TRUE);
} else if (tag.compare(result_indices) == 0) {
indices = element->getText(TRUE);
} else if (tag.compare(result_positions) == 0) {
positions = element->getText(TRUE);
} else {
// an unknown tag...
char *cTag = getCString(&tag);
log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
freeCString(cTag);
}
}
// TODO: make sure that the font, test-text, result-glyphs, result-indices and result-positions
// have all been provided
if (font == NULL) {
LEErrorCode fontStatus = LE_NO_ERROR;
font = new SimpleFontInstance(12, fontStatus);
typoFlags |= 0x80000000L; // use CharSubstitutionFilter...
}
expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount);
expected.indices = (le_int32 *) getHexArray(indices, indexCount);
expected.positions = getFloatArray(positions, positionCount);
expected.glyphCount = glyphCount;
if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
id, charCount, glyphCount, indexCount, positionCount);
goto free_expected;
};
engine = LayoutEngine::layoutEngineFactory(font, scriptCode, -1, typoFlags, success);
if (LE_FAILURE(success)) {
log_err("Test %s: could not create a LayoutEngine.\n", id);
goto free_expected;
}
actual.glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, charCount, getRTL(text), 0, 0, success);
actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount);
actual.indices = NEW_ARRAY(le_int32, actual.glyphCount);
actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2);
engine->getGlyphs(actual.glyphs, success);
engine->getCharIndices(actual.indices, success);
engine->getGlyphPositions(actual.positions, success);
compareResults(id, &expected, &actual);
DELETE_ARRAY(actual.positions);
DELETE_ARRAY(actual.indices);
DELETE_ARRAY(actual.glyphs);
delete engine;
free_expected:
DELETE_ARRAY(expected.positions);
DELETE_ARRAY(expected.indices);
DELETE_ARRAY(expected.glyphs);
delete font;
free_c_strings:
freeCString(script);
freeCString(id);
}
}
delete root;
delete parser;
}
U_CDECL_END
static void addAllTests(TestNode** root)
{
addTest(root, &ParamTest, "api/ParameterTest");
addTest(root, &FactoryTest, "api/FactoryTest");
addTest(root, &AccessTest, "layout/AccessTest");
addTest(root, &DataDrivenTest, "layout/DataDrivenTest");
}
/* returns the path to icu/source/data/out */
static const char *ctest_dataOutDir()
{
static const char *dataOutDir = NULL;
if(dataOutDir) {
return dataOutDir;
}
/* U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
// to point to the top of the build hierarchy, which may or
// may not be the same as the source directory, depending on
// the configure options used. At any rate,
// set the data path to the built data from this directory.
// The value is complete with quotes, so it can be used
// as-is as a string constant.
*/
#if defined (U_TOPBUILDDIR)
{
dataOutDir = U_TOPBUILDDIR "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
}
#else
/* On Windows, the file name obtained from __FILE__ includes a full path.
* This file is "wherever\icu\source\test\cintltst\cintltst.c"
* Change to "wherever\icu\source\data"
*/
{
static char p[sizeof(__FILE__) + 20];
char *pBackSlash;
int i;
strcpy(p, __FILE__);
/* We want to back over three '\' chars. */
/* Only Windows should end up here, so looking for '\' is safe. */
for (i=1; i<=3; i++) {
pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
if (pBackSlash != NULL) {
*pBackSlash = 0; /* Truncate the string at the '\' */
}
}
if (pBackSlash != NULL) {
/* We found and truncated three names from the path.
* Now append "source\data" and set the environment
*/
strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
dataOutDir = p;
}
else {
/* __FILE__ on MSVC7 does not contain the directory */
FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
if (file) {
fclose(file);
dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
}
else {
dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
}
}
}
#endif
return dataOutDir;
}
/* ctest_setICU_DATA - if the ICU_DATA environment variable is not already
* set, try to deduce the directory in which ICU was built,
* and set ICU_DATA to "icu/source/data" in that location.
* The intent is to allow the tests to have a good chance
* of running without requiring that the user manually set
* ICU_DATA. Common data isn't a problem, since it is
* picked up via a static (build time) reference, but the
* tests dynamically load some data.
*/
static void ctest_setICU_DATA() {
/* No location for the data dir was identifiable.
* Add other fallbacks for the test data location here if the need arises
*/
if (getenv("ICU_DATA") == NULL) {
/* If ICU_DATA isn't set, set it to the usual location */
u_setDataDirectory(ctest_dataOutDir());
}
}
int main(int argc, char* argv[])
{
int32_t nerrors = 0;
TestNode *root = NULL;
UErrorCode errorCode = U_ZERO_ERROR;
UDate startTime, endTime;
int32_t diffTime;
startTime = uprv_getUTCtime();
/* Check whether ICU will initialize without forcing the build data directory into
* the ICU_DATA path. Success here means either the data dll contains data, or that
* this test program was run with ICU_DATA set externally. Failure of this check
* is normal when ICU data is not packaged into a shared library.
*
* Whether or not this test succeeds, we want to cleanup and reinitialize
* with a data path so that data loading from individual files can be tested.
*/
u_init(&errorCode);
if (U_FAILURE(errorCode)) {
fprintf(stderr,
"#### Note: ICU Init without build-specific setDataDirectory() failed.\n");
}
u_cleanup();
errorCode = U_ZERO_ERROR;
/* Initialize ICU */
ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init() */
u_init(&errorCode);
if (U_FAILURE(errorCode)) {
fprintf(stderr,
"#### ERROR! %s: u_init() failed with status = \"%s\".\n"
"*** Check the ICU_DATA environment variable and \n"
"*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
return 1;
}
fprintf(stdout, "Default charset for this run is %s\n", ucnv_getDefaultName());
addAllTests(&root);
nerrors = processArgs(root, argc, argv);
cleanUpTestTree(root);
u_cleanup();
endTime = uprv_getUTCtime();
diffTime = (int32_t)(endTime - startTime);
printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
(int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
(int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
(int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
(int)(diffTime%U_MILLIS_PER_SECOND));
return nerrors;
}

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2005, International Business Machines
* Copyright (C) 1999-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -11,24 +11,23 @@
* created by: Eric R. Mader
*/
#ifndef __LETEST_H
#define __LETEST_H
#include "LETypes.h"
#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
#include <stdlib.h>
#include <string.h>
struct TestInput
{
const char *fontName;
const char *fontVersionString;
le_uint32 fontChecksum;
LEUnicode *text;
le_int32 textLength;
le_int32 scriptCode;
le_bool rightToLeft;
};
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
extern le_int32 testCount;
#define ARRAY_COPY(dst, src, count) memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0])
extern TestInput testInputs[];
#define NEW_ARRAY(type,count) (type *) malloc((count) * sizeof(type))
#define DELETE_ARRAY(array) free((void *) (array))
#define GROW_ARRAY(array,newSize) realloc((void *) (array), (newSize) * sizeof (array)[0])
struct TestResult
{
@ -37,7 +36,4 @@ struct TestResult
le_int32 *indices;
float *positions;
};
extern TestResult testResults[];
#endif

View file

@ -3,6 +3,7 @@
ProjectType="Visual C++"
Version="7.10"
Name="letest"
ProjectGUID="{67351485-4D18-4245-BE39-A7EF0675ACD2}"
SccProjectName=""
SccLocalPath="">
<Platforms>
@ -21,8 +22,8 @@
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\..\..\include\layout,..\..\..\include,..\..\common"
PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE,LE_USE_CMEMORY"
AdditionalIncludeDirectories="..\..\..\include\layout;..\..\..\include;..\..\common;..\..\tools\ctestfw;..\..\tools\toolutil;..\..\layout"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
@ -81,8 +82,8 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\include\layout,..\..\..\include,..\..\common"
PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,LE_USE_CMEMORY"
AdditionalIncludeDirectories="..\..\..\include\layout;..\..\..\include;..\..\common;..\..\tools\ctestfw;..\..\tools\toolutil;..\..\layout"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
TreatWChar_tAsBuiltInType="TRUE"
@ -100,10 +101,10 @@
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="../../../lib/iculed.lib ../../../lib/icuucd.lib odbc32.lib odbccp32.lib"
OutputFile=".\Debug/letest.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories=""
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/letest.pdb"
SubSystem="1"/>
@ -151,7 +152,7 @@
RelativePath=".\PortableFontInstance.cpp">
</File>
<File
RelativePath=".\testdata.cpp">
RelativePath=".\SimpleFontInstance.cpp">
</File>
</Filter>
<Filter
@ -172,6 +173,9 @@
<File
RelativePath=".\sfnt.h">
</File>
<File
RelativePath=".\SimpleFontInstance.h">
</File>
</Filter>
<Filter
Name="Resource Files"

627
icu4c/source/test/testdata/letest.xml vendored Normal file
View file

@ -0,0 +1,627 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 1999-2006 International Business Machines
Corporation and others. All rights reserved.
WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT
UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.
file name: letest.xml
generated on: 04/06/2006 03:18:07 PM Hawaiian Standard Time
generated by: gendata.cpp
-->
<layout-tests>
<test-case id="Ghita" script="deva">
<test-font name="raghu.ttf" version="Version 0.99" checksum="0x541C94C7"/>
<test-text>श्रीमद् भगवद्गीता अध्याय अर्जुन विषाद योग धृतराष्ट्र उवाचृ धर्मक्षेत्रे कुरुक्षेत्रे समवेता युयुत्सवः मामकाः पाण्डवाश्चैव किमकुर्वत संजव</test-text>
<result-glyphs>
0x0000012E, 0x0000FFFF, 0x0000FFFF, 0x00000222, 0x00000098, 0x0000026E, 0x0000FFFF, 0x00000003,
0x00000097, 0x00000082, 0x0000009D, 0x000001A5, 0x0000FFFF, 0x0000FFFF, 0x00000222, 0x0000008F,
0x00000221, 0x00000003, 0x0000005C, 0x000000DA, 0x0000FFFF, 0x00000099, 0x00000221, 0x00000099,
0x00000003, 0x0000005C, 0x00000087, 0x000001D5, 0x0000005B, 0x0000FFFF, 0x00000093, 0x00000003,
0x000001D2, 0x0000009D, 0x0000009F, 0x00000221, 0x00000091, 0x00000003, 0x00000099, 0x0000022A,
0x00000082, 0x00000003, 0x00000092, 0x000001D9, 0x0000008F, 0x0000009A, 0x00000221, 0x000001B6,
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x00000060, 0x0000009D, 0x00000221,
0x00000085, 0x000001D9, 0x00000003, 0x00000092, 0x00000098, 0x0000005B, 0x0000FFFF, 0x000000A2,
0x0000FFFF, 0x0000FFFF, 0x0000022F, 0x0000011F, 0x0000FFFF, 0x0000FFFF, 0x0000022F, 0x00000003,
0x00000080, 0x000001D5, 0x0000009A, 0x000001FD, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x0000022F,
0x0000011F, 0x0000FFFF, 0x0000FFFF, 0x0000022F, 0x00000003, 0x000000A0, 0x00000098, 0x0000009D,
0x0000022F, 0x0000008F, 0x00000221, 0x00000003, 0x00000099, 0x000001D5, 0x00000099, 0x000001D5,
0x000000D7, 0x0000FFFF, 0x000000A0, 0x0000009D, 0x0000022C, 0x00000003, 0x00000098, 0x00000221,
0x00000098, 0x00000080, 0x00000221, 0x0000022C, 0x00000003, 0x00000094, 0x00000221, 0x000000D6,
0x0000FFFF, 0x0000008C, 0x0000009D, 0x00000221, 0x000001B1, 0x0000FFFF, 0x0000FFFF, 0x00000230,
0x0000009D, 0x00000003, 0x000001D1, 0x00000080, 0x00000098, 0x00000080, 0x000001D5, 0x0000009D,
0x0000005B, 0x0000FFFF, 0x0000008F, 0x00000003, 0x000000A0, 0x00000232, 0x00000087, 0x0000009D
</result-glyphs>
<result-indices>
0x00000000, 0x00000002, 0x00000001, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007,
0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F,
0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017,
0x00000018, 0x00000019, 0x0000001C, 0x0000001D, 0x0000001A, 0x0000001B, 0x0000001E, 0x0000001F,
0x00000021, 0x00000020, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027,
0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F,
0x00000030, 0x00000031, 0x00000033, 0x00000032, 0x00000034, 0x00000035, 0x00000036, 0x00000037,
0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003E, 0x0000003C, 0x0000003D, 0x0000003F,
0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000045, 0x00000044, 0x00000046, 0x00000047,
0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F,
0x00000050, 0x00000052, 0x00000051, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057,
0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F,
0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067,
0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F,
0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077,
0x00000078, 0x00000079, 0x0000007B, 0x0000007A, 0x0000007C, 0x0000007D, 0x0000007E, 0x00000081,
0x0000007F, 0x00000080, 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x00000087
</result-indices>
<result-positions>
0.000000, 0.000000, 9.468750, 0.000000, 9.468750, 0.000000, 9.468750, 0.000000,
13.125000, 0.000000, 22.593750, 0.000000, 30.562500, 0.000000, 30.562500, 0.000000,
36.562500, 0.000000, 46.031250, 0.000000, 55.500000, 0.000000, 63.468750, 0.000000,
71.437500, 0.000000, 71.437500, 0.000000, 71.437500, 0.000000, 75.093750, 0.000000,
83.062500, 0.000000, 86.718750, 0.000000, 92.718750, 0.000000, 102.656250, 0.000000,
109.921875, 0.000000, 109.921875, 0.000000, 119.390625, 0.000000, 123.046875, 0.000000,
132.515625, 0.000000, 138.515625, 0.000000, 148.453125, 0.000000, 158.203125, -0.011719,
158.203125, 0.263672, 157.921875, 0.000000, 157.921875, 0.000000, 167.390625, 0.000000,
173.390625, 0.000000, 177.750000, 0.000000, 185.718750, 0.000000, 193.687500, 0.000000,
197.343750, 0.000000, 205.312500, 0.000000, 211.312500, 0.000000, 220.781250, 0.000000,
224.859375, 0.000000, 234.328125, 0.000000, 240.328125, 0.000000, 250.224609, -0.011719,
249.796875, 0.000000, 257.765625, 0.000000, 264.281250, 0.000000, 267.937500, 0.000000,
276.281250, 0.000000, 276.281250, 0.000000, 276.281250, 0.000000, 276.281250, 0.000000,
276.281250, 0.000000, 282.281250, 0.000000, 290.250000, 0.000000, 298.218750, 0.000000,
301.875000, 0.000000, 311.859375, -0.011719, 311.343750, 0.000000, 317.343750, 0.000000,
326.812500, 0.000000, 336.644531, 0.263672, 336.281250, 0.000000, 336.281250, 0.000000,
347.156250, 0.000000, 347.156250, 0.000000, 346.353516, 0.275391, 347.156250, 0.000000,
355.125000, 0.000000, 355.125000, 0.000000, 355.263672, 0.263672, 355.125000, 0.000000,
361.125000, 0.000000, 368.824219, -0.011719, 372.000000, 0.000000, 378.515625, 0.000000,
379.875000, 0.000000, 390.750000, 0.000000, 390.750000, 0.000000, 389.947266, 0.275391,
390.750000, 0.000000, 398.718750, 0.000000, 398.718750, 0.000000, 398.857422, 0.263672,
398.718750, 0.000000, 404.718750, 0.000000, 414.187500, 0.000000, 423.656250, 0.000000,
430.769531, 0.263672, 431.625000, 0.000000, 439.593750, 0.000000, 443.250000, 0.000000,
449.250000, 0.000000, 458.859375, -0.011719, 458.718750, 0.000000, 468.328125, -0.011719,
468.187500, 0.000000, 474.117188, 0.000000, 474.117188, 0.000000, 483.585938, 0.000000,
491.554688, 0.000000, 495.914063, 0.000000, 501.914063, 0.000000, 511.382813, 0.000000,
515.039063, 0.000000, 524.507813, 0.000000, 535.382813, 0.000000, 539.039063, 0.000000,
543.398438, 0.000000, 549.398438, 0.000000, 557.367188, 0.000000, 561.023438, 0.000000,
568.289063, 0.000000, 568.289063, 0.000000, 576.257813, 0.000000, 584.226563, 0.000000,
587.882813, 0.000000, 598.757813, 0.000000, 598.757813, 0.000000, 598.628906, 0.263672,
598.757813, 0.000000, 606.726563, 0.000000, 612.726563, 0.000000, 617.085938, 0.000000,
627.960938, 0.000000, 637.429688, 0.000000, 645.128906, -0.011719, 648.304688, 0.000000,
656.566406, 0.263672, 656.273438, 0.000000, 656.273438, 0.000000, 664.242188, 0.000000,
670.242188, 0.000000, 679.429688, 0.966797, 679.710938, 0.000000, 689.179688, 0.000000,
697.148438, 0.000000
</result-positions>
</test-case>
<test-case id="Arabic" script="arab">
<test-font name="CODE2000.TTF" version="Version 1.14" checksum="0x2B6E171D"/>
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
<result-glyphs>
0x0000C530, 0x0000C58F, 0x0000C549, 0x0000C589, 0x0000C54A, 0x0000C55C, 0x0000C57B, 0x0000C529,
0x00000003, 0x0000C56D, 0x0000C549, 0x0000C52A, 0x0000C540, 0x0000C580, 0x0000C57B, 0x0000C529,
0x00000003, 0x0000C566, 0x0000C590, 0x0000C580, 0x0000C53B, 0x00000003, 0x0000C58C, 0x0000C57C,
0x0000C567, 0x00000003, 0x0000C58D, 0x0000C58A, 0x0000C534, 0x0000C540, 0x0000C58F, 0x00000003,
0x0000C546, 0x0000C53F, 0x0000C529, 0x0000C589, 0x00000003, 0x0000C54A, 0x0000C590, 0x0000C570,
0x0000C554, 0x0000C533, 0x00000003, 0x0000C57D, 0x0000C52A, 0x0000C564, 0x0000C583, 0x00000003,
0x0000C546, 0x0000C53B, 0x0000C58A, 0x0000C58F, 0x00000003, 0x0000C57E, 0x0000C57B, 0x0000C589,
0x00000003, 0x00000528, 0x0000C56D, 0x0000C549, 0x0000C52A, 0x0000C540, 0x0000C580, 0x0000C57C,
0x0000C57B, 0x00000003, 0x0000C57D, 0x0000C52A, 0x0000C573, 0x0000C549, 0x0000FFFE, 0x0000C593,
0x0000C529, 0x00000003, 0x0000C585, 0x0000C548, 0x0000C587, 0x00000003, 0x0000C556, 0x0000C590,
0x0000C558, 0x0000C544, 0x0000C533, 0x0000C589, 0x00000003, 0x0000C54A, 0x0000C590, 0x0000C570,
0x0000C554, 0x0000C534, 0x0000C57C, 0x0000C57B, 0x00000003, 0x0000C530, 0x0000C580, 0x0000C564,
0x0000C583, 0x0000FFFE, 0x0000C593, 0x0000C529, 0x00000003, 0x0000C531, 0x0000C52A, 0x00000530,
0x0000C57F, 0x00000003, 0x0000C575, 0x0000C52A, 0x0000C584, 0x0000C587, 0x00000003, 0x0000C581,
0x0000C52A, 0x0000C577, 0x00000003, 0x00000528, 0x00000005, 0x0000C545, 0x0000C58A, 0x0000C578,
0x00000555, 0x0000C583, 0x0000C58A, 0x0000C58F, 0x00000005, 0x00000003, 0x0000C565, 0x0000C529,
0x0000C54A, 0x0000C534, 0x0000C543, 0x0000C529, 0x00000003, 0x0000C57A, 0x0000C52E, 0x0000C573,
0x0000C589, 0x00000003, 0x00000011, 0x0000C52A, 0x0000C588, 0x0000C584, 0x0000C57F, 0x00000003,
0x0000C546, 0x0000C53F, 0x0000C529, 0x0000C589, 0x00000003, 0x0000C57A, 0x0000C578, 0x0000C57B,
0x00000003, 0x0000C52A, 0x0000C584, 0x0000C590, 0x0000C568, 0x0000C57F, 0x00000003, 0x0000C52A,
0x0000C580, 0x0000C573, 0x0000C549, 0x00000003, 0x0000C58E, 0x0000C560, 0x0000C568, 0x00000554,
0x0000C533, 0x00000003, 0x0000C581, 0x0000C51F, 0x00000003, 0x0000C546, 0x0000C568, 0x0000C52D,
0x00000003, 0x0000C58B, 0x0000C54A, 0x0000C543, 0x0000FFFE, 0x0000C593, 0x0000C529, 0x00000003,
0x0000C56D, 0x0000C549, 0x0000C52A, 0x0000C540, 0x0000C580, 0x0000C57B, 0x0000C529, 0x0000C589,
0x00000003, 0x0000C56D, 0x0000C54A, 0x0000C53F, 0x0000FFFE, 0x0000C593, 0x0000C529, 0x00000003,
0x0000C582, 0x0000C58F, 0x0000C54C, 0x0000C544, 0x0000C534, 0x0000C52D, 0x00000003, 0x0000C57D,
0x0000C58A, 0x0000C574, 0x0000C533, 0x0000C589, 0x00000003, 0x00000528, 0x0000C57D, 0x0000C52A,
0x0000C573, 0x0000C549, 0x0000FFFE, 0x0000C593, 0x0000C529, 0x00000003, 0x0000C566, 0x0000C57F,
0x00000003, 0x0000C55E, 0x0000C574, 0x0000C56F, 0x00000003, 0x0000C52C, 0x0000C590, 0x0000C54F,
0x0000C529, 0x0000C58A, 0x0000C540, 0x0000C57B, 0x0000C529, 0x00000003, 0x0000C57A, 0x0000C57F,
0x0000C52A, 0x0000C568, 0x0000C534, 0x0000C533, 0x00000003, 0x00000528, 0x0000C52A, 0x00000550,
0x0000C54F, 0x0000C52A, 0x0000C54F, 0x0000C51F
</result-glyphs>
<result-indices>
0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4,
0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC,
0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4,
0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC,
0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4,
0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC,
0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4,
0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC,
0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4,
0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC,
0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4,
0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C,
0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094,
0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C,
0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084,
0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C,
0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074,
0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C,
0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064,
0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C,
0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054,
0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C,
0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044,
0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C,
0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034,
0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C,
0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C,
0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014,
0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C,
0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004,
0x00000003, 0x00000002, 0x00000001, 0x00000000
</result-indices>
<result-positions>
0.000000, 0.000000, 4.007813, 0.000000, 8.226563, 0.000000, 12.679688, 0.000000,
18.679688, 0.000000, 23.132813, 0.000000, 31.289063, 0.000000, 34.312500, 0.000000,
36.375000, 0.000000, 41.062500, 0.000000, 50.296875, 0.000000, 54.750000, 0.000000,
56.859375, 0.000000, 62.367188, 0.000000, 66.632813, 0.000000, 69.656250, 0.000000,
71.718750, 0.000000, 76.406250, 0.000000, 81.421875, 0.000000, 85.664063, 0.000000,
89.929688, 0.000000, 95.742188, 0.000000, 100.429688, 0.000000, 108.796875, 0.000000,
112.171875, 0.000000, 115.734375, 0.000000, 120.421875, 0.000000, 128.765625, 0.000000,
134.765625, 0.000000, 139.007813, 0.000000, 144.515625, 0.000000, 148.734375, 0.000000,
153.421875, 0.000000, 157.359375, 0.000000, 163.171875, 0.000000, 165.234375, 0.000000,
171.234375, 0.000000, 175.921875, 0.000000, 180.375000, 0.000000, 184.617188, 0.000000,
188.085938, 0.000000, 195.117188, 0.000000, 199.312500, 0.000000, 204.000000, 0.000000,
208.007813, 0.000000, 210.117188, 0.000000, 217.054688, 0.000000, 220.429688, 0.000000,
225.117188, 0.000000, 229.054688, 0.000000, 234.867188, 0.000000, 240.867188, 0.000000,
245.085938, 0.000000, 249.773438, 0.000000, 253.781250, 0.000000, 256.804688, 0.000000,
262.804688, 0.000000, 267.492188, 0.000000, 271.007813, 0.000000, 280.242188, 0.000000,
284.695313, 0.000000, 286.804688, 0.000000, 292.312500, 0.000000, 296.578125, 0.000000,
299.953125, 0.000000, 302.976563, 0.000000, 307.664063, 0.000000, 311.671875, 0.000000,
313.781250, 0.000000, 317.882813, 0.000000, 322.335938, 0.000000, 322.335938, 0.000000,
328.500000, 0.000000, 330.562500, 0.000000, 335.250000, 0.000000, 339.140625, 0.000000,
343.078125, 0.000000, 348.984375, 0.000000, 353.671875, 0.000000, 366.445313, 0.000000,
370.687500, 0.000000, 378.843750, 0.000000, 384.351563, 0.000000, 388.546875, 0.000000,
394.546875, 0.000000, 399.234375, 0.000000, 403.687500, 0.000000, 407.929688, 0.000000,
411.398438, 0.000000, 418.429688, 0.000000, 422.671875, 0.000000, 426.046875, 0.000000,
429.070313, 0.000000, 433.757813, 0.000000, 437.765625, 0.000000, 442.031250, 0.000000,
448.968750, 0.000000, 452.343750, 0.000000, 452.343750, 0.000000, 458.507813, 0.000000,
460.570313, 0.000000, 465.257813, 0.000000, 474.492188, 0.000000, 476.601563, 0.000000,
484.968750, 0.000000, 489.234375, 0.000000, 493.921875, 0.000000, 501.562500, 0.000000,
503.671875, 0.000000, 507.890625, 0.000000, 513.796875, 0.000000, 518.484375, 0.000000,
525.796875, 0.000000, 527.906250, 0.000000, 533.578125, 0.000000, 538.265625, 0.000000,
541.781250, 0.000000, 547.171875, 0.000000, 550.710938, 0.000000, 556.710938, 0.000000,
564.492188, 0.000000, 564.492188, 0.000000, 567.867188, 0.000000, 573.867188, 0.000000,
578.085938, 0.000000, 583.476563, 0.000000, 588.164063, 0.000000, 593.976563, 0.000000,
596.039063, 0.000000, 600.492188, 0.000000, 604.734375, 0.000000, 610.546875, 0.000000,
612.609375, 0.000000, 617.296875, 0.000000, 623.695313, 0.000000, 627.937500, 0.000000,
632.039063, 0.000000, 638.039063, 0.000000, 642.726563, 0.000000, 646.054688, 0.000000,
648.164063, 0.000000, 651.914063, 0.000000, 656.132813, 0.000000, 660.398438, 0.000000,
665.085938, 0.000000, 669.023438, 0.000000, 674.835938, 0.000000, 676.898438, 0.000000,
682.898438, 0.000000, 687.585938, 0.000000, 693.984375, 0.000000, 701.765625, 0.000000,
704.789063, 0.000000, 709.476563, 0.000000, 711.585938, 0.000000, 715.804688, 0.000000,
720.046875, 0.000000, 723.515625, 0.000000, 727.781250, 0.000000, 732.468750, 0.000000,
734.578125, 0.000000, 738.843750, 0.000000, 742.945313, 0.000000, 747.398438, 0.000000,
752.085938, 0.000000, 760.453125, 0.000000, 767.390625, 0.000000, 770.859375, 0.000000,
770.859375, 0.000000, 775.054688, 0.000000, 779.742188, 0.000000, 787.054688, 0.000000,
789.398438, 0.000000, 794.085938, 0.000000, 798.023438, 0.000000, 801.492188, 0.000000,
804.937500, 0.000000, 809.625000, 0.000000, 817.968750, 0.000000, 822.421875, 0.000000,
828.234375, 0.000000, 828.234375, 0.000000, 834.398438, 0.000000, 836.460938, 0.000000,
841.148438, 0.000000, 850.382813, 0.000000, 854.835938, 0.000000, 856.945313, 0.000000,
862.453125, 0.000000, 866.718750, 0.000000, 869.742188, 0.000000, 871.804688, 0.000000,
877.804688, 0.000000, 882.492188, 0.000000, 891.726563, 0.000000, 896.179688, 0.000000,
901.992188, 0.000000, 901.992188, 0.000000, 908.156250, 0.000000, 910.218750, 0.000000,
914.906250, 0.000000, 922.382813, 0.000000, 926.601563, 0.000000, 931.054688, 0.000000,
936.562500, 0.000000, 940.804688, 0.000000, 944.250000, 0.000000, 948.937500, 0.000000,
952.945313, 0.000000, 958.945313, 0.000000, 962.414063, 0.000000, 966.609375, 0.000000,
972.609375, 0.000000, 977.296875, 0.000000, 980.812500, 0.000000, 984.820313, 0.000000,
986.929688, 0.000000, 991.031250, 0.000000, 995.484375, 0.000000, 995.484375, 0.000000,
1001.648438, 0.000000, 1003.710938, 0.000000, 1008.398438, 0.000000, 1013.414063, 0.000000,
1017.679688, 0.000000, 1022.367188, 0.000000, 1030.312500, 0.000000, 1033.781250, 0.000000,
1037.882813, 0.000000, 1042.570313, 0.000000, 1051.921875, 0.000000, 1056.164063, 0.000000,
1062.984375, 0.000000, 1065.046875, 0.000000, 1071.046875, 0.000000, 1076.554688, 0.000000,
1079.578125, 0.000000, 1081.640625, 0.000000, 1086.328125, 0.000000, 1092.726563, 0.000000,
1096.992188, 0.000000, 1099.101563, 0.000000, 1102.570313, 0.000000, 1106.812500, 0.000000,
1111.007813, 0.000000, 1115.695313, 0.000000, 1119.210938, 0.000000, 1121.320313, 0.000000,
1121.320313, 0.000000, 1128.140625, 0.000000, 1130.250000, 0.000000, 1137.070313, 0.000000,
1139.414063, 0.000000
</result-positions>
</test-case>
<test-case id="Unicode Arabic" script="arab">
<test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D"/>
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
<result-glyphs>
0x00000872, 0x000008D1, 0x000003F9, 0x0000040B, 0x0000088C, 0x0000089E, 0x000008BD, 0x000003EF,
0x00000003, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF,
0x00000003, 0x000008A8, 0x000008D2, 0x000008C2, 0x0000087D, 0x00000003, 0x000008CE, 0x000008BE,
0x000008A9, 0x00000003, 0x0000040D, 0x000008CC, 0x00000876, 0x00000882, 0x000008D1, 0x00000003,
0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2,
0x00000896, 0x00000875, 0x00000003, 0x00000408, 0x0000086C, 0x000008A6, 0x000008C5, 0x00000003,
0x00000888, 0x0000087D, 0x000008CC, 0x000008D1, 0x00000003, 0x000008C0, 0x000008BD, 0x0000040B,
0x00000003, 0x000003E6, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BE,
0x000008BD, 0x00000003, 0x00000408, 0x0000086C, 0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5,
0x000003EF, 0x00000003, 0x0000040A, 0x0000088A, 0x000008C9, 0x00000003, 0x00000898, 0x000008D2,
0x0000089A, 0x00000886, 0x00000875, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2,
0x00000896, 0x00000876, 0x000008BE, 0x000008BD, 0x00000003, 0x00000872, 0x000008C2, 0x000008A6,
0x000008C5, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000003F2, 0x0000086C, 0x0000086A,
0x000008C1, 0x00000003, 0x00000406, 0x0000086C, 0x000008C6, 0x000008C9, 0x00000003, 0x00000409,
0x0000086C, 0x000008B9, 0x00000003, 0x000003E6, 0x00000005, 0x000003F7, 0x000008CC, 0x000008BA,
0x00000413, 0x000008C5, 0x000008CC, 0x000008D1, 0x00000005, 0x00000003, 0x00000401, 0x000003EF,
0x0000088C, 0x00000876, 0x00000885, 0x000003EF, 0x00000003, 0x000008BC, 0x00000870, 0x000008B5,
0x0000040B, 0x00000003, 0x00000011, 0x0000086C, 0x000008CA, 0x000008C6, 0x000008C1, 0x00000003,
0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x000008BC, 0x000008BA, 0x000008BD,
0x00000003, 0x0000086C, 0x000008C6, 0x000008D2, 0x000008AA, 0x000008C1, 0x00000003, 0x0000086C,
0x000008C2, 0x000008B5, 0x000003F9, 0x00000003, 0x000008D0, 0x000008A2, 0x000008AA, 0x00000412,
0x00000875, 0x00000003, 0x00000409, 0x000003EB, 0x00000003, 0x00000888, 0x000008AA, 0x0000086F,
0x00000003, 0x0000040C, 0x0000088C, 0x00000885, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003,
0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF, 0x0000040B,
0x00000003, 0x00000404, 0x0000088C, 0x00000881, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003,
0x000008C4, 0x000008D1, 0x0000088E, 0x00000886, 0x00000876, 0x0000086F, 0x00000003, 0x00000408,
0x000008CC, 0x000008B6, 0x00000875, 0x0000040B, 0x00000003, 0x000003E6, 0x00000408, 0x0000086C,
0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000008A8, 0x000008C1,
0x00000003, 0x000008A0, 0x000008B6, 0x000008B1, 0x00000003, 0x0000086E, 0x000008D2, 0x00000891,
0x000003EF, 0x000008CC, 0x00000882, 0x000008BD, 0x000003EF, 0x00000003, 0x000008BC, 0x000008C1,
0x0000086C, 0x000008AA, 0x00000876, 0x00000875, 0x00000003, 0x000003E6, 0x0000086C, 0x0000040E,
0x00000891, 0x0000086C, 0x00000891, 0x000003EB
</result-glyphs>
<result-indices>
0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4,
0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC,
0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4,
0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC,
0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4,
0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC,
0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4,
0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC,
0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4,
0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC,
0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4,
0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C,
0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094,
0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C,
0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084,
0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C,
0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074,
0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C,
0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064,
0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C,
0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054,
0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C,
0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044,
0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C,
0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034,
0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C,
0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C,
0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014,
0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C,
0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004,
0x00000003, 0x00000002, 0x00000001, 0x00000000
</result-indices>
<result-positions>
0.000000, 0.000000, 6.316406, 0.000000, 10.382813, 0.000000, 15.492188, 0.000000,
21.035156, 0.000000, 27.058594, 0.000000, 39.527344, 0.000000, 43.792969, 0.000000,
47.408203, 0.000000, 51.205078, 0.000000, 66.216797, 0.000000, 71.326172, 0.000000,
74.695313, 0.000000, 83.367188, 0.000000, 90.826172, 0.000000, 95.091797, 0.000000,
98.707031, 0.000000, 102.503906, 0.000000, 109.962891, 0.000000, 114.949219, 0.000000,
122.408203, 0.000000, 130.687500, 0.000000, 134.484375, 0.000000, 145.787109, 0.000000,
150.773438, 0.000000, 156.884766, 0.000000, 160.681641, 0.000000, 172.277344, 0.000000,
177.919922, 0.000000, 182.906250, 0.000000, 191.578125, 0.000000, 195.644531, 0.000000,
199.441406, 0.000000, 206.507813, 0.000000, 214.787109, 0.000000, 218.402344, 0.000000,
223.945313, 0.000000, 227.742188, 0.000000, 233.765625, 0.000000, 238.751953, 0.000000,
245.185547, 0.000000, 257.982422, 0.000000, 262.048828, 0.000000, 265.845703, 0.000000,
272.654297, 0.000000, 276.023438, 0.000000, 285.240234, 0.000000, 289.306641, 0.000000,
293.103516, 0.000000, 300.169922, 0.000000, 308.449219, 0.000000, 314.091797, 0.000000,
318.158203, 0.000000, 321.955078, 0.000000, 329.572266, 0.000000, 333.837891, 0.000000,
339.380859, 0.000000, 343.177734, 0.000000, 346.974609, 0.000000, 361.986328, 0.000000,
367.095703, 0.000000, 370.464844, 0.000000, 379.136719, 0.000000, 386.595703, 0.000000,
391.582031, 0.000000, 395.847656, 0.000000, 399.644531, 0.000000, 406.453125, 0.000000,
409.822266, 0.000000, 415.523438, 0.000000, 420.632813, 0.000000, 420.632813, 0.000000,
427.441406, 0.000000, 431.056641, 0.000000, 434.853516, 0.000000, 441.357422, 0.000000,
448.423828, 0.000000, 455.912109, 0.000000, 459.708984, 0.000000, 479.255859, 0.000000,
484.242188, 0.000000, 496.710938, 0.000000, 505.382813, 0.000000, 509.449219, 0.000000,
514.992188, 0.000000, 518.789063, 0.000000, 524.812500, 0.000000, 529.798828, 0.000000,
536.232422, 0.000000, 549.029297, 0.000000, 554.015625, 0.000000, 559.001953, 0.000000,
563.267578, 0.000000, 567.064453, 0.000000, 573.380859, 0.000000, 580.839844, 0.000000,
590.056641, 0.000000, 594.123047, 0.000000, 594.123047, 0.000000, 600.931641, 0.000000,
604.546875, 0.000000, 608.343750, 0.000000, 620.636719, 0.000000, 624.005859, 0.000000,
628.992188, 0.000000, 635.830078, 0.000000, 639.626953, 0.000000, 653.361328, 0.000000,
656.730469, 0.000000, 661.716797, 0.000000, 669.205078, 0.000000, 673.001953, 0.000000,
683.777344, 0.000000, 687.146484, 0.000000, 692.660156, 0.000000, 696.457031, 0.000000,
700.253906, 0.000000, 704.736328, 0.000000, 711.105469, 0.000000, 716.748047, 0.000000,
722.994141, 0.000000, 722.994141, 0.000000, 727.060547, 0.000000, 732.703125, 0.000000,
736.769531, 0.000000, 741.251953, 0.000000, 745.048828, 0.000000, 752.507813, 0.000000,
756.123047, 0.000000, 762.146484, 0.000000, 767.132813, 0.000000, 775.412109, 0.000000,
779.027344, 0.000000, 782.824219, 0.000000, 794.203125, 0.000000, 799.189453, 0.000000,
804.890625, 0.000000, 810.433594, 0.000000, 814.230469, 0.000000, 818.027344, 0.000000,
821.396484, 0.000000, 828.128906, 0.000000, 833.115234, 0.000000, 839.953125, 0.000000,
843.750000, 0.000000, 850.816406, 0.000000, 859.095703, 0.000000, 862.710938, 0.000000,
868.253906, 0.000000, 872.050781, 0.000000, 883.429688, 0.000000, 889.675781, 0.000000,
893.941406, 0.000000, 897.738281, 0.000000, 901.107422, 0.000000, 906.093750, 0.000000,
911.080078, 0.000000, 917.800781, 0.000000, 924.638672, 0.000000, 928.435547, 0.000000,
931.804688, 0.000000, 939.263672, 0.000000, 944.964844, 0.000000, 950.074219, 0.000000,
953.871094, 0.000000, 965.173828, 0.000000, 974.390625, 0.000000, 981.111328, 0.000000,
981.111328, 0.000000, 985.177734, 0.000000, 988.974609, 0.000000, 999.750000, 0.000000,
1003.365234, 0.000000, 1007.162109, 0.000000, 1014.228516, 0.000000, 1020.949219, 0.000000,
1025.015625, 0.000000, 1028.812500, 0.000000, 1040.408203, 0.000000, 1046.431641, 0.000000,
1054.710938, 0.000000, 1054.710938, 0.000000, 1061.519531, 0.000000, 1065.134766, 0.000000,
1068.931641, 0.000000, 1083.943359, 0.000000, 1089.052734, 0.000000, 1092.421875, 0.000000,
1101.093750, 0.000000, 1108.552734, 0.000000, 1112.818359, 0.000000, 1116.433594, 0.000000,
1121.976563, 0.000000, 1125.773438, 0.000000, 1140.785156, 0.000000, 1146.808594, 0.000000,
1155.087891, 0.000000, 1155.087891, 0.000000, 1161.896484, 0.000000, 1165.511719, 0.000000,
1169.308594, 0.000000, 1180.541016, 0.000000, 1184.607422, 0.000000, 1190.630859, 0.000000,
1199.302734, 0.000000, 1204.289063, 0.000000, 1208.355469, 0.000000, 1212.152344, 0.000000,
1218.960938, 0.000000, 1224.603516, 0.000000, 1231.037109, 0.000000, 1235.103516, 0.000000,
1240.646484, 0.000000, 1244.443359, 0.000000, 1248.240234, 0.000000, 1255.048828, 0.000000,
1258.417969, 0.000000, 1264.119141, 0.000000, 1269.228516, 0.000000, 1269.228516, 0.000000,
1276.037109, 0.000000, 1279.652344, 0.000000, 1283.449219, 0.000000, 1290.908203, 0.000000,
1297.746094, 0.000000, 1301.542969, 0.000000, 1311.427734, 0.000000, 1317.861328, 0.000000,
1323.562500, 0.000000, 1327.359375, 0.000000, 1341.492188, 0.000000, 1346.478516, 0.000000,
1357.904297, 0.000000, 1361.519531, 0.000000, 1367.162109, 0.000000, 1375.833984, 0.000000,
1380.099609, 0.000000, 1383.714844, 0.000000, 1387.511719, 0.000000, 1398.890625, 0.000000,
1405.728516, 0.000000, 1409.097656, 0.000000, 1415.818359, 0.000000, 1420.804688, 0.000000,
1424.871094, 0.000000, 1428.667969, 0.000000, 1432.464844, 0.000000, 1435.833984, 0.000000,
1435.833984, 0.000000, 1447.259766, 0.000000, 1450.628906, 0.000000, 1462.054688, 0.000000,
1465.669922, 0.000000
</result-positions>
</test-case>
<test-case id="Thai" script="thai">
<test-font name="angsd___.ttf" version="Version 2.1 - July 1995" checksum="0x49B67200"/>
<test-text>บทที่๑พายุไซโคลนโดโรธีอาศัยอยู่ท่ามกลางทุ่งใหญ่ในแคนซัสกับลุงเฮนรีชาวไร่และป้าเอ็มภรรยาชาวไร่บ้านของพวกเขาหลังเล็กเพราะไม้สร้างบ้านต้องขนมาด้วยเกวียนเป็นระยะทางหลายไมล์</test-text>
<result-glyphs>
0x000000F3, 0x000000F0, 0x000000F0, 0x0000010E, 0x0000011D, 0x00000126, 0x000000F7, 0x0000010B,
0x000000FB, 0x00000111, 0x00000119, 0x000000E4, 0x00000117, 0x000000DD, 0x000000FE, 0x000000F2,
0x00000117, 0x000000ED, 0x00000117, 0x000000FC, 0x000000F1, 0x0000010E, 0x00000106, 0x0000010B,
0x00000101, 0x0000010A, 0x000000FB, 0x00000106, 0x000000FB, 0x00000112, 0x0000013B, 0x000000F0,
0x0000013B, 0x0000010B, 0x000000FA, 0x000000DA, 0x000000FE, 0x0000010B, 0x000000E0, 0x000000F0,
0x00000111, 0x0000013B, 0x000000E0, 0x00000118, 0x00000104, 0x000000E6, 0x0000013B, 0x00000118,
0x000000F2, 0x00000116, 0x000000DD, 0x000000F2, 0x000000E4, 0x0000010A, 0x00000103, 0x000000DA,
0x0000010A, 0x000000F3, 0x000000FE, 0x00000111, 0x000000E0, 0x00000115, 0x00000107, 0x000000F2,
0x000000FC, 0x0000010E, 0x000000E3, 0x0000010B, 0x00000100, 0x00000119, 0x000000FC, 0x0000013B,
0x00000116, 0x000000FE, 0x00000109, 0x000000F4, 0x00000137, 0x0000010B, 0x00000115, 0x00000106,
0x0000011C, 0x000000FA, 0x000000F9, 0x000000FC, 0x000000FC, 0x000000FB, 0x0000010B, 0x000000E3,
0x0000010B, 0x00000100, 0x00000119, 0x000000FC, 0x0000013B, 0x000000F3, 0x0000013C, 0x0000010B,
0x000000F2, 0x000000DB, 0x00000106, 0x000000E0, 0x000000F7, 0x00000100, 0x000000DA, 0x00000115,
0x000000DB, 0x0000010B, 0x00000104, 0x000000FE, 0x0000010A, 0x000000E0, 0x00000115, 0x000000FE,
0x0000011C, 0x000000DA, 0x00000115, 0x000000F7, 0x000000FC, 0x0000010B, 0x00000109, 0x00000119,
0x000000FA, 0x0000013C, 0x00000103, 0x000000FC, 0x0000013C, 0x0000010B, 0x000000E0, 0x000000F3,
0x0000013C, 0x0000010B, 0x000000F2, 0x000000EE, 0x0000013C, 0x00000106, 0x000000E0, 0x000000DB,
0x000000F2, 0x000000FA, 0x0000010B, 0x000000ED, 0x0000013C, 0x00000100, 0x000000FB, 0x00000115,
0x000000DA, 0x00000100, 0x0000010E, 0x000000FB, 0x000000F2, 0x00000115, 0x000000F4, 0x00000143,
0x000000F2, 0x000000FC, 0x00000109, 0x000000FB, 0x00000109, 0x000000F0, 0x0000010B, 0x000000E0,
0x00000104, 0x000000FE, 0x0000010B, 0x000000FB, 0x00000119, 0x000000FA, 0x000000FE, 0x0000013F
</result-glyphs>
<result-indices>
0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007,
0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F,
0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017,
0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F,
0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027,
0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F,
0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037,
0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003C, 0x0000003D, 0x0000003E, 0x0000003F,
0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047,
0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F,
0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057,
0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F,
0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067,
0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F,
0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077,
0x00000078, 0x00000079, 0x0000007A, 0x0000007B, 0x0000007C, 0x0000007D, 0x0000007E, 0x0000007F,
0x00000080, 0x00000081, 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x00000087,
0x00000088, 0x00000089, 0x0000008A, 0x0000008B, 0x0000008C, 0x0000008D, 0x0000008E, 0x0000008F,
0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x00000094, 0x00000095, 0x00000096, 0x00000097,
0x00000098, 0x00000099, 0x0000009A, 0x0000009B, 0x0000009C, 0x0000009D, 0x0000009E, 0x0000009F,
0x000000A0, 0x000000A1, 0x000000A2, 0x000000A3, 0x000000A4, 0x000000A5, 0x000000A6, 0x000000A7
</result-indices>
<result-positions>
0.000000, 0.000000, 5.399414, 0.000000, 10.798828, 0.000000, 16.198242, 0.000000,
16.198242, 0.000000, 16.198242, 0.000000, 21.046875, 0.000000, 26.616211, 0.000000,
30.035156, 0.000000, 34.151367, 0.000000, 34.151367, 0.000000, 38.279297, 0.000000,
43.558594, 0.000000, 47.663086, 0.000000, 52.438477, 0.000000, 57.178711, 0.000000,
62.698242, 0.000000, 66.802734, 0.000000, 71.601563, 0.000000, 75.706055, 0.000000,
79.810547, 0.000000, 84.369141, 0.000000, 84.369141, 0.000000, 89.097656, 0.000000,
92.516602, 0.000000, 97.195313, 0.000000, 97.195313, 0.000000, 101.311523, 0.000000,
106.040039, 0.000000, 110.156250, 0.000000, 110.156250, 0.000000, 110.156250, 0.000000,
115.555664, 0.000000, 115.555664, 0.000000, 118.974609, 0.000000, 124.013672, 0.000000,
128.765625, 0.000000, 133.505859, 0.000000, 136.924805, 0.000000, 140.704102, 0.000000,
146.103516, 0.000000, 146.103516, 0.000000, 146.103516, 0.000000, 149.882813, 0.000000,
153.553711, 0.000000, 159.158203, 0.000000, 165.421875, 0.000000, 165.421875, 0.000000,
169.092773, 0.000000, 174.612305, 0.000000, 179.135742, 0.000000, 183.911133, 0.000000,
189.430664, 0.000000, 194.709961, 0.000000, 194.709961, 0.000000, 199.989258, 0.000000,
204.741211, 0.000000, 204.741211, 0.000000, 210.140625, 0.000000, 214.880859, 0.000000,
214.880859, 0.000000, 218.660156, 0.000000, 220.675781, 0.000000, 225.128906, 0.000000,
230.648438, 0.000000, 234.752930, 0.000000, 234.752930, 0.000000, 239.613281, 0.000000,
243.032227, 0.000000, 247.280273, 0.000000, 251.408203, 0.000000, 255.512695, 0.000000,
255.512695, 0.000000, 260.036133, 0.000000, 264.776367, 0.000000, 269.071289, 0.000000,
274.470703, 0.000000, 274.470703, 0.000000, 277.889648, 0.000000, 279.905273, 0.000000,
284.633789, 0.000000, 284.633789, 0.000000, 289.672852, 0.000000, 294.641602, 0.000000,
298.746094, 0.000000, 302.850586, 0.000000, 306.966797, 0.000000, 310.385742, 0.000000,
315.246094, 0.000000, 318.665039, 0.000000, 322.913086, 0.000000, 327.041016, 0.000000,
331.145508, 0.000000, 331.145508, 0.000000, 336.544922, 0.000000, 336.544922, 0.000000,
339.963867, 0.000000, 345.483398, 0.000000, 350.258789, 0.000000, 354.987305, 0.000000,
358.766602, 0.000000, 364.335938, 0.000000, 368.583984, 0.000000, 373.335938, 0.000000,
375.351563, 0.000000, 380.126953, 0.000000, 383.545898, 0.000000, 389.150391, 0.000000,
393.890625, 0.000000, 393.890625, 0.000000, 397.669922, 0.000000, 399.685547, 0.000000,
404.425781, 0.000000, 404.425781, 0.000000, 409.177734, 0.000000, 411.193359, 0.000000,
416.762695, 0.000000, 420.867188, 0.000000, 424.286133, 0.000000, 428.581055, 0.000000,
432.708984, 0.000000, 437.748047, 0.000000, 437.748047, 0.000000, 443.027344, 0.000000,
447.131836, 0.000000, 447.131836, 0.000000, 450.550781, 0.000000, 454.330078, 0.000000,
459.729492, 0.000000, 459.729492, 0.000000, 463.148438, 0.000000, 468.667969, 0.000000,
473.478516, 0.000000, 473.478516, 0.000000, 478.207031, 0.000000, 481.986328, 0.000000,
486.761719, 0.000000, 492.281250, 0.000000, 497.320313, 0.000000, 500.739258, 0.000000,
505.538086, 0.000000, 505.538086, 0.000000, 509.786133, 0.000000, 513.902344, 0.000000,
515.917969, 0.000000, 520.669922, 0.000000, 524.917969, 0.000000, 524.917969, 0.000000,
529.034180, 0.000000, 534.553711, 0.000000, 536.569336, 0.000000, 541.968750, 0.000000,
541.968750, 0.000000, 547.488281, 0.000000, 551.592773, 0.000000, 555.887695, 0.000000,
560.003906, 0.000000, 564.298828, 0.000000, 569.698242, 0.000000, 573.117188, 0.000000,
576.896484, 0.000000, 582.500977, 0.000000, 587.241211, 0.000000, 590.660156, 0.000000,
594.776367, 0.000000, 598.904297, 0.000000, 603.943359, 0.000000, 608.683594, 0.000000,
608.683594, 0.000000
</result-positions>
</test-case>
<test-case id="Arabic Simple" script="arab">
<test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
<result-glyphs>
0x0000FE94, 0x0000FEF3, 0x00000631, 0x00000648, 0x0000FFFE, 0x0000FD2C, 0x0000FEDF, 0x00000627,
0x00000020, 0x00000641, 0x00000631, 0x0000FE8E, 0x0000FFFE, 0x0000FFFE, 0x0000FD88, 0x00000627,
0x00000020, 0x0000FECA, 0x0000FEF4, 0x0000FFFE, 0x0000FCA8, 0x00000020, 0x0000FFFE, 0x0000FC86,
0x0000FECB, 0x00000020, 0x0000064A, 0x0000FEEE, 0x0000FE98, 0x0000FFFE, 0x0000FCDB, 0x00000020,
0x0000FEAA, 0x0000FEA3, 0x00000627, 0x00000648, 0x00000020, 0x0000FFFE, 0x0000FC91, 0x0000FED4,
0x0000FEB8, 0x0000FE97, 0x00000020, 0x00000645, 0x0000FE8E, 0x0000FEC8, 0x0000FEE7, 0x00000020,
0x0000FEAA, 0x0000FE9F, 0x0000FEEE, 0x0000FEF3, 0x00000020, 0x0000FFFE, 0x0000FC42, 0x00000648,
0x00000020, 0x0000060C, 0x00000641, 0x00000631, 0x0000FE8E, 0x0000FEA4, 0x0000FFFE, 0x0000FCED,
0x0000FEDF, 0x00000020, 0x00000645, 0x0000FE8E, 0x0000FED7, 0x00000631, 0x0000FFFE, 0x0000FEF7,
0x00000627, 0x00000020, 0x00000647, 0x0000FEAC, 0x0000FEEB, 0x00000020, 0x0000FEBA, 0x0000FEF4,
0x0000FEBC, 0x0000FFFE, 0x0000FCA3, 0x00000648, 0x00000020, 0x0000FFFE, 0x0000FC91, 0x0000FED4,
0x0000FEB8, 0x0000FE98, 0x0000FEE0, 0x0000FEDF, 0x00000020, 0x0000FE94, 0x0000FFFE, 0x0000FD3B,
0x0000FEE7, 0x0000FFFE, 0x0000FEF7, 0x00000627, 0x00000020, 0x0000062A, 0x0000FFFE, 0x0000FBEB,
0x0000FEE3, 0x00000020, 0x00000643, 0x0000FE8E, 0x0000FEE8, 0x0000FEEB, 0x00000020, 0x00000646,
0x0000FFFE, 0x0000FC37, 0x00000020, 0x0000060C, 0x00000022, 0x0000062F, 0x0000FEEE, 0x0000FEDC,
0x00000650, 0x0000FEE7, 0x0000FEEE, 0x0000FEF3, 0x00000022, 0x00000020, 0x00000639, 0x00000627,
0x0000FFFE, 0x0000FC70, 0x0000FEA7, 0x00000627, 0x00000020, 0x0000FEDE, 0x0000FE92, 0x0000FED7,
0x00000648, 0x00000020, 0x0000002E, 0x0000FE8E, 0x0000FFFE, 0x0000FCEF, 0x0000FEE3, 0x00000020,
0x0000FEAA, 0x0000FEA3, 0x00000627, 0x00000648, 0x00000020, 0x0000FFFE, 0x0000FC81, 0x0000FEDF,
0x00000020, 0x0000FE8E, 0x0000FEE8, 0x0000FEF4, 0x0000FECC, 0x0000FEE3, 0x00000020, 0x0000FE8E,
0x0000FFFE, 0x0000FCC3, 0x00000631, 0x00000020, 0x0000FFFE, 0x0000FD12, 0x0000FECC, 0x0000064F,
0x0000FE97, 0x00000020, 0x00000646, 0x00000623, 0x00000020, 0x0000FEAA, 0x0000FECC, 0x0000FE91,
0x00000020, 0x00000649, 0x0000FEAE, 0x0000FEA7, 0x0000FFFE, 0x0000FEF7, 0x00000627, 0x00000020,
0x00000641, 0x00000631, 0x0000FE8E, 0x0000FFFE, 0x0000FFFE, 0x0000FD88, 0x00000627, 0x00000648,
0x00000020, 0x00000641, 0x0000FEAE, 0x0000FEA3, 0x0000FFFE, 0x0000FEF7, 0x00000627, 0x00000020,
0x0000FEE6, 0x0000FEF3, 0x0000FEB0, 0x0000FEA8, 0x0000FE98, 0x0000FE91, 0x00000020, 0x00000645,
0x0000FEEE, 0x0000FED8, 0x0000FE97, 0x00000648, 0x00000020, 0x0000060C, 0x00000645, 0x0000FE8E,
0x0000FED7, 0x00000631, 0x0000FFFE, 0x0000FEF7, 0x00000627, 0x00000020, 0x0000FECA, 0x0000FEE3,
0x00000020, 0x0000FEC2, 0x0000FED8, 0x0000FED3, 0x00000020, 0x0000FE90, 0x0000FEF4, 0x0000FEB3,
0x00000627, 0x0000FEEE, 0x0000FFFE, 0x0000FCCA, 0x00000627, 0x00000020, 0x0000FEDE, 0x0000FEE3,
0x0000FE8E, 0x0000FECC, 0x0000FE98, 0x0000FE97, 0x00000020, 0x0000060C, 0x0000FE8E, 0x0000064B,
0x0000FEB3, 0x0000FE8E, 0x0000FEB3, 0x00000623
</result-glyphs>
<result-indices>
0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4,
0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC,
0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4,
0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC,
0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4,
0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC,
0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4,
0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC,
0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4,
0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC,
0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4,
0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C,
0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094,
0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C,
0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084,
0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C,
0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074,
0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C,
0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064,
0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C,
0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054,
0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C,
0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044,
0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C,
0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034,
0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C,
0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C,
0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014,
0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C,
0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004,
0x00000003, 0x00000002, 0x00000001, 0x00000000
</result-indices>
<result-positions>
0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000,
48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000,
96.000000, 0.000000, 108.000000, 0.000000, 120.000000, 0.000000, 132.000000, 0.000000,
144.000000, 0.000000, 156.000000, 0.000000, 168.000000, 0.000000, 180.000000, 0.000000,
192.000000, 0.000000, 204.000000, 0.000000, 216.000000, 0.000000, 228.000000, 0.000000,
240.000000, 0.000000, 252.000000, 0.000000, 264.000000, 0.000000, 276.000000, 0.000000,
288.000000, 0.000000, 300.000000, 0.000000, 312.000000, 0.000000, 324.000000, 0.000000,
336.000000, 0.000000, 348.000000, 0.000000, 360.000000, 0.000000, 372.000000, 0.000000,
384.000000, 0.000000, 396.000000, 0.000000, 408.000000, 0.000000, 420.000000, 0.000000,
432.000000, 0.000000, 444.000000, 0.000000, 456.000000, 0.000000, 468.000000, 0.000000,
480.000000, 0.000000, 492.000000, 0.000000, 504.000000, 0.000000, 516.000000, 0.000000,
528.000000, 0.000000, 540.000000, 0.000000, 552.000000, 0.000000, 564.000000, 0.000000,
576.000000, 0.000000, 588.000000, 0.000000, 600.000000, 0.000000, 612.000000, 0.000000,
624.000000, 0.000000, 636.000000, 0.000000, 648.000000, 0.000000, 660.000000, 0.000000,
672.000000, 0.000000, 684.000000, 0.000000, 696.000000, 0.000000, 708.000000, 0.000000,
720.000000, 0.000000, 732.000000, 0.000000, 744.000000, 0.000000, 756.000000, 0.000000,
768.000000, 0.000000, 780.000000, 0.000000, 792.000000, 0.000000, 804.000000, 0.000000,
816.000000, 0.000000, 828.000000, 0.000000, 840.000000, 0.000000, 852.000000, 0.000000,
864.000000, 0.000000, 876.000000, 0.000000, 888.000000, 0.000000, 900.000000, 0.000000,
912.000000, 0.000000, 924.000000, 0.000000, 936.000000, 0.000000, 948.000000, 0.000000,
960.000000, 0.000000, 972.000000, 0.000000, 984.000000, 0.000000, 996.000000, 0.000000,
1008.000000, 0.000000, 1020.000000, 0.000000, 1032.000000, 0.000000, 1044.000000, 0.000000,
1056.000000, 0.000000, 1068.000000, 0.000000, 1080.000000, 0.000000, 1092.000000, 0.000000,
1104.000000, 0.000000, 1116.000000, 0.000000, 1128.000000, 0.000000, 1140.000000, 0.000000,
1152.000000, 0.000000, 1164.000000, 0.000000, 1176.000000, 0.000000, 1188.000000, 0.000000,
1200.000000, 0.000000, 1212.000000, 0.000000, 1224.000000, 0.000000, 1236.000000, 0.000000,
1248.000000, 0.000000, 1260.000000, 0.000000, 1272.000000, 0.000000, 1284.000000, 0.000000,
1296.000000, 0.000000, 1308.000000, 0.000000, 1320.000000, 0.000000, 1332.000000, 0.000000,
1344.000000, 0.000000, 1356.000000, 0.000000, 1368.000000, 0.000000, 1380.000000, 0.000000,
1392.000000, 0.000000, 1404.000000, 0.000000, 1416.000000, 0.000000, 1428.000000, 0.000000,
1440.000000, 0.000000, 1440.000000, 0.000000, 1452.000000, 0.000000, 1464.000000, 0.000000,
1476.000000, 0.000000, 1488.000000, 0.000000, 1500.000000, 0.000000, 1512.000000, 0.000000,
1524.000000, 0.000000, 1536.000000, 0.000000, 1548.000000, 0.000000, 1560.000000, 0.000000,
1572.000000, 0.000000, 1584.000000, 0.000000, 1596.000000, 0.000000, 1608.000000, 0.000000,
1620.000000, 0.000000, 1632.000000, 0.000000, 1644.000000, 0.000000, 1656.000000, 0.000000,
1668.000000, 0.000000, 1680.000000, 0.000000, 1692.000000, 0.000000, 1704.000000, 0.000000,
1716.000000, 0.000000, 1728.000000, 0.000000, 1740.000000, 0.000000, 1752.000000, 0.000000,
1764.000000, 0.000000, 1776.000000, 0.000000, 1788.000000, 0.000000, 1800.000000, 0.000000,
1812.000000, 0.000000, 1824.000000, 0.000000, 1836.000000, 0.000000, 1848.000000, 0.000000,
1860.000000, 0.000000, 1872.000000, 0.000000, 1884.000000, 0.000000, 1896.000000, 0.000000,
1908.000000, 0.000000, 1920.000000, 0.000000, 1932.000000, 0.000000, 1944.000000, 0.000000,
1956.000000, 0.000000, 1968.000000, 0.000000, 1980.000000, 0.000000, 1992.000000, 0.000000,
1992.000000, 0.000000, 2004.000000, 0.000000, 2016.000000, 0.000000, 2028.000000, 0.000000,
2040.000000, 0.000000, 2052.000000, 0.000000, 2064.000000, 0.000000, 2076.000000, 0.000000,
2088.000000, 0.000000, 2100.000000, 0.000000, 2112.000000, 0.000000, 2124.000000, 0.000000,
2136.000000, 0.000000, 2148.000000, 0.000000, 2160.000000, 0.000000, 2172.000000, 0.000000,
2184.000000, 0.000000, 2196.000000, 0.000000, 2208.000000, 0.000000, 2220.000000, 0.000000,
2232.000000, 0.000000, 2244.000000, 0.000000, 2256.000000, 0.000000, 2268.000000, 0.000000,
2280.000000, 0.000000, 2292.000000, 0.000000, 2304.000000, 0.000000, 2316.000000, 0.000000,
2328.000000, 0.000000, 2340.000000, 0.000000, 2352.000000, 0.000000, 2364.000000, 0.000000,
2376.000000, 0.000000, 2388.000000, 0.000000, 2400.000000, 0.000000, 2412.000000, 0.000000,
2424.000000, 0.000000, 2436.000000, 0.000000, 2448.000000, 0.000000, 2460.000000, 0.000000,
2472.000000, 0.000000, 2484.000000, 0.000000, 2496.000000, 0.000000, 2508.000000, 0.000000,
2520.000000, 0.000000, 2532.000000, 0.000000, 2544.000000, 0.000000, 2556.000000, 0.000000,
2568.000000, 0.000000, 2580.000000, 0.000000, 2592.000000, 0.000000, 2604.000000, 0.000000,
2616.000000, 0.000000, 2628.000000, 0.000000, 2640.000000, 0.000000, 2652.000000, 0.000000,
2664.000000, 0.000000, 2676.000000, 0.000000, 2688.000000, 0.000000, 2700.000000, 0.000000,
2712.000000, 0.000000, 2724.000000, 0.000000, 2736.000000, 0.000000, 2748.000000, 0.000000,
2760.000000, 0.000000, 2772.000000, 0.000000, 2784.000000, 0.000000, 2796.000000, 0.000000,
2808.000000, 0.000000, 2820.000000, 0.000000, 2832.000000, 0.000000, 2844.000000, 0.000000,
2856.000000, 0.000000, 2868.000000, 0.000000, 2880.000000, 0.000000, 2892.000000, 0.000000,
2904.000000, 0.000000, 2916.000000, 0.000000, 2928.000000, 0.000000, 2940.000000, 0.000000,
2940.000000, 0.000000, 2952.000000, 0.000000, 2964.000000, 0.000000, 2976.000000, 0.000000,
2988.000000, 0.000000
</result-positions>
</test-case>
</layout-tests>