Loading ...
Sorry, an error occurred while loading the content.
 

FYI --- Fwd: Re: Tamil rendering bug in Qt

Expand Messages
  • Thuraiappah Vaseeharan
    ... http://tamil.homelinux.org/modules.php?op=modload&name=Downloads&file=index ...
    Message 1 of 1 , Sep 3, 2003
      --- Lars Knoll <lars@...> wrote:
      > From: Lars Knoll <lars@...>
      > To: Thuraiappah Vaseeharan <t_vasee@...>
      > Subject: Re: Tamil rendering bug
      > Date: Wed, 3 Sep 2003 18:01:16 +0200
      >
      > Hi,
      >
      > thanks for your report. I fixed this now (I attached the modified
      > QTDIR/src/kernel/qscriptengine_x11.cpp if you want to test further).
      > The fix
      > will appear in Qt 3.2.2
      >
      > best regards,
      > Lars
      >
      > On Tuesday 02 September 2003 21:41, you wrote:
      > > Hi Lars,
      > >
      > > I'm testing the Tamil language support in Qt-3.2, and came across
      > the
      > > following bug:
      > >
      > > Tamil Consonant + Vowel Modifier (UOBC2) should be rendered as a
      > > ligature , if the ligature is available in the OpenType font.
      > Qt-3.2
      > > does not. It render them directly as the component glyphs.
      > >
      > > To reproduce:
      > >
      > > A sample tamil file in UTF-8 is attached with some of the above
      > > sequences. The screenshot tamil_gtk2.png shows that in Gedit, the
      > > ligature substitution occurs correctly. The screenshot
      > > tamil_qt_3.2.0.png shows that in KEdit, Qt-3.2 does not perform the
      > > ligature substitution.
      > >
      > > The font used in the screenshots is TSCu_Paranar.ttf (GPL'd,
      > available
      > > from
      > >
      >
      http://tamil.homelinux.org/modules.php?op=modload&name=Downloads&file=index
      > >&req=getit&lid=9 )
      > >
      > > Regards,
      > >
      > > -Vasee
      > >
      > >
      > >
      > > __________________________________
      > > Do you Yahoo!?
      > > Yahoo! SiteBuilder - Free, easy-to-use web site design software
      > > http://sitebuilder.yahoo.com
      > >
      /****************************************************************************
      > ** $Id$
      > **
      > ** Continuation of middle eastern languages
      > **
      > ** Copyright (C) 2003 Trolltech AS. All rights reserved.
      > **
      > ** This file is part of the kernel module of the Qt GUI Toolkit.
      > **
      > ** This file may be distributed under the terms of the Q Public
      > License
      > ** as defined by Trolltech AS of Norway and appearing in the file
      > ** LICENSE.QPL included in the packaging of this file.
      > **
      > ** This file may be distributed and/or modified under the terms of
      > the
      > ** GNU General Public License version 2 as published by the Free
      > Software
      > ** Foundation and appearing in the file LICENSE.GPL included in the
      > ** packaging of this file.
      > **
      > ** Licensees holding valid Qt Enterprise Edition or Qt Professional
      > Edition
      > ** licenses for Unix/X11 or for Qt/Embedded may use this file in
      > accordance
      > ** with the Qt Commercial License Agreement provided with the
      > Software.
      > **
      > ** This file is provided AS IS with NO WARRANTY OF ANY KIND,
      > INCLUDING THE
      > ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      > PURPOSE.
      > **
      > ** See http://www.trolltech.com/pricing.html or email
      > sales@... for
      > ** information about Qt Commercial License Agreements.
      > ** See http://www.trolltech.com/qpl/ for QPL licensing information.
      > ** See http://www.trolltech.com/gpl/ for GPL licensing information.
      > **
      > ** Contact info@... if any conditions of this licensing are
      > ** not clear to you.
      > **
      >
      **********************************************************************/
      >
      > //
      >
      ------------------------------------------------------------------------------------------------------------------
      > //
      > // Continuation of middle eastern languages
      > //
      > //
      >
      ------------------------------------------------------------------------------------------------------------------
      >
      > // #### stil missing: identify invalid character combinations
      > static void hebrew_shape(int script, const QString &string, int from,
      > int len,
      > QTextEngine *engine, QScriptItem *si)
      > {
      > assert(script == QFont::Hebrew);
      >
      > #ifndef QT_NO_XFTFREETYPE
      > QOpenType *openType = si->fontEngine->openType();
      >
      > if ( openType && openType->supportsScript( script ) ) {
      > convertToCMap( string.unicode() + from, len, engine, si );
      > heuristicSetGlyphAttributes( string, from, len, engine, si );
      > openType->init(engine->glyphs(si), engine->glyphAttributes(si),
      > si->num_glyphs,
      > engine->logClusters(si), len);
      >
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'c', 'c', 'm', 'p' ));
      > // Uniscribe also defines dlig for Hebrew, but we leave this out for
      > now, as it's mostly
      > // ligatures one does not want in modern Hebrew (as lam-alef
      > ligatures).
      >
      > openType->applyGPOSFeatures();
      > si->num_glyphs = 0;
      > openType->appendTo(engine, si);
      >
      > return;
      > }
      > #endif
      > basic_shape( script, string, from, len, engine, si );
      > }
      >
      > // #### stil missing: identify invalid character combinations
      > static void syriac_shape( int script, const QString &string, int
      > from, int len,
      > QTextEngine *engine, QScriptItem *si )
      > {
      > #ifndef QT_NO_XFTFREETYPE
      > QOpenType *openType = si->fontEngine->openType();
      >
      > if ( openType && openType->supportsScript( QFont::Syriac ) ) {
      > arabicSyriacOpenTypeShape( QFont::Syriac, openType, string, from,
      > len, engine, si );
      > return;
      > }
      > #endif
      > basic_shape( script, string, from, len, engine, si );
      > }
      >
      >
      > static void thaana_shape(int script, const QString &string, int from,
      > int len,
      > QTextEngine *engine, QScriptItem *si)
      > {
      > assert(script == QFont::Thaana);
      >
      > #ifndef QT_NO_XFTFREETYPE
      > QOpenType *openType = si->fontEngine->openType();
      >
      > if ( openType && openType->supportsScript( script ) ) {
      > convertToCMap( string.unicode() + from, len, engine, si );
      > heuristicSetGlyphAttributes( string, from, len, engine, si );
      > openType->init(engine->glyphs(si), engine->glyphAttributes(si),
      > si->num_glyphs,
      > engine->logClusters(si), len);
      >
      > // thaana only uses positioning features
      > openType->applyGPOSFeatures();
      > si->num_glyphs = 0;
      > openType->appendTo(engine, si);
      >
      > return;
      > }
      > #endif
      > basic_shape( script, string, from, len, engine, si );
      > }
      >
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      > //
      > // Indic languages
      > //
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      >
      > enum Form {
      > Invalid = 0x0,
      > Unknown = Invalid,
      > Consonant,
      > Nukta,
      > Halant,
      > Matra,
      > VowelMark,
      > StressMark,
      > IndependentVowel,
      > LengthMark,
      > Control,
      > Other
      > };
      >
      > static const unsigned char indicForms[0xe00-0x900] = {
      > // Devangari
      > Invalid, VowelMark, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      >
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Nukta, Other, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Matra, Matra, Matra,
      > Matra, Matra, Matra, Matra,
      > Matra, Halant, Unknown, Unknown,
      >
      > Other, StressMark, StressMark, StressMark,
      > StressMark, Unknown, Unknown, Unknown,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > IndependentVowel, IndependentVowel, VowelMark, VowelMark,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Bengali
      > Invalid, VowelMark, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Invalid, Invalid, IndependentVowel,
      >
      > IndependentVowel, Invalid, Invalid, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Invalid, Consonant, Invalid,
      > Invalid, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Nukta, Other, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Invalid, Invalid, Matra,
      > Matra, Invalid, Invalid, Matra,
      > Matra, Halant, Unknown, Unknown,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, VowelMark,
      > Invalid, Invalid, Invalid, Invalid,
      > Consonant, Consonant, Invalid, Consonant,
      >
      > IndependentVowel, IndependentVowel, VowelMark, VowelMark,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Gurmukhi
      > Invalid, Invalid, VowelMark, Invalid,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
      > Invalid, Invalid, Invalid, IndependentVowel,
      >
      > IndependentVowel, Invalid, Invalid, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Invalid, Consonant, Consonant,
      > Invalid, Consonant, Consonant, Invalid,
      > Consonant, Consonant, Unknown, Unknown,
      > Nukta, Other, Matra, Matra,
      >
      > Matra, Matra, Matra, Invalid,
      > Invalid, Invalid, Invalid, Matra,
      > Matra, Invalid, Invalid, Matra,
      > Matra, Halant, Unknown, Unknown,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Unknown, Unknown, Unknown,
      > Invalid, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Invalid,
      >
      > Other, Other, Invalid, Invalid,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > StressMark, StressMark, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Gujarati
      > Invalid, VowelMark, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > Invalid, IndependentVowel, Invalid, IndependentVowel,
      >
      > IndependentVowel, IndependentVowel, Invalid, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Invalid, Consonant, Consonant,
      > Invalid, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Nukta, Other, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Matra, Invalid, Matra,
      > Matra, Matra, Invalid, Matra,
      > Matra, Halant, Unknown, Unknown,
      >
      > Other, Unknown, Unknown, Unknown,
      > Unknown, Unknown, Unknown, Unknown,
      > Unknown, Unknown, Unknown, Unknown,
      > Unknown, Unknown, Unknown, Unknown,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Oriya
      > Invalid, VowelMark, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Invalid, Invalid, IndependentVowel,
      >
      > IndependentVowel, Invalid, Invalid, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Invalid, Consonant, Consonant,
      > Invalid, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Nukta, Other, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Invalid, Invalid, Invalid, Matra,
      > Matra, Invalid, Invalid, Matra,
      > Matra, Halant, Unknown, Unknown,
      >
      > Other, Invalid, Invalid, Invalid,
      > Invalid, Unknown, LengthMark, LengthMark,
      > Invalid, Invalid, Invalid, Invalid,
      > Consonant, Consonant, Invalid, Consonant,
      >
      > IndependentVowel, IndependentVowel, Invalid, Invalid,
      > Invalid, Invalid, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > //Tamil
      > Invalid, Invalid, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
      > Invalid, Invalid, IndependentVowel, IndependentVowel,
      >
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      > IndependentVowel, Consonant, Invalid, Invalid,
      > Invalid, Consonant, Consonant, Invalid,
      > Consonant, Invalid, Consonant, Consonant,
      >
      > Invalid, Invalid, Invalid, Consonant,
      > Consonant, Invalid, Invalid, Invalid,
      > Consonant, Consonant, Consonant, Invalid,
      > Invalid, Invalid, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Invalid, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Invalid, Invalid, Matra, Matra,
      >
      > Matra, Matra, Matra, Invalid,
      > Invalid, Invalid, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Halant, Invalid, Invalid,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, LengthMark,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Telugu
      > Invalid, VowelMark, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      >
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Invalid, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Invalid, Invalid, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Halant, Invalid, Invalid,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, LengthMark, LengthMark, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      >
      > IndependentVowel, IndependentVowel, Invalid, Invalid,
      > Invalid, Invalid, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Kannada
      > Invalid, Invalid, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      >
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Invalid, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Invalid, Invalid, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Halant, Invalid, Invalid,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, LengthMark, LengthMark, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Consonant, Invalid,
      >
      > IndependentVowel, IndependentVowel, Invalid, Invalid,
      > Invalid, Invalid, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Malayalam
      > Invalid, Invalid, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      >
      > IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
      > IndependentVowel, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Unknown, Unknown,
      > Invalid, Invalid, Matra, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Invalid, Invalid, Matra, Matra,
      > Matra, Invalid, Matra, Matra,
      > Matra, Halant, Invalid, Invalid,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, LengthMark,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      >
      > IndependentVowel, IndependentVowel, Invalid, Invalid,
      > Invalid, Invalid, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      >
      > // Sinhala
      > Invalid, Invalid, VowelMark, VowelMark,
      > Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      >
      > IndependentVowel, IndependentVowel, IndependentVowel,
      > IndependentVowel,
      > IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
      > Invalid, Invalid, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      >
      > Consonant, Consonant, Invalid, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Consonant, Consonant,
      > Invalid, Consonant, Invalid, Invalid,
      >
      > Consonant, Consonant, Consonant, Consonant,
      > Consonant, Consonant, Invalid, Invalid,
      > Invalid, Invalid, Halant, Invalid,
      > Invalid, Invalid, Invalid, Matra,
      >
      > Matra, Matra, Matra, Matra,
      > Matra, Invalid, Matra, Invalid,
      > Matra, Matra, Matra, Matra,
      > Matra, Matra, Matra, Matra,
      >
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      > Invalid, Invalid, Invalid, Invalid,
      >
      > Invalid, Invalid, Matra, Matra,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > Other, Other, Other, Other,
      > };
      >
      > enum Position {
      > None,
      > Pre,
      > Above,
      > Below,
      > Post,
      > Split,
      > Base,
      > Reph,
      > Vattu,
      > Inherit
      > };
      >
      > static const unsigned char indicPosition[0xe00-0x900] = {
      > // Devanagari
      > None, Above, Above, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > Below, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, Post, Pre,
      >
      > Post, Below, Below, Below,
      > Below, Above, Above, Above,
      > Above, Post, Post, Post,
      > Post, None, None, None,
      >
      > None, Above, Below, Above,
      > Above, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, Below, Below,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Bengali
      > None, Above, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > Below, None, None, Post,
      >
      > Below, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > Below, None, Post, Pre,
      >
      > Post, Below, Below, Below,
      > Below, None, None, Pre,
      > Pre, None, None, Split,
      > Split, Below, None, None,
      >
      > None, None, None, None,
      > None, None, None, Post,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, Below, Below,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Gurmukhi
      > None, None, Above, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, Post,
      >
      > Below, None, None, None,
      > None, Below, None, None,
      > None, None, None, None,
      > Below, None, Post, Pre,
      >
      > Post, Below, Below, None,
      > None, None, None, Above,
      > Above, None, None, Above,
      > Above, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > Above, Above, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Gujarati
      > None, Above, Above, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > Below, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, Post, Pre,
      >
      > Post, Below, Below, Below,
      > Below, Above, None, Above,
      > Above, Post, None, Post,
      > Post, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Oriya
      > None, Above, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > Below, None, None, None,
      > Below, None, None, None,
      > Below, Below, Below, Post,
      >
      > Below, None, Below, Below,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, Post, Above,
      >
      > Post, Below, Below, Below,
      > None, None, None, Pre,
      > Split, None, None, Split,
      > Split, None, None, None,
      >
      > None, None, None, None,
      > None, None, Above, Post,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Tamil
      > None, None, Above, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, Post, Post,
      >
      > Above, Below, Below, None,
      > None, None, Pre, Pre,
      > Pre, None, Split, Split,
      > Split, Halant, None, None,
      >
      > None, None, None, None,
      > None, None, None, Post,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Telugu
      > None, Post, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, Below, Below, Below,
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      >
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      > Below, None, Below, Below,
      > Below, Below, Below, Below,
      >
      > Below, None, Below, Below,
      > None, Below, Below, Below,
      > Below, Below, None, None,
      > None, None, Post, Above,
      >
      > Above, Post, Post, Post,
      > Post, None, Above, Above,
      > Split, None, Post, Above,
      > Above, Halant, None, None,
      >
      > None, None, None, None,
      > None, Above, Below, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Kannada
      > None, None, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, Below, Below, Below,
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      >
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      > Below, Below, Below, Below,
      >
      > Below, None, Below, Below,
      > None, Below, Below, Below,
      > Below, Below, None, None,
      > None, None, Post, Above,
      >
      > Split, Post, Post, Post,
      > Post, None, Above, Split,
      > Split, None, Split, Split,
      > Above, Halant, None, None,
      >
      > None, None, None, None,
      > None, Post, Post, None,
      > None, None, None, None,
      > None, None, Below, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Malayalam
      > None, None, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, Post,
      >
      > Post, None, Below, None,
      > None, Post, None, None,
      > None, None, None, None,
      > None, None, Post, Post,
      >
      > Post, Post, Post, Post,
      > None, None, Pre, Pre,
      > Pre, None, Split, Split,
      > Split, Halant, None, None,
      >
      > None, None, None, None,
      > None, None, None, Post,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > // Sinhala
      > None, None, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, Post,
      >
      > Post, Post, Above, Above,
      > Below, None, Below, None,
      > Post, Pre, Split, Pre,
      > Split, Split, Split, Post,
      >
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None,
      >
      > None, None, Post, Post,
      > None, None, None, None,
      > None, None, None, None,
      > None, None, None, None
      > };
      >
      > static inline Form form( unsigned short uc ) {
      > if ( uc < 0x900 || uc > 0xdff ) {
      > if ( uc == 0x25cc )
      > return Consonant;
      > if ( uc == 0x200c || uc == 0x200d )
      > return Control;
      > return Other;
      > }
      > return (Form)indicForms[uc-0x900];
      > }
      >
      > static inline Position indic_position( unsigned short uc ) {
      > if ( uc < 0x900 || uc > 0xdff )
      > return None;
      > return (Position) indicPosition[uc-0x900];
      > }
      >
      >
      > enum IndicScriptProperties {
      > HasReph = 0x01,
      > HasSplit = 0x02
      > };
      >
      > const uchar scriptProperties[10] = {
      > // Devanagari,
      > HasReph,
      > // Bengali,
      > HasReph|HasSplit,
      > // Gurmukhi,
      > 0,
      > // Gujarati,
      > HasReph,
      > // Oriya,
      > HasReph|HasSplit,
      > // Tamil,
      > HasSplit,
      > // Telugu,
      > HasSplit,
      > // Kannada,
      > HasSplit|HasReph,
      > // Malayalam,
      > HasSplit,
      > // Sinhala,
      > HasSplit
      > };
      >
      > struct IndicOrdering {
      > Form form;
      > Position position;
      > };
      >
      > static const IndicOrdering devanagari_order [] = {
      > { Consonant, Below },
      > { Matra, Below },
      > { VowelMark, Below },
      > { StressMark, Below },
      > { Matra, Above },
      > { Matra, Post },
      > { Consonant, Reph },
      > { VowelMark, Above },
      > { StressMark, Above },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering bengali_order [] = {
      > { Consonant, Below },
      > { Matra, Below },
      > { Matra, Above },
      > { Consonant, Reph },
      > { VowelMark, Above },
      > { Consonant, Post },
      > { Matra, Post },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering gurmukhi_order [] = {
      > { Consonant, Below },
      > { Matra, Below },
      > { Matra, Above },
      > { Consonant, Post },
      > { Matra, Post },
      > { VowelMark, Above },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering tamil_order [] = {
      > { Matra, Above },
      > { Matra, Post },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering telugu_order [] = {
      > { Matra, Above },
      > { Matra, Below },
      > { Matra, Post },
      > { Consonant, Below },
      > { Consonant, Post },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering kannada_order [] = {
      > { Matra, Above },
      > { Matra, Post },
      > { Consonant, Below },
      > { Consonant, Post },
      > { LengthMark, Post },
      > { Consonant, Reph },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering malayalam_order [] = {
      > { Consonant, Below },
      > { Matra, Below },
      > { Consonant, Reph },
      > { Consonant, Post },
      > { Matra, Post },
      > { VowelMark, Post },
      > { (Form)0, None }
      > };
      >
      > static const IndicOrdering * const indic_order[] = {
      > devanagari_order, // Devanagari
      > bengali_order, // Bengali
      > gurmukhi_order, // Gurmukhi
      > devanagari_order, // Gujarati
      > bengali_order, // Oriya
      > tamil_order, // Tamil
      > telugu_order, // Telugu
      > kannada_order, // Kannada
      > malayalam_order, // Malayalam
      > devanagari_order // Sinhala // ### no OT specs available, we use
      > devanagari
      > };
      >
      >
      >
      > // vowel matras that have to be split into two parts.
      > static const unsigned short split_matras[] = {
      > // matra, split1, split2
      >
      > // bengalis
      > 0x9cb, 0x9c7, 0x9be,
      > 0x9cc, 0x9c7, 0x9d7,
      > // oriya
      > 0xb48, 0xb47, 0xb56,
      > 0xb4b, 0xb47, 0xb3e,
      > 0xb4c, 0xb47, 0xb57,
      > // tamil
      > 0xbca, 0xbc6, 0xbbe,
      > 0xbcb, 0xbc7, 0xbbe,
      > 0xbcc, 0xbc6, 0xbd7,
      > // telugu
      > 0xc48, 0xc46, 0xc56,
      > // kannada
      > 0xcc0, 0xcbf, 0xcd5,
      > 0xcc7, 0xcc6, 0xcd5,
      > 0xcc8, 0xcc6, 0xcd6,
      > 0xcca, 0xcc6, 0xcc2,
      > 0xccb, 0xcca, 0xcd5,
      > // malayalam
      > 0xd4a, 0xd46, 0xd3e,
      > 0xd4b, 0xd47, 0xd3e,
      > 0xd4c, 0xd46, 0xd57,
      > // sinhala
      > 0xdda, 0xdd9, 0xdca,
      > 0xddc, 0xdd9, 0xdcf,
      > 0xddd, 0xddc, 0xdca,
      > 0xdde, 0xdd9, 0xddf,
      > 0xffff
      > };
      >
      > static inline void splitMatra(unsigned short *reordered, int matra,
      > int &len, int &base)
      > {
      > unsigned short matra_uc = reordered[matra];
      > //qDebug("matra=%d, reordered[matra]=%x", matra,
      > reordered[matra]);
      >
      > const unsigned short *split = split_matras;
      > while ( split[0] < matra_uc )
      > split += 3;
      >
      > assert(*split == matra_uc);
      > ++split;
      >
      > if (indic_position(*split) == Pre) {
      > reordered[matra] = split[1];
      > memmove(reordered + 1, reordered, len*sizeof(unsigned short));
      > reordered[0] = split[0];
      > base++;
      > } else {
      > memmove(reordered + matra + 1, reordered + matra,
      > (len-matra)*sizeof(unsigned short));
      > reordered[matra] = split[0];
      > reordered[matra+1] = split[1];
      > }
      > len++;
      > }
      >
      > // #define INDIC_DEBUG
      > #ifdef INDIC_DEBUG
      > #define IDEBUG qDebug
      > #else
      > #define IDEBUG if(0) qDebug
      > #endif
      >
      > static void indic_shape_syllable( int script, const QString &string,
      > int from, int syllableLength,
      > QTextEngine *engine, QScriptItem *si, QOpenType *openType, bool
      > invalid )
      > {
      > assert( script >= QFont::Devanagari && script <= QFont::Sinhala
      > );
      > const unsigned short script_base = 0x0900 +
      > 0x80*(script-QFont::Devanagari);
      > const unsigned short ra = script_base + 0x30;
      > const unsigned short halant = script_base + 0x4d;
      > const unsigned short nukta = script_base + 0x3c;
      >
      > int len = syllableLength;
      > IDEBUG(">>>>> devanagari shape: from=%d, len=%d invalid=%d",
      > from, len, invalid);
      >
      > unsigned short r[64];
      > unsigned short *reordered = r;
      > GlyphAttributes ga[64];
      > GlyphAttributes *glyphAttributes = ga;
      > glyph_t gl[64];
      > glyph_t *glyphs = gl;
      > unsigned char p[64];
      > unsigned char *position = p;
      > if ( len > 60 ) {
      > reordered = (unsigned short *)malloc((len+4)*sizeof(unsigned
      > short));
      > glyphAttributes = (GlyphAttributes
      > *)malloc((len+4)*sizeof(GlyphAttributes));
      > glyphs = (glyph_t *)malloc((len+4)*sizeof(glyph_t));
      > position = (unsigned char*)malloc((len+4)*sizeof(unsigned char));
      > }
      >
      > unsigned char properties =
      > scriptProperties[script-QFont::Devanagari];
      >
      > if ( invalid ) {
      > *reordered = 0x25cc;
      > memcpy( reordered+1, string.unicode() + from, len*sizeof( QChar ) );
      > len++;
      > } else {
      > memcpy( reordered, string.unicode() + from, len*sizeof( QChar ) );
      > }
      > if (reordered[len-1] == 0x200c) // zero width non joiner
      > len--;
      >
      > int i;
      > int base = 0;
      > int reph = -1;
      >
      > #ifdef INDIC_DEBUG
      > IDEBUG("original:");
      > for (i = 0; i < len; i++) {
      > IDEBUG(" %d: %4x", i, reordered[i]);
      > }
      > #endif
      >
      > if ( len != 1 ) {
      > unsigned short *uc = reordered;
      > bool beginsWithRa = FALSE;
      >
      > // Rule 1: find base consonant
      > //
      > // The shaping engine finds the base consonant of the
      > // syllable, using the following algorithm: starting from the
      > // end of the syllable, move backwards until a consonant is
      > // found that does not have a below-base or post-base form
      > // (post-base forms have to follow below-base forms), or
      > // arrive at the first consonant. The consonant stopped at
      > // will be the base.
      > //
      > // * If the syllable starts with Ra + H (in a script that has
      > // 'Reph'), Ra is excluded from candidates for base
      > // consonants.
      > //
      > // * In Kannada and Telugu, the base consonant cannot be
      > // farther than 3 consonants from the end of the syllable.
      > // #### replace the HasReph property by testing if the feature
      > exists in the font!
      > if (form(*uc) == Consonant || (script == QFont::Bengali && form(*uc)
      > == IndependentVowel)) {
      > beginsWithRa = (properties & HasReph) && ((len > 2) && *uc == ra
      > && *(uc+1) == halant);
      >
      > if (beginsWithRa && script == QFont::Kannada &&
      > form(*(uc+2)) == Control)
      > beginsWithRa = false;
      >
      > base = (beginsWithRa ? 2 : 0);
      > IDEBUG(" length = %d, beginsWithRa = %d, base=%d", len,
      > beginsWithRa, base );
      >
      > int lastConsonant = 0;
      > int matra = -1;
      > int skipped = 0;
      > Position pos = Post;
      > // we remember:
      > // * the last consonant since we need it for rule 2
      > // * the matras position for rule 3 and 4
      >
      > // figure out possible base glyphs
      > memset(position, 0, len);
      > if (script == QFont::Devanagari || script == QFont::Gujarati) {
      > bool vattu = FALSE;
      > for (i = base; i < len; ++i) {
      > position[i] = form(uc[i]);
      > if (position[i] == Consonant) {
      > lastConsonant = i;
      > vattu = (!vattu && uc[i] == ra);
      > if (vattu) {
      > IDEBUG("excluding vattu glyph at %d from base candidates", i);
      > position[i] = Vattu;
      > }
      > } else if (position[i] == Matra) {
      > matra = i;
      > }
      > }
      > } else {
      > for (i = base; i < len; ++i) {
      > position[i] = form(uc[i]);
      > if (position[i] == Consonant)
      > lastConsonant = i;
      > else if (matra < 0 && position[i] == Matra)
      > matra = i;
      > }
      > }
      > for (i = len-1; i > base; i--) {
      > if (position[i] != Consonant)
      > continue;
      >
      > Position charPosition = indic_position(uc[i]);
      > if (pos == Post && charPosition == Post) {
      > pos = Below;
      > } else if ((pos == Post || pos == Below) && charPosition == Below)
      > {
      > if (script != QFont::Kannada && script != QFont::Telugu)
      > pos = None;
      > if (script == QFont::Devanagari || script == QFont::Gujarati)
      > base = i;
      > } else {
      > base = i;
      > break;
      > }
      > if (skipped == 2 && (script == QFont::Kannada || script ==
      > QFont::Telugu)) {
      > base = i;
      > break;
      > }
      > ++skipped;
      > }
      >
      > IDEBUG(" base consonant at %d skipped=%d, lastConsonant=%d",
      > base, skipped, lastConsonant );
      >
      > // Rule 2:
      > //
      > // If the base consonant is not the last one, Uniscribe
      > // moves the halant from the base consonant to the last
      > // one.
      > if ( lastConsonant != base && uc[base+1] == halant ) {
      > IDEBUG(" moving halant from %d to %d!", base+1, lastConsonant);
      > for (i = base+1; i < lastConsonant; i++)
      > uc[i] = uc[i+1];
      > uc[lastConsonant] = halant;
      >
      > }
      >
      > // Rule 3:
      > //
      > // If the syllable starts with Ra + H, Uniscribe moves
      > // this combination so that it follows either:
      >
      > // * the post-base 'matra' (if any) or the base consonant
      > // (in scripts that show similarity to Devanagari, i.e.,
      > // Devanagari, Gujarati, Bengali)
      > // * the base consonant (other scripts)
      > // * the end of the syllable (Kannada)
      >
      > Position matra_position = None;
      > if (matra > 0)
      > matra_position = indic_position( uc[matra] );
      > IDEBUG(" matra at %d with form %d, base=%d", matra,
      > matra_position, base);
      >
      > if (beginsWithRa && base != 0) {
      > int toPos = base+1;
      > if ( toPos < len && uc[toPos] == nukta )
      > toPos++;
      > if ( toPos < len-1 && uc[toPos] == ra && uc[toPos+1] == halant )
      > toPos += 2;
      > if (script == QFont::Devanagari || script == QFont::Gujarati ||
      > script == QFont::Bengali) {
      > if (matra_position == Post || matra_position == Split) {
      > toPos = matra+1;
      > matra -= 2;
      > }
      > } else if (script == QFont::Kannada) {
      > toPos = len;
      > matra -= 2;
      > }
      >
      > IDEBUG("moving leading ra+halant to position %d", toPos);
      > for (i = 2; i < toPos; i++)
      > uc[i-2] = uc[i];
      > uc[toPos-2] = ra;
      > uc[toPos-1] = halant;
      > base -= 2;
      > if (properties & HasReph)
      > reph = toPos-2;
      > }
      >
      > // Rule 4:
      >
      > // Uniscribe splits two- or three-part matras into their
      > // parts. This splitting is a character-to-character
      > // operation).
      > //
      > // Uniscribe describes some moving operations for these
      > // matras here. For shaping however all pre matras need
      > // to be at the begining of the syllable, so we just move
      > // them there now.
      > if (matra_position == Split)
      > splitMatra(uc, matra, len, base);
      > // Handle three-part matras (0xccb in Kannada)
      > matra_position = indic_position(uc[matra]);
      > if (matra_position == Split)
      > splitMatra(uc, matra, len, base);
      > else if (matra_position == Pre) {
      > unsigned short m = uc[matra];
      > while (matra--)
      > uc[matra+1] = uc[matra];
      > uc[0] = m;
      > base++;
      > }
      > }
      >
      > // Rule 5:
      > //
      > // Uniscribe classifies consonants and 'matra' parts as
      > // pre-base, above-base (Reph), below-base or post-base. This
      > // classification exists on the character code level and is
      > // language-dependent, not font-dependent.
      > for (i = 0; i < base; ++i)
      > position[i] = Pre;
      > position[base] = Base;
      > for (i = base+1; i < len; ++i) {
      > position[i] = indic_position(uc[i]);
      > // #### replace by adjusting table
      > if (uc[i] == nukta || uc[i] == halant)
      > position[i] = Inherit;
      > }
      > if (reph > 0) {
      > // recalculate reph, it might have changed.
      > for (i = base+1; i < len; ++i)
      > if (uc[i] == ra)
      > reph = i;
      > position[reph] = Reph;
      > position[reph+1] = Inherit;
      > }
      >
      > // all reordering happens now to the chars after the base
      > int fixed = base+1;
      > if ( fixed < len && uc[fixed] == nukta )
      > fixed++;
      >
      > #ifdef INDIC_DEBUG
      > for (i = fixed; i < len; ++i)
      > IDEBUG("position[%d] = %d, form=%d", i, position[i],
      > form(uc[i]));
      > #endif
      > // we continuosly position the matras and vowel marks and increase
      > the fixed
      > // until we reached the end.
      > const IndicOrdering *finalOrder =
      > indic_order[script-QFont::Devanagari];
      >
      > IDEBUG(" reordering pass:");
      > //IDEBUG(" base=%d fixed=%d", base, fixed );
      > int toMove = 0;
      > while ( finalOrder[toMove].form && fixed < len-1 ) {
      > //IDEBUG(" fixed = %d, moving form %d with pos %d",
      > fixed, finalOrder[toMove].form, finalOrder[toMove].position );
      > for ( i = fixed; i < len; i++ ) {
      > if ( form( uc[i] ) == finalOrder[toMove].form &&
      > position[i] == finalOrder[toMove].position ) {
      > // need to move this glyph
      > int to = fixed;
      > if (i < len-1 && position[i+1] == Inherit) {
      > IDEBUG(" moving two chars from %d to %d", i, to );
      > unsigned short ch = uc[i];
      > unsigned short ch2 = uc[i+1];
      > unsigned char pos = position[i];
      > for ( int j = i+1; j > to+1; j-- ) {
      > uc[j] = uc[j-2];
      > position[j] = uc[j-2];
      > }
      > uc[to] = ch;
      > uc[to+1] = ch2;
      > position[to] = pos;
      > position[to+1] = pos;
      > fixed += 2;
      > } else {
      > IDEBUG(" moving one char from %d to %d", i, to );
      > unsigned short ch = uc[i];
      > unsigned char pos = position[i];
      > for ( int j = i; j > to; j-- ) {
      > uc[j] = uc[j-1];
      > position[j] = position[j-1];
      > }
      > uc[to] = ch;
      > position[to] = pos;
      > fixed++;
      > }
      > }
      > }
      > toMove++;
      > }
      >
      > }
      > IDEBUG("reordered:");
      > for (i = 0; i < len; i++) {
      > glyphAttributes[i].mark = FALSE;
      > glyphAttributes[i].clusterStart = FALSE;
      > glyphAttributes[i].justification = 0;
      > glyphAttributes[i].zeroWidth = FALSE;
      > IDEBUG(" %d: %4x", i, reordered[i]);
      > }
      > if (reph > 0) {
      > // recalculate reph, it might have changed.
      > for (i = base+1; i < len; ++i)
      > if (reordered[i] == ra)
      > reph = i;
      > }
      > IDEBUG(" base=%d, reph=%d", base, reph);
      > glyphAttributes[0].clusterStart = TRUE;
      >
      > // now we have the syllable in the right order, and can start
      > running it through open type.
      >
      > int firstGlyph = si->num_glyphs;
      >
      > bool control = FALSE;
      > for (i = 0; i < len; ++i)
      > control |= (form(reordered[i]) == Control);
      >
      > #ifndef QT_NO_XFTFREETYPE
      > if (openType) {
      > int error = si->fontEngine->stringToCMap((QChar *)reordered, len,
      > glyphs, 0, &len,
      > (si->analysis.bidiLevel %2));
      > assert (!error);
      >
      > // we need to keep track of where the base glyph is for some scripts
      > and abuse the logcluster feature for this.
      > // This also means we have to correct the logCluster output from the
      > open type engine manually afterwards.
      > // for indic this is rather simple, as all chars just point to the
      > first glyph in the syllable.
      > unsigned short lc[64];
      > unsigned short *logClusters = lc;
      > bool w[64];
      > bool *where = w;
      > if (len > 63) {
      > where = (bool *)malloc(len*sizeof(bool));
      > logClusters = (unsigned short *)malloc((len+4)*sizeof(unsigned
      > short));
      > }
      > memset(where, 0, len*sizeof(bool));
      > for (i = 0; i < len; ++i)
      > logClusters[i] = i;
      >
      > openType->init(glyphs, glyphAttributes, len, logClusters, len);
      >
      > // substitutions
      >
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'c', 'c', 'm', 'p' ));
      >
      > where[0] = (from == 0 || !string.unicode()[from-1].isLetter());
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'i', 'n', 'i', 't' ),
      > where);
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'n', 'u', 'k', 't' ));
      >
      > for (i = 0; i <= base; ++i)
      > where[i] = TRUE;
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'a', 'k', 'h', 'n' ),
      > where);
      >
      > memset(where, 0, len*sizeof(bool));
      > if (reph >= 0) {
      > where[reph] = where[reph+1] = TRUE;
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'r', 'p', 'h', 'f' ),
      > where);
      > where[reph] = where[reph+1] = FALSE;
      > }
      >
      > for (i = base+1; i < len; ++i)
      > where[i] = TRUE;
      > if (script == QFont::Devanagari || script == QFont::Gujarati) {
      > // vattu glyphs need this aswell
      > bool vattu = FALSE;
      > for (i = base-2; i > 1; --i) {
      > if (form(reordered[i]) == Consonant) {
      > vattu = (!vattu && reordered[i] == ra);
      > if (vattu) {
      > IDEBUG("forming vattu ligature at %d", i);
      > where[i] = where[i+1] = TRUE;
      > }
      > }
      > }
      > }
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'b', 'l', 'w', 'f' ),
      > where);
      > memset(where, 0, len*sizeof(bool));
      > for (i = 0; i < base; ++i)
      > where[i] = TRUE;
      > if (control) {
      > for (i = 2; i < len; ++i) {
      > if (form(reordered[i]) == Control && reordered[i] == 0x200d) {
      > where[i-1] = TRUE;
      > where[i-2] = TRUE;
      > }
      > }
      > }
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'h', 'a', 'l', 'f' ),
      > where);
      > memset(where, 0, len*sizeof(bool));
      > for (i = base+1; i < len; ++i)
      > where[i] = TRUE;
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'p', 's', 't', 'f' ),
      > where);
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'v', 'a', 't', 'u' ));
      >
      > // Conjunkts and typographical forms
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'p', 'r', 'e', 's' ));
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'b', 'l', 'w', 's' ));
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'a', 'b', 'v', 's' ));
      > if (script == QFont::Tamil)
      > where[base] = true;
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'p', 's', 't', 's' ),
      > where);
      >
      > // halant forms
      > if (reordered[len-1] == halant || script == QFont::Malayalam) {
      > // The hlnt feature needs to get always applied for malayalam
      > according to the MS docs.
      > // memset(where, 0, len*sizeof(bool));
      > // where[len-1] = where[len-2] = TRUE;
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'h', 'a', 'l', 'n' ));
      > }
      >
      > int newLen;
      > const int *char_map = openType->mapping(newLen);
      >
      > // move the left matra back to it's correct position in malayalam
      > and tamil
      > if ((script == QFont::Malayalam || script == QFont::Tamil) &&
      > (form(reordered[0]) == Matra)) {
      > // need to find the base in the shaped string and move the matra
      > there
      > int basePos = 0;
      > while (basePos < newLen && char_map[basePos] <= base)
      > basePos++;
      > --basePos;
      > if (basePos < newLen && basePos > 1) {
      > IDEBUG("moving prebase matra to position %d in syllable newlen=%d",
      > basePos, newLen);
      > unsigned short *g = openType->glyphs();
      > unsigned short m = g[0];
      > --basePos;
      > for (i = 0; i < basePos; ++i)
      > g[i] = g[i+1];
      > g[basePos] = m;
      > }
      > }
      >
      > openType->applyGPOSFeatures();
      >
      > GlyphAttributes *ga = engine->glyphAttributes(si)+si->num_glyphs;
      >
      > for (i = 0; i < newLen; ++i)
      > ga[i] = glyphAttributes[char_map[i]];
      >
      > if (control) {
      > IDEBUG("found a control char in the syllable");
      > int i = 0, j = 0;
      > unsigned short *g = openType->glyphs();
      > while (i < newLen) {
      > if (form(reordered[char_map[i]]) == Control) {
      > ++i;
      > if (i >= newLen)
      > break;
      > }
      > g[j] = g[i];
      > ++i;
      > ++j;
      > }
      > openType->setLength(j);
      > }
      >
      > openType->appendTo(engine, si, FALSE);
      >
      > if (w != where) {
      > free(where);
      > free(logClusters);
      > }
      > } else
      > #endif
      > {
      > Q_UNUSED(openType);
      > // can't do any shaping, copy the stuff to the script item.
      > engine->ensureSpace(len);
      >
      > glyph_t *glyphs = engine->glyphs(si);
      > advance_t *advances = engine->advances(si);
      > GlyphAttributes *ga = engine->glyphAttributes(si);
      >
      > int error = si->fontEngine->stringToCMap((QChar *)reordered, len,
      > glyphs, advances, &len,
      > (si->analysis.bidiLevel %2));
      > assert (!error);
      >
      > memcpy(ga, glyphAttributes, len*sizeof(GlyphAttributes));
      >
      > si->num_glyphs += len;
      > }
      >
      > // fix logcluster array
      > unsigned short *logClusters =
      > engine->logClusters(si)+from-si->position;
      > for (i = 0; i < syllableLength; ++i)
      > logClusters[i] = firstGlyph;
      >
      > if (r != reordered) {
      > free(reordered);
      > free(glyphAttributes);
      > free(glyphs);
      > free(position);
      > }
      > IDEBUG("<<<<<<");
      > }
      >
      >
      > /* syllables are of the form:
      >
      > (Consonant Nukta? Halant)* Consonant Matra? VowelMark? StressMark?
      > (Consonant Nukta? Halant)* Consonant Halant
      > IndependentVowel VowelMark? StressMark?
      >
      > We return syllable boundaries on invalid combinations aswell
      > */
      > static int indic_nextSyllableBoundary( int script, const QString &s,
      > int start, int end, bool *invalid )
      > {
      > *invalid = FALSE;
      > IDEBUG("indic_nextSyllableBoundary: start=%d, end=%d", start, end
      > );
      > const QChar *uc = s.unicode()+start;
      >
      > int pos = 0;
      > Form state = form( uc[pos].unicode() );
      > IDEBUG("state[%d]=%d (uc=%4x)", pos, state, uc[pos].unicode() );
      > pos++;
      >
      > if ( state != Consonant && state != IndependentVowel ) {
      > if ( state != Other && state != Control )
      > *invalid = TRUE;
      > goto finish;
      > }
      >
      > while ( pos < end - start ) {
      > Form newState = form( uc[pos].unicode() );
      > IDEBUG("state[%d]=%d (uc=%4x)", pos, newState, uc[pos].unicode() );
      > switch( newState ) {
      > case Control:
      > if (uc[pos].unicode() == 0x200d) // Zero width joiner
      > newState = state;
      > break;
      > case Consonant:
      > if ( state == Halant )
      > break;
      > goto finish;
      > case Halant:
      > if ( state == Nukta || state == Consonant )
      > break;
      > // Bengali has a special exception allowing the combination
      > Vowel_A/E + Halant + Ya
      > if ( script == QFont::Bengali && pos == 1 &&
      > (uc[0].unicode() == 0x0985 || uc[0].unicode() == 0x098f) )
      > break;
      > goto finish;
      > case Nukta:
      > if ( state == Consonant )
      > break;
      > goto finish;
      > case StressMark:
      > if ( state == VowelMark )
      > break;
      > // fall through
      > case VowelMark:
      > if ( state == Matra || state == IndependentVowel )
      > break;
      > // fall through
      > case Matra:
      > if ( state == Consonant || state == Nukta )
      > break;
      > // ### not sure if this is correct. If it is, does it apply only
      > to Bengali or should
      > // it work for all Indic languages?
      > // the combination Independent_A + Vowel Sign AA is allowed.
      > if ( script == QFont::Bengali && uc[pos].unicode() == 0x9be &&
      > uc[pos-1].unicode() == 0x985 )
      > break;
      > if ( script == QFont::Tamil && state == Matra ) {
      > if ( uc[pos-1].unicode() == 0x0bc6 &&
      > ( uc[pos].unicode() == 0xbbe || uc[pos].unicode() == 0xbd7 ) )
      > break;
      > if ( uc[pos-1].unicode() == 0x0bc7 && uc[pos].unicode() == 0xbbe )
      > break;
      > }
      > goto finish;
      >
      > case LengthMark:
      > case IndependentVowel:
      > case Invalid:
      > case Other:
      > goto finish;
      > }
      > state = newState;
      > pos++;
      > }
      > finish:
      > return pos+start;
      > }
      >
      >
      > static void indic_shape( int script, const QString &string, int from,
      > int len, QTextEngine *engine, QScriptItem *si )
      > {
      > assert( script >= QFont::Devanagari && script <= QFont::Sinhala
      > );
      > si->num_glyphs = 0;
      > int sstart = from;
      > int end = sstart + len;
      > #ifndef QT_NO_XFTFREETYPE
      > QOpenType *openType = si->fontEngine->openType();
      > if (openType && !openType->supportsScript(script))
      > openType = 0;
      > #else
      > QOpenType *openType = 0;
      > #endif
      >
      > while ( sstart < end ) {
      > bool invalid;
      > int send = indic_nextSyllableBoundary( script, string, sstart, end,
      > &invalid );
      > IDEBUG("syllable from %d, length %d, invalid=%s", sstart,
      > send-sstart,
      > invalid ? "true" : "false" );
      > indic_shape_syllable(script, string, sstart, send-sstart, engine,
      > si, openType, invalid);
      > sstart = send;
      > }
      > }
      >
      >
      > static void indic_attributes( int script, const QString &text, int
      > from, int len, QCharAttributes *attributes )
      > {
      > int end = from + len;
      > const QChar *uc = text.unicode() + from;
      > attributes += from;
      > int i = 0;
      > while ( i < len ) {
      > bool invalid;
      > int boundary = indic_nextSyllableBoundary( script, text, from+i,
      > end, &invalid ) - from;
      >
      > attributes[i].whiteSpace = ::isSpace( *uc ) && (uc->unicode() !=
      > 0xa0);
      > attributes[i].softBreak = FALSE;
      > attributes[i].charStop = TRUE;
      > attributes[i].wordStop = FALSE;
      > attributes[i].invalid = invalid;
      >
      > if ( boundary > len-1 ) boundary = len;
      > i++;
      > while ( i < boundary ) {
      > attributes[i].whiteSpace = ::isSpace( *uc ) && (uc->unicode() !=
      > 0xa0);
      > attributes[i].softBreak = FALSE;
      > attributes[i].charStop = FALSE;
      > attributes[i].wordStop = FALSE;
      > attributes[i].invalid = invalid;
      > ++uc;
      > ++i;
      > }
      > assert( i == boundary );
      > }
      >
      >
      > }
      >
      >
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      > //
      > // Thai and Lao
      > //
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      >
      >
      >
      >
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      > //
      > // Tibetan
      > //
      > //
      >
      --------------------------------------------------------------------------------------------------------------------------------------------
      >
      > // tibetan syllables are of the form:
      > // head position consonant
      > // first sub-joined consonant
      > // ....intermediate sub-joined consonants (if any)
      > // last sub-joined consonant
      > // sub-joined vowel (a-chung U+0F71)
      > // standard or compound vowel sign (or 'virama' for devanagari
      > transliteration)
      >
      > enum TibetanForm {
      > TibetanOther,
      > TibetanHeadConsonant,
      > TibetanSubjoinedConsonant,
      > TibetanSubjoinedVowel,
      > TibetanVowel
      > };
      >
      > // this table starts at U+0f40
      > static const unsigned char tibetanForm[0x80] = {
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      >
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      >
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
      > TibetanHeadConsonant,
      > TibetanOther, TibetanOther, TibetanOther, TibetanOther,
      >
      > TibetanOther, TibetanVowel, TibetanVowel, TibetanVowel,
      > TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
      > TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
      > TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
      >
      > TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
      > TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
      > TibetanOther, TibetanOther, TibetanOther, TibetanOther,
      > TibetanOther, TibetanOther, TibetanOther, TibetanOther,
      >
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      >
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      >
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
      > TibetanSubjoinedConsonant, TibetanOther, TibetanOther,
      > TibetanOther
      > };
      >
      >
      > static inline TibetanForm tibetan_form( const QChar &c )
      > {
      > return (TibetanForm)tibetanForm[ c.unicode() - 0x0f40 ];
      > }
      >
      > static void tibetan_shape_syllable( const QString &string, int from,
      > int syllableLength,
      > QTextEngine *engine, QScriptItem *si, QOpenType *openType,
      > bool invalid )
      > {
      > int len = syllableLength;
      >
      > int i;
      > unsigned short r[64];
      > unsigned short *reordered = r;
      > GlyphAttributes ga[64];
      > GlyphAttributes *glyphAttributes = ga;
      > glyph_t gl[64];
      > glyph_t *glyphs = gl;
      > if ( len > 60 ) {
      > reordered = (unsigned short *)malloc((len+4)*sizeof(unsigned
      > short));
      > glyphAttributes = (GlyphAttributes
      > *)malloc((len+4)*sizeof(GlyphAttributes));
      > glyphs = (glyph_t *)malloc((len+4)*sizeof(glyph_t));
      > }
      >
      > const QChar *str = string.unicode() + from;
      > if ( invalid ) {
      > *reordered = 0x25cc;
      > memcpy( reordered+1, str, len*sizeof( QChar ) );
      > len++;
      > str = (QChar *)reordered;
      > }
      >
      > for (i = 0; i < len; i++) {
      > glyphAttributes[i].mark = FALSE;
      > glyphAttributes[i].clusterStart = FALSE;
      > glyphAttributes[i].justification = 0;
      > glyphAttributes[i].zeroWidth = FALSE;
      > IDEBUG(" %d: %4x", i, str[i].unicode());
      > }
      > glyphAttributes[0].clusterStart = TRUE;
      >
      > // now we have the syllable in the right order, and can start
      > running it through open type.
      >
      > int firstGlyph = si->num_glyphs;
      >
      > #ifndef QT_NO_XFTFREETYPE
      > if (openType) {
      > int error = si->fontEngine->stringToCMap(str, len, glyphs, 0, &len,
      > (si->analysis.bidiLevel %2));
      > assert (!error);
      >
      > // we need to keep track of where the base glyph is for some scripts
      > and abuse the logcluster feature for this.
      > // This also means we have to correct the logCluster output from the
      > open type engine manually afterwards.
      > // for indic this is rather simple, as all chars just point to the
      > first glyph in the syllable.
      > unsigned short lc[64];
      > unsigned short *logClusters = lc;
      > if (len > 63)
      > logClusters = (unsigned short *)malloc((len+4)*sizeof(unsigned
      > short));
      > for (i = 0; i < len; ++i)
      > logClusters[i] = i;
      >
      > openType->init(glyphs, glyphAttributes, len, logClusters, len);
      >
      > // substitutions
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'c', 'c', 'm', 'p' ));
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'a', 'b', 'v', 's' ));
      > openType->applyGSUBFeature(FT_MAKE_TAG( 'b', 'l', 'w', 's' ));
      > openType->applyGPOSFeatures();
      >
      > GlyphAttributes *ga = engine->glyphAttributes(si)+si->num_glyphs;
      >
      > int newLen;
      > const int *char_map = openType->mapping(newLen);
      > for (i = 0; i < newLen; ++i)
      > ga[i] = glyphAttributes[char_map[i]];
      >
      > openType->appendTo(engine, si, FALSE);
      >
      > if (lc != logClusters)
      > free(logClusters);
      > } else
      > #endif
      > {
      > Q_UNUSED(openType);
      > // can't do any shaping, copy the stuff to the script item.
      > engine->ensureSpace(len);
      >
      > glyph_t *g<br/><br/>(Message over 64 KB, truncated)
    Your message has been successfully submitted and would be delivered to recipients shortly.