1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26
27/*
28 *
29 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
30 *
31 */
32
33#include "LETypes.h"
34#include "LEScripts.h"
35#include "LEGlyphFilter.h"
36#include "LEGlyphStorage.h"
37#include "LayoutEngine.h"
38#include "OpenTypeLayoutEngine.h"
39#include "ArabicLayoutEngine.h"
40#include "ScriptAndLanguageTags.h"
41#include "CharSubstitutionFilter.h"
42
43#include "GlyphSubstitutionTables.h"
44#include "GlyphDefinitionTables.h"
45#include "GlyphPositioningTables.h"
46
47#include "GDEFMarkFilter.h"
48
49#include "ArabicShaping.h"
50#include "CanonShaping.h"
51
52U_NAMESPACE_BEGIN
53
54le_bool CharSubstitutionFilter::accept(LEGlyphID glyph, LEErrorCode &/*success*/) const
55{
56    return fFontInstance->canDisplay((LEUnicode) glyph);
57}
58
59UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
60
61ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
62                                                       le_int32 languageCode, le_int32 typoFlags,
63                                                       const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable,
64                                                       LEErrorCode &success)
65    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
66{
67    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
68    fFeatureOrder = TRUE;
69}
70
71ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
72                                                       le_int32 languageCode,
73                                                       le_int32 typoFlags, LEErrorCode &success)
74    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
75{
76    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
77
78    // NOTE: We don't need to set fFeatureOrder to TRUE here
79    // because this constructor is only called by the constructor
80    // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built
81    // GSUB table that has the features in the correct order.
82
83    //fFeatureOrder = TRUE;
84}
85
86ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
87{
88    // nothing to do
89}
90
91// Input: characters
92// Output: characters, char indices, tags
93// Returns: output character count
94le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count,
95                                                         le_int32 max, le_bool rightToLeft, LEUnicode *&outChars,
96                                                         LEGlyphStorage &glyphStorage, LEErrorCode &success)
97{
98    if (LE_FAILURE(success)) {
99        return 0;
100    }
101
102    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
103        success = LE_ILLEGAL_ARGUMENT_ERROR;
104        return 0;
105    }
106
107    outChars = LE_NEW_ARRAY(LEUnicode, count);
108
109    if (outChars == NULL) {
110        success = LE_MEMORY_ALLOCATION_ERROR;
111        return 0;
112    }
113
114    glyphStorage.allocateGlyphArray(count, rightToLeft, success);
115    glyphStorage.allocateAuxData(success);
116
117    if (LE_FAILURE(success)) {
118        LE_DELETE_ARRAY(outChars);
119        return 0;
120    }
121
122    CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
123
124    // Note: This processes the *original* character array so we can get context
125    // for the first and last characters. This is OK because only the marks
126    // will have been reordered, and they don't contribute to shaping.
127    ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage);
128
129    return count;
130}
131
132void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
133                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
134{
135    if (LE_FAILURE(success)) {
136        return;
137    }
138
139    if (chars == NULL || offset < 0 || count < 0) {
140        success = LE_ILLEGAL_ARGUMENT_ERROR;
141        return;
142    }
143
144    if (!fGPOSTable.isEmpty()) {
145        OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
146    } else if (!fGDEFTable.isEmpty()) {
147        GDEFMarkFilter filter(fGDEFTable, success);
148        adjustMarkGlyphs(glyphStorage, &filter, success);
149    } else {
150      LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData,
151                                                          CanonShaping::glyphDefinitionTable,
152                                                          CanonShaping::glyphDefinitionTableLen);
153        GDEFMarkFilter filter(gdefTable, success);
154
155        adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
156    }
157}
158
159UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
160  : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success)
161{
162  fGSUBTable.setTo(LETableReference::kStaticData, (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable, CanonShaping::glyphSubstitutionTableLen);
163  fGDEFTable.setTo(LETableReference::kStaticData, (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
164  /* OpenTypeLayoutEngine will allocate a substitution filter */
165}
166
167UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
168{
169    /* OpenTypeLayoutEngine will cleanup the substitution filter */
170}
171
172// "glyphs", "indices" -> glyphs, indices
173le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
174{
175    if (LE_FAILURE(success)) {
176        return 0;
177    }
178
179    // FIXME: we could avoid the memory allocation and copy if we
180    // made a clone of mapCharsToGlyphs which took the fake glyphs
181    // directly.
182    le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
183    LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);
184
185    if (tempChars == NULL) {
186        success = LE_MEMORY_ALLOCATION_ERROR;
187        return 0;
188    }
189
190    for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
191        tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
192    }
193
194    glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
195
196    ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);
197
198    LE_DELETE_ARRAY(tempChars);
199
200    return tempGlyphCount;
201}
202
203void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
204{
205    if (LE_FAILURE(success)) {
206        return;
207    }
208
209    if (chars == NULL || offset < 0 || count < 0) {
210        success = LE_ILLEGAL_ARGUMENT_ERROR;
211        return;
212    }
213
214    le_int32 i, dir = 1, out = 0;
215
216    if (reverse) {
217        out = count - 1;
218        dir = -1;
219    }
220
221    glyphStorage.allocateGlyphArray(count, reverse, success);
222
223    for (i = 0; i < count; i += 1, out += dir) {
224        glyphStorage[out] = (LEGlyphID) chars[offset + i];
225    }
226}
227
228void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
229                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
230{
231    if (LE_FAILURE(success)) {
232        return;
233    }
234
235    if (chars == NULL || offset < 0 || count < 0) {
236        success = LE_ILLEGAL_ARGUMENT_ERROR;
237        return;
238    }
239
240    GDEFMarkFilter filter(fGDEFTable, success);
241
242    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
243}
244
245U_NAMESPACE_END
246
247