sl@0: /* sl@0: ********************************************************************** sl@0: * Copyright (C) 1998-2004, International Business Machines sl@0: * Corporation and others. All Rights Reserved. sl@0: ********************************************************************** sl@0: */ sl@0: sl@0: #include "LETypes.h" sl@0: #include "LEInsertionList.h" sl@0: #include "LEGlyphStorage.h" sl@0: sl@0: U_NAMESPACE_BEGIN sl@0: sl@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage) sl@0: sl@0: LEGlyphStorage::LEGlyphStorage() sl@0: : fGlyphCount(0), fGlyphs(NULL), fCharIndices(NULL), fPositions(NULL), sl@0: fAuxData(NULL), fInsertionList(NULL), fSrcIndex(0), fDestIndex(0) sl@0: { sl@0: // nothing else to do! sl@0: } sl@0: sl@0: LEGlyphStorage::~LEGlyphStorage() sl@0: { sl@0: reset(); sl@0: } sl@0: sl@0: void LEGlyphStorage::reset() sl@0: { sl@0: fGlyphCount = 0; sl@0: sl@0: if (fPositions != NULL) { sl@0: LE_DELETE_ARRAY(fPositions); sl@0: fPositions = NULL; sl@0: } sl@0: sl@0: if (fAuxData != NULL) { sl@0: LE_DELETE_ARRAY(fAuxData); sl@0: fAuxData = NULL; sl@0: } sl@0: sl@0: if (fInsertionList != NULL) { sl@0: delete fInsertionList; sl@0: fInsertionList = NULL; sl@0: } sl@0: sl@0: if (fCharIndices != NULL) { sl@0: LE_DELETE_ARRAY(fCharIndices); sl@0: fCharIndices = NULL; sl@0: } sl@0: sl@0: if (fGlyphs != NULL) { sl@0: LE_DELETE_ARRAY(fGlyphs); sl@0: fGlyphs = NULL; sl@0: } sl@0: } sl@0: sl@0: // FIXME: This might get called more than once, for various reasons. Is sl@0: // testing for pre-existing glyph and charIndices arrays good enough? sl@0: void LEGlyphStorage::allocateGlyphArray(le_int32 initialGlyphCount, le_bool rightToLeft, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (initialGlyphCount <= 0) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fGlyphs == NULL) { sl@0: fGlyphCount = initialGlyphCount; sl@0: fGlyphs = LE_NEW_ARRAY(LEGlyphID, fGlyphCount); sl@0: sl@0: if (fGlyphs == NULL) { sl@0: success = LE_MEMORY_ALLOCATION_ERROR; sl@0: return; sl@0: } sl@0: } sl@0: sl@0: if (fCharIndices == NULL) { sl@0: fCharIndices = LE_NEW_ARRAY(le_int32, fGlyphCount); sl@0: sl@0: if (fCharIndices == NULL) { sl@0: LE_DELETE_ARRAY(fGlyphs); sl@0: fGlyphs = NULL; sl@0: success = LE_MEMORY_ALLOCATION_ERROR; sl@0: return; sl@0: } sl@0: sl@0: // Initialize the charIndices array sl@0: le_int32 i, count = fGlyphCount, dir = 1, out = 0; sl@0: sl@0: if (rightToLeft) { sl@0: out = fGlyphCount - 1; sl@0: dir = -1; sl@0: } sl@0: sl@0: for (i = 0; i < count; i += 1, out += dir) { sl@0: fCharIndices[out] = i; sl@0: } sl@0: } sl@0: sl@0: if (fInsertionList == NULL) { sl@0: fInsertionList = new LEInsertionList(rightToLeft); sl@0: if (fInsertionList == NULL) { sl@0: LE_DELETE_ARRAY(fCharIndices); sl@0: fCharIndices = NULL; sl@0: LE_DELETE_ARRAY(fGlyphs); sl@0: fGlyphs = NULL; sl@0: success = LE_MEMORY_ALLOCATION_ERROR; sl@0: return; sl@0: } sl@0: } sl@0: } sl@0: sl@0: // FIXME: do we want to initialize the positions to [0, 0]? sl@0: le_int32 LEGlyphStorage::allocatePositions(LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return -1; sl@0: } sl@0: sl@0: if (fPositions != NULL) { sl@0: LE_DELETE_ARRAY(fPositions); sl@0: } sl@0: sl@0: fPositions = LE_NEW_ARRAY(float, 2 * (fGlyphCount + 1)); sl@0: sl@0: if (fPositions == NULL) { sl@0: success = LE_MEMORY_ALLOCATION_ERROR; sl@0: return -1; sl@0: } sl@0: sl@0: return fGlyphCount; sl@0: } sl@0: sl@0: // FIXME: do we want to initialize the aux data to NULL? sl@0: le_int32 LEGlyphStorage::allocateAuxData(LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return -1; sl@0: } sl@0: sl@0: fAuxData = LE_NEW_ARRAY(void *, fGlyphCount); sl@0: sl@0: if (fAuxData == NULL) { sl@0: success = LE_MEMORY_ALLOCATION_ERROR; sl@0: return -1; sl@0: } sl@0: sl@0: return fGlyphCount; sl@0: } sl@0: sl@0: void LEGlyphStorage::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const sl@0: { sl@0: le_int32 i; sl@0: sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (charIndices == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fCharIndices == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: for (i = 0; i < fGlyphCount; i += 1) { sl@0: charIndices[i] = fCharIndices[i] + indexBase; sl@0: } sl@0: } sl@0: sl@0: void LEGlyphStorage::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (charIndices == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fCharIndices == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: LE_ARRAY_COPY(charIndices, fCharIndices, fGlyphCount); sl@0: } sl@0: sl@0: // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits sl@0: void LEGlyphStorage::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const sl@0: { sl@0: le_int32 i; sl@0: sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (glyphs == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fGlyphs == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: for (i = 0; i < fGlyphCount; i += 1) { sl@0: glyphs[i] = fGlyphs[i] | extraBits; sl@0: } sl@0: } sl@0: sl@0: void LEGlyphStorage::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (glyphs == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fGlyphs == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: LE_ARRAY_COPY(glyphs, fGlyphs, fGlyphCount); sl@0: } sl@0: sl@0: LEGlyphID LEGlyphStorage::getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0xFFFF; sl@0: } sl@0: sl@0: if (fGlyphs == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return 0xFFFF; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return 0xFFFF; sl@0: } sl@0: sl@0: return fGlyphs[glyphIndex]; sl@0: } sl@0: sl@0: void LEGlyphStorage::setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (fGlyphs == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: fGlyphs[glyphIndex] = glyphID; sl@0: } sl@0: sl@0: le_int32 LEGlyphStorage::getCharIndex(le_int32 glyphIndex, LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return -1; sl@0: } sl@0: sl@0: if (fCharIndices == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return -1; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return -1; sl@0: } sl@0: sl@0: return fCharIndices[glyphIndex]; sl@0: } sl@0: sl@0: void LEGlyphStorage::setCharIndex(le_int32 glyphIndex, le_int32 charIndex, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (fCharIndices == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: fCharIndices[glyphIndex] = charIndex; sl@0: } sl@0: sl@0: void LEGlyphStorage::getAuxData(void *auxData[], LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (auxData == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fAuxData == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: LE_ARRAY_COPY(auxData, fAuxData, fGlyphCount); sl@0: } sl@0: sl@0: void *LEGlyphStorage::getAuxData(le_int32 glyphIndex, LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return NULL; sl@0: } sl@0: sl@0: if (fAuxData == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return NULL; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return NULL; sl@0: } sl@0: sl@0: return fAuxData[glyphIndex]; sl@0: } sl@0: sl@0: void LEGlyphStorage::setAuxData(le_int32 glyphIndex, void *auxData, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (fAuxData == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex >= fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: fAuxData[glyphIndex] = auxData; sl@0: } sl@0: sl@0: void LEGlyphStorage::getGlyphPositions(float positions[], LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (positions == NULL) { sl@0: success = LE_ILLEGAL_ARGUMENT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fPositions == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: LE_ARRAY_COPY(positions, fPositions, fGlyphCount * 2 + 2); sl@0: } sl@0: sl@0: void LEGlyphStorage::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex > fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: if (fPositions == NULL) { sl@0: success = LE_NO_LAYOUT_ERROR; sl@0: return; sl@0: } sl@0: sl@0: x = fPositions[glyphIndex * 2]; sl@0: y = fPositions[glyphIndex * 2 + 1]; sl@0: } sl@0: sl@0: void LEGlyphStorage::setPosition(le_int32 glyphIndex, float x, float y, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex > fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: fPositions[glyphIndex * 2] = x; sl@0: fPositions[glyphIndex * 2 + 1] = y; sl@0: } sl@0: sl@0: void LEGlyphStorage::adjustPosition(le_int32 glyphIndex, float xAdjust, float yAdjust, LEErrorCode &success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: if (glyphIndex < 0 || glyphIndex > fGlyphCount) { sl@0: success = LE_INDEX_OUT_OF_BOUNDS_ERROR; sl@0: return; sl@0: } sl@0: sl@0: fPositions[glyphIndex * 2] += xAdjust; sl@0: fPositions[glyphIndex * 2 + 1] += yAdjust; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptGlyphArray(LEGlyphStorage &from) sl@0: { sl@0: if (fGlyphs != NULL) { sl@0: LE_DELETE_ARRAY(fGlyphs); sl@0: } sl@0: sl@0: fGlyphs = from.fGlyphs; sl@0: from.fGlyphs = NULL; sl@0: sl@0: if (fInsertionList != NULL) { sl@0: delete fInsertionList; sl@0: } sl@0: sl@0: fInsertionList = from.fInsertionList; sl@0: from.fInsertionList = NULL; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptCharIndicesArray(LEGlyphStorage &from) sl@0: { sl@0: if (fCharIndices != NULL) { sl@0: LE_DELETE_ARRAY(fCharIndices); sl@0: } sl@0: sl@0: fCharIndices = from.fCharIndices; sl@0: from.fCharIndices = NULL; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptPositionArray(LEGlyphStorage &from) sl@0: { sl@0: if (fPositions != NULL) { sl@0: LE_DELETE_ARRAY(fPositions); sl@0: } sl@0: sl@0: fPositions = from.fPositions; sl@0: from.fPositions = NULL; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptAuxDataArray(LEGlyphStorage &from) sl@0: { sl@0: if (fAuxData != NULL) { sl@0: LE_DELETE_ARRAY(fAuxData); sl@0: } sl@0: sl@0: fAuxData = from.fAuxData; sl@0: from.fAuxData = NULL; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from) sl@0: { sl@0: fGlyphCount = from.fGlyphCount; sl@0: } sl@0: sl@0: void LEGlyphStorage::adoptGlyphCount(le_int32 newGlyphCount) sl@0: { sl@0: fGlyphCount = newGlyphCount; sl@0: } sl@0: sl@0: LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32 atIndex, le_int32 insertCount, sl@0: LEErrorCode& success) sl@0: { sl@0: return fInsertionList->insert(atIndex, insertCount, success); sl@0: } sl@0: sl@0: le_int32 LEGlyphStorage::applyInsertions() sl@0: { sl@0: le_int32 growAmount = fInsertionList->getGrowAmount(); sl@0: sl@0: if (growAmount == 0) { sl@0: return fGlyphCount; sl@0: } sl@0: sl@0: le_int32 newGlyphCount = fGlyphCount + growAmount; sl@0: sl@0: LEGlyphID *newGlyphs = (LEGlyphID *) LE_GROW_ARRAY(fGlyphs, newGlyphCount); sl@0: if (!newGlyphs) { sl@0: // Could not grow the glyph array sl@0: return fGlyphCount; sl@0: } sl@0: fGlyphs = newGlyphs; sl@0: sl@0: le_int32 *newCharIndices = (le_int32 *) LE_GROW_ARRAY(fCharIndices, newGlyphCount); sl@0: if (!newCharIndices) { sl@0: // Could not grow the glyph array sl@0: return fGlyphCount; sl@0: } sl@0: fCharIndices = newCharIndices; sl@0: sl@0: if (fAuxData != NULL) { sl@0: void **newAuxData = (void **) LE_GROW_ARRAY(fAuxData, newGlyphCount); sl@0: if (!newAuxData) { sl@0: // could not grow the aux data array sl@0: return fGlyphCount; sl@0: } sl@0: fAuxData = newAuxData; sl@0: } sl@0: sl@0: fSrcIndex = fGlyphCount - 1; sl@0: fDestIndex = newGlyphCount - 1; sl@0: sl@0: #if 0 sl@0: // If the current position is at the end of the array sl@0: // update it to point to the end of the new array. The sl@0: // insertion callback will handle all other cases. sl@0: // FIXME: this is left over from GlyphIterator, but there's no easy sl@0: // way to implement this here... it seems that GlyphIterator doesn't sl@0: // really need it 'cause the insertions don't get applied until after a sl@0: // complete pass over the glyphs, after which the iterator gets reset anyhow... sl@0: // probably better to just document that for LEGlyphStorage and GlyphIterator... sl@0: if (position == glyphCount) { sl@0: position = newGlyphCount; sl@0: } sl@0: #endif sl@0: sl@0: fInsertionList->applyInsertions(this); sl@0: sl@0: fInsertionList->reset(); sl@0: sl@0: return fGlyphCount = newGlyphCount; sl@0: } sl@0: sl@0: le_bool LEGlyphStorage::applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[]) sl@0: { sl@0: #if 0 sl@0: // if the current position is within the block we're shifting sl@0: // it needs to be updated to the current glyph's sl@0: // new location. sl@0: // FIXME: this is left over from GlyphIterator, but there's no easy sl@0: // way to implement this here... it seems that GlyphIterator doesn't sl@0: // really need it 'cause the insertions don't get applied until after a sl@0: // complete pass over the glyphs, after which the iterator gets reset anyhow... sl@0: // probably better to just document that for LEGlyphStorage and GlyphIterator... sl@0: if (position >= atPosition && position <= fSrcIndex) { sl@0: position += fDestIndex - fSrcIndex; sl@0: } sl@0: #endif sl@0: sl@0: if (fAuxData != NULL) { sl@0: le_int32 src = fSrcIndex, dest = fDestIndex; sl@0: sl@0: while (src > atPosition) { sl@0: fAuxData[dest--] = fAuxData[src--]; sl@0: } sl@0: sl@0: for (le_int32 i = count - 1; i >= 0; i -= 1) { sl@0: fAuxData[dest--] = fAuxData[atPosition]; sl@0: } sl@0: } sl@0: sl@0: while (fSrcIndex > atPosition) { sl@0: fGlyphs[fDestIndex] = fGlyphs[fSrcIndex]; sl@0: fCharIndices[fDestIndex] = fCharIndices[fSrcIndex]; sl@0: sl@0: fDestIndex -= 1; sl@0: fSrcIndex -= 1; sl@0: } sl@0: sl@0: for (le_int32 i = count - 1; i >= 0; i -= 1) { sl@0: fGlyphs[fDestIndex] = newGlyphs[i]; sl@0: fCharIndices[fDestIndex] = fCharIndices[atPosition]; sl@0: sl@0: fDestIndex -= 1; sl@0: } sl@0: sl@0: // the source glyph we're pointing at sl@0: // just got replaced by the insertion sl@0: fSrcIndex -= 1; sl@0: sl@0: return FALSE; sl@0: } sl@0: sl@0: void LEGlyphStorage::forMlylRakar(LEGlyphID aGlyphID) sl@0: { sl@0: le_int32 i, j; sl@0: sl@0: if (fGlyphs == NULL) { sl@0: return; sl@0: } sl@0: sl@0: for (i = 0; i < fGlyphCount; i++) { sl@0: if (fGlyphs[i] == aGlyphID) { sl@0: j = i - 1; sl@0: while (j>=0 && fGlyphs[j] == 0xFFFF) { sl@0: j--; sl@0: } sl@0: sl@0: if (j>=0 && fGlyphs[j] != 0xFFFF && fGlyphs[j] != aGlyphID) { sl@0: fGlyphs[i] = fGlyphs[j]; sl@0: fGlyphs[j] = aGlyphID; sl@0: sl@0: le_int32 tempCharIndex = fCharIndices[j]; sl@0: fCharIndices[j] = fCharIndices[i]; sl@0: fCharIndices[i] = tempCharIndex; sl@0: sl@0: void * tempAuxData = fAuxData[j]; sl@0: fAuxData[j] = fAuxData[i]; sl@0: fAuxData[i] = fAuxData[j]; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: U_NAMESPACE_END sl@0: