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