1
2/*
3 *
4 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
5 *
6 */
7
8#include "LETypes.h"
9#include "LEScripts.h"
10#include "LEGlyphFilter.h"
11#include "LEGlyphStorage.h"
12#include "LayoutEngine.h"
13#include "OpenTypeLayoutEngine.h"
14#include "ArabicLayoutEngine.h"
15#include "ScriptAndLanguageTags.h"
16#include "CharSubstitutionFilter.h"
17
18#include "GlyphSubstitutionTables.h"
19#include "GlyphDefinitionTables.h"
20#include "GlyphPositioningTables.h"
21
22#include "GDEFMarkFilter.h"
23
24#include "ArabicShaping.h"
25#include "CanonShaping.h"
26
27U_NAMESPACE_BEGIN
28
29le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const
30{
31    return fFontInstance->canDisplay((LEUnicode) glyph);
32}
33
34UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
35
36ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
37                        le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
38    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
39{
40    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
41    fFeatureOrder = TRUE;
42}
43
44ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
45						       le_int32 typoFlags, LEErrorCode &success)
46    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
47{
48    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
49
50    // NOTE: We don't need to set fFeatureOrder to TRUE here
51    // because this constructor is only called by the constructor
52    // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built
53    // GSUB table that has the features in the correct order.
54
55    //fFeatureOrder = TRUE;
56}
57
58ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
59{
60    // nothing to do
61}
62
63// Input: characters
64// Output: characters, char indices, tags
65// Returns: output character count
66le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
67        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
68{
69    if (LE_FAILURE(success)) {
70        return 0;
71    }
72
73    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
74        success = LE_ILLEGAL_ARGUMENT_ERROR;
75        return 0;
76    }
77
78    outChars = LE_NEW_ARRAY(LEUnicode, count);
79
80    if (outChars == NULL) {
81        success = LE_MEMORY_ALLOCATION_ERROR;
82        return 0;
83    }
84
85    glyphStorage.allocateGlyphArray(count, rightToLeft, success);
86    glyphStorage.allocateAuxData(success);
87
88    if (LE_FAILURE(success)) {
89        LE_DELETE_ARRAY(outChars);
90        return 0;
91    }
92
93    CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
94
95    // Note: This processes the *original* character array so we can get context
96    // for the first and last characters. This is OK because only the marks
97    // will have been reordered, and they don't contribute to shaping.
98    ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage);
99
100    return count;
101}
102
103void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
104                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
105{
106    if (LE_FAILURE(success)) {
107        return;
108    }
109
110    if (chars == NULL || offset < 0 || count < 0) {
111        success = LE_ILLEGAL_ARGUMENT_ERROR;
112        return;
113    }
114
115    if (fGPOSTable != NULL) {
116        OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
117    } else if (fGDEFTable != NULL) {
118        GDEFMarkFilter filter(fGDEFTable);
119
120        adjustMarkGlyphs(glyphStorage, &filter, success);
121    } else {
122        GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
123        GDEFMarkFilter filter(gdefTable);
124
125        adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
126    }
127}
128
129UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
130    : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
131{
132    fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
133    fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
134
135    fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
136}
137
138UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
139{
140    delete fSubstitutionFilter;
141}
142
143// "glyphs", "indices" -> glyphs, indices
144le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
145{
146    if (LE_FAILURE(success)) {
147        return 0;
148    }
149
150    // FIXME: we could avoid the memory allocation and copy if we
151    // made a clone of mapCharsToGlyphs which took the fake glyphs
152    // directly.
153    le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
154    LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);
155
156    if (tempChars == NULL) {
157        success = LE_MEMORY_ALLOCATION_ERROR;
158        return 0;
159    }
160
161    for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
162        tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
163    }
164
165    glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
166
167    ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);
168
169    LE_DELETE_ARRAY(tempChars);
170
171    return tempGlyphCount;
172}
173
174void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
175{
176    if (LE_FAILURE(success)) {
177        return;
178    }
179
180    if (chars == NULL || offset < 0 || count < 0) {
181        success = LE_ILLEGAL_ARGUMENT_ERROR;
182        return;
183    }
184
185    le_int32 i, dir = 1, out = 0;
186
187    if (reverse) {
188        out = count - 1;
189        dir = -1;
190    }
191
192    glyphStorage.allocateGlyphArray(count, reverse, success);
193
194    for (i = 0; i < count; i += 1, out += dir) {
195        glyphStorage[out] = (LEGlyphID) chars[offset + i];
196    }
197}
198
199void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
200                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
201{
202    if (LE_FAILURE(success)) {
203        return;
204    }
205
206    if (chars == NULL || offset < 0 || count < 0) {
207        success = LE_ILLEGAL_ARGUMENT_ERROR;
208        return;
209    }
210
211    GDEFMarkFilter filter(fGDEFTable);
212
213    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
214}
215
216U_NAMESPACE_END
217
218