[ooo-build-commit] Branch 'ooo/master' - canvas/source cppcanvas/source cppcanvas/util svtools/source vcl/inc vcl/prj vcl/source vcl/unx vcl/util vcl/win

Jan Holesovsky kendy at kemper.freedesktop.org
Mon Aug 17 18:27:25 PDT 2009


 canvas/source/cairo/cairo_canvasfont.cxx           |    3 
 canvas/source/cairo/makefile.mk                    |    2 
 canvas/source/directx/dx_textlayout_drawhelper.cxx |    3 
 canvas/source/directx/makefile.mk                  |    4 
 canvas/source/vcl/canvasfont.cxx                   |    4 
 canvas/source/vcl/makefile.mk                      |    2 
 cppcanvas/source/mtfrenderer/implrenderer.cxx      |    4 
 cppcanvas/util/makefile.mk                         |    2 
 svtools/source/control/ctrltool.cxx                |    6 
 vcl/inc/vcl/graphite_adaptors.hxx                  |  154 ++
 vcl/inc/vcl/graphite_cache.hxx                     |  265 ++++
 vcl/inc/vcl/graphite_features.hxx                  |   77 +
 vcl/inc/vcl/graphite_layout.hxx                    |  167 ++
 vcl/inc/vcl/graphite_serverfont.hxx                |  103 +
 vcl/prj/build.lst                                  |    2 
 vcl/source/gdi/makefile.mk                         |    3 
 vcl/source/gdi/outdev3.cxx                         |   67 -
 vcl/source/gdi/sallayout.cxx                       |  140 +-
 vcl/source/glyphs/gcach_ftyp.cxx                   |   14 
 vcl/source/glyphs/glyphcache.cxx                   |   26 
 vcl/source/glyphs/graphite_adaptors.cxx            |  327 +++++
 vcl/source/glyphs/graphite_cache.cxx               |  198 +++
 vcl/source/glyphs/graphite_features.cxx            |  289 ++++
 vcl/source/glyphs/graphite_layout.cxx              | 1367 +++++++++++++++++++++
 vcl/source/glyphs/graphite_serverfont.cxx          |   88 +
 vcl/source/glyphs/graphite_textsrc.cxx             |  172 ++
 vcl/source/glyphs/graphite_textsrc.hxx             |  131 ++
 vcl/source/glyphs/makefile.mk                      |   21 
 vcl/unx/inc/salgdi.h                               |    2 
 vcl/unx/source/gdi/makefile.mk                     |    4 
 vcl/unx/source/gdi/pspgraphics.cxx                 |   48 
 vcl/unx/source/gdi/salgdi.cxx                      |    7 
 vcl/unx/source/gdi/salgdi3.cxx                     |   27 
 vcl/util/makefile.mk                               |   26 
 vcl/win/inc/salgdi.h                               |    6 
 vcl/win/source/gdi/MAKEFILE.MK                     |    4 
 vcl/win/source/gdi/salgdi3.cxx                     |   15 
 vcl/win/source/gdi/winlayout.cxx                   |  307 ++++
 vcl/win/source/window/MAKEFILE.MK                  |    4 
 39 files changed, 4039 insertions(+), 52 deletions(-)

New commits:
commit b7e34c7ff46610e89febe417156098247d47e61a
Author: Ivo Hinkelmann <ihi at openoffice.org>
Date:   Mon Aug 17 14:12:14 2009 +0000

    CWS-TOOLING: integrate CWS graphite01
    2009-08-06 11:09:01 +0200 hdu  r274708 : #i10000# fix build breaker for SYSTEM_GRAPHITE=NO
    2009-07-21 12:01:52 +0200 hdu  r274174 : #i93645# fix include files for EXT_USE_STLPORT
    2009-07-21 11:51:07 +0200 hdu  r274173 : #i93645# convert line-endings of files to be patched
    2009-07-21 10:49:01 +0200 hdu  r274170 : #i93645# adjust makefile.vc8 for HH-RelEng env (thanks ause)
    2009-07-20 05:21:32 +0200 kstribley  r274105 : attempt to fix Windows build error caused by NULL variable in nmake file
    2009-07-16 10:22:36 +0200 hdu  r274032 : #i69129# also use solar minor version to find graphite lib
    2009-07-16 05:36:06 +0200 kstribley  r274029 : allow windows build to have Graphite disabled with SAL_DISABLE_GRAPHITE
    2009-07-15 13:59:22 +0200 hdu  r274011 : #i69129# default to ENABLE_GRAPHITE=TRUE
    2009-07-15 13:19:54 +0200 hdu  r274008 : #i93645# ignore compile warnings for graphite
    2009-07-15 13:18:25 +0200 hdu  r274006 : #i93645# stlport needs libmath, use solar minor version to find matching libs
    2009-07-15 09:21:13 +0200 hdu  r273989 : #i100000# avoid compile warning
    2009-07-14 12:19:08 +0200 hdu  r273963 : CWS-TOOLING: rebase CWS graphite01 to trunk at 273858 (milestone: DEV300:m52)
    2009-07-13 06:54:56 +0200 kstribley  r273912 : change to use standard file headers
    2009-07-13 05:39:14 +0200 kstribley  r273911 : Remove unnecessary change to configure.in as reported by Rene
    2009-07-10 16:58:44 +0200 hdu  r273902 : #i100000# fix compile for precompiled-header support
    2009-07-02 13:48:26 +0200 kstribley  r273647 : #69129# fix a graphite bug which could crash with fonts containing obscure GDL positioning rules
    2009-07-02 01:44:02 +0200 rene  r273616 : #i10000# we need to link with -licuuc
    2009-07-01 04:02:20 +0200 kstribley  r273540 : restore missing sdf files from base
    2009-07-01 04:01:40 +0200 kstribley  r273539 : restore missing sdf files from base
    2009-07-01 04:01:12 +0200 kstribley  r273538 : restore missing sdf files from base
    2009-07-01 03:59:41 +0200 kstribley  r273537 : restore missing sdf files from base
    2009-06-29 10:16:51 +0200 kstribley  r273456 : #i69129# fixes a bug which caused occasional incorrect linebreaking when graphite is asked to render a part of a cluster not containing a base
    2009-06-27 10:43:58 +0200 kstribley  r273445 : #i69129# added kashida support for justified RTL text
    2009-06-01 12:57:06 +0200 kstribley  r272476 : CWS-TOOLING: rebase CWS graphite01 to trunk at 272291 (milestone: DEV300:m49)
    2009-05-26 10:50:06 +0200 kstribley  r272286 : #i69129# fixes a build error when NDEBUG is not defined
    2009-05-25 13:14:06 +0200 kstribley  r272237 : #i69129# enable debugging by fixing compile warnings
    2009-05-25 13:07:47 +0200 kstribley  r272234 : #i69129#  added env variable to disable GRAPHITE at run time on linux and fixed a bug with a rare attachment sequence
    2009-04-20 17:39:25 +0200 kstribley  r271001 : CWS-TOOLING: rebase CWS graphite01 to trunk at 270723 (milestone: DEV300:m46)
    2009-04-18 07:11:33 +0200 kstribley  r270957 : #i101178# attempt to fix buildbot builds by reordering configure.in
    2009-04-14 17:37:07 +0200 kstribley  r270801 : #i93645# tweak configure to enable graphite by default on windows and linux to assist testing with tinderbox build
    2009-04-14 16:33:17 +0200 kstribley  r270796 : #i96925# another fix for rtl fallback and add optional debug info in MultiSalLayout
    2009-04-08 13:27:55 +0200 kstribley  r270641 : #i69129# fix features after a bad merge
    2009-04-08 13:26:34 +0200 kstribley  r270640 : #i69129# add a patch for WinFont
    2009-03-24 12:37:54 +0100 kstribley  r269937 : #i69129# fix build error due to locale being included in method for features
    2009-03-24 12:36:10 +0100 kstribley  r269936 : #i93645# change patch variable and fix configure
    2009-03-20 04:18:56 +0100 kstribley  r269776 : CWS-TOOLING: rebase CWS graphite01 to trunk at 269297 (milestone: DEV300:m43)
    2009-03-01 13:10:59 +0100 kstribley  r268622 : added a patch to improve handling of a font with bad graphite language feature tables #i93645#
    2009-02-12 04:50:51 +0100 kstribley  r267631 : #i93645# fix windows build for graphite 2.3.1 and remove unnecessary patch
    2009-02-10 04:48:50 +0100 kstribley  r267535 : #i93645# fix a build error with stlport on Ubuntu 8.10 x86
    2009-02-10 03:51:10 +0100 kstribley  r267534 : #i69129# remove legacy config_office
    2009-02-07 19:12:54 +0100 kstribley  r267482 : #i93645# upgrade to using silgraphite-2.3.1
    2009-02-02 18:17:57 +0100 kstribley  r267290 : #i69129# backout unwanted checkin
    2009-02-02 17:44:03 +0100 kstribley  r267281 : #i69129# backout erroneous update to aclocal.m4
    2009-02-01 10:05:03 +0100 kstribley  r267236 : #i69129# fix build error due to locale being added to set font attributes
    2009-02-01 06:02:52 +0100 kstribley  r267235 : #i69129# fix erroneous merge
    2009-01-31 16:24:56 +0100 kstribley  r267234 : #i69129# update configure.in solenv.in in their new locations with enable graphite
    2009-01-31 10:53:18 +0100 kstribley  r267232 : CWS-TOOLING: rebase CWS graphite01 to trunk at 267171 (milestone: DEV300:m41)
    2008-12-17 04:17:33 +0100 kstribley  r265577 : #i93645# remove superfluous autoreconf check and autoconf patch
    2008-12-16 10:07:20 +0100 rene  r265529 : fix aclocal.m4 breakage
    2008-12-16 05:13:29 +0100 kstribley  r265520 : #i93645# change to autoconf && configure
    2008-12-16 04:39:48 +0100 kstribley  r265519 : #i93645# modified LD_FLAGS so that system graphite isn't pulled in by accident and fixed autoconf problem
    2008-12-15 14:16:25 +0100 rene  r265497 : check for working STL
    2008-12-15 12:53:39 +0100 rene  r265473 : revert broken check
    2008-12-15 11:59:21 +0100 kstribley  r265472 : #i93645# added check for system STL, since this is a requirement for system graphite to work correctly and moved the position of the check further down
    2008-12-15 11:55:34 +0100 kstribley  r265471 : #i93645# remove references to gr3ooo to allow system graphite to be used
    2008-12-12 18:48:18 +0100 rene  r265437 : fix link for system-graphite
    2008-12-12 18:46:45 +0100 rene  r265436 : the tarball is in graphite, remove obsolete check
    2008-12-12 18:22:22 +0100 rene  r265433 : typo; re-autoconf
    2008-12-12 17:35:26 +0100 rene  r265432 : actually implement SYSTEM_GRAPHIT checks (as already checked for in makefile.mks) but remove the checks in graphit itself and move to BUILD_TYPE
    2008-12-12 08:08:33 +0100 kstribley  r265387 : #i69129# 2 of the patched files need windows line endings so patch works on linux as well as windows
    2008-12-12 08:04:41 +0100 kstribley  r265386 : #i69129# rtl fallback fix which prevents caching of segments with fallback
    2008-12-08 04:28:12 +0100 kstribley  r264969 : results of running autoconf with graphite config changes #i69129#
    2008-12-05 08:12:47 +0100 kstribley  r264886 : backout unintential change at r264884
    2008-12-05 06:26:33 +0100 kstribley  r264884 : #i96925# fixes for uniscribe fallback
    2008-12-05 06:11:37 +0100 kstribley  r264883 : #i69129# improvements to windows graphite code, including caching of sila table lookup
    2008-12-02 13:28:51 +0100 kstribley  r264694 : #i93645# add graphite library and append to patch
    2008-11-27 06:47:10 +0100 kstribley  r264445 : #69129# fix rtl loop bug and rtl caching problem
    2008-11-27 06:42:20 +0100 kstribley  r264444 : add caching for GraphiteFontAdaptor
    2008-11-14 15:57:03 +0100 kstribley  r263681 : #69129# add graphite addtional files from cvs
    2008-11-14 15:54:47 +0100 kstribley  r263680 : #69129# fix for modified resolution api
    2008-11-13 16:24:09 +0100 kstribley  r263652 : #69129# add skeleton to build graphite module library
    2008-11-13 16:22:19 +0100 kstribley  r263651 : #69129# add skeleton to build graphite module library
    2008-11-13 16:16:10 +0100 kstribley  r263650 : #69129# migrate from cvs
    2008-11-13 15:26:54 +0100 kstribley  r263646 : #69129# add a module for the graphite library

diff --git a/canvas/source/cairo/cairo_canvasfont.cxx b/canvas/source/cairo/cairo_canvasfont.cxx
index 411ea4d..1762357 100644
--- a/canvas/source/cairo/cairo_canvasfont.cxx
+++ b/canvas/source/cairo/cairo_canvasfont.cxx
@@ -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 @@ namespace cairocanvas
         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) )
         {
diff --git a/canvas/source/cairo/makefile.mk b/canvas/source/cairo/makefile.mk
index bd54254..2ab726d 100644
--- a/canvas/source/cairo/makefile.mk
+++ b/canvas/source/cairo/makefile.mk
@@ -84,7 +84,7 @@ SLOFILES =	$(SLO)$/cairo_cachedbitmap.obj \
 
 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" 
 
diff --git a/canvas/source/directx/dx_textlayout_drawhelper.cxx b/canvas/source/directx/dx_textlayout_drawhelper.cxx
index 3bc7fa7..f9451b5 100755
--- a/canvas/source/directx/dx_textlayout_drawhelper.cxx
+++ b/canvas/source/directx/dx_textlayout_drawhelper.cxx
@@ -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 @@ namespace dxcanvas
             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 );
diff --git a/canvas/source/directx/makefile.mk b/canvas/source/directx/makefile.mk
index c1d210d..1a9db2e 100644
--- a/canvas/source/directx/makefile.mk
+++ b/canvas/source/directx/makefile.mk
@@ -96,7 +96,7 @@ GDIPLUS_SLOFILES = \
     $(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 @@ LIB3OBJFILES = $(GDIPLUS_SLOFILES)
 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
diff --git a/canvas/source/vcl/canvasfont.cxx b/canvas/source/vcl/canvasfont.cxx
index 6f37760..a68d6a4 100644
--- a/canvas/source/vcl/canvasfont.cxx
+++ b/canvas/source/vcl/canvasfont.cxx
@@ -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 @@ namespace vclcanvas
         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) )
         {
diff --git a/canvas/source/vcl/makefile.mk b/canvas/source/vcl/makefile.mk
index 781cd58..fdfdd62 100644
--- a/canvas/source/vcl/makefile.mk
+++ b/canvas/source/vcl/makefile.mk
@@ -73,7 +73,7 @@ SLOFILES =	$(SLO)$/backbuffer.obj \
 
 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
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index e57e5a8..b761367 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -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>
@@ -956,6 +957,9 @@ namespace cppcanvas
                 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() );
diff --git a/cppcanvas/util/makefile.mk b/cppcanvas/util/makefile.mk
index a5ac026..4d0ff2a 100644
--- a/cppcanvas/util/makefile.mk
+++ b/cppcanvas/util/makefile.mk
@@ -50,7 +50,7 @@ LIB1FILES=\
 
 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)
 
 .IF "$(debug)$(dbgutil)"!=""
 SHL1STDLIBS += $(CPPUHELPERLIB)
diff --git a/svtools/source/control/ctrltool.cxx b/svtools/source/control/ctrltool.cxx
index 3070dd0..9675268 100644
--- a/svtools/source/control/ctrltool.cxx
+++ b/svtools/source/control/ctrltool.cxx
@@ -161,7 +161,11 @@ static void ImplMakeSearchString( XubString& rStr )
 
 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 );
 }
 
diff --git a/vcl/inc/vcl/graphite_adaptors.hxx b/vcl/inc/vcl/graphite_adaptors.hxx
new file mode 100644
index 0000000..41ffa00
--- /dev/null
+++ b/vcl/inc/vcl/graphite_adaptors.hxx
@@ -0,0 +1,154 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPHITEADAPTORS_HXX
+#define _SV_GRAPHITEADAPTORS_HXX
+
+// 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<const 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
diff --git a/vcl/inc/vcl/graphite_cache.hxx b/vcl/inc/vcl/graphite_cache.hxx
new file mode 100644
index 0000000..5a537c5
--- /dev/null
+++ b/vcl/inc/vcl/graphite_cache.hxx
@@ -0,0 +1,265 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// Description: Classes to cache Graphite Segments to try to improve
+//              rendering performance.
+
+#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;
+      size_t nHash = (*(rope)).hashCode();
+      GrRMEntry range = m_ropeMap.equal_range(nHash);
+      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
+
diff --git a/vcl/inc/vcl/graphite_features.hxx b/vcl/inc/vcl/graphite_features.hxx
new file mode 100644
index 0000000..6cfe5df
--- /dev/null
+++ b/vcl/inc/vcl/graphite_features.hxx
@@ -0,0 +1,77 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// 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];
+    };
+}
diff --git a/vcl/inc/vcl/graphite_layout.hxx b/vcl/inc/vcl/graphite_layout.hxx
new file mode 100644
index 0000000..2ec3bc4
--- /dev/null
+++ b/vcl/inc/vcl/graphite_layout.hxx
@@ -0,0 +1,167 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPHITELAYOUT_HXX
+#define _SV_GRAPHITELAYOUT_HXX
+// Description: An implementation of the SalLayout interface that uses the
+//              Graphite engine.
+
+// 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;
+
+        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 &rArgs, std::vector<int> & rDeltaWidth);
+
+    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; };
+    virtual sal_GlyphId getKashidaGlyph(int & width) = 0;
+    void kashidaJustify(std::vector<int> & rDeltaWidth, sal_GlyphId, int width);
+
+    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
diff --git a/vcl/inc/vcl/graphite_serverfont.hxx b/vcl/inc/vcl/graphite_serverfont.hxx
new file mode 100644
index 0000000..d9e6670
--- /dev/null
+++ b/vcl/inc/vcl/graphite_serverfont.hxx
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPHITESERVERFONT_HXX
+#define _SV_GRAPHITESERVERFONT_HXX
+
+// 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
+
+class VCL_DLLPUBLIC GraphiteLayoutImpl : public GraphiteLayout
+{
+public:
+    GraphiteLayoutImpl(const gr::Font & font, const grutils::GrFeatureParser * features, GraphiteFontAdaptor * pFont) throw()
+    : GraphiteLayout(font, features), mpFont(pFont) {};
+    virtual ~GraphiteLayoutImpl() throw() {};
+    virtual sal_GlyphId getKashidaGlyph(int & width);
+private:
+    GraphiteFontAdaptor * mpFont;
+};
+
+// 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 GraphiteLayoutImpl 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
diff --git a/vcl/prj/build.lst b/vcl/prj/build.lst
index 3af135d..52b4441 100644
--- a/vcl/prj/build.lst
+++ b/vcl/prj/build.lst
@@ -1,4 +1,4 @@
-vc	vcl	:	l10n apple_remote BOOST:boost rsc sot ucbhelper unotools ICU:icu i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc SO:print_header cpputools NULL
+vc	vcl	:	l10n apple_remote BOOST:boost rsc sot ucbhelper unotools ICU:icu GRAPHITE:graphite i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools transex3 icc SO:print_header cpputools 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
diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk
index 4d0ded3..a09ae92 100644
--- a/vcl/source/gdi/makefile.mk
+++ b/vcl/source/gdi/makefile.mk
@@ -45,6 +45,9 @@ TARGET=gdi
 .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 --------------------------------------------------------
 
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index 2d5acfd..e88ae2d 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -66,6 +66,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>
@@ -2749,6 +2752,14 @@ size_t ImplFontCache::IFSD_Hash::operator()( const ImplFontSelectData& rFSD ) co
     // 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;
@@ -2800,6 +2811,15 @@ bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData& rA, const I
             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;
 }
 
@@ -2837,7 +2857,12 @@ ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
         // 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;
     }
 
@@ -2942,6 +2967,22 @@ ImplDevFontListData* ImplDevFontList::ImplFindByFont( ImplFontSelectData& rFSD,
     {
         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
@@ -2972,6 +3013,10 @@ ImplDevFontListData* ImplDevFontList::ImplFindByFont( ImplFontSelectData& rFSD,
             }
         }
 
+#ifdef ENABLE_GRAPHITE
+        // 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 )
@@ -2980,16 +3025,21 @@ ImplDevFontListData* ImplDevFontList::ImplFindByFont( ImplFontSelectData& rFSD,
         // some systems provide special customization
         // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
         //      because the system wants to map it to another font first, e.g. "Helvetica"
+#ifdef ENABLE_GRAPHITE
+        // use the target name to search in the prematch hook
+        rFSD.maTargetName = aBaseFontName;
+#endif
         if( mpPreMatchHook )
-        {
             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
-            {
                 ImplGetEnglishSearchFontName( aSearchName );
-                pFoundData = ImplFindBySearchName( aSearchName );
-                if( pFoundData )
-                    return pFoundData;
-            }
-        }
+#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
+        pFoundData = ImplFindBySearchName( aSearchName );
+        if( pFoundData )
+            return pFoundData;
 
         // break after last font name token was checked unsuccessfully
         if( nTokenPos == STRING_NOTFOUND)
@@ -5440,6 +5490,7 @@ void OutputDevice::SetFont( const Font& rNewFont )
     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 ) )
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 7915112..afb9828 100755
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -63,6 +63,26 @@
 
 #include <algorithm>
 
+#ifdef DEBUG
+//#define MULTI_SL_DEBUG
+#endif
+
+#ifdef MULTI_SL_DEBUG
+#include <string>
+FILE * mslLogFile = NULL;
+FILE * mslLog()
+{
+#ifdef MSC
+    std::string logFileName(getenv("TEMP"));
+    logFileName.append("\\msllayout.log");
+    if (mslLogFile == NULL) mslLogFile = fopen(logFileName.c_str(),"w");
+    else fflush(mslLogFile);
+    return mslLogFile;
+#else
+    return stdout;
+#endif
+}
+#endif
 // =======================================================================
 
 // TODO: ask the glyph directly, for now we need this method because of #i99367#
@@ -1157,11 +1177,17 @@ void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs )
     for( int nCharPos = i = -1; rArgs.GetNextPos( &nCharPos, &bRTL ); )
     {
         n = nCharPos - rArgs.mnMinCharPos;
-        i = pLogCluster[ n ];
-        long nDelta = rArgs.mpDXArray[ n ] ;
-        if( n > 0 )
-            nDelta -= rArgs.mpDXArray[ n-1 ];
-        pNewGlyphWidths[ i ] += nDelta * mnUnitsPerPixel;
+        if( (n < 0) || (nCharCount <= n) )  continue;
+
+        if( pLogCluster[ n ] >= 0 )
+            i = pLogCluster[ n ];
+        if( i >= 0 )
+        {
+            long nDelta = rArgs.mpDXArray[ n ] ;
+            if( n > 0 )
+                nDelta -= rArgs.mpDXArray[ n-1 ];
+            pNewGlyphWidths[ i ] += nDelta * mnUnitsPerPixel;
+        }
     }
 
     // move cluster positions using the adjusted widths
@@ -1768,6 +1794,19 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
         }
     }
 
+    // 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 ];
@@ -1804,6 +1843,10 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
         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]) fprintf(mslLog(), "layout[%d]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", n, nStartOld[nLevel], nStartNew[nLevel], aPos.X(), nGlyphAdv[nLevel], nCharPos[nLevel],
+            rArgs.mpStr[nCharPos[nLevel]]);
+#endif
         if( (n > 0) && !nValid[ nLevel ] )
         {
             // an empty fallback layout can be released
@@ -1829,6 +1872,9 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
     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
@@ -1864,6 +1910,9 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
                 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]) fprintf(mslLog(), "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;
             }
@@ -1881,7 +1930,9 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
             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]) fprintf(mslLog(), "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] )
             {
@@ -1927,6 +1978,27 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
                     { 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
@@ -1936,16 +2008,40 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
             // 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
+              fprintf(mslLog(), "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
+                fprintf(mslLog(), "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;
@@ -1963,9 +2059,27 @@ void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
 
         // 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 );
diff --git a/vcl/source/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx
index 1f0ed00..4f04802 100644
--- a/vcl/source/glyphs/gcach_ftyp.cxx
+++ b/vcl/source/glyphs/gcach_ftyp.cxx
@@ -1425,6 +1425,20 @@ bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap
         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 )
diff --git a/vcl/source/glyphs/gcach_layout.cxx b/vcl/source/glyphs/gcach_layout.cxx
old mode 100755
new mode 100644
diff --git a/vcl/source/glyphs/gcach_rbmp.cxx b/vcl/source/glyphs/gcach_rbmp.cxx
old mode 100755
new mode 100644
diff --git a/vcl/source/glyphs/glyphcache.cxx b/vcl/source/glyphs/glyphcache.cxx
index 9d887b5..817b10c 100644
--- a/vcl/source/glyphs/glyphcache.cxx
+++ b/vcl/source/glyphs/glyphcache.cxx
@@ -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 @@ size_t GlyphCache::IFSD_Hash::operator()( const ImplFontSelectData& rFontSelData
 {
     // 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 @@ bool GlyphCache::IFSD_Equal::operator()( const ImplFontSelectData& rA, const Imp
     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;
 }
 
diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx
new file mode 100644
index 0000000..6733069
--- /dev/null
+++ b/vcl/source/glyphs/graphite_adaptors.cxx
@@ -0,0 +1,327 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// Description: Implements the Graphite interfaces with access to the
+//              platform's font and graphics systems.
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// 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 = dynamic_cast<FreetypeServerFont &>(font);
+    FT_Face aFace = reinterpret_cast<FT_FaceRec_*>(aFtFont.GetFtFace());
+    SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFace));
+    if (i != sSilfMap.end())
+    {
+#ifdef DEBUG
+        if (static_cast<bool>(aFtFont.GetTable("Silf", 0)) != (*i).second)
+            printf("Silf cache font mismatch\n");
+#endif
+        return (*i).second;
+    }
+    bool bHasSilf = aFtFont.GetTable("Silf", 0);
+    sSilfMap[reinterpret_cast<long>(aFace)] = 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());
+        if (!aFace)
+        {
+            aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
+            advances.x = advances.y = 0;
+            return;
+        }
+        FT_Error aStatus = -1;
+        aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags);
+        if( aStatus != FT_Err_Ok || (!aFace->glyph))
+        {
+            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
diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx
new file mode 100644
index 0000000..c1bca0f
--- /dev/null
+++ b/vcl/source/glyphs/graphite_cache.cxx
@@ -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
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#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;
+}
diff --git a/vcl/source/glyphs/graphite_features.cxx b/vcl/source/glyphs/graphite_features.cxx
new file mode 100644
index 0000000..dca3c20
--- /dev/null
+++ b/vcl/source/glyphs/graphite_features.cxx
@@ -0,0 +1,289 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+ 
+// Description:
+// Parse a string of features specified as & separated pairs.
+// e.g.
+// 1001=1&2002=2&fav1=0
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#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;
+}
diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx
new file mode 100644
index 0000000..7759735
--- /dev/null
+++ b/vcl/source/glyphs/graphite_layout.cxx
@@ -0,0 +1,1367 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+ 
+// Description: An implementation of the SalLayout interface that uses the
+//              Graphite engine.
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// 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>
+#include <unicode/uscript.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
+    std::string logFileName(getenv("TEMP"));
+    logFileName.append("\\graphitelayout.log");
+    if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"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;
+                }
+            }
+            // Loop over attached glyphs and make sure they are all in the cluster since you
+            // can have glyphs attached with another base glyph in between
+            glyph_set_range_t iAttached = info.attachedClusterGlyphs();
+            for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi)
+            {
+                nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*agi).logicalIndex()) : max(nLastGlyph, (signed)(*agi).logicalIndex());
+            }
+
+            // 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;
+    if (rWidth < 0)
+    {
+        // This can happen when there was no base inside the range
+        rWidth = 0;
+    }
+    // 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
+    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;
+    // directionality seems to be unreliable
+    //nGlyphFlags |= gr::RightToLeftDir(gr::DirCode(gi.attachedClusterBase()->directionality())) ? GlyphItem::IS_RTL_GLYPH : 0;
+    nGlyphFlags |= (gi.directionLevel() & 0x1)? 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 attached 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", (int)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,%ld ", (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& rArgs)
+{
+    SalLayout::AdjustLayout(rArgs);
+
+    if(rArgs.mpDXArray)
+    {
+        std::vector<int> vDeltaWidths(mvGlyphs.size(), 0);
+        ApplyDXArray(rArgs, vDeltaWidths);
+
+        if( (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL) &&
+           !(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
+        {
+            // check if this is a kashida script
+            bool bKashidaScript = false;
+            for (int i = rArgs.mnMinCharPos; i < rArgs.mnEndCharPos; i++)
+            {
+                UErrorCode aStatus = U_ZERO_ERROR;
+                UScriptCode scriptCode = uscript_getScript(rArgs.mpStr[i], &aStatus);
+                if (scriptCode == USCRIPT_ARABIC || scriptCode == USCRIPT_SYRIAC)
+                {
+                    bKashidaScript = true;
+                    break;
+                }
+            }
+            int nKashidaWidth = 0;
+            int nKashidaIndex = getKashidaGlyph(nKashidaWidth);
+            if( nKashidaIndex != 0 && bKashidaScript)
+            {
+                kashidaJustify( vDeltaWidths, nKashidaIndex, nKashidaWidth );
+            }
+        }
+    }
+}
+
+
+void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth)
+{
+    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,%ld ", (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;
+                }
+            }
+            if (nLastGlyph < 0)
+            {
+                nLastGlyph = mvChar2BaseGlyph[i];
+            }
+            // 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;
+#ifdef GRLAYOUT_DEBUG
+            fprintf(grLog(), "c%d last glyph %d/%d\n", i, nLastGlyph, mvGlyphs.size());
+#endif
+            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;
+                }
+            }
+            rDeltaWidth[mvChar2BaseGlyph[i]] = nDWidth;
+#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 %ld(%ld)\n", args.mpDXArray[nChars - 1], mnWidth);
+#endif
+    mnWidth = args.mpDXArray[nChars - 1];
+}
+
+void GraphiteLayout::kashidaJustify(std::vector<int>& rDeltaWidths, sal_GlyphId nKashidaIndex, int nKashidaWidth)
+{
+    // skip if the kashida glyph in the font looks suspicious
+    if( nKashidaWidth <= 0 )
+        return;
+
+    // calculate max number of needed kashidas
+    Glyphs::iterator i = mvGlyphs.begin();
+    int nKashidaCount = 0;
+    int nOrigGlyphIndex = -1;
+    int nGlyphIndex = -1;
+    while (i != mvGlyphs.end())
+    {
+        nOrigGlyphIndex++;
+        nGlyphIndex++;
+        // only inject kashidas in RTL contexts
+        if( !(*i).IsRTLGlyph() )
+        {
+            ++i;
+            continue;
+        }
+        // no kashida-injection for blank justified expansion either
+        if( IsSpacingGlyph( (*i).mnGlyphIndex ) )
+        {
+            ++i;
+            continue;
+        }
+        // calculate gap, ignore if too small
+        int nGapWidth = rDeltaWidths[nOrigGlyphIndex];;
+        // worst case is one kashida even for mini-gaps
+        if( 3 * nGapWidth < nKashidaWidth )
+        {
+            ++i;
+            continue;
+        }
+        nKashidaCount = 1 + (nGapWidth / nKashidaWidth);
+#ifdef GRLAYOUT_DEBUG
+        printf("inserting %d kashidas at %ld\n", nKashidaCount, (*i).mnGlyphIndex);
+#endif
+        GlyphItem glyphItem = *i;
+        Point aPos(0, 0);
+        aPos.X() = (*i).maLinearPos.X();
+        GlyphItem newGi(glyphItem.mnCharPos, nKashidaIndex, aPos,
+                GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth);
+        mvGlyphs.reserve(mvGlyphs.size() + nKashidaCount);
+        i = mvGlyphs.begin() + nGlyphIndex;
+        mvGlyphs.insert(i, nKashidaCount, newGi);
+        i = mvGlyphs.begin() + nGlyphIndex;
+        nGlyphIndex += nKashidaCount;
+        // now fix up the kashida positions
+        for (int j = 0; j < nKashidaCount; j++)
+        {
+            (*(i)).maLinearPos.X() -= nGapWidth;
+            nGapWidth -= nKashidaWidth;
+            i++;
+        }
+
+        // fixup rightmost kashida for gap remainder
+        if( nGapWidth < 0 )
+        {
+            if( nKashidaCount <= 1 )
+                nGapWidth /= 2;               // for small gap move kashida to middle
+            (*(i-1)).mnNewWidth += nGapWidth;  // adjust kashida width to gap width
+            (*(i-1)).maLinearPos.X() += nGapWidth;
+        }
+
+        (*i).mnNewWidth = (*i).mnOrigWidth;
+        ++i;
+    }
+
+}
+
+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,%ld-%ld\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
+    // 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;
+}
diff --git a/vcl/source/glyphs/graphite_serverfont.cxx b/vcl/source/glyphs/graphite_serverfont.cxx
new file mode 100644
index 0000000..e8cd152
--- /dev/null
+++ b/vcl/source/glyphs/graphite_serverfont.cxx
@@ -0,0 +1,88 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// 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(), pFont)
+{
+    // 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;
+}
+
+sal_GlyphId GraphiteLayoutImpl::getKashidaGlyph(int & width)
+{
+    int nKashidaIndex = mpFont->font().GetGlyphIndex( 0x0640 );
+    if( nKashidaIndex != 0 )
+    {
+        const GlyphMetric& rGM = mpFont->font().GetGlyphMetric( nKashidaIndex );
+        width = rGM.GetCharWidth();
+    }
+    else
+    {
+        width = 0;
+    }
+    return nKashidaIndex;
+}
+
+#endif
diff --git a/vcl/source/glyphs/graphite_textsrc.cxx b/vcl/source/glyphs/graphite_textsrc.cxx
new file mode 100644
index 0000000..d2987e5
--- /dev/null
+++ b/vcl/source/glyphs/graphite_textsrc.cxx
@@ -0,0 +1,172 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// 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);
+}
diff --git a/vcl/source/glyphs/graphite_textsrc.hxx b/vcl/source/glyphs/graphite_textsrc.hxx
new file mode 100644
index 0000000..5e03bbf
--- /dev/null
+++ b/vcl/source/glyphs/graphite_textsrc.hxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * 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:  $
+ * $Revision:  $
+ *
+ * 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.
+ *
+ ************************************************************************/
+ 
+#ifndef _SV_GRAPHITETEXTSRC_HXX
+#define _SV_GRAPHITETEXTSRC_HXX
+// 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.
+
+// 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
diff --git a/vcl/source/glyphs/makefile.mk b/vcl/source/glyphs/makefile.mk
index b08777d..3c3ba62 100644
--- a/vcl/source/glyphs/makefile.mk
+++ b/vcl/source/glyphs/makefile.mk
@@ -54,6 +54,27 @@ SLOFILES=\
         $(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 ------------------------------------------------------
diff --git a/vcl/unx/inc/salgdi.h b/vcl/unx/inc/salgdi.h
index 910fbc1..d05ddac 100644
--- a/vcl/unx/inc/salgdi.h
+++ b/vcl/unx/inc/salgdi.h
@@ -106,6 +106,8 @@ protected:
     Pixel           nTextPixel_;
     BOOL            bFontVertical_;
 
+    BOOL            bDisableGraphite_;
+
     GC              pBrushGC_;      // Brush attributes
     SalColor        nBrushColor_;
     Pixel           nBrushPixel_;
diff --git a/vcl/unx/source/gdi/makefile.mk b/vcl/unx/source/gdi/makefile.mk
index 8f0faf8..bdd400b 100644
--- a/vcl/unx/source/gdi/makefile.mk
+++ b/vcl/unx/source/gdi/makefile.mk
@@ -90,6 +90,10 @@ ENVCFLAGS+=-DUSE_CDE
 CFLAGS+=-DXRENDER_LINK
 .ENDIF
 
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
 .ENDIF	# "$(GUIBASE)"!="unx"
 
 # --- Targets ------------------------------------------------------
diff --git a/vcl/unx/source/gdi/pspgraphics.cxx b/vcl/unx/source/gdi/pspgraphics.cxx
index 9e4a345..39d1f9a 100644
--- a/vcl/unx/source/gdi/pspgraphics.cxx
+++ b/vcl/unx/source/gdi/pspgraphics.cxx
@@ -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;
 
@@ -699,9 +704,30 @@ static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx
 
     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 );
@@ -961,7 +987,21 @@ SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel
 
     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 );
 
diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx
index 9a9f648..88ff949 100644
--- a/vcl/unx/source/gdi/salgdi.cxx
+++ b/vcl/unx/source/gdi/salgdi.cxx
@@ -119,6 +119,12 @@ X11SalGraphics::X11SalGraphics()
     nTextPixel_			= 0;
     nTextColor_			= MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
 
+#ifdef ENABLE_GRAPHITE
+    // check if graphite fonts have been disabled
+    static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" );
+    bDisableGraphite_		= pDisableGraphiteStr ? (pDisableGraphiteStr[0]!='0') : FALSE;
+#endif
+
     pBrushGC_			= NULL;
     nBrushPixel_			= 0;
     nBrushColor_		= MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
@@ -1490,7 +1496,6 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const :
         // should use ImplLineConverter normally)
         return false;
     }
-
     const XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
     if( !rRenderPeer.AreTrapezoidsSupported() )
         return false;
diff --git a/vcl/unx/source/gdi/salgdi3.cxx b/vcl/unx/source/gdi/salgdi3.cxx
index 3aceec6..2c11ba5 100644
--- a/vcl/unx/source/gdi/salgdi3.cxx
+++ b/vcl/unx/source/gdi/salgdi3.cxx
@@ -82,6 +82,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;
@@ -1681,11 +1686,29 @@ BOOL X11SalGraphics::GetGlyphOutline( long nGlyphIndex,
 
 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 (!bDisableGraphite_ &&
+            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
diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk
index 63994c1..dd17637 100644
--- a/vcl/util/makefile.mk
+++ b/vcl/util/makefile.mk
@@ -6,10 +6,6 @@
 #
 # OpenOffice.org - a multi-platform office productivity suite
 #
-# $RCSfile: makefile.mk,v $
-#
-# $Revision: 1.111.36.3 $
-#
 # This file is part of OpenOffice.org.
 #
 # OpenOffice.org is free software: you can redistribute it and/or modify
@@ -184,6 +180,16 @@ SHL1STDLIBS+=\
             $(ICUDATALIB)		\
             $(ICULELIB)			\
             $(JVMACCESSLIB)
+
+.IF "$(GUI)" == "UNX"
+.IF "$(ENABLE_GRAPHITE)" != ""
+.IF "$(SYSTEM_GRAPHITE)" == "YES"
+SHL1STDLIBS+= $(GRAPHITE_LIBS)
+.ELSE
+SHL1STDLIBS+= $(SOLARVERSION)/$(INPATH)/lib$(UPDMINOREXT)/libgraphite.a
+.ENDIF
+.ENDIF
+.ENDIF
 SHL1USE_EXPORTS=name
 
 .IF "$(GUIBASE)"=="aqua"
@@ -198,6 +204,10 @@ LIB1FILES+= \
 .IF "$(USE_BUILTIN_RASTERIZER)"!=""
     LIB1FILES +=    $(SLB)$/glyphs.lib
     SHL1STDLIBS+=   $(FREETYPELIB)
+.ELSE
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+    LIB1FILES +=    $(SLB)$/glyphs.lib
+.ENDIF
 .ENDIF # USE_BUILTIN_RASTERIZER
 
 SHL1LIBS=   $(LIB1TARGET)
@@ -223,6 +233,14 @@ DEFLIB1NAME =vcl
 
 .IF "$(GUI)" == "WNT"
 
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+.IF "$(COM)" == "GCC"
+SHL1STDLIBS += -lgraphite
+.ELSE
+SHL1STDLIBS += graphite_dll.lib
+.ENDIF
+.ENDIF
+
 SHL1STDLIBS += $(UWINAPILIB)      \
                $(GDI32LIB)        \
                $(GDIPLUSLIB)	  \
diff --git a/vcl/win/inc/salgdi.h b/vcl/win/inc/salgdi.h
index 18cfa2a..2901046 100644
--- a/vcl/win/inc/salgdi.h
+++ b/vcl/win/inc/salgdi.h
@@ -81,6 +81,9 @@ public:
     bool                    SupportsArabic() const      { return mbHasArabicSupport; }
     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; }
@@ -97,6 +100,9 @@ private:
     mutable bool                    mbDisableGlyphApi;
     mutable bool                    mbHasKoreanRange;
     mutable bool                    mbHasCJKSupport;
+#ifdef ENABLE_GRAPHITE
+    mutable bool                    mbHasGraphiteSupport;
+#endif
     mutable bool                    mbHasArabicSupport;
     mutable ImplFontCharMap*        mpUnicodeMap;
     mutable const Ucs2SIntMap*      mpEncodingVector;
diff --git a/vcl/win/source/gdi/MAKEFILE.MK b/vcl/win/source/gdi/MAKEFILE.MK
index a6d84d4..3d8fd90 100644
--- a/vcl/win/source/gdi/MAKEFILE.MK
+++ b/vcl/win/source/gdi/MAKEFILE.MK
@@ -64,6 +64,10 @@ SLOFILES=   $(SLO)$/salgdi.obj   \
 
 EXCEPTIONSFILES=	$(SLO)$/salprn.obj
 
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
 # --- Targets ------------------------------------------------------
 
 .INCLUDE :  target.mk
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
index 4316172..911be71 100644
--- a/vcl/win/source/gdi/salgdi3.cxx
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -74,6 +74,11 @@
 #include <algorithm>
 #endif
 
+#ifdef ENABLE_GRAPHITE
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#endif
+
 #include <vector>
 #include <set>
 #include <map>
@@ -807,6 +812,9 @@ ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
     mbDisableGlyphApi( false ),
     mbHasKoreanRange( false ),
     mbHasCJKSupport( false ),
+#ifdef ENABLE_GRAPHITE
+    mbHasGraphiteSupport( false ),
+#endif
     mbHasArabicSupport ( false ),
     mbAliasSymbolsLow( false ),
     mbAliasSymbolsHigh( false ),
@@ -865,6 +873,13 @@ void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
 
     ReadCmapTable( hDC );
     ReadOs2Table( hDC );
+#ifdef ENABLE_GRAPHITE
+    static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
+    if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
+    {
+        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
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
old mode 100755
new mode 100644
index 068a1ce..c4cf83b
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -71,6 +71,17 @@
 typedef std::hash_map<int,int> IntMap;
 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;
@@ -1757,6 +1768,8 @@ bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
         if( nMaxGlyphPos < n )
             nMaxGlyphPos = n;
     }
+    if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
+        nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
 
     // extend the glyph range to account for all glyphs in referenced clusters
     if( !rVisualItem.IsRTL() ) // LTR-item
@@ -2041,11 +2054,25 @@ void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
     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
     {
@@ -2066,11 +2093,18 @@ void UniscribeLayout::DropGlyph( int nStartx8 )
         --nStart;
     else                    // 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;
@@ -2127,11 +2161,12 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
         }
 
         // 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;
         }
 
@@ -2141,6 +2176,17 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
             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 )
@@ -2157,9 +2203,10 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ )
             mpGlyphAdvances[ j ]  = mpGlyphAdvances[ i ];
             if( mpJustifications )
                 mpJustifications[ j ] = mpJustifications[ i ];
-            int k = mpGlyphs2Chars[ i ];
+            const int k = mpGlyphs2Chars[ i ];
             mpGlyphs2Chars[ j ]   = k;
-            mpLogClusters[ k ]    = sal::static_int_cast<WORD>(j++);
+            const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
+            mpLogClusters[ k ]    = static_cast<WORD>(nRelGlyphPos);
         }
 
         rVI.mnEndGlyphPos = j;
@@ -2751,6 +2798,234 @@ bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
 
 #endif // USE_UNISCRIBE
 
+#ifdef ENABLE_GRAPHITE
+
+class GraphiteLayoutWinImpl : public GraphiteLayout
+{
+public:
+    GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
+        throw()
+    : GraphiteLayout(font), mrFont(rFont) {};
+    virtual ~GraphiteLayoutWinImpl() throw() {};
+    virtual sal_GlyphId getKashidaGlyph(int & rWidth);
+private:
+    ImplWinFontEntry & mrFont;
+};
+
+sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
+{
+    rWidth = mrFont.GetMinKashidaWidth();
+    return mrFont.GetMinKashidaGlyph();
+}
+
+// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
+// @author tse
+//
+class GraphiteWinLayout : public WinLayout
+{
+private:
+    mutable gr::WinFont   mpFont;
+    grutils::GrFeatureParser * mpFeatures;
+    mutable GraphiteLayoutWinImpl maImpl;
+public:
+    GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
+
+    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  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, rWFE)
+{
+    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& rArgs)
+{
+    WinLayout::AdjustLayout(rArgs);
+    maImpl.DrawBase() = WinLayout::maDrawBase;
+    maImpl.DrawOffset() = WinLayout::maDrawOffset;
+    if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
+    {
+        mrWinFontEntry.InitKashidaHandling(mhDC);
+    }
+    maImpl.AdjustLayout(rArgs);
+}
+
+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 = 2;
+    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::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 )
@@ -2766,6 +3041,11 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
     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
@@ -2788,7 +3068,12 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
         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 )
diff --git a/vcl/win/source/window/MAKEFILE.MK b/vcl/win/source/window/MAKEFILE.MK
index 17e73db..67cb1bf 100644
--- a/vcl/win/source/window/MAKEFILE.MK
+++ b/vcl/win/source/window/MAKEFILE.MK
@@ -60,6 +60,10 @@ SLOFILES=   \
 EXCEPTIONSFILES=   $(SLO)$/salframe.obj
 .ENDIF
 
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
 # --- Targets ------------------------------------------------------
 
 .INCLUDE :	target.mk


More information about the ooo-build-commit mailing list