[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