ICU4C API Proposal: LEGlyphStorage

Eric Mader <[email protected]> Wed, 05 May 2004 11:13:02 -0700
Newsgroups gmane.comp.lib.icu.general
Message-ID <[email protected]>
(I origially sent this proposal to the wrong list; sorry if you've 
already seen this)

The main part of this proposal is to add a class to the ICU LayoutEngine 
which encapsulates all of the per-glyph storage. This proposal also 
includes the class LEInsertionList, which is used to support dynamic 
growing of the per-glyph arrays. Finally, the proposal includes a change 
to LEFontInstance::mapCharsToGlyphs to use the new LEGlyphStorage class.

Eric Mader
IBM GCoC - San José
5600 Cottle Road  M/S 50-2/B11
San Jose, CA 95193

LEGlyphStorage.h:
----------------------------------------------------------------------------------------------------
/*
  **********************************************************************
  *   Copyright (C) 1998-2004, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  **********************************************************************
  */

#ifndef __LEGLYPHSTORAGE_H
#define __LEGLYPHSTORAGE_H

#include "LETypes.h"
#include "LEInsertionList.h"

U_NAMESPACE_BEGIN

/**
  * This class encapsulates the per-glyph storage used by the ICU 
LayoutEngine.
  * For each glyph it holds the glyph ID, the index of the backing store 
character
  * which produced the glyph, the X and Y position of the glyph and an 
auxillary data
  * pointer.
  *
  * The storage is growable using the <code>LEInsertionList</code> class.
  *
  *
  * @see LEInsertionList.h
  *
  * @draft ICU 3.0
  */
class U_LAYOUT_API LEGlyphStorage : public UObject, protected 
LEInsertionCallback
{
private:
     /*
      * [Private members not shown]
      */

protected:
     /**
      * This implements <code>LEInsertionCallback</code>. The 
<code>LEInsertionList</code>
      * will call this method once for each insertion.
      *
      * @param atPosition the position of the insertion
      * @param count the number of glyphs being inserted
      * @param newGlyphs the address of the new glyph IDs
      *
      * @return <code>true</code> if <code>LEInsertionList</code> should 
stop
      *         processing the insertion list after this insertion.
      *
      * @see LEInsertionList.h
      *
      * @draft ICU 3.0
      */
     virtual le_bool applyInsertion(le_int32 atPosition, le_int32 count, 
LEGlyphID newGlyphs[]);

public:

     /**
      * Allocates an empty <code>LEGlyphStorage</code> object. You must call
      * <code>allocateGlyphArray, allocatePositions and 
allocateAuxData</code>
      * to allocate the data.
      */
     LEGlyphStorage();

     /**
      * The destructor. This will deallocate all of the arrays.
      */
     ~LEGlyphStorage();

     /**
      * This method returns the number of glyphs in the glyph array.
      *
      * @return the number of glyphs in the glyph array
      *
      * @draft ICU 3.0
      */
     le_int32 getGlyphCount() const
     {
         return fGlyphCount;
     };

     /**
      * This method copies the glyph array into a caller supplied array.
      * The caller must ensure that the array is large enough to hold all
      * the glyphs.
      *
      * @param glyphs - the destiniation glyph array
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const;

     /**
      * This method copies the glyph array into a caller supplied array,
      * ORing in extra bits. (This functionality is needed by the JDK,
      * which uses 32 bits pre glyph idex, with the high 16 bits encoding
      * the composite font slot number)
      *
      * @param glyphs - the destination (32 bit) glyph array
      * @param extraBits - this value will be ORed with each glyph index
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode 
&success) const;

     /**
      * This method copies the character index array into a caller 
supplied array.
      * The caller must ensure that the array is large enough to hold a
      * character index for each glyph.
      *
      * @param charIndices - the destiniation character index array
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getCharIndices(le_int32 charIndices[], LEErrorCode &success) 
const;

     /**
      * This method copies the character index array into a caller 
supplied array.
      * The caller must ensure that the array is large enough to hold a
      * character index for each glyph.
      *
      * @param charIndices - the destiniation character index array
      * @param indexBase - an offset which will be added to each index
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getCharIndices(le_int32 charIndices[], le_int32 indexBase, 
LEErrorCode &success) const;

     /**
      * This method copies the position array into a caller supplied array.
      * The caller must ensure that the array is large enough to hold an
      * X and Y position for each glyph, plus an extra X and Y for the
      * advance of the last glyph.
      *
      * @param glyphs - the destiniation position array
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getGlyphPositions(float positions[], LEErrorCode &success) const;

     /**
      * This method returns the X and Y position of the glyph at
      * the given index.
      *
      * Input parameters:
      * @param glyphIndex - the index of the glyph
      *
      * Output parameters:
      * @param x - the glyph's X position
      * @param y - the glyph's Y position
      * @param success - set to an error code if the operation fails
      *
      * @draft ICU 3.0
      */
     void getGlyphPosition(le_int32 glyphIndex, float &x, float &y, 
LEErrorCode &success) const;

     /**
      * This method allocates the glyph array, the char indices array 
and the insertion list. You
      * must call this method before using the object. This method also 
initializes the char indices
      * array.
      *
      * @param initialGlyphCount the initial size of the glyph and char 
indices arrays.
      * @param rightToLeft <code>true</code> if the original input text 
is right to left.
      * @param success set to an error code if the storage cannot be 
allocated of if the initial
      *        glyph count is not positive.
      *
      * @draft ICU 3.0
      */
     void allocateGlyphArray(le_int32 initialGlyphCount, le_bool 
rightToLeft, LEErrorCode &success);

     /**
      * This method allocates the storage for the glyph positions. It 
allocates one extra X, Y
      * position pair for the position just after the last glyph.
      *
      * @param success set to an error code if the positions array 
cannot be allocated.
      *
      * @return the number of X, Y position pairs allocated.
      *
      * @draft ICU 3.0
      */
     le_int32 allocatePositions(LEErrorCode &success);

     /**
      * This method allocates the storage for the auxillary glyph data.
      *
      * @param success set to an error code if the aulillary data array 
cannot be allocated.
      *
      * @return the size of the auxillary data array.
      *
      * @draft ICU 3.0
      */
     le_int32 allocateAuxData(LEErrorCode &success);

     /**
      * Copy the entire auxillary data array.
      *
      * @param auxData the auxillary data array will be copied to this 
address
      * @param success set to an error code if the data cannot be copied
      *
      * @draft ICU 3.0
      */
     void getAuxData(void *auxData[], LEErrorCode &success) const;

     /**
      * Get the glyph ID for a particular glyph.
      *
      * @param glyphIndex the index into the glyph array
      * @param success set to an error code if the glyph ID cannot be 
retrieved.
      *
      * @return the glyph ID
      *
      * @draft ICU 3.0
      */
     LEGlyphID getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const;

     /**
      * Get the char index for a particular glyph.
      *
      * @param glyphIndex the index into the glyph array
      * @param success set to an error code if the char index cannot be 
retrieved.
      *
      * @return the character index
      *
      * @draft ICU 3.0
      */
     le_int32  getCharIndex(le_int32 glyphIndex, LEErrorCode &success) 
const;


     /**
      * Get the auxillary data for a particular glyph.
      *
      * @param glyphIndex the index into the glyph array
      * @param success set to an error code if the auxillary data cannot 
be retrieved.
      *
      * @return the auxillary data
      *
      * @draft ICU 3.0
      */
     void *getAuxData(le_int32 glyphIndex, LEErrorCode &success) const;

     /**
      * This operator allows direct access to the glyph array
      * using the index operator.
      *
      * @param glyphIndex the index into the glyph array
      *
      * @return a reference to the given location in the glyph array
      *
      * @draft ICU 3.0
      */
     LEGlyphID &operator[](le_int32 glyphIndex) const;

     /**
      * Call this method to replace a single glyph in the glyph array
      * with multiple glyphs. This method uses the 
<code>LEInsertionList</code>
      * to do the insertion. It returns the address of storage where the new
      * glyph IDs can be stored. They will not actually be inserted into the
      * glyph array until <code>applyInsertions</code> is called.
      *
      * @param atIndex the index of the glyph to be replaced
      * @param insertCount the number of glyphs to replace it with
      *
      * @return the address at which to store the replacement glyphs.
      *
      * @see LEInsetionList.h
      *
      * @draft ICU 3.0
      */
     LEGlyphID *insertGlyphs(le_int32 atIndex, le_int32 insertCount);

     /**
      * This method causes all of the glyph insertions recorded by
      * <code>insertGlyphs</code> to be applied to the glyph array. The
      * new slots in the char indices and the auxillary data arrays
      * will be filled in with the values for the glyph being replaced.
      *
      * @return the new size of the glyph array
      *
      * @see LEInsertionList.h
      *
      * @draft ICU 3.0
      */
     le_int32 applyInsertions();

     /**
      * Set the glyph ID for a particular glyph.
      *
      * @param glyphIndex the index of the glyph
      * @param glyphID the new glyph ID
      * @param success will be set to an error code if the glyph ID 
cannot be set.
      *
      * @draft ICU 3.0
      */
     void setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode 
&success);

     /**
      * Set the char index for a particular glyph.
      *
      * @param glyphIndex the index of the glyph
      * @param charIndex the new char index
      * @param success will be set to an error code if the char index 
cannot be set.
      *
      * @draft ICU 3.0
      */
     void setCharIndex(le_int32 glyphIndex, le_int32 charIndex, 
LEErrorCode &success);

     /**
      * Set the X, Y position for a particular glyph.
      *
      * @param glyphIndex the index of the glyph
      * @param x the new X position
      * @param y the new Y position
      * @param success will be set to an error code if the position 
cannot be set.
      *
      * @draft ICU 3.0
      */
     void setPosition(le_int32 glyphIndex, float x, float y, LEErrorCode 
&success);

     /**
      * Adjust the X, Y position for a particular glyph.
      *
      * @param glyphIndex the index of the glyph
      * @param xAdjust the adjustment to the glyph's X position
      * @param yAdjust the adjustment to the glyph's Y position
      * @param success will be set to an error code if the glyph's 
position cannot be adjusted.
      *
      * @draft ICU 3.0
      */
     void adjustPosition(le_int32 glyphIndex, float xAdjust, float 
yAdjust, LEErrorCode &success);

     /**
      * Set the auxillary data for a particular glyph.
      *
      * @param glyphIndex the index of the glyph
      * @param auxData the new auxillary data
      * @param success will be set to an error code if the auxillary 
data cannot be set.
      *
      * @draft ICU 3.0
      */
     void setAuxData(le_int32 glyphIndex, void *auxData, LEErrorCode 
&success);

     /**
      * Delete the glyph array and replace it with the one
      * in <code>from</code>. Set the glyph array pointer
      * in <code>from</code> to <code>NULL</code>.
      *
      * @param from the <code>LEGlyphStorage</code> object from which
      *             to get the new glyph array.
      *
      * @draft ICU 3.0
      */
     void adoptGlyphArray(LEGlyphStorage &from);

     /**
      * Delete the char indices array and replace it with the one
      * in <code>from</code>. Set the char indices array pointer
      * in <code>from</code> to <code>NULL</code>.
      *
      * @param from the <code>LEGlyphStorage</code> object from which
      *             to get the new char indices array.
      *
      * @draft ICU 3.0
      */
     void adoptCharIndicesArray(LEGlyphStorage &from);

     /**
      * Delete the position array and replace it with the one
      * in <code>from</code>. Set the position array pointer
      * in <code>from</code> to <code>NULL</code>.
      *
      * @param from the <code>LEGlyphStorage</code> object from which
      *             to get the new position array.
      *
      * @draft ICU 3.0
      */
     void adoptPositionArray(LEGlyphStorage &from);

     /**
      * Delete the auxillary data array and replace it with the one
      * in <code>from</code>. Set the auxillary data array pointer
      * in <code>from</code> to <code>NULL</code>.
      *
      * @param from the <code>LEGlyphStorage</code> object from which
      *             to get the new auxillary data array.
      *
      * @draft ICU 3.0
      */
     void adoptAuxDataArray(LEGlyphStorage &from);

     /**
      * Change the glyph count of this object to be the same
      * as the one in <code>from</code>.
      *
      * @param from the <code>LEGlyphStorage</code> object from which
      *             to get the new glyph count.
      *
      * @draft ICU 3.0
      */
     void adoptGlyphCount(LEGlyphStorage &from);

     /**
      * Change the glyph count of this object to the given value.
      *
      * @param newGlyphCount the new glyph count.
      *
      * @draft ICU 3.0
      */
     void adoptGlyphCount(le_int32 newGlyphCount);

     /**
      * This method frees the glyph, character index, position  and
      * auxillary data arrays so that the LayoutEngine can be reused
      * to layout a different characer array. (This method is also called
      * by the destructor)
      *
      * @draft ICU 3.0
      */
     void reset();

     /**
      * ICU "poor man's RTTI", returns a UClassID for the actual class.
      *
      * @darft ICU 3.0
      */
     virtual inline UClassID getDynamicClassID() const { return 
getStaticClassID(); }

     /**
      * ICU "poor man's RTTI", returns a UClassID for this class.
      *
      * @draft ICU 3.0
      */
     static inline UClassID getStaticClassID() { return 
(UClassID)&fgClassID; }
};

inline LEGlyphID &LEGlyphStorage::operator[](le_int32 glyphIndex) const
{
     return fGlyphs[glyphIndex];
}


U_NAMESPACE_END
#endif

LEInertionList.h:
----------------------------------------------------------------------------------------------------
/*
  **********************************************************************
  *   Copyright (C) 1998-2004, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  **********************************************************************
  */

#ifndef __LEINSERTIONLIST_H
#define __LEINSERTIONLIST_H

#include "LETypes.h"

U_NAMESPACE_BEGIN

struct InsertionRecord;

/**
  * This class encapsulates the callback used by 
<code>LEInsertionList</code>
  * to apply an insertion from the insertion list.
  *
  * @internal
  */
class LEInsertionCallback
{
public:
     /**
      * This method will be called by 
<code>LEInsertionList::applyInsertions</code> for each
      * entry on the insertion list.
      *
      * @param atPosition the position of the insertion
      * @param count the number of glyphs to insert
      * @param newGlyphs the address of the glyphs to insert
      *
      * @return <code>TRUE</code> if 
<code>LEInsertions::applyInsertions</code> should
      *         stop after applying this insertion.
      *
      * @internal
      */
     virtual le_bool applyInsertion(le_int32 atPosition, le_int32 count, 
LEGlyphID newGlyphs[]) = 0;
};

/**
  * This class is used to keep track of insertions to an array of
  * <code>LEGlyphIDs</code>. The insertions are kept on a linked
  * list of <code>InsertionRecords</code> so that the glyph array
  * doesn't have to be grown for each insertion. The insertions are
  * stored on the list from leftmost to rightmost to make it easier
  * to do the insertions.
  *
  * The insertions are applied to the array by calling the
  * <code>applyInsertions</code> method, which calls a client
  * supplied <code>LEInsertionCallback</code> object to actually
  * apply the individual insertions.
  *
  * @internal
  */
class LEInsertionList : public UObject
{
public:
     /**
      * Construct an empty insertion list.
      *
      * @param rightToLeft <code>TRUE</code> if the glyphs are stored
      *                    in the array in right to left order.
      *
      * @internal
      */
     LEInsertionList(le_bool rightToLeft);

     /**
      * The destructor.
      */
     ~LEInsertionList();

     /**
      * Add an entry to the insertion list.
      *
      * @param position the glyph at this position in the array will be
      *                 replaced by the new glyphs.
      * @param count the number of new glyphs
      *
      * @return the address of an array in which to store the new 
glyphs. This will
      *         <em>not</em> be in the glyph array.
      *
      * @internal
      */
     LEGlyphID *insert(le_int32 position, le_int32 count);

     /**
      * Return the number of new glyphs that have been inserted.
      *
      * @return the number of new glyphs which have been inserted
      *
      * @internal
      */
     le_int32 getGrowAmount();

     /**
      * Call the <code>LEInsertionCallback</code> once for each
      * entry on the insertion list.
      *
      * @param callback the <code>LEInsertionCallback</code> to call for 
each insertion.
      *
      * @return <code>TRUE</code> if <code>callback</code> returned 
<code>TRUE</code> to
      *         terminate the insertion list processing.
      *
      * @internal
      */
     le_bool applyInsertions(LEInsertionCallback *callback);

     /**
      * Empty the insertion list and free all associated
      * storage.
      *
      * @internal
      */
     void reset();

     /**
      * ICU "poor man's RTTI", returns a UClassID for the actual class.
      *
      * @stable ICU 2.8
      */
     virtual inline UClassID getDynamicClassID() const { return 
getStaticClassID(); }

     /**
      * ICU "poor man's RTTI", returns a UClassID for this class.
      *
      * @stable ICU 2.8
      */
     static inline UClassID getStaticClassID() { return 
(UClassID)&fgClassID; }

private:

     /*
      * [private members not shown]
      */
};

U_NAMESPACE_END
#endif

Change to LEFontInstance.h:
----------------------------------------------------------------------------------------------------

     /**
      * This method maps an array of character codes to an array of glyph
      * indices, using the font's character to glyph map.
      *
      * The default implementation iterates over all of the characters 
and calls
      * <code>mapCharToGlyph(ch, mapper)</code> on each one. It also 
handles surrogate
      * characters, storing the glyph ID for the high surrogate, and a 
deleted glyph (0xFFFF)
      * for the low surrogate.
      *
      * Most sublcasses will not need to implement this method.
      *
      * @param chars - the character array
      * @param offset - the index of the first character
      * @param count - the number of characters
      * @param reverse - if <code>TRUE</code>, store the glyph indices 
in reverse order.
      * @param mapper - the character mapper.
      * @param glyphStorage - the object which contains the output glyph 
array
      *
      * @see LECharMapper
      *
      * @draft ICU 3.0
      */
     virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 
offset, le_int32 count, le_bool reverse, const LECharMapper *mapper, 
LEGlyphStorage &glyphStorage) const;