]> git.saurik.com Git - apple/icu.git/blob - icuSources/layout/LEGlyphStorage.cpp
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / layout / LEGlyphStorage.cpp
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
14 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage)
15
16 LEInsertionCallback::~LEInsertionCallback()
17 {
18 // nothing to do...
19 }
20
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
28 LEGlyphStorage::~LEGlyphStorage()
29 {
30 reset();
31 }
32
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?
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]?
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?
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
169 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
192 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
212 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
235 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
254 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
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
292 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
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
330 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
349 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
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
387 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
406 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
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
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
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
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
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
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
503 void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from)
504 {
505 fGlyphCount = from.fGlyphCount;
506 }
507
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
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
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?
553 LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32 atIndex, le_int32 insertCount, LEErrorCode& success)
554 {
555 return fInsertionList->insert(atIndex, insertCount, success);
556 }
557
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
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