1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LETypes.h"
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LEScripts.h"
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LELanguages.h"
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LayoutEngine.h"
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ArabicLayoutEngine.h"
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "CanonShaping.h"
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "HanLayoutEngine.h"
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "HangulLayoutEngine.h"
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "IndicLayoutEngine.h"
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "KhmerLayoutEngine.h"
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ThaiLayoutEngine.h"
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "TibetanLayoutEngine.h"
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "GXLayoutEngine.h"
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ScriptAndLanguageTags.h"
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "CharSubstitutionFilter.h"
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LEGlyphStorage.h"
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "OpenTypeUtilities.h"
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "GlyphSubstitutionTables.h"
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "GlyphDefinitionTables.h"
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "MorphTables.h"
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "DefaultCharMapper.h"
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "KernTable.h"
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/* Leave this copyright notice here! It needs to go somewhere in this library. */
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const char copyright[] = U_COPYRIGHT_STRING;
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruconst LEUnicode32 DefaultCharMapper::controlChars[] = {
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    0x0009, 0x000A, 0x000D,
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /*0x200C, 0x200D,*/ 0x200E, 0x200F,
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruconst le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fFilterControls) {
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (controlChars[index] == ch) {
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 0xFFFF;
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fMirror) {
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount);
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (mirroredChars[index] == ch) {
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return DefaultCharMapper::srahCderorrim[index];
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return ch;
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// This is here to get it out of LEGlyphFilter.h.
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// No particular reason to put it here, other than
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// this is a good central location...
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLEGlyphFilter::~LEGlyphFilter()
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // nothing to do
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruCharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  : fFontInstance(fontInstance)
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // nothing to do
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruCharSubstitutionFilter::~CharSubstitutionFilter()
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // nothing to do
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruclass CanonMarkFilter : public UMemory, public LEGlyphFilter
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruprivate:
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const GlyphClassDefinitionTable *classDefTable;
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querupublic:
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable);
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    virtual ~CanonMarkFilter();
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    virtual le_bool accept(LEGlyphID glyph) const;
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruCanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    classDefTable = gdefTable->getMarkAttachClassDefinitionTable();
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruCanonMarkFilter::~CanonMarkFilter()
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // nothing to do?
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querule_bool CanonMarkFilter::accept(LEGlyphID glyph) const
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 glyphClass = classDefTable->getGlyphClass(glyph);
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return glyphClass != 0;
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define ccmpFeatureTag  LE_CCMP_FEATURE_TAG
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define ccmpFeatureMask 0x80000000UL
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define canonFeatures (ccmpFeatureMask)
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const FeatureMap canonFeatureMap[] =
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {ccmpFeatureTag, ccmpFeatureMask}
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap);
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
13785bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoLayoutEngine::LayoutEngine(const LEFontInstance *fontInstance,
13885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                           le_int32 scriptCode,
13985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                           le_int32 languageCode,
14085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                           le_int32 typoFlags,
14185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                           LEErrorCode &success)
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
14385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    fTypoFlags(typoFlags), fFilterZeroWidth(TRUE)
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
14585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (LE_FAILURE(success)) {
14685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return;
14785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
14885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage = new LEGlyphStorage();
15085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (fGlyphStorage == NULL) {
15185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        success = LE_MEMORY_ALLOCATION_ERROR;
15285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querule_int32 LayoutEngine::getGlyphCount() const
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return fGlyphStorage->getGlyphCount();
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getCharIndices(charIndices, indexBase, success);
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getCharIndices(charIndices, success);
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getGlyphs(glyphs, extraBits, success);
174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getGlyphs(glyphs, success);
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getGlyphPositions(positions, success);
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querule_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
19385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 i, dir = 1, out = 0, outCharCount = count;
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (canonGSUBTable->coversScript(scriptTag)) {
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
21185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (substitutionFilter == NULL) {
21285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            success = LE_MEMORY_ALLOCATION_ERROR;
21385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            return 0;
21485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
21585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		const LEUnicode *inChars = &chars[offset];
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		LEUnicode *reordered = NULL;
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        LEGlyphStorage fakeGlyphStorage;
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (LE_FAILURE(success)) {
22385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            delete substitutionFilter;
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 0;
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		// This is the cheapest way to get mark reordering only for Hebrew.
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		// We could just do the mark reordering for all scripts, but most
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		// of them probably don't need it...
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		if (fScriptCode == hebrScriptCode) {
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			reordered = LE_NEW_ARRAY(LEUnicode, count);
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			if (reordered == NULL) {
23485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                delete substitutionFilter;
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru				success = LE_MEMORY_ALLOCATION_ERROR;
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru				return 0;
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			}
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			inChars = reordered;
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fakeGlyphStorage.allocateAuxData(success);
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (LE_FAILURE(success)) {
24685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            delete substitutionFilter;
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 0;
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (rightToLeft) {
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            out = count - 1;
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dir = -1;
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (i = 0; i < count; i += 1, out += dir) {
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            fakeGlyphStorage.setAuxData(out, canonFeatures, success);
258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		if (reordered != NULL) {
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			LE_DELETE_ARRAY(reordered);
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		}
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
26485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success);
26585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
26685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (LE_FAILURE(success)) {
26785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            delete substitutionFilter;
26885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            return 0;
26985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        out = (rightToLeft? outCharCount - 1 : 0);
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
27385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        /*
27485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho         * The char indices array in fakeGlyphStorage has the correct mapping
27585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho         * back to the original input characters. Save it in glyphStorage. The
27685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho         * subsequent call to glyphStoratge.allocateGlyphArray will keep this
27785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho         * array rather than allocating and initializing a new one.
27885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho         */
27985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        glyphStorage.adoptCharIndicesArray(fakeGlyphStorage);
28085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
28285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
28385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (outChars == NULL) {
28485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            delete substitutionFilter;
28585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            success = LE_MEMORY_ALLOCATION_ERROR;
28685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            return 0;
28785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
28885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (i = 0; i < outCharCount; i += 1, out += dir) {
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete substitutionFilter;
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return outCharCount;
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querule_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                            LEGlyphStorage &glyphStorage, LEErrorCode &success)
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LEUnicode *outChars = NULL;
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (outChars != NULL) {
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return glyphStorage.getGlyphCount();
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Input: glyphs
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Output: positions
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.allocatePositions(success);
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 i, glyphCount = glyphStorage.getGlyphCount();
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (i = 0; i < glyphCount; i += 1) {
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        LEPoint advance;
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        glyphStorage.setPosition(i, x, y, success);
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        x += advance.fX;
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        y += advance.fY;
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.setPosition(glyphCount, x, y, success);
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool  reverse,
354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                        LEGlyphStorage &glyphStorage, LEErrorCode &success)
355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
359ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
360ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (chars == NULL || offset < 0 || count < 0) {
361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
362ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
364ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
365ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    CanonMarkFilter filter(gdefTable);
367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
370ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fTypoFlags & 0x1) { /* kerning enabled */
371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      KernTable kt(fFontInstance, getFontTable(kernTableTag));
374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      kt.process(glyphStorage);
375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
377ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // default is no adjustments
378ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
379ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    float xAdjust = 0;
384ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 p, glyphCount = glyphStorage.getGlyphCount();
385ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
386ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
387ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (markFilter == NULL) {
391ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
392ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
393ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
394ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    float ignore, prev;
396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.getGlyphPosition(0, prev, ignore, success);
398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (p = 0; p < glyphCount; p += 1) {
400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        float next, xAdvance;
401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        xAdvance = next - prev;
405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        glyphStorage.adjustPosition(p, xAdjust, 0, success);
406ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
407ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (markFilter->accept(glyphStorage[p])) {
408ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            xAdjust -= xAdvance;
409ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
410ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
411ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        prev = next;
412ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
413ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
414ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
415ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
416ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
417ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
418ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
419ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    float xAdjust = 0;
420ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 c = 0, direction = 1, p;
421ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 glyphCount = glyphStorage.getGlyphCount();
422ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
423ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
424ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
425ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
426ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
427ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (markFilter == NULL) {
428ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
429ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
430ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
431ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
432ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (reverse) {
433ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        c = glyphCount - 1;
434ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        direction = -1;
435ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
436ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
437ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    float ignore, prev;
438ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
439ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.getGlyphPosition(0, prev, ignore, success);
440ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
441ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (p = 0; p < charCount; p += 1, c += direction) {
442ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        float next, xAdvance;
443ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
444ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
445ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
446ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        xAdvance = next - prev;
447ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        glyphStorage.adjustPosition(p, xAdjust, 0, success);
448ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
449ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (markFilter->accept(chars[c])) {
450ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            xAdjust -= xAdvance;
451ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
452ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
453ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        prev = next;
454ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
455ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
456ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
457ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
458ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
459ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruconst void *LayoutEngine::getFontTable(LETag tableTag) const
460ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
461ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return fFontInstance->getFontTable(tableTag);
462ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
463ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
464ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
465ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                    LEGlyphStorage &glyphStorage, LEErrorCode &success)
466ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
467ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
468ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
469ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
470ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
471ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphStorage.allocateGlyphArray(count, reverse, success);
472ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
473ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    DefaultCharMapper charMapper(TRUE, mirror);
474ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
475ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
476ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
477ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
478ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Input: characters, font?
479ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Output: glyphs, positions, char indices
480ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Returns: number of glyphs
481ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querule_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
482ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                              float x, float y, LEErrorCode &success)
483ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
484ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
485ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
486ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
487ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
488ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
489ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_ILLEGAL_ARGUMENT_ERROR;
490ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
491ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
492ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
493ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_int32 glyphCount;
494ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
495ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fGlyphStorage->getGlyphCount() > 0) {
496ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fGlyphStorage->reset();
497ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
498ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
499ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
500ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    positionGlyphs(*fGlyphStorage, x, y, success);
501ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
502ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
503ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return glyphCount;
504ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
505ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
506ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid LayoutEngine::reset()
507ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
508ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fGlyphStorage->reset();
509ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
510ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
511ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
512ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
513ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  // 3 -> kerning and ligatures
514ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
515ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
516ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
517ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
518ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
519ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
520ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
521ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
522ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (LE_FAILURE(success)) {
523ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
524ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
525ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
526ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
527ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LayoutEngine *result = NULL;
528ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LETag scriptTag   = 0x00000000;
529ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LETag languageTag = 0x00000000;
53085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho	LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
531ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
53285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // Right now, only invoke V2 processing for Devanagari.  TODO: Allow more V2 scripts as they are
53385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // properly tested.
53485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
53585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho	if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) {
53685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho		result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
53785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho	}
53885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
539ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        switch (scriptCode) {
540ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case bengScriptCode:
541ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case devaScriptCode:
542ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case gujrScriptCode:
543ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case kndaScriptCode:
544ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case mlymScriptCode:
545ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case oryaScriptCode:
546ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case guruScriptCode:
547ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case tamlScriptCode:
548ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case teluScriptCode:
549ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case sinhScriptCode:
55085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
551ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
552ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
553ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case arabScriptCode:
55485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
555ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
556ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
557ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case hangScriptCode:
55885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
559ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
560ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
561ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case haniScriptCode:
562ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
563ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
564ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            switch (languageCode) {
565ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case korLanguageCode:
566ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case janLanguageCode:
567ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case zhtLanguageCode:
568ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case zhsLanguageCode:
569ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
57085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
571ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    break;
572ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
573ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
574ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // note: falling through to default case.
575ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            default:
57685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
577ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
578ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
579ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
580ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
581ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
582ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case tibtScriptCode:
58385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
584ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
585ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
586ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case khmrScriptCode:
58785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
588ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
589ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
590ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        default:
59185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
592ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
593ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
594ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
595ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
596ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
597ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (morphTable != NULL) {
59885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success);
599ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
600ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            switch (scriptCode) {
601ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case bengScriptCode:
602ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case devaScriptCode:
603ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case gujrScriptCode:
604ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case kndaScriptCode:
605ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case mlymScriptCode:
606ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case oryaScriptCode:
607ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case guruScriptCode:
608ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case tamlScriptCode:
609ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case teluScriptCode:
610ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case sinhScriptCode:
611ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            {
61285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
613ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
614ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
615ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
616ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case arabScriptCode:
617ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            //case hebrScriptCode:
61885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
619ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
620ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
621ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            //case hebrScriptCode:
622ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
623ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
624ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case thaiScriptCode:
62585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
626ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
627ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
628ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            case hangScriptCode:
62985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
630ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
631ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
632ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            default:
63385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
634ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
635ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
636ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
637ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
638ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
63985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (result && LE_FAILURE(success)) {
64085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho		delete result;
64185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho		result = NULL;
64285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho	}
64385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
644ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (result == NULL) {
645ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        success = LE_MEMORY_ALLOCATION_ERROR;
646ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
647ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
648ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return result;
649ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
650ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
651ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLayoutEngine::~LayoutEngine() {
652ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    delete fGlyphStorage;
653ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
654ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
655ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
656