1/*
2 **********************************************************************
3 *   Copyright (C) 1998-2009, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 */
7
8#include "LETypes.h"
9#include "LEInsertionList.h"
10#include "LEGlyphStorage.h"
11
12U_NAMESPACE_BEGIN
13
14UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage)
15
16LEInsertionCallback::~LEInsertionCallback()
17{
18	// nothing to do...
19}
20
21LEGlyphStorage::LEGlyphStorage()
22    : fGlyphCount(0), fGlyphs(NULL), fCharIndices(NULL), fPositions(NULL),
23      fAuxData(NULL), fInsertionList(NULL), fSrcIndex(0), fDestIndex(0)
24{
25    // nothing else to do!
26}
27
28LEGlyphStorage::~LEGlyphStorage()
29{
30    reset();
31}
32
33void LEGlyphStorage::reset()
34{
35    fGlyphCount = 0;
36
37    if (fPositions != NULL) {
38        LE_DELETE_ARRAY(fPositions);
39        fPositions = NULL;
40    }
41
42    if (fAuxData != NULL) {
43        LE_DELETE_ARRAY(fAuxData);
44        fAuxData = NULL;
45    }
46
47    if (fInsertionList != NULL) {
48        delete fInsertionList;
49        fInsertionList = NULL;
50    }
51
52    if (fCharIndices != NULL) {
53        LE_DELETE_ARRAY(fCharIndices);
54        fCharIndices = NULL;
55    }
56
57    if (fGlyphs != NULL) {
58        LE_DELETE_ARRAY(fGlyphs);
59        fGlyphs = NULL;
60    }
61}
62
63// FIXME: This might get called more than once, for various reasons. Is
64// testing for pre-existing glyph and charIndices arrays good enough?
65void LEGlyphStorage::allocateGlyphArray(le_int32 initialGlyphCount, le_bool rightToLeft, LEErrorCode &success)
66{
67    if (LE_FAILURE(success)) {
68        return;
69    }
70
71    if (initialGlyphCount <= 0) {
72        success = LE_ILLEGAL_ARGUMENT_ERROR;
73        return;
74    }
75
76    if (fGlyphs == NULL) {
77        fGlyphCount = initialGlyphCount;
78        fGlyphs = LE_NEW_ARRAY(LEGlyphID, fGlyphCount);
79
80        if (fGlyphs == NULL) {
81            success = LE_MEMORY_ALLOCATION_ERROR;
82            return;
83        }
84    }
85
86    if (fCharIndices == NULL) {
87        fCharIndices = LE_NEW_ARRAY(le_int32, fGlyphCount);
88
89        if (fCharIndices == NULL) {
90            LE_DELETE_ARRAY(fGlyphs);
91            fGlyphs = NULL;
92            success = LE_MEMORY_ALLOCATION_ERROR;
93            return;
94        }
95
96        // Initialize the charIndices array
97        le_int32 i, count = fGlyphCount, dir = 1, out = 0;
98
99        if (rightToLeft) {
100            out = fGlyphCount - 1;
101            dir = -1;
102        }
103
104        for (i = 0; i < count; i += 1, out += dir) {
105            fCharIndices[out] = i;
106        }
107    }
108
109    if (fInsertionList == NULL) {
110        // FIXME: check this for failure?
111        fInsertionList = new LEInsertionList(rightToLeft);
112        if (fInsertionList == NULL) {
113            LE_DELETE_ARRAY(fCharIndices);
114            fCharIndices = NULL;
115
116            LE_DELETE_ARRAY(fGlyphs);
117            fGlyphs = NULL;
118
119            success = LE_MEMORY_ALLOCATION_ERROR;
120            return;
121        }
122    }
123}
124
125// FIXME: do we want to initialize the positions to [0, 0]?
126le_int32 LEGlyphStorage::allocatePositions(LEErrorCode &success)
127{
128    if (LE_FAILURE(success)) {
129        return -1;
130    }
131
132    if (fPositions != NULL) {
133        success = LE_INTERNAL_ERROR;
134        return -1;
135    }
136
137    fPositions = LE_NEW_ARRAY(float, 2 * (fGlyphCount + 1));
138
139    if (fPositions == NULL) {
140        success = LE_MEMORY_ALLOCATION_ERROR;
141        return -1;
142    }
143
144    return fGlyphCount;
145}
146
147// FIXME: do we want to initialize the aux data to NULL?
148le_int32 LEGlyphStorage::allocateAuxData(LEErrorCode &success)
149{
150    if (LE_FAILURE(success)) {
151        return -1;
152    }
153
154    if (fAuxData != NULL) {
155        success = LE_INTERNAL_ERROR;
156        return -1;
157    }
158
159    fAuxData = LE_NEW_ARRAY(le_uint32, fGlyphCount);
160
161    if (fAuxData == NULL) {
162        success = LE_MEMORY_ALLOCATION_ERROR;
163        return -1;
164    }
165
166    return fGlyphCount;
167}
168
169void LEGlyphStorage::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
170{
171    le_int32 i;
172
173    if (LE_FAILURE(success)) {
174        return;
175    }
176
177    if (charIndices == NULL) {
178        success = LE_ILLEGAL_ARGUMENT_ERROR;
179        return;
180    }
181
182    if (fCharIndices == NULL) {
183        success = LE_NO_LAYOUT_ERROR;
184        return;
185    }
186
187    for (i = 0; i < fGlyphCount; i += 1) {
188        charIndices[i] = fCharIndices[i] + indexBase;
189    }
190}
191
192void LEGlyphStorage::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
193{
194    if (LE_FAILURE(success)) {
195      return;
196    }
197
198    if (charIndices == NULL) {
199      success = LE_ILLEGAL_ARGUMENT_ERROR;
200      return;
201    }
202
203    if (fCharIndices == NULL) {
204      success = LE_NO_LAYOUT_ERROR;
205      return;
206    }
207
208    LE_ARRAY_COPY(charIndices, fCharIndices, fGlyphCount);
209}
210
211// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
212void LEGlyphStorage::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
213{
214    le_int32 i;
215
216    if (LE_FAILURE(success)) {
217        return;
218    }
219
220    if (glyphs == NULL) {
221        success = LE_ILLEGAL_ARGUMENT_ERROR;
222        return;
223    }
224
225    if (fGlyphs == NULL) {
226        success = LE_NO_LAYOUT_ERROR;
227        return;
228    }
229
230    for (i = 0; i < fGlyphCount; i += 1) {
231        glyphs[i] = fGlyphs[i] | extraBits;
232    }
233}
234
235void LEGlyphStorage::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
236{
237    if (LE_FAILURE(success)) {
238      return;
239    }
240
241    if (glyphs == NULL) {
242      success = LE_ILLEGAL_ARGUMENT_ERROR;
243      return;
244    }
245
246    if (fGlyphs == NULL) {
247      success = LE_NO_LAYOUT_ERROR;
248      return;
249    }
250
251    LE_ARRAY_COPY(glyphs, fGlyphs, fGlyphCount);
252}
253
254LEGlyphID LEGlyphStorage::getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const
255{
256    if (LE_FAILURE(success)) {
257        return 0xFFFF;
258    }
259
260    if (fGlyphs == NULL) {
261        success = LE_NO_LAYOUT_ERROR;
262        return 0xFFFF;
263    }
264
265    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
266        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
267        return 0xFFFF;
268    }
269
270    return fGlyphs[glyphIndex];
271}
272
273void LEGlyphStorage::setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode &success)
274{
275    if (LE_FAILURE(success)) {
276        return;
277    }
278
279    if (fGlyphs == NULL) {
280        success = LE_NO_LAYOUT_ERROR;
281        return;
282    }
283
284    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
285        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
286        return;
287    }
288
289    fGlyphs[glyphIndex] = glyphID;
290}
291
292le_int32 LEGlyphStorage::getCharIndex(le_int32 glyphIndex, LEErrorCode &success) const
293{
294    if (LE_FAILURE(success)) {
295        return -1;
296    }
297
298    if (fCharIndices == NULL) {
299        success = LE_NO_LAYOUT_ERROR;
300        return -1;
301    }
302
303    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
304        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
305        return -1;
306    }
307
308    return fCharIndices[glyphIndex];
309}
310
311void LEGlyphStorage::setCharIndex(le_int32 glyphIndex, le_int32 charIndex, LEErrorCode &success)
312{
313    if (LE_FAILURE(success)) {
314        return;
315    }
316
317    if (fCharIndices == NULL) {
318        success = LE_NO_LAYOUT_ERROR;
319        return;
320    }
321
322    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
323        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
324        return;
325    }
326
327    fCharIndices[glyphIndex] = charIndex;
328}
329
330void LEGlyphStorage::getAuxData(le_uint32 auxData[], LEErrorCode &success) const
331{
332    if (LE_FAILURE(success)) {
333      return;
334    }
335
336    if (auxData == NULL) {
337      success = LE_ILLEGAL_ARGUMENT_ERROR;
338      return;
339    }
340
341    if (fAuxData == NULL) {
342      success = LE_NO_LAYOUT_ERROR;
343      return;
344    }
345
346    LE_ARRAY_COPY(auxData, fAuxData, fGlyphCount);
347}
348
349le_uint32 LEGlyphStorage::getAuxData(le_int32 glyphIndex, LEErrorCode &success) const
350{
351    if (LE_FAILURE(success)) {
352        return 0;
353    }
354
355    if (fAuxData == NULL) {
356        success = LE_NO_LAYOUT_ERROR;
357        return 0;
358    }
359
360    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
361        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
362        return 0;
363    }
364
365    return fAuxData[glyphIndex];
366}
367
368void LEGlyphStorage::setAuxData(le_int32 glyphIndex, le_uint32 auxData, LEErrorCode &success)
369{
370    if (LE_FAILURE(success)) {
371        return;
372    }
373
374    if (fAuxData == NULL) {
375        success = LE_NO_LAYOUT_ERROR;
376        return;
377    }
378
379    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
380        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
381        return;
382    }
383
384    fAuxData[glyphIndex] = auxData;
385}
386
387void LEGlyphStorage::getGlyphPositions(float positions[], LEErrorCode &success) const
388{
389    if (LE_FAILURE(success)) {
390      return;
391    }
392
393    if (positions == NULL) {
394      success = LE_ILLEGAL_ARGUMENT_ERROR;
395      return;
396    }
397
398    if (fPositions == NULL) {
399      success = LE_NO_LAYOUT_ERROR;
400      return;
401    }
402
403    LE_ARRAY_COPY(positions, fPositions, fGlyphCount * 2 + 2);
404}
405
406void LEGlyphStorage::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
407{
408    if (LE_FAILURE(success)) {
409      return;
410    }
411
412    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
413      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
414      return;
415    }
416
417    if (fPositions == NULL) {
418      success = LE_NO_LAYOUT_ERROR;
419      return;
420    }
421
422    x = fPositions[glyphIndex * 2];
423    y = fPositions[glyphIndex * 2 + 1];
424}
425
426void LEGlyphStorage::setPosition(le_int32 glyphIndex, float x, float y, LEErrorCode &success)
427{
428    if (LE_FAILURE(success)) {
429        return;
430    }
431
432    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
433      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
434      return;
435    }
436
437    fPositions[glyphIndex * 2]     = x;
438    fPositions[glyphIndex * 2 + 1] = y;
439}
440
441void LEGlyphStorage::adjustPosition(le_int32 glyphIndex, float xAdjust, float yAdjust, LEErrorCode &success)
442{
443    if (LE_FAILURE(success)) {
444        return;
445    }
446
447    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
448      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
449      return;
450    }
451
452    fPositions[glyphIndex * 2]     += xAdjust;
453    fPositions[glyphIndex * 2 + 1] += yAdjust;
454}
455
456void LEGlyphStorage::adoptGlyphArray(LEGlyphStorage &from)
457{
458    if (fGlyphs != NULL) {
459        LE_DELETE_ARRAY(fGlyphs);
460    }
461
462    fGlyphs = from.fGlyphs;
463    from.fGlyphs = NULL;
464
465    if (fInsertionList != NULL) {
466        delete fInsertionList;
467    }
468
469    fInsertionList = from.fInsertionList;
470    from.fInsertionList = NULL;
471}
472
473void LEGlyphStorage::adoptCharIndicesArray(LEGlyphStorage &from)
474{
475    if (fCharIndices != NULL) {
476        LE_DELETE_ARRAY(fCharIndices);
477    }
478
479    fCharIndices = from.fCharIndices;
480    from.fCharIndices = NULL;
481}
482
483void LEGlyphStorage::adoptPositionArray(LEGlyphStorage &from)
484{
485    if (fPositions != NULL) {
486        LE_DELETE_ARRAY(fPositions);
487    }
488
489    fPositions = from.fPositions;
490    from.fPositions = NULL;
491}
492
493void LEGlyphStorage::adoptAuxDataArray(LEGlyphStorage &from)
494{
495    if (fAuxData != NULL) {
496        LE_DELETE_ARRAY(fAuxData);
497    }
498
499    fAuxData = from.fAuxData;
500    from.fAuxData = NULL;
501}
502
503void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from)
504{
505    fGlyphCount = from.fGlyphCount;
506}
507
508void LEGlyphStorage::adoptGlyphCount(le_int32 newGlyphCount)
509{
510    fGlyphCount = newGlyphCount;
511}
512
513// Move a glyph to a different position in the LEGlyphStorage ( used for Indic v2 processing )
514
515void LEGlyphStorage::moveGlyph(le_int32 fromPosition, le_int32 toPosition, le_uint32 marker )
516{
517
518    LEErrorCode success = LE_NO_ERROR;
519
520    LEGlyphID holdGlyph = getGlyphID(fromPosition,success);
521    le_int32 holdCharIndex = getCharIndex(fromPosition,success);
522    le_uint32 holdAuxData = getAuxData(fromPosition,success);
523
524    if ( fromPosition < toPosition ) {
525        for ( le_int32 i = fromPosition ; i < toPosition ; i++ ) {
526            setGlyphID(i,getGlyphID(i+1,success),success);
527            setCharIndex(i,getCharIndex(i+1,success),success);
528            setAuxData(i,getAuxData(i+1,success),success);
529        }
530    } else {
531        for ( le_int32 i = toPosition ; i > fromPosition ; i-- ) {
532            setGlyphID(i,getGlyphID(i-1,success),success);
533            setCharIndex(i,getCharIndex(i-1,success),success);
534            setAuxData(i,getAuxData(i-1,success),success);
535
536        }
537    }
538
539    setGlyphID(toPosition,holdGlyph,success);
540    setCharIndex(toPosition,holdCharIndex,success);
541    setAuxData(toPosition,holdAuxData | marker,success);
542
543}
544
545// Glue code for existing stable API
546LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32  atIndex, le_int32 insertCount)
547{
548    LEErrorCode ignored = LE_NO_LAYOUT_ERROR;
549    return insertGlyphs(atIndex, insertCount, ignored);
550}
551
552// FIXME: add error checking?
553LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32  atIndex, le_int32 insertCount, LEErrorCode& success)
554{
555    return fInsertionList->insert(atIndex, insertCount, success);
556}
557
558le_int32 LEGlyphStorage::applyInsertions()
559{
560    le_int32 growAmount = fInsertionList->getGrowAmount();
561
562    if (growAmount == 0) {
563        return fGlyphCount;
564    }
565
566    le_int32 newGlyphCount = fGlyphCount + growAmount;
567
568    LEGlyphID *newGlyphs = (LEGlyphID *) LE_GROW_ARRAY(fGlyphs, newGlyphCount);
569    if (newGlyphs == NULL) {
570        // Could not grow the glyph array
571        return fGlyphCount;
572    }
573    fGlyphs = newGlyphs;
574
575    le_int32 *newCharIndices = (le_int32 *) LE_GROW_ARRAY(fCharIndices, newGlyphCount);
576    if (newCharIndices == NULL) {
577        // Could not grow the glyph array
578        return fGlyphCount;
579    }
580    fCharIndices = newCharIndices;
581
582    if (fAuxData != NULL) {
583        le_uint32 *newAuxData = (le_uint32 *) LE_GROW_ARRAY(fAuxData, newGlyphCount);
584        if (newAuxData == NULL) {
585            // could not grow the aux data array
586            return fGlyphCount;
587        }
588        fAuxData = (le_uint32 *)newAuxData;
589    }
590
591    fSrcIndex  = fGlyphCount - 1;
592    fDestIndex = newGlyphCount - 1;
593
594#if 0
595    // If the current position is at the end of the array
596    // update it to point to the end of the new array. The
597    // insertion callback will handle all other cases.
598    // FIXME: this is left over from GlyphIterator, but there's no easy
599    // way to implement this here... it seems that GlyphIterator doesn't
600    // really need it 'cause the insertions don't get  applied until after a
601    // complete pass over the glyphs, after which the iterator gets reset anyhow...
602    // probably better to just document that for LEGlyphStorage and GlyphIterator...
603    if (position == glyphCount) {
604        position = newGlyphCount;
605    }
606#endif
607
608    fInsertionList->applyInsertions(this);
609
610    fInsertionList->reset();
611
612    return fGlyphCount = newGlyphCount;
613}
614
615le_bool LEGlyphStorage::applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[])
616{
617#if 0
618    // if the current position is within the block we're shifting
619    // it needs to be updated to the current glyph's
620    // new location.
621    // FIXME: this is left over from GlyphIterator, but there's no easy
622    // way to implement this here... it seems that GlyphIterator doesn't
623    // really need it 'cause the insertions don't get  applied until after a
624    // complete pass over the glyphs, after which the iterator gets reset anyhow...
625    // probably better to just document that for LEGlyphStorage and GlyphIterator...
626    if (position >= atPosition && position <= fSrcIndex) {
627        position += fDestIndex - fSrcIndex;
628    }
629#endif
630
631    if (fAuxData != NULL) {
632        le_int32 src = fSrcIndex, dest = fDestIndex;
633
634        while (src > atPosition) {
635            fAuxData[dest--] = fAuxData[src--];
636        }
637
638        for (le_int32 i = count - 1; i >= 0; i -= 1) {
639            fAuxData[dest--] = fAuxData[atPosition];
640        }
641    }
642
643    while (fSrcIndex > atPosition) {
644        fGlyphs[fDestIndex]      = fGlyphs[fSrcIndex];
645        fCharIndices[fDestIndex] = fCharIndices[fSrcIndex];
646
647        fDestIndex -= 1;
648        fSrcIndex  -= 1;
649    }
650
651    for (le_int32 i = count - 1; i >= 0; i -= 1) {
652        fGlyphs[fDestIndex]      = newGlyphs[i];
653        fCharIndices[fDestIndex] = fCharIndices[atPosition];
654
655        fDestIndex -= 1;
656    }
657
658    // the source glyph we're pointing at
659    // just got replaced by the insertion
660    fSrcIndex -= 1;
661
662    return FALSE;
663}
664
665U_NAMESPACE_END
666
667