ooo-build r14939 - in trunk: . bin patches/dev300



Author: rengelhard
Date: Fri Dec 26 01:51:35 2008
New Revision: 14939
URL: http://svn.gnome.org/viewvc/ooo-build?rev=14939&view=rev

Log:
2008-12-26  Rene Engelhard  <rene debian org>

        * configure.in, bin/applyflags, bin/unpack,
          patches/dev300/apply. patches/dev300/cws-graphite01-20081226.diff:
          try to resurrect --enable-graphite


Added:
   trunk/patches/dev300/cws-graphite01-20081226.diff
Modified:
   trunk/ChangeLog
   trunk/bin/applyflags
   trunk/bin/unpack
   trunk/configure.in
   trunk/patches/dev300/apply

Modified: trunk/bin/applyflags
==============================================================================
--- trunk/bin/applyflags	(original)
+++ trunk/bin/applyflags	Fri Dec 26 01:51:35 2008
@@ -38,4 +38,6 @@
 if test "z$PIECE" != "z"; then
     echo -n " --pieces --distro=Piece";
 fi ;
-
+if test "$ENABLE_GRAPHITE" = "TRUE"; then
+    echo -n "--distro=Graphite";
+fi

Modified: trunk/bin/unpack
==============================================================================
--- trunk/bin/unpack	(original)
+++ trunk/bin/unpack	Fri Dec 26 01:51:35 2008
@@ -283,6 +283,11 @@
 fi
 fi
 
+if test "$ENABLE_GRAPHITE" = "TRUE"; then
+    mkdir -p $OOBUILDDIR/graphite/download
+    $GNUCP -af $SRCDIR/$GRAPHITE_SRC $OOBUILDDIR/graphite/download
+fi
+
 # Win32 prerequisites ...
 if test "z$BUILD_WIN32" != "z"; then
 

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Fri Dec 26 01:51:35 2008
@@ -1200,7 +1200,7 @@
 if test -n "$enable_graphite" -a "$enable_graphite" != "no"; then
    ENABLE_GRAPHITE=TRUE
    graphite_enabled=yes
-   GRAPHITE_SRC=silgraphite-1.0.0rc2.tar.gz
+   GRAPHITE_SRC=silgraphite-2.3.tar.gz
 else
    ENABLE_GRAPHITE=FALSE
    graphite_enabled=no

Modified: trunk/patches/dev300/apply
==============================================================================
--- trunk/patches/dev300/apply	(original)
+++ trunk/patches/dev300/apply	Fri Dec 26 01:51:35 2008
@@ -32,7 +32,7 @@
 	      UnUsedButNotYetRemovedFromSVN, WebDAVUpstream, \
 	      PostgreSQL, SELinux, VOSremoval, Glib2, \
 	      UnitBootstrap, RadioButtons, UnstableLibwpd, WWInProgress, \
-	      KDE4, MinGW
+	      KDE4, MinGW, Graphite
 DebianLooseSections: DebianBaseNoHelpContent
 # Optional sections
 Optional : DejaVuFonts, NovellOnlyExtensionFixes, Win32OnlyExtensionFixes, Linux32OnlyExtensionFixes
@@ -153,6 +153,9 @@
 
 # -------- [ Tag [ >= <tag> etc. ], ] patch sets --------
 
+[ Graphite ]
+cws-graphite-20081226.diff, i#69129
+
 [ PreprocessPatches ]
 # Collection of patches that must be applied before all the other patches.
 

Added: trunk/patches/dev300/cws-graphite01-20081226.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/cws-graphite01-20081226.diff	Fri Dec 26 01:51:35 2008
@@ -0,0 +1,5529 @@
+Index: vcl/source/gdi/makefile.mk
+===================================================================
+--- vcl/source/gdi/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/gdi/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -45,6 +45,9 @@
+ .IF "$(COM)"=="ICC"
+ CDEFS+=-D_STD_NO_NAMESPACE -D_VOS_NO_NAMESPACE -D_UNO_NO_NAMESPACE
+ .ENDIF
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++CDEFS+=-DENABLE_GRAPHITE
++.ENDIF
+ 
+ # --- Files --------------------------------------------------------
+ 
+Index: vcl/source/gdi/outdev3.cxx
+===================================================================
+--- vcl/source/gdi/outdev3.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/gdi/outdev3.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -67,6 +67,9 @@
+ #ifndef _OSL_FILE_H
+ #include <osl/file.h>
+ #endif
++#ifdef ENABLE_GRAPHITE
++#include <vcl/graphite_features.hxx>
++#endif
+ 
+ #include <vcl/unohelp.hxx>
+ #include <pdfwriter_impl.hxx>
+@@ -2706,10 +2709,10 @@
+     mpFontData( NULL ),
+     mpFontEntry( NULL )
+ {
+-    maTargetName = maName;
+-    
+     rFont.GetFontAttributes( *this );
+ 
++    maTargetName = maName;
++
+     // normalize orientation between 0 and 3600
+     if( 3600 <= (unsigned)mnOrientation )
+     {
+@@ -2752,6 +2755,14 @@
+     // TODO: does it pay off to improve this hash function?
+     static FontNameHash aFontNameHash;
+     size_t nHash = aFontNameHash( rFSD.maSearchName );
++#ifdef ENABLE_GRAPHITE
++    // check for features and generate a unique hash if necessary
++    if (rFSD.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++        != STRING_NOTFOUND)
++    {
++        nHash = aFontNameHash( rFSD.maTargetName );
++    }
++#endif
+     nHash += 11 * rFSD.mnHeight;
+     nHash += 19 * rFSD.meWeight;
+     nHash += 29 * rFSD.meItalic;
+@@ -2803,6 +2814,15 @@
+             return false;
+     }
+ 
++#ifdef ENABLE_GRAPHITE
++    // check for features
++    if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++         != STRING_NOTFOUND ||
++         rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++         != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
++        return false;
++#endif
++
+     return true;
+ }
+ 
+@@ -2840,7 +2860,12 @@
+         // if it is already known get its normalized search name
+         FontNameList::const_iterator it_name = maFontNameList.find( aSearchName );
+         if( it_name != maFontNameList.end() )
+-            if( !(*it_name).second.EqualsAscii( "hg", 0, 2) )
++            if( !(*it_name).second.EqualsAscii( "hg", 0, 2)
++#ifdef ENABLE_GRAPHITE
++                && (aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++                    == STRING_NOTFOUND)
++#endif
++            )
+                 aSearchName = (*it_name).second;
+     }
+ 
+@@ -2945,6 +2970,22 @@
+     {
+         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
+         aSearchName = rFSD.maTargetName;
++
++#ifdef ENABLE_GRAPHITE
++        // Until features are properly supported, they are appended to the
++        // font name, so we need to strip them off so the font is found.
++        xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
++        String aOrigName = rFSD.maTargetName;
++        String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
++        if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
++            aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
++        {
++            aSearchName = aBaseFontName;
++            rFSD.maTargetName = aBaseFontName;
++        }
++
++#endif
++
+         ImplGetEnglishSearchFontName( aSearchName );
+         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
+         // #114999# special emboldening for Ricoh fonts
+@@ -2981,7 +3022,11 @@
+         if( mpPreMatchHook )
+             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
+                 ImplGetEnglishSearchFontName( aSearchName );
+-
++#ifdef ENABLE_GRAPHITE
++        // the prematch hook uses the target name to search, but we now need
++        // to restore the features to make the font selection data unique
++        rFSD.maTargetName = aOrigName;
++#endif
+         // check if the current font name token or its substitute is valid
+ 	ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
+         if( pFoundData )
+@@ -5342,6 +5387,7 @@
+     DBG_CHKOBJ( &rNewFont, Font, NULL );
+ 
+     Font aFont( rNewFont );
++    aFont.SetLanguage(rNewFont.GetLanguage());
+     if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
+                        DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
+                        DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
+Index: vcl/source/gdi/sallayout.cxx
+===================================================================
+--- vcl/source/gdi/sallayout.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/gdi/sallayout.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -1107,6 +1107,8 @@
+     for( int nCharPos = i = -1; rArgs.GetNextPos( &nCharPos, &bRTL ); )
+     {
+         n = nCharPos - rArgs.mnMinCharPos;
++        if( (n < 0) || (nCharCount <= n) )  continue;
++
+         if( pLogCluster[ n ] >= 0 )
+             i = pLogCluster[ n ];
+         if( i >= 0 )
+@@ -1695,6 +1697,19 @@
+         }
+     }
+ 
++    // Compute rtl flags, since in some scripts glyphs/char order can be
++    // reversed for a few character sequencies e.g. Myanmar
++    std::vector<bool> vRtl(rArgs.mnEndCharPos - rArgs.mnMinCharPos, false);
++    rArgs.ResetPos();
++    bool bRtl;
++    int nRunStart, nRunEnd;
++    while (rArgs.GetNextRun(&nRunStart, &nRunEnd, &bRtl))
++    {
++        if (bRtl) std::fill(vRtl.begin() + nRunStart - rArgs.mnMinCharPos,
++                            vRtl.begin() + nRunEnd - rArgs.mnMinCharPos, true);
++    }
++    rArgs.ResetPos();
++
+     // prepare "merge sort"
+     int nStartOld[ MAX_FALLBACK ];
+     int nStartNew[ MAX_FALLBACK ];
+@@ -1728,6 +1743,10 @@
+         nStartNew[ nLevel ] = nStartOld[ nLevel ] = 0;
+         nValid[ nLevel ] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
+             nStartNew[ nLevel ], &nGlyphAdv[ nLevel ], &nCharPos[ nLevel ] );
++#ifdef MULTI_SL_DEBUG
++        if (nValid[nLevel]) printf("layout[%d]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", n, nStartOld[n], nStartNew[n], aPos.X(), nGlyphAdv[n], nCharPos[n],
++            rArgs.mpStr[nCharPos[n]]);
++#endif
+         if( (n > 0) && !nValid[ nLevel ] )
+         {
+             // an empty fallback layout can be released
+@@ -1753,6 +1772,9 @@
+     for( n = 0; n < nLevel; ++n )
+         maFallbackRuns[n].ResetPos();
+     int nActiveCharPos = nCharPos[0];
++    int nLastRunEndChar = (vRtl[nActiveCharPos - mnMinCharPos])?
++        rArgs.mnEndCharPos : rArgs.mnMinCharPos - 1;
++    int nRunVisibleEndChar = nCharPos[0];
+     while( nValid[0] && (nLevel > 0))
+     {
+         // find best fallback level
+@@ -1788,6 +1810,9 @@
+                 nStartOld[0] = nStartNew[0];
+                 nValid[0] = mpLayouts[0]->GetNextGlyphs( 1, &nDummy, aPos,
+                     nStartNew[0], &nGlyphAdv[0], &nCharPos[0] );
++#ifdef MULTI_SL_DEBUG
++                if (nValid[0]) printf("layout[0]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", nStartOld[0], nStartNew[0], aPos.X(), nGlyphAdv[0], nCharPos[0], rArgs.mpStr[nCharPos[0]]);
++#endif
+                 if( !nValid[0] )
+                    break;
+             }
+@@ -1805,7 +1830,9 @@
+             int nOrigCharPos = nCharPos[n];
+             nValid[n] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
+                 nStartNew[n], &nGlyphAdv[n], &nCharPos[n] );
+-
++#ifdef MULTI_SL_DEBUG
++            if (nValid[n]) printf("layout[%d]->GetNextGlyphs %d,%d a%d c%d %x\n", n, nStartOld[n], nStartNew[n], nGlyphAdv[n], nCharPos[n], rArgs.mpStr[nCharPos[n]]);
++#endif
+             // break after last glyph of active layout
+             if( !nValid[n] )
+             {
+@@ -1851,6 +1878,27 @@
+                     { maFallbackRuns[0].NextRun(); break; }
+                 bKeepNotDef = bNeedFallback;
+             }
++            // check for reordered glyphs
++            if (aMultiArgs.mpDXArray &&
++                nRunVisibleEndChar < mnEndCharPos &&
++                nRunVisibleEndChar >= mnMinCharPos &&
++                nCharPos[n] < mnEndCharPos &&
++                nCharPos[n] >= mnMinCharPos)
++            {
++                if (vRtl[nActiveCharPos - mnMinCharPos])
++                {
++                    if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
++                        >= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
++                    {
++                        nRunVisibleEndChar = nCharPos[n];
++                    }
++                }
++                else if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
++                         <= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
++                {
++                    nRunVisibleEndChar = nCharPos[n];
++                }
++            }
+         }
+ 
+         // if a justification array is available
+@@ -1860,16 +1908,40 @@
+             // the run advance is the width from the first char
+             // in the run to the first char in the next run
+             nRunAdvance = 0;
+-            const bool bLTR = (nActiveCharPos < nCharPos[0]);
++#ifdef MULTI_SL_DEBUG
++            const bool bLTR = !(vRtl[nActiveCharPos - mnMinCharPos]);//(nActiveCharPos < nCharPos[0]);
++            int nOldRunAdv = 0;
+             int nDXIndex = nCharPos[0] - mnMinCharPos - bLTR;
+             if( nDXIndex >= 0 )
+-                nRunAdvance += aMultiArgs.mpDXArray[ nDXIndex ];
++                nOldRunAdv += aMultiArgs.mpDXArray[ nDXIndex ];
+             nDXIndex = nActiveCharPos - mnMinCharPos - bLTR;
+             if( nDXIndex >= 0 )
+-                nRunAdvance -= aMultiArgs.mpDXArray[ nDXIndex ];
++                nOldRunAdv -= aMultiArgs.mpDXArray[ nDXIndex ];
+             if( !bLTR )
+-                nRunAdvance = -nRunAdvance;
+-
++                nOldRunAdv = -nOldRunAdv;
++#endif
++            if (vRtl[nActiveCharPos - mnMinCharPos])
++            {
++              if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <= mnEndCharPos)
++                  nRunAdvance -= aMultiArgs.mpDXArray[nRunVisibleEndChar - 1 - mnMinCharPos];
++              if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <= mnEndCharPos)
++                  nRunAdvance += aMultiArgs.mpDXArray[nLastRunEndChar - 1 - mnMinCharPos];
++#ifdef MULTI_SL_DEBUG
++              printf("rtl visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar-1, nRunVisibleEndChar-1, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
++#endif
++            }
++            else
++            {
++                if (nRunVisibleEndChar >= mnMinCharPos)
++                  nRunAdvance += aMultiArgs.mpDXArray[nRunVisibleEndChar - mnMinCharPos];
++                if (nLastRunEndChar >= mnMinCharPos)
++                  nRunAdvance -= aMultiArgs.mpDXArray[nLastRunEndChar - mnMinCharPos];
++#ifdef MULTI_SL_DEBUG
++                printf("visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar, nRunVisibleEndChar, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
++#endif
++            }
++            nLastRunEndChar = nRunVisibleEndChar;
++            nRunVisibleEndChar = nCharPos[0];
+             // the requested width is still in pixel units
+             // => convert it to base level font units
+             nRunAdvance *= mnUnitsPerPixel;
+@@ -1887,9 +1959,27 @@
+ 
+         // prepare for next fallback run
+         nActiveCharPos = nCharPos[0];
++        // it essential that the runs don't get ahead of themselves and in the
++        // if( bKeepNotDef && !bNeedFallback ) statement above, the next run may
++        // have already been reached on the base level
+         for( int i = nFBLevel; --i >= 0;)
+-            if( !maFallbackRuns[i].PosIsInRun( nActiveCharPos ) )
+-                maFallbackRuns[i].NextRun();
++        {
++            if (maFallbackRuns[i].GetRun(&nRunStart, &nRunEnd, &bRtl))
++            {
++                if (bRtl)
++                {
++                    if (nRunStart > nActiveCharPos)
++                        maFallbackRuns[i].NextRun();
++                }
++                else
++                {
++                    if (nRunEnd <= nActiveCharPos)
++                        maFallbackRuns[i].NextRun();
++                }
++            }
++        }
++//            if( !maFallbackRuns[i].PosIsInRun( nActiveCharPos ) )
++//                maFallbackRuns[i].NextRun();
+     }
+ 
+     mpLayouts[0]->Simplify( true );
+Index: vcl/source/glyphs/graphite_textsrc.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_textsrc.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_textsrc.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,155 @@
++//
++// C++ Implementation: Graphite to SAL adaptor classes
++//
++// Description: Implements the Graphite interfaces IGrTextSource and
++//              IGrGraphics which provide Graphite with access to the
++//              app's text storage system and the platform's font and
++//              graphics systems.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003-2004 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Header files
++//
++// Standard Library
++#include <string>
++#include <cassert>
++#include "graphite_textsrc.hxx"
++#include <vcl/graphite_features.hxx>
++
++// class TextSourceAdaptor implementation.
++//
++TextSourceAdaptor::~TextSourceAdaptor()
++{
++    delete mpFeatures;
++}
++
++gr::UtfType TextSourceAdaptor::utfEncodingForm() {
++    return gr::kutf16;
++}
++
++
++size_t TextSourceAdaptor::getLength()
++{
++    return maLayoutArgs.mnLength;
++}
++
++
++size_t  TextSourceAdaptor::fetch(gr::toffset, size_t, gr::utf32 *)
++{
++    assert(false);
++    return 0;
++}
++
++
++size_t  TextSourceAdaptor::fetch(gr::toffset offset, size_t char_count, gr::utf16 * char_buffer)
++{
++  assert(char_buf);
++
++  size_t copy_count =  std::min(size_t(maLayoutArgs.mnLength), char_count);
++  std::copy(maLayoutArgs.mpStr + offset, maLayoutArgs.mpStr + offset + copy_count, char_buffer);
++
++  return copy_count;
++}
++
++
++size_t TextSourceAdaptor::fetch(gr::toffset, size_t, gr::utf8  *)
++{
++    assert(false);
++    return 0;
++}
++
++
++inline void TextSourceAdaptor::getCharProperties(const int nCharIdx, int & min, int & lim, size_t & depth)
++{
++    maLayoutArgs.ResetPos();
++    bool rtl = maLayoutArgs.mnFlags & SAL_LAYOUT_BIDI_RTL;
++    for(depth = ((rtl)? 1:0); maLayoutArgs.maRuns.GetRun(&min, &lim, &rtl); maLayoutArgs.maRuns.NextRun())
++    {
++        if (min > nCharIdx)
++            break;
++        // Only increase the depth when a change of direction occurs.
++        depth += int(rtl ^ bool(depth & 0x1));
++        if (min <= nCharIdx && nCharIdx < lim)
++            break;
++    }
++    // If there is no run for this position increment the depth, but don't
++    // change if this is out of bounds context
++    if (lim > 0 && nCharIdx >= lim && nCharIdx < maLayoutArgs.mnEndCharPos)
++        depth++;
++}
++
++
++bool TextSourceAdaptor::getRightToLeft(gr::toffset nCharIdx)
++{
++    size_t depth;
++    int min, lim = 0;
++    getCharProperties(nCharIdx, min, lim, depth);
++    //printf("getRtl %d,%x=%d\n", nCharIdx, maLayoutArgs.mpStr[nCharIdx], depth & 0x1);
++    return depth & 0x1;
++}
++
++
++unsigned int TextSourceAdaptor::getDirectionDepth(gr::toffset nCharIdx)
++{
++    size_t depth;
++    int min, lim;
++    getCharProperties(nCharIdx, min, lim, depth);
++    //printf("getDirectionDepth %d,%x=%d\n", nCharIdx, maLayoutArgs.mpStr[nCharIdx], depth);
++    return depth;
++}
++
++
++float TextSourceAdaptor::getVerticalOffset(gr::toffset)
++{
++    return 0.0f;    //TODO: Implement correctly
++}
++
++gr::isocode TextSourceAdaptor::getLanguage(gr::toffset)
++{
++    if (mpFeatures && mpFeatures->hasLanguage())
++        return mpFeatures->getLanguage();
++    gr::isocode unknown = {{0,0,0,0}};
++    return unknown;
++}
++
++std::pair<gr::toffset, gr::toffset> TextSourceAdaptor::propertyRange(gr::toffset nCharIdx)
++{
++
++    if (nCharIdx < unsigned(maLayoutArgs.mnMinCharPos))
++        return std::make_pair(0, maLayoutArgs.mnMinCharPos);
++
++    if (nCharIdx < mnEnd)
++        return std::make_pair(maLayoutArgs.mnMinCharPos, mnEnd);
++
++    return std::make_pair(mnEnd, maLayoutArgs.mnLength);
++}
++
++size_t TextSourceAdaptor::getFontFeatures(gr::toffset, gr::FeatureSetting * settings)
++{
++    if (mpFeatures) return mpFeatures->getFontFeatures(settings);
++    return 0;
++}
++
++
++bool TextSourceAdaptor::sameSegment(gr::toffset char_idx1, gr::toffset char_idx2)
++{
++    const std::pair<gr::toffset, gr::toffset>
++    range1 = propertyRange(char_idx1),
++    range2 = propertyRange(char_idx2);
++
++    return range1 == range2;
++}
++
++void TextSourceAdaptor::setFeatures(const grutils::GrFeatureParser * pFeatures)
++{
++    mpFeatures = new grutils::GrFeatureParser(*pFeatures);
++}
+Index: vcl/source/glyphs/graphite_adaptors.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_adaptors.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_adaptors.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,293 @@
++//
++// C++ Implementation: Graphite to SAL adaptor classes
++//
++// Description: Implements the Graphite interfaces IGrTextSource and
++//              IGrGraphics which provide Graphite with access to the
++//              app's text storage system and the platform's font and
++//              graphics systems.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003-2004 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Header files
++//
++// Standard Library
++#include <string>
++#include <cassert>
++// Libraries
++#include <rtl/string.hxx>
++#include <rtl/ustring.hxx>
++#include <i18npool/mslangid.hxx>
++// Platform
++#ifndef MSC
++#include <saldisp.hxx>
++
++#include <vcl/salgdi.hxx>
++
++#include <freetype/ftsynth.h>
++
++// Module
++#include "gcach_ftyp.hxx"
++
++#include <vcl/graphite_features.hxx>
++#include <vcl/graphite_adaptors.hxx>
++
++// Module private type definitions and forward declarations.
++//
++using gr::GrResult;
++namespace
++{
++    inline float from_hinted(const int x) {
++        return static_cast<float>(x + 32) / 64.0;
++    }
++    typedef std::hash_map<long,bool> SilfMap;
++    SilfMap sSilfMap;
++}
++
++// class CharacterRenderProperties implentation.
++//
++FontProperties::FontProperties(const FreetypeServerFont &font) throw()
++{
++    clrFore = gr::kclrBlack;
++    clrBack = gr::kclrTransparent;
++
++    pixHeight = from_hinted(font.GetMetricsFT().height);
++
++    switch (font.GetFontSelData().meWeight)
++    {
++        case WEIGHT_SEMIBOLD: case WEIGHT_BOLD:
++        case WEIGHT_ULTRABOLD: case WEIGHT_BLACK:
++            fBold = true;
++            break;
++        default :
++            fBold = false;
++    }
++
++    switch (font.GetFontSelData().meItalic)
++    {
++        case ITALIC_NORMAL: case ITALIC_OBLIQUE:
++            fItalic = true;
++            break;
++        default :
++            fItalic = false;
++    }
++
++    // Get the font name.
++    const sal_Unicode    * name = font.GetFontSelData().maName.GetBuffer();
++    const size_t          name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1,
++                    size_t(font.GetFontSelData().maName.Len()));
++
++    std::copy(name, name + name_sz, szFaceName);
++    szFaceName[name_sz] = '\0';
++}
++
++// class GraphiteFontAdaptor implementaion.
++//
++GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpiX, const sal_Int32 dpiY)
++  :    mrFont(static_cast<FreetypeServerFont &>(sfont)),
++    maFontProperties(static_cast<FreetypeServerFont &>(sfont)),
++    mnDpiX(dpiX),
++    mnDpiY(dpiY),
++    mfAscent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().ascender)),
++    mfDescent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().descender)),
++    mfEmUnits(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().y_ppem),
++    mpFeatures(NULL)
++{
++    //std::wstring face_name(maFontProperties.szFaceName);
++    const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage );
++#ifdef DEBUG
++    printf("GraphiteFontAdaptor %lx\n", (long)this);
++#endif
++    rtl::OString name = rtl::OUStringToOString(
++        sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 );
++    sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
++    if (nFeat > 0)
++    {
++        rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
++        mpFeatures = new grutils::GrFeatureParser(*this, aFeat.getStr(), aLang.getStr());
++#ifdef DEBUG
++        printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n",
++            rtl::OUStringToOString( sfont.GetFontSelData().maName,
++            RTL_TEXTENCODING_UTF8 ).getStr(),
++            rtl::OUStringToOString( sfont.GetFontSelData().maTargetName,
++            RTL_TEXTENCODING_UTF8 ).getStr(),
++            rtl::OUStringToOString( sfont.GetFontSelData().maSearchName,
++            RTL_TEXTENCODING_UTF8 ).getStr(),
++            sfont.GetFontSelData().meLanguage,
++            (int)mpFeatures->getFontFeatures(NULL), mpFeatures->parseErrors());
++#endif
++    }
++    else
++    {
++        mpFeatures = new grutils::GrFeatureParser(*this, aLang.getStr());
++    }
++}
++
++GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor &rhs) throw()
++ :    Font(rhs),
++     mrFont (rhs.mrFont), maFontProperties(rhs.maFontProperties),
++    mnDpiX(rhs.mnDpiX), mnDpiY(rhs.mnDpiY),
++    mfAscent(rhs.mfAscent), mfDescent(rhs.mfDescent), mfEmUnits(rhs.mfEmUnits),
++    mpFeatures(NULL)
++{
++    if (rhs.mpFeatures) mpFeatures = new grutils::GrFeatureParser(*(rhs.mpFeatures));
++}
++
++
++GraphiteFontAdaptor::~GraphiteFontAdaptor() throw()
++{
++    maGlyphMetricMap.clear();
++    if (mpFeatures) delete mpFeatures;
++    mpFeatures = NULL;
++}
++
++void GraphiteFontAdaptor::UniqueCacheInfo(std::wstring & face_name_out, bool & bold_out, bool & italic_out)
++{
++    face_name_out = maFontProperties.szFaceName;
++    bold_out = maFontProperties.fBold;
++    italic_out = maFontProperties.fItalic;
++}
++
++bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont & font) throw()
++{
++    // NOTE: this assumes that the same FTFace pointer won't be reused,
++    // so FtFontInfo::ReleaseFaceFT must only be called at shutdown.
++    FreetypeServerFont & aFtFont = static_cast<FreetypeServerFont &>(font);
++    SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFtFont.GetFtFace()));
++    if (i != sSilfMap.end()) return (*i).second;
++    bool bHasSilf = aFtFont.GetTable("Silf", 0);
++    sSilfMap[reinterpret_cast<long>(aFtFont.GetFtFace())] = bHasSilf;
++    return bHasSilf;
++}
++
++
++gr::Font * GraphiteFontAdaptor::copyThis() {
++    return new GraphiteFontAdaptor(*this);
++}
++
++
++unsigned int GraphiteFontAdaptor::getDPIx() {
++    return mnDpiX;
++}
++
++
++unsigned int GraphiteFontAdaptor::getDPIy() {
++    return mnDpiY;
++}
++
++
++float GraphiteFontAdaptor::ascent() {
++    return mfAscent;
++}
++
++
++float GraphiteFontAdaptor::descent() {
++    return mfDescent;
++}
++
++
++bool GraphiteFontAdaptor::bold() {
++    return maFontProperties.fBold;
++}
++
++
++bool GraphiteFontAdaptor::italic() {
++    return maFontProperties.fItalic;
++}
++
++
++float GraphiteFontAdaptor::height() {
++    return maFontProperties.pixHeight;
++}
++
++
++void GraphiteFontAdaptor::getFontMetrics(float * ascent_out, float * descent_out, float * em_square_out) {
++    if (ascent_out)        *ascent_out    = mfAscent;
++    if (descent_out)    *descent_out   = mfDescent;
++    if (em_square_out)    *em_square_out = mfEmUnits;
++}
++
++
++const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * buffer_sz)
++{
++    char tag_name[5] = {char(table_id >> 24), char(table_id >> 16), char(table_id >> 8), char(table_id), 0};
++    ULONG temp = *buffer_sz;
++
++    const void * const tbl_buf = static_cast<FreetypeServerFont &>(mrFont).GetTable(tag_name, &temp);
++    *buffer_sz = temp;
++
++    return tbl_buf;
++}
++
++#define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
++
++// Return the glyph's metrics in pixels.
++void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances)
++{
++    // Graphite gets really confused if the glyphs have been transformed, so
++    // if orientation has been set we can't use the font's glyph cache
++    // unfortunately the font selection data, doesn't always have the orientation
++    // set, even if it was when the glyphs were cached, so we use our own cache.
++
++//         const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId);
++//
++//         aBounding.right  = aBounding.left = metric.GetOffset().X();
++//         aBounding.bottom = aBounding.top  = -metric.GetOffset().Y();
++//         aBounding.right  += metric.GetSize().Width();
++//         aBounding.bottom -= metric.GetSize().Height();
++//
++//         advances.x = metric.GetDelta().X();
++//         advances.y = -metric.GetDelta().Y();
++
++    GlyphMetricMap::const_iterator gm_itr = maGlyphMetricMap.find(nGlyphId);
++    if (gm_itr != maGlyphMetricMap.end())
++    {
++        // We've cached the results from last time.
++        aBounding = gm_itr->second.first;
++        advances    = gm_itr->second.second;
++    }
++    else
++    {
++        // We need to look up the glyph.
++        FT_Int nLoadFlags = mrFont.GetLoadFlags();
++
++        FT_Face aFace = reinterpret_cast<FT_Face>(mrFont.GetFtFace());
++        FT_Error aStatus = -1;
++        aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags);
++        if( aStatus != FT_Err_Ok )
++        {
++            aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
++            advances.x = advances.y = 0;
++            return;
++        }
++        // check whether we need synthetic bold/italic otherwise metric is wrong
++        if (mrFont.NeedsArtificialBold())
++            FT_GlyphSlot_Embolden(aFace->glyph);
++
++        if (mrFont.NeedsArtificialItalic())
++            FT_GlyphSlot_Oblique(aFace->glyph);
++
++        const FT_Glyph_Metrics &gm = aFace->glyph->metrics;
++
++        // Fill out the bounding box an advances.
++        aBounding.top = aBounding.bottom = fix26_6(gm.horiBearingY);
++        aBounding.bottom -= fix26_6(gm.height);
++        aBounding.left = aBounding.right = fix26_6(gm.horiBearingX);
++        aBounding.right += fix26_6(gm.width);
++        advances.x = fix26_6(gm.horiAdvance);
++        advances.y = 0;
++
++        // Now add an entry to our metrics map.
++        maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances);
++    }
++}
++
++#endif
+Index: vcl/source/glyphs/graphite_layout.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_layout.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_layout.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,1229 @@
++//
++// C++ Implementation: GraphiteLayout
++//
++// Description: An implementation of the SalLayout interface that uses the
++//              Graphite engine.
++//
++// Author: Tim Eves <tim_eves sil org>
++//         Keith Stribley <devel thanlwinsoft org>
++//
++// Copyright: Copyright (C) 2003,2008 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Enable lots of debug info
++#ifdef DEBUG
++#define GRLAYOUT_DEBUG 1
++//#undef NDEBUG
++#endif
++
++// Header files
++//
++// Standard Library
++#include <algorithm>
++#include <cassert>
++#include <functional>
++#include <limits>
++#include <numeric>
++#include <deque>
++// Platform
++#ifdef MSC
++#include <tools/svwin.h>
++#include <svsys.h>
++#endif
++
++#include <vcl/salgdi.hxx>
++
++#include <unicode/uchar.h>
++#include <unicode/ubidi.h>
++
++// Graphite Libraries (must be after vcl headers on windows)
++#include <graphite/GrClient.h>
++#include <graphite/Font.h>
++#include <graphite/ITextSource.h>
++#include <graphite/Segment.h>
++#include <graphite/SegmentPainter.h>
++
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_features.hxx>
++#include "graphite_textsrc.hxx"
++
++
++// Module private type definitions and forward declarations.
++//
++// Module private names.
++//
++
++#ifdef GRLAYOUT_DEBUG
++FILE * grLogFile = NULL;
++FILE * grLog()
++{
++#ifdef MSC
++  if (grLogFile == NULL) grLogFile = fopen("graphitelayout.log","w");
++  else fflush(grLogFile);
++  return grLogFile;
++#else
++  return stdout;
++#endif
++}
++#endif
++
++#ifdef GRCACHE
++#include <vcl/graphite_cache.hxx>
++#endif
++
++
++namespace
++{
++    typedef std::pair<gr::GlyphIterator, gr::GlyphIterator>       glyph_range_t;
++    typedef std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t;
++
++    inline long round(const float n) {
++        return long(n + (n < 0 ? -0.5 : 0.5));
++    }
++
++
++    template<typename T>
++    inline bool in_range(const T i, const T b, const T e) {
++        return !(b > i) && i < e;
++    }
++
++
++    template<typename T>
++    inline bool is_subrange(const T sb, const T se, const T b, const T e) {
++        return !(b > sb || se > e);
++    }
++
++
++    template<typename T>
++    inline bool is_subrange(const std::pair<T, T> &s, const T b, const T e) {
++        return is_subrange(s.first, s.second, b, e);
++    }
++
++    int findSameDirLimit(const xub_Unicode* buffer, int charCount, bool rtl)
++    {
++        UErrorCode status = U_ZERO_ERROR;
++        UBiDi *ubidi = ubidi_openSized(charCount, 0, &status);
++        int limit = 0;
++        ubidi_setPara(ubidi, buffer, charCount,
++            (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status);
++        UBiDiLevel level = 0;
++        ubidi_getLogicalRun(ubidi, 0, &limit, &level);
++        ubidi_close(ubidi);
++        if ((rtl && !(level & 1)) || (!rtl && (level & 1)))
++        {
++            limit = 0;
++        }
++        return limit;
++    }
++
++} // namespace
++
++
++
++// Impementation of the GraphiteLayout::Glyphs container class.
++//    This is an extended vector class with methods added to enable
++//        o Correctly filling with glyphs.
++//        o Querying clustering relationships.
++//        o manipulations that affect neighouring glyphs.
++
++const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10;
++#ifdef GRCACHE
++GraphiteCacheHandler GraphiteCacheHandler::instance;
++#endif
++
++// The Graphite glyph stream is really a sequence of glyph attachment trees
++//  each rooted at a non-attached base glyph.  fill_from walks the glyph stream
++//  find each non-attached base glyph and calls append to record them as a
++//  sequence of clusters.
++void
++GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs,
++    bool bRtl, long &rWidth, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs)
++{
++    // Create a glyph item for each of the glyph and append it to the base class glyph list.
++    typedef std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet;
++    int nChar = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
++    glyph_range_t iGlyphs = rSegment.glyphs();
++    int nGlyphs = iGlyphs.second - iGlyphs.first;
++    gr::GlyphIterator prevBase = iGlyphs.second;
++    float fMinX = rSegment.advanceWidth();
++    float fMaxX = 0.0f;
++    rGlyph2Char.assign(nGlyphs, -1);
++    long nDxOffset = 0;
++    int nGlyphIndex = (bRtl)? (nGlyphs - 1) : 0;
++    // OOo always expects the glyphs in ltr order
++    int nDelta = (bRtl)? -1 : 1;
++
++    int nLastGlyph = (bRtl)? nGlyphs - 1: 0;
++    int nNextChar = (bRtl)? (rSegment.stopCharacter() - 1) : rSegment.startCharacter();//rArgs.mnMinCharPos;
++    // current glyph number (Graphite glyphs)
++    //int currGlyph = 0;
++    int nFirstCharInCluster = nNextChar;
++    int nFirstGlyphInCluster = nLastGlyph;
++
++    // ltr first char in cluster is lowest, same is true for rtl
++    // ltr first glyph in cluster is lowest, rtl first glyph is highest
++
++    // loop over the glyphs determining which characters are linked to them
++    gr::GlyphIterator gi;
++    for (gi = iGlyphs.first + nGlyphIndex;
++         nGlyphIndex >= 0 && nGlyphIndex < nGlyphs;
++         nGlyphIndex+= nDelta, gi = iGlyphs.first + nGlyphIndex)
++    {
++        gr::GlyphInfo info = (*gi);
++#ifdef GRLAYOUT_DEBUG
++        fprintf(grLog(),"Glyph %d %f,%f\n", (int)info.logicalIndex(), info.origin(), info.yOffset());
++#endif
++        // the last character associated with this glyph is after
++        // our current cluster buffer position
++        if ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
++            (!bRtl && ((signed)info.lastChar() >= nNextChar)))
++        {
++            if ((bRtl && nGlyphIndex < nLastGlyph) ||
++                (!bRtl && nGlyphIndex > nLastGlyph))
++            {
++                // this glyph is after the previous one left->right
++                // if insertion is allowed before it then we are in a
++                // new cluster
++                int nAttachedBase = (*(info.attachedClusterBase())).logicalIndex();
++                if (!info.isAttached() ||
++                    !in_range(nAttachedBase, nFirstGlyphInCluster, nGlyphIndex))
++                {
++                    if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
++                        nFirstGlyphInCluster != nGlyphIndex)
++                    {
++                        std::pair <float,float> aBounds =
++                            appendCluster(rSegment, rArgs, bRtl, nFirstCharInCluster,
++                            nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling,
++                            rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
++                        fMinX = std::min(aBounds.first, fMinX);
++                        fMaxX = std::max(aBounds.second, fMaxX);
++                    }
++                    nFirstCharInCluster = (bRtl)? info.lastChar() : info.firstChar();
++                    nFirstGlyphInCluster = nGlyphIndex;
++                }
++                nLastGlyph = (bRtl)? std::min(nGlyphIndex, nAttachedBase) :
++                    std::max(nGlyphIndex, nAttachedBase);
++            }
++            // loop over chacters associated with this glyph and characters
++            // between nextChar and the last character associated with this glyph
++            // giving them the current cluster id.  This allows for character /glyph
++            // order reversal.
++            // For each character we do a reverse glyph id look up
++            // and store the glyph id with the highest logical index in nLastGlyph
++            while ((bRtl && ((signed)info.firstChar() <= nNextChar)) ||
++                   (!bRtl && (signed)info.lastChar() >= nNextChar))
++            {
++                GrGlyphSet charGlyphs = rSegment.charToGlyphs(nNextChar);
++                nNextChar += nDelta;
++                gr::GlyphSetIterator gj = charGlyphs.first;
++                while (gj != charGlyphs.second)
++                {
++                    nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*gj).logicalIndex()) : max(nLastGlyph, (signed)(*gj).logicalIndex());
++                    ++gj;
++                }
++            }
++            // if this is a rtl attached glyph, then we need to include its
++            // base in the cluster, which will have a lower graphite index
++            if (bRtl)
++            {
++                if ((signed)info.attachedClusterBase()->logicalIndex() < nLastGlyph)
++                {
++                    nLastGlyph = info.attachedClusterBase()->logicalIndex();
++                }
++            }
++        }
++
++        // it is possible for the lastChar to be after nextChar and
++        // firstChar to be before the nFirstCharInCluster in rare
++        // circumstances e.g. Myanmar word for cemetery
++        if ((bRtl && ((signed)info.lastChar() > nFirstCharInCluster)) ||
++            (!bRtl && ((signed)info.firstChar() < nFirstCharInCluster)))
++        {
++            nFirstCharInCluster = info.firstChar();
++        }
++    }
++    // process last cluster
++    if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) &&
++        nFirstGlyphInCluster != nGlyphIndex)
++    {
++        std::pair <float,float> aBounds =
++            appendCluster(rSegment, rArgs, bRtl, nFirstCharInCluster, nNextChar,
++                          nFirstGlyphInCluster, nGlyphIndex, fScaling,
++                          rChar2Base, rGlyph2Char, rCharDxs, nDxOffset);
++        fMinX = std::min(aBounds.first, fMinX);
++        fMaxX = std::max(aBounds.second, fMaxX);
++    }
++    long nXOffset = round(fMinX * fScaling);
++    rWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset;
++    // fill up non-base char dx with cluster widths from previous base glyph
++    if (bRtl)
++    {
++        if (rCharDxs[nChar-1] == -1)
++            rCharDxs[nChar-1] = 0;
++        else
++            rCharDxs[nChar-1] -= nXOffset;
++        for (int i = nChar - 2; i >= 0; i--)
++        {
++            if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i+1];
++            else rCharDxs[i] -= nXOffset;
++        }
++    }
++    else
++    {
++        if (rCharDxs[0] == -1)
++            rCharDxs[0] = 0;
++        else
++            rCharDxs[0] -= nXOffset;
++        for (int i = 1; i < nChar; i++)
++        {
++            if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i-1];
++            else rCharDxs[i] -= nXOffset;
++        }
++    }
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"Glyphs xOff%ld dropDx%ld w%ld\n", nXOffset, nDxOffset, rWidth);
++#endif
++    // remove offset due to context if there is one
++    if (nXOffset != 0)
++    {
++        for (size_t i = 0; i < size(); i++)
++            (*this)[i].maLinearPos.X() -= nXOffset;
++    }
++}
++
++std::pair<float,float> GraphiteLayout::Glyphs::appendCluster(gr::Segment & rSeg,
++    ImplLayoutArgs & rArgs, bool bRtl, int nFirstCharInCluster, int nNextChar,
++    int nFirstGlyphInCluster, int nNextGlyph, float fScaling,
++    std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char,
++    std::vector<int> & rCharDxs, long & rDXOffset)
++{
++    glyph_range_t iGlyphs = rSeg.glyphs();
++    int nGlyphs = iGlyphs.second - iGlyphs.first;
++    int nDelta = (bRtl)? -1 : 1;
++    gr::GlyphInfo aFirstGlyph = *(iGlyphs.first + nFirstGlyphInCluster);
++    std::pair <float, float> aBounds;
++    aBounds.first = aFirstGlyph.origin();
++    aBounds.second = aFirstGlyph.origin();
++    // before we add the glyphs to this vector, we record the
++    // glyph's index in the vector (which is not the same as
++    // the Segment's glyph index!)
++    assert(size() < rGlyph2Char.size());
++    rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size();
++    rGlyph2Char[size()] = nFirstCharInCluster;
++    bool bBaseGlyph = true;
++    for (int j = nFirstGlyphInCluster;
++        j != nNextGlyph; j += nDelta)
++    {
++        long nNextOrigin;
++        float fNextOrigin;
++        gr::GlyphInfo aGlyph = *(iGlyphs.first + j);
++        if (j + nDelta >= nGlyphs || j + nDelta < 0) // at rhs ltr,rtl
++        {
++            fNextOrigin = rSeg.advanceWidth();
++            nNextOrigin = round(rSeg.advanceWidth() * fScaling + rDXOffset);
++            aBounds.second = std::max(rSeg.advanceWidth(), aBounds.second);
++        }
++        else
++        {
++            gr::GlyphInfo aNextGlyph = *(iGlyphs.first + j + nDelta);
++            fNextOrigin = std::max(aNextGlyph.attachedClusterBase()->origin(), aNextGlyph.origin());
++            aBounds.second = std::max(fNextOrigin, aBounds.second);
++            nNextOrigin = round(fNextOrigin * fScaling + rDXOffset);
++        }
++        aBounds.first = std::min(aGlyph.origin(), aBounds.first);
++        if ((signed)aGlyph.firstChar() < rArgs.mnEndCharPos &&
++            (signed)aGlyph.firstChar() >= rArgs.mnMinCharPos)
++        {
++            rCharDxs[aGlyph.firstChar()-rArgs.mnMinCharPos] = nNextOrigin;
++        }
++        if ((signed)aGlyph.attachedClusterBase()->logicalIndex() == j)
++        {
++            append(rSeg, rArgs, aGlyph, fNextOrigin, fScaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, bBaseGlyph);
++            bBaseGlyph = false;
++        }
++    }
++    // from the point of view of the dx array, the xpos is
++    // the origin of the first glyph of the next cluster ltr
++    // rtl it is the origin of the 1st glyph of the cluster
++    long nXPos = (bRtl)?
++        round(aFirstGlyph.attachedClusterBase()->origin() * fScaling) + rDXOffset :
++        round(aBounds.second * fScaling) + rDXOffset;
++    // force the last char in range to have the width of the cluster
++//     for (int n = nNextChar - nDelta; n != nFirstCharInCluster - nDelta; n-= nDelta)
++//     {
++//         if (nNextChar-nDelta < rArgs.mnEndCharPos && nNextChar-nDelta >= rArgs.mnMinCharPos)
++//             rCharDxs[nNextChar-nDelta-rArgs.mnMinCharPos] = nXPos;
++//     }
++    if (bRtl)
++    {
++        for (int n = nNextChar + 1; n <= nFirstCharInCluster; n++)
++        {
++            if ((n < rArgs.mnEndCharPos) && (n >= rArgs.mnMinCharPos))
++                rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
++        }
++    }
++    else
++    {
++        for (int n = nNextChar - 1; n >= nFirstCharInCluster; n--)
++        {
++            if (n < rArgs.mnEndCharPos && n >= rArgs.mnMinCharPos)
++                rCharDxs[n-rArgs.mnMinCharPos] = nXPos;
++        }
++    }
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset());
++#endif
++    return aBounds;
++}
++
++// append walks an attachment tree, flattening it, and converting it into a
++// sequence of GlyphItem objects which we can later manipulate.
++void
++GraphiteLayout::Glyphs::append(gr::Segment &segment, ImplLayoutArgs &args, gr::GlyphInfo & gi, float nextGlyphOrigin, float scaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase)
++{
++    float nextOrigin = nextGlyphOrigin;
++    int firstChar = std::min(gi.firstChar(), gi.lastChar());
++    assert(size() < rGlyph2Char.size());
++    if (!bIsBase) rGlyph2Char[size()] = firstChar;
++    // is the next glyph attached or in the next cluster?
++    glyph_set_range_t iAttached = gi.attachedClusterGlyphs();
++    if (iAttached.first != iAttached.second)
++    {
++        nextOrigin = iAttached.first->origin();
++    }
++    long glyphId = gi.glyphID();
++    long deltaOffset = 0;
++    int glyphWidth = round(nextOrigin * scaling) - round(gi.origin() * scaling);
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"c%d g%d gWidth%d x%f ", firstChar, (int)gi.logicalIndex(), glyphWidth, nextOrigin);
++#endif
++    if (glyphId == 0)
++    {
++        args.NeedFallback(
++            firstChar,
++            gr::RightToLeftDir(gr::DirCode(gi.directionality())));
++        if( (SAL_LAYOUT_FOR_FALLBACK & args.mnFlags ))
++        {
++            glyphId = GF_DROPPED;
++            deltaOffset -= glyphWidth;
++            glyphWidth = 0;
++        }
++    }
++    else if(args.mnFlags & SAL_LAYOUT_FOR_FALLBACK)
++    {
++#ifdef GRLAYOUT_DEBUG
++        fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, args.mpStr[firstChar],
++            args.maRuns.PosIsInAnyRun(firstChar));
++#endif
++        // glyphs that aren't requested for fallback will be taken from base
++        // layout, so mark them as dropped (should this wait until Simplify(false) is called?)
++        if (!args.maRuns.PosIsInAnyRun(firstChar) &&
++            in_range(firstChar, args.mnMinCharPos, args.mnEndCharPos))
++        {
++            glyphId = GF_DROPPED;
++            deltaOffset -= glyphWidth;
++            glyphWidth = 0;
++        }
++    }
++    // append this glyph.
++    long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER;
++    nGlyphFlags |= gr::RightToLeftDir(gr::DirCode(gi.directionality())) ? GlyphItem::IS_RTL_GLYPH : 0;
++    GlyphItem aGlyphItem(size(),//gi.logicalIndex(),
++        glyphId,
++        Point(round(gi.origin() * scaling + rDXOffset),
++            round((-gi.yOffset() * scaling) - segment.AscentOffset()* scaling)),
++        nGlyphFlags,
++        glyphWidth);
++    aGlyphItem.mnOrigWidth = round(gi.advanceWidth() * scaling);
++    push_back(aGlyphItem);
++
++    // update the offset if this glyph was dropped
++    rDXOffset += deltaOffset;
++
++    // Recursively apply append all the attched glyphs.
++    for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
++    {
++        if (agi + 1 == iAttached.second)
++            append(segment, args, *agi, nextGlyphOrigin, scaling, rChar2Base, rGlyph2Char,rCharDxs, rDXOffset, false);
++        else
++            append(segment, args, *agi, (agi + 1)->origin(), scaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, false);
++    }
++}
++
++//
++// An implementation of the SalLayout interface to enable Graphite enabled fonts to be used.
++//
++GraphiteLayout::GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * pFeatures) throw()
++  : mpTextSrc(0),
++    mrFont(font),
++    mnWidth(0),
++    mfScaling(1.0),
++    mpFeatures(pFeatures)
++{
++    // Line settings can have subtle affects on space handling
++    // since we don't really know whether it is the end of a line or just a run
++    // in the middle, it is hard to know what to set them to.
++    // If true, it can cause end of line spaces to be hidden e.g. Doulos SIL
++    maLayout.setStartOfLine(false);
++    maLayout.setEndOfLine(false);
++//    maLayout.setDumbFallback(false);
++    // trailing ws doesn't seem to always take affect if end of line is true
++    maLayout.setTrailingWs(gr::ktwshAll);
++#ifdef GRLAYOUT_DEBUG
++    gr::ScriptDirCode aDirCode = font.getSupportedScriptDirections();
++    fprintf(grLog(),"GraphiteLayout scripts %x %lx\n", aDirCode, long(this));
++#endif
++}
++
++
++GraphiteLayout::~GraphiteLayout() throw()
++{
++    clear();
++    // the features are owned by the platform layers
++    mpFeatures = NULL;
++}
++
++void GraphiteLayout::clear()
++{
++    // Destroy the segment and text source from any previous invocation of
++    // LayoutText
++    mvGlyphs.clear();
++    mvCharDxs.clear();
++    mvChar2BaseGlyph.clear();
++    mvGlyph2Char.clear();
++
++#ifndef GRCACHE
++    delete mpTextSrc;
++#endif
++
++    // Reset the state to the empty state.
++    mpTextSrc=0;
++    mnWidth = 0;
++    // Don't reset the scaling, because it is set before LayoutText
++}
++
++// This method shouldn't be called on windows, since it needs the dc reset
++bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs)
++{
++#ifdef GRCACHE
++    GrSegRecord * pSegRecord = NULL;
++    gr::Segment * pSegment = CreateSegment(rArgs, &pSegRecord);
++    if (!pSegment)
++       return false;
++
++    // layout the glyphs as required by OpenOffice
++    bool success = LayoutGlyphs(rArgs, pSegment, pSegRecord);
++
++    if (pSegRecord) pSegRecord->unlock();
++    else delete pSegment;
++#else
++    gr::Segment * pSegment = CreateSegment(rArgs);
++    bool success = LayoutGlyphs(rArgs, pSegment);
++    delete pSegment;
++#endif
++    return success;
++}
++
++#ifdef GRCACHE
++class GrFontHasher : public gr::Font
++{
++public:
++    GrFontHasher(const gr::Font & aFont) : gr::Font(aFont), mrRealFont(const_cast<gr::Font&>(aFont)) {};
++    ~GrFontHasher(){};
++    virtual bool bold() { return mrRealFont.bold(); };
++    virtual bool italic() { return mrRealFont.italic(); };
++    virtual float ascent()  { return mrRealFont.ascent(); };
++    virtual float descent()  { return mrRealFont.descent(); };
++    virtual float height()  { return mrRealFont.height(); };
++    virtual gr::Font* copyThis() { return mrRealFont.copyThis(); };
++    virtual unsigned int getDPIx() { return mrRealFont.getDPIx(); };
++    virtual unsigned int getDPIy() { return mrRealFont.getDPIy(); };
++    virtual const void* getTable(gr::fontTableId32 nId, size_t* nSize)
++    { return mrRealFont.getTable(nId,nSize); }
++    virtual void getFontMetrics(float*pA, float*pB, float*pC) { mrRealFont.getFontMetrics(pA,pB,pC); };
++
++    sal_Int32 hashCode(const grutils::GrFeatureParser * mpFeatures)
++    {
++        // is this sufficient?
++        std::wstring aFace;
++        bool bBold;
++        bool bItalic;
++        UniqueCacheInfo(aFace, bBold, bItalic);
++        sal_Unicode uName[32]; // max length used in gr::Font
++        // Note: graphite stores font names as UTF-16 even if wchar_t is 32bit
++        // this conversion should be OK.
++        for (size_t i = 0; i < aFace.size() && i < 32; i++)
++        {
++            uName[i] = aFace[i];
++        }
++        size_t iSize = aFace.size();
++        if (0 == iSize) return 0;
++        sal_Int32 hash = rtl_ustr_hashCode_WithLength(uName, iSize);
++        hash ^= static_cast<sal_Int32>(height());
++        hash |= (bBold)? 0x1000000 : 0;
++        hash |= (bItalic)? 0x2000000 : 0;
++        if (mpFeatures)
++            hash ^= mpFeatures->hashCode();
++#ifdef GRLAYOUT_DEBUG
++        fprintf(grLog(), "font hash %x size %f\n", hash, height());
++#endif
++        return hash;
++    };
++
++private:
++    gr::Font & mrRealFont;
++};
++#endif
++
++#ifdef GRCACHE
++gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pSegRecord)
++#else
++gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs)
++#endif
++{
++    assert(rArgs.mnLength >= 0);
++
++    gr::Segment * pSegment = NULL;
++
++    // Set the SalLayouts values to be the inital ones.
++    SalLayout::AdjustLayout(rArgs);
++    // TODO check if this is needed
++    if (mnUnitsPerPixel > 1)
++        mfScaling = 1.0f / mnUnitsPerPixel;
++
++    // Clear out any previous buffers
++    clear();
++    bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
++    try
++    {
++        // Don't set RTL if font doesn't support it otherwise it forces rtl on
++        // everything
++        if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl))
++            maLayout.setRightToLeft(bRtl);
++
++#ifdef GRCACHE
++        GrFontHasher hasher(mrFont);
++        sal_Int32 aFontHash = hasher.hashCode(mpFeatures);
++        GraphiteSegmentCache * pCache =
++            (GraphiteCacheHandler::instance).getCache(aFontHash);
++        if (pCache)
++        {
++            *pSegRecord = pCache->getSegment(rArgs, bRtl);
++            if (*pSegRecord)
++            {
++                pSegment = (*pSegRecord)->getSegment();
++                mpTextSrc = (*pSegRecord)->getTextSrc();
++                maLayout.setRightToLeft((*pSegRecord)->isRtl());
++                if (rArgs.mpStr != mpTextSrc->getLayoutArgs().mpStr ||
++                    rArgs.mnMinCharPos != mpTextSrc->getLayoutArgs().mnMinCharPos ||
++                    rArgs.mnEndCharPos != mpTextSrc->getLayoutArgs().mnEndCharPos ||
++                    (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
++                {
++                    (*pSegRecord)->clearVectors();
++                }
++                mpTextSrc->switchLayoutArgs(rArgs);
++                return pSegment;
++            }
++        }
++#endif
++
++        // Context is often needed beyond the specified end, however, we don't
++        // want it if there has been a direction change, since it is hard
++        // to tell between reordering within one direction and multi-directional
++        // text.
++        const int  segCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH);
++        int limit = rArgs.mnEndCharPos;
++        if (segCharLimit > limit)
++        {
++            limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos,
++                segCharLimit - rArgs.mnEndCharPos, bRtl);
++        }
++
++        // Create a new TextSource object for the engine.
++        mpTextSrc = new TextSourceAdaptor(rArgs, limit);
++        if (mpFeatures) mpTextSrc->setFeatures(mpFeatures);
++
++        pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit);
++        if (pSegment != NULL)
++        {
++#ifdef GRLAYOUT_DEBUG
++            fprintf(grLog(),"Gr::LayoutText %d-%d, context %d,len%d rtl%d/%d scaling %f\n", rArgs.mnMinCharPos,
++               rArgs.mnEndCharPos, limit, rArgs.mnLength, maLayout.rightToLeft(), pSegment->rightToLeft(), mfScaling);
++#endif
++#ifdef GRCACHE
++            // on a new segment rightToLeft should be correct
++            *pSegRecord = pCache->cacheSegment(mpTextSrc, pSegment, pSegment->rightToLeft());
++#endif
++        }
++        else
++        {
++            clear();
++            return NULL;
++        }
++    }
++    catch (...)
++    {
++        clear();  // destroy the text source and any partially built segments.
++        return NULL;
++    }
++    return pSegment;
++}
++
++#ifdef GRCACHE
++bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord)
++#else
++bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment)
++#endif
++{
++#ifdef GRCACHE
++#ifdef GRCACHE_REUSE_VECTORS
++    // if we have an exact match, then we can reuse the glyph vectors from before
++    if (pSegRecord && (pSegRecord->glyphs().size() > 0) &&
++        !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) )
++    {
++        mnWidth = pSegRecord->width();
++        mvGlyphs = pSegRecord->glyphs();
++        mvCharDxs = pSegRecord->charDxs();
++        mvChar2BaseGlyph = pSegRecord->char2BaseGlyph();
++        mvGlyph2Char = pSegRecord->glyph2Char();
++        return true;
++    }
++#endif
++#endif
++    // Calculate the initial character dxs.
++    mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1);
++    mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1);
++    mnWidth = 0;
++    if (mvCharDxs.size() > 0)
++    {
++        // Discover all the clusters.
++        try
++        {
++            // Note: we use the layout rightToLeft() because in cached segments
++            // rightToLeft() may no longer be valid if the engine has been run
++            // ltr since the segment was created.
++#ifdef GRCACHE
++			bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft();
++#else
++			bool bRtl = pSegment->rightToLeft();
++#endif
++            mvGlyphs.fill_from(*pSegment, rArgs, bRtl,
++                mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs);
++
++            if (bRtl)
++            {
++                // not needed for adjacent differences, but for mouse clicks to char
++                std::transform(mvCharDxs.begin(), mvCharDxs.end(), mvCharDxs.begin(),
++                    std::bind1st(std::minus<long>(), mnWidth));
++                // fixup last dx to ensure it always equals the width
++                mvCharDxs[mvCharDxs.size() - 1] = mnWidth;
++            }
++#ifdef GRCACHE
++#ifdef GRCACHE_REUSE_VECTORS
++            if (pSegRecord && rArgs.maReruns.IsEmpty() &&
++                !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags))
++            {
++                pSegRecord->setGlyphVectors(mnWidth, mvGlyphs, mvCharDxs,
++                                            mvChar2BaseGlyph, mvGlyph2Char);
++            }
++#endif
++#endif
++        }
++        catch (std::exception e)
++        {
++#ifdef GRLAYOUT_DEBUG
++            fprintf(grLog(),"LayoutGlyphs failed %s\n", e.what());
++#endif
++            return false;
++        }
++        catch (...)
++        {
++#ifdef GRLAYOUT_DEBUG
++            fprintf(grLog(),"LayoutGlyphs failed with exception");
++#endif
++            return false;
++        }
++	}
++    else
++    {
++        mnWidth = 0;
++    }
++    return true;
++}
++
++int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) const
++{
++    // Adjust maxmnWidth so FindNextBreakPoint returns a sensible answer.
++    maxmnWidth -= (mnEndCharPos-mnMinCharPos-1)*char_extra;  // extra character spacing.
++    maxmnWidth /= factor;                                    // scaling factor.
++
++    // Ask the segment for the nearest whole letter break for the width.
++    //float width;
++    float targetWidth = maxmnWidth/mfScaling;
++    // return quickly if this segment is narrower than the target width
++    // (sometimes graphite doesn't seem to realise this!)
++    if (targetWidth > mnWidth)
++        return STRING_LEN;
++    //int    nBreak = mpSegment->findNextBreakPoint(mnMinCharPos,
++    //        gr::klbWordBreak, gr::klbLetterBreak, targetWidth, &width);
++
++    // LineFillSegment seems to give better results that findNextBreakPoint
++    // though it may be slower
++    gr::LayoutEnvironment aLE;
++    gr::LineFillSegment lineSeg(const_cast<gr::Font *>(&mrFont), mpTextSrc, &aLE,
++                                mnMinCharPos, mpTextSrc->getContextLength(),
++                                targetWidth);
++    int nBreak = lineSeg.stopCharacter();
++
++    if (nBreak > mnEndCharPos) nBreak = STRING_LEN;
++    else if (nBreak < mnMinCharPos) nBreak = mnMinCharPos;
++    return nBreak;
++}
++
++
++long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const
++{
++    if (mnEndCharPos == mnMinCharPos)
++        // Then we must be zero width!
++        return 0;
++
++    if (pDXArray)
++    {
++        for (size_t i = 0; i < mvCharDxs.size(); i++)
++        {
++            assert((mvChar2BaseGlyph[i] >= -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size()));
++            if (mvChar2BaseGlyph[i] != -1 &&
++                mvGlyphs[mvChar2BaseGlyph[i]].mnGlyphIndex == GF_DROPPED)
++            {
++                // when used in MultiSalLayout::GetTextBreak dropped glyphs
++                // must have zero width
++                pDXArray[i] = 0;
++            }
++            else
++            {
++                pDXArray[i] = mvCharDxs[i];
++                if (i > 0) pDXArray[i] -= mvCharDxs[i-1];
++            }
++#ifdef GRLAYOUT_DEBUG
++            fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
++#endif
++        }
++        //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray);
++        //for (size_t i = 0; i < mvCharDxs.size(); i++)
++        //    fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]);
++        //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0));
++    }
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"FillDXArray %d-%d,%d=%ld\n", mnMinCharPos, mnEndCharPos, (int)mpTextSrc->getLength(), mnWidth);
++#endif
++    return mnWidth;
++}
++
++
++void  GraphiteLayout::AdjustLayout(ImplLayoutArgs& args)
++{
++    SalLayout::AdjustLayout(args);
++
++    if(args.mpDXArray)
++        ApplyDXArray(args);
++//    else if( rArgs.mnLayoutWidth )  FIXME: Justification
++//        Justify( rArgs.mnLayoutWidth );
++}
++
++
++void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args)
++{
++    const size_t nChars = args.mnEndCharPos - args.mnMinCharPos;
++    if (nChars == 0) return;
++
++#ifdef GRLAYOUT_DEBUG
++    for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++)
++         fprintf(grLog(),"%d,%d,%d ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]);
++    fprintf(grLog(),"ApplyDx\n");
++#endif
++    bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL;
++    int nXOffset = 0;
++    if (bRtl)
++    {
++        nXOffset = args.mpDXArray[nChars - 1] - mvCharDxs[nChars - 1];
++    }
++    int nPrevClusterGlyph = (bRtl)? mvGlyphs.size() : -1;
++    int nPrevClusterLastChar = -1;
++    for (size_t i = 0; i < nChars; i++)
++    {
++        if (mvChar2BaseGlyph[i] > -1 && mvChar2BaseGlyph[i] != nPrevClusterGlyph)
++        {
++            assert((mvChar2BaseGlyph[i] > -1) && (mvChar2BaseGlyph[i] < (signed)mvGlyphs.size()));
++            GlyphItem & gi = mvGlyphs[mvChar2BaseGlyph[i]];
++            if (!gi.IsClusterStart())
++                continue;
++
++            // find last glyph of this cluster
++            size_t j = i + 1;
++            int nLastChar = i;
++            int nLastGlyph = mvChar2BaseGlyph[i];
++            for (; j < nChars; j++)
++            {
++                assert((mvChar2BaseGlyph[j] >= -1) && (mvChar2BaseGlyph[j] < (signed)mvGlyphs.size()));
++                if (mvChar2BaseGlyph[j] != -1 && mvGlyphs[mvChar2BaseGlyph[j]].IsClusterStart())
++                {
++                    nLastGlyph = mvChar2BaseGlyph[j] + ((bRtl)? 1 : -1);
++                    nLastChar = j - 1;
++                    break;
++                }
++            }
++            // Its harder to find the last glyph rtl, since the first of
++            // cluster is still on the left so we need to search towards
++            // the previous cluster to the right
++            if (bRtl)
++            {
++                nLastGlyph = mvChar2BaseGlyph[i];
++                while (nLastGlyph + 1 < (signed)mvGlyphs.size() &&
++                       !mvGlyphs[nLastGlyph+1].IsClusterStart())
++                {
++                    ++nLastGlyph;
++                }
++            }
++            if (j == nChars)
++            {
++                nLastChar = nChars - 1;
++                if (!bRtl) nLastGlyph = mvGlyphs.size() - 1;
++            }
++            assert((nLastChar > -1) && (nLastChar < (signed)nChars));
++            long nNewClusterWidth = args.mpDXArray[nLastChar];
++            long nOrigClusterWidth = mvCharDxs[nLastChar];
++            long nDGlyphOrigin = 0;
++            if (nPrevClusterLastChar > - 1)
++            {
++                assert(nPrevClusterLastChar < (signed)nChars);
++                nNewClusterWidth -= args.mpDXArray[nPrevClusterLastChar];
++                nOrigClusterWidth -= mvCharDxs[nPrevClusterLastChar];
++                nDGlyphOrigin = args.mpDXArray[nPrevClusterLastChar] - mvCharDxs[nPrevClusterLastChar];
++            }
++            long nDWidth = nNewClusterWidth - nOrigClusterWidth;
++            assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size()));
++            mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
++            if (gi.mnGlyphIndex != GF_DROPPED)
++                mvGlyphs[nLastGlyph].mnNewWidth += nDWidth;
++            else
++                nDGlyphOrigin += nDWidth;
++            // update glyph positions
++            if (bRtl)
++            {
++                for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++)
++                {
++                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
++                    mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset;
++                }
++            }
++            else
++            {
++                for (int n = mvChar2BaseGlyph[i]; n <= nLastGlyph; n++)
++                {
++                    assert((n > - 1) && (n < (signed)mvGlyphs.size()));
++                    mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset;
++                }
++            }
++#ifdef GRLAYOUT_DEBUG
++            fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, mvChar2BaseGlyph[i], nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[mvChar2BaseGlyph[i]].maLinearPos.X());
++#endif
++            nPrevClusterGlyph = mvChar2BaseGlyph[i];
++            nPrevClusterLastChar = nLastChar;
++            i = nLastChar;
++        }
++    }
++    // Update the dx vector with the new values.
++    std::copy(args.mpDXArray, args.mpDXArray + nChars,
++      mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos));
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"ApplyDx %d(%ld)\n", args.mpDXArray[nChars - 1], mnWidth);
++#endif
++    mnWidth = args.mpDXArray[nChars - 1];
++}
++
++
++void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const
++{
++    // For each character except the last discover the caret positions
++    // immediatly before and after that character.
++    // This is used for underlines in the GUI amongst other things.
++    // It may be used from MultiSalLayout, in which case it must take into account
++    // glyphs that have been moved.
++    std::fill(pCaretXArray, pCaretXArray + nArraySize, -1);
++    // the layout method doesn't modify the layout even though it isn't
++    // const in the interface
++    bool bRtl = const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft();
++    int prevBase = -1;
++    long prevClusterWidth = 0;
++    for (int i = 0, nCharSlot = 0; i < nArraySize && nCharSlot < static_cast<int>(mvCharDxs.size()); ++nCharSlot, i+=2)
++    {
++        if (mvChar2BaseGlyph[nCharSlot] != -1)
++        {
++            assert((mvChar2BaseGlyph[nCharSlot] > -1) && (mvChar2BaseGlyph[nCharSlot] < (signed)mvGlyphs.size()));
++            GlyphItem gi = mvGlyphs[mvChar2BaseGlyph[nCharSlot]];
++            if (gi.mnGlyphIndex == GF_DROPPED)
++            {
++                continue;
++            }
++            int nCluster = mvChar2BaseGlyph[nCharSlot];
++            long origClusterWidth = gi.mnNewWidth;
++            long nMin = gi.maLinearPos.X();
++            long nMax = gi.maLinearPos.X() + gi.mnNewWidth;
++            // attached glyphs are always stored after their base rtl or ltr
++            while (++nCluster < static_cast<int>(mvGlyphs.size()) &&
++                !mvGlyphs[nCluster].IsClusterStart())
++            {
++                origClusterWidth += mvGlyphs[nCluster].mnNewWidth;
++                if (mvGlyph2Char[nCluster] == nCharSlot)
++                {
++                    nMin = std::min(nMin, mvGlyphs[nCluster].maLinearPos.X());
++                    nMax = std::min(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth);
++                }
++            }
++            if (bRtl)
++            {
++                pCaretXArray[i+1] = nMin;
++                pCaretXArray[i] = nMax;
++            }
++            else
++            {
++                pCaretXArray[i] = nMin;
++                pCaretXArray[i+1] = nMax;
++            }
++            prevBase = mvChar2BaseGlyph[nCharSlot];
++            prevClusterWidth = origClusterWidth;
++        }
++        else if (prevBase > -1)
++        {
++            // this could probably be improved
++            assert((prevBase > -1) && (prevBase < (signed)mvGlyphs.size()));
++            GlyphItem gi = mvGlyphs[prevBase];
++            int nGlyph = prevBase + 1;
++            // try to find a better match, otherwise default to complete cluster
++            for (; nGlyph < static_cast<int>(mvGlyphs.size()) &&
++                 !mvGlyphs[nGlyph].IsClusterStart(); nGlyph++)
++            {
++                if (mvGlyph2Char[nGlyph] == nCharSlot)
++                {
++                    gi = mvGlyphs[nGlyph];
++                    break;
++                }
++            }
++            long nGWidth = gi.mnNewWidth;
++            // if no match position at end of cluster
++            if (nGlyph == static_cast<int>(mvGlyphs.size()) ||
++                mvGlyphs[nGlyph].IsClusterStart())
++            {
++                nGWidth = prevClusterWidth;
++                if (bRtl)
++                {
++                    pCaretXArray[i+1] = gi.maLinearPos.X();
++                    pCaretXArray[i] = gi.maLinearPos.X();
++                }
++                else
++                {
++                    pCaretXArray[i] = gi.maLinearPos.X() + prevClusterWidth;
++                    pCaretXArray[i+1] = gi.maLinearPos.X() + prevClusterWidth;
++                }
++            }
++            else
++            {
++                if (bRtl)
++                {
++                    pCaretXArray[i+1] = gi.maLinearPos.X();
++                    pCaretXArray[i] = gi.maLinearPos.X() + gi.mnNewWidth;
++                }
++                else
++                {
++                    pCaretXArray[i] = gi.maLinearPos.X();
++                    pCaretXArray[i+1] = gi.maLinearPos.X() + gi.mnNewWidth;
++                }
++            }
++        }
++        else
++        {
++            pCaretXArray[i] = pCaretXArray[i+1] = 0;
++        }
++#ifdef GRLAYOUT_DEBUG
++        fprintf(grLog(),"%d,%d-%d\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]);
++#endif
++    }
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"\n");
++#endif
++}
++
++
++// GetNextGlyphs returns a contiguous sequence of glyphs that can be
++// rendered together. It should never return a dropped glyph.
++// The glyph_slot returned should be the index of the next visible
++// glyph after the last glyph returned by this call.
++// The char_index array should be filled with the characters corresponding
++// to each glyph returned.
++// glyph_adv array should be a virtual width such that if successive
++// glyphs returned by this method are added one after the other they
++// have the correct spacing.
++// The logic in this method must match that expected in MultiSalLayout which
++// is used when glyph fallback is in operation.
++int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out,
++        ::Point & aPosOut, int &glyph_slot, sal_Int32 * glyph_adv, int *char_index) const
++{
++  // Sanity check on the slot index.
++  if (glyph_slot >= signed(mvGlyphs.size()))
++  {
++    glyph_slot = mvGlyphs.size();
++    return 0;
++  }
++  assert(glyph_slot >= 0);
++  // Find the first glyph in the substring.
++  for (; glyph_slot < signed(mvGlyphs.size()) &&
++          ((mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED);
++          ++glyph_slot) {};
++
++  // Update the length
++  const int nGlyphSlotEnd = std::min(size_t(glyph_slot + length), mvGlyphs.size());
++
++  // We're all out of glyphs here.
++  if (glyph_slot == nGlyphSlotEnd)
++  {
++    return 0;
++  }
++
++  // Find as many glyphs as we can which can be drawn in one go.
++  Glyphs::const_iterator glyph_itr = mvGlyphs.begin() + glyph_slot;
++  const int         glyph_slot_begin = glyph_slot;
++  const int            initial_y_pos = glyph_itr->maLinearPos.Y();
++
++  // Set the position to the position of the start glyph.
++  ::Point aStartPos = glyph_itr->maLinearPos;
++  //aPosOut = glyph_itr->maLinearPos;
++  aPosOut = GetDrawPosition(aStartPos);
++
++
++  for (;;)  // Forever
++  {
++     // last index of the range from glyph_to_chars does not include this glyph
++     if (char_index)
++     {
++        assert((glyph_slot >= -1) && (glyph_slot < (signed)mvGlyph2Char.size()));
++        if (mvGlyph2Char[glyph_slot] == -1)
++            *char_index++ = mvCharDxs.size();
++        else
++            *char_index++ = mvGlyph2Char[glyph_slot];
++     }
++     // Copy out this glyphs data.
++     ++glyph_slot;
++     *glyph_out++ = glyph_itr->mnGlyphIndex;
++
++     // Find the actual advance - this must be correct if called from
++     // MultiSalLayout::AdjustLayout which requests one glyph at a time.
++     const long nGlyphAdvance = (glyph_slot == static_cast<int>(mvGlyphs.size()))?
++          glyph_itr->mnNewWidth :
++          ((glyph_itr+1)->maLinearPos.X() - glyph_itr->maLinearPos.X());
++
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1,
++            mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance,
++            aPosOut.X(), aPosOut.Y());
++#endif
++
++     if (glyph_adv)  // If we are returning advance store it.
++       *glyph_adv++ = nGlyphAdvance;
++     else // Stop when next advance is unexpected.
++       if (glyph_itr->mnOrigWidth != nGlyphAdvance)  break;
++
++     // Have fetched all the glyphs we need to
++     if (glyph_slot == nGlyphSlotEnd)
++         break;
++
++     ++glyph_itr;
++     // Stop when next y position is unexpected.
++     if (initial_y_pos != glyph_itr->maLinearPos.Y())
++       break;
++
++     // Stop if glyph dropped
++     if (glyph_itr->mnGlyphIndex == GF_DROPPED)
++       break;
++  }
++  int numGlyphs = glyph_slot - glyph_slot_begin;
++  // move the next glyph_slot to a glyph that hasn't been dropped
++  while (glyph_slot < static_cast<int>(mvGlyphs.size()) &&
++         (mvGlyphs.begin() + glyph_slot)->mnGlyphIndex == GF_DROPPED)
++         ++glyph_slot;
++  return numGlyphs;
++}
++
++
++void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos )
++{
++    // TODO it might be better to actualy implement simplify properly, but this
++    // could needs to be done carefully so the glyph/char maps are maintained
++    // If a glyph has been dropped then it wasn't returned by GetNextGlyphs, so
++    // the index here may be wrong
++    while ((mvGlyphs[nGlyphIndex].mnGlyphIndex == GF_DROPPED) &&
++           (nGlyphIndex < (signed)mvGlyphs.size()))
++    {
++        nGlyphIndex++;
++    }
++    const long dx = nNewPos - mvGlyphs[nGlyphIndex].maLinearPos.X();
++
++    if (dx == 0)  return;
++    // GenericSalLayout only changes maLinearPos, mvCharDxs doesn't change
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"Move %d (%ld,%ld) c%d by %ld\n", nGlyphIndex, mvGlyphs[nGlyphIndex].maLinearPos.X(), nNewPos, mvGlyph2Char[nGlyphIndex], dx);
++#endif
++    for (size_t gi = nGlyphIndex; gi < mvGlyphs.size(); gi++)
++    {
++        mvGlyphs[gi].maLinearPos.X() += dx;
++    }
++    // width does need to be updated for correct fallback
++    mnWidth += dx;
++}
++
++
++void GraphiteLayout::DropGlyph( int nGlyphIndex )
++{
++    if(nGlyphIndex >= signed(mvGlyphs.size()))
++        return;
++
++    GlyphItem & glyph = mvGlyphs[nGlyphIndex];
++    glyph.mnGlyphIndex = GF_DROPPED;
++#ifdef GRLAYOUT_DEBUG
++    fprintf(grLog(),"Dropped %d\n", nGlyphIndex);
++#endif
++}
++
++void GraphiteLayout::Simplify( bool isBaseLayout )
++{
++  const sal_GlyphId dropMarker = isBaseLayout ? GF_DROPPED : 0;
++
++  Glyphs::iterator gi = mvGlyphs.begin();
++  // TODO check whether we need to adjust positions here
++  // MultiSalLayout seems to move the glyphs itself, so it may not be needed.
++  long deltaX = 0;
++  while (gi != mvGlyphs.end())
++  {
++      if (gi->mnGlyphIndex == dropMarker)
++      {
++        deltaX += gi->mnNewWidth;
++        gi->mnNewWidth = 0;
++      }
++      else
++      {
++        deltaX = 0;
++      }
++      //mvCharDxs[mvGlyph2Char[gi->mnCharPos]] -= deltaX;
++      ++gi;
++  }
++#ifdef GRLAYOUT_DEBUG
++  fprintf(grLog(),"Simplify base%d dx=%ld newW=%ld\n", isBaseLayout, deltaX, mnWidth - deltaX);
++#endif
++  // discard width from trailing dropped glyphs, but not those in the middle
++  mnWidth -= deltaX;
++}
+Index: vcl/source/glyphs/graphite_serverfont.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_serverfont.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_serverfont.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,55 @@
++//
++// C++ Implementation: GraphiteLayout
++//
++// Description: An implementation of the SalLayout interface that use the
++//              Graphite engine.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Header files
++//
++
++// Platform
++#include <vcl/sallayout.hxx>
++// Module
++#include "gcach_ftyp.hxx"
++#include <vcl/graphite_features.hxx>
++#include "graphite_textsrc.hxx"
++#include <vcl/graphite_serverfont.hxx>
++
++#ifndef MSC
++
++//
++// An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used.
++//
++
++GraphiteServerFontLayout::GraphiteServerFontLayout(GraphiteFontAdaptor * pFont) throw()
++  : ServerFontLayout(pFont->font()), mpFont(pFont),
++    maImpl(*mpFont, mpFont->features())
++{
++    // Nothing needed here
++}
++
++GraphiteServerFontLayout::~GraphiteServerFontLayout() throw()
++{
++    delete mpFont;
++    mpFont = NULL;
++}
++
++const sal_Unicode* GraphiteServerFontLayout::getTextPtr() const
++{
++    return maImpl.textSrc()->getLayoutArgs().mpStr +
++        maImpl.textSrc()->getLayoutArgs().mnMinCharPos;
++}
++
++
++#endif
+Index: vcl/source/glyphs/graphite_features.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_features.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_features.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,268 @@
++/*-----------------------------------------------------------------------------
++Copyright (C) 2008 www.thanlwinsoft.org
++
++Distributable under the terms of either the Common Public License or the
++GNU Lesser General Public License, as specified in the LICENSING.txt file.
++
++File:
++Responsibility: Keith Stribley
++Last reviewed: Not yet.
++
++Description:
++Parse a string of features specified as ; separated pairs.
++e.g.
++1001=1;2002=2;fav1=0
++
++-----------------------------------------------------------------------------*/
++
++#include <sal/types.h>
++
++#ifdef MSC
++#include <tools/svwin.h>
++#include <svsys.h>
++#endif
++
++#include <vcl/graphite_features.hxx>
++
++using namespace grutils;
++// These mustn't conflict with font name lists which use ; and ,
++const char GrFeatureParser::FEAT_PREFIX = ':';
++const char GrFeatureParser::FEAT_SEPARATOR = '&';
++const char GrFeatureParser::FEAT_ID_VALUE_SEPARATOR = '=';
++const std::string GrFeatureParser::ISO_LANG("lang");
++
++GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string lang)
++    : mnNumSettings(0), mbErrors(false)
++{
++    maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
++    setLang(font, lang);
++}
++
++GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, const std::string lang)
++    : mnNumSettings(0), mbErrors(false)
++{
++    size_t nEquals = 0;
++    size_t nFeatEnd = 0;
++    size_t pos = 0;
++    maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0';
++    setLang(font, lang);
++    while (pos < features.length() && mnNumSettings < MAX_FEATURES)
++    {
++        nEquals = features.find(FEAT_ID_VALUE_SEPARATOR,pos);
++        if (nEquals == std::string::npos)
++        {
++            mbErrors = true;
++            break;
++        }
++        // check for a lang=xxx specification
++        if (features.compare(pos, nEquals - pos, ISO_LANG) == 0)
++        {
++            pos = nEquals + 1;
++            nFeatEnd = features.find(FEAT_SEPARATOR, pos);
++            if (nFeatEnd == std::string::npos)
++            {
++                nFeatEnd = features.length();
++            }
++            if (nFeatEnd - pos > 3)
++                mbErrors = true;
++            else
++            {
++                gr::isocode aLang = maLang;
++                for (size_t i = pos; i < nFeatEnd; i++)
++                    aLang.rgch[i-pos] = features[i];
++                std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
++                    = font.getSupportedLanguages();
++                gr::LanguageIterator iL = aSupported.first;
++                while (iL != aSupported.second)
++                {
++                    gr::isocode aSupportedLang = *iL;
++                    // here we only expect full 3 letter codes
++                    if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
++                        aLang.rgch[1] == aSupportedLang.rgch[1] &&
++                        aLang.rgch[2] == aSupportedLang.rgch[2] &&
++                        aLang.rgch[3] == aSupportedLang.rgch[3]) break;
++                    ++iL;
++                }
++                if (iL == aSupported.second) mbErrors = true;
++                else maLang = aLang;
++            }
++        }
++        else
++        {
++            if (isCharId(features, pos, nEquals - pos))
++                maSettings[mnNumSettings].id = getCharId(features, pos, nEquals - pos);
++            else maSettings[mnNumSettings].id = getIntValue(features, pos, nEquals - pos);
++            pos = nEquals + 1;
++            nFeatEnd = features.find(FEAT_SEPARATOR, pos);
++            if (nFeatEnd == std::string::npos)
++            {
++                nFeatEnd = features.length();
++            }
++            if (isCharId(features, pos, nFeatEnd - pos))
++                maSettings[mnNumSettings].value = getCharId(features, pos, nFeatEnd - pos);
++            else
++                maSettings[mnNumSettings].value= getIntValue(features, pos, nFeatEnd - pos);
++            if (isValid(font, maSettings[mnNumSettings]))
++                mnNumSettings++;
++            else
++                mbErrors = true;
++        }
++        pos = nFeatEnd + 1;
++    }
++}
++
++void GrFeatureParser::setLang(gr::Font & font, const std::string & lang)
++{
++    gr::isocode aLang = {{0,0,0,0}};
++    if (lang.length() > 2)
++    {
++        for (size_t i = 0; i < lang.length() && i < 3; i++)
++        {
++            if (lang[i] == '-') break;
++            aLang.rgch[i] = lang[i];
++        }
++        std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
++                    = font.getSupportedLanguages();
++        gr::LanguageIterator iL = aSupported.first;
++        while (iL != aSupported.second)
++        {
++            gr::isocode aSupportedLang = *iL;
++            if (aLang.rgch[0] == aSupportedLang.rgch[0] &&
++                aLang.rgch[1] == aSupportedLang.rgch[1] &&
++                aLang.rgch[2] == aSupportedLang.rgch[2] &&
++                aLang.rgch[3] == aSupportedLang.rgch[3]) break;
++            ++iL;
++        }
++        if (iL != aSupported.second)
++            maLang = aLang;
++#ifdef DEBUG
++        else
++            printf("%s has no features\n", aLang.rgch);
++#endif
++    }
++}
++
++GrFeatureParser::GrFeatureParser(const GrFeatureParser & aCopy)
++ : maLang(aCopy.maLang), mbErrors(aCopy.mbErrors)
++{
++    mnNumSettings = aCopy.getFontFeatures(maSettings);
++}
++
++GrFeatureParser::~GrFeatureParser()
++{
++}
++
++size_t GrFeatureParser::getFontFeatures(gr::FeatureSetting settings[64]) const
++{
++    if (settings)
++    {
++        std::copy(maSettings, maSettings + mnNumSettings, settings);
++    }
++    return mnNumSettings;
++}
++
++bool GrFeatureParser::isValid(gr::Font & font, gr::FeatureSetting & setting)
++{
++    gr::FeatureIterator i = font.featureWithID(setting.id);
++    if (font.getFeatures().second == i)
++    {
++        return false;
++    }
++    std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator >
++        validValues = font.getFeatureSettings(i);
++    gr::FeatureSettingIterator j = validValues.first;
++    while (j != validValues.second)
++    {
++        if (*j == setting.value) return true;
++        ++j;
++    }
++    return false;
++}
++
++bool GrFeatureParser::isCharId(const std::string & id, size_t offset, size_t length)
++{
++    if (length > 4) return false;
++    for (size_t i = 0; i < length; i++)
++    {
++        if (i > 0 && id[offset+i] == '\0') continue;
++        if ((id[offset+i]) < 0x20 || (id[offset+i]) < 0)
++            return false;
++        if (i==0 && id[offset+i] < 0x41)
++            return false;
++    }
++    return true;
++}
++
++int GrFeatureParser::getCharId(const std::string & id, size_t offset, size_t length)
++{
++    FeatId charId;
++    charId.num = 0;
++#ifdef WORDS_BIGENDIAN
++    for (size_t i = 0; i < length; i++)
++    {
++        charId.label[i] = id[offset+i];
++    }
++#else
++    for (size_t i = 0; i < length; i++)
++    {
++        charId.label[3-i] = id[offset+i];
++    }
++#endif
++    return charId.num;
++}
++
++int GrFeatureParser::getIntValue(const std::string & id, size_t offset, size_t length)
++{
++    int value = 0;
++    int sign = 1;
++    for (size_t i = 0; i < length; i++)
++    {
++        switch (id[offset + i])
++        {
++        case '0':
++        case '1':
++        case '2':
++        case '3':
++        case '4':
++        case '5':
++        case '6':
++        case '7':
++        case '8':
++        case '9':
++            value *= 10;
++            if (sign < 0)
++            {
++                value = -(id[offset + i] - '0');
++                sign = 1;
++            }
++            value += (id[offset + i] - '0');
++            break;
++        case '-':
++            if (i == 0)
++                sign = -1;
++            else
++            {
++                mbErrors = true;
++                break;
++            }
++        default:
++            mbErrors = true;
++            break;
++        }
++    }
++    return value;
++}
++
++
++sal_Int32 GrFeatureParser::hashCode() const
++{
++    union IsoHash { sal_Int32 mInt; gr::isocode mCode; };
++    IsoHash isoHash;
++    isoHash.mCode = maLang;
++    sal_Int32 hash = isoHash.mInt;
++    for (size_t i = 0; i < mnNumSettings; i++)
++    {
++        hash = (hash << 16) ^ ((maSettings[i].id << 8) | maSettings[i].value);
++    }
++    return hash;
++}
+Index: vcl/source/glyphs/makefile.mk
+===================================================================
+--- vcl/source/glyphs/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/glyphs/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -54,8 +54,29 @@
+ 		$(SLO)$/gcach_rbmp.obj		\
+ 		$(SLO)$/gcach_layout.obj	\
+ 		$(SLO)$/gcach_ftyp.obj
++
++.IF "$(ENABLE_GRAPHITE)" != ""
++CFLAGS+=-DENABLE_GRAPHITE
++SLOFILES+=	$(SLO)$/graphite_adaptors.obj	\
++		$(SLO)$/graphite_features.obj	\
++		$(SLO)$/graphite_cache.obj	\
++		$(SLO)$/graphite_textsrc.obj	\
++		$(SLO)$/graphite_serverfont.obj	\
++		$(SLO)$/graphite_layout.obj
+ .ENDIF
+ 
++.ELSE
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++# make use of stlport headerfiles
++EXT_USE_STLPORT=TRUE
++SLOFILES=\
++		$(SLO)$/graphite_textsrc.obj	\
++		$(SLO)$/graphite_cache.obj	\
++		$(SLO)$/graphite_features.obj	\
++		$(SLO)$/graphite_layout.obj
++.ENDIF
++.ENDIF
++
+ # --- Targets ------------------------------------------------------
+ 
+ .INCLUDE :  target.mk
+Index: vcl/source/glyphs/graphite_textsrc.hxx
+===================================================================
+--- vcl/source/glyphs/graphite_textsrc.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_textsrc.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,112 @@
++#ifndef _SV_GRAPHITETEXTSRC_HXX
++#define _SV_GRAPHITETEXTSRC_HXX
++//
++// C++ Interface: Graphite to SAL adaptor classes
++//
++// Description: Implements the Graphite interfaces IGrTextSource and
++//              IGrGraphics which provide Graphite with access to the
++//              app's text storage system and the platform's font and
++//              graphics systems.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003-2004 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Standard Library
++#include <stdexcept>
++// Platform
++
++#ifndef _SVWIN_H
++#include <tools/svwin.h>
++#endif
++
++#ifndef _SV_SVSYS_HXX
++#include <svsys.h>
++#endif
++
++#ifndef _SV_SALGDI_HXX
++#include <vcl/salgdi.hxx>
++#endif
++
++#ifndef _SV_SALLAYOUT_HXX
++#include <vcl/sallayout.hxx>
++#endif
++
++// Module
++#include "vcl/dllapi.h"
++
++// Libraries
++#include <graphite/GrClient.h>
++#include <graphite/Font.h>
++#include <graphite/ITextSource.h>
++
++// Module type definitions and forward declarations.
++//
++namespace grutils
++{
++    class GrFeatureParser;
++}
++// Implements the Adaptor pattern to adapt the LayoutArgs and the ServerFont interfaces to the
++// gr::IGrTextSource interface.
++// @author tse
++//
++class TextSourceAdaptor : public gr::ITextSource
++{
++public:
++        TextSourceAdaptor(ImplLayoutArgs &layout_args, const int nContextLen) throw();
++        ~TextSourceAdaptor();
++        virtual gr::UtfType     utfEncodingForm();
++        virtual size_t          getLength();
++        virtual size_t          fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer);
++        virtual size_t          fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchwBuffer);
++        virtual size_t          fetch(gr::toffset ichMin, size_t cch, gr::utf8  * prgchsBuffer);
++        virtual bool            getRightToLeft(gr::toffset ich);
++        virtual unsigned int    getDirectionDepth(gr::toffset ich);
++        virtual float           getVerticalOffset(gr::toffset ich);
++        virtual gr::isocode     getLanguage(gr::toffset ich);
++
++        virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich);
++        virtual size_t  getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset);
++        virtual bool    sameSegment(gr::toffset ich1, gr::toffset ich2);
++
++        operator ImplLayoutArgs & () throw();
++        void setFeatures(const grutils::GrFeatureParser * pFeatures);
++        const ImplLayoutArgs & getLayoutArgs() const { return maLayoutArgs; }
++        size_t          getContextLength() const { return mnEnd; };
++        inline void switchLayoutArgs(ImplLayoutArgs & newArgs);
++private:
++        // Prevent the generation of a default assignment operator.
++        TextSourceAdaptor & operator=(const TextSourceAdaptor &);
++
++        void getCharProperties(const int, int &, int &, size_t &);
++
++        ImplLayoutArgs  maLayoutArgs;
++        size_t    mnEnd;
++        const grutils::GrFeatureParser * mpFeatures;
++};
++
++inline TextSourceAdaptor::TextSourceAdaptor(ImplLayoutArgs &la, const int nContextLen) throw()
++  : maLayoutArgs(la),
++    mnEnd(std::min(la.mnLength, nContextLen)),
++    mpFeatures(NULL)
++{
++}
++
++inline  TextSourceAdaptor::operator ImplLayoutArgs & () throw() {
++        return maLayoutArgs;
++}
++
++inline void TextSourceAdaptor::switchLayoutArgs(ImplLayoutArgs & aNewArgs)
++{
++    mnEnd += aNewArgs.mnMinCharPos - maLayoutArgs.mnMinCharPos;
++    maLayoutArgs = aNewArgs;
++}
++
++#endif
+Index: vcl/source/glyphs/graphite_cache.cxx
+===================================================================
+--- vcl/source/glyphs/graphite_cache.cxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/source/glyphs/graphite_cache.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,198 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: graphite_cache.cxx,v $
++ * $Revision: 1.1.2.1 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifdef MSC
++#include <tools/svwin.h>
++#include <svsys.h>
++#endif
++
++#include <tools/debug.hxx>
++#include <vcl/sallayout.hxx>
++
++#include <graphite/GrClient.h>
++#include <graphite/Segment.h>
++
++#include <rtl/ustring.hxx>
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_cache.hxx>
++
++#include "graphite_textsrc.hxx"
++
++GrSegRecord::GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
++    : m_rope(rope), m_text(textSrc), m_seg(seg), m_nextKey(NULL),
++    m_fontScale(0.0f), mbIsRtl(bIsRtl), m_lockCount(0)
++{
++	m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
++	m_startChar = seg->startCharacter();
++}
++
++GrSegRecord::~GrSegRecord()
++{
++	clear();
++}
++
++void GrSegRecord::reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
++{
++    clear();
++    mnWidth = 0;
++    m_rope = rope;
++    m_text = textSrc;
++    m_seg = seg;
++    m_nextKey = NULL;
++    m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
++    m_startChar = seg->startCharacter();
++    mbIsRtl = bIsRtl;
++}
++
++void GrSegRecord::clearVectors()
++{
++    mvGlyphs.clear();
++    mvCharDxs.clear();
++    mvChar2BaseGlyph.clear();
++    mvGlyph2Char.clear();
++}
++
++void GrSegRecord::clear()
++{
++#ifdef GR_DEBUG_TEXT
++    if (m_lockCount != 0)
++      OutputDebugString("GrSegRecord locked!");
++#endif
++    clearVectors();
++    delete m_rope;
++    delete m_seg;
++    delete m_text;
++    m_rope = NULL;
++    m_seg = NULL;
++    m_text = NULL;
++    m_fontScale = 0.0f;
++    m_lockCount = 0;
++}
++
++GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl)
++{
++    GrSegRecord * record = NULL;
++    // We keep a record of the oldest key and the last key added
++    // when the next key is added, the record for the prevKey's m_nextKey field
++    // is updated to the newest key so that m_oldestKey can be updated to the
++    // next oldest key when the record for m_oldestKey is deleted
++    if (m_segMap.size() > SEG_CACHE_SIZE)
++    {
++      GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast<long>(m_oldestKey));
++      // oldest record may no longer exist if a buffer was changed
++      if (oldestPair != m_segMap.end())
++      {
++        record = oldestPair->second;
++        m_segMap.erase(reinterpret_cast<long>(m_oldestKey));
++        GrRMEntry range = m_ropeMap.equal_range((*(record->m_rope)).hashCode());
++        while (range.first != range.second)
++        {
++          if (range.first->second == record)
++          {
++            m_ropeMap.erase(range.first);
++            break;
++          }
++          ++range.first;
++        }
++        m_oldestKey = record->m_nextKey;
++        // record will be reused, so don't delete
++      }
++	}
++
++
++//    const int seg_char_limit = min(adapter->maLayoutArgs().mnLength,
++//      adapter->maLayoutArgs().mnEndCharPos
++//      + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
++//    if (seg->stopCharacter() - seg->startCharacter() <= 0)
++//      OutputDebugString("Invalid seg indices\n");
++    rtl::OUString * pRope = new rtl::OUString(adapter->getLayoutArgs().mpStr + seg->startCharacter(),
++       seg->stopCharacter() - seg->startCharacter());
++    if (!pRope) return NULL;
++    bool reuse = false;
++    if (record)
++      record->reuse(pRope, adapter, seg, bIsRtl);
++    else
++      record = new GrSegRecord(pRope, adapter, seg, bIsRtl);
++    if (!record)
++    {
++      delete pRope;
++      return NULL;
++    }
++    GraphiteSegMap::iterator iMap =
++      m_segMap.find(reinterpret_cast<long>(record->m_pStr));
++    if (iMap != m_segMap.end())
++    {
++      // the buffer has changed, so the old cached Segment is useless
++      reuse = true;
++      GrSegRecord * found = iMap->second;
++      // Note: we reuse the old next key to avoid breaking our history
++      // chain. This means it will be prematurely deleted, but this is
++      // unlikely to happen very often.
++      record->m_nextKey = found->m_nextKey;
++      // overwrite the old record
++      m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
++      // erase the old rope key and save the new one
++      GrRMEntry range = m_ropeMap.equal_range((*(found->m_rope)).hashCode());
++      while (range.first != range.second)
++      {
++        if (range.first->second == found)
++        {
++          m_ropeMap.erase(range.first);
++          break;
++        }
++        ++range.first;
++      }
++      GraphiteRopeMap::value_type mapEntry(record->m_rope->hashCode(), record);
++      m_ropeMap.insert(mapEntry);
++      // remove the old record
++      delete found;
++      record->m_lockCount++;
++      return record;
++    }
++    m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
++    GraphiteRopeMap::value_type mapEntry((*(record->m_rope)).hashCode(), record);
++    m_ropeMap.insert(mapEntry);
++
++    if (m_oldestKey == NULL)
++    {
++      m_oldestKey = record->m_pStr;
++      m_prevKey = record->m_pStr;
++    }
++    else if (reuse == false)
++    {
++      DBG_ASSERT(m_segMap.count(reinterpret_cast<long>(m_prevKey)),
++        "Previous key got lost somehow!");
++      m_segMap.find(reinterpret_cast<long>(m_prevKey))
++        ->second->m_nextKey = record->m_pStr;
++      m_prevKey = record->m_pStr;
++    }
++    record->m_lockCount++;
++    return record;
++}
+Index: vcl/source/glyphs/gcach_ftyp.cxx
+===================================================================
+--- vcl/source/glyphs/gcach_ftyp.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/glyphs/gcach_ftyp.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -1399,6 +1399,20 @@
+         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
+     }
+ 
++    // Check for zero area bounding boxes as this crashes some versions of FT.
++    // This also provides a handy short cut as much of the code following
++    //  becomes an expensive nop when a glyph covers no pixels.
++    FT_BBox cbox;
++    FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
++  
++    if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
++    {
++        nAngle = 0;
++        memset(&rRawBitmap, 0, sizeof rRawBitmap);
++        FT_Done_Glyph( pGlyphFT );
++        return true;
++    }
++    
+     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
+     {
+         if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
+Index: vcl/source/glyphs/glyphcache.cxx
+===================================================================
+--- vcl/source/glyphs/glyphcache.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/source/glyphs/glyphcache.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -41,6 +41,10 @@
+ #include <vcl/bitmap.hxx>
+ #include <vcl/outfont.hxx>
+ 
++#ifdef ENABLE_GRAPHITE
++#include <vcl/graphite_features.hxx>
++#endif
++
+ #include <rtl/ustring.hxx>		// used only for string=>hashvalue
+ #include <osl/file.hxx>
+ #include <tools/debug.hxx>
+@@ -85,12 +89,23 @@
+ {
+     // TODO: is it worth to improve this hash function?
+     sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFontSelData.mpFontData );
++#ifdef ENABLE_GRAPHITE
++    if (rFontSelData.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++        != STRING_NOTFOUND)
++    {
++        rtl::OString aFeatName = rtl::OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
++        nFontId ^= aFeatName.hashCode();
++    }
++#endif
+     size_t nHash = nFontId << 8;
+     nHash   += rFontSelData.mnHeight;
+     nHash   += rFontSelData.mnOrientation;
+     nHash   += rFontSelData.mbVertical;
+     nHash   += rFontSelData.meItalic;
+     nHash   += rFontSelData.meWeight;
++#ifdef ENABLE_GRAPHITE
++    nHash   += rFontSelData.meLanguage;
++#endif
+     return nHash;
+ }
+ 
+@@ -121,7 +136,16 @@
+     if( (rA.mnWidth != rB.mnWidth)
+     && ((rA.mnHeight != rB.mnWidth) || (rA.mnWidth != 0)) )
+         return false;
+-
++#ifdef ENABLE_GRAPHITE
++   if (rA.meLanguage != rB.meLanguage)
++        return false;
++   // check for features
++   if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++        != STRING_NOTFOUND ||
++        rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
++        != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
++        return false;
++#endif
+     return true;
+ }
+ 
+Index: vcl/inc/vcl/graphite_serverfont.hxx
+===================================================================
+--- vcl/inc/vcl/graphite_serverfont.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/inc/vcl/graphite_serverfont.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,74 @@
++#ifndef _SV_GRAPHITESERVERFONT_HXX
++#define _SV_GRAPHITESERVERFONT_HXX
++//
++// C++ Interface: GraphiteLayout
++//
++// Description: An implementation of the SalLayout interface that uses the
++//              Graphite engine.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++#ifndef MSC
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_adaptors.hxx>
++
++// Modules
++
++// This class implments the server font specific parts.
++// @author tse
++//
++class VCL_DLLPUBLIC GraphiteServerFontLayout : public ServerFontLayout
++{
++private:
++        mutable GraphiteFontAdaptor * mpFont;
++        // mutable so that the DrawOffset/DrawBase can be set
++        mutable GraphiteLayout maImpl;
++public:
++        GraphiteServerFontLayout(GraphiteFontAdaptor * font) throw();
++
++        virtual bool  LayoutText( ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); return maImpl.LayoutText(rArgs); };    // first step of layout
++        virtual void  AdjustLayout( ImplLayoutArgs& rArgs)
++        {
++            SalLayout::AdjustLayout(rArgs);
++            maImpl.DrawBase() = maDrawBase;
++            maImpl.DrawOffset() = maDrawOffset;
++            maImpl.AdjustLayout(rArgs);
++        };
++        virtual long    GetTextWidth() const                           { return maImpl.GetTextWidth(); }
++        virtual long    FillDXArray( sal_Int32* dxa ) const                 { return maImpl.FillDXArray(dxa); }
++        virtual int     GetTextBreak( long mw, long ce, int f ) const  { return maImpl.GetTextBreak(mw, ce, f); }
++        virtual void    GetCaretPositions( int as, sal_Int32* cxa ) const   { maImpl.GetCaretPositions(as, cxa); }
++
++        // used by display layers
++        virtual int     GetNextGlyphs( int l, sal_GlyphId* gia, Point& p, int& s,
++                        sal_Int32* gaa = NULL, int* cpa = NULL ) const
++        {
++            maImpl.DrawBase() = maDrawBase;
++            maImpl.DrawOffset() = maDrawOffset;
++            return maImpl.GetNextGlyphs(l, gia, p, s, gaa, cpa);
++        }
++
++        virtual void    MoveGlyph( int nStart, long nNewXPos ) { maImpl.MoveGlyph(nStart, nNewXPos); };
++        virtual void    DropGlyph( int nStart ) { maImpl.DropGlyph(nStart); };
++        virtual void    Simplify( bool bIsBase ) { maImpl.Simplify(bIsBase); };
++
++        virtual ~GraphiteServerFontLayout() throw();
++
++// For use with PspGraphics
++        const sal_Unicode* getTextPtr() const;
++        int getMinCharPos() const { return mnMinCharPos; }
++        int getMaxCharPos() const { return mnEndCharPos; }
++};
++
++
++#endif
++#endif //_SV_GRAPHITESERVERFONT_HXX
+Index: vcl/inc/vcl/graphite_layout.hxx
+===================================================================
+--- vcl/inc/vcl/graphite_layout.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/inc/vcl/graphite_layout.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,149 @@
++#ifndef _SV_GRAPHITELAYOUT_HXX
++#define _SV_GRAPHITELAYOUT_HXX
++//
++// C++ Interface: GraphiteLayout
++//
++// Description: An implementation of the SalLayout interface that uses the
++//              Graphite engine.
++//
++// Author: Tim Eves <tim_eves sil org>
++//         Keith Stribley <devel thanlwinsoft org>
++//
++// Copyright: Copyright (C) 2003 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++#define GRCACHE 1
++
++// Standard Library
++#include <memory>
++#include <vector>
++#include <utility>
++// Libraries
++#include <graphite/GrClient.h>
++#include <graphite/Font.h>
++#include <graphite/GrConstants.h>
++#include <graphite/GrAppData.h>
++#include <graphite/SegmentAux.h>
++// Platform
++#include <vcl/sallayout.hxx>
++#include <vcl/dllapi.h>
++// Module
++
++// For backwards compatibility with 2.4.x
++#if (SUPD == 680)
++typedef sal_Int32 sal_GlyphId;
++#endif
++
++
++// Module type definitions and forward declarations.
++//
++class TextSourceAdaptor;
++class GraphiteFontAdaptor;
++class GrSegRecord;
++// SAL/VCL types
++class ServerFont;
++// Graphite types
++namespace gr { class Segment; class GlyphIterator; }
++namespace grutils { class GrFeatureParser; }
++
++// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
++// @author tse
++//
++class VCL_DLLPUBLIC GraphiteLayout : public SalLayout
++{
++public:
++    class Glyphs : public std::vector<GlyphItem>
++    {
++    public:
++        typedef std::pair<Glyphs::const_iterator, Glyphs::const_iterator> iterator_pair_t;
++
++        static const int ADJUSTED;
++
++        void    fill_from(gr::Segment & rSeg, ImplLayoutArgs & rArgs,
++            bool bRtl, long &rWidth, float fScaling,
++            std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char,
++            std::vector<int> & rCharDxs);
++        void    move_glyph(Glyphs::iterator, long dx);
++
++        const_iterator    cluster_base(const_iterator) const;
++        iterator_pair_t    neighbour_clusters(const_iterator) const;
++    private:
++        std::pair<float,float> appendCluster(gr::Segment & rSeg, ImplLayoutArgs & rArgs,
++            bool bRtl, int nFirstCharInCluster, int nNextChar,
++            int nFirstGlyphInCluster, int nNextGlyph, float fScaling,
++            std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char,
++            std::vector<int> & rCharDxs, long & rDXOffset);
++        void         append(gr::Segment & rSeg, ImplLayoutArgs & rArgs, gr::GlyphInfo & rGi, float nextGlyphOrigin, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase);
++    };
++
++    mutable Glyphs          mvGlyphs;
++    void clear();
++
++private:
++    TextSourceAdaptor     * mpTextSrc; // Text source.
++    gr::LayoutEnvironment   maLayout;
++    const gr::Font         &mrFont;
++    long                    mnWidth;
++    std::vector<int>        mvCharDxs;
++    std::vector<int>        mvChar2BaseGlyph;
++    std::vector<int>        mvGlyph2Char;
++    float                   mfScaling;
++    const grutils::GrFeatureParser * mpFeatures;
++
++public:
++    GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * features = NULL) throw();
++
++    // used by upper layers
++    virtual bool  LayoutText( ImplLayoutArgs& );    // first step of layout
++    // split into two stages to allow dc to be restored on the segment
++#ifdef GRCACHE
++    gr::Segment * CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pRecord = NULL);
++    bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord);
++#else
++    gr::Segment * CreateSegment(ImplLayoutArgs& rArgs);
++    bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment);
++#endif
++
++    virtual void  AdjustLayout( ImplLayoutArgs& );  // adjusting positions
++
++    // methods using string indexing
++    virtual int   GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
++    virtual long  FillDXArray( sal_Int32* pDXArray ) const;
++    virtual void  ApplyDXArray(ImplLayoutArgs &args);
++
++    virtual void  GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const;
++
++    // methods using glyph indexing
++    virtual int   GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
++            sal_Int32* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
++
++    // used by glyph+font+script fallback
++    virtual void    MoveGlyph( int nStart, long nNewXPos );
++    virtual void    DropGlyph( int nStart );
++    virtual void    Simplify( bool bIsBase );
++
++    // Dummy implementation so layout can be shared between Linux/Windows
++    virtual void    DrawText(SalGraphics&) const {};
++
++    virtual ~GraphiteLayout() throw();
++    void SetFeatures(grutils::GrFeatureParser * aFeature) { mpFeatures = aFeature; }
++    void SetFontScale(float s) { mfScaling = s; };
++    const TextSourceAdaptor * textSrc() const { return mpTextSrc; };
++
++    static const int EXTRA_CONTEXT_LENGTH;
++private:
++    int                   glyph_to_char(Glyphs::iterator);
++    std::pair<int,int>    glyph_to_chars(const GlyphItem &) const;
++
++    std::pair<long,long>  caret_positions(size_t) const;
++};
++
++
++
++#endif // _SV_GRAPHITELAYOUT_HXX
+Index: vcl/inc/vcl/graphite_adaptors.hxx
+===================================================================
+--- vcl/inc/vcl/graphite_adaptors.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/inc/vcl/graphite_adaptors.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,139 @@
++#ifndef _SV_GRAPHITEADAPTORS_HXX
++#define _SV_GRAPHITEADAPTORS_HXX
++//
++// C++ Interface: Graphite to SAL adaptor classes
++//
++// Description: Implements the Graphite interfaces IGrTextSource and
++//              IGrGraphics which provide Graphite with access to the
++//              app's text storage system and the platform's font and
++//              graphics systems.
++//
++// Author: Tim Eves <tim_eves sil org>
++//
++// Copyright: Copyright (C) 2003-2004 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++
++// We need this to enable namespace support in libgrengine headers.
++#define GR_NAMESPACE
++
++// Standard Library
++#include <stdexcept>
++// Platform
++
++#ifndef _SVWIN_H
++#include <tools/svwin.h>
++#endif
++
++#ifndef _SV_SVSYS_HXX
++#include <svsys.h>
++#endif
++
++#ifndef _SV_SALGDI_HXX
++#include <vcl/salgdi.hxx>
++#endif
++
++#ifndef _SV_SALLAYOUT_HXX
++#include <vcl/sallayout.hxx>
++#endif
++
++// Module
++#include "vcl/dllapi.h"
++
++// Libraries
++#include <graphite/GrClient.h>
++#include <graphite/Font.h>
++#include <graphite/ITextSource.h>
++
++
++// Module type definitions and forward declarations.
++//
++#ifndef MSC
++// SAL/VCL types
++class ServerFont;
++class FreetypeServerFont;
++
++// Graphite types
++
++struct FontProperties : gr::FontProps
++{
++    FontProperties(const FreetypeServerFont & font) throw();
++};
++
++namespace grutils
++{
++    class GrFeatureParser;
++}
++
++// This class adapts the Sal font and graphics services to form required by
++// the Graphite engine.
++// @author tse
++//
++class VCL_DLLPUBLIC GraphiteFontAdaptor : public gr::Font
++{
++typedef std::map<gr::gid16, std::pair<gr::Rect, gr::Point> > GlyphMetricMap;
++
++public:
++    static bool    IsGraphiteEnabledFont(ServerFont &) throw();
++
++    GraphiteFontAdaptor(ServerFont & font, const sal_Int32 dpi_x, const sal_Int32 dpi_y);
++    GraphiteFontAdaptor(const GraphiteFontAdaptor &) throw();
++    ~GraphiteFontAdaptor() throw();
++
++     gr::Font    * copyThis();
++
++    // Basic attribute accessors.
++    virtual float        ascent();
++    virtual float        descent();
++    virtual bool        bold();
++    virtual bool        italic();
++    virtual float        height();
++    virtual unsigned int    getDPIx();
++    virtual unsigned int    getDPIy();
++
++    // Font access methods.
++    virtual const void    * getTable(gr::fontTableId32 tableID, size_t * pcbSize);
++    virtual void          getFontMetrics(float * ascent_out, float * descent_out = 0, float * em_square_out = 0);
++
++    // Glyph metrics.
++    virtual void      getGlyphMetrics(gr::gid16 glyphID, gr::Rect & boundingBox, gr::Point & advances);
++
++    // Adaptor attributes.
++    const FontProperties    & fontProperties() const throw();
++    FreetypeServerFont        & font() const throw();
++    const grutils::GrFeatureParser * features() const { return mpFeatures; };
++
++private:
++    virtual void UniqueCacheInfo(std::wstring &, bool &, bool &);
++
++    FreetypeServerFont& mrFont;
++    FontProperties        maFontProperties;
++    const unsigned int    mnDpiX, mnDpiY;
++    const float           mfAscent,
++                    mfDescent,
++                    mfEmUnits;
++    grutils::GrFeatureParser * mpFeatures;
++    GlyphMetricMap maGlyphMetricMap;
++};
++
++// Partial implementation of class GraphiteFontAdaptor.
++//
++inline const FontProperties & GraphiteFontAdaptor::fontProperties() const throw() {
++    return maFontProperties;
++}
++
++inline FreetypeServerFont & GraphiteFontAdaptor::font() const throw() {
++    return mrFont;
++}
++#endif // not MFC
++
++// Partial implementation of class TextSourceAdaptor.
++//
++//inline const ImplLayoutArgs & TextSourceAdaptor::layoutArgs() const throw() {
++//  return _layout_args;
++//}
++
++
++#endif // _SV_GRAPHITEADAPTORS_HXX
+Index: vcl/inc/vcl/graphite_cache.hxx
+===================================================================
+--- vcl/inc/vcl/graphite_cache.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/inc/vcl/graphite_cache.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,245 @@
++//
++// C++ Implementation: GraphiteLayout
++//
++// Description: A Class to cache Graphite Segments to try to improve
++//              rendering performance.
++//
++// Author: Keith Stribley <devel thanlwinsoft org>
++// Contributors:
++//
++// Copyright: Copyright (C) 2006, 2008 SIL International.
++//            All rights reserved. Distributable under the terms of either
++//            the Common Public License or the GNU Lesser General Public
++//            License.
++//
++#ifndef GraphiteSegmentCache_h
++#define GraphiteSegmentCache_h
++
++#include <tools/solar.h>
++#include <rtl/ustring.h>
++
++#define GRCACHE_REUSE_VECTORS 1
++
++//#include <rope>
++#include <hash_map>
++
++class TextSourceAdaptor;
++/**
++* GrSegRecord stores a Graphite Segment and its associated text
++*/
++class GrSegRecord {
++public:
++    GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl);
++
++    ~GrSegRecord();
++
++    void reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl);
++
++    void clearVectors();
++    void clear();
++#ifdef GRCACHE_REUSE_VECTORS
++    void setGlyphVectors(long nWidth, GraphiteLayout::Glyphs & vGlyphs, std::vector<int> vCharDxs,
++                         std::vector<int> & vChar2Base, std::vector<int> & vGlyph2Char)
++    {
++        clearVectors();
++        mnWidth = nWidth;
++        mvGlyphs.insert(mvGlyphs.begin(), vGlyphs.begin(), vGlyphs.end());
++        mvCharDxs.insert(mvCharDxs.begin(),vCharDxs.begin(),vCharDxs.end());
++        mvChar2BaseGlyph.insert(mvChar2BaseGlyph.begin(),vChar2Base.begin(),vChar2Base.end());
++        mvGlyph2Char.insert(mvGlyph2Char.begin(),vGlyph2Char.begin(),vGlyph2Char.end());
++    }
++#endif
++    gr::Segment * getSegment() { return m_seg; }
++    TextSourceAdaptor * getTextSrc() { return m_text; }
++    void unlock() { --m_lockCount; }
++    bool isRtl() const { return mbIsRtl; }
++#ifdef GRCACHE_REUSE_VECTORS
++    const long width() const { return mnWidth; }
++    const GraphiteLayout::Glyphs & glyphs() const { return mvGlyphs; }
++    const std::vector<int> & charDxs() const { return mvCharDxs; }
++    const std::vector<int> & char2BaseGlyph() const { return mvChar2BaseGlyph; }
++    const std::vector<int> & glyph2Char() const { return mvGlyph2Char; }
++#endif
++private:
++    rtl::OUString * m_rope;
++    TextSourceAdaptor * m_text;
++    gr::Segment * m_seg;
++    const xub_Unicode * m_nextKey;
++    const xub_Unicode*  m_pStr;
++    size_t m_startChar;
++    float m_fontScale;
++    long mnWidth;
++    GraphiteLayout::Glyphs mvGlyphs; // glyphs in display order
++    std::vector<int> mvCharDxs; // right hand side x offset of each glyph
++    std::vector<int> mvChar2BaseGlyph;
++    std::vector<int> mvGlyph2Char;
++    bool mbIsRtl;
++    int m_lockCount;
++    friend class GraphiteSegmentCache;
++};
++
++typedef std::hash_map<long, GrSegRecord*, std::hash<long> > GraphiteSegMap;
++typedef std::hash_multimap<size_t, GrSegRecord*> GraphiteRopeMap;
++typedef std::pair<GraphiteRopeMap::iterator, GraphiteRopeMap::iterator> GrRMEntry;
++
++/**
++* GraphiteSegmentCache contains the cached Segments for one particular font size
++*/
++class GraphiteSegmentCache
++{
++  enum {
++    // not really sure what good values are here,
++    // bucket size should be >> cache size
++    SEG_BUCKET_SIZE = 4096,
++    SEG_CACHE_SIZE = 255
++  };
++public:
++  GraphiteSegmentCache()
++    : m_segMap(SEG_BUCKET_SIZE),
++    m_oldestKey(NULL) {};
++  ~GraphiteSegmentCache()
++  {
++    m_ropeMap.clear();
++    GraphiteSegMap::iterator i = m_segMap.begin();
++    while (i != m_segMap.end())
++    {
++      GrSegRecord *r = i->second;
++      delete r;
++      ++i;
++    }
++    m_segMap.clear();
++  };
++  GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl)
++  {
++    GrSegRecord * found = NULL;
++    // try to find a segment starting at correct place, if not, try to find a
++    //  match for the complete buffer
++    GraphiteSegMap::iterator iMap =
++      m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr +
++                                           layoutArgs.mnMinCharPos));
++    if (iMap != m_segMap.end())
++    {
++      found = iMap->second;
++    }
++    else
++    {
++      iMap = m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr));
++      if (iMap != m_segMap.end())
++      {
++        found = iMap->second;
++      }
++    }
++    if (found)
++    {
++      if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos &&
++          found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos)
++      {
++        const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos
++          + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
++        DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache");
++        // restore original start character, in case it has changed
++        found->m_seg->setTextSourceOffset(found->m_startChar);
++        // check that characters are the same, at least in the range of
++        // interest
++        // We could use substr and ==, but substr does a copy,
++        // so its probably faster to do it like this
++        for (size_t i = layoutArgs.mnMinCharPos; i < seg_char_limit; i++)
++        {
++          //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter()))
++          if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i])
++            return NULL;
++        }
++        if (found->isRtl() != bIsRtl)
++        {
++            return NULL;
++        }
++//        if (found->m_lockCount != 0)
++//          OutputDebugString("Multple users of SegRecord!");
++        found->m_lockCount++;
++      }
++      else found = NULL;
++    }
++    else
++    {
++      // the pointers aren't the same, but we might still have the same text in a segment
++      // this is expecially needed when editing a large paragraph
++      // each edit changes the pointers, but if we don't reuse any segments it gets very
++      // slow.
++      const size_t seg_char_limit = min(layoutArgs.mnLength, layoutArgs.mnEndCharPos
++          + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
++      rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos,
++                                         seg_char_limit - layoutArgs.mnMinCharPos);
++      if (!rope) return NULL;
++      GrRMEntry range = m_ropeMap.equal_range((*(rope)).hashCode());
++      while (range.first != range.second)
++      {
++        found = range.first->second;
++        if (found->m_lockCount == 0)
++        {
++          if(rope->match(*(found->m_rope)))
++          {
++            // found, but the pointers are all wrong
++            found->m_seg->setTextSourceOffset(layoutArgs.mnMinCharPos);
++            // the switch is done in graphite_layout.cxx
++            //found->m_text->switchLayoutArgs(layoutArgs);
++            found->m_lockCount++;
++            break;
++          }
++          else
++            found = NULL;
++        }
++        else
++          found = NULL;
++        ++(range.first);
++      }
++      delete rope;
++    }
++    return found;
++  };
++  GrSegRecord * cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl);
++private:
++  GraphiteSegMap m_segMap;
++  GraphiteRopeMap m_ropeMap;
++  const xub_Unicode * m_oldestKey;
++  const xub_Unicode * m_prevKey;
++};
++
++typedef std::hash_map<int, GraphiteSegmentCache *, std::hash<int> > GraphiteCacheMap;
++
++/**
++* GraphiteCacheHandler maps a particular font, style, size to a GraphiteSegmentCache
++*/
++class GraphiteCacheHandler
++{
++public:
++  GraphiteCacheHandler() : m_cacheMap(255) {};
++  ~GraphiteCacheHandler()
++  {
++    GraphiteCacheMap::iterator i = m_cacheMap.begin();
++    while (i != m_cacheMap.end())
++    {
++      GraphiteSegmentCache *r = i->second;
++      delete r;
++      ++i;
++    }
++    m_cacheMap.clear();
++  };
++
++  static GraphiteCacheHandler instance;
++
++  GraphiteSegmentCache * getCache(sal_Int32 & fontHash)
++  {
++    if (m_cacheMap.count(fontHash) > 0)
++    {
++      return m_cacheMap.find(fontHash)->second;
++    }
++    GraphiteSegmentCache *pCache = new GraphiteSegmentCache();
++    m_cacheMap[fontHash] = pCache;
++    return pCache;
++  }
++private:
++  GraphiteCacheMap m_cacheMap;
++};
++
++#endif
++
+Index: vcl/inc/vcl/graphite_features.hxx
+===================================================================
+--- vcl/inc/vcl/graphite_features.hxx	(.../tags/DEV300_m35)	(Revision 0)
++++ vcl/inc/vcl/graphite_features.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,58 @@
++/*-----------------------------------------------------------------------------
++Copyright (C) 2008 www.thanlwinsoft.org
++
++Distributable under the terms of either the Common Public License or the
++GNU Lesser General Public License, as specified in the LICENSING.txt file.
++
++File:
++Responsibility: Keith Stribley
++Last reviewed: Not yet.
++
++Description:
++Parse a string of features specified as ; separated pairs.
++e.g.
++1001=1;2002=2;fav1=0
++
++-----------------------------------------------------------------------------*/
++#include <graphite/GrClient.h>
++#include <graphite/Font.h>
++#include <graphite/GrFeature.h>
++
++namespace grutils
++{
++
++    class GrFeatureParser
++    {
++    public:
++        enum { MAX_FEATURES = 64 };
++        static const char FEAT_PREFIX;
++        static const char FEAT_SEPARATOR;
++        static const char FEAT_ID_VALUE_SEPARATOR;
++        static const std::string ISO_LANG;
++        GrFeatureParser(gr::Font & font, const std::string features, const std::string lang);
++        GrFeatureParser(gr::Font & font, const std::string lang);
++        GrFeatureParser(const GrFeatureParser & copy);
++        ~GrFeatureParser();
++        size_t getFontFeatures(gr::FeatureSetting settings[MAX_FEATURES]) const;
++        bool parseErrors() { return mbErrors; };
++        static bool isValid(gr::Font & font, gr::FeatureSetting & setting);
++        gr::isocode getLanguage() const { return maLang; };
++        bool hasLanguage() const { return (maLang.rgch[0] != '\0'); }
++        sal_Int32 hashCode() const;
++    private:
++        void setLang(gr::Font & font, const std::string & lang);
++        bool isCharId(const std::string & id, size_t offset, size_t length);
++        int getCharId(const std::string & id, size_t offset, size_t length);
++        int getIntValue(const std::string & id, size_t offset, size_t length);
++        size_t mnNumSettings;
++        gr::isocode maLang;
++        bool mbErrors;
++        gr::FeatureSetting maSettings[64];
++    };
++
++    union FeatId
++    {
++        gr::featid num;
++        unsigned char label[5];
++    };
++}
+Index: vcl/unx/source/gdi/makefile.mk
+===================================================================
+--- vcl/unx/source/gdi/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/unx/source/gdi/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -96,6 +96,10 @@
+ CFLAGS+=-DXRENDER_LINK
+ .ENDIF
+ 
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++CFLAGS+=-DENABLE_GRAPHITE
++.ENDIF
++
+ .ENDIF	# "$(GUIBASE)"!="unx"
+ 
+ # --- Targets ------------------------------------------------------
+Index: vcl/unx/source/gdi/pspgraphics.cxx
+===================================================================
+--- vcl/unx/source/gdi/pspgraphics.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/unx/source/gdi/pspgraphics.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -51,6 +51,11 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ 
++#ifdef ENABLE_GRAPHITE
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_serverfont.hxx>
++#endif
++
+ using namespace psp;
+ using namespace rtl;
+ 
+@@ -702,9 +707,30 @@
+ 
+     Point aPos;
+     long nUnitsPerPixel = rLayout.GetUnitsPerPixel();
+-    const sal_Unicode* pText = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getTextPtr() : NULL;
+-    int nMinCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMinCharPos() : 0;
+-    int nMaxCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMaxCharPos() : 0;
++    const sal_Unicode* pText = NULL;
++    int nMinCharPos = 0;
++    int nMaxCharPos = 0;
++    if (bIsPspServerFontLayout)
++    {
++        const PspServerFontLayout * pPspLayout = dynamic_cast<const PspServerFontLayout*>(&rLayout);
++#ifdef ENABLE_GRAPHITE
++        const GraphiteServerFontLayout * pGrLayout = dynamic_cast<const GraphiteServerFontLayout*>(&rLayout);
++#endif
++        if (pPspLayout)
++        {
++            pText = pPspLayout->getTextPtr();
++            nMinCharPos = pPspLayout->getMinCharPos();
++            nMaxCharPos = pPspLayout->getMaxCharPos();
++        }
++#ifdef ENABLE_GRAPHITE
++        else if (pGrLayout)
++        {
++            pText = pGrLayout->getTextPtr();
++            nMinCharPos = pGrLayout->getMinCharPos();
++            nMaxCharPos = pGrLayout->getMaxCharPos();
++        }
++#endif
++    }
+     for( int nStart = 0;; )
+     {
+         int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, bIsPspServerFontLayout ? aCharPosAry : NULL );
+@@ -958,7 +984,21 @@
+ 
+     if( m_pServerFont[ nFallbackLevel ]
+         && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+-        pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
++    {
++#ifdef ENABLE_GRAPHITE
++        // Is this a Graphite font?
++        if (GraphiteFontAdaptor::IsGraphiteEnabledFont(*m_pServerFont[nFallbackLevel]))
++        {
++            sal_Int32 xdpi, ydpi;
++            GetResolution(xdpi, ydpi);
++            GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *m_pServerFont[nFallbackLevel], xdpi, ydpi);
++            if (!pGrfont) return NULL;
++            pLayout = new GraphiteServerFontLayout(pGrfont);
++        }
++        else
++#endif
++            pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
++    }
+     else
+         pLayout = new PspFontLayout( *m_pPrinterGfx );
+ 
+Index: vcl/unx/source/gdi/salgdi3.cxx
+===================================================================
+--- vcl/unx/source/gdi/salgdi3.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/unx/source/gdi/salgdi3.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -79,6 +79,11 @@
+ 
+ #include <hash_set>
+ 
++#ifdef ENABLE_GRAPHITE
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_serverfont.hxx>
++#endif
++
+ struct cairo_surface_t;
+ struct cairo_t;
+ struct cairo_font_face_t;
+@@ -1688,11 +1693,28 @@
+ 
+ SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+ {
+-    GenericSalLayout* pLayout = NULL;
++    SalLayout* pLayout = NULL;
+ 
+     if( mpServerFont[ nFallbackLevel ]
+     && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+-        pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
++    {
++#ifdef ENABLE_GRAPHITE
++        // Is this a Graphite font?
++        if (GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
++        {
++            sal_Int32 xdpi, ydpi;
++
++            xdpi = GetDisplay()->GetResolution().A();
++            ydpi = GetDisplay()->GetResolution().B();
++
++            GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi);
++            if (!pGrfont) return NULL;
++            pLayout = new GraphiteServerFontLayout(pGrfont);
++        }
++        else
++#endif
++            pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
++    }
+     else if( mXFont[ nFallbackLevel ] )
+         pLayout = new X11FontLayout( *mXFont[ nFallbackLevel ] );
+     else
+Index: vcl/prj/build.lst
+===================================================================
+--- vcl/prj/build.lst	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/prj/build.lst	(.../cws/graphite01)	(Revision 265804)
+@@ -1,4 +1,4 @@
+-vc	vcl	:	apple_remote BOOST:boost psprint rsc sot ucbhelper unotools ICU:icu i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc NULL
++vc	vcl	:	apple_remote BOOST:boost psprint rsc sot ucbhelper unotools ICU:icu GRAPHITE:graphite i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc NULL
+ vc	vcl										usr1	-	all	vc_mkout NULL
+ vc	vcl\inc									nmake	-	all	vc_inc NULL
+ vc	vcl\source\glyphs						nmake	-	all	vc_glyphs vc_inc NULL
+Index: vcl/util/makefile.mk
+===================================================================
+--- vcl/util/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/util/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -181,6 +181,16 @@
+             $(ICUUCLIB)			\
+             $(ICULELIB)			\
+ 			$(JVMACCESSLIB)
++
++.IF "$(GUI)" == "UNX"
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++.IF "$(SYSTEM_GRAPHITE)" == "YES"
++SHL1STDLIBS+= $(GRAPHITE_LIBS)
++.ELSE
++SHL1STDLIBS+= $(SOLARVERSION)$/$(INPATH)$/lib$/libgraphite.a
++.ENDIF
++.ENDIF
++.ENDIF
+ SHL1USE_EXPORTS=name
+ 
+ .IF "$(GUIBASE)"=="aqua"
+@@ -197,6 +207,10 @@
+ .IF "$(USE_BUILTIN_RASTERIZER)"!=""
+     LIB1FILES +=    $(SLB)$/glyphs.lib
+     SHL1STDLIBS+=   $(FREETYPELIB)  $(PSPLIB)
++.ELSE
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++    LIB1FILES +=    $(SLB)$/glyphs.lib
++.ENDIF
+ .ENDIF # USE_BUILTIN_RASTERIZER
+ 
+ SHL1LIBS=   $(LIB1TARGET)
+@@ -226,6 +240,14 @@
+ SHL1STDLIBS += $(PSPLIB)
+ .ENDIF
+ 
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++.IF "$(COM)" == "GCC"
++SHL1STDLIBS += -lgraphite
++.ELSE
++SHL1STDLIBS += graphite_dll.lib
++.ENDIF
++.ENDIF
++
+ SHL1STDLIBS += $(UWINAPILIB)      \
+                $(GDI32LIB)        \
+                $(MSIMG32LIB)        \
+Index: vcl/win/source/gdi/MAKEFILE.MK
+===================================================================
+--- vcl/win/source/gdi/MAKEFILE.MK	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/win/source/gdi/MAKEFILE.MK	(.../cws/graphite01)	(Revision 265804)
+@@ -64,6 +64,10 @@
+ 
+ EXCEPTIONSFILES=	$(SLO)$/salprn.obj
+ 
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++CFLAGS+=-DENABLE_GRAPHITE
++.ENDIF
++
+ # --- Targets ------------------------------------------------------
+ 
+ .INCLUDE :  target.mk
+Index: vcl/win/source/gdi/salgdi3.cxx
+===================================================================
+--- vcl/win/source/gdi/salgdi3.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/win/source/gdi/salgdi3.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -72,6 +72,10 @@
+ #include <tools/stream.hxx>
+ #include <rtl/bootstrap.hxx>
+ 
++#ifdef ENABLE_GRAPHITE
++#include <graphite/GrClient.h>
++#include <graphite/WinFont.h>
++#endif
+ 
+ #include <vector>
+ #include <set>
+@@ -806,6 +810,9 @@
+     mbDisableGlyphApi( false ),
+     mbHasKoreanRange( false ),
+     mbHasCJKSupport( false ),
++#ifdef ENABLE_GRAPHITE
++    mbHasGraphiteSupport( false ),
++#endif
+     mbAliasSymbolsLow( false ),
+     mbAliasSymbolsHigh( false ),
+     mnId( 0 ),
+@@ -863,6 +870,9 @@
+ 
+     ReadCmapTable( hDC );
+     ReadOs2Table( hDC );
++#ifdef ENABLE_GRAPHITE
++    mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
++#endif
+ 
+     // even if the font works some fonts have problems with the glyph API
+     // => the heuristic below tries to figure out which fonts have the problem
+Index: vcl/win/source/gdi/winlayout.cxx
+===================================================================
+--- vcl/win/source/gdi/winlayout.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/win/source/gdi/winlayout.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -65,6 +65,17 @@
+ #include <set>
+ typedef std::set<int> IntSet;
+ 
++// Graphite headers
++#ifdef ENABLE_GRAPHITE
++#include <i18npool/mslangid.hxx>
++#include <graphite/GrClient.h>
++#include <graphite/WinFont.h>
++#include <graphite/Segment.h>
++#include <vcl/graphite_layout.hxx>
++#include <vcl/graphite_cache.hxx>
++#include <vcl/graphite_features.hxx>
++#endif
++
+ #define DROPPED_OUTGLYPH 0xFFFF
+ 
+ using namespace rtl;
+@@ -1953,11 +1964,25 @@
+     long nDelta = nNewXPos - pVI->mnXOffset;
+     if( nStart > nMinGlyphPos )
+     {
+-        // move the glyph by expanding its left glyph
+-        int i;
++        // move the glyph by expanding its left glyph but ignore dropped glyphs
++        int i, nLastUndropped = nMinGlyphPos - 1;
+         for( i = nMinGlyphPos; i < nStart; ++i )
+-            nDelta -= mpGlyphAdvances[ i ];
+-        mpGlyphAdvances[ i-1 ] += nDelta;
++		{
++			if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
++			{
++	            nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
++				nLastUndropped = i;
++			}
++		}
++		if (nLastUndropped >= nMinGlyphPos)
++		{
++			mpGlyphAdvances[ nLastUndropped ] += nDelta;
++			if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
++		}
++		else
++		{
++			pVI->mnXOffset += nDelta;
++		}
+     }
+     else
+     {
+@@ -1976,11 +2001,18 @@
+         --nStart;
+     else // if( !nStart )   // nStart==0 for first visible glyph
+     {
+-        const VisualItem* pVI = mpVisualItems;
++        VisualItem* pVI = mpVisualItems;
+         for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
+             if( GetItemSubrange( *pVI, nStart, nDummy ) )
+                 break;
+         DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
++		int nOffset = 0;
++		int j = pVI->mnMinGlyphPos;
++		while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
++		if (j == nStart)
++		{
++			pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
++		}
+     }
+ 
+     mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+@@ -2037,11 +2069,12 @@
+         }
+ 
+         // handle dropped glyphs at start of visual item
+-        int nEndGlyphPos;
+-        GetItemSubrange( rVI, i, nEndGlyphPos );
++        int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
++        GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
++        i = nMinGlyphPos;
+         while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
+         {
+-            rVI.mnXOffset += pGlyphWidths[ i ];
++            //rVI.mnXOffset += pGlyphWidths[ i ];
+             rVI.mnMinGlyphPos = ++i;
+         }
+ 
+@@ -2051,6 +2084,17 @@
+             rVI.mnEndGlyphPos = 0;
+             continue;
+         }
++		// If there are still glyphs in the cluster and mnMinGlyphPos
++		// has changed then we need to remove the dropped glyphs at start
++		// to correct logClusters, which is unsigned and relative to the 
++		// item start.
++		if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
++		{
++			// drop any glyphs in the visual item outside the range
++			for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
++				mpOutGlyphs[ i ] = cDroppedGlyph;
++			rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
++		}
+ 
+         // handle dropped glyphs in the middle of visual item
+         for(; i < nEndGlyphPos; ++i )
+@@ -2069,7 +2113,7 @@
+                 mpJustifications[ j ] = mpJustifications[ i ];
+             int k = mpGlyphs2Chars[ i ];
+             mpGlyphs2Chars[ j ]   = k;
+-            mpLogClusters[ k ]    = sal::static_int_cast<WORD>(j++);
++            mpLogClusters[ k ]    = sal::static_int_cast<WORD>(j++) - rVI.mnMinGlyphPos;
+         }
+ 
+         rVI.mnEndGlyphPos = j;
+@@ -2473,6 +2517,223 @@
+ 
+ #endif // USE_UNISCRIBE
+ 
++#ifdef ENABLE_GRAPHITE
++// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
++// @author tse
++//
++class GraphiteWinLayout : public WinLayout
++{
++private:
++//  GraphiteLayout                                           _layout;
++    mutable gr::WinFont   mpFont;
++	grutils::GrFeatureParser * mpFeatures;
++    mutable GraphiteLayout maImpl;
++public:
++    //GraphiteLayout(ServerFont & font, const long xDPI, const long yDPI) throw();
++    GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
++
++    //static bool IsGraphiteEnabledFont(ServerFont & font) throw();
++    static bool IsGraphiteEnabledFont(HDC hDC) throw();
++
++    // used by upper layers
++    virtual bool  LayoutText( ImplLayoutArgs& );    // first step of layout
++    virtual void  AdjustLayout( ImplLayoutArgs& );  // adjusting after fallback etc.
++    //  virtual void  InitFont() const;
++    virtual void  DrawText( SalGraphics& ) const;
++
++    // methods using string indexing
++    virtual int   GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
++    virtual long  FillDXArray( long* pDXArray ) const;
++    virtual void  ApplyDXArray(ImplLayoutArgs &args);
++
++    virtual void  GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
++
++    // methods using glyph indexing
++    virtual int   GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
++                      long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
++
++    // used by glyph+font+script fallback
++    virtual void    MoveGlyph( int nStart, long nNewXPos );
++    virtual void    DropGlyph( int nStart );
++    virtual void    Simplify( bool bIsBase );
++    ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
++protected:
++    virtual void    ReplaceDC(gr::Segment & segment) const;
++    virtual void    RestoreDC(gr::Segment & segment) const;
++};
++
++bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
++{
++  return gr::WinFont::FontHasGraphiteTables(hDC);
++}
++
++GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
++  : WinLayout(hDC, rWFD, rWFE),
++	mpFont(hDC),
++    maImpl(mpFont)
++{
++	const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
++	rtl::OString name = rtl::OUStringToOString(
++        rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
++    sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
++    if (nFeat > 0)
++    {
++        rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
++        mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
++	}
++	else
++	{
++		mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
++	}
++	maImpl.SetFeatures(mpFeatures);
++}
++
++void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
++{
++    COLORREF color = GetTextColor(mhDC);
++    dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
++    SetTextColor(mhDC, color);
++}
++
++void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
++{
++    dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
++}
++
++bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
++{
++    HFONT hUnRotatedFont;
++    if (args.mnOrientation)
++    {
++        // Graphite gets very confused if the font is rotated
++        LOGFONTW aLogFont;
++        ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
++        aLogFont.lfEscapement = 0;
++        aLogFont.lfOrientation = 0;
++        hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
++        ::SelectFont(mhDC, hUnRotatedFont);
++    }
++    WinLayout::AdjustLayout(args);
++    mpFont.replaceDC(mhDC);
++    maImpl.SetFontScale(WinLayout::mfFontScale);
++    //bool succeeded = maImpl.LayoutText(args);
++#ifdef GRCACHE
++    GrSegRecord * pSegRecord = NULL;
++    gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
++#else
++    gr::Segment * pSegment = maImpl.CreateSegment(args);
++#endif
++    bool bSucceeded = false;
++    if (pSegment)
++    {
++        // replace the DC on the font within the segment
++        ReplaceDC(*pSegment);
++        // create glyph vectors
++#ifdef GRCACHE
++        bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
++#else
++        bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
++#endif
++        // restore original DC
++        RestoreDC(*pSegment);
++#ifdef GRCACHE
++        if (pSegRecord) pSegRecord->unlock();
++        else delete pSegment;
++#else
++        delete pSegment;
++#endif
++    }
++    mpFont.restoreDC();
++    if (args.mnOrientation)
++    {
++        // restore the rotated font
++        ::SelectFont(mhDC, mhFont);
++        ::DeleteObject(hUnRotatedFont);
++    }
++    return bSucceeded;
++}
++
++void  GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& args)
++{
++    WinLayout::AdjustLayout(args);
++    maImpl.DrawBase() = WinLayout::maDrawBase;
++    maImpl.DrawOffset() = WinLayout::maDrawOffset;
++    maImpl.AdjustLayout(args);
++}
++
++void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
++{
++    HFONT hOrigFont = DisableFontScaling();
++    HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
++    maImpl.DrawBase() = WinLayout::maDrawBase;
++    maImpl.DrawOffset() = WinLayout::maDrawOffset;
++    const int MAX_GLYPHS = 160;
++    sal_GlyphId glyphIntStr[MAX_GLYPHS];
++    WORD glyphWStr[MAX_GLYPHS];
++    int glyphIndex = 0;
++    Point aPos(0,0);
++    int nGlyphs = 0;
++    do
++    {
++        nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
++        if (nGlyphs < 1)
++          break;
++        std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
++        ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
++		              NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
++    } while (nGlyphs);
++    if( hOrigFont )
++          DeleteFont( SelectFont( mhDC, hOrigFont ) );
++}
++
++int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
++{
++    mpFont.replaceDC(mhDC);
++    int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
++    mpFont.restoreDC();
++    return nBreak;
++}
++
++long  GraphiteWinLayout::FillDXArray( long* pDXArray ) const
++{
++    return maImpl.FillDXArray(pDXArray);
++}
++
++void  GraphiteWinLayout::ApplyDXArray(ImplLayoutArgs &args)
++{
++    maImpl.DrawBase() = WinLayout::maDrawBase;
++    maImpl.DrawOffset() = WinLayout::maDrawOffset;
++    maImpl.ApplyDXArray(args);
++}
++
++void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
++{
++	maImpl.GetCaretPositions(nArraySize, pCaretXArray);
++}
++
++int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
++        ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
++{
++    maImpl.DrawBase() = WinLayout::maDrawBase;
++    maImpl.DrawOffset() = WinLayout::maDrawOffset;
++    return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
++}
++
++void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
++{
++	maImpl.MoveGlyph(glyph_idx, new_x_pos);
++}
++
++void GraphiteWinLayout::DropGlyph( int glyph_idx )
++{
++	maImpl.DropGlyph(glyph_idx);
++}
++
++void GraphiteWinLayout::Simplify( bool is_base )
++{
++	maImpl.Simplify(is_base);
++}
++#endif // ENABLE_GRAPHITE
+ // =======================================================================
+ 
+ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+@@ -2488,6 +2749,11 @@
+     if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
+     &&   (aUspModule || (bUspEnabled && InitUSP())) )   // CTL layout engine
+     {
++#ifdef ENABLE_GRAPHITE
++        if (rFontFace.SupportsGraphite())
++            pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
++        else
++#endif // ENABLE_GRAPHITE
+         // script complexity is determined in upper layers
+         pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
+         // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
+@@ -2510,7 +2776,12 @@
+         BYTE eCharSet = ANSI_CHARSET;
+         if( mpLogFont )
+             eCharSet = mpLogFont->lfCharSet;
+-        pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
++#ifdef ENABLE_GRAPHITE
++        if (rFontFace.SupportsGraphite())
++            pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
++        else
++#endif // ENABLE_GRAPHITE
++            pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
+     }
+ 
+     if( mfFontScale != 1.0 )
+Index: vcl/win/source/window/MAKEFILE.MK
+===================================================================
+--- vcl/win/source/window/MAKEFILE.MK	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/win/source/window/MAKEFILE.MK	(.../cws/graphite01)	(Revision 265804)
+@@ -60,6 +60,10 @@
+ EXCEPTIONSFILES=   $(SLO)$/salframe.obj
+ .ENDIF
+ 
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++CFLAGS+=-DENABLE_GRAPHITE
++.ENDIF
++
+ # --- Targets ------------------------------------------------------
+ 
+ .INCLUDE :	target.mk
+Index: vcl/win/inc/salgdi.h
+===================================================================
+--- vcl/win/inc/salgdi.h	(.../tags/DEV300_m35)	(Revision 265804)
++++ vcl/win/inc/salgdi.h	(.../cws/graphite01)	(Revision 265804)
+@@ -80,6 +80,9 @@
+     bool                    SupportsCJK() const         { return mbHasCJKSupport; }
+     bool                    AliasSymbolsHigh() const    { return mbAliasSymbolsHigh; }
+     bool                    AliasSymbolsLow() const     { return mbAliasSymbolsLow; }
++#ifdef ENABLE_GRAPHITE
++	bool                    SupportsGraphite() const    { return mbHasGraphiteSupport; }
++#endif
+ 
+     ImplFontCharMap*        GetImplFontCharMap() const;
+     const Ucs2SIntMap* GetEncodingVector() const { return mpEncodingVector; }
+@@ -96,6 +99,9 @@
+     mutable bool                    mbDisableGlyphApi;
+     mutable bool                    mbHasKoreanRange;
+     mutable bool                    mbHasCJKSupport;
++#ifdef ENABLE_GRAPHITE
++	mutable bool                    mbHasGraphiteSupport;
++#endif
+     mutable ImplFontCharMap*        mpUnicodeMap;
+     mutable const Ucs2SIntMap*      mpEncodingVector;
+ 
+Index: drawinglayer/source/processor2d/vclprocessor2d.cxx
+===================================================================
+--- drawinglayer/source/processor2d/vclprocessor2d.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/source/processor2d/vclprocessor2d.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -129,7 +129,7 @@
+ 				{
+ 					// prepare everything that is not sheared and mirrored
+                     Font aFont(primitive2d::getVclFontFromFontAttributes(
+-                        rTextCandidate.getFontAttributes(), aScale.getX(), aScale.getY(), fRotate, *mpOutputDevice));
++                        rTextCandidate.getFontAttributes(), aScale.getX(), aScale.getY(), fRotate, rTextCandidate.getLocale(), *mpOutputDevice));
+ 
+ 					// handle additional font attributes
+ 					const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP =
+Index: drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
+===================================================================
+--- drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -92,7 +92,7 @@
+ 
+                 // TextLayouterDevice is needed to get metrics for text decorations like 
+                 // underline/strikeout/emphasis marks from it. For setup, the font size is needed
+-			    aTextLayouter.setFontAttributes(getFontAttributes(), rDecTrans.getScale().getX(), rDecTrans.getScale().getY());
++			    aTextLayouter.setFontAttributes(getFontAttributes(), rDecTrans.getScale().getX(), rDecTrans.getScale().getY(), getLocale());
+ 
+ 				// get text width
+ 				double fTextWidth(0.0);
+Index: drawinglayer/source/primitive2d/textlayoutdevice.cxx
+===================================================================
+--- drawinglayer/source/primitive2d/textlayoutdevice.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/source/primitive2d/textlayoutdevice.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -41,6 +41,7 @@
+ #include <vcl/virdev.hxx>
+ #include <vcl/font.hxx>
+ #include <vcl/metric.hxx>
++#include <i18npool/mslangid.hxx>
+ #include <drawinglayer/primitive2d/textprimitive2d.hxx>
+ 
+ //////////////////////////////////////////////////////////////////////////////
+@@ -165,14 +166,14 @@
+ 			mrDevice.SetFont( rFont );
+ 		}
+ 
+-		void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform)
++		void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform, const ::com::sun::star::lang::Locale & rLocale)
+ 		{
+-			setFont(getVclFontFromFontAttributes(rFontAttributes, rTransform, mrDevice));
++			setFont(getVclFontFromFontAttributes(rFontAttributes, rTransform, rLocale, mrDevice));
+ 		}
+ 
+-		void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY)
++		void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY, const ::com::sun::star::lang::Locale & rLocale)
+ 		{
+-			setFont(getVclFontFromFontAttributes(rFontAttributes, fFontScaleX, fFontScaleY, 0.0, mrDevice));
++			setFont(getVclFontFromFontAttributes(rFontAttributes, fFontScaleX, fFontScaleY, 0.0, rLocale, mrDevice));
+         }
+ 
+ 		double TextLayouterDevice::getUnderlineOffset() const
+@@ -262,6 +263,7 @@
+ 		Font getVclFontFromFontAttributes(
+             const FontAttributes& rFontAttributes, 
+             const basegfx::B2DHomMatrix& rTransform,
++            const ::com::sun::star::lang::Locale & rLocale,
+             const OutputDevice& rOutDev)
+ 		{
+ 			// decompose matrix to have position and size of text
+@@ -270,7 +272,7 @@
+ 			
+             rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+             
+-            return getVclFontFromFontAttributes(rFontAttributes, aScale.getX(), aScale.getY(), fRotate, rOutDev);
++            return getVclFontFromFontAttributes(rFontAttributes, aScale.getX(), aScale.getY(), fRotate, rLocale, rOutDev);
+ 		}
+ 
+ 		Font getVclFontFromFontAttributes(
+@@ -278,6 +280,7 @@
+             double fFontScaleX, 
+             double fFontScaleY, 
+             double fFontRotation,
++            const ::com::sun::star::lang::Locale & rLocale,
+             const OutputDevice& /*rOutDev*/)
+ 		{
+ 			sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
+@@ -297,6 +300,7 @@
+ 			aRetval.SetWeight(static_cast<FontWeight>(rFontAttributes.getWeight()));
+ 			aRetval.SetItalic(rFontAttributes.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
+ 			aRetval.SetOutline(rFontAttributes.getOutline());
++            aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale));
+ 
+ #ifdef WIN32
+             if(nWidth != nHeight)
+Index: drawinglayer/source/primitive2d/textprimitive2d.cxx
+===================================================================
+--- drawinglayer/source/primitive2d/textprimitive2d.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/source/primitive2d/textprimitive2d.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -142,7 +142,7 @@
+ 
+ 					// prepare textlayoutdevice
+ 					TextLayouterDevice aTextLayouter;
+-					aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY());
++					aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY(), getLocale());
+ 	                
+ 					// get the text outlines. No DXArray is given (would contain integers equal to unit vector
+ 					// transformed by object's transformation), let VCL do the job
+@@ -289,7 +289,7 @@
+ 
+ 					// prepare textlayoutdevice
+ 					TextLayouterDevice aTextLayouter;
+-					aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY());
++					aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY(), getLocale());
+ 
+ 					// get basic text range
+ 					aRetval = aTextLayouter.getTextBoundRect(getText(), getTextPosition(), getTextLength());
+Index: drawinglayer/inc/drawinglayer/primitive2d/textlayoutdevice.hxx
+===================================================================
+--- drawinglayer/inc/drawinglayer/primitive2d/textlayoutdevice.hxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/inc/drawinglayer/primitive2d/textlayoutdevice.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -41,6 +41,7 @@
+ #include <tools/poly.hxx>
+ #include <basegfx/range/b2drange.hxx>
+ #include <vector>
++#include <com/sun/star/lang/Locale.hpp>
+ 
+ //////////////////////////////////////////////////////////////////////////////
+ // predefines
+@@ -75,8 +76,8 @@
+ 			~TextLayouterDevice();
+ 			
+ 			void setFont(const Font& rFont);
+-			void setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform);
+-			void setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY);
++			void setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform, const ::com::sun::star::lang::Locale & rLocale);
++			void setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY, const ::com::sun::star::lang::Locale & rLocale);
+ 
+ 			double getTextHeight() const;
+ 			double getUnderlineHeight() const;
+@@ -113,12 +114,14 @@
+             const FontAttributes& rFontAttributes, 
+             double fFontScaleX, 
+             double fFontScaleY,
+-            double fFontRotation, 
++            double fFontRotation,
++            const ::com::sun::star::lang::Locale & rLocale,
+             const OutputDevice& rOutDev);
+ 		
+         Font getVclFontFromFontAttributes(
+             const FontAttributes& rFontAttributes, 
+             const basegfx::B2DHomMatrix& rTransform,
++            const ::com::sun::star::lang::Locale & rLocale,
+             const OutputDevice& rOutDev);
+ 		
+         FontAttributes getFontAttributesFromVclFont(basegfx::B2DVector& rSize, const Font& rFont, bool bRTL, bool bBiDiStrong);
+Index: drawinglayer/util/makefile.mk
+===================================================================
+--- drawinglayer/util/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ drawinglayer/util/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -72,6 +72,7 @@
+ 		$(CPPUHELPERLIB)	\
+ 		$(CPPULIB)			\
+ 		$(AVMEDIALIB)		\
++		$(I18NISOLANGLIB)	\
+ 		$(COMPHELPERLIB)
+ 
+ SHL1DEF=	$(MISC)$/$(SHL1TARGET).def
+Index: sc/source/core/data/patattr.cxx
+===================================================================
+--- sc/source/core/data/patattr.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ sc/source/core/data/patattr.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -257,14 +257,16 @@
+ 	FontEmphasisMark eEmphasis;
+ 	FontRelief eRelief;
+ 	Color aColor;
++	LanguageType eLang;
+ 
+-	USHORT nFontId, nHeightId, nWeightId, nPostureId;
++	USHORT nFontId, nHeightId, nWeightId, nPostureId, nLangId;
+ 	if ( nScript == SCRIPTTYPE_ASIAN )
+ 	{
+ 		nFontId    = ATTR_CJK_FONT;
+ 		nHeightId  = ATTR_CJK_FONT_HEIGHT;
+ 		nWeightId  = ATTR_CJK_FONT_WEIGHT;
+ 		nPostureId = ATTR_CJK_FONT_POSTURE;
++		nLangId    = ATTR_CJK_FONT_LANGUAGE;
+ 	}
+ 	else if ( nScript == SCRIPTTYPE_COMPLEX )
+ 	{
+@@ -272,6 +274,7 @@
+ 		nHeightId  = ATTR_CTL_FONT_HEIGHT;
+ 		nWeightId  = ATTR_CTL_FONT_WEIGHT;
+ 		nPostureId = ATTR_CTL_FONT_POSTURE;
++		nLangId    = ATTR_CTL_FONT_LANGUAGE;
+ 	}
+ 	else
+ 	{
+@@ -279,6 +282,7 @@
+ 		nHeightId  = ATTR_FONT_HEIGHT;
+ 		nWeightId  = ATTR_FONT_WEIGHT;
+ 		nPostureId = ATTR_FONT_POSTURE;
++		nLangId    = ATTR_FONT_LANGUAGE;
+ 	}
+ 
+ 	if ( pCondSet )
+@@ -332,6 +336,10 @@
+ 		if ( pCondSet->GetItemState( ATTR_FONT_COLOR, TRUE, &pItem ) != SFX_ITEM_SET )
+             pItem = &rItemSet.Get( ATTR_FONT_COLOR );
+ 		aColor = ((const SvxColorItem*)pItem)->GetValue();
++
++		if ( pCondSet->GetItemState( nLangId, TRUE, &pItem ) != SFX_ITEM_SET )
++			pItem = &rItemSet.Get( nLangId );
++		eLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ 	}
+     else    // alles aus rItemSet
+ 	{
+@@ -358,6 +366,9 @@
+                         rItemSet.Get( ATTR_FONT_RELIEF )).GetValue();
+ 		aColor = ((const SvxColorItem&)
+                         rItemSet.Get( ATTR_FONT_COLOR )).GetValue();
++		// for graphite language features
++		eLang =
++		((const SvxLanguageItem&)rItemSet.Get( nLangId )).GetLanguage();
+ 	}
+ 	DBG_ASSERT(pFontAttr,"nanu?");
+ 
+@@ -374,6 +385,8 @@
+ 	rFont.SetCharSet( pFontAttr->GetCharSet() );
+ 	rFont.SetPitch( pFontAttr->GetPitch() );
+ 
++	rFont.SetLanguage(eLang);
++
+ 	//	Groesse
+ 
+Index: config_office/configure.in
+===================================================================
+--- config_office/configure.in	(.../tags/DEV300_m35)	(Revision 265804)
++++ config_office/configure.in	(.../cws/graphite01)	(Revision 265804)
+@@ -29,6 +29,12 @@
+ [  --without-gpc           Use the internal polygon clipping code instead of
+                           the external GPC polygon clipping library.
+ ],,if test ! -e ../external/gpc/gpc.c && test ! -e ../external/gpc/gpc.h; then without_gpc=yes; fi)
++AC_ARG_ENABLE(graphite,
++[  --enable-graphite       Enables the compilation of Graphite smart font rendering
++],,)
++AC_ARG_WITH(system-graphite,
++[  --with-system-graphite    use graphite library already installed on system
++],,)
+ AC_ARG_ENABLE(ldap,
+ [  --disable-ldap          Disables the use of LDAP backend via Netscape/Mozilla
+                           or OpenLDAP LDAP SDK
+@@ -4234,6 +4240,39 @@
+ AC_SUBST(SYSTEM_GENCMN)
+ 
+ dnl ===================================================================
++dnl Graphite
++dnl ===================================================================
++
++AC_MSG_CHECKING([whether to enable graphite support])
++if test "z$enable_graphite" != "z" -a "$enable_graphite" != "no" ; then
++    AC_MSG_RESULT([yes])
++    ENABLE_GRAPHITE="TRUE"
++    AC_MSG_CHECKING([which graphite to use])
++    if test -n "$with_system_graphite" -o -n "$with_system_libs" && \
++        test "$with_system_graphite" != "no"; then
++        AC_MSG_RESULT([external])
++        SYSTEM_GRAPHITE=YES
++        PKG_CHECK_MODULES( GRAPHITE, silgraphite )
++	AC_MSG_CHECKING([STL compatibility])
++	if test "$WITH_STLPORT" != "no"; then
++		AC_MSG_ERROR([to use system graphite you need to use --without-stlport])
++	else
++		AC_MSG_RESULT([OK])	
++	fi
++    else
++        AC_MSG_RESULT([internal])
++        SYSTEM_GRAPHITE=NO
++        BUILD_TYPE="$BUILD_TYPE GRAPHITE"
++    fi
++else
++   AC_MSG_RESULT([no])
++fi
++AC_SUBST(ENABLE_GRAPHITE)
++AC_SUBST(SYSTEM_GRAPHITE)
++AC_SUBST(GRAPHITE_LIBS)
++AC_SUBST(GRAPHITE_CFLAGS)
++
++dnl ===================================================================
+ dnl Checks for libraries.
+ dnl ===================================================================
+ dnl Check for Mac OS X native GUI, which may be used instead of X11.
+Index: config_office/set_soenv.in
+===================================================================
+--- config_office/set_soenv.in	(.../tags/DEV300_m35)	(Revision 265804)
++++ config_office/set_soenv.in	(.../cws/graphite01)	(Revision 265804)
+@@ -1887,6 +1887,10 @@
+ ToFile( "ENABLE_DIRECTX",    "@ENABLE_DIRECTX@",    "e" );
+ ToFile( "ENABLE_LAYOUT",     "@ENABLE_LAYOUT@",     "e" );
+ ToFile( "ENABLE_PCH",        "@ENABLE_PCH@",       "e" );
++ToFile( "ENABLE_GRAPHITE",   "@ENABLE_GRAPHITE@",   "e");
++ToFile( "SYSTEM_GRAPHITE",   "@SYSTEM_GRAPHITE@",   "e");
++ToFile( "GRAPHITE_LIBS",     "@GRAPHITE_LIBS@",     "e");
++ToFile( "GRAPHITE_CFLAGS",   "@GRAPHITE_CFLAGS@",   "e");
+ ToFile( "VC_STANDARD",       "@VC_STANDARD@",      "e" );
+ ToFile( "WITH_GPC",          "@WITH_GPC@",         "e" );
+ ToFile( "WITH_MYSPELL_DICTS","@WITH_MYSPELL_DICTS@","e");
+Index: sw/source/core/text/itrform2.cxx
+===================================================================
+--- sw/source/core/text/itrform2.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ sw/source/core/text/itrform2.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -1973,6 +1973,7 @@
+         nReformat -= 2;
+ 
+ #ifndef QUARTZ
++#ifndef ENABLE_GRAPHITE
+         // --> FME 2004-09-27 #i28795#, #i34607#, #i38388#
+         // step back six(!) more characters for complex scripts
+         // this is required e.g., for Khmer (thank you, Javier!)
+@@ -1981,6 +1982,10 @@
+         if( ::i18n::ScriptType::COMPLEX == rSI.ScriptType( nReformat ) )
+             nMaxContext = 6;
+ #else
++        // Some Graphite fonts need context for scripts not marked as complex
++        static const xub_StrLen nMaxContext = 10;
++#endif
++#else
+         // some fonts like Quartz's Zapfino need more context
+         // TODO: query FontInfo for maximum unicode context
+         static const xub_StrLen nMaxContext = 8;
+Index: sw/source/core/text/makefile.mk
+===================================================================
+--- sw/source/core/text/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ sw/source/core/text/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -45,6 +45,9 @@
+ CDEFS+=-Dmydebug
+ .ENDIF
+ 
++.IF "$(ENABLE_GRAPHITE)" == "TRUE"
++CFLAGS+=-DENABLE_GRAPHITE
++.ENDIF
+ # --- Files --------------------------------------------------------
+ 
+ .IF "$(product)$(cap)" == ""
+Index: sw/source/core/text/porlay.cxx
+===================================================================
+--- sw/source/core/text/porlay.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ sw/source/core/text/porlay.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -45,6 +45,7 @@
+ #include <porrst.hxx>		// SwHangingPortion
+ #include <pormulti.hxx> 	// SwMultiPortion
+ #include <breakit.hxx>
++#include <unicode/uchar.h>
+ #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+ #include <com/sun/star/i18n/ScriptType.hdl>
+ #endif
+@@ -986,7 +987,26 @@
+         if ( nChg > rTxt.Len() )
+             nChg = rTxt.Len();
+ 
+-        aScriptChg.Insert( nChg, nCnt );
++        // special case for dotted circle since it can be used with complex
++        // before a mark, so we want it associated with the mark's script
++        if (nChg < rTxt.Len() && nChg > 0 && (i18n::ScriptType::WEAK ==
++            pBreakIt->xBreak->getScriptType(rTxt,nChg - 1)))
++        {
++            int8_t nType = u_charType(rTxt.GetChar(nChg) );
++            if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
++                nType == U_COMBINING_SPACING_MARK )
++            {
++                aScriptChg.Insert( nChg - 1, nCnt );
++            }
++            else
++            {
++                aScriptChg.Insert( nChg, nCnt );
++            }
++        }
++        else
++        {
++            aScriptChg.Insert( nChg, nCnt );
++        }
+         aScriptType.Insert( nScript, nCnt++ );
+ 
+         // if current script is asian, we search for compressable characters
+Index: sw/source/core/txtnode/fntcache.cxx
+===================================================================
+--- sw/source/core/txtnode/fntcache.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ sw/source/core/txtnode/fntcache.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -177,6 +177,7 @@
+ 	bPaintBlank = ( UNDERLINE_NONE != aFont.GetUnderline()
+ 				  || STRIKEOUT_NONE != aFont.GetStrikeout() )
+ 				  && !aFont.IsWordLineMode();
++	aFont.SetLanguage(rFont.GetLanguage());
+ }
+ 
+ SwFntObj::~SwFntObj()
+Index: sw/source/core/bastyp/breakit.cxx
+===================================================================
+--- sw/source/core/bastyp/breakit.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ sw/source/core/bastyp/breakit.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -32,6 +32,7 @@
+ #include "precompiled_sw.hxx"
+ 
+ #include "breakit.hxx"
++#include <unicode/uchar.h>
+ #include <com/sun/star/lang/XMultiServiceFactory.hpp>
+ #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
+ #include <com/sun/star/i18n/ScriptType.hdl>
+@@ -114,6 +115,18 @@
+ 			--nPos;
+ 		nScript = xBreak->getScriptType( rTxt, nPos );
+ 		sal_Int32 nChgPos = 0;
++        if ( i18n::ScriptType::WEAK == nScript && nPos + 1 < rTxt.Len() )
++        {
++            // A weak character followed by a mark may be meant to combine with
++            // the mark, so prefer the following character's script
++            switch ( u_charType(rTxt.GetChar(nPos + 1) ) ) {
++            case U_NON_SPACING_MARK:
++            case U_ENCLOSING_MARK:
++            case U_COMBINING_SPACING_MARK:
++                nScript = xBreak->getScriptType( rTxt, nPos+1 );
++                break;
++            }
++        }
+         if( i18n::ScriptType::WEAK == nScript && nPos &&
+ 			0 < (nChgPos = xBreak->beginOfScript( rTxt, nPos, nScript )) )
+ 			nScript = xBreak->getScriptType( rTxt, nChgPos-1 );
+Index: graphite/graphite-2.3.patch
+===================================================================
+--- graphite/graphite-2.3.patch	(.../tags/DEV300_m35)	(Revision 0)
++++ graphite/graphite-2.3.patch	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,358 @@
++--- misc/build/silgraphite-2.3/engine/include/graphite/GrCommon.h	2007-12-20 12:51:13.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/include/graphite/GrCommon.h	2007-12-20 12:50:53.000000000 +0000
++@@ -41,7 +41,7 @@
++ // Provided the client includes GrClient.h first this #define is
++ // picked up by all files.
++ 
++-//#define gr gr2
+++#define gr gr3ooo
++ 
++ // Project headers
++ #include "GrPlatform.h"
++
++
++--- misc/build/silgraphite-2.3/wrappers/win32/WinFont.h	2008-02-06 19:20:23.437500000 +0000
+++++ misc/build/silgraphite-2.3/wrappers/win32/WinFont.h	2008-02-06 19:25:01.406250000 +0000
++@@ -27,6 +27,10 @@
++ #include "GrClient.h"
++ #include "Font.h"
++ 
+++#ifdef _STLPORT_VERSION
+++namespace stdext = std;
+++#endif
+++
++ namespace gr
++ {
++ 
++--- misc/build/silgraphite-2.3/engine/src/segment/GrTableManager.cpp	2008-02-06 19:32:56.015625000 +0000
+++++ misc/build/silgraphite-2.3/engine/src/segment/GrTableManager.cpp	2008-02-06 19:33:09.734375000 +0000
++@@ -25,8 +25,8 @@
++ DEFINE_THIS_FILE
++ #ifndef _WIN32
++ #include <stdlib.h>
++-#include <math.h>
++ #endif
+++#include <math.h>
++ 
++ //:>********************************************************************************************
++ //:>	Forward declarations
++--- misc/build/silgraphite-2.3/engine/src/segment/GrEngine.cpp	2008-01-31 17:02:28.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/src/segment/GrEngine.cpp	2008-02-07 22:44:00.875000000 +0000
++@@ -158,12 +158,12 @@
++ GrEngine::~GrEngine()
++ {
++ 	DestroyEverything();
++-	#ifdef _MSC_VER
++-	if (!_CrtCheckMemory())
++-	{
++-		OutputDebugString(L"bad memory");
++-	}
++-	#endif
+++//	#ifdef _MSC_VER
+++//	if (!_CrtCheckMemory())
+++//	{
+++//		OutputDebugString(L"bad memory");
+++//	}
+++//	#endif
++ }
++ 
++ /*----------------------------------------------------------------------------------------------
++@@ -172,12 +172,12 @@
++ void GrEngine::DestroyEverything()
++ {
++ 	DestroyContents();
++-	#ifdef _MSC_VER
++-	if (!_CrtCheckMemory())
++-	{
++-		OutputDebugString(L"bad memory");
++-	}
++-	#endif
+++//	#ifdef _MSC_VER
+++//	if (!_CrtCheckMemory())
+++//	{
+++//		OutputDebugString(L"bad memory");
+++//	}
+++//	#endif
++ 
++ 	m_strCtrlFileReg.erase();
++ 	m_strCtrlFileBold.erase();
++--- misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp	2008-01-31 17:02:28.000000000 +0000
+++++ misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp	2008-02-14 20:51:20.937500000 +0000
++@@ -219,7 +219,12 @@
++ ----------------------------------------------------------------------------------------------*/
++ bool WinFont::FontHasGraphiteTables(HDC hdc)
++ {
++-	DWORD cbTableSz = ::GetFontData(hdc, kttiSilf, 0, NULL, 0);
+++	fontTableId32 tableID = kttiSilf;
+++	fontTableId32 tableIdBIG  = (tableID & 0x000000FF) << 24;
+++	              tableIdBIG += (tableID & 0x0000FF00) << 8;
+++	              tableIdBIG += (tableID & 0x00FF0000) >> 8;
+++	              tableIdBIG += (tableID & 0xFF000000) >> 24;
+++	DWORD cbTableSz = ::GetFontData(hdc, tableIdBIG, 0, NULL, 0);
++ 	if (cbTableSz == GDI_ERROR)
++ 		return false;
++ 	else if (cbTableSz == 0)
++--- misc/build/silgraphite-2.3/engine/makefile.vc	2008-01-31 17:02:28.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/makefile.vc	2008-03-07 18:46:55.015625000 +0000
++@@ -1,8 +1,14 @@
++ 
++ TARGET=graphite
++ 
+++!IF "$(COMEX)" == "11"
+++WCHAR=/Zc:wchar_t-
+++!ELSE
+++WCHAR=
+++!ENDIF
+++
++ CPP=cl.exe
++-CPPFLAGS=/nologo /W4 /GR /GX /I "./src/font" /I "./src/painter" /I "./src/segment" /I "./src/textsource" /I "./src/generic" /I "./include/graphite" /I "../wrappers/win32" /D "GR_NAMESPACE" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /D "TRACING"  /Fp"$(INTDIR)\graphite.pch" /YX /Fd"$(INTDIR)\\" /FD /c
+++CPPFLAGS=/nologo /W4 /GR /EHsc /I "./src/font" /I "./src/painter" /I "./src/segment" /I "./src/textsource" /I "./src/generic" /I "./include/graphite" /I "../wrappers/win32" /D "GR_NAMESPACE" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /D "TRACING"  /Fp"$(INTDIR)\graphite.pch" /Fd"$(INTDIR)\\" /FD /c $(WCHAR)
++ 
++ LINK=link.exe
++ LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /pdb:"$(OUTDIR)\\graphite.pdb" /machine:I386 /out:"$(OUTDIR)\\$(TARGET).dll" /implib:"$(OUTDIR)\\$(TARGET).lib"
++--- misc/build/silgraphite-2.3/engine/configure.ac~	2008-01-15 10:57:55.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/configure.ac	2008-03-25 14:51:35.000000000 +0000
++@@ -56,7 +56,7 @@
++ # Enable debug
++ build_flags=""
++ if test "$enable_debug" = yes; then
++-  build_flags="$build_flags -O0 -g -Wall -Wno-unknown-pragmas -Wparentheses -Werror"
+++  build_flags="$build_flags -O0 -g -Wall -Wno-unknown-pragmas -Wparentheses"
++ else
++   build_flags="$build_flags -DNDEBUG"
++ fi
++--- misc/build/silgraphite-2.3/engine/src/segment/Segment.cpp~	2008-01-30 09:36:46.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/src/segment/Segment.cpp	2008-03-27 11:15:43.000000000 +0000
++@@ -1363,7 +1363,7 @@
++ 		ichTry++;
++ 	}
++ 
++-	if (ichTry >= m_ichwMin + m_dichwLim)
+++	if (ichBestBreak > -1 && ichTry >= m_ichwMin + m_dichwLim)
++ 	{
++ 		// Break at the end of the segment.
++ 		ichBreak = m_ichwMin + m_dichwLim;
++--- misc/build/silgraphite-2.3/engine/include/graphite/Segment.h	2007-11-24 20:37:07.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/include/graphite/Segment.h	2008-07-07 11:13:40.000000000 +0700
++@@ -203,7 +203,7 @@
++ //		m_psegNext = psegNext;
++ //	}
++ 
++-	void SetFaceName(std::wstring stu, std::wstring stuBase)
+++	void SetFaceName(std::wstring /*stu*/, std::wstring /*stuBase*/)
++ 	{
++ //		m_stuFaceName = stu;
++ //		m_stuBaseFaceName = stuBase;
++--- misc/build/silgraphite-2.3/engine/include/graphite/SegmentPainter.h	2008-01-10 14:41:13.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/include/graphite/SegmentPainter.h	2008-07-07 11:16:17.000000000 +0700
++@@ -53,8 +53,8 @@
++ 	virtual void setPosition(float xdPosition, float ydPosition);
++     virtual void setScalingFactors(float xFactor, float yFactor);
++ 
++-	virtual void setBuggyDisplayFormat(int strategy, long textColor, long backColor,
++-		long underlineColor)
+++	virtual void setBuggyDisplayFormat(int /*strategy*/, long /*textColor*/, long /*backColor*/,
+++		long /*underlineColor*/)
++ 	{
++ 		// Currently not implemented to do anything useful.
++ 	}
++@@ -197,7 +197,7 @@
++ 
++ 	// Low-level routines--these must be implemented appropriate by subclasses:
++ 
++-	virtual void InvertRect(float xLeft, float yTop, float xRight, float yBottom)
+++	virtual void InvertRect(float /*xLeft*/, float /*yTop*/, float /*xRight*/, float /*yBottom*/)
++ 	{
++ 		GrAssert(false); // no device context
++ 	}
++
++--- misc/build/silgraphite-2.3/engine/src/segment/GrSlotStream.cpp.orig	2007-11-24 13:37:08.000000000 +0000
+++++ misc/build/silgraphite-2.3/engine/src/segment/GrSlotStream.cpp	2008-08-28 19:48:22.796875000 +0100
++@@ -1094,6 +1094,7 @@
++ 	case kdircLRO:
++ 	case kdircLRE:
++ 	case kdircPdfL:
+++	case kdircLlb:
++ 		return false;
++ 
++ 	case kdircR:
++@@ -1103,9 +1104,17 @@
++ 	case kdircRLO:
++ 	case kdircRLE:
++ 	case kdircPdfR:
+++	case kdircRlb:
++ 		return true;
++ 
++ 	case kdircNeutral:
+++	case kdircWhiteSpace:
+++	case kdircComSep:
+++	case kdircEuroSep:
+++	case kdircEuroTerm:
+++	case kdircBndNeutral:
+++	case kdircNSM:
+++	case kdircPDF:
++ 		return false;
++ 
++ 	default:
++@@ -1970,7 +1979,12 @@
++ 	while (m_vislotNextChunkMap[islotRet] == -1 && islotRet < m_islotReadPos)
++ 	{
++ 		++islotRet;
++-		Assert(islotRet < signed(m_vislotNextChunkMap.size()));
+++		//Assert(islotRet < signed(m_vislotNextChunkMap.size()));
+++       if (islotRet >= signed(m_vislotNextChunkMap.size()))
+++ 		{
+++ 			islotRet = m_vislotNextChunkMap.size() - 1;
+++ 			break;
+++ 		}
++ 	}
++ 	return islotRet;
++ }
++--- misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp.orig	2008-09-27 19:58:12.937500000 +0630
+++++ misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp	2008-09-27 21:10:26.187500000 +0630
++@@ -722,6 +722,7 @@
++ WinFont::FontHandleCache::~FontHandleCache()
++ {
++ 	ResetFontCache();
+++	m_bValid = false;
++ }
++ 
++ /*----------------------------------------------------------------------------------------------
++@@ -767,7 +768,7 @@
++ ----------------------------------------------------------------------------------------------*/
++ void WinFont::FontHandleCache::DeleteFont(HFONT hfont)
++ {
++-	if (!hfont)
+++	if (!hfont || !m_bValid)
++ 		return;
++ 
++ 	// find the font in the hash map
++@@ -782,7 +782,7 @@
++ 			{
++ 				// delete font
++ 				::DeleteObject(hfont);
++-				m_hmlffcv.erase(it->first);
+++				m_hmlffcv.erase(it);
++ 			}
++ 			else
++ 			{
++--- misc/build/silgraphite-2.3/wrappers/win32/WinFont.h.orig	2008-09-29 10:14:03.453125000 +0630
+++++ misc/build/silgraphite-2.3/wrappers/win32/WinFont.h	2008-09-29 10:16:33.093750000 +0630
++@@ -199,7 +199,7 @@
++ 				return (hfont == val.hfont);
++ 			}
++ 		};
++-
+++		FontHandleCache() : m_bValid(true) {};
++ 		~FontHandleCache();
++ 
++ 		HFONT GetFont(LOGFONT & lf);
++@@ -209,7 +209,7 @@
++ 
++ 	protected:
++ 		FontHandleHashMap m_hmlffcv;
++-
+++		bool m_bValid;
++ 		void ResetFontCache(); // delete all the fonts in the cache
++ 	};
++ 
++--- misc/build/silgraphite-2.3/engine/test/RegressionTest/main.h~	2007-04-05 07:23:53.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/test/RegressionTest/main.h	2008-11-13 01:53:34.000000000 +0700
++@@ -34,7 +34,8 @@
++ #include <iostream>
++ #include <vector>
++ ////#include <algorithm>
++-#include <string>
+++#include <string>
+++#include <cstring>
++ #ifdef _WIN32
++ #include <crtdbg.h>
++ #endif // _WIN32
++ 
++--- misc/build/silgraphite-2.3/engine/src/font/TtfUtil.cpp.orig	2008-11-13 02:03:45.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/src/font/TtfUtil.cpp	2008-11-13 02:04:18.000000000 +0700
++@@ -21,6 +21,8 @@
++ #include <algorithm>
++ #include <cassert>
++ #include <cstddef>
+++#include <limits.h>
+++#include <cstring>
++ #include <stdexcept>
++ // Platform headers
++ // Module headers
++@@ -583,9 +585,9 @@
++ 			bool fNameFound = false;
++ 			int nLangId = read(pRecord->language_id);
++ 			int nNameId = read(pRecord->name_id);
++-			for (int i = 0; i < cNameIds; i++)
+++			for (int j = 0; j < cNameIds; j++)
++ 			{
++-				if (nNameId == nameIdList[i])
+++				if (nNameId == nameIdList[j])
++ 				{
++ 					fNameFound = true;
++ 					break;
++--- misc/build/silgraphite-2.3/engine/src/segment/GrEngine.cpp.orig	2008-11-13 02:08:13.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/src/segment/GrEngine.cpp	2008-11-13 02:08:36.000000000 +0700
++@@ -15,6 +15,7 @@
++ //:>	   Include files
++ //:>********************************************************************************************
++ #include "Main.h"
+++#include <cstring>
++ #include <functional>
++ #ifdef _MSC_VER
++ #pragma hdrstop
++--- misc/build/silgraphite-2.3/engine/src/segment/Main.h~	2007-11-24 20:37:08.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/src/segment/Main.h	2008-11-13 02:14:56.000000000 +0700
++@@ -51,6 +51,7 @@
++ #include <vector>
++ ////#include <algorithm>
++ #include <string>
+++#include <cstring>
++ 
++ // gAssert should be used for any kind of assertions that can be caused by a corrupted font,
++ // particularly those that won't be caught when loading the tables.
++--- misc/build/silgraphite-2.3/engine/test/ProfileHarness/ProfileHarness.cpp.orig	2008-11-13 02:23:37.000000000 +0700
+++++ misc/build/silgraphite-2.3/engine/test/ProfileHarness/ProfileHarness.cpp	2008-11-13 02:25:13.000000000 +0700
++@@ -22,6 +22,7 @@
++ #include <iomanip>
++ #include <string>
++ #include <sstream>
+++#include <cstring>
++ 
++ #include <graphite/GrClient.h>
++ #include <graphite/ITextSource.h>
++--- misc/build/silgraphite-2.3/engine/makefile.vc.orig	2008-11-17 22:14:39.562500000 +0630
+++++ misc/build/silgraphite-2.3/engine/makefile.vc	2008-11-17 22:14:44.781250000 +0630
++@@ -1,7 +1,7 @@
++ 
++ TARGET=graphite
++ 
++-!IF "$(COMEX)" == "11"
+++!IF "$(COMEX)" == "11" || "$(COMEX)" == "12"
++ WCHAR=/Zc:wchar_t-
++ !ELSE
++ WCHAR=
++--- misc/build/silgraphite-2.3/engine/makefile.vc.orig	2008-11-29 09:54:31.562500000 +0630
+++++ misc/build/silgraphite-2.3/engine/makefile.vc	2008-11-29 09:54:55.468750000 +0630
++@@ -29,7 +29,7 @@
++ SBREXT = .sbr
++ 
++ !IF "$(CFG)" == "DEBUG"
++-CPP_DEBUG=/D "DEBUG" /Gm /GR /ZI /Od /GZ /FR"$(INTDIR)\\" /$(MLIB)d
+++CPP_DEBUG=/D "DEBUG" /Gm /GR /ZI /Od /RTC1 /FR"$(INTDIR)\\" /$(MLIB)d
++ # CPP_DEBUG=/D "DEBUG" /Gm /GR /ZI /Od /GZ /FR"$(INTDIR)\\" /MDd
++ 
++ OUTDIR=.\debug
++--- misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp.orig.cc	2008-12-02 15:36:54.968750000 +0630
+++++ misc/build/silgraphite-2.3/wrappers/win32/WinFont.cpp	2008-12-02 15:37:29.046875000 +0630
++@@ -841,7 +841,7 @@
++ --------------------------------------------------------------------------------------*/
++ bool WinFont::LogFontWrapper::operator==(const WinFont::LogFontWrapper & lfw) const
++ {
++-	return memcmp(&m_lf, &(lfw.m_lf), sizeof(LOGFONT));
+++	return (memcmp(&m_lf, &(lfw.m_lf), sizeof(LOGFONT)) == 0);
++ }
++ 
++ 
++
+Index: graphite/makefile.mk
+===================================================================
+--- graphite/makefile.mk	(.../tags/DEV300_m35)	(Revision 0)
++++ graphite/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,160 @@
++#*************************************************************************
++#
++#   $RCSfile: graphite-makefile-mk.diff,v $
++#
++#   $Revision: 1.11 $
++#
++#   last change: $Author: rodo $ $Date: 2006/01/03 17:58:01 $
++#
++#   The Contents of this file are made available subject to the terms of
++#   either of the following licenses
++#
++#          - GNU Lesser General Public License Version 2.1
++#          - Sun Industry Standards Source License Version 1.1
++#
++#   Sun Microsystems Inc., October, 2000
++#
++#   GNU Lesser General Public License Version 2.1
++#   =============================================
++#   Copyright 2000 by Sun Microsystems, Inc.
++#   901 San Antonio Road, Palo Alto, CA 94303, USA
++#
++#   This library is free software; you can redistribute it and/or
++#   modify it under the terms of the GNU Lesser General Public
++#   License version 2.1, as published by the Free Software Foundation.
++#
++#   This library is distributed in the hope that it will be useful,
++#   but WITHOUT ANY WARRANTY; without even the implied warranty of
++#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++#   Lesser General Public License for more details.
++#
++#   You should have received a copy of the GNU Lesser General Public
++#   License along with this library; if not, write to the Free Software
++#   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++#   MA  02111-1307  USA
++#
++#
++#   Sun Industry Standards Source License Version 1.1
++#   =================================================
++#   The contents of this file are subject to the Sun Industry Standards
++#   Source License Version 1.1 (the "License"); You may not use this file
++#   except in compliance with the License. You may obtain a copy of the
++#   License at http://www.openoffice.org/license.html.
++#
++#   Software provided under this License is provided on an "AS IS" basis,
++#   WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
++#   WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
++#   MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
++#   See the License for the specific provisions governing your rights and
++#   obligations concerning the Software.
++#
++#   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
++#
++#   Copyright: 2000 by Sun Microsystems, Inc.
++#
++#   All Rights Reserved.
++#
++#   Contributor(s): _______________________________________
++#
++#
++#
++#*************************************************************************
++
++PRJ=.
++
++PRJNAME=graphite
++TARGET=so_graphite
++
++# --- Settings -----------------------------------------------------
++
++.INCLUDE :	settings.mk
++
++# --- Files --------------------------------------------------------
++
++TARFILE_NAME=silgraphite-2.3
++PATCH_FILE_NAME=graphite-2.3.patch
++
++#.IF "$(OS)"=="WNT" && "$(COM)"!="GCC"
++#CONFIGURE_DIR=win32
++#.ELSE
++#CONFIGURE_DIR=engine
++#.ENDIF
++
++CONFIGURE_DIR=engine
++
++.IF "$(COM)"=="MSC"
++# make use of stlport headerfiles
++EXT_USE_STLPORT=TRUE
++BUILD_ACTION=nmake
++.IF "$(debug)"=="true"
++BUILD_FLAGS= "CFG=DEBUG" "MLIB=MD" /F makefile.vc dll
++.ELSE
++BUILD_FLAGS="MLIB=MD" /F makefile.vc dll
++.ENDIF
++.ENDIF
++
++.IF "$(COM)"=="GCC"
++
++# Does linux want --disable-shared?
++.IF "$(debug)"=="true"
++CONFIGURE_FLAGS= --enable-debug --enable-static --disable-shared
++.ELSE
++CONFIGURE_FLAGS= --enable-final --enable-static --disable-shared
++.ENDIF
++EXTRA_GR_CXX_FLAGS=-fPIC
++
++# don't use SOLARLIB for LDFLAGS because it pulls in system graphite so build will fail
++CONFIGURE_ACTION=bash -c 'CXXFLAGS="$(INCLUDE) $(CFLAGSCXX) $(CFLAGSCOBJ) $(CDEFS) $(CDEFSOBJ) $(SOLARINC) $(LFS_CFLAGS) $(EXTRA_GR_CXX_FLAGS)" LDFLAGS="-L$(SOLARVERSION)/$(INPATH)/lib" ./configure $(CONFIGURE_FLAGS)'
++.ENDIF
++
++BUILD_DIR=$(CONFIGURE_DIR)
++
++.IF "$(OS)"=="WNT" && "$(COM)"!="GCC"
++#OUT2LIB=win32$/bin.msvc$/*.lib
++.IF "$(debug)"=="true"
++OUT2LIB=engine$/debug$/*.lib
++.ELSE
++OUT2LIB=engine$/release$/*.lib
++.ENDIF
++.ELSE
++OUT2LIB=engine$/src$/.libs$/libgraphite*.a
++.ENDIF
++
++.IF "$(COM)"=="GCC"
++BUILD_ACTION=$(GNUMAKE) -j$(EXTMAXPROCESS) EXT_USE_STLPORT=TRUE
++.ENDIF
++
++.IF "$(OS)"=="MACOSX"
++OUT2LIB+=src$/.libs$/libgraphite.*.dylib
++.ELSE
++.IF "$(OS)"=="WNT"
++#OUT2LIB+=engine$/src$/.libs$/libgraphite*.dll
++.IF "$(debug)"=="true"
++OUT2BIN= \
++    engine$/debug$/*.dll \
++    engine$/debug$/*.pdb
++.ELSE
++OUT2BIN= \
++    engine$/release$/*.dll
++#    engine$/release$/*.pdb
++.ENDIF
++.ELSE
++#OUT2LIB+=engine$/src$/.libs$/libgraphite.so.*.*.*
++.ENDIF
++.ENDIF
++
++
++OUTDIR2INC= \
++	engine$/include$/graphite
++
++.IF "$(OS)"=="WNT"
++OUT2INC=wrappers$/win32$/WinFont.h
++.ENDIF
++
++# --- Targets ------------------------------------------------------
++
++
++.INCLUDE :	set_ext.mk
++.INCLUDE :	target.mk
++.INCLUDE :	tg_ext.mk
++
+Index: graphite/download/silgraphite-2.3.tar.gz
+===================================================================
+Kann nicht anzeigen: Dateityp ist als binÃr angegeben.
+svn:mime-type = application/octet-stream
+
+EigenschaftsÃnderungen: graphite/download/silgraphite-2.3.tar.gz
+___________________________________________________________________
+HinzugefÃgt: svn:executable
+   + *
+HinzugefÃgt: svn:mime-type
+   + application/octet-stream
+
+Index: graphite/download/Readme.txt
+===================================================================
+--- graphite/download/Readme.txt	(.../tags/DEV300_m35)	(Revision 0)
++++ graphite/download/Readme.txt	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,15 @@
++The Graphite library is free software; you can redistribute it and/or modify
++    it under the terms of either:
++
++	a) the Common Public License as published by the "Agreement
++         Steward" for that license (currently IBM); either version 0.5
++         of the License, or (at your option) any later version,
++
++    or
++
++	b) the GNU Lesser General Public License as published by the
++         Free Software Foundation; either version 2.1 of License, or
++         (at your option) any later version.
++
++Download source tarball of silgraphite-version.tar.gz from http://sf.net/projects/silgraphite
++Place the downloaded tar ball in this directory.
+Index: graphite/prj/build.lst
+===================================================================
+--- graphite/prj/build.lst	(.../tags/DEV300_m35)	(Revision 0)
++++ graphite/prj/build.lst	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,3 @@
++gr	graphite	:	stlport solenv NULL
++gr	graphite		usr1	-	all	gr_mkout NULL
++gr	graphite		nmake	-	all	gr_graphite NULL
+Index: graphite/prj/d.lst
+===================================================================
+--- graphite/prj/d.lst	(.../tags/DEV300_m35)	(Revision 0)
++++ graphite/prj/d.lst	(.../cws/graphite01)	(Revision 265804)
+@@ -0,0 +1,15 @@
++mkdir: %_DEST%\inc%_EXT%\graphite
++..\%__SRC%\inc\graphite\*.h %_DEST%\inc%_EXT%\graphite\*.h
++..\%__SRC%\inc\WinFont.h %_DEST%\inc%_EXT%\graphite\WinFont.h
++
++..\%__SRC%\lib\*.so.* %_DEST%\lib%_EXT%\*.so.*
++..\%__SRC%\lib\*.dylib %_DEST%\lib%_EXT%\*.dylib
++..\%__SRC%\lib\*.a %_DEST%\lib%_EXT%\*.a
++..\%__SRC%\lib\*.lib %_DEST%\lib%_EXT%\*.lib
++..\%__SRC%\bin\*.dll %_DEST%\bin%_EXT%\*.dll
++..\%__SRC%\bin\*.pdb %_DEST%\bin%_EXT%\*.pdb
++..\%__SRC%\lib\graphite.lib %_DEST%\lib%_EXT%\graphite.lib
++
++linklib: libgraphite.so.*.*.*
++linklib: libgraphite.dylib.*.*.*
++#linklib: graphite.*
+
+EigenschaftsÃnderungen: graphite
+___________________________________________________________________
+HinzugefÃgt: svn:ignore
+   + unxlngs390x unxlngi6 unxlngmips unxirxm3 unxfbsd.pro unxols4 unxirxm3.pro unxsogi.pro unxlngp unxsoli4.pro common.pro unxlngppc64.pro unxubit8.pro wntmsci12 unxlngx6.pro unxsogi unxlngr unxols4.pro unxsols4 unxfbsdx unxhpxr unxlngs.pro unxsoli4 unxbsds.pro unxaixp.pro unxlngx6 unxlngppc4 unxfbsd unxbsds unxmacxp unxbsdi2 common unxlngr.pro unxirgm unxbsdi.pro unxbsda.pro unxirgm.pro unxsolu4.pro unxlngppc.pro unxhpgr.pro unxlngs3904 unxaixp unxsolu4 unxlngm68k unxlnga unxmacxi.pro unxirxm unxlngppc4.pro unxsols4.pro unxfbsdi unxmacxi wntmsci12.pro unxlngs390x.pro unxlngmips.pro unxhpgr unxirxm.pro unxmacxp.pro unxlngppc unxfbsdx.pro unxlnxi.pro unxlnxi unxubit8 unxhpxr.pro unxlngppc64 unxfbsdi.pro unxlngs3904.pro unxlngi6.pro unxlngp.pro unxlngs unxbsdi2.pro unxbsdi unxlnga.pro unxbsda unxsogs.pro unxsogs unxlngm68k.pro 
+
+
+Index: scp2/source/ooo/shortcut_ooo.scp
+===================================================================
+--- scp2/source/ooo/shortcut_ooo.scp	(.../tags/DEV300_m35)	(Revision 265804)
++++ scp2/source/ooo/shortcut_ooo.scp	(.../cws/graphite01)	(Revision 265804)
+@@ -116,6 +116,28 @@
+ End
+ 
+ #endif
++
++Shortcut gid_Shortcut_Lib_Graphite_0
++    FileID = gid_File_Lib_Graphite;
++    Dir = gid_Dir_Program;
++    Name = STRING(CONCAT2(libgraphite,UNXSUFFIX));
++    Styles = (NETWORK,RELATIVE);
++End
++
++Shortcut gid_Shortcut_Lib_Graphite_1
++    FileID = gid_File_Lib_Graphite;
++    Dir = gid_Dir_Program;
++    Name = STRING(CONCAT4(libgraphite,UNXSUFFIX,.,3));
++    Styles = (NETWORK,RELATIVE);
++End
++
++Shortcut gid_Shortcut_Lib_Graphite_2
++    FileID = gid_File_Lib_Graphite;
++    Dir = gid_Dir_Program;
++    Name = STRING(CONCAT4(libgraphite,UNXSUFFIX,.,3.0));
++    Styles = (NETWORK,RELATIVE);
++End
++
+ #endif
+ 
+ #ifdef MACOSX
+Index: canvas/source/directx/makefile.mk
+===================================================================
+--- canvas/source/directx/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/directx/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -96,7 +96,7 @@
+ 	$(SLO)$/dx_canvas.obj
+ GDIPLUS_SLOFILES += $(SHARED_SLOFILES)
+ 
+-STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB)
++STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB)
+ 
+ 
+ ########################################################
+@@ -194,7 +194,7 @@
+ SHL3TARGET=$(TARGET3).uno
+ 
+ # Links import libraries.
+-SHL3STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB)
++SHL3STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB)
+ 
+ # Specifies an import library to create. For Win32 only.
+ SHL3IMPLIB=i$(TARGET3).lib
+Index: canvas/source/directx/dx_textlayout_drawhelper.cxx
+===================================================================
+--- canvas/source/directx/dx_textlayout_drawhelper.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/directx/dx_textlayout_drawhelper.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -52,6 +52,7 @@
+ #include <canvas/debug.hxx>
+ #include "dx_impltools.hxx"
+ #include <vcl/sysdata.hxx>
++#include <i18npool/mslangid.hxx>
+ #include "dx_textlayout_drawhelper.hxx"
+ #include "dx_bitmap.hxx"
+ #include "dx_canvasfont.hxx"
+@@ -135,6 +136,8 @@
+             aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+             aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
+ 
++            aFont.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale));
++
+             // setup font color
+             aFont.SetColor( aColor );
+             aFont.SetFillColor( aColor );
+Index: canvas/source/vcl/makefile.mk
+===================================================================
+--- canvas/source/vcl/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/vcl/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -73,7 +73,7 @@
+ 
+ SHL1TARGET=$(TARGET).uno
+ 
+-SHL1STDLIBS= $(TOOLSLIB) $(TKLIB) $(CPPULIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(GOODIESLIB)
++SHL1STDLIBS= $(TOOLSLIB) $(TKLIB) $(CPPULIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(GOODIESLIB) $(I18NISOLANGLIB)
+ 
+ SHL1IMPLIB=i$(TARGET)
+ SHL1LIBS=$(SLB)$/$(TARGET).lib
+Index: canvas/source/vcl/canvasfont.cxx
+===================================================================
+--- canvas/source/vcl/canvasfont.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/vcl/canvasfont.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -35,7 +35,7 @@
+ 
+ #include <rtl/math.hxx>
+ #include <basegfx/numeric/ftools.hxx>
+-
++#include <i18npool/mslangid.hxx>
+ #include <vcl/metric.hxx>
+ 
+ #include "canvasfont.hxx"
+@@ -67,6 +67,8 @@
+         maFont->SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+         maFont->SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
+ 
++		maFont->SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale));
++
+         // adjust to stretched/shrinked font
+         if( !::rtl::math::approxEqual( rFontMatrix.m00, rFontMatrix.m11) )
+         {
+Index: canvas/source/cairo/cairo_canvasfont.cxx
+===================================================================
+--- canvas/source/cairo/cairo_canvasfont.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/cairo/cairo_canvasfont.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -37,6 +37,7 @@
+ #include <basegfx/numeric/ftools.hxx>
+ 
+ #include <vcl/metric.hxx>
++#include <i18npool/mslangid.hxx>
+ 
+ #include "cairo_canvasfont.hxx"
+ #include "cairo_textlayout.hxx"
+@@ -86,6 +87,8 @@
+         maFont->SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+         maFont->SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
+ 
++        maFont->SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale));
++
+         // adjust to stretched/shrinked font
+         if( !::rtl::math::approxEqual( rFontMatrix.m00, rFontMatrix.m11) )
+         {
+Index: canvas/source/cairo/makefile.mk
+===================================================================
+--- canvas/source/cairo/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ canvas/source/cairo/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -84,7 +84,7 @@
+ 
+ SHL1TARGET=$(TARGET).uno
+ 
+-SHL1STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(TOOLSLIB)
++SHL1STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(TOOLSLIB) $(I18NISOLANGLIB)
+ 
+ .IF "$(GUI)"=="UNX" 
+ 
+Index: svx/source/editeng/impedit2.cxx
+===================================================================
+--- svx/source/editeng/impedit2.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svx/source/editeng/impedit2.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -1674,7 +1674,7 @@
+ 		::rtl::OUString aOUText( aText );
+ 		USHORT nTextLen = (USHORT)aOUText.getLength();
+ 
+-		long nPos = 0;
++		sal_Int32 nPos = 0;
+ 		short nScriptType = _xBI->getScriptType( aOUText, nPos );
+ 		rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() );
+ 		nPos = _xBI->endOfScript( aOUText, nPos, nScriptType );
+@@ -1705,6 +1705,17 @@
+             }
+             else
+             {
++                if ( _xBI->getScriptType( aOUText, nPos - 1 ) == i18n::ScriptType::WEAK )
++                {
++                    switch ( u_charType(aOUText.iterateCodePoints(&nPos, 0) ) ) {
++                    case U_NON_SPACING_MARK:
++                    case U_ENCLOSING_MARK:
++                    case U_COMBINING_SPACING_MARK:
++                        --nPos;
++                        rTypes[rTypes.Count()-1].nEndPos--;
++                        break;
++                    }
++                }
+ 			    rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() );
+             }
+ 
+Index: svx/source/dialog/chardlg.hxx
+===================================================================
+--- svx/source/dialog/chardlg.hxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svx/source/dialog/chardlg.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -70,6 +70,7 @@
+ 
+ 	void				SetPrevFontSize( const SfxItemSet& rSet, USHORT nSlot, SvxFont& rFont );
+ 	void				SetPrevFont( const SfxItemSet& rSet, USHORT nSlot, SvxFont& rFont );
++	void				SetPrevFontLang( const SfxItemSet& rSet, USHORT nSlot, SvxFont& rFont );
+ 	void				SetPrevFontStyle( const SfxItemSet& rSet, USHORT nSlotPosture, USHORT nSlotWeight, SvxFont& rFont ); // posture/weight
+ 	void				SetPrevFontWidthScale( const SfxItemSet& rSet );
+ 
+Index: svx/source/dialog/chardlg.cxx
+===================================================================
+--- svx/source/dialog/chardlg.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svx/source/dialog/chardlg.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -393,6 +393,11 @@
+ 	SetPrevFont( rSet, SID_ATTR_CHAR_CJK_FONT, rCJKFont );
+ 	SetPrevFont( rSet, SID_ATTR_CHAR_CTL_FONT, rCTLFont );
+ 
++	SetPrevFontLang( rSet, SID_ATTR_CHAR_LANGUAGE, rFont );
++	SetPrevFontLang( rSet, SID_ATTR_CHAR_CJK_LANGUAGE, rCJKFont );
++	SetPrevFontLang( rSet, SID_ATTR_CHAR_CTL_LANGUAGE, rCTLFont );
++
++
+ 	// Style
+ 	SetPrevFontStyle( rSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, rFont );
+ 	SetPrevFontStyle( rSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, rCJKFont );
+@@ -494,6 +499,21 @@
+ 
+ // -----------------------------------------------------------------------
+ 
++void SvxCharBasePage::SetPrevFontLang( const SfxItemSet& rSet, USHORT nSlot, SvxFont& rFont )
++{
++	USHORT nWhich = GetWhich( nSlot );
++	if( ISITEMSET )
++	{
++		const SvxLanguageItem& rItem = ( SvxLanguageItem& ) rSet.Get( nWhich );
++		LanguageType eLangType = (LanguageType)rItem.GetValue();
++		DBG_ASSERT( eLangType != LANGUAGE_SYSTEM, "LANGUAGE_SYSTEM not allowed" );
++		if ( eLangType != LANGUAGE_DONTKNOW )
++			rFont.SetLanguage( eLangType );
++	}
++}
++
++// -----------------------------------------------------------------------
++
+ void SvxCharBasePage::SetPrevFontStyle( const SfxItemSet& rSet, USHORT nPosture, USHORT nWeight, SvxFont& rFont )
+ {
+ 	USHORT nWhich = GetWhich( nPosture );
+@@ -777,12 +797,15 @@
+     m_pWestFontNameLB->SetModifyHdl( aLink );
+     m_pWestFontStyleLB->SetModifyHdl( aLink );
+     m_pWestFontSizeLB->SetModifyHdl( aLink );
++    m_pWestFontLanguageLB->SetSelectHdl( aLink );
+     m_pEastFontNameLB->SetModifyHdl( aLink );
+     m_pEastFontStyleLB->SetModifyHdl( aLink );
+     m_pEastFontSizeLB->SetModifyHdl( aLink );
++    m_pEastFontLanguageLB->SetSelectHdl( aLink );
+     m_pCTLFontNameLB->SetModifyHdl( aLink );
+     m_pCTLFontStyleLB->SetModifyHdl( aLink );
+     m_pCTLFontSizeLB->SetModifyHdl( aLink );
++    m_pCTLFontLanguageLB->SetSelectHdl( aLink );
+ 
+ 	m_pImpl->m_aUpdateTimer.SetTimeoutHdl( LINK( this, SvxCharNamePage, UpdateHdl_Impl ) );
+ 
+@@ -831,8 +854,10 @@
+ 					const FontNameBox* _pFontNameLB,
+ 					const FontStyleBox* _pFontStyleLB,
+ 					const FontSizeBox* _pFontSizeLB,
++					const SvxLanguageBox* _pFontLangLB,
+ 					const FontList* _pFontList,
+ 					USHORT _nFontWhich,
++					USHORT _nFontLangWhich,
+ 					USHORT _nFontHeightWhich)
+ 	{
+ 		Size aSize = _rFont.GetSize();
+@@ -856,6 +881,24 @@
+ 				aFontInfo.SetCharSet(pFontItem->GetCharSet());
+ 			}
+ 		}
++                if (_pFontLangLB->GetSavedValue() != _pFontLangLB->GetSelectEntryPos() && _pFontLangLB->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND)
++		{
++			USHORT nLangPos = _pFontLangLB->GetSelectEntryPos();
++			LanguageType eLangType = (LanguageType)(ULONG)_pFontLangLB->GetEntryData( nLangPos );
++			aFontInfo.SetLanguage(eLangType);
++		}
++		else
++		{
++			SfxItemState eState = _pPage->GetItemSet().GetItemState( _nFontLangWhich );
++			if ( eState >= SFX_ITEM_DEFAULT )
++			{
++				const SvxLanguageItem* pLangItem = (const SvxLanguageItem*)&(_pPage->GetItemSet().Get( _nFontLangWhich ));
++				LanguageType eLangType = (LanguageType)pLangItem->GetValue();
++				DBG_ASSERT( eLangType != LANGUAGE_SYSTEM, "LANGUAGE_SYSTEM not allowed" );
++				if ( eLangType != LANGUAGE_DONTKNOW )
++					aFontInfo.SetLanguage(eLangType);
++			}
++		}
+ 		if ( _pFontSizeLB->IsRelative() )
+ 		{
+ 			DBG_ASSERT( _pPage->GetItemSet().GetParent(), "No parent set" );
+@@ -886,6 +929,7 @@
+ 		_rFont.SetWeight( aFontInfo.GetWeight() );
+ 		_rFont.SetItalic( aFontInfo.GetItalic() );
+ 		_rFont.SetSize( aFontInfo.GetSize() );
++		_rFont.SetLanguage( aFontInfo.GetLanguage() );
+ 
+ 		return aFontInfo;
+ 	}
+@@ -908,11 +952,11 @@
+ 	// Font
+ 	const FontList* pFontList = GetFontList();
+ 	FontInfo aFontInfo =
+-		calcFontInfo(rFont,this,m_pWestFontNameLB,m_pWestFontStyleLB,m_pWestFontSizeLB,pFontList,GetWhich( SID_ATTR_CHAR_FONT ),GetWhich( SID_ATTR_CHAR_FONTHEIGHT ));
++		calcFontInfo(rFont,this,m_pWestFontNameLB,m_pWestFontStyleLB,m_pWestFontSizeLB,m_pWestFontLanguageLB,pFontList,GetWhich( SID_ATTR_CHAR_FONT ),GetWhich( SID_ATTR_CHAR_LANGUAGE ),GetWhich( SID_ATTR_CHAR_FONTHEIGHT ));
+ 
+-	calcFontInfo(rCJKFont,this,m_pEastFontNameLB,m_pEastFontStyleLB,m_pEastFontSizeLB,pFontList,GetWhich( SID_ATTR_CHAR_CJK_FONT ),GetWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT ));
++	calcFontInfo(rCJKFont,this,m_pEastFontNameLB,m_pEastFontStyleLB,m_pEastFontSizeLB,m_pEastFontLanguageLB,pFontList,GetWhich( SID_ATTR_CHAR_CJK_FONT ),GetWhich( SID_ATTR_CHAR_CJK_LANGUAGE ),GetWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT ));
+ 
+-	calcFontInfo(rCTLFont,this,m_pCTLFontNameLB,m_pCTLFontStyleLB,m_pCTLFontSizeLB,pFontList,GetWhich( SID_ATTR_CHAR_CTL_FONT ),GetWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT ));
++	calcFontInfo(rCTLFont,this,m_pCTLFontNameLB,m_pCTLFontStyleLB,m_pCTLFontSizeLB,m_pCTLFontLanguageLB,pFontList,GetWhich( SID_ATTR_CHAR_CTL_FONT ),GetWhich( SID_ATTR_CHAR_CTL_LANGUAGE ),GetWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT ));
+ 
+     m_aPreviewWin.Invalidate();
+     m_aFontTypeFT.SetText( pFontList->GetFontMapText( aFontInfo ) );
+Index: svx/source/dialog/fntctrl.cxx
+===================================================================
+--- svx/source/dialog/fntctrl.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svx/source/dialog/fntctrl.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -36,6 +36,7 @@
+ #include <sfx2/printer.hxx>		// SfxPrinter
+ #include <vcl/metric.hxx>
+ #include <vcl/svapp.hxx>
++#include <unicode/uchar.h>
+ #include <com/sun/star/uno/Reference.h>
+ #include <com/sun/star/i18n/XBreakIterator.hpp>
+ #include <com/sun/star/lang/XMultiServiceFactory.hpp>
+@@ -244,7 +245,25 @@
+         do
+         {
+             nChg = (xub_StrLen)xBreak->endOfScript( aText, nChg, nScript );
+-            aScriptChg.Insert( nChg, nCnt );
++            if (nChg < aText.Len() && nChg > 0 &&
++                (com::sun::star::i18n::ScriptType::WEAK ==
++                 xBreak->getScriptType(aText, nChg - 1)))
++            {
++                int8_t nType = u_charType(aText.GetChar(nChg) );
++                if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
++                    nType == U_COMBINING_SPACING_MARK )
++                {
++                    aScriptChg.Insert( nChg - 1, nCnt );
++                }
++                else
++                {
++                    aScriptChg.Insert( nChg, nCnt );
++                }
++            }
++            else
++            {
++                aScriptChg.Insert( nChg, nCnt );
++            }
+             aScriptType.Insert( nScript, nCnt );
+             aTextWidth.Insert( ULONG(0), nCnt++ );
+ 
+Index: svx/inc/svx/svxfont.hxx
+===================================================================
+--- svx/inc/svx/svxfont.hxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svx/inc/svx/svxfont.hxx	(.../cws/graphite01)	(Revision 265804)
+@@ -70,7 +70,8 @@
+ 	inline void    SetCaseMap( const SvxCaseMap eNew ) { eCaseMap = eNew; }
+ 
+ 	inline LanguageType GetLanguage() const { return eLang; }
+-	inline void SetLanguage( const LanguageType eNewLan ) { eLang = eNewLan; }
++	inline void SetLanguage( const LanguageType eNewLan )
++		{ eLang = eNewLan;  Font::SetLanguage(eNewLan); }
+ 
+ 	// Is-Methoden:
+ 	inline BOOL IsCaseMap() const { return SVX_CASEMAP_NOT_MAPPED != eCaseMap; }
+Index: svtools/source/control/ctrltool.cxx
+===================================================================
+--- svtools/source/control/ctrltool.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ svtools/source/control/ctrltool.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -161,7 +161,11 @@
+ 
+ static void ImplMakeSearchStringFromName( XubString& rStr )
+ {
+-	rStr = rStr.GetToken( 0, ';' );
++    // check for features before alternate font separator
++    if (rStr.Search(':') < rStr.Search(';'))
++        rStr = rStr.GetToken( 0, ':' );
++    else
++        rStr = rStr.GetToken( 0, ';' );
+ 	ImplMakeSearchString( rStr );
+ }
+ 
+Index: cppcanvas/source/mtfrenderer/implrenderer.cxx
+===================================================================
+--- cppcanvas/source/mtfrenderer/implrenderer.cxx	(.../tags/DEV300_m35)	(Revision 265804)
++++ cppcanvas/source/mtfrenderer/implrenderer.cxx	(.../cws/graphite01)	(Revision 265804)
+@@ -83,6 +83,7 @@
+ #include <vcl/metric.hxx>
+ #include <vcl/graphictools.hxx>
+ #include <tools/poly.hxx>
++#include <i18npool/mslangid.hxx>
+ 
+ #include <implrenderer.hxx>
+ #include <tools.hxx>
+@@ -963,6 +964,9 @@
+                 rParms.mrParms.maFontLetterForm.getValue() :
+                 (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9;
+ 
++            LanguageType aLang = rFont.GetLanguage();
++            aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false);
++
+             // setup state-local text transformation,
+             // if the font be rotated
+             const short nFontAngle( rFont.GetOrientation() );
+Index: cppcanvas/util/makefile.mk
+===================================================================
+--- cppcanvas/util/makefile.mk	(.../tags/DEV300_m35)	(Revision 265804)
++++ cppcanvas/util/makefile.mk	(.../cws/graphite01)	(Revision 265804)
+@@ -50,7 +50,7 @@
+ 
+ SHL1TARGET= 	$(TARGET)$(DLLPOSTFIX)
+ SHL1IMPLIB= 	i$(TARGET)
+-SHL1STDLIBS=	$(TOOLSLIB) $(CPPULIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CANVASTOOLSLIB) $(CPPUHELPERLIB) $(BASEGFXLIB)
++SHL1STDLIBS=	$(TOOLSLIB) $(CPPULIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CANVASTOOLSLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(I18NISOLANGLIB)
+ 
+ SHL1LIBS=		$(SLB)$/$(TARGET).lib
+ 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]