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