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