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