ICU-120 Initial checkin of the LayoutEngine!

X-SVN-Rev: 2909
This commit is contained in:
Eric Mader 2000-11-14 21:22:14 +00:00
parent f46dcab450
commit 54c5c881a8
24 changed files with 4662 additions and 0 deletions

View File

@ -372,6 +372,18 @@ Package=<4>
###############################################################################
Project: "layout"=..\layout\layout.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "makeconv"=..\tools\makeconv\makeconv.dsp - Package Owner=<4>
Package=<5>

View File

@ -0,0 +1,176 @@
/*
* %W% %E%
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LEGlyphFilter.h"
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "ArabicLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
#include "GDEFMarkFilter.h"
#include "ArabicShaping.h"
#include "HebrewShaping.h"
class CharSubstitutionFilter : public LEGlyphFilter
{
private:
LEFontInstance *fFontInstance;
public:
CharSubstitutionFilter(LEFontInstance *fontInstance);
le_bool accept(LEGlyphID glyph);
};
CharSubstitutionFilter::CharSubstitutionFilter(LEFontInstance *fontInstance)
: fFontInstance(fontInstance)
{
// nothing to do
}
le_bool CharSubstitutionFilter::accept(LEGlyphID glyph)
{
return fFontInstance->canDisplay((LEUnicode) glyph);
}
ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable)
{
// nothing else to do...
}
ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode)
{
// nothing else to do...
}
ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
{
// nothing to do
}
// Input: characters
// Output: characters, char indices, tags
// Returns: output character count
le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEUnicode *&outChars, le_int32 *&charIndices, const LETag **&featureTags)
{
featureTags = new const LETag*[count];
switch (fScriptCode) {
case arabScriptCode:
{
GlyphShaper shaper(featureTags);
// NOTE: may not need seperate shaper if always use tags...
// NOTE: shaper could allocate the feature tags...
ArabicShaping::shape(chars, offset, count, max, rightToLeft, shaper);
break;
}
case hebrScriptCode:
HebrewShaping::shape(chars, offset, count, max, rightToLeft, featureTags);
break;
}
return count;
}
void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
LEGlyphID glyphs[], le_int32 glyphCount, float positions[])
{
if (fGPOSTable != NULL) {
OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphs, glyphCount, positions);
} else if (fGDEFTable != NULL) {
GDEFMarkFilter filter(fGDEFTable);
adjustMarkGlyphs(glyphs, glyphCount, false, &filter, positions);
} else {
GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) ArabicShaping::glyphDefinitionTable;
GDEFMarkFilter filter(gdefTable);
// this won't work if LEGlyphID and LEUnicode aren't the same size...
adjustMarkGlyphs((const LEGlyphID *) &chars[offset], count, reverse, &filter, positions);
}
}
UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode)
{
switch (scriptCode) {
case arabScriptCode:
fGSUBTable = (GlyphSubstitutionTableHeader *) ArabicShaping::glyphSubstitutionTable;
fGDEFTable = (GlyphDefinitionTableHeader *) ArabicShaping::glyphDefinitionTable;
break;
case hebrScriptCode:
fGSUBTable = (GlyphSubstitutionTableHeader *) HebrewShaping::glyphSubstitutionTable;
fGDEFTable = (GlyphDefinitionTableHeader *) HebrewShaping::glyphDefinitionTable;
break;
}
fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
}
UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
{
delete fSubstitutionFilter;
}
// "glyphs", "indices" -> glyphs, indices
le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphID tempGlyphs[], le_int32 tempCharIndices[], le_int32 tempGlyphCount,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
charIndices = tempCharIndices;
// NOTE: need to copy tempGlyphs to an LEUnicode array if LEGlyphID and LEUnicode aren't the same size...
ArabicOpenTypeLayoutEngine::mapCharsToGlyphs((LEUnicode *) tempGlyphs, 0, tempGlyphCount, false, true, glyphs, charIndices);
return tempGlyphCount;
}
void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphID *&glyphs, le_int32 *&charIndices)
{
le_int32 i, dir, out;
out = 0;
dir = 1;
if (reverse) {
out = count - 1;
dir = -1;
}
glyphs = new LEGlyphID[count];
charIndices = new le_int32[count];
for (i = 0; i < count; i += 1, out += dir) {
glyphs[out] = (LEGlyphID) chars[offset + i];
charIndices[out] = i;
}
}
void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
LEGlyphID glyphs[], le_int32 glyphCount, float positions[])
{
GDEFMarkFilter filter(fGDEFTable);
// this won't work if LEGlyphID and LEUnicode aren't the same size...
adjustMarkGlyphs((const LEGlyphID *) &chars[offset], count, reverse, &filter, positions);
}

View File

@ -0,0 +1,193 @@
/*
* @(#)ArabicLayoutEngine.h 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __ARABICLAYOUTENGINE_H
#define __ARABICLAYOUTENGINE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "LEGlyphFilter.h"
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
/**
* This class implements OpenType layout for Arabic fonts. It overrides
* the characerProcessing method to assign the correct OpenType feature
* tags for the Arabic contextual forms. It also overrides the adjustGlyphPositions
* method to guarantee that all vowel and accent glyphs have zero advance width.
*/
class ArabicOpenTypeLayoutEngine : public OpenTypeLayoutEngine
{
public:
/**
* This is the main constructor. It constructs an instance of ArabicOpenTypeLayoutEngine for
* a particular font, script and language. It takes the GSUB table as a parameter since
* LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
* Indic OpenType font.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
* @param gsubTable - the GSUB table
*
* @see LayoutEngine::layoutEngineFactory
* @see OpenTypeLayoutEngine
* @see ScriptAndLangaugeTags.h for script and language codes
*/
ArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable);
/**
* This constructor is used when the font requires a "canned" GSUB table which can't be known
* until after this constructor has been invoked.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
*
* @see OpenTypeLayoutEngine
* @see ScriptAndLangaugeTags.h for script and language codes
*/
ArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~ArabicOpenTypeLayoutEngine();
protected:
/**
* This method does Arabic OpenType character processing. It assigns the OpenType feature
* tags to the characters to generate the correct contextual forms and ligatures.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characters are in a right to left directional run
*
* Output parameters:
* @param outChars - the output character arrayt
* @param charIndices - the output character index array
* @param featureTags - the output feature tag array
*
* @return the output character count
*/
virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEUnicode *&outChars, le_int32 *&charIndices, const LETag **&featureTags);
/**
* This method applies the GPOS table if it is present, otherwise it ensures that all vowel
* and accent glyphs have a zero advance width by calling the adjustMarkGlyphs method.
* If the font contains a GDEF table, that is used to identify voewls and accents. Otherwise
* the character codes are used.
*
* @param chars - the input character context
* @param offset - the offset of the first character to process
* @param count - the number of characters to process
* @param reverse - true if the glyphs in the glyph array have been reordered
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs
* @param positions - the position array, will be updated as needed
*/
virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[], le_int32 glyphCount, float positions[]);
};
/**
* The class implements OpenType layout for Arabic fonts which don't
* contain a GSUB table, using a canned GSUB table based on Unicode
* Arabic Presentation Forms. It overrides the mapCharsToGlyphs method
* to use the Presentation Forms as logical glyph indices. It overrides the
* glyphPostProcessing method to convert the Presentation Forms to actual
* glyph indices.
*
* @see ArabicOpenTypeLayoutEngine
*/
class UnicodeArabicOpenTypeLayoutEngine : public ArabicOpenTypeLayoutEngine
{
public:
/**
* This constructs an instance of UnicodeArabicOpenTypeLayoutEngine for a specific font,
* script and language.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param languageCode - the language
*
* @see LEFontInstance
* @see ScriptAndLanguageTags.h for script and language codes
*/
UnicodeArabicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~UnicodeArabicOpenTypeLayoutEngine();
protected:
/**
* This method converts the Arabic Presentation Forms in the temp glyph array
* into actual glyph indices using ArabicOpenTypeLayoutEngine::mapCharsToGlyps.
*
* Input paramters:
* @param tempGlyphs - the input presentation forms
* @param tempCharIndices - the input character index array
* @param tempGlyphCount - the number of Presentation Froms
*
* Output parameters:
* @param glyphs - the output glyph index array
* @param charIndices - the output character index array
*
* @return the number of glyph indices in the output glyph index array
*/
virtual le_int32 glyphPostProcessing(LEGlyphID tempGlyphs[], le_int32 tempCharIndices[], le_int32 tempGlyphCount,
LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method copies the input characters into the output glyph index array,
* for use by the canned GSUB table. It also generates the character index array.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the offset of the first character to be mapped
* @param count - the number of characters to be mapped
* @param reverse - if true, the output will be in reverse order
* @param mirror - if true, do character mirroring
*
* Output parameters:
* @param glyphs - the glyph array
* @param charIndices - the character index array
*/
virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method ensures that all vowel and accent glyphs have a zero advance width by calling
* the adjustMarkGlyphs method. The character codes are used to identify the vowel and mark
* glyphs.
*
* @param chars - the input character context
* @param offset - the offset of the first character to process
* @param count - the number of characters to process
* @param reverse - true if the glyphs in the glyph array have been reordered
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs
* @param positions - the position array, will be updated as needed
*/
virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[], le_int32 glyphCount, float positions[]);
};
#endif

View File

@ -0,0 +1,40 @@
/*
* @(#)GXLayoutEngine.cpp 1.5 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LayoutEngine.h"
#include "GXLayoutEngine.h"
#include "MorphTables.h"
GXLayoutEngine::GXLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, MorphTableHeader *morphTable)
: LayoutEngine(fontInstance, scriptCode, languageCode), fMorphTable(morphTable)
{
// nothing else to do?
}
GXLayoutEngine::~GXLayoutEngine()
{
reset();
}
// apply 'mort' table
le_int32 GXLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphID *&glyphs, le_int32 *&charIndices)
{
mapCharsToGlyphs(chars, offset, count, false, rightToLeft, glyphs, charIndices);
fMorphTable->process(glyphs, charIndices, count);
return count;
}
// apply positional tables
void GXLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[], le_int32 glyphCount, float positions[])
{
// FIXME: no positional processing yet...
}

View File

@ -0,0 +1,98 @@
/*
* @(#)GXLayoutEngine.h 1.4 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __GXLAYOUTENGINE_H
#define __GXLAYOUTENGINE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "LEGlyphFilter.h"
#include "LayoutEngine.h"
#include "MorphTables.h"
/**
* This class implements layout for QuickDraw GX or Apple Advanced Typograyph (AAT)
* fonts. A font is a GX or AAT font if it contains a 'mort' table. See Apple's
* TrueType Reference Manual (http://fonts.apple.com/TTRefMan/index.html) for details.
* Information about 'mort' tables is in the chapter titled "Font Files."
*/
class GXLayoutEngine : public LayoutEngine
{
public:
/**
* This is the main constructor. It constructs an instance of GXLayoutEngine for
* a particular font, script and language. It takes the 'mort' table as a parameter since
* LayoutEngine::layoutEngineFactory has to read the 'mort' table to know that it has a
* GX font.
*
* Note: GX and AAT fonts don't contain any script and language specific tables, so
* the script and language are ignored.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
* @param morphTable - the 'mort' table
*
* @see LayoutEngine::layoutEngineFactory
* @see ScriptAndLangaugeTags.h for script and language codes
*/
GXLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, MorphTableHeader *morphTable);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~GXLayoutEngine();
protected:
/**
* The address of the 'mort' table
*/
MorphTableHeader *fMorphTable;
/**
* This method does GX layout using the font's 'mort' table. It converts the
* input character codes to glyph indices using mapCharsToGlyphs, and then
* applies the 'mort' table.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the text is in a right to left directional run
*
* Output parameters:
* @param glyphs - the glyph index array
* @param charIndices - the character index array
*
* @return the number of glyphs in the glyph index array
*/
virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method adjusts the glyph positions using the font's
* 'kern', 'trak', 'bsln', 'opbd' and 'just' tables.
*
* Input parameters:
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs in the glyph array
* @param x - the starting X position
* @param y - the starting Y position
*
* Output parameters:
* @param positions - the output X and Y positions (two entries per glyph)
*/
virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[],
le_int32 glyphCount, float positions[]);
};
#endif

View File

@ -0,0 +1,112 @@
/*
* @(#)IndicLayoutEngine.cpp 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "IndicLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
#include "GDEFMarkFilter.h"
#include "CDACLayout.h"
#include "IndicReordering.h"
IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable)
{
// nothing else to do...
}
IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode)
{
// nothing else to do...
}
IndicOpenTypeLayoutEngine::~IndicOpenTypeLayoutEngine()
{
// nothing to do
}
// Input: characters, tags
// Output: glyphs, char indices
le_int32 IndicOpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, const LETag **featureTags,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
le_int32 retCount = OpenTypeLayoutEngine::glyphProcessing(chars, offset, count, max, rightToLeft, featureTags, glyphs, charIndices);
IndicReordering::adjustMPres(&chars[offset], count, glyphs, charIndices, fScriptCode);
return retCount;
}
// Input: characters
// Output: characters, char indices, tags
// Returns: output character count
le_int32 IndicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEUnicode *&outChars, le_int32 *&charIndices, const LETag **&featureTags)
{
le_int32 worstCase = count * IndicReordering::getWorstCaseExpansion(fScriptCode);
outChars = new LEUnicode[worstCase];
charIndices = new le_int32[worstCase];
featureTags = new const LETag*[worstCase];
// NOTE: assumes this allocates featureTags...
// (probably better than doing the worst case stuff here...)
return IndicReordering::reorder(&chars[offset], count, fScriptCode, outChars, charIndices, featureTags);
}
CDACOpenTypeLayoutEngine::CDACOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
const CDACLayout::ScriptInfo *scriptInfo)
: IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode), fScriptInfo(scriptInfo)
{
fGSUBTable = (GlyphSubstitutionTableHeader *) fScriptInfo->glyphSubstitutionTable;
fGDEFTable = (GlyphDefinitionTableHeader *) fScriptInfo->glyphDefinitionTable;
}
CDACOpenTypeLayoutEngine::~CDACOpenTypeLayoutEngine()
{
reset();
}
// "glyph" -> char
// char -> glyph
le_int32 CDACOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphID tempGlyphs[], le_int32 tempCharIndices[], le_int32 tempGlyphCount,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
LEUnicode *tempChars;
le_int32 glyphCount = CDACLayout::countCDACGlyphs(fScriptInfo, tempGlyphs, tempGlyphCount);
tempChars = new LEUnicode[glyphCount];
glyphs = new LEGlyphID[glyphCount];
charIndices = new le_int32[glyphCount];
// NOTE: might want mapCDACGlyphsToChars to count output chars and allocate the array to hold them...
// or it could make a guess and grow the array if the guess is too small...
CDACLayout::mapCDACGlyphsToChars(fScriptInfo, tempGlyphs, tempCharIndices, tempGlyphCount, tempChars, charIndices);
IndicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, glyphCount, false, false, glyphs, charIndices);
delete[] tempChars;
return glyphCount;
}
void CDACOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphID *&glyphs, le_int32 *&charIndices)
{
glyphs = new LEGlyphID[count];
CDACLayout::initCDACGlyphs(fScriptInfo, chars, offset, count, glyphs);
}

View File

@ -0,0 +1,205 @@
/*
* @(#)IndicLayoutEngine.h 1.4 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __INDICLAYOUTENGINE_H
#define __INDICLAYOUTENGINE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "LEGlyphFilter.h"
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
#include "CDACLayout.h"
#include <string.h>
/**
* This class implements OpenType layout for Indic OpenType fonts, as
* specified by Microsoft in "Creating and Supporting OpenType Fonts for
* Indic Scripts" (http://www.microsoft.com/typography/otspec/indicot/default.htm)
*
* This class overrides the characterProcessing method to do Indic character processing
* and reordering, and the glyphProcessing method to implement post-GSUB processing for
* left matras. (See the MS spec. for more details)
*/
class IndicOpenTypeLayoutEngine : public OpenTypeLayoutEngine
{
public:
/**
* This is the main constructor. It constructs an instance of IndicOpenTypeLayoutEngine for
* a particular font, script and language. It takes the GSUB table as a parameter since
* LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
* Indic OpenType font.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
* @param gsubTable - the GSUB table
*
* @see LayoutEngine::layoutEngineFactory
* @see OpenTypeLayoutEngine
* @see ScriptAndLangaugeTags.h for script and language codes
*/
IndicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable);
/**
* This constructor is used when the font requires a "canned" GSUB table which can't be known
* until after this constructor has been invoked.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
*
* @see OpenTypeLayoutEngine
* @see ScriptAndLangaugeTags.h for script and language codes
*/
IndicOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~IndicOpenTypeLayoutEngine();
protected:
/**
* This method does Indic OpenType character processing. It assigns the OpenType feature
* tags to the characters, and may generate output characters which have been reordered. For
* some Indic scripts, it may also split some vowels, resulting in more output characters
* than input characters.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characters are in a right to left directional run
*
* Output parameters:
* @param outChars - the output character arrayt
* @param charIndices - the output character index array
* @param featureTags - the output feature tag array
*
* @return the output character count
*/
virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEUnicode *&outChars, le_int32 *&charIndices, const LETag **&featureTags);
/**
* This method does character to glyph mapping, applies the GSUB table and applies
* any post GSUB fixups for left matras. It calls OpenTypeLayoutEngine::glyphProcessing
* to do the character to glyph mapping, and apply the GSUB table.
*
* Note that in the case of "canned" GSUB tables, the output glyph indices may be
* "fake" glyph indices that need to be converted to "real" glyph indices by the
* glyphPostProcessing method.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characters are in a right to left directional run
* @param featureTags - the feature tag array
*
* Output parameters:
* @param glyphs - the output glyph index array
* @param charIndices - the output character index array
*
* @return the number of glyphs in the output glyph index array
*
* Note: if the character index array was already set by the characterProcessing
* method, this method won't change it.
*/
// Input: characters, tags
// Output: glyphs, char indices
virtual le_int32 glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
const LETag **featureTags, LEGlyphID *&glyphs, le_int32 *&charIndices);
};
/**
* This class implements Indic OpenType layout for CDAC fonts. Since CDAC fonts don't contain
* a GSUB table, it uses a canned GSUB table, using logical glyph indices. Each logical glyph
* may be rendered with several physical glyphs in the CDAC font. It uses the CDACLayout class
* to do the layout.
*
* @see CDACLayout
* @see IndicOpenTypeLayout
*/
class CDACOpenTypeLayoutEngine : public IndicOpenTypeLayoutEngine
{
public:
/**
* This constructs an instance of CDACOpenTypeLayoutEngine for a specific font, script and
* language. The scriptInfo parameter contains the information that CDACLayout needs to
* layout using the font, including the character to logical glyph mapping information,
* the canned GSUB table, and the map from logical to physical glyphs. This will be obtained
* by LayoutEngine::layoutEngineFactory to determine if the font is a CDAC font.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param languageCode - the language
* @param scriptInfo - the CDAC script information
*
* @see LEFontInstance
* @see CDACLayout
* @see ScriptAndLanguageTags.h for script and language codes
*/
CDACOpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
const CDACLayout::ScriptInfo *scriptInfo);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~CDACOpenTypeLayoutEngine();
protected:
const CDACLayout::ScriptInfo *fScriptInfo;
/**
* This method converts logical glyph indices to physical glyph indices.
*
* Input paramters:
* @param tempGlyphs - the input "fake" glyph index array
* @param tempCharIndices - the input "fake" character index array
* @param tempGlyphCount - the number of "fake" glyph indices
*
* Output parameters:
* @param glyphs - the output glyph index array
* @param charIndices - the output character index array
*
* @return the number of glyph indices in the output glyph index array
*/
virtual le_int32 glyphPostProcessing(LEGlyphID tempGlyphs[], le_int32 tempCharIndices[], le_int32 tempGlyphCount,
LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method maps charcters to logical glyph indices.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the offset of the first character to be mapped
* @param count - the number of characters to be mapped
* @param reverse - if true, the output should be in reverse order
* @param mirror - if true, map characters like parenthesis to their mirror image
*
* Output parameters:
* @param glyphs - the glyph array
* @param charIndices - the character index array
*/
virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
LEGlyphID *&glyphs, le_int32 *&charIndices);
};
#endif

View File

@ -0,0 +1,263 @@
/*
* @(#)LEFontInstance.h 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LEFONTINSTANCE_H
#define __LEFONTINSTANCE_H
#include "LETypes.h"
/**
* Instances of this class are used by LEFontInstance::mapCharsToGlyphs and
* LEFontInstance::mapCharToGlyph to adjust character codes before the character
* to glyph mapping process. Examples of this are filtering out control charcters
* and character mirroring - replacing a character which has both a left and a right
* hand form with the opposite form.
*/
class LECharMapper
{
public:
/**
* This method does the adjustments.
*
* @param ch - the input charcter
*
* @return the adjusted character
*/
virtual LEUnicode32 mapChar(LEUnicode32 ch) = 0;
};
/**
* This is a pure virtual base class that servers as the interface between a LayoutEngine
* and the platform font environment. It allows a LayoutEngine to access font tables, do
* character to glyph mapping, and obtain metrics information without knowing any platform
* specific details. There are also a few utility methods for converting between points,
* pixels and funits. (font design units)
*
* Each instance of an LEFontInstance represents a renerable instance of a font. (i.e. a
* single font at a particular point size, with a particular transform)
*/
class LEFontInstance
{
public:
/**
* This virtual destructor is here so that the subclass
* destructors can be invoked through the base class.
*/
virtual ~LEFontInstance() { };
//
// Font file access
//
/**
* This method reads a table from the font.
*
* @param tableTag - the four byte table tag
*
* @return the address of the table in memory
*/
virtual const void *getFontTable(LETag tableTag) = 0;
/**
* This method is used to determine if the font can
* render the given character. This can usually be done
* by looking the character up in the font's character
* to glyph mapping.
*
* @param ch - the character to be tested
*
* @return true if the font can render ch.
*/
virtual le_bool canDisplay(LEUnicode ch) = 0;
/**
* This method returns the number of design units in
* the font's EM square.
*
* @return the number of design units pre EM.
*/
virtual le_int32 getUnitsPerEM() = 0;
/**
* This method maps an array of charcter codes to an array of glyph
* indices, using the font's character to glyph map.
*
* @param chars - the character array
* @param offset - the index of the first charcter
* @param count - the number of charcters
* @param reverse - if true, store the glyph indices in reverse order.
* @param mapper - the character mapper.
* @param glyphs - the output glyph array
*
* @see LECharMapper
*/
virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LECharMapper *mapper, LEGlyphID glyphs[]) = 0;
/**
* This method maps a single character to a glyph index, using the
* font's charcter to glyph map.
*
* @param ch - the character
* @param mapper - the character mapper
*
* @return the glyph index
*
* @see LECharMapper
*/
virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch, LECharMapper *mapper) = 0;
/**
* This method gets a name from the font. (e.g. the family name) The encoding
* of the name is specified by the platform, the script, and the language.
*
* @param platformID - the platform id
* @param scriptID - the script id
* @param langaugeID - the language id
* @param name - the destination character array (can be null)
*
* @return the number of characters in the name
*/
virtual le_int32 getName(le_uint16 platformID, le_uint16 scriptID, le_uint16 languageID, le_uint16 nameID, LEUnicode *name) = 0;
//
// Metrics
//
/**
* This method gets the X and Y advance of a particular glyph, in pixels.
*
* @param glyph - the glyph index
* @param advance - the X and Y pixel values will be stored here
*/
virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) = 0;
/**
* This method gets the hinted X and Y pixel coordinates of a particular
* point in the outline of the given glyph.
*
* @param glyph - the glyph index
* @param pointNumber - the number of the point
* @param point - the point's X and Y pixel values will be stored here
*
* @return true if the point coordinates could be stored.
*/
virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) = 0;
/**
* This method returns the width of the font's EM square
* in pixels.
*
* @return the pixel width of the EM square
*/
virtual float getXPixelsPerEm() = 0;
/**
* This method returns the height of the font's EM square
* in pixels.
*
* @return the pixel height of the EM square
*/
virtual float getYPixelsPerEm() = 0;
/**
* This method converts font design units in the
* X direction to points.
*
* @param xUnits - design units in the X direction
*
* @return points in the X direction
*/
virtual float xUnitsToPoints(float xUnits) = 0;
/**
* This method converts font design units in the
* Y direction to points.
*
* @param yUnits - design units in the Y direction
*
* @return points in the Y direction
*/
virtual float yUnitsToPoints(float yUunits) = 0;
/**
* This method converts font design units to points.
*
* @param units - X and Y design units
* @param points - set to X and Y points
*/
virtual void unitsToPoints(LEPoint &units, LEPoint &points) = 0;
/**
* This method converts pixels in the
* X direction to font design units.
*
* @param xPixels - pixels in the X direction
*
* @return font design units in the X direction
*/
virtual float xPixelsToUnits(float xPixels) = 0;
/**
* This method converts pixels in the
* Y direction to font design units.
*
* @param yPixels - pixels in the Y direction
*
* @return font design units in the Y direction
*/
virtual float yPixelsToUnits(float yPixels) = 0;
/**
* This method converts pixels to font design units.
*
* @param pixels - X and Y pixel
* @param units - set to X and Y font design units
*/
virtual void pixelsToUnits(LEPoint &pixels, LEPoint &units) = 0;
/**
* This method transforms an X, Y point in font design units to a
* pixel coordinate, applying the font's transform.
*
* @param xFunits - the X coordinate in font design units
* @param yFunits - the Y coordinate in font design units
* @param pixels - the tranformed co-ordinate in pixels
*/
virtual void transformFunits(float xFunits, float yFunits, LEPoint &pixels) = 0;
/**
* This is a convenience method used to convert
* values in a 16.16 fixed point format to floating point.
*
* @param fixed - the fixed point value
*
* @return the floating point value
*/
static float fixedToFloat(le_int32 fixed)
{
return (float) (fixed / 65536.0);
};
/**
* This is a convenience method used to convert
* floating point values to 16.16 fixed point format.
*
* @param theFloat - the floating point value
*
* @return the fixed point value
*/
static le_int32 floatToFixed(float theFloat)
{
return (le_int32) (theFloat * 65536.0);
};
};
#endif

View File

@ -0,0 +1,32 @@
/*
* @(#)LEGlyphFilter.h 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LEGLYPHFILTER__H
#define __LEGLYPHFILTER__H
#include "LETypes.h"
/**
* This is a helper class that is used to
* recognize a set of glyph indices.
*/
class LEGlyphFilter
{
public:
/**
* This method is used to test a particular
* glyph index to see if it is in the set
* recognized by the filter.
*
* @param glyph - the glyph index to be tested
*
* @return true if the glyph index is in the set.
*/
virtual le_bool accept(LEGlyphID glyph) = 0;
};
#endif

View File

@ -0,0 +1,44 @@
/*
* %W% %E%
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LESCRIPTS_H
#define __LESCRIPTS_H
enum ScriptCodes {
neutScriptCode = 0,
latnScriptCode = 1,
grekScriptCode = 2,
cyrlScriptCode = 3,
armnScriptCode = 4,
hebrScriptCode = 5,
arabScriptCode = 6,
devaScriptCode = 7,
bengScriptCode = 8,
punjScriptCode = 9,
gujrScriptCode = 10,
oryaScriptCode = 11,
tamlScriptCode = 12,
teluScriptCode = 13,
kndaScriptCode = 14,
mlymScriptCode = 15,
thaiScriptCode = 16,
laoScriptCode = 17,
tibtScriptCode = 18,
grgnScriptCode = 19,
hangScriptCode = 20,
kanaScriptCode = 21,
bpmfScriptCode = 22,
knbnScriptCode = 23,
haniScriptCode = 24,
surrScriptCode = 25,
puseScriptCode = 26,
spclScriptCode = 27,
scriptCodeCount = 28
};
#endif

View File

@ -0,0 +1,78 @@
/*
* @(#)LESwaps.h 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LESWAPS_H
#define __LESWAPS_H
#include "LETypes.h"
/**
* These are convenience macros which invoke the swap functions
* from a concise call.
*/
#define SWAPW(value) (LESwaps::isBigEndian() ? (value) : LESwaps::swapWord(value))
#define SWAPL(value) (LESwaps::isBigEndian() ? (value) : LESwaps::swapLong(value))
/**
* This class is used to access data which stored in big endian order
* regardless of the conventions of the platform. It has been designed
* to automatically detect the endian-ness of the platform, so that a
* compilation flag is not needed.
*
* All methods are static and inline in an attempt to induce the compiler
* to do most of the calculations at compile time.
*/
class LESwaps
{
public:
/**
* This method detects the endian-ness of the platform by
* casting a pointer to a word to a pointer to a byte. On
* big endian platforms the FF will be in the byte with the
* lowest address. On little endian platforms, the FF will
* be in the byte with the highest address.
*
* @return true if the platform is big endian
*/
static le_bool isBigEndian()
{
static le_uint16 word = 0xFF00;
static le_uint8 *byte = (le_uint8 *) &word;
return *byte;
};
/**
* This method the byte swap required on little endian platforms
* to correctly access a word.
*
* @param value - the word to be byte swapped
*
* @return the byte swapped word
*/
static le_uint16 swapWord(le_uint16 value)
{
return (((le_uint8) (value >> 8)) | (value << 8));
};
/**
* This method does the byte swapping required on little endian platforms
* to correctly access a long.
*
* @param value - the long to be byte swapped
*
* @return the byte swapped long
*/
static le_uint32 swapLong(le_uint32 value)
{
return swapWord((le_uint16) (value >> 16)) | (swapWord((le_uint16) value) << 16);
};
};
#endif

View File

@ -0,0 +1,49 @@
/*
* @(#)LETypes.h 1.2 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LETYPES_H
#define __LETYPES_H
typedef long le_int32;
typedef unsigned long le_uint32;
typedef short le_int16;
typedef unsigned short le_uint16;
typedef signed char le_int8;
typedef unsigned char le_uint8;
typedef char le_bool;
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#ifndef NULL
#define NULL 0
#endif
typedef le_uint32 LETag;
typedef le_uint16 LEGlyphID;
typedef le_uint16 LEUnicode16;
typedef le_uint32 LEUnicode32;
typedef le_uint16 LEUnicode; // FIXME: we should depricate this type in favor of LEUnicode16...
struct LEPoint
{
float fX;
float fY;
};
#endif

View File

@ -0,0 +1,325 @@
/*
* %W% %E%
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LayoutEngine.h"
#include "ArabicLayoutEngine.h"
//#include "HebrewLayoutEngine.h"
#include "IndicLayoutEngine.h"
#include "ThaiLayoutEngine.h"
#include "GXLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "OpenTypeUtilities.h"
#include "GlyphSubstitutionTables.h"
#include "MorphTables.h"
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
class DefaultCharMapper : public LECharMapper
{
private:
le_bool fFilterControls;
le_bool fMirror;
static LEUnicode32 controlChars[];
static const le_int32 controlCharsCount;
static LEUnicode32 mirroredChars[];
static const le_int32 mirroredCharsCount;
public:
DefaultCharMapper(le_bool filterControls, le_bool mirror)
: fFilterControls(filterControls), fMirror(mirror)
{
// nothing
};
~DefaultCharMapper()
{
// nada
};
LEUnicode32 mapChar(LEUnicode32 ch);
};
LEUnicode32 DefaultCharMapper::controlChars[] = {
0x0009, 0x000A, 0x000D,
/*0x200C, 0x200D,*/ 0x200E, 0x200F,
0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
};
const le_int32 DefaultCharMapper::controlCharsCount = ARRAY_SIZE(controlChars);
LEUnicode32 DefaultCharMapper::mirroredChars[] = {
0x0028, 0x0029, // ascii paired punctuation
0x003c, 0x003e,
0x005b, 0x005d,
0x007b, 0x007d,
0x2045, 0x2046, // math symbols (not complete)
0x207d, 0x207e,
0x208d, 0x208e,
0x2264, 0x2265,
0x3008, 0x3009, // chinese paired punctuation
0x300a, 0x300b,
0x300c, 0x300d,
0x300e, 0x300f,
0x3010, 0x3011,
0x3014, 0x3015,
0x3016, 0x3017,
0x3018, 0x3019,
0x301a, 0x301b
};
const le_int32 DefaultCharMapper::mirroredCharsCount = ARRAY_SIZE(mirroredChars);
LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch)
{
if (fFilterControls) {
le_int32 index = OpenTypeUtilities::search(ch, controlChars, controlCharsCount);
if (controlChars[index] == ch) {
return 0xFFFF;
}
}
if (fMirror) {
le_int32 index = OpenTypeUtilities::search(ch, mirroredChars, mirroredCharsCount);
if (mirroredChars[index] == ch) {
le_int32 mirrorOffset = ((index & 1) == 0) ? 1 : -1;
return mirroredChars[index + mirrorOffset];
}
}
return ch;
}
LayoutEngine::LayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: fGlyphCount(0), fGlyphs(NULL), fCharIndices(NULL), fPositions(NULL),
fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode)
{
// nothing else to do?
}
void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase)
{
le_int32 i;
for (i = 0; i < fGlyphCount; i += 1) {
charIndices[i] = fCharIndices[i] + indexBase;
}
}
// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits)
{
le_int32 i;
for (i = 0; i < fGlyphCount; i += 1) {
glyphs[i] = fGlyphs[i] | extraBits;
}
};
le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphs, charIndices);
return count;
}
// Input: glyphs
// Output: positions
void LayoutEngine::positionGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, float x, float y, float *&positions)
{
if (positions == NULL) {
positions = new float[2 * (glyphCount + 1)];
}
le_int32 i;
for (i = 0; i < glyphCount; i += 1) {
LEPoint advance;
positions[i * 2] = x;
positions[i * 2 + 1] = y;
fFontInstance->getGlyphAdvance(glyphs[i], advance);
x += advance.fX;
y += advance.fY;
}
positions[glyphCount * 2] = x;
positions[glyphCount * 2 + 1] = y;
}
void LayoutEngine::adjustMarkGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, le_bool reverse, LEGlyphFilter *markFilter,
float positions[])
{
float xAdjust = 0;
le_int32 g = 0, direction = 1;
le_int32 p;
if (reverse) {
g = glyphCount - 1;
direction = -1;
}
for (p = 0; p < glyphCount; p += 1, g += direction) {
float xAdvance = positions[(p + 1) * 2] - positions[p * 2];
positions[p * 2] += xAdjust;
if (markFilter->accept(glyphs[g])) {
xAdjust -= xAdvance;
}
}
positions[glyphCount * 2] += xAdjust;
}
void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
if (glyphs == NULL) {
glyphs = new LEGlyphID[count];
}
if (charIndices == NULL) {
le_int32 i, dir = 1, out = 0;
if (reverse) {
out = count - 1;
dir = -1;
}
charIndices = new le_int32[count];
for (i = 0; i < count; i += 1, out += dir) {
charIndices[out] = i;
}
}
DefaultCharMapper charMapper(true, mirror);
fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, glyphs);
}
// Input: characters, font?
// Output: glyphs, positions, char indices
// Returns: number of glyphs
le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
float x, float y)
{
fGlyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, fGlyphs, fCharIndices);
positionGlyphs(fGlyphs, fGlyphCount, x, y, fPositions);
adjustGlyphPositions(chars, offset, count, rightToLeft, fGlyphs, fGlyphCount, fPositions);
return fGlyphCount;
}
void LayoutEngine::reset()
{
fGlyphCount = 0;
if (fGlyphs != NULL) {
delete[] fGlyphs;
fGlyphs = NULL;
}
if (fCharIndices != NULL) {
delete[] fCharIndices;
fCharIndices = NULL;
}
if (fPositions != NULL) {
delete[] fPositions;
fPositions = NULL;
}
}
LayoutEngine *LayoutEngine::layoutEngineFactory(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
{
static le_uint32 gsubTableTag = 0x47535542; // "GSUB"
static le_uint32 mortTableTag = 0x6D6F7274; // 'mort'
GlyphSubstitutionTableHeader *gsubTable = (GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
if (gsubTable != NULL && gsubTable->coversScript(OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
switch (scriptCode) {
case bengScriptCode:
case devaScriptCode:
case gujrScriptCode:
case kndaScriptCode:
case mlymScriptCode:
case oryaScriptCode:
case punjScriptCode:
case tamlScriptCode:
case teluScriptCode:
return new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
case arabScriptCode:
return new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
default:
return new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
break;
}
} else {
MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
if (morphTable != NULL) {
return new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable);
} else {
switch (scriptCode) {
case bengScriptCode:
case devaScriptCode:
case gujrScriptCode:
case kndaScriptCode:
case mlymScriptCode:
case oryaScriptCode:
case punjScriptCode:
case tamlScriptCode:
case teluScriptCode:
{
const CDACLayout::ScriptInfo *scriptInfo = CDACLayout::getCDACScriptInfo(fontInstance, scriptCode);
if (scriptInfo != NULL) {
return new CDACOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, scriptInfo);
} else {
return new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
}
}
case arabScriptCode:
case hebrScriptCode:
return new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
//case hebrScriptCode:
// return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
case thaiScriptCode:
return new ThaiLayoutEngine(fontInstance, scriptCode, languageCode);
default:
break;
}
}
}
return new LayoutEngine(fontInstance, scriptCode, languageCode);
}
LayoutEngine::~LayoutEngine() {
reset();
}

View File

@ -0,0 +1,371 @@
/*
* @(#)LayoutEngine.h 1.4 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __LAYOUTENGINE_H
#define __LAYOUTENGINE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "LEGlyphFilter.h"
#include "unicode/utypes.h"
#include <string.h>
#define ARRAY_COPY(dst, src, count) memcpy(dst, src, (count) * sizeof (src)[0])
/**
* This is a virtual base class used to do complex text layout. The text must all
* be in a single font, script, and language. An instance of a LayoutEngine can be
* created by calling the layoutEngineFactory method. Fonts are identified by
* instances of the LEFontInstance class. Script and language codes are identified
* by integer codes, which are defined in ScriptAndLanuageTags.h.
*
* The input to the layout process is an array of characters in logical order,
* and a starting X, Y position for the text. The output is an array of glyph indices,
* an array of character indices for the glyphs, and an array of glyph positions.
* These arrays are protected members of LayoutEngine which can be retreived by a
* public method. The reset method can be called to free these arrays so that the
* LayoutEngine can be reused.
*
* The layout process is done in three steps. There is a protected virtual method
* for each step. These methods have a default implementation which only does
* character to glyph mapping and default positioning using the glyph's advance
* widths. Subclasses can override these methods for more advanced layout.
* There is a public method which invokes the steps in the correct order.
*
* The steps are:
*
* 1) Glyph processing - character to glyph mapping and any other glyph processing
* such as ligature substitution and contextual forms.
*
* 2) Glyph positioning - position the glyphs based on their advance widths.
*
* 3) Glyph position adjustments - adjustment of glyph positions for kerning,
* accent placement, etc.
*
* NOTE: in all methods below, output parameters are references to pointers so
* the method can allocate and free the storage as needed. All storage allocated
* in this way is owned by the object which created it, and will be freed when it
* is no longer needed, or when the object's destructor is invoked.
*
* @see LEFontInstance
* @see ScriptAndLanguageTags.h
*/
class U_LAYOUT_API LayoutEngine
{
protected:
/**
* The number of glyphs in the output
*/
le_int32 fGlyphCount;
/**
* The output glyph array
*/
LEGlyphID *fGlyphs;
/**
* The character index array. One entry for each output glyph, giving the index
* in the input character array of the character which corresponds to this glyph.
*/
le_int32 *fCharIndices;
/**
* The glyph position array. There are two entries for each glyph giving the
* X and Y positions of the glyph. Thus, for glyph i, the X position is at index
* 2i, and the Y position is at index 2i + 1.
*/
float *fPositions;
/**
* The font instance for the text font.
*
* @see LEFontInstance
*/
LEFontInstance *fFontInstance;
/**
* The script code for the text
*
* @see ScriptAndLanguageTags.h for script codes.
*/
le_int32 fScriptCode;
/**
* The langauge code for the text
*
* @see ScriptAndLanguageTags.h for language codes.
*/
le_int32 fLanguageCode;
/**
* This constructs an instance for a given font, script and language. Subclass constructors
* must call this constructor.
*
* @param fontInstance - the font for the text
* @param scriptCode - the script for the text
* @param langaugeCode - the language for the text
*
* @see LEFontInstance
* @see ScriptAndLanguageTags.h
*/
LayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* This overrides the default no argument constructor to make it
* difficult for clients to call it. Clients are expected to call
* layoutEngineFactory.
*/
LayoutEngine();
/**
* This method does the glyph processing. It converts an array of characters
* into an array of glyph indices and character indices. The characters to be
* processed are passed in a surrounding context. The context is specified as
* a starting address and a maximum character count. An offset and a count are
* used to specify the characters to be processed.
*
* The default implementation of this method only does character to glyph mapping.
* Subclasses needing more elaborate glyph processing must override this method.
*
* Input parameters:
* @param chars - the character context
* @param offset - the offset of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the context.
* @param rightToLeft - true if the text is in a right to left directional run
*
* Output parameters:
* @param glyphs - the glyph index array
* @param charIndices - the character index array
*
* @return the number of glyphs in the glyph index array
*/
virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method does basic glyph positioning. The default implementation positions
* the glyphs based on their advance widths. This is sufficient for most uses. It
* is not expected that many subclasses will override this method.
*
* Input parameters:
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs in the glyph array
* @param x - the starting X position
* @param y - the starting Y position
*
* Output parameters:
* @param positions - the output X and Y positions (two entries per glyph)
*/
virtual void positionGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, float x, float y, float *&positions);
/**
* This method does positioning adjustments like accent positioning and
* kerning. The default implementation does nothing. Subclasses needing
* position adjustments must override this method.
*
* Note that this method has both characters and glyphs as input so that
* it can use the character codes to determine glyph types if that information
* isn't directly available. (e.g. Some Arabic OpenType fonts don't have a GDEF
* table)
*
* @param chars - the input character context
* @param offset - the offset of the first character to process
* @param count - the number of characters to process
* @param reverse - true if the glyphs in the glyph array have been reordered
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs
* @param positions - the position array, will be updated as needed
*
* Note: the positions are passed as a plain array because this method should
* not need to reallocate them.
*/
virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[], le_int32 glyphCount, float positions[])
{
// default is no adjustments
};
/**
* This method gets a table from the font associated with
* the text. The default implementation gets the table from
* the font instance. Subclasses which need to get the tables
* some other way must override this method.
*
* @param tableTag - the four byte table tag.
*
* @return the address of the table.
*/
virtual const void *getFontTable(LETag tableTag)
{
return fFontInstance->getFontTable(tableTag);
};
/**
* This method does character to glyph mapping. The default implementation
* uses the font instance to do the mapping. It will allocate the glyph and
* character index arrays if they're not already allocated. If it allocates the
* character index array, it will fill it it.
*
* This method supports right to left
* text with the ability to store the glyphs in reverse order, and by supporting
* character mirroring, which will replace a character which has a left and right
* form, such as parens, with the opposite form before mapping it to a glyph index.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the offset of the first character to be mapped
* @param count - the number of characters to be mapped
* @param reverse - if true, the output will be in reverse order
* @param mirror - if true, do character mirroring
*
* Output parameters:
* @param glyphs - the glyph array
* @param charIndices - the character index array
*
* @see LEFontInstance
*/
virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This is a convenience method that forces the advance width of mark
* glyphs to be zero, which is required for proper selection and highlighting.
*
* @param glyphs - the glyph array
* @param glyphCount - the number of glyphs
* @param reverse - true if the glyph array has been reordered
* @param markFilter - used to identify mark glyphs
* @param positions - the glyph position array - updated as required
*
* @see LEGlyphFilter
*/
static void adjustMarkGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, le_bool reverse, LEGlyphFilter *markFilter, float positions[]);
public:
/**
* The destructor. It will free any storage allocated for the
* glyph, character index and position arrays by calling the reset
* method. It is declared virtual so that it will be invoked by the
* subclass destructors.
*/
virtual ~LayoutEngine();
/**
* This method will invoke the layout steps in their correct order by calling
* the computeGlyphs, positionGlyphs and adjustGlyphPosition methods.. It will
* compute the glyph, character index and position arrays.
*
* @param chars - the input character context
* @param offset - the offset of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characers are in a right to left directional run
* @param x - the initial X position
* @param y - the initial Y position
*
* @return the number of glyphs in the glyph array
*
* Note; the glyph, character index and position array can be accessed
* using the getter method below.
*/
le_int32 layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, float x, float y);
/**
* This method copies the glyph array into a caller supplied array.
* The caller must ensure that the array is large enough to hold all
* the glyphs.
*
* @param glyphs - the destiniation glyph array
*/
void getGlyphs(LEGlyphID glyphs[])
{
ARRAY_COPY(glyphs, fGlyphs, fGlyphCount);
};
/**
* This method copies the glyph array into a caller supplied array,
* ORing in extra bits. (This functionality is needed by the JDK,
* which uses 32 bits pre glyph idex, with the high 16 bits encoding
* the composite font slot number)
*
* @param glyphs - the destination (32 bit) glyph array
* @param extraBits - this value will be ORed with each glyph index
*/
void getGlyphs(le_uint32 glyphs[], le_uint32 extraBits);
/**
* This method copies the character index array into a caller supplied array.
* The caller must ensure that the array is large enough to hold all
* the character indices.
*
* @param charIndices - the destiniation character index array
*/
void getCharIndices(le_int32 charIndices[])
{
ARRAY_COPY(charIndices, fCharIndices, fGlyphCount);
};
/**
* This method copies the character index array into a caller supplied array.
* The caller must ensure that the array is large enough to hold all
* the character indices.
*
* @param charIndices - the destiniation character index array
* @param indexBase - an offset which will be added to each index
*/
void getCharIndices(le_int32 charIndices[], le_int32 indexBase);
/**
* This method copies the position array into a caller supplied array.
* The caller must ensure that the array is large enough to hold all
* the positions.
*
* @param glyphs - the destiniation position array
*/
void getGlyphPositions(float positions[])
{
ARRAY_COPY(positions, fPositions, fGlyphCount * 2 + 2);
};
/**
* This method returns the x position of the glyph at the
* given index.
*
* @param glyphIndex - the index of the glyph
*
* @return the glyph's x position
*/
float getGlyphXPosition(le_int32 glyphIndex)
{
return fPositions[glyphIndex * 2];
};
/**
* This method frees the glyph, character index and position arrays
* so that the LayoutEngine can be reused to layout a different
* characer array. (This method is also called by the destructor)
*/
virtual void reset();
/**
* This method returns a LayoutEngine capable of laying out text
* in the given font, script and langauge. Note that the LayoutEngine
* returned may be a subclass of LayoutEngine.
*
* @param fontInstance - the font of the text
* @param scriptCode - the script of the text
* @param langaugeCode - the language of the text
*
* @see LEFontInstance
*/
static LayoutEngine *layoutEngineFactory(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
};
#endif

View File

@ -0,0 +1,167 @@
## Makefile.in for ICU - layout
SO_TARGET_VERSION = @LIB_VERSION@
SO_TARGET_VERSION_MAJOR = @LIB_VERSION_MAJOR@
## Install directory information
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ..
include $(top_builddir)/icudefs.mk
include $(srcdir)/layoutobj.inc
## Platform-specific setup
include @platform_make_fragment@
## Build directory information
subdir = layout
SUBDIRS = aat opentype
## Extra files to remove for 'make clean'
CLEANFILES = *~ $(DEPS)
## Target information
ENABLE_STATIC = @ENABLE_STATIC@
ENABLE_SHARED = @ENABLE_SHARED@
TARGET_STUBNAME=layout
ifneq ($(ENABLE_STATIC),)
TARGET = $(LIBICU)$(TARGET_STUBNAME).a
RANLIB = @RANLIB@
endif
ifneq ($(ENABLE_SHARED),)
SO_TARGET = $(LIBICU)$(TARGET_STUBNAME).$(SO)
ALL_SO_TARGETS = $(SO_TARGET) $(MIDDLE_SO_TARGET) $(FINAL_SO_TARGET)
endif
ALL_TARGETS = $(TARGET) $(ALL_SO_TARGETS)
DYNAMICCPPFLAGS = $(SHAREDLIBCPPFLAGS)
DYNAMICCFLAGS = $(SHAREDLIBCFLAGS)
DYNAMICCXXFLAGS = $(SHAREDLIBCXXFLAGS)
DEFS = @DEFS@
CPPFLAGS = @CPPFLAGS@ $(LIBCPPFLAGS) -I$(srcdir) -I$(top_builddir)/common -I$(srcdir)/aat -I$(srcdir)/opentype -I$(top_builddir)/common -I$(top_srcdir)/common
CFLAGS = @CFLAGS@
CXXFLAGS = @CXXFLAGS@
ENABLE_RPATH = @ENABLE_RPATH@
ifeq ($(ENABLE_RPATH),YES)
RPATHLDFLAGS = $(LD_RPATH)$(LD_RPATH_PRE)$(libdir)
endif
LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)
#LIBS = $(LIBICUUC) @LIBS@
LIBS= @LIBS@
OBJECTS = $(LAYOUT_OBJS) $(AAT_OBJS:%.o=aat/%.o) $(OPENTYPE_OBJS:%.o=opentype/%.o)
STATIC_OBJECTS = $(OBJECTS:.o=.$(STATIC_O))
DEPS = $(LAYOUT_OBJS:.o=.d)
## Header files to install
HEADERS= $(srcdir)/*.h
## List of phony targets
.PHONY : all all-local install install-local clean clean-local \
distclean distclean-local install-library install-headers dist \
dist-local check check-local
## Clear suffix list
.SUFFIXES :
## List of standard targets
all: all-recursive all-local
install: install-local
clean: clean-recursive clean-local
distclean : distclean-recursive distclean-local
dist: dist-recursive dist-local
check: all check-local
## Recursive targets
all-recursive install-recursive clean-recursive distclean-recursive dist-recursive check-recursive:
@dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-local"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $$local_target) || exit; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) "$$target-local" || exit; \
fi
# end recursion
all-local: $(ALL_TARGETS)
install-local: install-headers install-library
install-library: all-local
$(MKINSTALLDIRS) $(DESTDIR)$(libdir)
ifneq ($(ENABLE_STATIC),)
$(INSTALL-L) $(TARGET) $(DESTDIR)$(libdir)/$(TARGET)
endif
ifneq ($(ENABLE_SHARED),)
$(INSTALL-L) $(FINAL_SO_TARGET) $(DESTDIR)$(libdir)/$(FINAL_SO_TARGET)
ifneq ($(FINAL_SO_TARGET),$(SO_TARGET))
cd $(DESTDIR)$(libdir) && $(RM) $(MIDDLE_SO_TARGET) && ln -s $(FINAL_SO_TARGET) $(MIDDLE_SO_TARGET)
cd $(DESTDIR)$(libdir) && $(RM) $(SO_TARGET) && ln -s $(FINAL_SO_TARGET) $(SO_TARGET)
endif
endif
install-headers:
$(MKINSTALLDIRS) $(DESTDIR)$(includedir)/layout
@for file in $(HEADERS); do \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout || exit; \
done
dist-local:
clean-local:
test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
$(RMV) $(LAYOUT_OBJS) $(ALL_TARGETS)
# $(RMV) $(LAYOUT_OBJS) $(STATIC_OBJECTS) $(ALL_TARGETS)
distclean-local: clean-local
$(RMV) Makefile
check-local:
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
ifneq ($(ENABLE_STATIC),)
$(TARGET): $(TARGET)($(STATIC_OBJECTS))
$(RANLIB) $@
endif
ifneq ($(ENABLE_SHARED),)
$(FINAL_SO_TARGET): $(OBJECTS)
$(SHLIB.cc) $(LD_SONAME) -o $@ $^ $(LIBS)
endif
ifeq (,$(MAKECMDGOALS))
-include $(DEPS)
else
ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),)
-include $(DEPS)
endif
endif

View File

@ -0,0 +1,200 @@
/*
* @(#)OpenTypeLayoutEngine.cpp 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LayoutEngine.h"
#include "OpenTypeLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
#include "GDEFMarkFilter.h"
OpenTypeLayoutEngine::OpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable)
: LayoutEngine(fontInstance, scriptCode, languageCode), fFeatureTags(NULL), fGSUBTable(gsubTable), fSubstitutionFilter(NULL)
{
static le_uint32 gdefTableTag = 0x47444546; // "GDEF"
static le_uint32 gposTableTag = 0x47504F53; // "GPOS"
fGDEFTable = (GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
fGPOSTable = (GlyphPositioningTableHeader *) getFontTable(gposTableTag);
setScriptAndLanguageTags();
}
void OpenTypeLayoutEngine::reset()
{
// NOTE: if we're called from
// the destructor, LayoutEngine;:reset()
// will have been called already by
// LayoutEngine::~LayoutEngine()
LayoutEngine::reset();
// The double call could be avoided by
// puting the following into a private
// method that's called from here and
// from our destructor
if (fFeatureTags != NULL) {
delete[] fFeatureTags;
fFeatureTags = NULL;
}
}
OpenTypeLayoutEngine::OpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: LayoutEngine(fontInstance, scriptCode, languageCode), fFeatureTags(NULL), fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL),
fSubstitutionFilter(NULL)
{
setScriptAndLanguageTags();
}
OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
{
reset();
}
LETag scriptTags[] = {
neutScriptTag, // 'NEUT'
latnScriptTag, // 'latn'
grekScriptTag, // 'grek'
cyrlScriptTag, // 'cyrl'
armnScriptTag, // 'armn' **** Armenian: no MS definition ****
hebrScriptTag, // 'hebr'
arabScriptTag, // 'arab'
devaScriptTag, // 'deva'
bengScriptTag, // 'beng'
punjScriptTag, // 'punj' punjabi == gurmukhi
gujrScriptTag, // 'gujr'
oryaScriptTag, // 'orya'
tamlScriptTag, // 'taml'
teluScriptTag, // 'telu'
kndaScriptTag, // 'knda'
mlymScriptTag, // 'mlym'
thaiScriptTag, // 'thai'
laoScriptTag, // 'lao ' **** Lao: no MS definition ****
tibtScriptTag, // 'tibt'
grgnScriptTag, // 'grgn' **** Georgian: no MS definition ****
hangScriptTag, // 'hang'
kanaScriptTag, // 'kana'
bpmfScriptTag, // 'bpmf' **** Bopomofo: no MS definition ****
knbnScriptTag, // 'knbn' **** Kanbun: no MS definition ****
haniScriptTag, // 'hani'
surrScriptTag, // 'SURR'
puseScriptTag, // 'PUSE'
spclScriptTag // 'SPCL'
};
LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
{
if (scriptCode == -1) {
return -1;
}
return scriptTags[scriptCode];
}
LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
{
// FIXME: do this for real some day (soon?)
return -1;
}
void OpenTypeLayoutEngine::setScriptAndLanguageTags()
{
fScriptTag = getScriptTag(fScriptCode);
fLangSysTag = getLangSysTag(fLanguageCode);
}
// Input: characters, tags
// Output: glyphs, char indices
le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, const LETag **featureTags,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphs, charIndices);
if (fGSUBTable != NULL) {
fGSUBTable->process(glyphs, featureTags, count, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter);
}
return count;
}
le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphID *&glyphs, le_int32 *&charIndices)
{
LEUnicode *outChars = NULL;
LEGlyphID *fakeGlyphs = NULL;
le_int32 *tempCharIndices = NULL;
le_int32 outCharCount, outGlyphCount, fakeGlyphCount;
outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, tempCharIndices, fFeatureTags);
if (outChars != NULL) {
fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fFeatureTags, fakeGlyphs, tempCharIndices);
//adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
} else {
fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fFeatureTags, fakeGlyphs, tempCharIndices);
//adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
}
outGlyphCount = glyphPostProcessing(fakeGlyphs, tempCharIndices, fakeGlyphCount, glyphs, charIndices);
if (outChars != chars) {
delete[] outChars;
}
if (fakeGlyphs != glyphs) {
delete[] fakeGlyphs;
}
if (tempCharIndices != charIndices) {
delete[] tempCharIndices;
}
return outGlyphCount;
}
// apply GPOS table, if any
void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
LEGlyphID glyphs[], le_int32 glyphCount, float positions[])
{
if (fGPOSTable != NULL) {
GlyphPositionAdjustment *adjustments = new GlyphPositionAdjustment[glyphCount];
fGPOSTable->process(glyphs, adjustments, fFeatureTags, glyphCount, reverse, fScriptTag, fLangSysTag, fGDEFTable, fFontInstance);
float xAdjust = 0, yAdjust = 0;
le_int32 i;
for (i = 0; i < glyphCount; i += 1) {
float xPlacement = fFontInstance->xUnitsToPoints(adjustments[i].getXPlacement());
float xAdvance = fFontInstance->xUnitsToPoints(adjustments[i].getXAdvance());
float yPlacement = fFontInstance->yUnitsToPoints(adjustments[i].getYPlacement());
float yAdvance = fFontInstance->yUnitsToPoints(adjustments[i].getYAdvance());
xAdjust += xPlacement;
yAdjust += yPlacement;
positions[i*2] += xAdjust;
positions[i*2+1] += yAdjust;
xAdjust += xAdvance;
yAdjust += yAdvance;
}
positions[glyphCount*2] += xAdjust;
positions[glyphCount*2+1] += yAdjust;
delete[] adjustments;
}
delete[] fFeatureTags;
fFeatureTags = NULL;
}

View File

@ -0,0 +1,280 @@
/*
* @(#)OpenTypeLayoutEngine.h 1.4 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __OPENTYPELAYOUTENGINE_H
#define __OPENTYPELAYOUTENGINE_H
#include "LETypes.h"
#include "LEGlyphFilter.h"
#include "LEFontInstance.h"
#include "LayoutEngine.h"
#include "GlyphSubstitutionTables.h"
#include "GlyphDefinitionTables.h"
#include "GlyphPositioningTables.h"
/**
* OpenTypeLayoutEngine implements complex text layout for OpenType fonts - that is
* fonts which have GSUB and GPOS tables associated with them. In order to do this,
* the glyph processsing step described for LayoutEngine is further broken into three
* steps:
*
* 1) Character processing - this step analyses the characters and assigns a list of OpenType
* feature tags to each one. It may also change, remove or add characters, and change
* their order.
*
* 2) Glyph processing - This step performs character to glyph mapping,and uses the GSUB
* table associated with the font to perform glyph substitutions, such as ligature substitution.
*
* 3) Glyph post processing - in cases where the font doesn't directly contain a GSUB table,
* the previous two steps may have generated "fake" glyph indices to use with a "canned" GSUB
* table. This step turns those glyph indices into actual font-specific glyph indices, and may
* perform any other adjustments requried by the previous steps.
*
* OpenTypeLayoutEngine will also use the font's GPOS table to apply position adjustments
* such as kerning and accent positioning.
*
* @see LayoutEngine
*/
class OpenTypeLayoutEngine : public LayoutEngine
{
public:
/**
* This is the main constructor. It constructs an instance of OpenTypeLayoutEngine for
* a particular font, script and language. It takes the GSUB table as a parameter since
* LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
* OpenType font.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
* @param gsubTable - the GSUB table
*
* @see LayoutEngine::layoutEngineFactory
* @see ScriptAndLangaugeTags.h for script and language codes
*/
OpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
GlyphSubstitutionTableHeader *gsubTable);
/**
* This constructor is used when the font requires a "canned" GSUB table which can't be known
* until after this constructor has been invoked.
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param langaugeCode - the language
*/
OpenTypeLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~OpenTypeLayoutEngine();
/**
* A convenience method used to convert the script code into
* the four byte script tag required by OpenType.
*
* @param scriptCode - the script code
*
* @return the four byte script tag
*/
static LETag getScriptTag(le_int32 scriptCode);
/**
* A convenience method used to convert the langauge code into
* the four byte langauge tag required by OpenType.
*
* @param languageCode - the language code
*
* @return the four byte language tag
*/
static LETag getLangSysTag(le_int32 languageCode);
private:
/**
* This method is used by the constructors to convert the script
* and language codes to four byte tags and save them.
*/
void setScriptAndLanguageTags();
protected:
/**
* An array of pointers to four byte feature tags.
* Each pointer points to a list of tags, terminated
* by a special empty tag.
*/
const LETag **fFeatureTags;
/**
* The address of the GSUB table.
*/
GlyphSubstitutionTableHeader *fGSUBTable;
/**
* The address of the GDEF table.
*/
GlyphDefinitionTableHeader *fGDEFTable;
/**
* The address of the GPOS table.
*/
GlyphPositioningTableHeader *fGPOSTable;
/**
* An optional filter used to inhibit substitutions
* preformed by the GSUB table. This is used for some
* "canned" GSUB tables to restrict substitutions to
* glyphs that are in the font.
*/
LEGlyphFilter *fSubstitutionFilter;
/**
* The four byte script tag.
*/
LETag fScriptTag;
/**
* The four byte language tag
*/
LETag fLangSysTag;
/**
* This method does the OpenType character processing. It assigns the OpenType feature
* tags to the characters, and may generate output characters that differ from the input
* charcters dueto insertions, deletions, or reorderings. In such cases, it will also
* generate an output character index array reflecting these changes.
*
* Subclasses must override this method.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characters are in a right to left directional run
*
* Output parameters:
* @param outChars - the output character array, if different from the input
* @param charIndices - the output character index array
* @param featureTags - the output feature tag array
*
* @return the output character count (input character count if no change)
*/
virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEUnicode *&outChars, le_int32 *&charIndices, const LETag **&featureTags) /*= 0;*/
{
return count;
};
/**
* This method does character to glyph mapping, and applies the GSUB table. The
* default implementation calls mapCharsToGlyphs and then applies the GSUB table,
* if there is one.
*
* Note that in the case of "canned" GSUB tables, the output glyph indices may be
* "fake" glyph indices that need to be converted to "real" glyph indices by the
* glyphPostProcessing method.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the characters are in a right to left directional run
* @param featureTags - the feature tag array
*
* Output parameters:
* @param glyphs - the output glyph index array
* @param charIndices - the output character index array
*
* @return the number of glyphs in the output glyph index array
*
* Note: if the character index array was already set by the characterProcessing
* method, this method won't change it.
*/
virtual le_int32 glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
const LETag **featureTags, LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method does any processing necessary to convert "fake"
* glyph indices used by the glyphProcessing method into "real" glyph
* indices which can be used to render the text. Note that in some
* cases, such as CDAC Indic fonts, several "real" glyphs may be needed
* to render one "fake" glyph.
*
* The default implementation of this method just returns the input glyph
* index and character index arrays, assuming that no "fake" glyph indices
* were needed to do GSUB processing.
*
* Input paramters:
* @param tempGlyphs - the input "fake" glyph index array
* @param tempCharIndices - the input "fake" character index array
* @param tempGlyphCount - the number of "fake" glyph indices
*
* Output parameters:
* @param glyphs - the output glyph index array
* @param charIndices - the output character index array
*
* @return the number of glyph indices in the output glyph index array
*/
virtual le_int32 glyphPostProcessing(LEGlyphID tempGlyphs[], le_int32 tempCharIndices[], le_int32 tempGlyphCount,
LEGlyphID *&glyphs, le_int32 *&charIndices)
{
glyphs = tempGlyphs;
charIndices = tempCharIndices;
return tempGlyphCount;
};
/**
* This method applies the characterProcessing, glyphProcessing and glyphPostProcessing
* methods. Most subclasses will not need to override this method.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the text is in a right to left directional run
*
* Output parameters:
* @param glyphs - the glyph index array
* @param charIndices - the character index array
*
* @return the number of glyphs in the glyph index array
*
* @see LayoutEngine::computeGlyphs
*/
virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphID *&glyphs, le_int32 *&charIndices);
/**
* This method uses the GPOS table, if there is one, to adjust the glyph positions.
*
* Input parameters:
* @param glyphs - the input glyph array
* @param glyphCount - the number of glyphs in the glyph array
* @param x - the starting X position
* @param y - the starting Y position
*
* Output parameters:
* @param positions - the output X and Y positions (two entries per glyph)
*/
virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphID glyphs[], le_int32 glyphCount, float positions[]);
/**
* This method frees the feature tag array so that the
* OpenTypeLayoutEngine can be reused for different text.
* It is also called from our destructor.
*/
virtual void reset();
};
#endif

View File

@ -0,0 +1,67 @@
/*
* @(#)ThaiLayoutEngine.cpp 1.2 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LayoutEngine.h"
#include "ThaiLayoutEngine.h"
#include "ScriptAndLanguageTags.h"
#include "ThaiShaping.h"
ThaiLayoutEngine::ThaiLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
: LayoutEngine(fontInstance, scriptCode, languageCode)
{
fErrorChar = 0x25CC;
// Figure out which presentation forms the font uses
if (fontInstance->canDisplay(0x0E64)) {
// WorldType uses reserved space in Thai block
fGlyphSet = 0;
} else if (fontInstance->canDisplay(0xF701)) {
// Microsoft corporate zone
fGlyphSet = 1;
if (!fontInstance->canDisplay(fErrorChar)) {
fErrorChar = 0xF71B;
}
} else if (fontInstance->canDisplay(0xF885)) {
// Apple corporate zone
fGlyphSet = 2;
} else {
// no presentation forms in the font
fGlyphSet = 3;
}
}
ThaiLayoutEngine::~ThaiLayoutEngine()
{
// nothing to do
}
// Input: characters (0..max provided for context)
// Output: glyphs, char indices
// Returns: the glyph count
// NOTE: this assumes that ThaiShaping::compose will allocate the outChars array...
le_int32 ThaiLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphID *&glyphs, le_int32 *&charIndices)
{
LEUnicode *outChars;
le_int32 glyphCount;
// This is enough room for the worst-case expansion
// (it says here...)
outChars = new LEUnicode[count * 2];
charIndices = new le_int32[count * 2];
glyphCount = ThaiShaping::compose(chars, offset, count, fGlyphSet, fErrorChar, outChars, charIndices);
mapCharsToGlyphs(outChars, 0, glyphCount, false, false, glyphs, charIndices);
delete[] outChars;
return glyphCount;
}

View File

@ -0,0 +1,90 @@
/*
* @(#)ThaiLayoutEngine.h 1.3 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __THAILAYOUTENGINE_H
#define __THAILAYOUTENGINE_H
#include "LETypes.h"
#include "LEFontInstance.h"
#include "LayoutEngine.h"
#include "ThaiShaping.h"
/**
* This class implements layout for the Thai script, using the ThaiShapingClass.
* All existing Thai fonts use an encoding which assigns character codes to all
* the variant forms needed to display accents and tone marks correctly in context.
* This class can deal with fonts using the Microsoft, Macintosh, and WorldType encodings.
*/
class ThaiLayoutEngine : public LayoutEngine
{
public:
/**
* This constructs an instance of ThaiLayoutEngine for the given font, script and
* language. It examines the font, using LEFontInstance::canDisplay, to set fGlyphSet
* and fErrorChar. (see below)
*
* @param fontInstance - the font
* @param scriptCode - the script
* @param languageCode - the language
*
* @see LEFontInstance
* @see ScriptAndLanguageTags.h for script and language codes
*/
ThaiLayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode);
/**
* The destructor, virtual for correct polymorphic invocation.
*/
virtual ~ThaiLayoutEngine();
protected:
/**
* A small integer indicating which Thai encoding
* the font uses.
*
* @see ThaiShaping
*/
le_uint8 fGlyphSet;
/**
* The character used as a base for vowels and
* tone marks that are out of sequence. Usually
* this will be Unicode 0x25CC, if the font can
* display it.
*
* @see ThaiShaping
*/
LEUnicode fErrorChar;
/**
* This method performs Thai layout. It calls ThaiShaping::compose to
* generate the correct contextual character codes, and then calls
* mapCharsToGlyphs to generate the glyph indices.
*
* Input parameters:
* @param chars - the input character context
* @param offset - the index of the first character to process
* @param count - the number of characters to process
* @param max - the number of characters in the input context
* @param rightToLeft - true if the text is in a right to left directional run
*
* Output parameters:
* @param glyphs - the glyph index array
* @param charIndices - the character index array
*
* @return the number of glyphs in the glyph index array
*
* @see ThaiShaping
*/
virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
LEGlyphID *&glyphs, le_int32 *&charIndices);
};
#endif

View File

@ -0,0 +1,354 @@
/*
* @(#)ThaiShaping.cpp 1.13 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "LEGlyphFilter.h"
#include "OpenTypeTables.h"
#include "ThaiShaping.h"
enum {
CH_SPACE = 0x0020,
CH_YAMAKKAN = 0x0E4E,
CH_MAI_HANAKAT = 0x0E31,
CH_SARA_AA = 0x0E32,
CH_SARA_AM = 0x0E33,
CH_SARA_UEE = 0x0E37,
CH_MAITAIKHU = 0x0E47,
CH_NIKHAHIT = 0x0E4D,
CH_SARA_U = 0x0E38,
CH_PHINTHU = 0x0E3A,
CH_YO_YING = 0x0E0D,
CH_THO_THAN = 0x0E10,
CH_DOTTED_CIRCLE = 0x25CC
};
le_uint8 ThaiShaping::getCharClass(LEUnicode ch)
{
le_uint8 charClass = NON;
if (ch >= 0x0E00 && ch <= 0x0E5B) {
charClass = classTable[ch - 0x0E00];
}
return charClass;
}
LEUnicode ThaiShaping::leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet)
{
static LEUnicode leftAboveVowels[][7] = {
{0x0E61, 0x0E32, 0x0E33, 0x0E64, 0x0E65, 0x0E66, 0x0E67},
{0xF710, 0x0E32, 0x0E33, 0xF701, 0xF702, 0xF703, 0xF704},
{0xF884, 0x0E32, 0x0E33, 0xF885, 0xF886, 0xF887, 0xF788},
{0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37}
};
if (vowel >= CH_MAI_HANAKAT && vowel <= CH_SARA_UEE) {
return leftAboveVowels[glyphSet][vowel - CH_MAI_HANAKAT];
}
if (vowel == CH_YAMAKKAN && glyphSet == 0) {
return 0x0E7E;
}
return vowel;
}
LEUnicode ThaiShaping::lowerRightTone(LEUnicode tone, le_uint8 glyphSet)
{
static LEUnicode lowerRightTones[][7] = {
{0x0E68, 0x0E69, 0x0E6A, 0x0E6B, 0x0E6C, 0x0E6D, 0x0E6E},
{0x0E47, 0xF70A, 0xF70B, 0xF70C, 0xF70D, 0xF70E, 0x0E4D},
{0x0E47, 0xF88B, 0xF88E, 0xF891, 0xF894, 0xF897, 0x0E4D},
{0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
};
if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
return lowerRightTones[glyphSet][tone - CH_MAITAIKHU];
}
return tone;
}
LEUnicode ThaiShaping::lowerLeftTone(LEUnicode tone, le_uint8 glyphSet)
{
static LEUnicode lowerLeftTones[][7] = {
{0x0E76, 0x0E77, 0x0E78, 0x0E79, 0x0E7A, 0x0E7B, 0x0E7C},
{0xF712, 0xF705, 0xF706, 0xF707, 0xF708, 0xF709, 0xF711},
{0xF889, 0xF88C, 0xF88F, 0xF892, 0xF895, 0xF898, 0xF899},
{0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
};
if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
return lowerLeftTones[glyphSet][tone - CH_MAITAIKHU];
}
return tone;
}
LEUnicode ThaiShaping::upperLeftTone(LEUnicode tone, le_uint8 glyphSet)
{
static LEUnicode upperLeftTones[][7] = {
{0x0E6F, 0x0E70, 0x0E71, 0x0E72, 0x0E73, 0x0E74, 0x0E75},
{0xF712, 0xF713, 0xF714, 0xF715, 0xF716, 0xF717, 0xF711},
{0xF889, 0xF88A, 0xF88D, 0xF890, 0xF893, 0xF896, 0xF899},
{0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
};
if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
return upperLeftTones[glyphSet][tone - CH_MAITAIKHU];
}
return tone;
}
LEUnicode ThaiShaping::lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet)
{
static LEUnicode lowerBelowVowels[][3] = {
{0x0E3C, 0x0E3D, 0x0E3E},
{0xF718, 0xF719, 0xF71A},
{0x0E38, 0x0E39, 0x0E3A},
{0x0E38, 0x0E39, 0x0E3A}
};
if (vowel >= CH_SARA_U && vowel <= CH_PHINTHU) {
return lowerBelowVowels[glyphSet][vowel - CH_SARA_U];
}
return vowel;
}
LEUnicode ThaiShaping::noDescenderCOD(LEUnicode cod, le_uint8 glyphSet)
{
static LEUnicode noDescenderCODs[][4] = {
{0x0E60, 0x0E0E, 0x0E0F, 0x0E63},
{0xF70F, 0x0E0E, 0x0E0F, 0xF700},
{0x0E0D, 0x0E0E, 0x0E0F, 0x0E10},
{0x0E0D, 0x0E0E, 0x0E0F, 0x0E10}
};
if (cod >= CH_YO_YING && cod <= CH_THO_THAN) {
return noDescenderCODs[glyphSet][cod - CH_YO_YING];
}
return cod;
}
le_uint8 ThaiShaping::doTransition (StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
LEUnicode errorChar, LEUnicode *outputBuffer, le_int32 *charIndicies, le_int32 &outputIndex)
{
switch (transition.action) {
case _A:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
case _C:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
case _D:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = leftAboveVowel(currChar, glyphSet);
break;
case _E:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = lowerRightTone(currChar, glyphSet);
break;
case _F:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = lowerLeftTone(currChar, glyphSet);
break;
case _G:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = upperLeftTone(currChar, glyphSet);
break;
case _H:
{
LEUnicode cod = outputBuffer[outputIndex - 1];
LEUnicode coa = noDescenderCOD(cod, glyphSet);
if (cod != coa) {
outputBuffer[outputIndex - 1] = coa;
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
}
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = lowerBelowVowel(currChar, glyphSet);
break;
}
case _R:
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = errorChar;
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
case _S:
if (currChar == CH_SARA_AM) {
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = errorChar;
}
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
default:
// FIXME: if we get here, there's an error
// in the state table!
charIndicies[outputIndex] = inputIndex;
outputBuffer[outputIndex++] = currChar;
break;
}
return transition.nextState;
}
le_uint8 ThaiShaping::getNextState(LEUnicode ch, le_uint8 prevState, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
le_uint8 &charClass, LEUnicode *output, le_int32 *charIndicies, le_int32 &outputIndex)
{
StateTransition transition;
charClass = getCharClass(ch);
transition = getTransition(prevState, charClass);
return doTransition(transition, ch, inputIndex, glyphSet, errorChar, output, charIndicies, outputIndex);
}
le_bool ThaiShaping::isLegalHere(LEUnicode ch, le_uint8 prevState)
{
le_uint8 charClass = getCharClass(ch);
StateTransition transition = getTransition(prevState, charClass);
switch (transition.action) {
case _A:
case _C:
case _D:
case _E:
case _F:
case _G:
case _H:
return true;
case _R:
case _S:
return false;
default:
// FIXME: if we get here, there's an error
// in the state table!
return false;
}
}
le_int32 ThaiShaping::compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
LEUnicode errorChar, LEUnicode *output, le_int32 *charIndicies)
{
le_uint8 state = 0;
le_int32 inputIndex;
le_int32 outputIndex = 0;
le_uint8 conState = -1;
le_int32 conInput = -1;
le_int32 conOutput = -1;
for (inputIndex = 0; inputIndex < charCount; inputIndex += 1) {
LEUnicode ch = input[inputIndex + offset];
le_uint8 charClass;
// Decompose SARA AM into NIKHAHIT + SARA AA
if (ch == CH_SARA_AM && isLegalHere(ch, state)) {
outputIndex = conOutput;
state = getNextState(CH_NIKHAHIT, conState, inputIndex, glyphSet, errorChar, charClass,
output, charIndicies, outputIndex);
for (int j = conInput + 1; j < inputIndex; j += 1) {
ch = input[j + offset];
state = getNextState(ch, state, j, glyphSet, errorChar, charClass,
output, charIndicies, outputIndex);
}
ch = CH_SARA_AA;
}
state = getNextState(ch, state, inputIndex, glyphSet, errorChar, charClass,
output, charIndicies, outputIndex);
if (charClass >= CON && charClass <= COD) {
conState = state;
conInput = inputIndex;
conOutput = outputIndex;
}
}
return outputIndex;
}
ThaiMarkFilter::ThaiMarkFilter(le_uint8 glyphSet)
: rangeList(NULL)
{
static MarkRange glyphSet0MarkRanges[] =
{
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0E61, 0x0E61}, {0x0E64, 0x0E7C}, {0xFFFF, 0xFFFF}
};
static MarkRange glyphSet1MarkRanges[] =
{
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0xF701, 0xF70E}, {0xF710, 0xF71A}, {0xFFFF, 0xFFFF}
};
static MarkRange glyphSet2MarkRanges[] =
{
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0xF884, 0xF899}, {0xFFFF, 0xFFFF}
};
static MarkRange glyphSet3MarkRanges[] =
{
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0xFFFF, 0xFFFF}
};
static MarkRange *rangeTable[] =
{glyphSet0MarkRanges, glyphSet1MarkRanges, glyphSet2MarkRanges, glyphSet3MarkRanges};
if (glyphSet <= 3) {
rangeList = rangeTable[glyphSet];
}
}
ThaiMarkFilter::~ThaiMarkFilter()
{
// nothing to do here...
}
le_bool ThaiMarkFilter::filter(LEGlyphID glyph)
{
le_int32 i;
if (rangeList != NULL) {
for (i = 0; rangeList[i].first <= glyph; i += 1) {
if (rangeList[i].last >= glyph) {
return true;
}
}
}
return false;
}

View File

@ -0,0 +1,114 @@
/*
* @(#)ThaiShaping.h 1.9 00/03/15
*
* (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved
*
*/
#ifndef __THAISHAPING_H
#define __THAISHAPING_H
#include "LETypes.h"
#include "LEGlyphFilter.h"
#include "OpenTypeTables.h"
class ThaiMarkFilter : public LEGlyphFilter
{
private:
struct MarkRange
{
LEUnicode first;
LEUnicode last;
};
MarkRange *rangeList;
public:
ThaiMarkFilter(le_uint8 glyphSet);
~ThaiMarkFilter();
virtual le_bool filter(LEGlyphID glyph);
};
class ThaiShaping
{
public:
enum {
// Character classes
NON = 0,
CON = 1,
COA = 2,
COD = 3,
LVO = 4,
FV1 = 5,
FV2 = 6,
FV3 = 7,
BV1 = 8,
BV2 = 9,
BDI = 10,
TON = 11,
AD1 = 12,
AD2 = 13,
AD3 = 14,
NIK = 15,
AV1 = 16,
AV2 = 17,
AV3 = 18,
classCount = 19,
// State Transition actions
_A = 0,
_C = 1,
_D = 2,
_E = 3,
_F = 4,
_G = 5,
_H = 6,
_R = 7,
_S = 8
};
struct StateTransition
{
le_uint8 nextState;
le_uint8 action;
le_uint8 getNextState() { return nextState; };
le_uint8 getAction() { return action; };
};
static le_int32 compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
LEUnicode errorChar, LEUnicode *output, le_int32 *charIndicies);
private:
static le_uint8 classTable[];
static StateTransition thaiStateTable[][classCount];
static StateTransition getTransition(le_uint8 state, le_uint8 currClass);
static le_uint8 doTransition(StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
LEUnicode errorChar, LEUnicode *outputBuffer, le_int32 *charIndicies, le_int32 &outputIndex);
static le_uint8 getNextState(LEUnicode ch, le_uint8 state, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
le_uint8 &charClass, LEUnicode *output, le_int32 *charIndicies, le_int32 &outputIndex);
static le_bool isLegalHere(LEUnicode ch, le_uint8 prevState);
static le_uint8 getCharClass(LEUnicode ch);
static LEUnicode noDescenderCOD(LEUnicode cod, le_uint8 glyphSet);
static LEUnicode leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet);
static LEUnicode lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet);
static LEUnicode lowerRightTone(LEUnicode tone, le_uint8 glyphSet);
static LEUnicode lowerLeftTone(LEUnicode tone, le_uint8 glyphSet);
static LEUnicode upperLeftTone(LEUnicode tone, le_uint8 glyphSet);
};
inline ThaiShaping::StateTransition ThaiShaping::getTransition(le_uint8 state, le_uint8 currClass)
{
return thaiStateTable[state][currClass];
}
#endif

View File

@ -0,0 +1,84 @@
/*
* @(#)ThaiStateTables.cpp 1.8 00/03/15
*
* (C) Copyright IBM Corp. 1999, 2000 - All Rights Reserved
*
* WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
* YOU REALLY KNOW WHAT YOU'RE DOING.
*
*/
#include "LETypes.h"
#include "ThaiShaping.h"
le_uint8 ThaiShaping::classTable[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
// -------------------------------------------------------------------------------
/*0E00*/ NON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, COD, COD, COD,
/*0E10*/ COD, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, COA, CON, COA, CON, COA,
/*0E20*/ CON, CON, CON, CON, FV3, CON, FV3, CON, CON, CON, CON, CON, CON, CON, CON, NON,
/*0E30*/ FV1, AV2, FV1, FV1, AV1, AV3, AV2, AV3, BV1, BV2, BDI, NON, NON, NON, NON, NON,
/*0E40*/ LVO, LVO, LVO, LVO, LVO, FV2, NON, AD2, TON, TON, TON, TON, AD1, NIK, AD3, NON,
/*0E50*/ NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON
};
ThaiShaping::StateTransition ThaiShaping::thaiStateTable[][ThaiShaping::classCount] = {
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| N C C C L F F F B B B T A A A N A A A |
//| O O O O V V V V V V D O D D D I V V V |
//| N N A D O 1 2 3 1 2 I N 1 2 3 K 1 2 3 |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
/*00*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*01*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 2, _C}, { 6, _C}, { 0, _C}, { 8, _E}, { 0, _E}, { 0, _E}, { 0, _C}, { 9, _E}, {11, _C}, {14, _C}, {16, _C}},
/*02*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 3, _E}, { 0, _E}, { 0, _R}, { 0, _R}, { 4, _E}, { 0, _R}, { 0, _R}, { 0, _R}},
/*03*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*04*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 5, _C}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*05*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*06*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 7, _E}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*07*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*08*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*09*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {10, _C}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*10*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*11*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {12, _C}, { 0, _C}, { 0, _R}, { 0, _R}, {13, _C}, { 0, _R}, { 0, _R}, { 0, _R}},
/*12*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*13*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*14*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {15, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*15*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*16*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {17, _C}, { 0, _R}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*17*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*18*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _S}, { 0, _A}, {19, _C}, {23, _C}, { 0, _C}, {25, _F}, { 0, _F}, { 0, _F}, { 0, _D}, {26, _F}, {28, _D}, {31, _D}, {33, _D}},
/*19*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {20, _F}, { 0, _F}, { 0, _R}, { 0, _R}, {21, _F}, { 0, _R}, { 0, _R}, { 0, _R}},
/*20*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*21*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {22, _C}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*22*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*23*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {24, _F}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*24*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*25*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*26*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {27, _G}, { 0, _G}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*27*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*28*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {29, _G}, { 0, _G}, { 0, _R}, { 0, _R}, {30, _G}, { 0, _R}, { 0, _R}, { 0, _R}},
/*29*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*30*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*31*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {32, _G}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*32*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*33*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {34, _G}, { 0, _R}, { 0, _G}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*34*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*35*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _S}, { 0, _A}, {36, _H}, {40, _H}, { 0, _H}, {42, _E}, { 0, _E}, { 0, _E}, { 0, _C}, {43, _E}, {45, _C}, {48, _C}, {50, _C}},
/*36*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {37, _E}, { 0, _E}, { 0, _R}, { 0, _R}, {38, _E}, { 0, _R}, { 0, _R}, { 0, _R}},
/*37*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*38*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {39, _C}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*39*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*40*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {41, _E}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*41*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*42*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*43*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {44, _C}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*44*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*45*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {46, _C}, { 0, _C}, { 0, _R}, { 0, _R}, {47, _C}, { 0, _R}, { 0, _R}, { 0, _R}},
/*46*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*47*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*48*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {49, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*49*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*50*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _S}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, {51, _C}, { 0, _R}, { 0, _C}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}},
/*51*/ {{ 0, _A}, { 1, _A}, {18, _A}, {35, _A}, { 0, _A}, { 0, _S}, { 0, _A}, { 0, _A}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}, { 0, _R}}
};

File diff suppressed because it is too large Load Diff

View File

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