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 
  52 U_NAMESPACE_BEGIN
  53 
  54 le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const
  55 {
  56     return fFontInstance->canDisplay((LEUnicode) glyph);
  57 }
  58 
  59 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
  60 
  61 ArabicOpenTypeLayoutEngine::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 
  71 ArabicOpenTypeLayoutEngine::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 
  86 ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
  87 {
  88     // nothing to do
  89 }
  90 
  91 // Input: characters
  92 // Output: characters, char indices, tags
  93 // Returns: output character count
  94 le_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 
 132 void 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(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
 151         GDEFMarkFilter filter(gdefTable, success);
 152 
 153         adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
 154     }
 155 }
 156 
 157 UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
 158   : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success)
 159 {
 160     fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
 161     fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
 162     /* OpenTypeLayoutEngine will allocate a substitution filter */
 163 }
 164 
 165 UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
 166 {
 167     /* OpenTypeLayoutEngine will cleanup the substitution filter */
 168 }
 169 
 170 // "glyphs", "indices" -> glyphs, indices
 171 le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
 172 {
 173     if (LE_FAILURE(success)) {
 174         return 0;
 175     }
 176 
 177     // FIXME: we could avoid the memory allocation and copy if we
 178     // made a clone of mapCharsToGlyphs which took the fake glyphs
 179     // directly.
 180     le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
 181     LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);
 182 
 183     if (tempChars == NULL) {
 184         success = LE_MEMORY_ALLOCATION_ERROR;
 185         return 0;
 186     }
 187 
 188     for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
 189         tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
 190     }
 191 
 192     glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
 193 
 194     ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);
 195 
 196     LE_DELETE_ARRAY(tempChars);
 197 
 198     return tempGlyphCount;
 199 }
 200 
 201 void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
 202 {
 203     if (LE_FAILURE(success)) {
 204         return;
 205     }
 206 
 207     if (chars == NULL || offset < 0 || count < 0) {
 208         success = LE_ILLEGAL_ARGUMENT_ERROR;
 209         return;
 210     }
 211 
 212     le_int32 i, dir = 1, out = 0;
 213 
 214     if (reverse) {
 215         out = count - 1;
 216         dir = -1;
 217     }
 218 
 219     glyphStorage.allocateGlyphArray(count, reverse, success);
 220 
 221     for (i = 0; i < count; i += 1, out += dir) {
 222         glyphStorage[out] = (LEGlyphID) chars[offset + i];
 223     }
 224 }
 225 
 226 void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
 227                                                       LEGlyphStorage &glyphStorage, LEErrorCode &success)
 228 {
 229     if (LE_FAILURE(success)) {
 230         return;
 231     }
 232 
 233     if (chars == NULL || offset < 0 || count < 0) {
 234         success = LE_ILLEGAL_ARGUMENT_ERROR;
 235         return;
 236     }
 237 
 238     GDEFMarkFilter filter(fGDEFTable, success);
 239 
 240     adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
 241 }
 242 
 243 U_NAMESPACE_END
 244