1 /*
2 **********************************************************************
3 * Copyright (C) 1998-2006, 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 }
113 }
114
115 // FIXME: do we want to initialize the positions to [0, 0]?
allocatePositions(LEErrorCode & success)116 le_int32 LEGlyphStorage::allocatePositions(LEErrorCode &success)
117 {
118 if (LE_FAILURE(success)) {
119 return -1;
120 }
121
122 if (fPositions != NULL) {
123 success = LE_INTERNAL_ERROR;
124 return -1;
125 }
126
127 fPositions = LE_NEW_ARRAY(float, 2 * (fGlyphCount + 1));
128
129 if (fPositions == NULL) {
130 success = LE_MEMORY_ALLOCATION_ERROR;
131 return -1;
132 }
133
134 return fGlyphCount;
135 }
136
137 // FIXME: do we want to initialize the aux data to NULL?
allocateAuxData(LEErrorCode & success)138 le_int32 LEGlyphStorage::allocateAuxData(LEErrorCode &success)
139 {
140 if (LE_FAILURE(success)) {
141 return -1;
142 }
143
144 if (fAuxData != NULL) {
145 success = LE_INTERNAL_ERROR;
146 return -1;
147 }
148
149 fAuxData = LE_NEW_ARRAY(le_uint32, fGlyphCount);
150
151 if (fAuxData == NULL) {
152 success = LE_MEMORY_ALLOCATION_ERROR;
153 return -1;
154 }
155
156 return fGlyphCount;
157 }
158
getCharIndices(le_int32 charIndices[],le_int32 indexBase,LEErrorCode & success) const159 void LEGlyphStorage::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
160 {
161 le_int32 i;
162
163 if (LE_FAILURE(success)) {
164 return;
165 }
166
167 if (charIndices == NULL) {
168 success = LE_ILLEGAL_ARGUMENT_ERROR;
169 return;
170 }
171
172 if (fCharIndices == NULL) {
173 success = LE_NO_LAYOUT_ERROR;
174 return;
175 }
176
177 for (i = 0; i < fGlyphCount; i += 1) {
178 charIndices[i] = fCharIndices[i] + indexBase;
179 }
180 }
181
getCharIndices(le_int32 charIndices[],LEErrorCode & success) const182 void LEGlyphStorage::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
183 {
184 if (LE_FAILURE(success)) {
185 return;
186 }
187
188 if (charIndices == NULL) {
189 success = LE_ILLEGAL_ARGUMENT_ERROR;
190 return;
191 }
192
193 if (fCharIndices == NULL) {
194 success = LE_NO_LAYOUT_ERROR;
195 return;
196 }
197
198 LE_ARRAY_COPY(charIndices, fCharIndices, fGlyphCount);
199 }
200
201 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
getGlyphs(le_uint32 glyphs[],le_uint32 extraBits,LEErrorCode & success) const202 void LEGlyphStorage::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
203 {
204 le_int32 i;
205
206 if (LE_FAILURE(success)) {
207 return;
208 }
209
210 if (glyphs == NULL) {
211 success = LE_ILLEGAL_ARGUMENT_ERROR;
212 return;
213 }
214
215 if (fGlyphs == NULL) {
216 success = LE_NO_LAYOUT_ERROR;
217 return;
218 }
219
220 for (i = 0; i < fGlyphCount; i += 1) {
221 glyphs[i] = fGlyphs[i] | extraBits;
222 }
223 }
224
getGlyphs(LEGlyphID glyphs[],LEErrorCode & success) const225 void LEGlyphStorage::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
226 {
227 if (LE_FAILURE(success)) {
228 return;
229 }
230
231 if (glyphs == NULL) {
232 success = LE_ILLEGAL_ARGUMENT_ERROR;
233 return;
234 }
235
236 if (fGlyphs == NULL) {
237 success = LE_NO_LAYOUT_ERROR;
238 return;
239 }
240
241 LE_ARRAY_COPY(glyphs, fGlyphs, fGlyphCount);
242 }
243
getGlyphID(le_int32 glyphIndex,LEErrorCode & success) const244 LEGlyphID LEGlyphStorage::getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const
245 {
246 if (LE_FAILURE(success)) {
247 return 0xFFFF;
248 }
249
250 if (fGlyphs == NULL) {
251 success = LE_NO_LAYOUT_ERROR;
252 return 0xFFFF;
253 }
254
255 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
256 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
257 return 0xFFFF;
258 }
259
260 return fGlyphs[glyphIndex];
261 }
262
setGlyphID(le_int32 glyphIndex,LEGlyphID glyphID,LEErrorCode & success)263 void LEGlyphStorage::setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode &success)
264 {
265 if (LE_FAILURE(success)) {
266 return;
267 }
268
269 if (fGlyphs == NULL) {
270 success = LE_NO_LAYOUT_ERROR;
271 return;
272 }
273
274 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
275 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
276 return;
277 }
278
279 fGlyphs[glyphIndex] = glyphID;
280 }
281
getCharIndex(le_int32 glyphIndex,LEErrorCode & success) const282 le_int32 LEGlyphStorage::getCharIndex(le_int32 glyphIndex, LEErrorCode &success) const
283 {
284 if (LE_FAILURE(success)) {
285 return -1;
286 }
287
288 if (fCharIndices == NULL) {
289 success = LE_NO_LAYOUT_ERROR;
290 return -1;
291 }
292
293 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
294 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
295 return -1;
296 }
297
298 return fCharIndices[glyphIndex];
299 }
300
setCharIndex(le_int32 glyphIndex,le_int32 charIndex,LEErrorCode & success)301 void LEGlyphStorage::setCharIndex(le_int32 glyphIndex, le_int32 charIndex, LEErrorCode &success)
302 {
303 if (LE_FAILURE(success)) {
304 return;
305 }
306
307 if (fCharIndices == NULL) {
308 success = LE_NO_LAYOUT_ERROR;
309 return;
310 }
311
312 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
313 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
314 return;
315 }
316
317 fCharIndices[glyphIndex] = charIndex;
318 }
319
getAuxData(le_uint32 auxData[],LEErrorCode & success) const320 void LEGlyphStorage::getAuxData(le_uint32 auxData[], LEErrorCode &success) const
321 {
322 if (LE_FAILURE(success)) {
323 return;
324 }
325
326 if (auxData == NULL) {
327 success = LE_ILLEGAL_ARGUMENT_ERROR;
328 return;
329 }
330
331 if (fAuxData == NULL) {
332 success = LE_NO_LAYOUT_ERROR;
333 return;
334 }
335
336 LE_ARRAY_COPY(auxData, fAuxData, fGlyphCount);
337 }
338
getAuxData(le_int32 glyphIndex,LEErrorCode & success) const339 le_uint32 LEGlyphStorage::getAuxData(le_int32 glyphIndex, LEErrorCode &success) const
340 {
341 if (LE_FAILURE(success)) {
342 return 0;
343 }
344
345 if (fAuxData == NULL) {
346 success = LE_NO_LAYOUT_ERROR;
347 return 0;
348 }
349
350 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
351 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
352 return 0;
353 }
354
355 return fAuxData[glyphIndex];
356 }
357
setAuxData(le_int32 glyphIndex,le_uint32 auxData,LEErrorCode & success)358 void LEGlyphStorage::setAuxData(le_int32 glyphIndex, le_uint32 auxData, LEErrorCode &success)
359 {
360 if (LE_FAILURE(success)) {
361 return;
362 }
363
364 if (fAuxData == NULL) {
365 success = LE_NO_LAYOUT_ERROR;
366 return;
367 }
368
369 if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
370 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
371 return;
372 }
373
374 fAuxData[glyphIndex] = auxData;
375 }
376
getGlyphPositions(float positions[],LEErrorCode & success) const377 void LEGlyphStorage::getGlyphPositions(float positions[], LEErrorCode &success) const
378 {
379 if (LE_FAILURE(success)) {
380 return;
381 }
382
383 if (positions == NULL) {
384 success = LE_ILLEGAL_ARGUMENT_ERROR;
385 return;
386 }
387
388 if (fPositions == NULL) {
389 success = LE_NO_LAYOUT_ERROR;
390 return;
391 }
392
393 LE_ARRAY_COPY(positions, fPositions, fGlyphCount * 2 + 2);
394 }
395
getGlyphPosition(le_int32 glyphIndex,float & x,float & y,LEErrorCode & success) const396 void LEGlyphStorage::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
397 {
398 if (LE_FAILURE(success)) {
399 return;
400 }
401
402 if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
403 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
404 return;
405 }
406
407 if (fPositions == NULL) {
408 success = LE_NO_LAYOUT_ERROR;
409 return;
410 }
411
412 x = fPositions[glyphIndex * 2];
413 y = fPositions[glyphIndex * 2 + 1];
414 }
415
setPosition(le_int32 glyphIndex,float x,float y,LEErrorCode & success)416 void LEGlyphStorage::setPosition(le_int32 glyphIndex, float x, float y, 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] = x;
428 fPositions[glyphIndex * 2 + 1] = y;
429 }
430
adjustPosition(le_int32 glyphIndex,float xAdjust,float yAdjust,LEErrorCode & success)431 void LEGlyphStorage::adjustPosition(le_int32 glyphIndex, float xAdjust, float yAdjust, LEErrorCode &success)
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 fPositions[glyphIndex * 2] += xAdjust;
443 fPositions[glyphIndex * 2 + 1] += yAdjust;
444 }
445
adoptGlyphArray(LEGlyphStorage & from)446 void LEGlyphStorage::adoptGlyphArray(LEGlyphStorage &from)
447 {
448 if (fGlyphs != NULL) {
449 LE_DELETE_ARRAY(fGlyphs);
450 }
451
452 fGlyphs = from.fGlyphs;
453 from.fGlyphs = NULL;
454
455 if (fInsertionList != NULL) {
456 delete fInsertionList;
457 }
458
459 fInsertionList = from.fInsertionList;
460 from.fInsertionList = NULL;
461 }
462
adoptCharIndicesArray(LEGlyphStorage & from)463 void LEGlyphStorage::adoptCharIndicesArray(LEGlyphStorage &from)
464 {
465 if (fCharIndices != NULL) {
466 LE_DELETE_ARRAY(fCharIndices);
467 }
468
469 fCharIndices = from.fCharIndices;
470 from.fCharIndices = NULL;
471 }
472
adoptPositionArray(LEGlyphStorage & from)473 void LEGlyphStorage::adoptPositionArray(LEGlyphStorage &from)
474 {
475 if (fPositions != NULL) {
476 LE_DELETE_ARRAY(fPositions);
477 }
478
479 fPositions = from.fPositions;
480 from.fPositions = NULL;
481 }
482
adoptAuxDataArray(LEGlyphStorage & from)483 void LEGlyphStorage::adoptAuxDataArray(LEGlyphStorage &from)
484 {
485 if (fAuxData != NULL) {
486 LE_DELETE_ARRAY(fAuxData);
487 }
488
489 fAuxData = from.fAuxData;
490 from.fAuxData = NULL;
491 }
492
adoptGlyphCount(LEGlyphStorage & from)493 void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from)
494 {
495 fGlyphCount = from.fGlyphCount;
496 }
497
adoptGlyphCount(le_int32 newGlyphCount)498 void LEGlyphStorage::adoptGlyphCount(le_int32 newGlyphCount)
499 {
500 fGlyphCount = newGlyphCount;
501 }
502
503 // FIXME: add error checking?
insertGlyphs(le_int32 atIndex,le_int32 insertCount)504 LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32 atIndex, le_int32 insertCount)
505 {
506 return fInsertionList->insert(atIndex, insertCount);
507 }
508
applyInsertions()509 le_int32 LEGlyphStorage::applyInsertions()
510 {
511 le_int32 growAmount = fInsertionList->getGrowAmount();
512
513 if (growAmount == 0) {
514 return fGlyphCount;
515 }
516
517 le_int32 newGlyphCount = fGlyphCount + growAmount;
518
519 fGlyphs = (LEGlyphID *) LE_GROW_ARRAY(fGlyphs, newGlyphCount);
520 fCharIndices = (le_int32 *) LE_GROW_ARRAY(fCharIndices, newGlyphCount);
521
522 if (fAuxData != NULL) {
523 fAuxData = (le_uint32 *) LE_GROW_ARRAY(fAuxData, newGlyphCount);
524 }
525
526 fSrcIndex = fGlyphCount - 1;
527 fDestIndex = newGlyphCount - 1;
528
529 #if 0
530 // If the current position is at the end of the array
531 // update it to point to the end of the new array. The
532 // insertion callback will handle all other cases.
533 // FIXME: this is left over from GlyphIterator, but there's no easy
534 // way to implement this here... it seems that GlyphIterator doesn't
535 // really need it 'cause the insertions don't get applied until after a
536 // complete pass over the glyphs, after which the iterator gets reset anyhow...
537 // probably better to just document that for LEGlyphStorage and GlyphIterator...
538 if (position == glyphCount) {
539 position = newGlyphCount;
540 }
541 #endif
542
543 fInsertionList->applyInsertions(this);
544
545 fInsertionList->reset();
546
547 return fGlyphCount = newGlyphCount;
548 }
549
applyInsertion(le_int32 atPosition,le_int32 count,LEGlyphID newGlyphs[])550 le_bool LEGlyphStorage::applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[])
551 {
552 #if 0
553 // if the current position is within the block we're shifting
554 // it needs to be updated to the current glyph's
555 // new location.
556 // FIXME: this is left over from GlyphIterator, but there's no easy
557 // way to implement this here... it seems that GlyphIterator doesn't
558 // really need it 'cause the insertions don't get applied until after a
559 // complete pass over the glyphs, after which the iterator gets reset anyhow...
560 // probably better to just document that for LEGlyphStorage and GlyphIterator...
561 if (position >= atPosition && position <= fSrcIndex) {
562 position += fDestIndex - fSrcIndex;
563 }
564 #endif
565
566 if (fAuxData != NULL) {
567 le_int32 src = fSrcIndex, dest = fDestIndex;
568
569 while (src > atPosition) {
570 fAuxData[dest--] = fAuxData[src--];
571 }
572
573 for (le_int32 i = count - 1; i >= 0; i -= 1) {
574 fAuxData[dest--] = fAuxData[atPosition];
575 }
576 }
577
578 while (fSrcIndex > atPosition) {
579 fGlyphs[fDestIndex] = fGlyphs[fSrcIndex];
580 fCharIndices[fDestIndex] = fCharIndices[fSrcIndex];
581
582 fDestIndex -= 1;
583 fSrcIndex -= 1;
584 }
585
586 for (le_int32 i = count - 1; i >= 0; i -= 1) {
587 fGlyphs[fDestIndex] = newGlyphs[i];
588 fCharIndices[fDestIndex] = fCharIndices[atPosition];
589
590 fDestIndex -= 1;
591 }
592
593 // the source glyph we're pointing at
594 // just got replaced by the insertion
595 fSrcIndex -= 1;
596
597 return FALSE;
598 }
599
600 U_NAMESPACE_END
601
602