diff --git a/.gitattributes b/.gitattributes
index 3323978257f..ea40b039699 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -88,6 +88,9 @@ icu4c/source/i18n/persncal.cpp -text
icu4c/source/i18n/persncal.h -text
icu4c/source/i18n/reldtfmt.cpp -text
icu4c/source/i18n/reldtfmt.h -text
+icu4c/source/samples/layout/cgnomelayout.c -text
+icu4c/source/samples/layout/gnomeglue.cpp -text
+icu4c/source/samples/layout/gnomeglue.h -text
icu4c/source/samples/ucnv/data02.bin -text
icu4c/source/test/compat/Makefile.in -text
icu4c/source/test/compat/readme.txt -text
diff --git a/icu4c/source/layout/CursiveAttachmentSubtables.cpp b/icu4c/source/layout/CursiveAttachmentSubtables.cpp
index 40c38fa49ce..9d2144fcefa 100644
--- a/icu4c/source/layout/CursiveAttachmentSubtables.cpp
+++ b/icu4c/source/layout/CursiveAttachmentSubtables.cpp
@@ -1,5 +1,5 @@
/*
- * (C) Copyright IBM Corp. 1998 - 2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998 - 2007 - All Rights Reserved
*
*/
@@ -34,6 +34,8 @@ le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const
entryAnchorTable->getAnchor(glyphID, fontInstance, entryAnchor);
glyphIterator->setCursiveEntryPoint(entryAnchor);
+ } else {
+ //glyphIterator->clearCursiveEntryPoint();
}
if (exitOffset != 0) {
@@ -41,6 +43,8 @@ le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const
exitAnchorTable->getAnchor(glyphID, fontInstance, exitAnchor);
glyphIterator->setCursiveExitPoint(exitAnchor);
+ } else {
+ //glyphIterator->clearCursiveExitPoint();
}
return 1;
diff --git a/icu4c/source/layout/GlyphIterator.cpp b/icu4c/source/layout/GlyphIterator.cpp
index 91c5d5684ca..b60dfb00323 100644
--- a/icu4c/source/layout/GlyphIterator.cpp
+++ b/icu4c/source/layout/GlyphIterator.cpp
@@ -1,6 +1,6 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
*
*/
@@ -274,6 +274,36 @@ void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float
glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust);
}
+void GlyphIterator::clearCursiveEntryPoint()
+{
+ if (direction < 0) {
+ if (position <= nextLimit || position >= prevLimit) {
+ return;
+ }
+ } else {
+ if (position <= prevLimit || position >= nextLimit) {
+ return;
+ }
+ }
+
+ glyphPositionAdjustments->clearEntryPoint(position);
+}
+
+void GlyphIterator::clearCursiveExitPoint()
+{
+ if (direction < 0) {
+ if (position <= nextLimit || position >= prevLimit) {
+ return;
+ }
+ } else {
+ if (position <= prevLimit || position >= nextLimit) {
+ return;
+ }
+ }
+
+ glyphPositionAdjustments->clearExitPoint(position);
+}
+
void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint)
{
if (direction < 0) {
diff --git a/icu4c/source/layout/GlyphIterator.h b/icu4c/source/layout/GlyphIterator.h
index 6ecf83a92a4..4b4ba97e57b 100644
--- a/icu4c/source/layout/GlyphIterator.h
+++ b/icu4c/source/layout/GlyphIterator.h
@@ -1,6 +1,6 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
*
*/
@@ -63,6 +63,8 @@ public:
void setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
float xAdvanceAdjust, float yAdvanceAdjust);
+ void clearCursiveEntryPoint();
+ void clearCursiveExitPoint();
void setCursiveEntryPoint(LEPoint &entryPoint);
void setCursiveExitPoint(LEPoint &exitPoint);
void setCursiveGlyph();
diff --git a/icu4c/source/layout/GlyphPositionAdjustments.cpp b/icu4c/source/layout/GlyphPositionAdjustments.cpp
index c7e57ef1329..4a4b33b91f9 100644
--- a/icu4c/source/layout/GlyphPositionAdjustments.cpp
+++ b/icu4c/source/layout/GlyphPositionAdjustments.cpp
@@ -1,6 +1,6 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
*
*/
@@ -46,6 +46,20 @@ const LEPoint *GlyphPositionAdjustments::getExitPoint(le_int32 index, LEPoint &e
return fEntryExitPoints[index].getExitPoint(exitPoint);
}
+void GlyphPositionAdjustments::clearEntryPoint(le_int32 index)
+{
+ CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+ fEntryExitPoints[index].clearEntryPoint();
+}
+
+void GlyphPositionAdjustments::clearExitPoint(le_int32 index)
+{
+ CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+ fEntryExitPoints[index].clearExitPoint();
+}
+
void GlyphPositionAdjustments::setEntryPoint(le_int32 index, LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd)
{
CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
diff --git a/icu4c/source/layout/GlyphPositionAdjustments.h b/icu4c/source/layout/GlyphPositionAdjustments.h
index 31146e56f9b..9c9e39bffe6 100644
--- a/icu4c/source/layout/GlyphPositionAdjustments.h
+++ b/icu4c/source/layout/GlyphPositionAdjustments.h
@@ -1,6 +1,6 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
*
*/
@@ -72,6 +72,8 @@ private:
LEPoint *getEntryPoint(LEPoint &entryPoint) const;
LEPoint *getExitPoint(LEPoint &exitPoint) const;
+ inline void clearEntryPoint();
+ inline void clearExitPoint();
inline void setEntryPoint(LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd);
inline void setExitPoint(LEPoint &newExitPoint, le_bool baselineIsLogicalEnd);
inline void setCursiveGlyph(le_bool baselineIsLogicalEnd);
@@ -126,6 +128,8 @@ public:
inline void adjustXAdvance(le_int32 index, float xAdjustment);
inline void adjustYAdvance(le_int32 index, float yAdjustment);
+ void clearEntryPoint(le_int32 index);
+ void clearExitPoint(le_int32 index);
void setEntryPoint(le_int32 index, LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd);
void setExitPoint(le_int32 index, LEPoint &newExitPoint, le_bool baselineIsLogicalEnd);
void setCursiveGlyph(le_int32 index, le_bool baselineIsLogicalEnd);
@@ -241,6 +245,16 @@ inline le_bool GlyphPositionAdjustments::EntryExitPoint::baselineIsLogicalEnd()
return (fFlags & EEF_BASELINE_IS_LOGICAL_END) != 0;
}
+inline void GlyphPositionAdjustments::EntryExitPoint::clearEntryPoint()
+{
+ fFlags &= ~EEF_HAS_ENTRY_POINT;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::clearExitPoint()
+{
+ fFlags &= ~EEF_HAS_EXIT_POINT;
+}
+
inline void GlyphPositionAdjustments::EntryExitPoint::setEntryPoint(LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd)
{
if (baselineIsLogicalEnd) {
diff --git a/icu4c/source/layout/LETypes.h b/icu4c/source/layout/LETypes.h
index 51da9cb513c..4903a1c0d3a 100644
--- a/icu4c/source/layout/LETypes.h
+++ b/icu4c/source/layout/LETypes.h
@@ -1,6 +1,6 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
*
*/
@@ -12,7 +12,10 @@
#endif
#include "unicode/utypes.h"
+
+#ifdef XP_CPLUSPLUS
#include "unicode/uobject.h"
+#endif
#ifdef LE_USE_CMEMORY
#include "cmemory.h"
diff --git a/icu4c/source/layout/LayoutEngine.cpp b/icu4c/source/layout/LayoutEngine.cpp
index d2d9fe581d8..eb4ea8e7f2f 100644
--- a/icu4c/source/layout/LayoutEngine.cpp
+++ b/icu4c/source/layout/LayoutEngine.cpp
@@ -26,6 +26,7 @@
#include "OpenTypeUtilities.h"
#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
#include "MorphTables.h"
#include "DefaultCharMapper.h"
@@ -86,6 +87,37 @@ CharSubstitutionFilter::~CharSubstitutionFilter()
// nothing to do
}
+class CanonMarkFilter : public UMemory, public LEGlyphFilter
+{
+private:
+ const GlyphClassDefinitionTable *classDefTable;
+
+ CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class
+ CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class
+
+public:
+ CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable);
+ virtual ~CanonMarkFilter();
+
+ virtual le_bool accept(LEGlyphID glyph) const;
+};
+
+CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
+{
+ classDefTable = gdefTable->getMarkAttachClassDefinitionTable();
+}
+
+CanonMarkFilter::~CanonMarkFilter()
+{
+ // nothing to do?
+}
+
+le_bool CanonMarkFilter::accept(LEGlyphID glyph) const
+{
+ le_int32 glyphClass = classDefTable->getGlyphClass(glyph);
+
+ return glyphClass != 0;
+}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
@@ -279,7 +311,7 @@ void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y
glyphStorage.setPosition(glyphCount, x, y, success);
}
-void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/,
+void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
if (LE_FAILURE(success)) {
@@ -291,6 +323,11 @@ void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset
return;
}
+ GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
+ CanonMarkFilter filter(gdefTable);
+
+ adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
+
if (fTypoFlags & 0x1) { /* kerning enabled */
static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
diff --git a/icu4c/source/layout/Makefile.in b/icu4c/source/layout/Makefile.in
index caeaafa058d..d77746aaf96 100644
--- a/icu4c/source/layout/Makefile.in
+++ b/icu4c/source/layout/Makefile.in
@@ -1,6 +1,6 @@
#******************************************************************************
#
-# Copyright (C) 1999-2006, International Business Machines
+# Copyright (C) 1999-2007, International Business Machines
# Corporation and others. All Rights Reserved.
#
#******************************************************************************
@@ -132,10 +132,11 @@ KhmerReordering.o \
TibetanLayoutEngine.o \
TibetanReordering.o \
HangulLayoutEngine.o \
-KernTable.o
+KernTable.o \
+loengine.o
## Header files to install
-HEADERS= $(srcdir)/LayoutEngine.h $(srcdir)/LE*.h
+HEADERS= $(srcdir)/LayoutEngine.h $(srcdir)/LE*.h $(srcdir)/loengine.h
STATIC_OBJECTS = $(OBJECTS:.o=.$(STATIC_O))
diff --git a/icu4c/source/layout/OpenTypeLayoutEngine.cpp b/icu4c/source/layout/OpenTypeLayoutEngine.cpp
index a2baee44558..abc9ebf8d1c 100644
--- a/icu4c/source/layout/OpenTypeLayoutEngine.cpp
+++ b/icu4c/source/layout/OpenTypeLayoutEngine.cpp
@@ -332,6 +332,19 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3
delete adjustments;
}
+ LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C);
+ LEGlyphID nbsp = fFontInstance->mapCharToGlyph(0x00A0);
+
+ for (le_int32 g = 0; g < glyphCount; g += 1) {
+ LEGlyphID glyph = glyphStorage[g];
+
+ if (glyph == zwnj) {
+ glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF);
+ } else if (glyph == nbsp) {
+ glyphStorage[g] = LE_SET_GLYPH(glyph, 0x0003);
+ }
+ }
+
#if 0
// Don't know why this is here...
LE_DELETE_ARRAY(fFeatureTags);
diff --git a/icu4c/source/layout/layout.vcproj b/icu4c/source/layout/layout.vcproj
index db94f04ca46..6635468b41d 100644
--- a/icu4c/source/layout/layout.vcproj
+++ b/icu4c/source/layout/layout.vcproj
@@ -369,6 +369,10 @@
RelativePath=".\LigatureSubstSubtables.cpp"
>
+
+
@@ -872,6 +876,19 @@
RelativePath=".\LigatureSubstSubtables.h"
>
+
+
+
+
+
diff --git a/icu4c/source/layout/loengine.cpp b/icu4c/source/layout/loengine.cpp
new file mode 100644
index 00000000000..3718b9f6f8a
--- /dev/null
+++ b/icu4c/source/layout/loengine.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "loengine.h"
+#include "LayoutEngine.h"
+
+/**
+ * \file
+ * \brief C API for complex text layout.
+ */
+
+U_NAMESPACE_USE
+
+U_CAPI le_engine * U_EXPORT2
+le_create(const le_font *font,
+ le_int32 scriptCode,
+ le_int32 languageCode,
+ le_int32 typo_flags,
+ LEErrorCode *success)
+{
+ LEFontInstance *fontInstance = (LEFontInstance *) font;
+
+ return (le_engine *) LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, typo_flags, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_close(le_engine *engine)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ delete le;
+}
+
+U_CAPI le_int32 U_EXPORT2
+le_layoutChars(le_engine *engine,
+ const LEUnicode chars[],
+ le_int32 offset,
+ le_int32 count,
+ le_int32 max,
+ le_bool rightToLeft,
+ float x,
+ float y,
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ return le->layoutChars(chars, offset, count, max, rightToLeft, x, y, *success);
+}
+
+U_CAPI le_int32 U_EXPORT2
+le_getGlyphCount(le_engine *engine,
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ return le->getGlyphCount();
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphs(le_engine *engine,
+ LEGlyphID glyphs[],
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->getGlyphs(glyphs, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getCharIndices(le_engine *engine,
+ le_int32 charIndices[],
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->getCharIndices(charIndices, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getCharIndicesWithBase(le_engine *engine,
+ le_int32 charIndices[],
+ le_int32 indexBase,
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->getCharIndices(charIndices, indexBase, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphPositions(le_engine *engine,
+ float positions[],
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->getGlyphPositions(positions, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphPosition(le_engine *engine,
+ le_int32 glyphIndex,
+ float *x,
+ float *y,
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->getGlyphPosition(glyphIndex, *x, *y, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_reset(le_engine *engine,
+ LEErrorCode *success)
+{
+ LayoutEngine *le = (LayoutEngine *) engine;
+
+ if (le == NULL) {
+ *success = LE_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ le->reset();
+}
diff --git a/icu4c/source/layout/loengine.h b/icu4c/source/layout/loengine.h
new file mode 100644
index 00000000000..a3a78ce33f8
--- /dev/null
+++ b/icu4c/source/layout/loengine.h
@@ -0,0 +1,223 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __LOENGINE_H
+#define __LOENGINE_H
+
+#include "LETypes.h"
+
+/**
+ * \file
+ * \brief C API for complex text layout.
+ * \internal
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * The opaque type for a LayoutEngine.
+ *
+ * @internal
+ */
+typedef void le_engine;
+
+/**
+ * The opaque type for a font instance.
+ *
+ * @internal
+ */
+typedef void le_font;
+
+/**
+ * This function returns an le_engine capable of laying out text
+ * in the given font, script and langauge. Note that the LayoutEngine
+ * returned may be a subclass of LayoutEngine.
+ *
+ * @param font - the font of the text
+ * @param scriptCode - the script of the text
+ * @param languageCode - the language of the text
+ * @param typo_flags - flags that control layout features like kerning and ligatures.
+ * @param success - output parameter set to an error code if the operation fails
+ *
+ * @return an le_engine which can layout text in the given font.
+ *
+ * @internal
+ */
+U_DRAFT le_engine * U_EXPORT2
+le_create(const le_font *font,
+ le_int32 scriptCode,
+ le_int32 languageCode,
+ le_int32 typo_flags,
+ LEErrorCode *success);
+
+/**
+ * This function closes the given LayoutEngine. After
+ * it returns, the le_engine is no longer valid.
+ *
+ * @param engine - the LayoutEngine to close.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_close(le_engine *engine);
+
+/**
+ * This routine will compute the glyph, character index and position arrays.
+ *
+ * @param engine - the LayoutEngine
+ * @param chars - the input character context
+ * @param offset - the offset of the first character to process
+ * @param count - the number of characters to process
+ * @param max - the number of characters in the input context
+ * @param rightToLeft - TRUE if the characers are in a right to left directional run
+ * @param x - the initial X position
+ * @param y - the initial Y position
+ * @param success - output parameter set to an error code if the operation fails
+ *
+ * @return the number of glyphs in the glyph array
+ *
+ * Note: The glyph, character index and position array can be accessed
+ * using the getter routines below.
+ *
+ * Note: If you call this function more than once, you must call the reset()
+ * function first to free the glyph, character index and position arrays
+ * allocated by the previous call.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+le_layoutChars(le_engine *engine,
+ const LEUnicode chars[],
+ le_int32 offset,
+ le_int32 count,
+ le_int32 max,
+ le_bool rightToLeft,
+ float x,
+ float y,
+ LEErrorCode *success);
+
+/**
+ * This function returns the number of glyphs in the glyph array. Note
+ * that the number of glyphs will be greater than or equal to the number
+ * of characters used to create the LayoutEngine.
+ *
+ * @param engine - the LayoutEngine
+ * @param success - output parameter set to an error code if the operation fails.
+ *
+ * @return the number of glyphs in the glyph array
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+le_getGlyphCount(le_engine *engine,
+ LEErrorCode *success);
+
+/**
+ * This function 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 engine - the LayoutEngine
+ * @param glyphs - the destiniation glyph array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_getGlyphs(le_engine *engine,
+ LEGlyphID glyphs[],
+ LEErrorCode *success);
+
+/**
+ * This function 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 engine - the LayoutEngine
+ * @param charIndices - the destiniation character index array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_getCharIndices(le_engine *engine,
+ le_int32 charIndices[],
+ LEErrorCode *success);
+
+/**
+ * This function 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 engine - the LayoutEngine
+ * @param charIndices - the destiniation character index array
+ * @param indexBase - an offset that will be added to each index.
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_getCharIndicesWithBase(le_engine *engine,
+ le_int32 charIndices[],
+ le_int32 indexBase,
+ LEErrorCode *success);
+
+/**
+ * This function 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 engine - the LayoutEngine
+ * @param positions - the destiniation position array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_getGlyphPositions(le_engine *engine,
+ float positions[],
+ LEErrorCode *success);
+
+/**
+ * This function returns the X and Y position of the glyph at
+ * the given index.
+ *
+ * Input parameters:
+ * @param engine - the LayoutEngine
+ * @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
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_getGlyphPosition(le_engine *engine,
+ le_int32 glyphIndex,
+ float *x,
+ float *y,
+ LEErrorCode *success);
+
+/**
+ * This function frees the glyph, character index and position arrays
+ * so that the LayoutEngine can be reused to layout a different
+ * characer array. (This function is also called by le_close)
+ *
+ * @param engine - the LayoutEngine
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+le_reset(le_engine *engine,
+ LEErrorCode *success);
+
+#endif
diff --git a/icu4c/source/layoutex/Makefile.in b/icu4c/source/layoutex/Makefile.in
index a1a1c022de3..7eb4e949c16 100644
--- a/icu4c/source/layoutex/Makefile.in
+++ b/icu4c/source/layoutex/Makefile.in
@@ -1,6 +1,6 @@
#******************************************************************************
#
-# Copyright (C) 1999-2005, International Business Machines
+# Copyright (C) 1999-2007, International Business Machines
# Corporation and others. All Rights Reserved.
#
#******************************************************************************
@@ -62,7 +62,9 @@ LIBS = $(LIBICUUC) $(LIBICULE) $(DEFAULT_LIBS)
OBJECTS = ParagraphLayout.o \
RunArrays.o \
-LXUtilities.o
+LXUtilities.o \
+playout.o \
+plruns.o
## Header files to install
HEADERS= $(srcdir)/layout/ParagraphLayout.h $(srcdir)/layout/RunArrays.h
diff --git a/icu4c/source/layoutex/layout/RunArrays.h b/icu4c/source/layoutex/layout/RunArrays.h
index 27f928b4c9e..08a76e38791 100644
--- a/icu4c/source/layoutex/layout/RunArrays.h
+++ b/icu4c/source/layoutex/layout/RunArrays.h
@@ -1,6 +1,6 @@
/*
**********************************************************************
- * Copyright (C) 2003-2005, International Business Machines
+ * Copyright (C) 2003-2007, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
@@ -502,6 +502,8 @@ protected:
virtual void init(le_int32 capacity);
virtual void grow(le_int32 capacity);
+ const Locale **fLocales;
+
private:
inline LocaleRuns();
@@ -513,8 +515,6 @@ private:
* for ICU "poor man's RTTI".
*/
static const char fgClassID;
-
- const Locale **fLocales;
};
inline LocaleRuns::LocaleRuns()
diff --git a/icu4c/source/layoutex/layout/playout.h b/icu4c/source/layoutex/layout/playout.h
new file mode 100644
index 00000000000..f6321314f1a
--- /dev/null
+++ b/icu4c/source/layoutex/layout/playout.h
@@ -0,0 +1,458 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __PLAYOUT_H
+#define __PLAYOUT_H
+
+#include "unicode/ubidi.h"
+#include "layout/LETypes.h"
+#include "plruns.h"
+
+/**
+ * \file
+ * \brief C API for paragraph layout.
+ * \internal
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * The opaque type for a paragraph layout.
+ *
+ * @internal
+ */
+typedef void pl_paragraph;
+
+/**
+ * The opaque type for a line in a paragraph layout.
+ *
+ * @internal
+ */
+typedef void pl_line;
+
+/**
+ * The opaque type for a visual run in a line.
+ *
+ * @internal
+ */
+typedef void pl_visualRun;
+
+/**
+ * Construct a ParagraphLayout
object for a styled paragraph. The paragraph is specified
+ * as runs of text all in the same font. An LEFontInstance
object and a limit offset
+ * are specified for each font run. The limit offset is the offset of the character immediately
+ * after the font run.
+ *
+ * Clients can optionally specify directional runs and / or script runs. If these aren't specified
+ * they will be computed.
+ *
+ * If any errors are encountered during construction, status
will be set, and the object
+ * will be set to be empty.
+ *
+ * @param chars is an array of the characters in the paragraph
+ *
+ * @param count is the number of characters in the paragraph.
+ *
+ * @param fontRuns a pointer to a pl_fontRuns
object representing the font runs.
+ *
+ * @param levelRuns is a pointer to a pl_valueRuns
object representing the directional levels.
+ * If this pointer in NULL
the levels will be determined by running the Unicde
+ * Bidi algorithm.
+ *
+ * @param scriptRuns is a pointer to a pl_valueRuns
object representing script runs.
+ * If this pointer in NULL
the script runs will be determined using the
+ * Unicode code points.
+ *
+ * @param localeRuns is a pointer to a pl_localeRuns
object representing locale runs.
+ * The Locale
objects are used to determind the language of the text. If this
+ * pointer is NULL
the default locale will be used for all of the text.
+ *
+ * @param paragraphLevel is the directionality of the paragraph, as in the UBiDi object.
+ *
+ * @param vertical is TRUE
if the paragraph should be set vertically.
+ *
+ * @param status will be set to any error code encountered during construction.
+ *
+ * @return a pointer to the newly created pl_paragraph
object. The object
+ * will remain valid until pl_close
is called.
+ *
+ * @see ubidi.h
+ * @see longine.h
+ * @see plruns.h
+ *
+ * @internal
+ */
+U_DRAFT pl_paragraph * U_EXPORT2
+pl_create(const LEUnicode chars[],
+ le_int32 count,
+ const pl_fontRuns *fontRuns,
+ const pl_valueRuns *levelRuns,
+ const pl_valueRuns *scriptRuns,
+ const pl_localeRuns *localeRuns,
+ UBiDiLevel paragraphLevel,
+ le_bool vertical,
+ LEErrorCode *status);
+
+/**
+ * Close the given paragraph layout object.
+ *
+ * @param paragraph the pl_paragraph
object to be
+ * closed. Once this routine returns the object
+ * can no longer be referenced
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_close(pl_paragraph *paragraph);
+
+/**
+ * Examine the given text and determine if it contains characters in any
+ * script which requires complex processing to be rendered correctly.
+ *
+ * @param chars is an array of the characters in the paragraph
+ *
+ * @param count is the number of characters in the paragraph.
+ *
+ * @return TRUE
if any of the text requires complex processing.
+ *
+ * @internal
+ */
+
+U_DRAFT le_bool U_EXPORT2
+pl_isComplex(const LEUnicode chars[],
+ le_int32 count);
+
+/**
+ * Return the resolved paragraph level. This is useful for those cases
+ * where the bidi analysis has determined the level based on the first
+ * strong character in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @return the resolved paragraph level.
+ *
+ * @internal
+ */
+U_DRAFT UBiDiLevel U_EXPORT2
+pl_getParagraphLevel(pl_paragraph *paragraph);
+
+/**
+ * Return the directionality of the text in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @return UBIDI_LTR
if the text is all left to right,
+ * UBIDI_RTL
if the text is all right to left,
+ * or UBIDI_MIXED
if the text has mixed direction.
+ *
+ * @internal
+ */
+U_DRAFT UBiDiDirection U_EXPORT2
+pl_getTextDirection(pl_paragraph *paragraph);
+
+/**
+ * Get the max ascent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * Return the max ascent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @return the ascent value.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getAscent(const pl_paragraph *paragraph);
+
+/**
+ * Return the max descent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @return the decent value.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getDescent(const pl_paragraph *paragraph);
+
+/**
+ * Return the max leading value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @return the leading value.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLeading(const pl_paragraph *paragraph);
+
+/**
+ * Reset line breaking to start from the beginning of the paragraph.
+ *
+ * @param paragraph the pl_paragraph
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_reflow(pl_paragraph *paragraph);
+
+/**
+ * Return a pl_line
object which represents next line
+ * in the paragraph. The width of the line is specified each time so that it can
+ * be varied to support arbitrary paragraph shapes.
+ *
+ * @param paragraph the pl_paragraph
+ * @param width is the width of the line. If width
is less than or equal
+ * to zero, a ParagraphLayout::Line
object representing the
+ * rest of the paragraph will be returned.
+ *
+ * @return a ParagraphLayout::Line
object which represents the line. The caller
+ * is responsible for deleting the object. Returns NULL
if there are no
+ * more lines in the paragraph.
+ *
+ * @see pl_line
+ *
+ * @internal
+ */
+U_DRAFT pl_line * U_EXPORT2
+pl_nextLine(pl_paragraph *paragraph, float width);
+
+/**
+ * Close the given line object. Line objects are created
+ * by pl_nextLine
but it is the client's responsibility
+ * to close them by calling this routine.
+ *
+ * @param line the pl_line
object to close.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_closeLine(pl_line *line);
+
+/**
+ * Count the number of visual runs in the line.
+ *
+ * @param line the pl_line
object.
+ *
+ * @return the number of visual runs.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_countLineRuns(const pl_line *line);
+
+/**
+ * Get the ascent of the line. This is the maximum ascent
+ * of all the fonts on the line.
+ *
+ * @param line the pl_line
object.
+ *
+ * @return the ascent of the line.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLineAscent(const pl_line *line);
+
+/**
+ * Get the descent of the line. This is the maximum descent
+ * of all the fonts on the line.
+ *
+ * @param line the pl_line
object.
+ *
+ * @return the descent of the line.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLineDescent(const pl_line *line);
+
+/**
+ * Get the leading of the line. This is the maximum leading
+ * of all the fonts on the line.
+ *
+ * @param line the pl_line
object.
+ *
+ * @return the leading of the line.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLineLeading(const pl_line *line);
+
+/**
+ * Get the width of the line. This is a convenience method
+ * which returns the last X position of the last visual run
+ * in the line.
+ *
+ * @param line the pl_line
object.
+ *
+ * @return the width of the line.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLineWidth(const pl_line *line);
+
+/**
+ * Get a ParagraphLayout::VisualRun
object for a given
+ * visual run in the line.
+ *
+ * @param line the pl_line
object.
+ * @param runIndex is the index of the run, in visual order.
+ *
+ * @return the pl_visualRun
object representing the
+ * visual run. This object is owned by the pl_line
object which
+ * created it, and will remain valid for as long as the pl_line
+ * object is valid.
+ *
+ * @see pl_visualRun
+ *
+ * @internal
+ */
+U_DRAFT const pl_visualRun * U_EXPORT2
+pl_getLineVisualRun(const pl_line *line, le_int32 runIndex);
+
+/**
+ * Get the le_font
object which
+ * represents the font of the visual run. This will always
+ * be a non-composite font.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the le_font
object which represents the
+ * font of the visual run.
+ *
+ * @see le_font
+ *
+ * @internal
+ */
+U_DRAFT const le_font * U_EXPORT2
+pl_getVisualRunFont(const pl_visualRun *run);
+
+/**
+ * Get the direction of the visual run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the direction of the run. This will be UBIDI_LTR
if the
+ * run is left-to-right and UBIDI_RTL
if the line is right-to-left.
+ *
+ * @internal
+ */
+U_DRAFT UBiDiDirection U_EXPORT2
+pl_getVisualRunDirection(const pl_visualRun *run);
+
+/**
+ * Get the number of glyphs in the visual run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the number of glyphs.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getVisualRunGlyphCount(const pl_visualRun *run);
+
+/**
+ * Get the glyphs in the visual run. Glyphs with the values 0xFFFE
and
+ * 0xFFFF
should be ignored.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the address of the array of glyphs for this visual run. The storage
+ * is owned by the pl_visualRun
object and must not be deleted.
+ * It will remain valid as long as the pl_visualRun
object is valid.
+ *
+ * @internal
+ */
+U_DRAFT const LEGlyphID * U_EXPORT2
+pl_getVisualRunGlyphs(const pl_visualRun *run);
+
+/**
+ * Get the (x, y) positions of the glyphs in the visual run. To simplify storage
+ * management, the x and y positions are stored in a single array with the x positions
+ * at even offsets in the array and the corresponding y position in the following odd offset.
+ * There is an extra (x, y) pair at the end of the array which represents the advance of
+ * the final glyph in the run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the address of the array of glyph positions for this visual run. The storage
+ * is owned by the pl_visualRun
object and must not be deleted.
+ * It will remain valid as long as the pl_visualRun
object is valid.
+ *
+ * @internal
+ */
+U_DRAFT const float * U_EXPORT2
+pl_getVisualRunPositions(const pl_visualRun *run);
+
+/**
+ * Get the glyph-to-character map for this visual run. This maps the indices into
+ * the glyph array to indices into the character array used to create the paragraph.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the address of the character-to-glyph map for this visual run. The storage
+ * is owned by the pl_visualRun
object and must not be deleted.
+ * It will remain valid as long as the pl_visualRun
object is valid.
+ *
+ * @internal
+ */
+U_DRAFT const le_int32 * U_EXPORT2
+pl_getVisualRunGlyphToCharMap(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the ascent value for the font
+ * associated with this run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the ascent value of this run's font.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getVisualRunAscent(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the descent value for the font
+ * associated with this run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the descent value of this run's font.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getVisualRunDescent(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the leading value for the font
+ * associated with this run.
+ *
+ * @param run the pl_visualRun
object.
+ *
+ * @return the leading value of this run's font.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getVisualRunLeading(const pl_visualRun *run);
+
+#endif
diff --git a/icu4c/source/layoutex/layout/plruns.h b/icu4c/source/layoutex/layout/plruns.h
new file mode 100644
index 00000000000..deb1dac2889
--- /dev/null
+++ b/icu4c/source/layoutex/layout/plruns.h
@@ -0,0 +1,429 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __PLRUNS_H
+#define __PLRUNS_H
+
+#include "unicode/utypes.h"
+#include "unicode/ubidi.h"
+#include "layout/LETypes.h"
+
+#include "layout/loengine.h"
+
+typedef void pl_fontRuns;
+typedef void pl_valueRuns;
+typedef void pl_localeRuns;
+
+/**
+ * \file
+ * \brief C API for run arrays.
+ * \internal
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * Construct a pl_fontRuns
object from pre-existing arrays of fonts
+ * and limit indices.
+ *
+ * @param fonts is the address of an array of pointers to le_font
objects. This
+ * array, and the le_font
objects to which it points must remain
+ * valid until the pl_fontRuns
object is closed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ * the pl_fontRuns
object is closed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_DRAFT pl_fontRuns * U_EXPORT2
+pl_openFontRuns(const le_font **fonts,
+ const le_int32 *limits,
+ le_int32 count);
+
+/**
+ * Construct an empty pl_fontRuns
object. Clients can add font and limit
+ * indices arrays using the pl_addFontRun
routine.
+ *
+ * @param initialCapacity is the initial size of the font and limit indices arrays. If
+ * this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addFontRun
+ *
+ * @internal
+ */
+U_DRAFT pl_fontRuns * U_EXPORT2
+pl_openEmptyFontRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given pl_fontRuns
object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_closeFontRuns(pl_fontRuns *fontRuns);
+
+/**
+ * Get the number of font runs.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ *
+ * @return the number of entries in the limit indices array.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getFontRunCount(const pl_fontRuns *fontRuns);
+
+/**
+ * Reset the number of font runs to zero.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_resetFontRuns(pl_fontRuns *fontRuns);
+
+/**
+ * Get the limit index for the last font run. This is the
+ * number of characters in the text.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getFontRunLastLimit(const pl_fontRuns *fontRuns);
+
+/**
+ * Get the limit index for a particular font run.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ * @param run is the run. This is an index into the limit index array.
+ *
+ * @return the limit index for the run, or -1 if run
is out of bounds.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getFontRunLimit(const pl_fontRuns *fontRuns,
+ le_int32 run);
+
+/**
+ * Get the le_font
object assoicated with the given run
+ * of text. Use pl_getFontRunLimit(run)
to get the corresponding
+ * limit index.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ * @param run is the index into the font and limit indices arrays.
+ *
+ * @return the le_font
associated with the given text run.
+ *
+ * @internal
+ */
+U_DRAFT const le_font * U_EXPORT2
+pl_getFontRunFont(const pl_fontRuns *fontRuns,
+ le_int32 run);
+
+
+/**
+ * Add a new font run to the given pl_fontRuns
object.
+ *
+ * If the pl_fontRuns
object was not created by calling
+ * pl_openEmptyFontRuns
, this method will return a run index of -1.
+ *
+ * @param fontRuns is the pl_fontRuns
object.
+ *
+ * @param font is the address of the le_font
to add. This object must
+ * remain valid until the pl_fontRuns
object is closed.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if
+ * the run cannot be added.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_addFontRun(pl_fontRuns *fontRuns,
+ const le_font *font,
+ le_int32 limit);
+
+/**
+ * Construct a pl_valueRuns
object from pre-existing arrays of values
+ * and limit indices.
+ *
+ * @param values is the address of an array of values. This array must remain valid until
+ the pl_valueRuns
object is closed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ * the pl_valueRuns
object is closed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_DRAFT pl_valueRuns * U_EXPORT2
+pl_openValueRuns(const le_int32 *values,
+ const le_int32 *limits,
+ le_int32 count);
+
+/**
+ * Construct an empty pl_valueRuns
object. Clients can add values and limits
+ * using the pl_addValueRun
routine.
+ *
+ * @param initialCapacity is the initial size of the value and limit indices arrays. If
+ * this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addValueRun
+ *
+ * @internal
+ */
+U_DRAFT pl_valueRuns * U_EXPORT2
+pl_openEmptyValueRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given pl_valueRuns
object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_closeValueRuns(pl_valueRuns *valueRuns);
+
+/**
+ * Get the number of value runs.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ *
+ * @return the number of value runs.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getValueRunCount(const pl_valueRuns *valueRuns);
+
+/**
+ * Reset the number of value runs to zero.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_resetValueRuns(pl_valueRuns *valueRuns);
+
+/**
+ * Get the limit index for the last value run. This is the
+ * number of characters in the text.
+ *
+ * @param valuetRuns is the pl_valueRuns
object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getValueRunLastLimit(const pl_valueRuns *valueRuns);
+
+/**
+ * Get the limit index for a particular value run.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ * @param run is the run index.
+ *
+ * @return the limit index for the run, or -1 if run
is out of bounds.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getValueRunLimit(const pl_valueRuns *valueRuns,
+ le_int32 run);
+
+/**
+ * Get the value assoicated with the given run * of text. Use
+ * pl_getValueRunLimit(run)
to get the corresponding
+ * limit index.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ * @param run is the run index.
+ *
+ * @return the value associated with the given text run.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getValueRunValue(const pl_valueRuns *valueRuns,
+ le_int32 run);
+
+
+/**
+ * Add a new font run to the given pl_valueRuns
object.
+ *
+ * If the pl_valueRuns
object was not created by calling
+ * pl_openEmptyFontRuns
, this method will return a run index of -1.
+ *
+ * @param valueRuns is the pl_valueRuns
object.
+ *
+ * @param value is the value to add.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if
+ * the run cannot be added.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_addValueRun(pl_valueRuns *valueRuns,
+ le_int32 value,
+ le_int32 limit);
+
+/**
+ * Construct a pl_localeRuns
object from pre-existing arrays of fonts
+ * and limit indices.
+ *
+ * @param locales is the address of an array of pointers to locale name strings. This
+ * array must remain valid until the pl_localeRuns
object is destroyed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ * the pl_valueRuns
object is destroyed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_DRAFT pl_localeRuns * U_EXPORT2
+pl_openLocaleRuns(const char **locales,
+ const le_int32 *limits,
+ le_int32 count);
+
+/**
+ * Construct an empty pl_localeRuns
object. Clients can add font and limit
+ * indices arrays using the pl_addFontRun
routine.
+ *
+ * @param initialCapacity is the initial size of the font and limit indices arrays. If
+ * this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addLocaleRun
+ *
+ * @internal
+ */
+U_DRAFT pl_localeRuns * U_EXPORT2
+pl_openEmptyLocaleRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given pl_localeRuns
object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_closeLocaleRuns(pl_localeRuns *localeRuns);
+
+/**
+ * Get the number of font runs.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ *
+ * @return the number of entries in the limit indices array.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLocaleRunCount(const pl_localeRuns *localeRuns);
+
+/**
+ * Reset the number of locale runs to zero.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ *
+ * @internal
+ */
+U_DRAFT void U_EXPORT2
+pl_resetLocaleRuns(pl_localeRuns *localeRuns);
+
+/**
+ * Get the limit index for the last font run. This is the
+ * number of characters in the text.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLocaleRunLastLimit(const pl_localeRuns *localeRuns);
+
+/**
+ * Get the limit index for a particular font run.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ * @param run is the run. This is an index into the limit index array.
+ *
+ * @return the limit index for the run, or -1 if run
is out of bounds.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_getLocaleRunLimit(const pl_localeRuns *localeRuns,
+ le_int32 run);
+
+/**
+ * Get the le_font
object assoicated with the given run
+ * of text. Use pl_getLocaleRunLimit(run)
to get the corresponding
+ * limit index.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ * @param run is the index into the font and limit indices arrays.
+ *
+ * @return the le_font
associated with the given text run.
+ *
+ * @internal
+ */
+U_DRAFT const char * U_EXPORT2
+pl_getLocaleRunLocale(const pl_localeRuns *localeRuns,
+ le_int32 run);
+
+
+/**
+ * Add a new run to the given pl_localeRuns
object.
+ *
+ * If the pl_localeRuns
object was not created by calling
+ * pl_openEmptyLocaleRuns
, this method will return a run index of -1.
+ *
+ * @param localeRuns is the pl_localeRuns
object.
+ *
+ * @param locale is the name of the locale to add. This name must
+ * remain valid until the pl_localeRuns
object is closed.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if
+ * the run cannot be added.
+ *
+ * @internal
+ */
+U_DRAFT le_int32 U_EXPORT2
+pl_addLocaleRun(pl_localeRuns *localeRuns,
+ const char *locale,
+ le_int32 limit);
+
+#endif
diff --git a/icu4c/source/layoutex/layoutex.vcproj b/icu4c/source/layoutex/layoutex.vcproj
index 9f9ea3966d2..9cadf551a2d 100644
--- a/icu4c/source/layoutex/layoutex.vcproj
+++ b/icu4c/source/layoutex/layoutex.vcproj
@@ -4,6 +4,7 @@
Version="8.00"
Name="layoutex"
ProjectGUID="{37FC2C7F-1904-4811-8955-2F478830EAD1}"
+ RootNamespace="layoutex"
>
+
+
+
+
@@ -254,6 +263,32 @@
/>
+
+
+
+
+
+
+
+
+
+
diff --git a/icu4c/source/layoutex/playout.cpp b/icu4c/source/layoutex/playout.cpp
new file mode 100644
index 00000000000..bcfd475c585
--- /dev/null
+++ b/icu4c/source/layoutex/playout.cpp
@@ -0,0 +1,323 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "layout/LETypes.h"
+#include "layout/loengine.h"
+#include "layout/plruns.h"
+#include "layout/playout.h"
+
+#include "unicode/locid.h"
+
+#include "layout/LayoutEngine.h"
+#include "layout/ParagraphLayout.h"
+
+U_NAMESPACE_USE
+
+U_CAPI pl_paragraph * U_EXPORT2
+pl_create(const LEUnicode chars[],
+ le_int32 count,
+ const pl_fontRuns *fontRuns,
+ const pl_valueRuns *levelRuns,
+ const pl_valueRuns *scriptRuns,
+ const pl_localeRuns *localeRuns,
+ UBiDiLevel paragraphLevel,
+ le_bool vertical,
+ LEErrorCode *status)
+{
+ ParagraphLayout *pl = new ParagraphLayout(chars, count, (const FontRuns *) fontRuns,
+ (const ValueRuns *) levelRuns, (const ValueRuns *) scriptRuns, (const LocaleRuns *) localeRuns,
+ paragraphLevel, vertical, *status);
+
+ return (pl_paragraph *) pl;
+}
+
+U_CAPI void U_EXPORT2
+pl_close(pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ delete pl;
+}
+
+U_CAPI le_bool U_EXPORT2
+pl_isComplex(const LEUnicode chars[],
+ le_int32 count)
+{
+ return ParagraphLayout::isComplex(chars, count);
+}
+
+U_CAPI UBiDiLevel U_EXPORT2
+pl_getParagraphLevel(pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return 0;
+ }
+
+ return pl->getParagraphLevel();
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+pl_getTextDirection(pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return UBIDI_LTR;
+ }
+
+ return pl->getTextDirection();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getAscent(const pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return 0;
+ }
+
+ return pl->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getDescent(const pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return 0;
+ }
+
+ return pl->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLeading(const pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return 0;
+ }
+
+ return pl->getLeading();
+}
+
+U_CAPI void U_EXPORT2
+pl_reflow(pl_paragraph *paragraph)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return;
+ }
+
+ return pl->reflow();
+}
+
+U_CAPI pl_line * U_EXPORT2
+pl_nextLine(pl_paragraph *paragraph, float width)
+{
+ ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+ if (pl == NULL) {
+ return NULL;
+ }
+
+ return (pl_line *) pl->nextLine(width);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeLine(pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ delete ll;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_countLineRuns(const pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return ll->countRuns();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineAscent(const pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return ll->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineDescent(const pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return ll->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineLeading(const pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return ll->getLeading();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineWidth(const pl_line *line)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return ll->getWidth();
+}
+
+U_CAPI const pl_visualRun * U_EXPORT2
+pl_getLineVisualRun(const pl_line *line, le_int32 runIndex)
+{
+ ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+ if (ll == NULL) {
+ return 0;
+ }
+
+ return (pl_visualRun *) ll->getVisualRun(runIndex);
+}
+
+U_CAPI const le_font * U_EXPORT2
+pl_getVisualRunFont(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return NULL;
+ }
+
+ return (const le_font *) vr->getFont();
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+pl_getVisualRunDirection(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return UBIDI_LTR;
+ }
+
+ return vr->getDirection();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunGlyphCount(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->getGlyphCount();
+}
+
+U_CAPI const LEGlyphID * U_EXPORT2
+pl_getVisualRunGlyphs(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return NULL;
+ }
+
+ return vr->getGlyphs();
+}
+
+U_CAPI const float * U_EXPORT2
+pl_getVisualRunPositions(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return NULL;
+ }
+
+ return vr->getPositions();
+}
+
+U_CAPI const le_int32 * U_EXPORT2
+pl_getVisualRunGlyphToCharMap(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return NULL;
+ }
+
+ return vr->getGlyphToCharMap();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunAscent(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return 0;
+ }
+
+ return vr->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunDescent(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return 0;
+ }
+
+ return vr->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunLeading(const pl_visualRun *run)
+{
+ ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+ if (vr == NULL) {
+ return 0;
+ }
+
+ return vr->getLeading();
+}
+
diff --git a/icu4c/source/layoutex/plruns.cpp b/icu4c/source/layoutex/plruns.cpp
new file mode 100644
index 00000000000..f73112b08ac
--- /dev/null
+++ b/icu4c/source/layoutex/plruns.cpp
@@ -0,0 +1,508 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "layout/LETypes.h"
+#include "layout/loengine.h"
+#include "layout/plruns.h"
+
+#include "unicode/locid.h"
+
+#include "layout/LayoutEngine.h"
+#include "layout/RunArrays.h"
+
+U_NAMESPACE_USE
+
+U_CAPI pl_fontRuns * U_EXPORT2
+pl_openFontRuns(const le_font **fonts,
+ const le_int32 *limits,
+ le_int32 count)
+{
+ return (pl_fontRuns *) new FontRuns((const LEFontInstance **) fonts, limits, count);
+}
+
+U_CAPI pl_fontRuns * U_EXPORT2
+pl_openEmptyFontRuns(le_int32 initialCapacity)
+{
+ return (pl_fontRuns *) new FontRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeFontRuns(pl_fontRuns *fontRuns)
+{
+ FontRuns *fr = (FontRuns *) fontRuns;
+
+ delete fr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunCount(const pl_fontRuns *fontRuns)
+{
+ const FontRuns *fr = (const FontRuns *) fontRuns;
+
+ if (fr == NULL) {
+ return -1;
+ }
+
+ return fr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetFontRuns(pl_fontRuns *fontRuns)
+{
+ FontRuns *fr = (FontRuns *) fontRuns;
+
+ if (fr != NULL) {
+ fr->reset();
+ }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunLastLimit(const pl_fontRuns *fontRuns)
+{
+ const FontRuns *fr = (const FontRuns *) fontRuns;
+
+ if (fr == NULL) {
+ return -1;
+ }
+
+ return fr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunLimit(const pl_fontRuns *fontRuns,
+ le_int32 run)
+{
+ const FontRuns *fr = (const FontRuns *) fontRuns;
+
+ if (fr == NULL) {
+ return -1;
+ }
+
+ return fr->getLimit(run);
+}
+
+U_CAPI const le_font * U_EXPORT2
+pl_getFontRunFont(const pl_fontRuns *fontRuns,
+ le_int32 run)
+{
+ const FontRuns *fr = (const FontRuns *) fontRuns;
+
+ if (fr == NULL) {
+ return NULL;
+ }
+
+ return (const le_font *) fr->getFont(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addFontRun(pl_fontRuns *fontRuns,
+ const le_font *font,
+ le_int32 limit)
+{
+ FontRuns *fr = (FontRuns *) fontRuns;
+
+ if (fr == NULL) {
+ return -1;
+ }
+
+ return fr->add((const LEFontInstance *) font, limit);
+}
+
+U_CAPI pl_valueRuns * U_EXPORT2
+pl_openValueRuns(const le_int32 *values,
+ const le_int32 *limits,
+ le_int32 count)
+{
+ return (pl_valueRuns *) new ValueRuns(values, limits, count);
+}
+
+U_CAPI pl_valueRuns * U_EXPORT2
+pl_openEmptyValueRuns(le_int32 initialCapacity)
+{
+ return (pl_valueRuns *) new ValueRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeValueRuns(pl_valueRuns *valueRuns)
+{
+ ValueRuns *vr = (ValueRuns *) valueRuns;
+
+ delete vr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunCount(const pl_valueRuns *valueRuns)
+{
+ const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetValueRuns(pl_valueRuns *valueRuns)
+{
+ ValueRuns *vr = (ValueRuns *) valueRuns;
+
+ if (vr != NULL) {
+ vr->reset();
+ }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunLastLimit(const pl_valueRuns *valueRuns)
+{
+ const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunLimit(const pl_valueRuns *valueRuns,
+ le_int32 run)
+{
+ const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->getLimit(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunValue(const pl_valueRuns *valueRuns,
+ le_int32 run)
+{
+ const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->getValue(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addValueRun(pl_valueRuns *valueRuns,
+ le_int32 value,
+ le_int32 limit)
+{
+ ValueRuns *vr = (ValueRuns *) valueRuns;
+
+ if (vr == NULL) {
+ return -1;
+ }
+
+ return vr->add(value, limit);
+}
+
+class ULocRuns : public LocaleRuns
+{
+public:
+ /**
+ * Construct a LocaleRuns
object from pre-existing arrays of locales
+ * and limit indices.
+ *
+ * @param locales is the address of an array of locale name strings. This array,
+ * and the Locale
objects to which it points, must remain valid until
+ * the LocaleRuns
object is destroyed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until the
+ * LocaleRuns
object is destroyed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @draft ICU 3.8
+ */
+ ULocRuns(const char **locales, const le_int32 *limits, le_int32 count);
+
+ /**
+ * Construct an empty LoIDRuns
object. Clients can add locale and limit
+ * indices arrays using the add
method.
+ *
+ * @param initialCapacity is the initial size of the locale and limit indices arrays. If
+ * this value is zero, no arrays will be allocated.
+ *
+ * @see add
+ *
+ * @draft ICU 3.8
+ */
+ ULocRuns(le_int32 initialCapacity);
+
+ /**
+ * The destructor; virtual so that subclass destructors are invoked as well.
+ *
+ * @draft ICU 3.8
+ */
+ virtual ~ULocRuns();
+
+ /**
+ * Get the name of the locale assoicated with the given run
+ * of text. Use RunArray::getLimit(run)
to get the corresponding
+ * limit index.
+ *
+ * @param run is the index into the font and limit indices arrays.
+ *
+ * @return the locale name associated with the given text run.
+ *
+ * @see RunArray::getLimit
+ *
+ * @draft ICU 3.8
+ */
+ const char *getLocaleName(le_int32 run) const;
+
+ /**
+ * Add a Locale
and limit index pair to the data arrays and return
+ * the run index where the data was stored. This method calls
+ * RunArray::add(limit)
which will create or grow the arrays as needed.
+ *
+ * If the ULocRuns
object was created with a client-supplied
+ * locale and limit indices arrays, this method will return a run index of -1.
+ *
+ * Subclasses should not override this method. Rather they should provide a new add
+ * method which takes a locale name and a limit index along with whatever other data they implement.
+ * The new add
method should first call this method to grow the font and limit indices
+ * arrays, and use the returned run index to store data their own arrays.
+ *
+ * @param locale is the name of the locale to add. This object must remain valid
+ * until the ULocRuns
object is destroyed.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the locale and limit index were stored, or -1 if the data cannot be stored.
+ *
+ * @draft ICU 3.8
+ */
+ le_int32 add(const char *locale, le_int32 limit);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 3.8
+ */
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 3.8
+ */
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+ virtual void init(le_int32 capacity);
+ virtual void grow(le_int32 capacity);
+
+private:
+
+ inline ULocRuns();
+ inline ULocRuns(const ULocRuns &other);
+ inline ULocRuns &operator=(const ULocRuns & /*other*/) { return *this; };
+
+ /**
+ * The address of this static class variable serves as this class's ID
+ * for ICU "poor man's RTTI".
+ */
+ static const char fgClassID;
+
+ const char **fLocaleNames;
+ Locale **fLocalesCopy;
+};
+
+const char ULocRuns::fgClassID = 0;
+
+inline ULocRuns::ULocRuns()
+ : LocaleRuns(0), fLocaleNames(NULL)
+{
+ // nothing else to do...
+}
+
+inline ULocRuns::ULocRuns(const ULocRuns & /*other*/)
+ : LocaleRuns(0), fLocaleNames(NULL)
+{
+ // nothing else to do...
+}
+
+const Locale **getLocales(const char **localeNames, le_int32 count)
+{
+ Locale **locales = LE_NEW_ARRAY(Locale *, count);
+
+ for (int i = 0; i < count; i += 1) {
+ locales[i] = new Locale(Locale::createFromName(localeNames[i]));
+ }
+
+ return (const Locale **) locales;
+}
+
+ULocRuns::ULocRuns(const char **locales, const le_int32 *limits, le_int32 count)
+ : LocaleRuns(getLocales(locales, count), limits, count), fLocaleNames(locales)
+{
+ // nothing else to do...
+}
+
+ULocRuns::ULocRuns(le_int32 initialCapacity)
+ : LocaleRuns(initialCapacity), fLocaleNames(NULL)
+{
+ if(initialCapacity > 0) {
+ fLocaleNames = LE_NEW_ARRAY(const char *, initialCapacity);
+ }
+}
+
+ULocRuns::~ULocRuns()
+{
+ le_int32 count = getCount();
+
+ for(int i = 0; i < count; i += 1) {
+ delete fLocales[i];
+ }
+
+ if (fClientArrays) {
+ LE_DELETE_ARRAY(fLocales);
+ fLocales = NULL;
+ } else {
+ LE_DELETE_ARRAY(fLocaleNames);
+ fLocaleNames = NULL;
+ }
+}
+
+void ULocRuns::init(le_int32 capacity)
+{
+ LocaleRuns::init(capacity);
+ fLocaleNames = LE_NEW_ARRAY(const char *, capacity);
+}
+
+void ULocRuns::grow(le_int32 capacity)
+{
+ RunArray::grow(capacity);
+ fLocaleNames = (const char **) LE_GROW_ARRAY(fLocaleNames, capacity);
+}
+
+le_int32 ULocRuns::add(const char *locale, le_int32 limit)
+{
+ Locale *loc = new Locale(Locale::createFromName(locale));
+ le_int32 index = LocaleRuns::add(loc, limit);
+
+ if (index >= 0) {
+ char **localeNames = (char **) fLocaleNames;
+
+ localeNames[index] = (char *) locale;
+ }
+
+ return index;
+}
+
+const char *ULocRuns::getLocaleName(le_int32 run) const
+{
+ if (run < 0 || run >= getCount()) {
+ return NULL;
+ }
+
+ return fLocaleNames[run];
+}
+
+U_CAPI pl_localeRuns * U_EXPORT2
+pl_openLocaleRuns(const char **locales,
+ const le_int32 *limits,
+ le_int32 count)
+{
+ return (pl_localeRuns *) new ULocRuns(locales, limits, count);
+}
+
+U_CAPI pl_localeRuns * U_EXPORT2
+pl_openEmptyLocaleRuns(le_int32 initialCapacity)
+{
+ return (pl_localeRuns *) new ULocRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeLocaleRuns(pl_localeRuns *localeRuns)
+{
+ ULocRuns *lr = (ULocRuns *) localeRuns;
+
+ delete lr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunCount(const pl_localeRuns *localeRuns)
+{
+ const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+ if (lr == NULL) {
+ return -1;
+ }
+
+ return lr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetLocaleRuns(pl_localeRuns *localeRuns)
+{
+ ULocRuns *lr = (ULocRuns *) localeRuns;
+
+ if (lr != NULL) {
+ lr->reset();
+ }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunLastLimit(const pl_localeRuns *localeRuns)
+{
+ const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+ if (lr == NULL) {
+ return -1;
+ }
+
+ return lr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunLimit(const pl_localeRuns *localeRuns,
+ le_int32 run)
+{
+ const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+ if (lr == NULL) {
+ return -1;
+ }
+
+ return lr->getLimit(run);
+}
+
+U_CAPI const char * U_EXPORT2
+pl_getLocaleRunLocale(const pl_localeRuns *localeRuns,
+ le_int32 run)
+{
+ const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+ if (lr == NULL) {
+ return NULL;
+ }
+
+ return lr->getLocaleName(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addLocaleRun(pl_localeRuns *localeRuns,
+ const char *locale,
+ le_int32 limit)
+{
+ ULocRuns *lr = (ULocRuns *) localeRuns;
+
+ if (lr == NULL) {
+ return -1;
+ }
+
+ return lr->add(locale, limit);
+}
diff --git a/icu4c/source/samples/layout/GnomeFontInstance.cpp b/icu4c/source/samples/layout/GnomeFontInstance.cpp
index d30c744a9e1..5d708923c97 100644
--- a/icu4c/source/samples/layout/GnomeFontInstance.cpp
+++ b/icu4c/source/samples/layout/GnomeFontInstance.cpp
@@ -166,14 +166,12 @@ le_bool GnomeFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber,
return FALSE;
}
- FT_OutlineGlyph oglyph = (FT_OutlineGlyph) fFace->glyph;
-
- if (pointNumber >= oglyph->outline.n_points) {
+ if (pointNumber >= fFace->glyph->outline.n_points) {
return FALSE;
}
- point.fX = oglyph->outline.points[pointNumber].x >> 6;
- point.fY = oglyph->outline.points[pointNumber].y >> 6;
+ point.fX = fFace->glyph->outline.points[pointNumber].x >> 6;
+ point.fY = fFace->glyph->outline.points[pointNumber].y >> 6;
return TRUE;
}
diff --git a/icu4c/source/samples/layout/Makefile.in b/icu4c/source/samples/layout/Makefile.in
index cabaddc2546..15fae07c16a 100644
--- a/icu4c/source/samples/layout/Makefile.in
+++ b/icu4c/source/samples/layout/Makefile.in
@@ -1,5 +1,5 @@
## Makefile.in for ICU - samples/layout
-## Copyright (c) 2001-2003, International Business Machines Corporation and
+## Copyright (c) 2001-2007, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information
@@ -20,13 +20,18 @@ subdir = samples/layout
CLEANFILES = *~ $(DEPS)
## Target information
-TARGET = gnomelayout
+TARGET = gnomelayout
+CTARGET = cgnomelayout
CPPFLAGS += -DLE_USE_CMEMORY `pkg-config --cflags libgnomeui-2.0 freetype2 cairo` -I$(top_builddir)/common -I$(top_srcdir)/common -I$(top_srcdir)/i18n -I$(top_srcdir)/layoutex -I$(top_srcdir)/layout -I$(top_srcdir) -g
LIBS = $(LIBICULX) $(LIBICULE) $(LIBICUUC) $(LIBICUI18N) @LIBS@ @LIB_M@ `pkg-config --libs libgnomeui-2.0 freetype2 cairo`
-OBJECTS=cmaps.o UnicodeReader.o GnomeGUISupport.o FontMap.o GnomeFontMap.o ScriptCompositeFontInstance.o GnomeFontInstance.o FontTableCache.o paragraph.o gnomelayout.o
+COMMON=cmaps.o UnicodeReader.o GnomeGUISupport.o FontMap.o GnomeFontMap.o ScriptCompositeFontInstance.o GnomeFontInstance.o FontTableCache.o paragraph.o
+
+OBJECTS=gnomelayout.o
+
+COBJECTS=gnomeglue.o pflow.o rsurface.o ucreader.o cgnomelayout.o
DEPS = $(OBJECTS:.o=.d)
@@ -44,16 +49,20 @@ clean: clean-local
distclean : distclean-local
dist: dist-local
check: all check-local
+c-all: c-all-local
+c-check: c-all c-check-local
all-local: $(TARGET)
+c-all-local: $(CTARGET)
+
install-local:
dist-local:
clean-local:
test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
- $(RMV) $(OBJECTS) $(TARGET)
+ $(RMV) $(COMMON) $(OBJECTS) $(COBJECTS) $(TARGET)
distclean-local: clean-local
$(RMV) Makefile
@@ -61,6 +70,9 @@ distclean-local: clean-local
check-local: all-local
$(INVOKE) ./$(TARGET)
+c-check-local: c-all-local
+ $(INVOKE) ./$(CTARGET)
+
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
@@ -77,7 +89,10 @@ scrptrun.d: $(top_srcdir)/extra/scrptrun/scrptrun.cpp
scrptrun.o: $(top_srcdir)/extra/scrptrun/scrptrun.cpp
$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
-$(TARGET) : $(OBJECTS)
+$(TARGET) : $(COMMON) $(OBJECTS)
+ $(LINK.cc) -o $@ $^ $(LIBS)
+
+$(CTARGET) : $(COMMON) $(COBJECTS)
$(LINK.cc) -o $@ $^ $(LIBS)
invoke:
diff --git a/icu4c/source/samples/layout/arraymem.h b/icu4c/source/samples/layout/arraymem.h
new file mode 100644
index 00000000000..7c54d96bdd0
--- /dev/null
+++ b/icu4c/source/samples/layout/arraymem.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __ARRAYMEM_H
+#define __ARRAYMEM_H
+
+#include
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define ARRAY_COPY(dst, src, count) memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0])
+
+#define NEW_ARRAY(type,count) (type *) malloc((count) * sizeof(type))
+
+#define DELETE_ARRAY(array) free((void *) (array))
+
+#define GROW_ARRAY(array,newSize) realloc((void *) (array), (newSize) * sizeof (array)[0])
+
+#endif
diff --git a/icu4c/source/samples/layout/cgnomelayout.c b/icu4c/source/samples/layout/cgnomelayout.c
new file mode 100644
index 00000000000..f95b7a5c6bc
--- /dev/null
+++ b/icu4c/source/samples/layout/cgnomelayout.c
@@ -0,0 +1,342 @@
+
+/*
+ ****************************************************************************** *
+ *
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ ****************************************************************************** *
+ */
+
+#include
+#include
+#include FT_FREETYPE_H
+
+#include "pflow.h"
+
+#include "gnomeglue.h"
+
+#include "arraymem.h"
+
+struct Context
+{
+ long width;
+ long height;
+ pf_flow *paragraph;
+};
+
+typedef struct Context Context;
+
+static FT_Library engine;
+static gs_guiSupport *guiSupport;
+static fm_fontMap *fontMap;
+static le_font *font;
+
+static GSList *appList = NULL;
+
+GtkWidget *newSample(const gchar *fileName);
+void closeSample(GtkWidget *sample);
+
+static void showabout(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *aboutBox;
+ const gchar *documentedBy[] = {NULL};
+ const gchar *writtenBy[] = {
+ "Eric Mader",
+ NULL
+ };
+
+ aboutBox = gnome_about_new("Gnome Layout Sample",
+ "0.1",
+ "Copyright (C) 1998-2006 By International Business Machines Corporation and others. All Rights Reserved.",
+ "A simple demo of the ICU LayoutEngine.",
+ writtenBy,
+ documentedBy,
+ "",
+ NULL);
+
+ gtk_widget_show(aboutBox);
+}
+
+#if 0
+static void notimpl(GtkObject *object, gpointer data)
+{
+ gnome_ok_dialog("Not implemented...");
+}
+#endif
+
+static gchar *prettyTitle(const gchar *path)
+{
+ const gchar *name = g_basename(path);
+ gchar *title = g_strconcat("Gnome Layout Sample - ", name, NULL);
+
+ return title;
+}
+
+static void openOK(GtkObject *object, gpointer data)
+{
+ GtkFileSelection *fileselection = GTK_FILE_SELECTION(data);
+ GtkWidget *app = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(fileselection), "app"));
+ Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
+ gchar *fileName = g_strdup(gtk_file_selection_get_filename(fileselection));
+ pf_flow *newPara;
+
+ gtk_widget_destroy(GTK_WIDGET(fileselection));
+
+ newPara = pf_factory(fileName, font, guiSupport);
+
+ if (newPara != NULL) {
+ gchar *title = prettyTitle(fileName);
+ GtkWidget *area = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(app), "area"));
+
+ if (context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ context->paragraph = newPara;
+ gtk_window_set_title(GTK_WINDOW(app), title);
+
+ gtk_widget_hide(area);
+ pf_breakLines(context->paragraph, context->width, context->height);
+ gtk_widget_show_all(area);
+
+ g_free(title);
+ }
+
+ g_free(fileName);
+}
+
+static void openfile(GtkObject *object, gpointer data)
+{
+ GtkWidget *app = GTK_WIDGET(data);
+ GtkWidget *fileselection;
+ GtkWidget *okButton;
+ GtkWidget *cancelButton;
+
+ fileselection =
+ gtk_file_selection_new("Open File");
+
+ gtk_object_set_data(GTK_OBJECT(fileselection), "app", app);
+
+ okButton =
+ GTK_FILE_SELECTION(fileselection)->ok_button;
+
+ cancelButton =
+ GTK_FILE_SELECTION(fileselection)->cancel_button;
+
+ gtk_signal_connect(GTK_OBJECT(fileselection), "destroy",
+ GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+
+ gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
+ GTK_SIGNAL_FUNC(openOK), fileselection);
+
+ gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(fileselection));
+
+ gtk_window_set_modal(GTK_WINDOW(fileselection), TRUE);
+ gtk_widget_show(fileselection);
+ gtk_main();
+}
+
+static void newapp(GtkObject *object, gpointer data)
+{
+ GtkWidget *app = newSample("Sample.txt");
+
+ gtk_widget_show_all(app);
+}
+
+static void closeapp(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *app = GTK_WIDGET(data);
+
+ closeSample(app);
+}
+
+static void shutdown(GtkObject *object, gpointer data)
+{
+ gtk_main_quit();
+}
+
+GnomeUIInfo fileMenu[] =
+{
+ GNOMEUIINFO_MENU_NEW_ITEM((gchar *) "_New Sample",
+ (gchar *) "Create a new Gnome Layout Sample",
+ newapp, NULL),
+
+ GNOMEUIINFO_MENU_OPEN_ITEM(openfile, NULL),
+ GNOMEUIINFO_SEPARATOR,
+ GNOMEUIINFO_MENU_CLOSE_ITEM(closeapp, NULL),
+ GNOMEUIINFO_MENU_EXIT_ITEM(shutdown, NULL),
+ GNOMEUIINFO_END
+};
+
+GnomeUIInfo helpMenu[] =
+{
+ /* GNOMEUIINFO_HELP("gnomelayout"), */
+ GNOMEUIINFO_MENU_ABOUT_ITEM(showabout, NULL),
+ GNOMEUIINFO_END
+};
+
+GnomeUIInfo mainMenu[] =
+{
+ GNOMEUIINFO_SUBTREE(N_((gchar *) "File"), fileMenu),
+ GNOMEUIINFO_SUBTREE(N_((gchar *) "Help"), helpMenu),
+ GNOMEUIINFO_END
+};
+
+static gint eventDelete(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ closeSample(widget);
+
+ /* indicate that closeapp already destroyed the window */
+ return TRUE;
+}
+
+static gint eventConfigure(GtkWidget *widget, GdkEventConfigure *event, Context *context)
+{
+ if (context->paragraph != NULL) {
+ context->width = event->width;
+ context->height = event->height;
+
+ if (context->width > 0 && context->height > 0) {
+ pf_breakLines(context->paragraph, context->width, context->height);
+ }
+ }
+
+ return TRUE;
+}
+
+static gint eventExpose(GtkWidget *widget, GdkEvent *event, Context *context)
+{
+ if (context->paragraph != NULL) {
+ gint maxLines = pf_getLineCount(context->paragraph) - 1;
+ gint firstLine = 0, lastLine = context->height / pf_getLineHeight(context->paragraph);
+ rs_surface *surface = rs_gnomeRenderingSurfaceOpen(widget);
+
+ pf_draw(context->paragraph, surface, firstLine, (maxLines < lastLine)? maxLines : lastLine);
+
+ rs_gnomeRenderingSurfaceClose(surface);
+ }
+
+ return TRUE;
+}
+
+GtkWidget *newSample(const gchar *fileName)
+{
+ Context *context = NEW_ARRAY(Context, 1);
+ gchar *title;
+ GtkWidget *app;
+ GtkWidget *area;
+ GtkStyle *style;
+ int i;
+
+ context->width = 600;
+ context->height = 400;
+ context->paragraph = pf_factory(fileName, font, guiSupport);
+
+ title = prettyTitle(fileName);
+ app = gnome_app_new("gnomeLayout", title);
+
+ gtk_object_set_data(GTK_OBJECT(app), "context", context);
+
+ gtk_window_set_default_size(GTK_WINDOW(app), 600 - 24, 400);
+
+ gnome_app_create_menus_with_data(GNOME_APP(app), mainMenu, app);
+
+ gtk_signal_connect(GTK_OBJECT(app), "delete_event",
+ GTK_SIGNAL_FUNC(eventDelete), NULL);
+
+ area = gtk_drawing_area_new();
+ gtk_object_set_data(GTK_OBJECT(app), "area", area);
+
+ style = gtk_style_copy(gtk_widget_get_style(area));
+
+ for (i = 0; i < 5; i += 1) {
+ style->fg[i] = style->white;
+ }
+
+ gtk_widget_set_style(area, style);
+
+ gnome_app_set_contents(GNOME_APP(app), area);
+
+ gtk_signal_connect(GTK_OBJECT(area),
+ "expose_event",
+ GTK_SIGNAL_FUNC(eventExpose),
+ context);
+
+ gtk_signal_connect(GTK_OBJECT(area),
+ "configure_event",
+ GTK_SIGNAL_FUNC(eventConfigure),
+ context);
+
+ appList = g_slist_prepend(appList, app);
+
+ g_free(title);
+
+ return app;
+}
+
+void closeSample(GtkWidget *app)
+{
+ Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
+
+ if (context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ DELETE_ARRAY(context);
+
+ appList = g_slist_remove(appList, app);
+
+ gtk_widget_destroy(app);
+
+ if (appList == NULL) {
+ gtk_main_quit();
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ LEErrorCode fontStatus = LE_NO_ERROR;
+ poptContext ptctx;
+ GtkWidget *app;
+ const char *defaultArgs[] = {"Sample.txt", NULL};
+ const char **args;
+ int i;
+
+ FT_Init_FreeType(&engine);
+
+ gnome_init_with_popt_table("gnomelayout", "0.1", argc, argv, NULL, 0, &ptctx);
+
+ guiSupport = gs_gnomeGuiSupportOpen();
+ fontMap = fm_gnomeFontMapOpen(engine, "FontMap.Gnome", 24, guiSupport, &fontStatus);
+ font = le_scriptCompositeFontOpen(fontMap);
+
+ if (LE_FAILURE(fontStatus)) {
+ FT_Done_FreeType(engine);
+ return 1;
+ }
+
+ args = poptGetArgs(ptctx);
+
+ if (args == NULL) {
+ args = defaultArgs;
+ }
+
+ for (i = 0; args[i] != NULL; i += 1) {
+ app = newSample(args[i]);
+
+ gtk_widget_show_all(app);
+ }
+
+ poptFreeContext(ptctx);
+
+ gtk_main();
+
+ le_fontClose(font);
+ gs_gnomeGuiSupportClose(guiSupport);
+
+ FT_Done_FreeType(engine);
+
+ exit(0);
+}
diff --git a/icu4c/source/samples/layout/clayout.c b/icu4c/source/samples/layout/clayout.c
new file mode 100644
index 00000000000..701ab8dc09c
--- /dev/null
+++ b/icu4c/source/samples/layout/clayout.c
@@ -0,0 +1,363 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: Layout.cpp
+ *
+ * created on: 08/03/2000
+ * created by: Eric R. Mader
+ */
+
+#include
+#include
+
+#include "playout.h"
+#include "pflow.h"
+
+#include "gdiglue.h"
+#include "ucreader.h"
+
+#include "arraymem.h"
+
+#include "resource.h"
+
+struct Context
+{
+ le_int32 width;
+ le_int32 height;
+ pf_flow *paragraph;
+};
+
+typedef struct Context Context;
+
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+
+#define APP_NAME "LayoutSample"
+
+TCHAR szAppName[] = TEXT(APP_NAME);
+
+void PrettyTitle(HWND hwnd, char *fileName)
+{
+ char title[MAX_PATH + 64];
+
+ sprintf(title, "%s - %s", APP_NAME, fileName);
+
+ SetWindowTextA(hwnd, title);
+}
+
+void InitParagraph(HWND hwnd, Context *context)
+{
+ SCROLLINFO si;
+
+ if (context->paragraph != NULL) {
+ // FIXME: does it matter what we put in the ScrollInfo
+ // if the window's been minimized?
+ if (context->width > 0 && context->height > 0) {
+ pf_breakLines(context->paragraph, context->width, context->height);
+ }
+
+ si.cbSize = sizeof si;
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
+ si.nMin = 0;
+ si.nMax = pf_getLineCount(context->paragraph) - 1;
+ si.nPage = context->height / pf_getLineHeight(context->paragraph);
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
+{
+ HWND hwnd;
+ HACCEL hAccel;
+ MSG msg;
+ WNDCLASS wndclass;
+ LEErrorCode status = LE_NO_ERROR;
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(LONG);
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wndclass.lpszMenuName = szAppName;
+ wndclass.lpszClassName = szAppName;
+
+ if (!RegisterClass(&wndclass)) {
+ MessageBox(NULL, TEXT("This demo only runs on Windows 2000!"), szAppName, MB_ICONERROR);
+
+ return 0;
+ }
+
+ hAccel = LoadAccelerators(hInstance, szAppName);
+
+ hwnd = CreateWindow(szAppName, NULL,
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 600, 400,
+ NULL, NULL, hInstance, NULL);
+
+ ShowWindow(hwnd, iCmdShow);
+ UpdateWindow(hwnd);
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ if (!TranslateAccelerator(hwnd, hAccel, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ UnregisterClass(szAppName, hInstance);
+ return msg.wParam;
+}
+
+LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ Context *context;
+ static le_int32 windowCount = 0;
+ static fm_fontMap *fontMap = NULL;
+ static rs_surface *surface = NULL;
+ static gs_guiSupport *guiSupport = NULL;
+ static le_font *font = NULL;
+
+ switch (message) {
+ case WM_CREATE:
+ {
+ LEErrorCode fontStatus = LE_NO_ERROR;
+
+ hdc = GetDC(hwnd);
+ guiSupport = gs_gdiGuiSupportOpen();
+ surface = rs_gdiRenderingSurfaceOpen(hdc);
+
+ fontMap = fm_gdiFontMapOpen(surface, "FontMap.GDI", 24, guiSupport, &fontStatus);
+ font = le_scriptCompositeFontOpen(fontMap);
+
+ if (LE_FAILURE(fontStatus)) {
+ ReleaseDC(hwnd, hdc);
+ return -1;
+ }
+
+ context = NEW_ARRAY(Context, 1);
+
+ context->width = 600;
+ context->height = 400;
+
+ context->paragraph = pf_factory("Sample.txt", font, guiSupport);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) context);
+
+ windowCount += 1;
+ ReleaseDC(hwnd, hdc);
+
+ PrettyTitle(hwnd, "Sample.txt");
+ return 0;
+ }
+
+ case WM_SIZE:
+ {
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
+ context->width = LOWORD(lParam);
+ context->height = HIWORD(lParam);
+
+ InitParagraph(hwnd, context);
+ return 0;
+ }
+
+ case WM_VSCROLL:
+ {
+ SCROLLINFO si;
+ le_int32 vertPos;
+
+ si.cbSize = sizeof si;
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+
+ vertPos = si.nPos;
+
+ switch (LOWORD(wParam))
+ {
+ case SB_TOP:
+ si.nPos = si.nMin;
+ break;
+
+ case SB_BOTTOM:
+ si.nPos = si.nMax;
+ break;
+
+ case SB_LINEUP:
+ si.nPos -= 1;
+ break;
+
+ case SB_LINEDOWN:
+ si.nPos += 1;
+ break;
+
+ case SB_PAGEUP:
+ si.nPos -= si.nPage;
+ break;
+
+ case SB_PAGEDOWN:
+ si.nPos += si.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+
+ default:
+ break;
+ }
+
+ si.fMask = SIF_POS;
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ GetScrollInfo(hwnd, SB_VERT, &si);
+
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
+
+ if (context->paragraph != NULL && si.nPos != vertPos) {
+ ScrollWindow(hwnd, 0, pf_getLineHeight(context->paragraph) * (vertPos - si.nPos), NULL, NULL);
+ UpdateWindow(hwnd);
+ }
+
+ return 0;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ SCROLLINFO si;
+ le_int32 firstLine, lastLine;
+
+ hdc = BeginPaint(hwnd, &ps);
+ SetBkMode(hdc, TRANSPARENT);
+
+ si.cbSize = sizeof si;
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, SB_VERT, &si);
+
+ firstLine = si.nPos;
+
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
+
+ if (context->paragraph != NULL) {
+ rs_gdiRenderingSurfaceSetHDC(surface, hdc);
+
+ // NOTE: si.nPos + si.nPage may include a partial line at the bottom
+ // of the window. We need this because scrolling assumes that the
+ // partial line has been painted.
+ lastLine = min (si.nPos + (le_int32) si.nPage, pf_getLineCount(context->paragraph) - 1);
+
+ pf_draw(context->paragraph, surface, firstLine, lastLine);
+ }
+
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDM_FILE_OPEN:
+ {
+ OPENFILENAMEA ofn;
+ char szFileName[MAX_PATH], szTitleName[MAX_PATH];
+ static char szFilter[] = "Text Files (.txt)\0*.txt\0"
+ "All Files (*.*)\0*.*\0\0";
+
+ ofn.lStructSize = sizeof (OPENFILENAMEA);
+ ofn.hwndOwner = hwnd;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 0;
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrFileTitle = szTitleName;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = NULL;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = "txt";
+ ofn.lCustData = 0L;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+
+ szFileName[0] = '\0';
+
+ if (GetOpenFileNameA(&ofn)) {
+ pf_flow *newParagraph;
+
+ hdc = GetDC(hwnd);
+ rs_gdiRenderingSurfaceSetHDC(surface, hdc);
+
+ newParagraph = pf_factory(szFileName, font, guiSupport);
+
+ if (newParagraph != NULL) {
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
+
+ if (context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ context->paragraph = newParagraph;
+ InitParagraph(hwnd, context);
+ PrettyTitle(hwnd, szTitleName);
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ }
+ }
+
+ //ReleaseDC(hwnd, hdc);
+
+ return 0;
+ }
+
+ case IDM_FILE_EXIT:
+ case IDM_FILE_CLOSE:
+ SendMessage(hwnd, WM_CLOSE, 0, 0);
+ return 0;
+
+ case IDM_HELP_ABOUTLAYOUTSAMPLE:
+ MessageBox(hwnd, TEXT("Windows Layout Sample 0.1\n")
+ TEXT("Copyright (C) 1998-2005 By International Business Machines Corporation and others.\n")
+ TEXT("Author: Eric Mader"),
+ szAppName, MB_ICONINFORMATION | MB_OK);
+ return 0;
+
+ }
+ break;
+
+
+ case WM_DESTROY:
+ {
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
+
+ if (context != NULL && context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ DELETE_ARRAY(context);
+
+ if (--windowCount <= 0) {
+ le_fontClose(font);
+ rs_gdiRenderingSurfaceClose(surface);
+ gs_gdiGuiSupportClose(guiSupport);
+
+ PostQuitMessage(0);
+ }
+
+ return 0;
+ }
+
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+
+ return 0;
+}
diff --git a/icu4c/source/samples/layout/gdiglue.cpp b/icu4c/source/samples/layout/gdiglue.cpp
new file mode 100644
index 00000000000..e553c0617b1
--- /dev/null
+++ b/icu4c/source/samples/layout/gdiglue.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include
+
+#include "unicode/utypes.h"
+#include "loengine.h"
+#include "rsurface.h"
+#include "gsupport.h"
+
+#include "gdiglue.h"
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "GDIGUISupport.h"
+#include "GDIFontMap.h"
+#include "ScriptCompositeFontInstance.h"
+
+
+U_CDECL_BEGIN
+
+gs_guiSupport *gs_gdiGuiSupportOpen()
+{
+ return (gs_guiSupport *) new GDIGUISupport();
+}
+
+void gs_gdiGuiSupportClose(gs_guiSupport *guiSupport)
+{
+ GDIGUISupport *gs = (GDIGUISupport *) guiSupport;
+
+ delete gs;
+}
+
+rs_surface *rs_gdiRenderingSurfaceOpen(HDC hdc)
+{
+ return (rs_surface *) new GDISurface(hdc);
+}
+
+void rs_gdiRenderingSurfaceSetHDC(rs_surface *surface, HDC hdc)
+{
+ GDISurface *rs = (GDISurface *) surface;
+
+ rs->setHDC(hdc);
+}
+
+void rs_gdiRenderingSurfaceClose(rs_surface *surface)
+{
+ GDISurface *rs = (GDISurface *) surface;
+
+ delete rs;
+}
+
+fm_fontMap *fm_gdiFontMapOpen(rs_surface *surface, const char *fileName, le_int16 pointSize, gs_guiSupport *guiSupport, LEErrorCode *status)
+{
+ return (fm_fontMap *) new GDIFontMap((GDISurface *) surface, fileName, pointSize, (GDIGUISupport *) guiSupport, *status);
+}
+
+void fm_fontMapClose(fm_fontMap *fontMap)
+{
+ GDIFontMap *fm = (GDIFontMap *) fontMap;
+
+ delete fm;
+}
+
+le_font *le_scriptCompositeFontOpen(fm_fontMap *fontMap)
+{
+ return (le_font *) new ScriptCompositeFontInstance((FontMap *) fontMap);
+}
+
+void le_fontClose(le_font *font)
+{
+ LEFontInstance *fi = (LEFontInstance *) font;
+
+ delete fi;
+}
+
+U_CDECL_END
diff --git a/icu4c/source/samples/layout/gdiglue.h b/icu4c/source/samples/layout/gdiglue.h
new file mode 100644
index 00000000000..bdd8422bb65
--- /dev/null
+++ b/icu4c/source/samples/layout/gdiglue.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __GDIGLUE_H
+#define __GDIGLUE_H
+
+#include
+
+#include "unicode/utypes.h"
+
+#include "LETypes.h"
+#include "loengine.h"
+#include "gsupport.h"
+#include "rsurface.h"
+
+typedef void fm_fontMap;
+
+U_CDECL_BEGIN
+
+gs_guiSupport *gs_gdiGuiSupportOpen();
+void gs_gdiGuiSupportClose(gs_guiSupport *guiSupport);
+
+rs_surface *rs_gdiRenderingSurfaceOpen(HDC hdc);
+void rs_gdiRenderingSurfaceSetHDC(rs_surface *surface, HDC hdc);
+void rs_gdiRenderingSurfaceClose(rs_surface *surface);
+
+fm_fontMap *fm_gdiFontMapOpen(rs_surface *surface, const char *fileName, le_int16 pointSize, gs_guiSupport *guiSupport, LEErrorCode *status);
+void fm_fontMapClose(fm_fontMap *fontMap);
+
+le_font *le_scriptCompositeFontOpen(fm_fontMap *fontMap);
+void le_fontClose(le_font *font);
+
+U_CDECL_END
+
+#endif
diff --git a/icu4c/source/samples/layout/gnomeglue.cpp b/icu4c/source/samples/layout/gnomeglue.cpp
new file mode 100644
index 00000000000..a081e0bfcbf
--- /dev/null
+++ b/icu4c/source/samples/layout/gnomeglue.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include
+#include
+#include FT_FREETYPE_H
+
+#include "unicode/utypes.h"
+#include "loengine.h"
+#include "rsurface.h"
+#include "gsupport.h"
+
+#include "gnomeglue.h"
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "GnomeGUISupport.h"
+#include "GnomeFontMap.h"
+#include "GnomeFontInstance.h"
+#include "ScriptCompositeFontInstance.h"
+
+
+U_CDECL_BEGIN
+
+gs_guiSupport *gs_gnomeGuiSupportOpen()
+{
+ return (gs_guiSupport *) new GnomeGUISupport();
+}
+
+void gs_gnomeGuiSupportClose(gs_guiSupport *guiSupport)
+{
+ GnomeGUISupport *gs = (GnomeGUISupport *) guiSupport;
+
+ delete gs;
+}
+
+rs_surface *rs_gnomeRenderingSurfaceOpen(GtkWidget *theWidget)
+{
+ return (rs_surface *) new GnomeSurface(theWidget);
+}
+
+void rs_gnomeRenderingSurfaceClose(rs_surface *surface)
+{
+ GnomeSurface *rs = (GnomeSurface *) surface;
+
+ delete rs;
+}
+
+fm_fontMap *fm_gnomeFontMapOpen(FT_Library engine, const char *fileName, le_int16 pointSize, gs_guiSupport *guiSupport, LEErrorCode *status)
+{
+ return (fm_fontMap *) new GnomeFontMap(engine, fileName, pointSize, (GnomeGUISupport *) guiSupport, *status);
+}
+
+void fm_fontMapClose(fm_fontMap *fontMap)
+{
+ GnomeFontMap *fm = (GnomeFontMap *) fontMap;
+
+ delete fm;
+}
+
+le_font *le_scriptCompositeFontOpen(fm_fontMap *fontMap)
+{
+ return (le_font *) new ScriptCompositeFontInstance((FontMap *) fontMap);
+}
+
+void le_fontClose(le_font *font)
+{
+ LEFontInstance *fi = (LEFontInstance *) font;
+
+ delete fi;
+}
+
+U_CDECL_END
diff --git a/icu4c/source/samples/layout/gnomeglue.h b/icu4c/source/samples/layout/gnomeglue.h
new file mode 100644
index 00000000000..78561468eee
--- /dev/null
+++ b/icu4c/source/samples/layout/gnomeglue.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __GNOMEGLUE_H
+#define __GNOMEGLUE_H
+
+#include
+#include
+#include FT_FREETYPE_H
+
+#include "unicode/utypes.h"
+
+#include "LETypes.h"
+#include "loengine.h"
+#include "gsupport.h"
+#include "rsurface.h"
+
+typedef void fm_fontMap;
+
+U_CDECL_BEGIN
+
+gs_guiSupport *gs_gnomeGuiSupportOpen();
+void gs_gnomeGuiSupportClose(gs_guiSupport *guiSupport);
+
+rs_surface *rs_gnomeRenderingSurfaceOpen(GtkWidget *theWidget);
+void rs_gnomeRenderingSurfaceClose(rs_surface *surface);
+
+fm_fontMap *fm_gnomeFontMapOpen(FT_Library engine, const char *fileName, le_int16 pointSize, gs_guiSupport *guiSupport, LEErrorCode *status);
+void fm_fontMapClose(fm_fontMap *fontMap);
+
+le_font *le_scriptCompositeFontOpen(fm_fontMap *fontMap);
+void le_fontClose(le_font *font);
+
+U_CDECL_END
+
+#endif
diff --git a/icu4c/source/samples/layout/gsupport.h b/icu4c/source/samples/layout/gsupport.h
new file mode 100644
index 00000000000..26f33b4c064
--- /dev/null
+++ b/icu4c/source/samples/layout/gsupport.h
@@ -0,0 +1,14 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __GSUPPORT_H
+#define __GSUPPORT_H
+
+typedef void gs_guiSupport;
+
+void gs_postErrorMessage(gs_guiSupport *guiSupport, const char *message, const char *title);
+
+#endif
diff --git a/icu4c/source/samples/layout/layout.cpp b/icu4c/source/samples/layout/layout.cpp
index 332e03d9d9c..745bb11b661 100644
--- a/icu4c/source/samples/layout/layout.cpp
+++ b/icu4c/source/samples/layout/layout.cpp
@@ -146,7 +146,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
context->height = 400;
context->paragraph = Paragraph::paragraphFactory("Sample.txt", font, guiSupport);
- SetWindowLong(hwnd, 0, (LONG) context);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) context);
windowCount += 1;
ReleaseDC(hwnd, hdc);
@@ -157,7 +157,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_SIZE:
{
- context = (Context *) GetWindowLong(hwnd, 0);
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
context->width = LOWORD(lParam);
context->height = HIWORD(lParam);
@@ -214,7 +214,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si);
- context = (Context *) GetWindowLong(hwnd, 0);
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
if (context->paragraph != NULL && si.nPos != vertPos) {
ScrollWindow(hwnd, 0, context->paragraph->getLineHeight() * (vertPos - si.nPos), NULL, NULL);
@@ -239,7 +239,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
firstLine = si.nPos;
- context = (Context *) GetWindowLong(hwnd, 0);
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
if (context->paragraph != NULL) {
surface->setHDC(hdc);
@@ -295,7 +295,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Paragraph *newParagraph = Paragraph::paragraphFactory(szFileName, font, guiSupport);
if (newParagraph != NULL) {
- context = (Context *) GetWindowLong(hwnd, 0);
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
if (context->paragraph != NULL) {
delete context->paragraph;
@@ -332,7 +332,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DESTROY:
{
- context = (Context *) GetWindowLong(hwnd, 0);
+ context = (Context *) GetWindowLongPtr(hwnd, 0);
if (context != NULL && context->paragraph != NULL) {
delete context->paragraph;
diff --git a/icu4c/source/samples/layout/layout.vcproj b/icu4c/source/samples/layout/layout.vcproj
index 750f1335ba2..c9c13375254 100644
--- a/icu4c/source/samples/layout/layout.vcproj
+++ b/icu4c/source/samples/layout/layout.vcproj
@@ -3,7 +3,7 @@
ProjectType="Visual C++"
Version="8.00"
Name="layout"
- ProjectGUID="{EE80B3B5-40F2-46F2-AC4B-FB929683515C}"
+ ProjectGUID="{497500ED-DE1D-4B20-B529-F41B5A0FBEEB}"
>
offset) {
+ return run;
+ }
+ }
+
+ return -1;
+}
+
+static void subsetFontRuns(const pl_fontRuns *fontRuns, le_int32 start, le_int32 limit, pl_fontRuns *sub)
+{
+ le_int32 startRun = findFontRun(fontRuns, start);
+ le_int32 endRun = findFontRun(fontRuns, limit - 1);
+ le_int32 run;
+
+ pl_resetFontRuns(sub);
+
+ for (run = startRun; run <= endRun; run += 1) {
+ const le_font *runFont = pl_getFontRunFont(fontRuns, run);
+ le_int32 runLimit = pl_getFontRunLimit(fontRuns, run) - start;
+
+ if (run == endRun) {
+ runLimit = limit - start;
+ }
+
+ pl_addFontRun(sub, runFont, runLimit);
+ }
+}
+
+pf_flow *pf_create(const LEUnicode chars[], le_int32 charCount, const pl_fontRuns *fontRuns, LEErrorCode *status)
+{
+ pf_object *flow;
+ le_int32 ascent = 0;
+ le_int32 descent = 0;
+ le_int32 leading = 0;
+ pl_localeRuns *locales = NULL;
+ pl_fontRuns *fr;
+ LEUnicode *pStart;
+ static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP, 0x0000};
+
+ if (LE_FAILURE(*status)) {
+ return NULL;
+ }
+
+ flow = NEW_ARRAY(pf_object, 1);
+
+ flow->fParagraphLayout = NULL;
+ flow->fParagraphCount = 0;
+ flow->fParagraphMax = PARA_GROW;
+ flow->fParagraphGrow = PARA_GROW;
+ flow->fLineCount = 0;
+ flow->fLinesMax = LINE_GROW;
+ flow->fLinesGrow = LINE_GROW;
+ flow->fLines = NULL;
+ flow->fChars = NULL;
+ flow->fLineHeight = -1;
+ flow->fAscent = -1;
+ flow->fWidth = -1;
+ flow->fHeight = -1;
+ flow->fParagraphLevel = UBIDI_DEFAULT_LTR;
+
+ fr = pl_openEmptyFontRuns(0);
+
+#ifdef TEST_LOCALE
+ locales = pl_openEmptyLocaleRuns(0);
+#endif
+
+ flow->fLines = NEW_ARRAY(pl_line *, flow->fLinesMax);
+ flow->fParagraphLayout = NEW_ARRAY(pl_paragraph *, flow->fParagraphMax);
+
+ flow->fChars = NEW_ARRAY(LEUnicode, charCount + 1);
+ LE_ARRAY_COPY(flow->fChars, chars, charCount);
+ flow->fChars[charCount] = 0;
+
+ pStart = &flow->fChars[0];
+
+ while (*pStart != 0) {
+ LEUnicode *pEnd = u_strpbrk(pStart, separators);
+ le_int32 pAscent, pDescent, pLeading;
+ pl_paragraph *paragraphLayout = NULL;
+
+ if (pEnd == NULL) {
+ pEnd = &flow->fChars[charCount];
+ }
+
+ if (pEnd != pStart) {
+ subsetFontRuns(fontRuns, pStart - flow->fChars, pEnd - flow->fChars, fr);
+
+#ifdef TEST_LOCALE
+ pl_resetLocaleRuns(locales);
+ pl_addLocaleRun(locales, TEST_LOCALE, pEnd - pStart);
+#endif
+
+ paragraphLayout = pl_create(pStart, pEnd - pStart, fr, NULL, NULL, locales, flow->fParagraphLevel, FALSE, status);
+
+ if (LE_FAILURE(*status)) {
+ break; /* return? something else? */
+ }
+
+ if (flow->fParagraphLevel == UBIDI_DEFAULT_LTR) {
+ flow->fParagraphLevel = pl_getParagraphLevel(paragraphLayout);
+ }
+
+ pAscent = pl_getAscent(paragraphLayout);
+ pDescent = pl_getDescent(paragraphLayout);
+ pLeading = pl_getLeading(paragraphLayout);
+
+ if (pAscent > ascent) {
+ ascent = pAscent;
+ }
+
+ if (pDescent > descent) {
+ descent = pDescent;
+ }
+
+ if (pLeading > leading) {
+ leading = pLeading;
+ }
+ }
+
+ if (flow->fParagraphCount >= flow->fParagraphMax) {
+ flow->fParagraphLayout = (pl_paragraph **) GROW_ARRAY(flow->fParagraphLayout, flow->fParagraphMax + flow->fParagraphGrow);
+ flow->fParagraphMax += flow->fParagraphGrow;
+ }
+
+ flow->fParagraphLayout[flow->fParagraphCount++] = paragraphLayout;
+
+ if (*pEnd == 0) {
+ break;
+ }
+
+ pStart = skipLineEnd(pEnd);
+ }
+
+ flow->fLineHeight = ascent + descent + leading;
+ flow->fAscent = ascent;
+
+ pl_closeLocaleRuns(locales);
+ pl_closeFontRuns(fr);
+
+ return (pf_flow *) flow;
+}
+
+void pf_close(pf_flow *flow)
+{
+ pf_object *obj = (pf_object *) flow;
+ le_int32 i;
+
+ for (i = 0; i < obj->fLineCount; i += 1) {
+ DELETE_ARRAY(obj->fLines[i]);
+ }
+
+ DELETE_ARRAY(obj->fLines);
+
+ for (i = 0; i < obj->fParagraphCount; i += 1) {
+ pl_close(obj->fParagraphLayout[i]);
+ }
+
+ DELETE_ARRAY(obj->fParagraphLayout);
+
+ DELETE_ARRAY(obj->fChars);
+
+ DELETE_ARRAY(obj);
+}
+
+
+le_int32 pf_getAscent(pf_flow *flow)
+{
+ pf_object *obj = (pf_object *) flow;
+
+ return obj->fAscent;
+}
+
+le_int32 pf_getLineHeight(pf_flow *flow)
+{
+ pf_object *obj = (pf_object *) flow;
+
+ return obj->fLineHeight;
+}
+
+le_int32 pf_getLineCount(pf_flow *flow)
+{
+ pf_object *obj = (pf_object *) flow;
+
+ return obj->fLineCount;
+}
+
+static void addLine(pf_object *obj, pl_line *line)
+{
+ if (obj->fLineCount >= obj->fLinesMax) {
+ obj->fLines = (pl_line **) GROW_ARRAY(obj->fLines, obj->fLinesMax + obj->fLinesGrow);
+ obj->fLinesMax += obj->fLinesGrow;
+ }
+
+ obj->fLines[obj->fLineCount++] = line;
+}
+
+void pf_breakLines(pf_flow *flow, le_int32 width, le_int32 height)
+{
+ pf_object *obj = (pf_object *) flow;
+ le_int32 li, p;
+ float lineWidth;
+ pl_line *line;
+
+ obj->fHeight = height;
+
+ /* don't re-break if the width hasn't changed */
+ if (obj->fWidth == width) {
+ return;
+ }
+
+ obj->fWidth = width;
+
+ lineWidth = (float) (width - 2 * MARGIN);
+
+ /* Free the old Lines... */
+ for (li = 0; li < obj->fLineCount; li += 1) {
+ pl_closeLine(obj->fLines[li]);
+ }
+
+ obj->fLineCount = 0;
+
+ for (p = 0; p < obj->fParagraphCount; p += 1) {
+ pl_paragraph *paragraphLayout = obj->fParagraphLayout[p];
+
+ if (paragraphLayout != NULL) {
+ pl_reflow(paragraphLayout);
+ while ((line = pl_nextLine(paragraphLayout, lineWidth)) != NULL) {
+ addLine(obj, line);
+ }
+ } else {
+ addLine(obj, NULL);
+ }
+ }
+}
+
+void pf_draw(pf_flow *flow, rs_surface *surface, le_int32 firstLine, le_int32 lastLine)
+{
+ pf_object *obj = (pf_object *) flow;
+ le_int32 li, x, y;
+
+ x = MARGIN;
+ y = obj->fAscent;
+
+ for (li = firstLine; li <= lastLine; li += 1) {
+ const pl_line *line = obj->fLines[li];
+
+ if (line != NULL) {
+ le_int32 runCount = pl_countLineRuns(line);
+ le_int32 run;
+
+ if (obj->fParagraphLevel == UBIDI_RTL) {
+ le_int32 lastX = pl_getLineWidth(line);
+
+ x = (obj->fWidth - lastX - MARGIN);
+ }
+
+
+ for (run = 0; run < runCount; run += 1) {
+ const pl_visualRun *visualRun = pl_getLineVisualRun(line, run);
+ le_int32 glyphCount = pl_getVisualRunGlyphCount(visualRun);
+ const le_font *font = pl_getVisualRunFont(visualRun);
+ const LEGlyphID *glyphs = pl_getVisualRunGlyphs(visualRun);
+ const float *positions = pl_getVisualRunPositions(visualRun);
+
+ rs_drawGlyphs(surface, font, glyphs, glyphCount, positions, x, y, obj->fWidth, obj->fHeight);
+ }
+ }
+
+ y += obj->fLineHeight;
+ }
+}
+
+pf_flow *pf_factory(const char *fileName, const le_font *font, gs_guiSupport *guiSupport)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ le_int32 charCount;
+ const UChar *text = uc_readFile(fileName, guiSupport, &charCount);
+ pl_fontRuns *fontRuns;
+ pf_flow *result = NULL;
+
+ if (text == NULL) {
+ return NULL;
+ }
+
+ fontRuns = pl_openEmptyFontRuns(0);
+
+ pl_addFontRun(fontRuns, font, charCount);
+
+ result = pf_create(text, charCount, fontRuns, &status);
+
+ if (LE_FAILURE(status)) {
+ pf_close(result);
+ result = NULL;
+ }
+
+ pl_closeFontRuns(fontRuns);
+
+ DELETE_ARRAY(text);
+
+ return result;
+}
+
diff --git a/icu4c/source/samples/layout/pflow.h b/icu4c/source/samples/layout/pflow.h
new file mode 100644
index 00000000000..7e0b7f313d8
--- /dev/null
+++ b/icu4c/source/samples/layout/pflow.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __PFLOW_H
+#define __PFLOW_H
+
+#include "unicode/utypes.h"
+#include "layout/LETypes.h"
+
+#include "layout/plruns.h"
+#include "layout/playout.h"
+
+#include "gsupport.h"
+#include "rsurface.h"
+
+typedef void pf_flow;
+
+pf_flow *pf_create(const LEUnicode chars[], le_int32 charCount, const pl_fontRuns *fontRuns, LEErrorCode *status);
+
+void pf_close(pf_flow *flow);
+
+le_int32 pf_getAscent(pf_flow *flow);
+le_int32 pf_getLineHeight(pf_flow *flow);
+le_int32 pf_getLineCount(pf_flow *flow);
+void pf_breakLines(pf_flow *flow, le_int32 width, le_int32 height);
+void pf_draw(pf_flow *flow, rs_surface *surface, le_int32 firstLine, le_int32 lastLine);
+
+pf_flow *pf_factory(const char *fileName, const le_font *font, gs_guiSupport *guiSupport);
+
+#endif
diff --git a/icu4c/source/samples/layout/rsurface.cpp b/icu4c/source/samples/layout/rsurface.cpp
new file mode 100644
index 00000000000..f383aa7dd56
--- /dev/null
+++ b/icu4c/source/samples/layout/rsurface.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "loengine.h"
+#include "rsurface.h"
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "RenderingSurface.h"
+
+U_CDECL_BEGIN
+
+void rs_drawGlyphs(rs_surface *surface, const le_font *font, const LEGlyphID *glyphs, le_int32 count,
+ const float *positions, le_int32 x, le_int32 y, le_int32 width, le_int32 height)
+{
+ RenderingSurface *rs = (RenderingSurface *) surface;
+
+ rs->drawGlyphs((const LEFontInstance *) font, glyphs, count, positions, x, y, width, height);
+}
+
+U_CDECL_END
diff --git a/icu4c/source/samples/layout/rsurface.h b/icu4c/source/samples/layout/rsurface.h
new file mode 100644
index 00000000000..c58194e5f94
--- /dev/null
+++ b/icu4c/source/samples/layout/rsurface.h
@@ -0,0 +1,21 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __RSURFACE_H
+#define __RSURFACE_H
+
+#include "loengine.h"
+
+typedef void rs_surface;
+
+U_CDECL_BEGIN
+
+void rs_drawGlyphs(rs_surface *surface, const le_font *font, const LEGlyphID *glyphs, le_int32 count,
+ const float *positions, le_int32 x, le_int32 y, le_int32 width, le_int32 height);
+
+U_CDECL_END
+
+#endif
diff --git a/icu4c/source/samples/layout/ucreader.cpp b/icu4c/source/samples/layout/ucreader.cpp
new file mode 100644
index 00000000000..bc928417aef
--- /dev/null
+++ b/icu4c/source/samples/layout/ucreader.cpp
@@ -0,0 +1,20 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "unicode/utypes.h"
+
+#include "ucreader.h"
+#include "gsupport.h"
+#include "UnicodeReader.h"
+
+U_CDECL_BEGIN
+
+const UChar *uc_readFile(const char *fileName, gs_guiSupport *guiSupport, int32_t *charCount)
+{
+ return UnicodeReader::readFile(fileName, (GUISupport *) guiSupport, *charCount);
+}
+
+U_CDECL_END
diff --git a/icu4c/source/samples/layout/ucreader.h b/icu4c/source/samples/layout/ucreader.h
new file mode 100644
index 00000000000..948db14deed
--- /dev/null
+++ b/icu4c/source/samples/layout/ucreader.h
@@ -0,0 +1,19 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __UCREADER_H
+#define __UCREADER_H
+
+#include "unicode/utypes.h"
+#include "gsupport.h"
+
+U_CDECL_BEGIN
+
+const UChar *uc_readFile(const char *fileName, gs_guiSupport *guiSupport, int32_t *charCount);
+
+U_CDECL_END
+
+#endif
diff --git a/icu4c/source/test/letest/Makefile.in b/icu4c/source/test/letest/Makefile.in
index 0f1093fa8f0..4d8b3341310 100644
--- a/icu4c/source/test/letest/Makefile.in
+++ b/icu4c/source/test/letest/Makefile.in
@@ -1,5 +1,5 @@
## Makefile.in for ICU - test/letest
-## Copyright (c) 2001-2006, International Business Machines Corporation and
+## Copyright (c) 2001-2007, International Business Machines Corporation and
## others. All Rights Reserved.
## Source directory information
@@ -20,8 +20,8 @@ subdir = test/letest
CLEANFILES = *~ $(DEPS)
## Target information
-TESTTARGET = letest
-GENTARGET = gendata
+TESTTARGET = letest
+GENTARGET = gendata
BUILDDIR := $(CURR_SRCCODE_FULL_DIR)/../../
# Simplify the path for Unix
@@ -41,6 +41,7 @@ LIBS = $(LIBICULE) $(LIBICUUC) $(LIBICUI18N) $(LIBCTESTFW) $(LIBICUTOOLUTIL) @LI
COMMONOBJECTS = letsutil.o cmaps.o FontTableCache.o SimpleFontInstance.o PortableFontInstance.o
TESTOBJECTS = letest.o
+CTESTOBJECTS = cfonts.o xmlreader.o cletest.o
GENOBJECTS = gendata.o
OBJECTS = $(COMMONOBJECTS) $(TESTOBJECTS) $(GENOBJECTS)
@@ -70,7 +71,7 @@ dist-local:
clean-local:
test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
- $(RMV) $(OBJECTS) $(TARGET)
+ $(RMV) $(COMMONOBJECTS) $(TESTOBJECTS) $(CTESTOBJECTS) $(GENOBJECTS) $(TARGET)
distclean-local: clean-local
$(RMV) Makefile
@@ -82,7 +83,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-$(TESTTARGET) : $(COMMONOBJECTS) $(TESTOBJECTS)
+$(TESTTARGET) : $(COMMONOBJECTS) $(TESTOBJECTS) $(CTESTOBJECTS)
$(LINK.cc) -o $@ $^ $(LIBS)
$(POST_BUILD_STEP)
diff --git a/icu4c/source/test/letest/cfonts.cpp b/icu4c/source/test/letest/cfonts.cpp
new file mode 100644
index 00000000000..a06ec08d5fd
--- /dev/null
+++ b/icu4c/source/test/letest/cfonts.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "loengine.h"
+#include "PortableFontInstance.h"
+#include "SimpleFontInstance.h"
+
+U_CDECL_BEGIN
+
+le_font *le_portableFontOpen(const char *fileName,
+ float pointSize,
+ LEErrorCode *status)
+{
+ return (le_font *) new PortableFontInstance(fileName, pointSize, *status);
+}
+
+le_font *le_simpleFontOpen(float pointSize,
+ LEErrorCode *status)
+{
+ return (le_font *) new SimpleFontInstance(pointSize, *status);
+}
+
+void le_fontClose(le_font *font)
+{
+ LEFontInstance *fontInstance = (LEFontInstance *) font;
+
+ delete fontInstance;
+}
+
+const char *le_getNameString(le_font *font, le_uint16 nameID, le_uint16 platform, le_uint16 encoding, le_uint16 language)
+{
+ PortableFontInstance *pfi = (PortableFontInstance *) font;
+
+ return pfi->getNameString(nameID, platform, encoding, language);
+}
+
+void le_deleteNameString(le_font *font, const char *name)
+{
+ PortableFontInstance *pfi = (PortableFontInstance *) font;
+
+ pfi->deleteNameString(name);
+}
+
+le_uint32 le_getFontChecksum(le_font *font)
+{
+ PortableFontInstance *pfi = (PortableFontInstance *) font;
+
+ return pfi->getFontChecksum();
+}
+
+U_CDECL_END
diff --git a/icu4c/source/test/letest/cfonts.h b/icu4c/source/test/letest/cfonts.h
new file mode 100644
index 00000000000..2dda8a2a283
--- /dev/null
+++ b/icu4c/source/test/letest/cfonts.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __CFONTS_H
+#define __CFONTS_H
+
+#include "LETypes.h"
+#include "loengine.h"
+
+le_font *le_portableFontOpen(const char *fileName,
+ float pointSize,
+ LEErrorCode *status);
+
+le_font *le_simpleFontOpen(float pointSize,
+ LEErrorCode *status);
+
+void le_fontClose(le_font *font);
+
+const char *le_getNameString(le_font *font, le_uint16 nameID, le_uint16 platform, le_uint16 encoding, le_uint16 language);
+
+void le_deleteNameString(le_font *font, const char *name);
+
+le_uint32 le_getFontChecksum(le_font *font);
+
+#endif
diff --git a/icu4c/source/test/letest/cletest.c b/icu4c/source/test/letest/cletest.c
new file mode 100644
index 00000000000..e886503d47d
--- /dev/null
+++ b/icu4c/source/test/letest/cletest.c
@@ -0,0 +1,489 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/ubidi.h"
+#include "unicode/uscript.h"
+#include "unicode/ctest.h"
+
+#include "layout/LETypes.h"
+#include "layout/LEScripts.h"
+#include "loengine.h"
+
+#include "cfonts.h"
+
+#include "letest.h"
+
+#include "sfnt.h"
+#include "xmlreader.h"
+#include "putilimp.h" /* for U_FILE_SEP_STRING */
+
+#include
+#include
+#include
+
+#define CH_COMMA 0x002C
+
+U_CDECL_BEGIN
+static void U_CALLCONV ParamTest(void)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ le_font *font = le_simpleFontOpen(12, &status);
+ le_engine *engine = le_create(font, arabScriptCode, -1, 0, &status);
+ LEGlyphID *glyphs = NULL;
+ le_int32 *indices = NULL;
+ float *positions = NULL;
+ le_int32 glyphCount = 0;
+
+ float x = 0.0, y = 0.0;
+ LEUnicode chars[] = {
+ 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
+ 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
+ 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
+ };
+
+
+ glyphCount = le_getGlyphCount(engine, &status);
+ if (glyphCount != 0) {
+ log_err("Calling getGlyphCount() on an empty layout returned %d.\n", glyphCount);
+ }
+
+ glyphs = NEW_ARRAY(LEGlyphID, glyphCount + 10);
+ indices = NEW_ARRAY(le_int32, glyphCount + 10);
+ positions = NEW_ARRAY(float, glyphCount + 10);
+
+ le_getGlyphs(engine, NULL, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling getGlyphs(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getGlyphs(engine, glyphs, &status);
+
+ if (status != LE_NO_LAYOUT_ERROR) {
+ log_err("Calling getGlyphs(glyphs, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getCharIndices(engine, NULL, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling getCharIndices(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getCharIndices(engine, indices, &status);
+
+ if (status != LE_NO_LAYOUT_ERROR) {
+ log_err("Calling getCharIndices(indices, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getCharIndicesWithBase(engine, NULL, 1024, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling getCharIndices(NULL, 1024, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getCharIndicesWithBase(engine, indices, 1024, &status);
+
+ if (status != LE_NO_LAYOUT_ERROR) {
+ log_err("Calling getCharIndices(indices, 1024, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getGlyphPositions(engine, NULL, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling getGlyphPositions(NULL, status) did not return LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getGlyphPositions(engine, positions, &status);
+
+ if (status != LE_NO_LAYOUT_ERROR) {
+ log_err("Calling getGlyphPositions(positions, status) on an empty layout did not return LE_NO_LAYOUT_ERROR.\n");
+ }
+
+ DELETE_ARRAY(positions);
+ DELETE_ARRAY(indices);
+ DELETE_ARRAY(glyphs);
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, NULL, 0, 0, 0, FALSE, 0.0, 0.0, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling layoutChars(NULL, 0, 0, 0, FALSE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, chars, -1, 6, 20, TRUE, 0.0, 0.0, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling layoutChars(chars, -1, 6, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, chars, 8, -1, 20, TRUE, 0.0, 0.0, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling layoutChars(chars, 8, -1, 20, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, chars, 8, 6, -1, TRUE, 0.0, 0.0, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling layoutChars((chars, 8, 6, -1, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, chars, 8, 6, 10, TRUE, 0.0, 0.0, &status);
+
+ if (status != LE_ILLEGAL_ARGUMENT_ERROR) {
+ log_err("Calling layoutChars(chars, 8, 6, 10, TRUE, 0.0, 0.0, status) did not fail w/ LE_ILLEGAL_ARGUMENT_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ glyphCount = le_layoutChars(engine, chars, 8, 6, 20, TRUE, 0.0, 0.0, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("Calling layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
+ goto bail;
+ }
+
+ le_getGlyphPosition(engine, -1, &x, &y, &status);
+
+ if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
+ log_err("Calling getGlyphPosition(-1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
+ }
+
+ status = LE_NO_ERROR;
+ le_getGlyphPosition(engine, glyphCount + 1, &x, &y, &status);
+
+ if (status != LE_INDEX_OUT_OF_BOUNDS_ERROR) {
+ log_err("Calling getGlyphPosition(glyphCount + 1, x, y, status) did not fail w/ LE_INDEX_OUT_OF_BOUNDS_ERROR.\n");
+ }
+
+bail:
+ le_close(engine);
+ le_fontClose(font);
+}
+U_CDECL_END
+
+U_CDECL_BEGIN
+static void U_CALLCONV FactoryTest(void)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ le_font *font = le_simpleFontOpen(12, &status);
+ le_engine *engine = NULL;
+ le_int32 scriptCode;
+
+ for(scriptCode = 0; scriptCode < scriptCodeCount; scriptCode += 1) {
+ status = LE_NO_ERROR;
+ engine = le_create(font, scriptCode, -1, 0, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("Could not create a LayoutEngine for script \'%s\'.\n", uscript_getShortName((UScriptCode)scriptCode));
+ }
+
+ le_close(engine);
+ }
+
+ le_fontClose(font);
+}
+U_CDECL_END
+
+U_CDECL_BEGIN
+static void U_CALLCONV AccessTest(void)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ le_font *font = le_simpleFontOpen(12, &status);
+ le_engine *engine =le_create(font, arabScriptCode, -1, 0, &status);
+ le_int32 glyphCount;
+ LEGlyphID glyphs[6];
+ le_int32 biasedIndices[6], indices[6], glyph;
+ float positions[6 * 2 + 2];
+ LEUnicode chars[] = {
+ 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068, 0x0020, /* "English " */
+ 0x0645, 0x0627, 0x0646, 0x062A, 0x0648, 0x0634, /* MEM ALIF KAF NOON TEH WAW SHEEN */
+ 0x0020, 0x0074, 0x0065, 0x0078, 0x0074, 0x02E /* " text." */
+ };
+
+ if (LE_FAILURE(status)) {
+ log_err("Could not create LayoutEngine.\n");
+ goto bail;
+ }
+
+ glyphCount = le_layoutChars(engine, chars, 8, 6, 20, TRUE, 0.0, 0.0, &status);
+
+ if (LE_FAILURE(status) || glyphCount != 6) {
+ log_err("layoutChars(chars, 8, 6, 20, TRUE, 0.0, 0.0, status) failed.\n");
+ goto bail;
+ }
+
+ le_getGlyphs(engine, glyphs, &status);
+ le_getCharIndices(engine, indices, &status);
+ le_getGlyphPositions(engine, positions, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("Could not get glyph, indices and position arrays.\n");
+ goto bail;
+ }
+
+ status = LE_NO_ERROR;
+ le_getCharIndicesWithBase(engine, biasedIndices, 1024, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("getCharIndices(biasedIndices, 1024, status) failed.\n");
+ } else {
+ for (glyph = 0; glyph < glyphCount; glyph += 1) {
+ if (biasedIndices[glyph] != (indices[glyph] + 1024)) {
+ log_err("biasedIndices[%d] != indices[%d] + 1024: %8X, %8X\n",
+ glyph, glyph, biasedIndices[glyph], indices[glyph]);
+ break;
+ }
+ }
+ }
+
+ status = LE_NO_ERROR;
+ for (glyph = 0; glyph <= glyphCount; glyph += 1) {
+ float x = 0.0, y = 0.0;
+
+ le_getGlyphPosition(engine, glyph, &x, &y, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("getGlyphPosition(%d, x, y, status) failed.\n", glyph);
+ break;
+ }
+
+ if (x != positions[glyph*2] || y != positions[glyph*2 + 1]) {
+ log_err("getGlyphPosition(%d, x, y, status) returned bad position: (%f, %f) != (%f, %f)\n",
+ glyph, x, y, positions[glyph*2], positions[glyph*2 + 1]);
+ break;
+ }
+ }
+
+bail:
+ le_close(engine);
+ le_fontClose(font);
+}
+U_CDECL_END
+
+static le_bool compareResults(const char *testID, TestResult *expected, TestResult *actual)
+{
+ le_int32 i;
+
+ /* NOTE: we'll stop on the first failure 'cause once there's one error, it may cascade... */
+ if (actual->glyphCount != expected->glyphCount) {
+ log_err("Test %s: incorrect glyph count: exptected %d, got %d\n",
+ testID, expected->glyphCount, actual->glyphCount);
+ return FALSE;
+ }
+
+ for (i = 0; i < actual->glyphCount; i += 1) {
+ if (actual->glyphs[i] != expected->glyphs[i]) {
+ log_err("Test %s: incorrect id for glyph %d: expected %4X, got %4X\n",
+ testID, i, expected->glyphs[i], actual->glyphs[i]);
+ return FALSE;
+ }
+ }
+
+ for (i = 0; i < actual->glyphCount; i += 1) {
+ if (actual->indices[i] != expected->indices[i]) {
+ log_err("Test %s: incorrect index for glyph %d: expected %8X, got %8X\n",
+ testID, i, expected->indices[i], actual->indices[i]);
+ return FALSE;
+ }
+ }
+
+ for (i = 0; i <= actual->glyphCount; i += 1) {
+ double xError = uprv_fabs(actual->positions[i * 2] - expected->positions[i * 2]);
+ double yError = uprv_fabs(actual->positions[i * 2 + 1] - expected->positions[i * 2 + 1]);
+
+ if (xError > 0.0001) {
+ log_err("Test %s: incorrect x position for glyph %d: expected %f, got %f\n",
+ testID, i, expected->positions[i * 2], actual->positions[i * 2]);
+ return FALSE;
+ }
+
+ if (yError < 0) {
+ yError = -yError;
+ }
+
+ if (yError > 0.0001) {
+ log_err("Test %s: incorrect y position for glyph %d: expected %f, got %f\n",
+ testID, i, expected->positions[i * 2 + 1], actual->positions[i * 2 + 1]);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void checkFontVersion(le_font *font, const char *testVersionString,
+ le_uint32 testChecksum, const char *testID)
+{
+ le_uint32 fontChecksum = le_getFontChecksum(font);
+
+ if (fontChecksum != testChecksum) {
+ const char *fontVersionString = le_getNameString(font, NAME_VERSION_STRING,
+ PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
+
+ log_info("Test %s: this may not be the same font used to generate the test data.\n", testID);
+ log_info("Your font's version string is \"%s\"\n", fontVersionString);
+ log_info("The expected version string is \"%s\"\n", testVersionString);
+ log_info("If you see errors, they may be due to the version of the font you're using.\n");
+
+ le_deleteNameString(font, fontVersionString);
+ }
+}
+
+/* Returns the path to icu/source/test/testdata/ */
+static const char *getSourceTestData() {
+#ifdef U_TOPSRCDIR
+ const char *srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+#else
+ const char *srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+ FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
+
+ if (f != NULL) {
+ /* We're in icu/source/test/letest/ */
+ fclose(f);
+ } else {
+ /* We're in icu/source/test/letest/(Debug|Release) */
+ srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+ }
+#endif
+
+ return srcDataDir;
+}
+
+static const char *getPath(char buffer[2048], const char *filename) {
+ const char *testDataDirectory = getSourceTestData();
+
+ strcpy(buffer, testDataDirectory);
+ strcat(buffer, filename);
+
+ return buffer;
+}
+
+static le_font *openFont(const char *fontName, const char *checksum, const char *version, const char *testID)
+{
+ char path[2048];
+ le_font *font;
+ LEErrorCode fontStatus = LE_NO_ERROR;
+
+ if (fontName != NULL) {
+ font = le_portableFontOpen(getPath(path, fontName), 12, &fontStatus);
+
+ if (LE_FAILURE(fontStatus)) {
+ log_info("Test %s: can't open font %s - test skipped.\n", testID, fontName);
+ le_fontClose(font);
+ return NULL;
+ } else {
+ le_uint32 cksum = 0;
+
+ sscanf(checksum, "%x", &cksum);
+
+ checkFontVersion(font, version, cksum, testID);
+ }
+ } else {
+ font = le_simpleFontOpen(12, &fontStatus);
+ }
+
+ return font;
+}
+
+static le_bool getRTL(const LEUnicode *text, le_int32 charCount)
+{
+ UBiDiLevel paraLevel;
+ UErrorCode status = U_ZERO_ERROR;
+ UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
+
+ ubidi_setPara(ubidi, text, charCount, UBIDI_DEFAULT_LTR, NULL, &status);
+ paraLevel = ubidi_getParaLevel(ubidi);
+ ubidi_close(ubidi);
+
+ return paraLevel & 1;
+}
+
+static void doTestCase (const char *testID,
+ const char *fontName,
+ const char *fontVersion,
+ const char *fontChecksum,
+ le_int32 scriptCode,
+ le_int32 languageCode,
+ const LEUnicode *text,
+ le_int32 charCount,
+ TestResult *expected)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ le_engine *engine;
+ le_font *font = openFont(fontName, fontChecksum, fontVersion, testID);
+ le_int32 typoFlags = 3; /* kerning + ligatures */
+ TestResult actual;
+
+ if (font == NULL) {
+ /* error message already printed. */
+ return;
+ }
+
+ if (fontName == NULL) {
+ typoFlags |= 0x80000000L; /* use CharSubstitutionFilter... */
+ }
+
+ engine = le_create(font, scriptCode, languageCode, typoFlags, &status);
+
+ if (LE_FAILURE(status)) {
+ log_err("Test %s: could not create a LayoutEngine.\n", testID);
+ goto free_expected;
+ }
+
+ actual.glyphCount = le_layoutChars(engine, text, 0, charCount, charCount, getRTL(text, charCount), 0, 0, &status);
+
+ actual.glyphs = NEW_ARRAY(LEGlyphID, actual.glyphCount);
+ actual.indices = NEW_ARRAY(le_int32, actual.glyphCount);
+ actual.positions = NEW_ARRAY(float, actual.glyphCount * 2 + 2);
+
+ le_getGlyphs(engine, actual.glyphs, &status);
+ le_getCharIndices(engine, actual.indices, &status);
+ le_getGlyphPositions(engine, actual.positions, &status);
+
+ compareResults(testID, expected, &actual);
+
+ DELETE_ARRAY(actual.positions);
+ DELETE_ARRAY(actual.indices);
+ DELETE_ARRAY(actual.glyphs);
+
+ le_close(engine);
+
+free_expected:
+ le_fontClose(font);
+}
+
+static void U_CALLCONV DataDrivenTest(void)
+{
+ char path[2048];
+ const char *testFilePath = getPath(path, "letest.xml");
+
+ readTestFile(testFilePath, doTestCase);
+}
+
+U_CFUNC void addCTests(TestNode **root)
+{
+ addTest(root, &ParamTest, "c_api/ParameterTest");
+ addTest(root, &FactoryTest, "c_api/FactoryTest");
+ addTest(root, &AccessTest, "c_layout/AccessTest");
+ addTest(root, &DataDrivenTest, "c_layout/DataDrivenTest");
+}
+
+
diff --git a/icu4c/source/test/letest/cletest.sln b/icu4c/source/test/letest/cletest.sln
new file mode 100644
index 00000000000..1ac75a272b2
--- /dev/null
+++ b/icu4c/source/test/letest/cletest.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cletest", "cletest.vcproj", "{798E3AE4-A984-43FF-8928-EACFF43F56AE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {798E3AE4-A984-43FF-8928-EACFF43F56AE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {798E3AE4-A984-43FF-8928-EACFF43F56AE}.Debug|Win32.Build.0 = Debug|Win32
+ {798E3AE4-A984-43FF-8928-EACFF43F56AE}.Release|Win32.ActiveCfg = Release|Win32
+ {798E3AE4-A984-43FF-8928-EACFF43F56AE}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/icu4c/source/test/letest/cletest.vcproj b/icu4c/source/test/letest/cletest.vcproj
new file mode 100644
index 00000000000..ed9685ab355
--- /dev/null
+++ b/icu4c/source/test/letest/cletest.vcproj
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/icu4c/source/test/letest/letest.cpp b/icu4c/source/test/letest/letest.cpp
index e73d9b82cb0..4429e8ce667 100644
--- a/icu4c/source/test/letest/letest.cpp
+++ b/icu4c/source/test/letest/letest.cpp
@@ -1,7 +1,7 @@
/*
*******************************************************************************
*
- * Copyright (C) 1999-2006, International Business Machines
+ * Copyright (C) 1999-2007, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@@ -657,7 +657,7 @@ static void U_CALLCONV DataDrivenTest(void)
expected.glyphCount = glyphCount;
if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
- log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
+ log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
id, charCount, glyphCount, indexCount, positionCount);
goto free_expected;
};
@@ -707,12 +707,14 @@ free_c_strings:
}
U_CDECL_END
-static void addAllTests(TestNode** root)
+static void addAllTests(TestNode **root)
{
addTest(root, &ParamTest, "api/ParameterTest");
addTest(root, &FactoryTest, "api/FactoryTest");
addTest(root, &AccessTest, "layout/AccessTest");
addTest(root, &DataDrivenTest, "layout/DataDrivenTest");
+
+ addCTests(root);
}
/* returns the path to icu/source/data/out */
diff --git a/icu4c/source/test/letest/letest.h b/icu4c/source/test/letest/letest.h
index da5b2110765..9f066ca8c99 100644
--- a/icu4c/source/test/letest/letest.h
+++ b/icu4c/source/test/letest/letest.h
@@ -15,6 +15,7 @@
#define __LETEST_H
#include "LETypes.h"
+#include "unicode/ctest.h"
#include
#include
@@ -38,4 +39,11 @@ struct TestResult
le_int32 *indices;
float *positions;
};
+
+#ifndef XP_CPLUSPLUS
+typedef struct TestResult TestResult;
+#endif
+
+U_CFUNC void addCTests(TestNode **root);
+
#endif
diff --git a/icu4c/source/test/letest/letest.vcproj b/icu4c/source/test/letest/letest.vcproj
index 23203bd06b6..9352bc24367 100644
--- a/icu4c/source/test/letest/letest.vcproj
+++ b/icu4c/source/test/letest/letest.vcproj
@@ -201,6 +201,14 @@
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
+
+
+
+
@@ -225,11 +233,19 @@
RelativePath=".\SimpleFontInstance.cpp"
>
+
+
+
+
@@ -258,6 +274,10 @@
RelativePath=".\SimpleFontInstance.h"
>
+
+
+#include
+#include
+
+//U_NAMESPACE_USE
+
+#define CH_COMMA 0x002C
+
+static le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
+{
+ int32_t offset = -1;
+
+ arraySize = 1;
+ while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
+ arraySize += 1;
+ }
+
+ le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
+ char number[16];
+ le_int32 count = 0;
+ le_int32 start = 0, end = 0;
+ le_int32 len = 0;
+
+ // trim leading whitespace
+ while(u_isUWhiteSpace(numbers[start])) {
+ start += 1;
+ }
+
+ while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
+ len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
+ number[len] = '\0';
+ start = end + 1;
+
+ sscanf(number, "%x", &array[count++]);
+
+ // trim whitespace following the comma
+ while(u_isUWhiteSpace(numbers[start])) {
+ start += 1;
+ }
+ }
+
+ // trim trailing whitespace
+ end = numbers.length();
+ while(u_isUWhiteSpace(numbers[end - 1])) {
+ end -= 1;
+ }
+
+ len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
+ number[len] = '\0';
+ sscanf(number, "%x", &array[count]);
+
+ return array;
+}
+
+static float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
+{
+ int32_t offset = -1;
+
+ arraySize = 1;
+ while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
+ arraySize += 1;
+ }
+
+ float *array = NEW_ARRAY(float, arraySize);
+ char number[32];
+ le_int32 count = 0;
+ le_int32 start = 0, end = 0;
+ le_int32 len = 0;
+
+ // trim leading whitespace
+ while(u_isUWhiteSpace(numbers[start])) {
+ start += 1;
+ }
+
+ while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
+ len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
+ number[len] = '\0';
+ start = end + 1;
+
+ sscanf(number, "%f", &array[count++]);
+
+ // trim whiteapce following the comma
+ while(u_isUWhiteSpace(numbers[start])) {
+ start += 1;
+ }
+ }
+
+ while(u_isUWhiteSpace(numbers[start])) {
+ start += 1;
+ }
+
+ // trim trailing whitespace
+ end = numbers.length();
+ while(u_isUWhiteSpace(numbers[end - 1])) {
+ end -= 1;
+ }
+
+ len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
+ number[len] = '\0';
+ sscanf(number, "%f", &array[count]);
+
+ return array;
+}
+
+U_CDECL_BEGIN
+void readTestFile(const char *testFilePath, TestCaseCallback callback)
+{
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ UErrorCode status = U_ZERO_ERROR;
+ UXMLParser *parser = UXMLParser::createParser(status);
+ UXMLElement *root = parser->parseFile(testFilePath, status);
+
+ if (root == NULL) {
+ log_err("Could not open the test data file: %s\n", testFilePath);
+ delete parser;
+ return;
+ }
+
+ UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case");
+ UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text");
+ UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font");
+ UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs");
+ UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices");
+ UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
+
+ // test-case attributes
+ UnicodeString id_attr = UNICODE_STRING_SIMPLE("id");
+ UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
+ UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang");
+
+ // test-font attributes
+ UnicodeString name_attr = UNICODE_STRING_SIMPLE("name");
+ UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version");
+ UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum");
+
+ const UXMLElement *testCase;
+ int32_t tc = 0;
+
+ while((testCase = root->nextChildElement(tc)) != NULL) {
+ if (testCase->getTagName().compare(test_case) == 0) {
+ char *id = getCString(testCase->getAttribute(id_attr));
+ char *script = getCString(testCase->getAttribute(script_attr));
+ char *lang = getCString(testCase->getAttribute(lang_attr));
+ char *fontName = NULL;
+ char *fontVer = NULL;
+ char *fontCksum = NULL;
+ const UXMLElement *element;
+ int32_t ec = 0;
+ int32_t charCount = 0;
+ int32_t typoFlags = 3; // kerning + ligatures...
+ UScriptCode scriptCode;
+ le_int32 languageCode = -1;
+ UnicodeString text, glyphs, indices, positions;
+ int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
+ TestResult expected = {0, NULL, NULL, NULL};
+
+ uscript_getCode(script, &scriptCode, 1, &status);
+ if (LE_FAILURE(status)) {
+ log_err("invalid script name: %s.\n", script);
+ goto free_c_strings;
+ }
+
+ if (lang != NULL) {
+ languageCode = getLanguageCode(lang);
+
+ if (languageCode < 0) {
+ log_err("invalid language name: %s.\n", lang);
+ goto free_c_strings;
+ }
+ }
+
+ while((element = testCase->nextChildElement(ec)) != NULL) {
+ UnicodeString tag = element->getTagName();
+
+ // TODO: make sure that each element is only used once.
+ if (tag.compare(test_font) == 0) {
+ fontName = getCString(element->getAttribute(name_attr));
+ fontVer = getCString(element->getAttribute(ver_attr));
+ fontCksum = getCString(element->getAttribute(cksum_attr));
+
+ } else if (tag.compare(test_text) == 0) {
+ text = element->getText(TRUE);
+ charCount = text.length();
+ } else if (tag.compare(result_glyphs) == 0) {
+ glyphs = element->getText(TRUE);
+ } else if (tag.compare(result_indices) == 0) {
+ indices = element->getText(TRUE);
+ } else if (tag.compare(result_positions) == 0) {
+ positions = element->getText(TRUE);
+ } else {
+ // an unknown tag...
+ char *cTag = getCString(&tag);
+
+ log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
+ freeCString(cTag);
+ }
+ }
+
+ expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount);
+ expected.indices = (le_int32 *) getHexArray(indices, indexCount);
+ expected.positions = getFloatArray(positions, positionCount);
+
+ expected.glyphCount = glyphCount;
+
+ if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
+ log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
+ id, charCount, glyphCount, indexCount, positionCount);
+ goto free_expected;
+ };
+
+ (*callback)(id, fontName, fontVer, fontCksum, scriptCode, languageCode, text.getBuffer(), charCount, &expected);
+
+free_expected:
+ DELETE_ARRAY(expected.positions);
+ DELETE_ARRAY(expected.indices);
+ DELETE_ARRAY(expected.glyphs);
+
+free_c_strings:
+ freeCString(fontCksum);
+ freeCString(fontVer);
+ freeCString(fontName);
+ freeCString(lang);
+ freeCString(script);
+ freeCString(id);
+ }
+ }
+
+ delete root;
+ delete parser;
+#endif
+}
+U_CDECL_END
diff --git a/icu4c/source/test/letest/xmlreader.h b/icu4c/source/test/letest/xmlreader.h
new file mode 100644
index 00000000000..be47b562795
--- /dev/null
+++ b/icu4c/source/test/letest/xmlreader.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __XMLREADER_H
+#define __XMLREADER_H
+
+#include "LETypes.h"
+#include "letest.h"
+
+typedef void (*TestCaseCallback) (const char *testID,
+ const char *fontName,
+ const char *fontVersion,
+ const char *fontChecksum,
+ le_int32 scriptCode,
+ le_int32 languageCode,
+ const LEUnicode *text,
+ le_int32 charCount,
+ TestResult *expected);
+
+U_CAPI void readTestFile(const char *testFilePath, TestCaseCallback callback);
+
+#endif