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 
12 U_NAMESPACE_BEGIN
13 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage)14 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage)
15 
16 LEInsertionCallback::~LEInsertionCallback()
17 {
18 	// nothing to do...
19 }
20 
LEGlyphStorage()21 LEGlyphStorage::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 
~LEGlyphStorage()28 LEGlyphStorage::~LEGlyphStorage()
29 {
30     reset();
31 }
32 
reset()33 void 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?
allocateGlyphArray(le_int32 initialGlyphCount,le_bool rightToLeft,LEErrorCode & success)65 void 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]?
allocatePositions(LEErrorCode & success)126 le_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?
allocateAuxData(LEErrorCode & success)148 le_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 
getCharIndices(le_int32 charIndices[],le_int32 indexBase,LEErrorCode & success) const169 void 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 
getCharIndices(le_int32 charIndices[],LEErrorCode & success) const192 void 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
getGlyphs(le_uint32 glyphs[],le_uint32 extraBits,LEErrorCode & success) const212 void 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 
getGlyphs(LEGlyphID glyphs[],LEErrorCode & success) const235 void 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 
getGlyphID(le_int32 glyphIndex,LEErrorCode & success) const254 LEGlyphID 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 
setGlyphID(le_int32 glyphIndex,LEGlyphID glyphID,LEErrorCode & success)273 void 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 
getCharIndex(le_int32 glyphIndex,LEErrorCode & success) const292 le_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 
setCharIndex(le_int32 glyphIndex,le_int32 charIndex,LEErrorCode & success)311 void 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 
getAuxData(le_uint32 auxData[],LEErrorCode & success) const330 void 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 
getAuxData(le_int32 glyphIndex,LEErrorCode & success) const349 le_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 
setAuxData(le_int32 glyphIndex,le_uint32 auxData,LEErrorCode & success)368 void 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 
getGlyphPositions(float positions[],LEErrorCode & success) const387 void 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 
getGlyphPosition(le_int32 glyphIndex,float & x,float & y,LEErrorCode & success) const406 void 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 
setPosition(le_int32 glyphIndex,float x,float y,LEErrorCode & success)426 void 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 
adjustPosition(le_int32 glyphIndex,float xAdjust,float yAdjust,LEErrorCode & success)441 void 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 
adoptGlyphArray(LEGlyphStorage & from)456 void 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 
adoptCharIndicesArray(LEGlyphStorage & from)473 void 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 
adoptPositionArray(LEGlyphStorage & from)483 void 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 
adoptAuxDataArray(LEGlyphStorage & from)493 void 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 
adoptGlyphCount(LEGlyphStorage & from)503 void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from)
504 {
505     fGlyphCount = from.fGlyphCount;
506 }
507 
adoptGlyphCount(le_int32 newGlyphCount)508 void 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 
moveGlyph(le_int32 fromPosition,le_int32 toPosition,le_uint32 marker)515 void 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
insertGlyphs(le_int32 atIndex,le_int32 insertCount)546 LEGlyphID *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?
insertGlyphs(le_int32 atIndex,le_int32 insertCount,LEErrorCode & success)553 LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32  atIndex, le_int32 insertCount, LEErrorCode& success)
554 {
555     return fInsertionList->insert(atIndex, insertCount, success);
556 }
557 
applyInsertions()558 le_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 
applyInsertion(le_int32 atPosition,le_int32 count,LEGlyphID newGlyphs[])615 le_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 
665 U_NAMESPACE_END
666 
667