summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite/engine-2.3.1/src
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2009-11-10 10:18:38 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2009-11-10 10:18:38 +0000
commit9ab1d67ae5be915e0a7e146123ea577b8b7d85cf (patch)
tree02180daeded681369095ccb9e1f592502d032c90 /Build/source/libs/graphite/engine-2.3.1/src
parentc9e6fa742a274dd314b6e483c65a810f7ed44d1e (diff)
towards TL2010: libs graphite
git-svn-id: svn://tug.org/texlive/trunk@15953 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/graphite/engine-2.3.1/src')
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/Makefile.am22
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/Makefile.in781
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/FileFont.cpp429
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/Font.cpp949
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/FontTableCache.h52
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/Makefile.am7
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/TtfTypes.h388
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.cpp1935
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.h147
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree.h71
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree_i.cpp225
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/Debug.cpp83
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/GenericResource.h86
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap.h328
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap_i.cpp561
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/Makefile.am8
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/generic/Util.cpp261
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/painter/Makefile.am5
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/painter/SegmentPainter.cpp3004
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.cpp266
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.h104
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.cpp308
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.h105
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.cpp598
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.h246
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.cpp652
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.h183
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.cpp382
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.h188
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.cpp2031
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.h622
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.cpp526
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.h245
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeature.cpp321
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeatureValues.h66
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.cpp650
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.h429
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.cpp2030
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.h747
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrPassActionCode.cpp1490
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrPseudoMap.h48
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.cpp1540
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.h1315
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.cpp2381
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.h577
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.cpp2694
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.h557
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/Main.h182
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/Makefile.am26
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/MemoryUsage.cpp781
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/Platform.cpp113
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/Segment.cpp3558
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/SegmentAux.cpp256
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/TestFSM.cpp3416
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/TestPasses.cpp1005
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/TransductionLog.cpp2129
-rw-r--r--Build/source/libs/graphite/engine-2.3.1/src/segment/resource.h15
57 files changed, 42124 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/Makefile.am b/Build/source/libs/graphite/engine-2.3.1/src/Makefile.am
new file mode 100644
index 00000000000..7d55c002a23
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/Makefile.am
@@ -0,0 +1,22 @@
+AUTOMAKE_OPTIONS = 1.6
+
+AM_CPPFLAGS = -I$(top_srcdir)/include/graphite -I$(top_srcdir)/src/generic
+AM_CPPFLAGS += -I$(top_srcdir)/src/font -I$(top_srcdir)/src/segment
+#AM_CPPFLAGS += $(FT_CFLAGS) $(XFT_CFLAGS)
+#AM_CPPFLAGS += -D_UNICODE -DUNICODE -DNO_ASM
+
+lib_LTLIBRARIES = libgraphite.la
+
+libgraphite_la_LDFLAGS = -version-info 3:0:0
+
+#EXTRA_DIST=textsource
+EXTRA_DIST=
+graphiteinclude_HEADERS =
+graphiteincludedir = $(includedir)/graphite
+include ../include/Makefile.am
+
+libgraphite_la_SOURCES =
+include generic/Makefile.am
+include font/Makefile.am
+include segment/Makefile.am
+include painter/Makefile.am
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/Makefile.in b/Build/source/libs/graphite/engine-2.3.1/src/Makefile.in
new file mode 100644
index 00000000000..487f21dc19c
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/Makefile.in
@@ -0,0 +1,781 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(graphiteinclude_HEADERS) \
+ $(srcdir)/../include/Makefile.am $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/font/Makefile.am \
+ $(srcdir)/generic/Makefile.am $(srcdir)/painter/Makefile.am \
+ $(srcdir)/segment/Makefile.am
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(graphiteincludedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libgraphite_la_LIBADD =
+am_libgraphite_la_OBJECTS = Debug.lo Util.lo Font.lo TtfUtil.lo \
+ FileFont.lo FileInput.lo FontCache.lo FontFace.lo \
+ GrCharStream.lo GrClassTable.lo GrEngine.lo GrFeature.lo \
+ GrFSM.lo GrGlyphTable.lo GrPassActionCode.lo GrPass.lo \
+ GrSlotState.lo GrSlotStream.lo GrTableManager.lo \
+ MemoryUsage.lo Platform.lo SegmentAux.lo Segment.lo TestFSM.lo \
+ TestPasses.lo TransductionLog.lo SegmentPainter.lo
+libgraphite_la_OBJECTS = $(am_libgraphite_la_OBJECTS)
+libgraphite_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libgraphite_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgraphite_la_SOURCES)
+DIST_SOURCES = $(libgraphite_la_SOURCES)
+graphiteincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(graphiteinclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LSB_RELEASE = @LSB_RELEASE@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+REL_CODENAME = @REL_CODENAME@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIZEOF_WCHAR_T = @SIZEOF_WCHAR_T@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = 1.6
+AM_CPPFLAGS = -I$(top_srcdir)/include/graphite \
+ -I$(top_srcdir)/src/generic -I$(top_srcdir)/src/font \
+ -I$(top_srcdir)/src/segment
+#AM_CPPFLAGS += $(FT_CFLAGS) $(XFT_CFLAGS)
+#AM_CPPFLAGS += -D_UNICODE -DUNICODE -DNO_ASM
+lib_LTLIBRARIES = libgraphite.la
+libgraphite_la_LDFLAGS = -version-info 3:0:0
+
+#EXTRA_DIST=textsource
+EXTRA_DIST = $(top_srcdir)/include/graphite/BinTree.h \
+ $(top_srcdir)/include/graphite/GenericResource.h \
+ $(top_srcdir)/include/graphite/HashMap.h $(genericdir)/*.h \
+ $(genericdir)/BinTree_i.cpp $(genericdir)/HashMap_i.cpp \
+ $(fontdir)/*.h $(segmentdir)/*.h
+graphiteinclude_HEADERS = $(top_srcdir)/include/graphite/FileFont.h \
+ $(top_srcdir)/include/graphite/Font.h \
+ $(top_srcdir)/include/graphite/GraphiteProcess.h \
+ $(top_srcdir)/include/graphite/GrAppData.h \
+ $(top_srcdir)/include/graphite/GrClient.h \
+ $(top_srcdir)/include/graphite/GrCommon.h \
+ $(top_srcdir)/include/graphite/GrConstants.h \
+ $(top_srcdir)/include/graphite/GrData.h \
+ $(top_srcdir)/include/graphite/GrDebug.h \
+ $(top_srcdir)/include/graphite/GrExt.h \
+ $(top_srcdir)/include/graphite/GrFeature.h \
+ $(top_srcdir)/include/graphite/GrMstypes.h \
+ $(top_srcdir)/include/graphite/GrPlatform.h \
+ $(top_srcdir)/include/graphite/GrResult.h \
+ $(top_srcdir)/include/graphite/GrStructs.h \
+ $(top_srcdir)/include/graphite/GrWrappers.h \
+ $(top_srcdir)/include/graphite/IGraphiteProcess.h \
+ $(top_srcdir)/include/graphite/IGrEngine.h \
+ $(top_srcdir)/include/graphite/IGrJustifier.h \
+ $(top_srcdir)/include/graphite/ITextSource.h \
+ $(top_srcdir)/include/graphite/MemoryUsage.h \
+ $(top_srcdir)/include/graphite/SegmentAux.h \
+ $(top_srcdir)/include/graphite/Segment.h \
+ $(top_srcdir)/include/graphite/SegmentPainter.h
+graphiteincludedir = $(includedir)/graphite
+libgraphite_la_SOURCES = $(genericdir)/Debug.cpp \
+ $(genericdir)/Util.cpp $(fontdir)/Font.cpp \
+ $(fontdir)/TtfUtil.cpp $(fontdir)/FileFont.cpp \
+ $(segmentdir)/FileInput.cpp $(segmentdir)/FontCache.cpp \
+ $(segmentdir)/FontFace.cpp $(segmentdir)/GrCharStream.cpp \
+ $(segmentdir)/GrClassTable.cpp $(segmentdir)/GrEngine.cpp \
+ $(segmentdir)/GrFeature.cpp $(segmentdir)/GrFSM.cpp \
+ $(segmentdir)/GrGlyphTable.cpp \
+ $(segmentdir)/GrPassActionCode.cpp $(segmentdir)/GrPass.cpp \
+ $(segmentdir)/GrSlotState.cpp $(segmentdir)/GrSlotStream.cpp \
+ $(segmentdir)/GrTableManager.cpp $(segmentdir)/MemoryUsage.cpp \
+ $(segmentdir)/Platform.cpp $(segmentdir)/SegmentAux.cpp \
+ $(segmentdir)/Segment.cpp $(segmentdir)/TestFSM.cpp \
+ $(segmentdir)/TestPasses.cpp $(segmentdir)/TransductionLog.cpp \
+ $(painterdir)/SegmentPainter.cpp
+genericdir = $(top_srcdir)/src/generic
+fontdir = $(top_srcdir)/src/font
+segmentdir = $(top_srcdir)/src/segment
+painterdir = $(top_srcdir)/src/painter
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../include/Makefile.am $(srcdir)/generic/Makefile.am $(srcdir)/font/Makefile.am $(srcdir)/segment/Makefile.am $(srcdir)/painter/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgraphite.la: $(libgraphite_la_OBJECTS) $(libgraphite_la_DEPENDENCIES)
+ $(libgraphite_la_LINK) -rpath $(libdir) $(libgraphite_la_OBJECTS) $(libgraphite_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileFont.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileInput.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Font.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FontCache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FontFace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrCharStream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrClassTable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrEngine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrFSM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrFeature.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrGlyphTable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrPass.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrPassActionCode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrSlotState.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrSlotStream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrTableManager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemoryUsage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Platform.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Segment.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentAux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentPainter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestFSM.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestPasses.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransductionLog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TtfUtil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+Debug.lo: $(genericdir)/Debug.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Debug.lo -MD -MP -MF $(DEPDIR)/Debug.Tpo -c -o Debug.lo `test -f '$(genericdir)/Debug.cpp' || echo '$(srcdir)/'`$(genericdir)/Debug.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Debug.Tpo $(DEPDIR)/Debug.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(genericdir)/Debug.cpp' object='Debug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Debug.lo `test -f '$(genericdir)/Debug.cpp' || echo '$(srcdir)/'`$(genericdir)/Debug.cpp
+
+Util.lo: $(genericdir)/Util.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Util.lo -MD -MP -MF $(DEPDIR)/Util.Tpo -c -o Util.lo `test -f '$(genericdir)/Util.cpp' || echo '$(srcdir)/'`$(genericdir)/Util.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Util.Tpo $(DEPDIR)/Util.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(genericdir)/Util.cpp' object='Util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Util.lo `test -f '$(genericdir)/Util.cpp' || echo '$(srcdir)/'`$(genericdir)/Util.cpp
+
+Font.lo: $(fontdir)/Font.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Font.lo -MD -MP -MF $(DEPDIR)/Font.Tpo -c -o Font.lo `test -f '$(fontdir)/Font.cpp' || echo '$(srcdir)/'`$(fontdir)/Font.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Font.Tpo $(DEPDIR)/Font.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(fontdir)/Font.cpp' object='Font.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Font.lo `test -f '$(fontdir)/Font.cpp' || echo '$(srcdir)/'`$(fontdir)/Font.cpp
+
+TtfUtil.lo: $(fontdir)/TtfUtil.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TtfUtil.lo -MD -MP -MF $(DEPDIR)/TtfUtil.Tpo -c -o TtfUtil.lo `test -f '$(fontdir)/TtfUtil.cpp' || echo '$(srcdir)/'`$(fontdir)/TtfUtil.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TtfUtil.Tpo $(DEPDIR)/TtfUtil.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(fontdir)/TtfUtil.cpp' object='TtfUtil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TtfUtil.lo `test -f '$(fontdir)/TtfUtil.cpp' || echo '$(srcdir)/'`$(fontdir)/TtfUtil.cpp
+
+FileFont.lo: $(fontdir)/FileFont.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FileFont.lo -MD -MP -MF $(DEPDIR)/FileFont.Tpo -c -o FileFont.lo `test -f '$(fontdir)/FileFont.cpp' || echo '$(srcdir)/'`$(fontdir)/FileFont.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/FileFont.Tpo $(DEPDIR)/FileFont.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(fontdir)/FileFont.cpp' object='FileFont.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o FileFont.lo `test -f '$(fontdir)/FileFont.cpp' || echo '$(srcdir)/'`$(fontdir)/FileFont.cpp
+
+FileInput.lo: $(segmentdir)/FileInput.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FileInput.lo -MD -MP -MF $(DEPDIR)/FileInput.Tpo -c -o FileInput.lo `test -f '$(segmentdir)/FileInput.cpp' || echo '$(srcdir)/'`$(segmentdir)/FileInput.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/FileInput.Tpo $(DEPDIR)/FileInput.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/FileInput.cpp' object='FileInput.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o FileInput.lo `test -f '$(segmentdir)/FileInput.cpp' || echo '$(srcdir)/'`$(segmentdir)/FileInput.cpp
+
+FontCache.lo: $(segmentdir)/FontCache.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FontCache.lo -MD -MP -MF $(DEPDIR)/FontCache.Tpo -c -o FontCache.lo `test -f '$(segmentdir)/FontCache.cpp' || echo '$(srcdir)/'`$(segmentdir)/FontCache.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/FontCache.Tpo $(DEPDIR)/FontCache.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/FontCache.cpp' object='FontCache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o FontCache.lo `test -f '$(segmentdir)/FontCache.cpp' || echo '$(srcdir)/'`$(segmentdir)/FontCache.cpp
+
+FontFace.lo: $(segmentdir)/FontFace.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FontFace.lo -MD -MP -MF $(DEPDIR)/FontFace.Tpo -c -o FontFace.lo `test -f '$(segmentdir)/FontFace.cpp' || echo '$(srcdir)/'`$(segmentdir)/FontFace.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/FontFace.Tpo $(DEPDIR)/FontFace.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/FontFace.cpp' object='FontFace.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o FontFace.lo `test -f '$(segmentdir)/FontFace.cpp' || echo '$(srcdir)/'`$(segmentdir)/FontFace.cpp
+
+GrCharStream.lo: $(segmentdir)/GrCharStream.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrCharStream.lo -MD -MP -MF $(DEPDIR)/GrCharStream.Tpo -c -o GrCharStream.lo `test -f '$(segmentdir)/GrCharStream.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrCharStream.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrCharStream.Tpo $(DEPDIR)/GrCharStream.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrCharStream.cpp' object='GrCharStream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrCharStream.lo `test -f '$(segmentdir)/GrCharStream.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrCharStream.cpp
+
+GrClassTable.lo: $(segmentdir)/GrClassTable.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrClassTable.lo -MD -MP -MF $(DEPDIR)/GrClassTable.Tpo -c -o GrClassTable.lo `test -f '$(segmentdir)/GrClassTable.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrClassTable.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrClassTable.Tpo $(DEPDIR)/GrClassTable.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrClassTable.cpp' object='GrClassTable.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrClassTable.lo `test -f '$(segmentdir)/GrClassTable.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrClassTable.cpp
+
+GrEngine.lo: $(segmentdir)/GrEngine.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrEngine.lo -MD -MP -MF $(DEPDIR)/GrEngine.Tpo -c -o GrEngine.lo `test -f '$(segmentdir)/GrEngine.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrEngine.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrEngine.Tpo $(DEPDIR)/GrEngine.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrEngine.cpp' object='GrEngine.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrEngine.lo `test -f '$(segmentdir)/GrEngine.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrEngine.cpp
+
+GrFeature.lo: $(segmentdir)/GrFeature.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrFeature.lo -MD -MP -MF $(DEPDIR)/GrFeature.Tpo -c -o GrFeature.lo `test -f '$(segmentdir)/GrFeature.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrFeature.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrFeature.Tpo $(DEPDIR)/GrFeature.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrFeature.cpp' object='GrFeature.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrFeature.lo `test -f '$(segmentdir)/GrFeature.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrFeature.cpp
+
+GrFSM.lo: $(segmentdir)/GrFSM.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrFSM.lo -MD -MP -MF $(DEPDIR)/GrFSM.Tpo -c -o GrFSM.lo `test -f '$(segmentdir)/GrFSM.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrFSM.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrFSM.Tpo $(DEPDIR)/GrFSM.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrFSM.cpp' object='GrFSM.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrFSM.lo `test -f '$(segmentdir)/GrFSM.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrFSM.cpp
+
+GrGlyphTable.lo: $(segmentdir)/GrGlyphTable.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrGlyphTable.lo -MD -MP -MF $(DEPDIR)/GrGlyphTable.Tpo -c -o GrGlyphTable.lo `test -f '$(segmentdir)/GrGlyphTable.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrGlyphTable.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrGlyphTable.Tpo $(DEPDIR)/GrGlyphTable.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrGlyphTable.cpp' object='GrGlyphTable.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrGlyphTable.lo `test -f '$(segmentdir)/GrGlyphTable.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrGlyphTable.cpp
+
+GrPassActionCode.lo: $(segmentdir)/GrPassActionCode.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrPassActionCode.lo -MD -MP -MF $(DEPDIR)/GrPassActionCode.Tpo -c -o GrPassActionCode.lo `test -f '$(segmentdir)/GrPassActionCode.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrPassActionCode.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrPassActionCode.Tpo $(DEPDIR)/GrPassActionCode.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrPassActionCode.cpp' object='GrPassActionCode.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrPassActionCode.lo `test -f '$(segmentdir)/GrPassActionCode.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrPassActionCode.cpp
+
+GrPass.lo: $(segmentdir)/GrPass.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrPass.lo -MD -MP -MF $(DEPDIR)/GrPass.Tpo -c -o GrPass.lo `test -f '$(segmentdir)/GrPass.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrPass.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrPass.Tpo $(DEPDIR)/GrPass.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrPass.cpp' object='GrPass.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrPass.lo `test -f '$(segmentdir)/GrPass.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrPass.cpp
+
+GrSlotState.lo: $(segmentdir)/GrSlotState.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrSlotState.lo -MD -MP -MF $(DEPDIR)/GrSlotState.Tpo -c -o GrSlotState.lo `test -f '$(segmentdir)/GrSlotState.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrSlotState.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrSlotState.Tpo $(DEPDIR)/GrSlotState.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrSlotState.cpp' object='GrSlotState.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrSlotState.lo `test -f '$(segmentdir)/GrSlotState.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrSlotState.cpp
+
+GrSlotStream.lo: $(segmentdir)/GrSlotStream.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrSlotStream.lo -MD -MP -MF $(DEPDIR)/GrSlotStream.Tpo -c -o GrSlotStream.lo `test -f '$(segmentdir)/GrSlotStream.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrSlotStream.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrSlotStream.Tpo $(DEPDIR)/GrSlotStream.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrSlotStream.cpp' object='GrSlotStream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrSlotStream.lo `test -f '$(segmentdir)/GrSlotStream.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrSlotStream.cpp
+
+GrTableManager.lo: $(segmentdir)/GrTableManager.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT GrTableManager.lo -MD -MP -MF $(DEPDIR)/GrTableManager.Tpo -c -o GrTableManager.lo `test -f '$(segmentdir)/GrTableManager.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrTableManager.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/GrTableManager.Tpo $(DEPDIR)/GrTableManager.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/GrTableManager.cpp' object='GrTableManager.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o GrTableManager.lo `test -f '$(segmentdir)/GrTableManager.cpp' || echo '$(srcdir)/'`$(segmentdir)/GrTableManager.cpp
+
+MemoryUsage.lo: $(segmentdir)/MemoryUsage.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT MemoryUsage.lo -MD -MP -MF $(DEPDIR)/MemoryUsage.Tpo -c -o MemoryUsage.lo `test -f '$(segmentdir)/MemoryUsage.cpp' || echo '$(srcdir)/'`$(segmentdir)/MemoryUsage.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/MemoryUsage.Tpo $(DEPDIR)/MemoryUsage.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/MemoryUsage.cpp' object='MemoryUsage.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o MemoryUsage.lo `test -f '$(segmentdir)/MemoryUsage.cpp' || echo '$(srcdir)/'`$(segmentdir)/MemoryUsage.cpp
+
+Platform.lo: $(segmentdir)/Platform.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Platform.lo -MD -MP -MF $(DEPDIR)/Platform.Tpo -c -o Platform.lo `test -f '$(segmentdir)/Platform.cpp' || echo '$(srcdir)/'`$(segmentdir)/Platform.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Platform.Tpo $(DEPDIR)/Platform.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/Platform.cpp' object='Platform.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Platform.lo `test -f '$(segmentdir)/Platform.cpp' || echo '$(srcdir)/'`$(segmentdir)/Platform.cpp
+
+SegmentAux.lo: $(segmentdir)/SegmentAux.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SegmentAux.lo -MD -MP -MF $(DEPDIR)/SegmentAux.Tpo -c -o SegmentAux.lo `test -f '$(segmentdir)/SegmentAux.cpp' || echo '$(srcdir)/'`$(segmentdir)/SegmentAux.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/SegmentAux.Tpo $(DEPDIR)/SegmentAux.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/SegmentAux.cpp' object='SegmentAux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SegmentAux.lo `test -f '$(segmentdir)/SegmentAux.cpp' || echo '$(srcdir)/'`$(segmentdir)/SegmentAux.cpp
+
+Segment.lo: $(segmentdir)/Segment.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Segment.lo -MD -MP -MF $(DEPDIR)/Segment.Tpo -c -o Segment.lo `test -f '$(segmentdir)/Segment.cpp' || echo '$(srcdir)/'`$(segmentdir)/Segment.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Segment.Tpo $(DEPDIR)/Segment.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/Segment.cpp' object='Segment.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Segment.lo `test -f '$(segmentdir)/Segment.cpp' || echo '$(srcdir)/'`$(segmentdir)/Segment.cpp
+
+TestFSM.lo: $(segmentdir)/TestFSM.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestFSM.lo -MD -MP -MF $(DEPDIR)/TestFSM.Tpo -c -o TestFSM.lo `test -f '$(segmentdir)/TestFSM.cpp' || echo '$(srcdir)/'`$(segmentdir)/TestFSM.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TestFSM.Tpo $(DEPDIR)/TestFSM.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/TestFSM.cpp' object='TestFSM.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TestFSM.lo `test -f '$(segmentdir)/TestFSM.cpp' || echo '$(srcdir)/'`$(segmentdir)/TestFSM.cpp
+
+TestPasses.lo: $(segmentdir)/TestPasses.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestPasses.lo -MD -MP -MF $(DEPDIR)/TestPasses.Tpo -c -o TestPasses.lo `test -f '$(segmentdir)/TestPasses.cpp' || echo '$(srcdir)/'`$(segmentdir)/TestPasses.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TestPasses.Tpo $(DEPDIR)/TestPasses.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/TestPasses.cpp' object='TestPasses.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TestPasses.lo `test -f '$(segmentdir)/TestPasses.cpp' || echo '$(srcdir)/'`$(segmentdir)/TestPasses.cpp
+
+TransductionLog.lo: $(segmentdir)/TransductionLog.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TransductionLog.lo -MD -MP -MF $(DEPDIR)/TransductionLog.Tpo -c -o TransductionLog.lo `test -f '$(segmentdir)/TransductionLog.cpp' || echo '$(srcdir)/'`$(segmentdir)/TransductionLog.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TransductionLog.Tpo $(DEPDIR)/TransductionLog.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(segmentdir)/TransductionLog.cpp' object='TransductionLog.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TransductionLog.lo `test -f '$(segmentdir)/TransductionLog.cpp' || echo '$(srcdir)/'`$(segmentdir)/TransductionLog.cpp
+
+SegmentPainter.lo: $(painterdir)/SegmentPainter.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SegmentPainter.lo -MD -MP -MF $(DEPDIR)/SegmentPainter.Tpo -c -o SegmentPainter.lo `test -f '$(painterdir)/SegmentPainter.cpp' || echo '$(srcdir)/'`$(painterdir)/SegmentPainter.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/SegmentPainter.Tpo $(DEPDIR)/SegmentPainter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(painterdir)/SegmentPainter.cpp' object='SegmentPainter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SegmentPainter.lo `test -f '$(painterdir)/SegmentPainter.cpp' || echo '$(srcdir)/'`$(painterdir)/SegmentPainter.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-graphiteincludeHEADERS: $(graphiteinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(graphiteincludedir)" || $(MKDIR_P) "$(DESTDIR)$(graphiteincludedir)"
+ @list='$(graphiteinclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(graphiteincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(graphiteincludedir)/$$f'"; \
+ $(graphiteincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(graphiteincludedir)/$$f"; \
+ done
+
+uninstall-graphiteincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(graphiteinclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(graphiteincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(graphiteincludedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(graphiteincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-graphiteincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-graphiteincludeHEADERS \
+ uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am \
+ install-graphiteincludeHEADERS install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-graphiteincludeHEADERS \
+ uninstall-libLTLIBRARIES
+
+
+#EXTRA_DIST += $(painterdir)/*.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/FileFont.cpp b/Build/source/libs/graphite/engine-2.3.1/src/font/FileFont.cpp
new file mode 100644
index 00000000000..4600b788ed2
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/FileFont.cpp
@@ -0,0 +1,429 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999 - 2008 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FileFont.cpp
+Responsibility: Keith Stribley
+Last reviewed: Not yet.
+
+Description:
+ A Font is an object that represents a font-family + bold + italic setting, that contains
+ Graphite tables.
+----------------------------------------------------------------------------------------------*/
+
+#include "Main.h"
+
+#include "FontTableCache.h"
+#include "FileFont.h"
+#include <stdio.h>
+
+
+// TBD do this properly
+#define FUDGE_FACTOR 72
+#define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
+
+namespace gr
+{
+
+
+FileFont::FileFont()
+ : Font(),
+ m_pfile(NULL),
+ m_pTableCache(NULL),
+ m_mAscent(0),
+ m_mDescent(0),
+ m_mEmSquare(0),
+ m_pointSize(0),
+ m_dpiX(FUDGE_FACTOR),
+ m_dpiY(FUDGE_FACTOR),
+ m_fIsValid(false),
+ m_pHeader(NULL),
+ m_pTableDir(NULL),
+ m_xScale(1.0f),
+ m_yScale(1.0f)
+{
+ m_fItalic = false;
+ m_fBold = false;
+ // colors are not used
+ m_clrFore = (unsigned long)kclrBlack;
+ m_clrBack = (unsigned long)kclrTransparent;
+}
+
+FileFont::FileFont(FILE * pfile, float pointSize,
+ unsigned int dpiX, unsigned int dpiY)
+ : Font(),
+ m_pfile(pfile),
+ m_pTableCache(NULL),
+ m_mAscent(0),
+ m_mDescent(0),
+ m_mEmSquare(0),
+ m_pointSize(pointSize),
+ m_dpiX(dpiX),
+ m_dpiY(dpiY),
+ m_fIsValid(false),
+ m_pHeader(NULL),
+ m_pTableDir(NULL),
+ m_xScale(1.0f),
+ m_yScale(1.0f)
+{
+ Assert(m_pfile); // shouldn't be null
+ initializeFromFace();
+
+}
+
+FileFont::FileFont(char * fileName, float pointSize,
+ unsigned int dpiX, unsigned int dpiY)
+ : Font(),
+ m_pfile(NULL),
+ m_pTableCache(NULL),
+ m_mAscent(0),
+ m_mDescent(0),
+ m_mEmSquare(0),
+ m_pointSize(pointSize),
+ m_dpiX(dpiX),
+ m_dpiY(dpiY),
+ m_fIsValid(false),
+ m_pHeader(NULL),
+ m_pTableDir(NULL),
+ m_xScale(1.0f),
+ m_yScale(1.0f)
+{
+ Assert(fileName); // shouldn't be null but we play safe anyway
+ m_pfile = fopen(fileName, "rb");
+
+ initializeFromFace();
+}
+
+FileFont::FileFont(std::string fileName, float pointSize,
+ unsigned int dpiX, unsigned int dpiY)
+ : Font(),
+ m_pfile(NULL),
+ m_pTableCache(NULL),
+ m_mAscent(0),
+ m_mDescent(0),
+ m_mEmSquare(0),
+ m_pointSize(pointSize),
+ m_dpiX(dpiX),
+ m_dpiY(dpiY),
+ m_fIsValid(false),
+ m_pHeader(NULL),
+ m_pTableDir(NULL),
+ m_xScale(1.0f),
+ m_yScale(1.0f)
+{
+ Assert(fileName.length()); // shouldn't be null but we play safe anyway
+ m_pfile = fopen(fileName.c_str(), "rb");
+
+ initializeFromFace();
+}
+
+
+void
+FileFont::initializeFromFace()
+{
+ if (m_dpiY == 0) m_dpiY = m_dpiX;
+ m_fItalic = false;
+ m_fBold = false;
+ // colors are not used
+ m_clrFore = (unsigned long)kclrBlack;
+ m_clrBack = (unsigned long)kclrTransparent;
+
+ if (m_pfile)
+ {
+ size_t lOffset, lSize;
+ TtfUtil::GetHeaderInfo(lOffset, lSize);
+ m_pHeader = new byte [lSize];
+ m_fIsValid = true;
+ if (!m_pHeader)
+ {
+ m_fIsValid = false;
+ return;
+ }
+ m_fIsValid = (fseek(m_pfile, lOffset, SEEK_SET) == 0);
+ size_t bytesRead = fread(m_pHeader, 1, lSize, m_pfile);
+ Assert(bytesRead == lSize);
+ m_fIsValid = TtfUtil::CheckHeader(m_pHeader);
+
+ if (!m_fIsValid) return;
+ m_fIsValid = TtfUtil::GetTableDirInfo(m_pHeader, lOffset, lSize);
+ m_pTableDir = new byte[lSize];
+ if (!m_pTableDir)
+ {
+ m_fIsValid = false;
+ return;
+ }
+ // if lOffset hasn't changed this isn't needed
+ fseek(m_pfile, lOffset, SEEK_SET);
+ bytesRead = fread(m_pTableDir, 1, lSize, m_pfile);
+ Assert(bytesRead == lSize);
+
+ // now read head tables
+ m_fIsValid = TtfUtil::GetTableInfo(ktiOs2, m_pHeader, m_pTableDir,
+ lOffset, lSize);
+ if (!m_fIsValid)
+ {
+ return;
+ }
+ byte * pTable = readTable(ktiOs2, lSize);
+ // get ascent, descent, style while we have the OS2 table loaded
+ if (!m_fIsValid || !pTable)
+ {
+ return;
+ }
+ m_fIsValid = TtfUtil::FontOs2Style(pTable, m_fBold, m_fItalic);
+ m_mAscent = static_cast<float>(TtfUtil::FontAscent(pTable));
+ m_mDescent = static_cast<float>(TtfUtil::FontDescent(pTable));
+
+ pTable = readTable(ktiName, lSize);
+ if (!m_fIsValid || !pTable)
+ {
+ return;
+ }
+ if (!TtfUtil::Get31EngFamilyInfo(pTable, lOffset, lSize))
+ {
+ // not English name
+ m_fIsValid = false;
+ return;
+ }
+ Assert(lSize %2 == 0);// should be utf16
+ utf16 rgchwFace[128];
+ int cchw = (lSize / isizeof(utf16)) + 1;
+ cchw = min(cchw, 128);
+ utf16 * pTable16 = reinterpret_cast<utf16*>(pTable + lOffset);
+ std::copy(pTable16, pTable16 + cchw - 1, rgchwFace);
+ rgchwFace[cchw - 1] = 0; // zero terminate
+ TtfUtil::SwapWString(rgchwFace, cchw - 1);
+// We could use something like "if (sizeof(std::wstring::value_type) == 4)" here,
+// but a compile-time switch is preferable.
+#if SIZEOF_WCHAR_T == 4
+ for (int cch16 = 0; cch16 < cchw; )
+ {
+ int cch16Used = 0;
+ utf32 ch32 = GrCharStream::Utf16ToUtf32(&(rgchwFace[cch16]),
+ cchw - cch16, &cch16Used);
+ m_stuFaceName.push_back(ch32);
+ cch16 += cch16Used;
+ }
+// }
+#else
+ m_stuFaceName.assign(rgchwFace);
+ // VS 2005 needs this:
+ //for (int cch16 = 0; cch16 < cchw; cch16++)
+ // m_stuFaceName.push_back(rgchwFace[cch16]);
+#endif
+ pTable = readTable(ktiHead, lSize);
+ if (!m_fIsValid || !pTable)
+ {
+ return;
+ }
+ m_mEmSquare = static_cast<float>(TtfUtil::DesignUnits(pTable));
+ // can now set the scale
+ m_xScale = scaleFromDpi(m_dpiX);
+ m_yScale = scaleFromDpi(m_dpiY);
+ }
+ else
+ {
+ m_fIsValid = false;
+ }
+}
+
+byte *
+FileFont::readTable(int /*TableId*/ tid, size_t & size)
+{
+ const TableId tableId = TableId(tid);
+ bool isValid = true;
+ size_t lOffset = 0, lSize = 0;
+ if (!m_pTableCache)
+ {
+ m_pTableCache = new FontTableCache();
+ }
+ if (!m_pTableCache) return NULL;
+
+ byte * pTable = m_pTableCache->getTable(tableId);
+ size = m_pTableCache->getTableSize(tableId);
+ // check whether it is already in the cache
+ if (pTable) return pTable;
+ isValid &= TtfUtil::GetTableInfo(tableId, m_pHeader, m_pTableDir,
+ lOffset, lSize);
+ if (!isValid)
+ return NULL;
+ fseek(m_pfile, lOffset, SEEK_SET);
+ // only allocate if needed
+ pTable = m_pTableCache->allocateTable(tableId, lSize);
+
+ if (!pTable)
+ {
+ isValid = false;
+ return NULL;
+ }
+ size_t bytesRead = fread(pTable, 1, lSize, m_pfile);
+ isValid = bytesRead == lSize;
+ if (isValid)
+ {
+ isValid &= TtfUtil::CheckTable(tableId, pTable, lSize);
+ }
+ if (!isValid)
+ {
+ return 0;
+ }
+ size = lSize;
+ return pTable;
+}
+
+
+FileFont::~FileFont()
+{
+
+ // if this is the last copy of the font sharing these tables
+ // delete them
+ if (m_pTableCache)
+ {
+ m_pTableCache->decrementFontCount();
+ if (m_pTableCache->getFontCount() == 0)
+ {
+ delete [] m_pHeader;
+ delete [] m_pTableDir;
+ delete m_pTableCache;
+ m_pTableCache = NULL;
+ if (m_pfile)
+ fclose(m_pfile);
+ }
+ }
+ else
+ {
+ delete [] m_pHeader;
+ delete [] m_pTableDir;
+ if (m_pfile)
+ fclose(m_pfile);
+ }
+ // note the DecFontCount(); is done in the Font base class
+}
+
+Font * FileFont::copyThis()
+{
+ FileFont * copy = new FileFont(*this);
+ return copy;
+}
+
+/**
+* A copy constructor that allows a change of point size or dpi
+* The underlying table cache will be shared between the fonts, so
+* this should have a low overhead.
+*/
+FileFont::FileFont(const FileFont & font, float pointSize,
+ unsigned int dpiX, unsigned int dpiY)
+: Font(font),
+ m_pfile(font.m_pfile),
+ m_mAscent(font.m_mAscent),
+ m_mDescent(font.m_mDescent),
+ m_mEmSquare(font.m_mEmSquare),
+ m_pointSize(font.m_pointSize),
+ m_dpiX(font.m_dpiX),
+ m_dpiY(font.m_dpiY),
+ m_fIsValid(font.m_fIsValid),
+ m_pHeader(font.m_pHeader),
+ m_pTableDir(font.m_pTableDir),
+ m_xScale(font.m_xScale),
+ m_yScale(font.m_yScale)
+{
+ if (pointSize > 0)
+ {
+ m_pointSize = pointSize;
+ if (dpiX > 0)
+ {
+ m_dpiX = dpiX;
+ if (dpiY > 0) m_dpiY = dpiY;
+ else dpiY = dpiX;
+ }
+ m_xScale = scaleFromDpi(m_dpiX);
+ m_yScale = scaleFromDpi(m_dpiY);
+ }
+ m_fItalic = font.m_fItalic;
+ m_fBold = font.m_fBold;
+ // colors are not used
+ m_clrFore = font.m_clrFore;
+ m_clrBack = font.m_clrBack;
+ m_stuFaceName.assign(font.m_stuFaceName);
+
+ m_pTableCache = font.m_pTableCache;
+ // use the same table cache between instances
+ if (m_pTableCache)
+ m_pTableCache->incrementFontCount();
+
+
+ // I dont' see why we need to reget the face, but WinFont does
+ //m_pfface = FontFace::GetFontFace(this, m_fpropDef.szFaceName,
+ // m_fpropDef.fBold, m_fpropDef.fItalic);
+}
+
+
+
+ //virtual FontErrorCode isValidForGraphite(int * pnVersion = NULL, int * pnSubVersion = NULL);
+
+/*----------------------------------------------------------------------------------------------
+ Read a table from the font.
+----------------------------------------------------------------------------------------------*/
+const void *
+FileFont::getTable(fontTableId32 tableID, size_t * pcbSize)
+{
+ *pcbSize = 0;
+ // use a cache to reduce the number of times tables have to be reloaded
+ if (m_pTableCache == NULL)
+ {
+ // constructor automatically sets the font count to 1
+ m_pTableCache = new FontTableCache();
+ }
+ TableId tid;
+ for (int i = 0; i<ktiLast; i++)
+ {
+ tid = static_cast<TableId>(i);
+ if (tableID == TtfUtil::TableIdTag(tid))
+ {
+ if (m_pTableCache->getTable(tid))
+ {
+ *pcbSize = m_pTableCache->getTableSize(tid);
+ return m_pTableCache->getTable(tid);
+ }
+ break;
+ }
+ }
+ Assert(tid < ktiLast);
+ size_t tableSize = 0;
+ void * pTable = readTable(tid, tableSize);
+ *pcbSize = static_cast<int>(tableSize);
+ return pTable;
+}
+
+
+void FileFont::getFontMetrics(float * pAscent, float * pDescent,
+ float * pEmSquare)
+{
+ if (pEmSquare) *pEmSquare = m_mEmSquare * m_xScale;
+ if (pAscent) *pAscent = m_mAscent * m_yScale;
+ if (pDescent) *pDescent = m_mDescent * m_yScale;
+}
+
+
+bool FileFont::FontHasGraphiteTables(FILE * file)
+{
+ FileFont testFont(file, 1.0f, FUDGE_FACTOR);
+ return testFont.fontHasGraphiteTables();
+}
+
+bool FileFont::FontHasGraphiteTables(char * fileName)
+{
+ FileFont testFont(fileName, 1.0f, FUDGE_FACTOR);
+ return testFont.fontHasGraphiteTables();
+}
+
+bool FileFont::fontHasGraphiteTables()
+{
+ size_t tableSize;
+ bool isGraphiteFont = m_fIsValid;
+ isGraphiteFont &= (readTable(ktiSilf, tableSize) != NULL);
+ return isGraphiteFont;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/Font.cpp b/Build/source/libs/graphite/engine-2.3.1/src/font/Font.cpp
new file mode 100644
index 00000000000..02a5769d809
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/Font.cpp
@@ -0,0 +1,949 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999 - 2008 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: Font.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ A font is an object that knows how to read tables from a (platform-specific) font resource.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Font methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Constructor.
+----------------------------------------------------------------------------------------------*/
+Font::Font(const Font & fontSrc) : m_pfface(fontSrc.m_pfface), m_fTablesCached(false)
+{
+ if (m_pfface)
+ m_pfface->IncFontCount();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructor.
+----------------------------------------------------------------------------------------------*/
+Font::~Font()
+{
+ if (m_pfface)
+ m_pfface->DecFontCount();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Mark the font-cache as to whether it should be deleted when all the font instances go away.
+----------------------------------------------------------------------------------------------*/
+void Font::SetFlushMode(int flush)
+{
+ FontFace::SetFlushMode(flush);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Cache the common tables if necessary.
+----------------------------------------------------------------------------------------------*/
+void Font::EnsureTablesCached()
+{
+ if (m_fTablesCached)
+ return;
+
+ size_t cbBogus;
+ m_pHead = getTable(TtfUtil::TableIdTag(ktiHead), &cbBogus);
+ m_pHmtx = getTable(TtfUtil::TableIdTag(ktiHmtx), &m_cbHmtxSize);
+ m_pGlyf = getTable(TtfUtil::TableIdTag(ktiGlyf), &cbBogus);
+ m_pLoca = getTable(TtfUtil::TableIdTag(ktiLoca), &m_cbLocaSize);
+
+ // getTable can return 0 for the lengths if it is hard to calculate them, but it should
+ // never do that for hmtx or loca.
+ Assert(m_cbHmtxSize > 0);
+ Assert(m_cbLocaSize > 0);
+
+ m_fTablesCached = true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the flush mode of the font-cache.
+----------------------------------------------------------------------------------------------*/
+int Font::GetFlushMode()
+{
+ return FontFace::GetFlushMode();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the internal object representing the font-face. This is the object that is stored
+ in Graphite's internal cache.
+----------------------------------------------------------------------------------------------*/
+inline FontFace & Font::fontFace(bool fDumbFallback)
+{
+ if (m_pfface == 0)
+ initialiseFontFace(fDumbFallback);
+ return *m_pfface;
+}
+
+void Font::initialiseFontFace(bool fDumbFallback)
+{
+ std::wstring stuFaceName;
+ bool fBold, fItalic;
+
+ UniqueCacheInfo(stuFaceName, fBold, fItalic);
+
+ m_pfface = FontFace::GetFontFace(this, stuFaceName, fBold, fItalic, fDumbFallback);
+
+ Assert(m_pfface != 0);
+
+ m_pfface->IncFontCount();
+
+ FontException fexptn;
+ fexptn.version = -1;
+ fexptn.subVersion = -1;
+ if (m_pfface->BadFont(&fexptn.errorCode)
+ || (!fDumbFallback && m_pfface->DumbFallback(&fexptn.errorCode)))
+ {
+ throw fexptn;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return uniquely identifying information that will be used as the key for this font
+ in the font cache. This includes the font face name and the bold and italic flags.
+----------------------------------------------------------------------------------------------*/
+void Font::UniqueCacheInfo(std::wstring & stuFace, bool & fBold, bool & fItalic)
+{
+ size_t cbSize;
+ const byte * pNameTbl = static_cast<const byte *>(getTable(TtfUtil::TableIdTag(ktiName), &cbSize));
+ size_t lOffset, lSize;
+ if (!TtfUtil::Get31EngFamilyInfo(pNameTbl, lOffset, lSize))
+ {
+ // TODO: try to find any name in any arbitrary language.
+ Assert(false);
+ return;
+ }
+ // byte * pvName = (byte *)pNameTbl + lOffset;
+ utf16 rgchwFace[128];
+ const size_t cchw = min(long(lSize / sizeof(utf16)), long(sizeof rgchwFace - 1));
+ const utf16 *src_start = reinterpret_cast<const utf16 *>(pNameTbl+ lOffset);
+ std::copy(src_start, src_start + cchw, rgchwFace);
+ rgchwFace[cchw] = 0; // zero terminate
+ TtfUtil::SwapWString(rgchwFace, cchw);
+ for (size_t ich16 = 0; ich16 < cchw; ich16++) // to handle situation where wchar_t is 4 bytes
+ stuFace.push_back(wchar_t(rgchwFace[ich16]));
+ ///stuFace.assign(rgchwFace, rgchwFace + cchw);
+
+ const void * pOs2Tbl = getTable(TtfUtil::TableIdTag(ktiOs2), &cbSize);
+ TtfUtil::FontOs2Style(pOs2Tbl, fBold, fItalic);
+ // Do we need to compare the results from the OS2 table with the italic flag in the
+ // head table? (There is no requirement that they be consistent!)
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ A default unhinted implmentation of getGlyphPoint(..)
+----------------------------------------------------------------------------------------------*/
+void Font::getGlyphPoint(gid16 glyphID, unsigned int pointNum, Point & pointReturn)
+{
+ EnsureTablesCached();
+
+ // Default values
+ pointReturn.x = 0;
+ pointReturn.y = 0;
+
+ if (m_pGlyf == 0) return;
+ if (m_pHead == 0) return;
+ if (m_pLoca == 0) return;
+
+ size_t cContours;
+ size_t cPoints;
+
+ const size_t CONTOUR_BUF_SIZE = 16;
+ const size_t POINT_BUF_SIZE = 64;
+ // Fixed-size buffers that will be used in most cases:
+ bool rgfOnCurveFixedBuf[POINT_BUF_SIZE], *rgfOnCurveHeapBuf=0;
+ int rgnEndPtFixedBuf[CONTOUR_BUF_SIZE], *rgnEndPtHeapBuf=0,
+ rgnXFixedBuf[POINT_BUF_SIZE], *rgnXHeapBuf=0,
+ rgnYFixedBuf[POINT_BUF_SIZE], *rgnYHeapBuf=0;
+
+ if (!TtfUtil::GlyfContourCount(glyphID, m_pGlyf, m_pLoca, m_cbLocaSize, m_pHead, cContours))
+ return; // can't figure it out
+
+ int * prgnEndPt = (cContours > CONTOUR_BUF_SIZE) ?
+ rgnEndPtHeapBuf = new int[cContours] :
+ rgnEndPtFixedBuf;
+
+ if (!TtfUtil::GlyfContourEndPoints(glyphID, m_pGlyf, m_pLoca, m_cbLocaSize, m_pHead,
+ prgnEndPt, cContours))
+ {
+ return; // should have been caught above
+ }
+ cPoints = prgnEndPt[cContours - 1] + 1;
+
+ bool* prgfOnCurve = (cPoints > POINT_BUF_SIZE) ? rgfOnCurveHeapBuf= new bool[cPoints] : rgfOnCurveFixedBuf;
+ int * prgnX = (cPoints > POINT_BUF_SIZE) ? rgnXHeapBuf= new int[cPoints] : rgnXFixedBuf;
+ int * prgnY = (cPoints > POINT_BUF_SIZE) ? rgnYHeapBuf= new int[cPoints] : rgnYFixedBuf;
+
+ if (TtfUtil::GlyfPoints(glyphID, m_pGlyf, m_pLoca, m_cbLocaSize, m_pHead, 0, 0,
+ prgnX, prgnY, prgfOnCurve, cPoints))
+ {
+ float nPixEmSquare;
+ getFontMetrics(0, 0, &nPixEmSquare);
+
+ const float nDesignUnitsPerPixel = float(TtfUtil::DesignUnits(m_pHead)) / nPixEmSquare;
+ pointReturn.x = prgnX[pointNum] / nDesignUnitsPerPixel;
+ pointReturn.y = prgnY[pointNum] / nDesignUnitsPerPixel;
+ }
+
+ delete[] rgnEndPtHeapBuf;
+ delete[] rgfOnCurveHeapBuf;
+ delete[] rgnXHeapBuf;
+ delete[] rgnYHeapBuf;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ A default unhinted implmentation of getGlyphMetrics(..)
+----------------------------------------------------------------------------------------------*/
+void Font::getGlyphMetrics(gid16 glyphID, gr::Rect & boundingBox, gr::Point & advances)
+{
+ EnsureTablesCached();
+
+ // Setup default return values in case of failiure.
+ boundingBox.left = 0;
+ boundingBox.right = 0;
+ boundingBox.bottom = 0;
+ boundingBox.top = 0;
+ advances.x = 0;
+ advances.y = 0;
+
+ if (m_pHead == 0) return;
+
+ // Calculate the number of design units per pixel.
+ float pixelEmSquare;
+ getFontMetrics(0, 0, &pixelEmSquare);
+ const float pixelsPerDesignUnit =
+ pixelEmSquare / float(TtfUtil::DesignUnits(m_pHead));
+
+ // getTable can return 0 for the lengths if it is hard to calculate them, but it should
+ // never do that for hmtx or loca.
+ Assert(m_cbHmtxSize > 0);
+
+ // Use the Hmtx and Head tables to find the glyph advances.
+ int lsb;
+ unsigned int advance = 0;
+ if (TtfUtil::HorMetrics(glyphID, m_pHmtx, m_cbHmtxSize, m_pHead,
+ lsb, advance))
+ {
+ advances.x = (advance * pixelsPerDesignUnit);
+ advances.y = 0.0f;
+ }
+
+ if (m_pGlyf == 0) return;
+ if (m_pLoca == 0) return;
+ Assert(m_cbLocaSize > 0);
+
+ // Fetch the glyph bounding box. GlyphBox may return false for a whitespace glyph.
+ // Note that using GlyfBox here allows attachment points (ie, points lying outside
+ // the glyph's outline) to affect the bounding box, which might not be what we want.
+ int xMin, xMax, yMin, yMax;
+ if (TtfUtil::GlyfBox(glyphID, m_pGlyf, m_pLoca, m_cbLocaSize, m_pHead,
+ xMin, yMin, xMax, yMax))
+ {
+ boundingBox.left = (xMin * pixelsPerDesignUnit);
+ boundingBox.bottom = (yMin * pixelsPerDesignUnit);
+ boundingBox.right = (xMax * pixelsPerDesignUnit);
+ boundingBox.top = (yMax * pixelsPerDesignUnit);
+ }
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Return a pair of iterators over a sequence of features defined for the font.
+----------------------------------------------------------------------------------------------*/
+std::pair<FeatureIterator, FeatureIterator> Font::getFeatures()
+{
+ std::pair<FeatureIterator, FeatureIterator> pairRet;
+ pairRet.first = BeginFeature();
+ pairRet.second = EndFeature();
+ return pairRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns an iterator indicating the feature with the given ID. If no such feature,
+ returns the end iterator.
+----------------------------------------------------------------------------------------------*/
+FeatureIterator Font::featureWithID(featid id)
+{
+ FeatureIterator fit = BeginFeature();
+ FeatureIterator fitEnd = EndFeature();
+ for ( ; fit != fitEnd ; ++fit)
+ {
+ if (*fit == id)
+ return fit;
+ }
+ return fitEnd; // invalid
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns the UI label for the indicated feature. Return false if there is no label for the
+ language, or it is empty.
+----------------------------------------------------------------------------------------------*/
+bool Font::getFeatureLabel(FeatureIterator fit, lgid nLanguage, utf16 * label)
+{
+ return GetFeatureLabel(fit.m_ifeat, nLanguage, label);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns an iterator pointing at the default value for the feature.
+----------------------------------------------------------------------------------------------*/
+FeatureSettingIterator Font::getDefaultFeatureValue(FeatureIterator fit)
+{
+ size_t ifset = GetFeatureDefault(fit.m_ifeat);
+ FeatureSettingIterator fsit = fit.BeginSetting();
+ fsit += ifset;
+ return fsit;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns a pair of iterators spanning the defined settings for the feature.
+----------------------------------------------------------------------------------------------*/
+std::pair<FeatureSettingIterator, FeatureSettingIterator>
+ Font::getFeatureSettings(FeatureIterator fit)
+{
+ std::pair<FeatureSettingIterator, FeatureSettingIterator> pairRet;
+ pairRet.first = fit.BeginSetting();
+ pairRet.second = fit.EndSetting();
+ return pairRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns the UI label for the indicated feature. Return false if there is no label for the
+ language, or it is empty.
+----------------------------------------------------------------------------------------------*/
+bool Font::getFeatureSettingLabel(FeatureSettingIterator fsit, lgid nLanguage, utf16 * label)
+{
+ //FeatureIterator * pfit = static_cast<FeatureIterator *>(fsit.m_pfit);
+ return GetFeatureSettingLabel(fsit.m_fit.m_ifeat, fsit.m_ifset, nLanguage, label);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Private methods for feature and language access.
+----------------------------------------------------------------------------------------------*/
+size_t Font::NumberOfFeatures()
+{
+ try {
+ return fontFace().NumberOfFeatures();
+ }
+ catch (...) { return 0; }
+}
+featid Font::FeatureID(size_t ifeat)
+{
+ try {
+ return fontFace().FeatureID(ifeat);
+ }
+ catch (...) { return 0; }
+}
+size_t Font::FeatureWithID(featid id)
+{
+ try {
+ return fontFace().FeatureWithID(id);
+ }
+ catch (...) { return 0; }
+}
+bool Font::GetFeatureLabel(size_t ifeat, lgid language, utf16 * label)
+{
+ try {
+ return fontFace().GetFeatureLabel(ifeat, language, label);
+ }
+ catch (...)
+ {
+ *label = 0;
+ return false;
+ }
+}
+int Font::GetFeatureDefault(size_t ifeat) // index of default setting
+{
+ try {
+ return fontFace().GetFeatureDefault(ifeat);
+ }
+ catch (...) { return 0; }
+}
+size_t Font::NumberOfSettings(size_t ifeat)
+{
+ try {
+ return fontFace().NumberOfSettings(ifeat);
+ }
+ catch (...) { return 0; }
+}
+int Font::GetFeatureSettingValue(size_t ifeat, size_t ifset)
+{
+ try {
+ return fontFace().GetFeatureSettingValue(ifeat, ifset);
+ }
+ catch (...) { return 0; }
+}
+bool Font::GetFeatureSettingLabel(size_t ifeat, size_t ifset, lgid language, utf16 * label)
+{
+ try {
+ return fontFace().GetFeatureSettingLabel(ifeat, ifset, language, label);
+ }
+ catch (...)
+ {
+ *label = 0;
+ return false;
+ }
+}
+size_t Font::NumberOfFeatLangs()
+{
+ try {
+ return fontFace().NumberOfFeatLangs();
+ }
+ catch (...) { return 0; }
+}
+short Font::FeatLabelLang(size_t ilang)
+{
+ try {
+ return fontFace().FeatLabelLang(ilang);
+ }
+ catch (...) { return 0; }
+}
+size_t Font::NumberOfLanguages()
+{
+ try {
+ return fontFace().NumberOfLanguages();
+ }
+ catch (...) { return 0; }
+}
+isocode Font::LanguageCode(size_t ilang)
+{
+ try {
+ return fontFace().LanguageCode(ilang);
+ }
+ catch (...)
+ {
+ isocode ret;
+ std::fill_n(ret.rgch, sizeof(ret.rgch), '\0');
+ return ret;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pair of iterators over a sequence of feature-label languages for this font.
+----------------------------------------------------------------------------------------------*/
+std::pair<FeatLabelLangIterator, FeatLabelLangIterator> Font::getFeatureLabelLanguages()
+{
+ std::pair<FeatLabelLangIterator, FeatLabelLangIterator> pairRet;
+ pairRet.first = BeginFeatLang();
+ pairRet.second = EndFeatLang();
+ return pairRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pair of iterators over a sequence of languages defined for the font, that is,
+ those that have features specified for them.
+----------------------------------------------------------------------------------------------*/
+std::pair<LanguageIterator, LanguageIterator> Font::getSupportedLanguages()
+{
+ std::pair<LanguageIterator, LanguageIterator> pairRet;
+ pairRet.first = BeginLanguage();
+ pairRet.second = EndLanguage();
+ return pairRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a bitmap indicating which directions are supported by the font.
+----------------------------------------------------------------------------------------------*/
+ScriptDirCode Font::getSupportedScriptDirections() const throw()
+{
+ try {
+ Font * pfontThis = const_cast<Font *>(this);
+ FontFace & fface = pfontThis->fontFace();
+ return fface.ScriptDirection();
+ }
+ catch (...) {
+ return kfsdcHorizLtr;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ For segment creation.
+----------------------------------------------------------------------------------------------*/
+void Font::RenderLineFillSegment(Segment * pseg, ITextSource * pts, LayoutEnvironment & layout,
+ toffset ichStart, toffset ichStop, float xsMaxWidth, bool fBacktracking)
+{
+ fontFace(layout.dumbFallback()).RenderLineFillSegment(pseg, this, pts, layout,
+ ichStart, ichStop, xsMaxWidth, fBacktracking);
+}
+
+void Font::RenderRangeSegment(Segment * pseg, ITextSource * pts, LayoutEnvironment & layout,
+ toffset ichStart, toffset ichStop)
+{
+ fontFace(layout.dumbFallback()).RenderRangeSegment(pseg, this, pts, layout, ichStart, ichStop);
+}
+
+void Font::RenderJustifiedSegment(Segment * pseg, ITextSource * pts,
+ LayoutEnvironment & layout, toffset ichStart, toffset ichStop,
+ float xsCurrentWidth, float xsDesiredWidth)
+{
+ fontFace(layout.dumbFallback()).RenderJustifiedSegment(pseg, this, pts, layout,
+ ichStart, ichStop, xsCurrentWidth, xsDesiredWidth);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Feature iterators.
+----------------------------------------------------------------------------------------------*/
+FeatureIterator Font::BeginFeature()
+{
+ FeatureIterator fit(this, 0, NumberOfFeatures());
+ return fit;
+}
+
+FeatureIterator Font::EndFeature()
+{
+ int cfeat = NumberOfFeatures();
+ FeatureIterator fit (this, cfeat, cfeat);
+ return fit;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Feature-label language iterators.
+----------------------------------------------------------------------------------------------*/
+FeatLabelLangIterator Font::BeginFeatLang()
+{
+ FeatLabelLangIterator lgit(this, 0, NumberOfFeatLangs());
+ return lgit;
+}
+
+FeatLabelLangIterator Font::EndFeatLang()
+{
+ int clang = NumberOfFeatLangs();
+ FeatLabelLangIterator lgit(this, clang, clang);
+ return lgit;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Language iterators.
+----------------------------------------------------------------------------------------------*/
+LanguageIterator Font::BeginLanguage()
+{
+ LanguageIterator lgit(this, 0, NumberOfLanguages());
+ return lgit;
+}
+
+LanguageIterator Font::EndLanguage()
+{
+ int clang = NumberOfLanguages();
+ LanguageIterator lgit(this, clang, clang);
+ return lgit;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Debugging.
+----------------------------------------------------------------------------------------------*/
+//bool Font::DbgCheckFontCache()
+//{
+// return FontFace::DbgCheckFontCache();
+//}
+
+
+//:>********************************************************************************************
+//:> FeatureIterator methods
+//:>********************************************************************************************
+
+//FeatureIterator::FeatureIterator(FeatureIterator & fitToCopy)
+//{
+// m_pfont = fitToCopy.m_pfont;
+// m_ifeat = fitToCopy.m_ifeat;
+// m_cfeat = fitToCopy.m_cfeat;
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Dereference the iterator, returning a feature ID.
+----------------------------------------------------------------------------------------------*/
+featid FeatureIterator::operator*()
+{
+ if (m_ifeat >= m_cfeat)
+ {
+ Assert(false);
+ return (unsigned int)kInvalid;
+ }
+
+ return m_pfont->FeatureID(m_ifeat);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator.
+----------------------------------------------------------------------------------------------*/
+FeatureIterator FeatureIterator::operator++()
+{
+ if (m_ifeat >= m_cfeat)
+ {
+ // Can't increment.
+ Assert(false);
+ }
+ else
+ m_ifeat++;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator by the given value.
+----------------------------------------------------------------------------------------------*/
+FeatureIterator FeatureIterator::operator+=(int n)
+{
+ if (m_ifeat + n >= m_cfeat)
+ {
+ // Can't increment.
+ Assert(false);
+ m_ifeat = m_cfeat;
+ }
+ else if (m_ifeat + n < 0)
+ {
+ // Can't decrement.
+ Assert(false);
+ m_ifeat = 0;
+ }
+ else
+ m_ifeat += m_cfeat;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test whether the two iterators are equal.
+----------------------------------------------------------------------------------------------*/
+bool FeatureIterator::operator==(FeatureIterator & fit)
+{
+ return (fit.m_ifeat == m_ifeat && fit.m_pfont == m_pfont);
+}
+
+bool FeatureIterator::operator!=(FeatureIterator & fit)
+{
+ return (fit.m_ifeat != m_ifeat || fit.m_pfont != m_pfont);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of items represented by the range of the two iterators.
+----------------------------------------------------------------------------------------------*/
+int FeatureIterator::operator-(FeatureIterator & fit)
+{
+ if (m_pfont != fit.m_pfont)
+ {
+ throw;
+ }
+ return (m_ifeat - fit.m_ifeat);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Iterators.
+----------------------------------------------------------------------------------------------*/
+FeatureSettingIterator FeatureIterator::BeginSetting()
+{
+ int cfset = m_pfont->NumberOfSettings(m_ifeat);
+ FeatureSettingIterator fsit(*this, 0, cfset);
+ return fsit;
+}
+
+FeatureSettingIterator FeatureIterator::EndSetting()
+{
+ int cfset = m_pfont->NumberOfSettings(m_ifeat);
+ FeatureSettingIterator fsit(*this, cfset, cfset);
+ return fsit;
+}
+
+
+//:>********************************************************************************************
+//:> FeatureSettingIterator methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Dereference the iterator, returning a feature value.
+----------------------------------------------------------------------------------------------*/
+int FeatureSettingIterator::operator*()
+{
+ if (m_ifset >= m_cfset)
+ {
+ Assert(false);
+ return kInvalid;
+ }
+
+ return m_fit.m_pfont->GetFeatureSettingValue(m_fit.m_ifeat, m_ifset);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator.
+----------------------------------------------------------------------------------------------*/
+FeatureSettingIterator FeatureSettingIterator::operator++()
+{
+ if (m_ifset >= m_cfset)
+ {
+ // Can't increment.
+ Assert(false);
+ }
+ else
+ m_ifset++;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator by the given value.
+----------------------------------------------------------------------------------------------*/
+FeatureSettingIterator FeatureSettingIterator::operator+=(int n)
+{
+ if (m_ifset + n >= m_cfset)
+ {
+ // Can't increment.
+ Assert(false);
+ m_ifset = m_cfset;
+ }
+ if (m_ifset + n < 0)
+ {
+ // Can't decrement.
+ Assert(false);
+ m_ifset = 0;
+ }
+ else
+ m_ifset += n;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test whether the two iterators are equal.
+----------------------------------------------------------------------------------------------*/
+bool FeatureSettingIterator::operator==(FeatureSettingIterator & fsit)
+{
+ //FeatureIterator * pfit = static_cast<FeatureIterator *>(m_pfit);
+ //FeatureIterator * pfitOther = static_cast<FeatureIterator *>(fsit.m_pfit);
+ //return (m_ifset == fsit.m_ifset && pfit == pfitOther);
+ return (m_ifset == fsit.m_ifset && m_fit == fsit.m_fit);
+}
+
+bool FeatureSettingIterator::operator!=(FeatureSettingIterator & fsit)
+{
+ //FeatureIterator * pfit = static_cast<FeatureIterator *>(m_pfit);
+ //FeatureIterator * pfitOther = static_cast<FeatureIterator *>(fsit.m_pfit);
+ //return (m_ifset != fsit.m_ifset || pfit != pfitOther);
+
+ return (m_ifset != fsit.m_ifset || m_fit != fsit.m_fit);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of items represented by the range of the two iterators.
+----------------------------------------------------------------------------------------------*/
+int FeatureSettingIterator::operator-(FeatureSettingIterator fsit)
+{
+ //FeatureIterator * pfit = static_cast<FeatureIterator *>(m_pfit);
+ //FeatureIterator * pfitOther = static_cast<FeatureIterator *>(fsit.m_pfit);
+ //if (pfit != pfitOther)
+
+ if (m_fit != fsit.m_fit)
+ {
+ throw;
+ }
+ return (m_ifset - fsit.m_ifset);
+}
+
+//:>********************************************************************************************
+//:> FeatLabelLangIterator methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Dereference the iterator, returning a language LCID.
+----------------------------------------------------------------------------------------------*/
+data16 FeatLabelLangIterator::operator*()
+{
+ if (m_ilang >= m_clang)
+ {
+ Assert(false);
+ return 0;
+ }
+
+ return m_pfont->FeatLabelLang(m_ilang);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator.
+----------------------------------------------------------------------------------------------*/
+FeatLabelLangIterator FeatLabelLangIterator::operator++()
+{
+ if (m_ilang >= m_clang)
+ {
+ // Can't increment.
+ Assert(false);
+ }
+ else
+ m_ilang++;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator by the given value.
+----------------------------------------------------------------------------------------------*/
+FeatLabelLangIterator FeatLabelLangIterator::operator+=(int n)
+{
+ if (m_ilang + n >= m_clang)
+ {
+ // Can't increment.
+ Assert(false);
+ m_ilang = m_clang;
+ }
+ else if (m_ilang + n < 0)
+ {
+ // Can't decrement.
+ Assert(false);
+ m_ilang = 0;
+ }
+ else
+ m_ilang += m_clang;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test whether the two iterators are equal.
+----------------------------------------------------------------------------------------------*/
+bool FeatLabelLangIterator::operator==(FeatLabelLangIterator & fllit)
+{
+ return (fllit.m_ilang == m_ilang && fllit.m_pfont == m_pfont);
+}
+
+bool FeatLabelLangIterator::operator!=(FeatLabelLangIterator & fllit)
+{
+ return (fllit.m_ilang != m_ilang || fllit.m_pfont != m_pfont);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of items represented by the range of the two iterators.
+----------------------------------------------------------------------------------------------*/
+int FeatLabelLangIterator::operator-(FeatLabelLangIterator & fllit)
+{
+ if (m_pfont != fllit.m_pfont)
+ {
+ throw;
+ }
+ return (m_ilang - fllit.m_ilang);
+}
+
+
+//:>********************************************************************************************
+//:> LanguageIterator methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Dereference the iterator, returning a language code.
+----------------------------------------------------------------------------------------------*/
+isocode LanguageIterator::operator*()
+{
+ if (m_ilang >= m_clang)
+ {
+ Assert(false);
+ isocode codeRet;
+ codeRet.rgch[0] = '?'; codeRet.rgch[1] = '?';
+ codeRet.rgch[2] = '?'; codeRet.rgch[3] = 0;
+ return codeRet;
+ }
+
+ return m_pfont->LanguageCode(m_ilang);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator.
+----------------------------------------------------------------------------------------------*/
+LanguageIterator LanguageIterator::operator++()
+{
+ if (m_ilang >= m_clang)
+ {
+ // Can't increment.
+ Assert(false);
+ }
+ else
+ m_ilang++;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Increment the iterator by the given value.
+----------------------------------------------------------------------------------------------*/
+LanguageIterator LanguageIterator::operator+=(int n)
+{
+ if (m_ilang + n >= m_clang)
+ {
+ // Can't increment.
+ Assert(false);
+ m_ilang = m_clang;
+ }
+ else if (m_ilang + n < 0)
+ {
+ // Can't decrement.
+ Assert(false);
+ m_ilang = 0;
+ }
+ else
+ m_ilang += m_clang;
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test whether the two iterators are equal.
+----------------------------------------------------------------------------------------------*/
+bool LanguageIterator::operator==(LanguageIterator & lgit)
+{
+ return (lgit.m_ilang == m_ilang && lgit.m_pfont == m_pfont);
+}
+
+bool LanguageIterator::operator!=(LanguageIterator & lgit)
+{
+ return (lgit.m_ilang != m_ilang || lgit.m_pfont != m_pfont);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of items represented by the range of the two iterators.
+----------------------------------------------------------------------------------------------*/
+int LanguageIterator::operator-(LanguageIterator & lgit)
+{
+ if (m_pfont != lgit.m_pfont)
+ {
+ throw;
+ }
+ return (m_ilang - lgit.m_ilang);
+}
+
+
+} // namespace gr
+
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/FontTableCache.h b/Build/source/libs/graphite/engine-2.3.1/src/font/FontTableCache.h
new file mode 100644
index 00000000000..461b00d745f
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/FontTableCache.h
@@ -0,0 +1,52 @@
+
+#include "TtfUtil.h"
+
+namespace gr
+{
+
+
+// used to allow table sharing among font copies
+// TBD: should this be a real class or is it acceptable to
+// make the attributes public
+class FontTableCache
+{
+public:
+ FontTableCache()
+ : m_fontCount(1)
+ {
+ for (int i = 0; i<ktiLast; i++)
+ {
+ m_pTable[i] = NULL;
+ }
+ }
+ ~FontTableCache()
+ {
+ Assert(m_fontCount == 0);
+ for (int i = 0; i<ktiLast; i++)
+ {
+ if (m_pTable[i]) delete[] m_pTable[i];
+ }
+ }
+ const int & getFontCount() { return m_fontCount; }
+ void incrementFontCount() { m_fontCount++; }
+ void decrementFontCount() { m_fontCount--; Assert(m_fontCount > -1); }
+ byte * getTable(TableId id) const { Assert(id < ktiLast); return m_pTable[id]; }
+ const long & getTableSize(TableId id) const
+ {
+ Assert(id < ktiLast);
+ return m_tableSize[id];
+ }
+ byte * allocateTable(TableId id, long size)
+ {
+ m_pTable[id] = new byte[size];
+ m_tableSize[id] = size;
+ return m_pTable[id];
+ }
+
+private:
+ int m_fontCount;
+ byte * m_pTable[ktiLast];
+ long m_tableSize[ktiLast];
+};
+
+}
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/Makefile.am b/Build/source/libs/graphite/engine-2.3.1/src/font/Makefile.am
new file mode 100644
index 00000000000..461af621b49
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/Makefile.am
@@ -0,0 +1,7 @@
+fontdir = $(top_srcdir)/src/font
+
+libgraphite_la_SOURCES += $(fontdir)/Font.cpp
+libgraphite_la_SOURCES += $(fontdir)/TtfUtil.cpp
+libgraphite_la_SOURCES += $(fontdir)/FileFont.cpp
+
+EXTRA_DIST += $(fontdir)/*.h
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/TtfTypes.h b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfTypes.h
new file mode 100644
index 00000000000..da8d90f1f26
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfTypes.h
@@ -0,0 +1,388 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2007 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TtfTypes.h
+Responsibility: Tim Eves
+Last reviewed: Not yet.
+
+Description:
+Provides types required to represent the TTF basic types.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+
+//**********************************************************************************************
+// Include files
+//**********************************************************************************************
+#include "GrPlatform.h"
+
+namespace TtfUtil
+{
+//**********************************************************************************************
+// Forward declarations
+//**********************************************************************************************
+
+
+//**********************************************************************************************
+// Type declarations
+//**********************************************************************************************
+typedef gr::data8 uint8;
+typedef gr::sdata8 int8;
+typedef gr::data16 uint16;
+typedef gr::sdata16 int16;
+typedef gr::data32 uint32;
+typedef gr::sdata32 int32;
+
+typedef int16 short_frac;
+typedef int32 fixed;
+typedef int16 fword;
+typedef uint16 ufword;
+typedef int16 f2dot14;
+typedef uint32 long_date_time[2];
+
+//**********************************************************************************************
+// Constants and enum types
+//**********************************************************************************************/
+enum
+{
+ OneFix = 1<<16
+};
+
+//**********************************************************************************************
+// Table declarations
+//**********************************************************************************************
+namespace Sfnt
+{
+#pragma pack(1) // We need this or the structure members aren't alligned
+ // correctly. Fortunately this form of pragma is supposed
+ // to be recongnised by VS C++ too (at least according to
+ // MSDN).
+
+ struct OffsetSubTable
+ {
+ uint32 scaler_type;
+ uint16 num_tables,
+ search_range,
+ entry_selector,
+ range_shift;
+ struct Entry
+ {
+ uint32 tag,
+ checksum,
+ offset,
+ length;
+ } table_directory[1];
+
+ enum ScalerType
+ {
+ TrueTypeMac = 0x74727565U,
+ TrueTypeWin = 0x00010000U,
+ Type1 = 0x74797031U
+ };
+ };
+
+
+
+
+ struct CharacterCodeMap
+ {
+ uint16 version,
+ num_subtables;
+ struct
+ {
+ uint16 platform_id,
+ platform_specific_id;
+ uint32 offset;
+ } encoding[1];
+ };
+
+ struct CmapSubTable
+ {
+ uint16 format,
+ length,
+ language;
+ };
+
+ struct CmapSubTableFormat4 : CmapSubTable
+ {
+ uint16 seg_count_x2,
+ search_range,
+ entry_selector,
+ range_shift,
+ end_code[1];
+ // There are arrarys after this which need their
+ // start positions calculated since end_code is
+ // seg_count uint16s long.
+ };
+
+ struct CmapSubTableFormat12
+ {
+ fixed format;
+ uint32 length,
+ language,
+ num_groups;
+ struct
+ {
+ uint32 start_char_code,
+ end_char_code,
+ start_glyph_id;
+ } group[1];
+ };
+
+
+
+ struct FontHeader
+ {
+ fixed version,
+ font_revision;
+ uint32 check_sum_adjustment,
+ magic_number;
+ uint16 flags,
+ units_per_em;
+ long_date_time created,
+ modified;
+ fword x_min,
+ y_min,
+ x_max,
+ y_max;
+ uint16 mac_style,
+ lowest_rec_ppem;
+ int16 font_direction_hint,
+ index_to_loc_format,
+ glyph_data_format;
+ enum
+ {
+ MagicNumber = 0x5F0F3CF5,
+ GlypDataFormat = 0
+ };
+ enum {ShortIndexLocFormat, LongIndexLocFormat};
+ };
+
+
+
+
+ struct PostScriptGlyphName
+ {
+ fixed format,
+ italic_angle;
+ fword underline_position,
+ underline_thickness;
+ uint32 is_fixed_pitch,
+ min_mem_type42,
+ max_mem_type42,
+ min_mem_type1,
+ max_mem_type1;
+ enum
+ {
+ Format1 = 0x10000,
+ Format2 = 0x20000,
+ Format25 = 0x28000,
+ Format3 = 0x30000,
+ Format4 = 0x40000
+ };
+ };
+
+ struct PostScriptGlyphName2 : PostScriptGlyphName
+ {
+ uint16 number_of_glyphs,
+ glyph_name_index[1];
+ };
+
+ struct PostScriptGlyphName25 : PostScriptGlyphName
+ {
+ uint16 number_of_glyphs;
+ int8 offset[1];
+ };
+
+ struct PostScriptGlyphName3 : PostScriptGlyphName {};
+
+ struct PostScriptGlyphName4 : PostScriptGlyphName
+ {
+ uint16 glyph_to_char_map[1];
+ };
+
+
+ struct HorizontalHeader
+ {
+ fixed version;
+ fword ascent,
+ descent,
+ line_gap;
+ ufword advance_width_max;
+ fword min_left_side_bearing,
+ max_left_side_bearing,
+ x_max_element;
+ int16 caret_slope_rise,
+ caret_slope_run;
+ fword caret_offset;
+ int16 reserved[4],
+ metric_data_format;
+ uint16 num_long_hor_metrics;
+ };
+
+ struct MaximumProfile
+ {
+ fixed version;
+ uint16 num_glyphs,
+ max_points,
+ max_contours,
+ max_component_points,
+ max_component_contours,
+ max_zones,
+ max_twilight_points,
+ max_storage,
+ max_function_defs,
+ max_instruction_defs,
+ max_stack_elements,
+ max_size_of_instructions,
+ max_component_elements,
+ max_component_depth;
+ };
+
+
+ typedef gr::byte Panose[10];
+
+ struct Compatibility0
+ {
+ uint16 version;
+ int16 x_avg_char_width;
+ uint16 weight_class,
+ width_class;
+ int16 fs_type,
+ y_subscript_x_size,
+ y_subscript_y_size,
+ y_subscript_x_offset,
+ y_subscript_y_offset,
+ y_superscript_x_size,
+ y_superscript_y_size,
+ y_superscript_x_offset,
+ y_superscript_y_offset,
+ y_strikeout_size,
+ y_strikeout_position,
+ family_class;
+ Panose panose;
+ uint32 unicode_range[4];
+ int8 ach_vend_id[4];
+ uint16 fs_selection,
+ fs_first_char_index,
+ fs_last_char_index, // Acording to Apple's spec this is where v0 should end
+ typo_ascender,
+ typo_descender,
+ type_linegap,
+ win_ascent,
+ win_descent;
+
+ enum
+ {
+ Italic =0x01,
+ Underscore=0x02,
+ Negative =0x04,
+ Outlined =0x08,
+ StrikeOut =0x10,
+ Bold =0x20
+ };
+ };
+
+ struct Compatibility1 : Compatibility0
+ {
+ uint32 codepage_range[2];
+ };
+
+ struct Compatibility2 : Compatibility1
+ {
+ int16 x_height,
+ cap_height;
+ uint16 default_char,
+ break_char,
+ max_context;
+ };
+
+ struct Compatibility3 : Compatibility2 {};
+
+ typedef Compatibility3 Compatibility;
+
+
+ struct NameRecord
+ {
+ uint16 platform_id,
+ platform_specific_id,
+ language_id,
+ name_id,
+ length,
+ offset;
+ enum {Unicode, Mactintosh, Reserved, Microsoft};
+ enum
+ {
+ Copyright, Family, Subfamily, UniqueSubfamily,
+ Fullname, Version, PostScript
+ };
+ };
+
+ struct FontNames
+ {
+ uint16 format,
+ count,
+ string_offset;
+ NameRecord name_record[1];
+ };
+
+
+ struct HorizontalMetric
+ {
+ uint16 advance_width;
+ int16 left_side_bearing;
+ };
+
+
+ struct Glyph
+ {
+ int16 number_of_contours;
+ fword x_min,
+ y_min,
+ x_max,
+ y_max;
+ };
+
+ struct SimpleGlyph : Glyph
+ {
+ uint16 end_pts_of_contours[1];
+ enum
+ {
+ OnCurve = 0x01,
+ XShort = 0x02,
+ YShort = 0x04,
+ Repeat = 0x08,
+ XIsSame = 0x10,
+ XIsPos = 0x10,
+ YIsSame = 0x20,
+ YIsPos = 0x20
+ };
+ };
+
+ struct CompoundGlyph : Glyph
+ {
+ uint16 flags,
+ glyph_index;
+ enum
+ {
+ Arg1Arg2Words = 0x01,
+ ArgsAreXYValues = 0x02,
+ RoundXYToGrid = 0x04,
+ HaveScale = 0x08,
+ MoreComponents = 0x20,
+ HaveXAndYScale = 0x40,
+ HaveTwoByTwo = 0x80,
+ HaveInstructions = 0x100,
+ UseMyMetrics = 0x200,
+ OverlapCompund = 0x400,
+ ScaledOffset = 0x800,
+ UnscaledOffset = 0x1000
+ };
+ };
+
+#pragma pack()
+} // end of namespace Sfnt
+
+} // end of namespace TtfUtil
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.cpp b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.cpp
new file mode 100644
index 00000000000..4fe98adadb2
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.cpp
@@ -0,0 +1,1935 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2000, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TtfUtil.cpp
+Responsibility: Alan Ward
+Last reviewed: Not yet.
+
+Description:
+ Implements the methods for TtfUtil class. This file should remain portable to any C++
+ environment by only using standard C++ and the TTF structurs defined in Tt.h.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+
+/***********************************************************************************************
+ Include files
+***********************************************************************************************/
+// Language headers
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <climits>
+#include <stdexcept>
+// Platform headers
+// Module headers
+#include "TtfUtil.h"
+#include "TtfTypes.h"
+
+/***********************************************************************************************
+ Forward declarations
+***********************************************************************************************/
+
+/***********************************************************************************************
+ Local Constants and static variables
+***********************************************************************************************/
+namespace
+{
+ // max number of components allowed in composite glyphs
+ const int kMaxGlyphComponents = 8;
+
+ // These are basic byte order swapping functions
+ template<typename T> inline T rev16(const T d) {
+ T r = (d & 0xff) << 8; r |= (d & 0xff00) >> 8;
+ return r;
+ }
+
+ template<typename T> inline T rev32(const T d) {
+ T r = (d & 0xff) << 24; r |= (d & 0xff00) << 8;
+ r |= (d & 0xff0000) >> 8; r |= (d & 0xff000000) >> 24;
+ return r;
+ }
+
+ // This is the generic read function which does the swapping
+ template<typename T> inline T read(const T d) {
+ return d;
+ }
+
+#if !defined WORDS_BIGENDIAN || defined PC_OS
+ template<> inline TtfUtil::uint16 read(const TtfUtil::uint16 d) {
+ return rev16(d);
+ }
+
+ template<> inline TtfUtil::int16 read(const TtfUtil::int16 d) {
+ return rev16(d);
+ }
+
+ template<> inline TtfUtil::uint32 read(const TtfUtil::uint32 d) {
+ return rev32(d);
+ }
+
+ template<> inline TtfUtil::int32 read(const TtfUtil::int32 d) {
+ return rev32(d);
+ }
+#endif
+
+ template <int R, typename T>
+ inline float fixed_to_float(const T f) {
+ return float(f)/float(2^R);
+ }
+
+#define MAKE_TAG(a,b,c,d) ((a << 24UL) + (b << 16UL) + (c << 8UL) + (d))
+ const gr::fontTableId32 mapIdToTag[] = {
+ MAKE_TAG('c','m','a','p'),
+ MAKE_TAG('c','v','t',' '),
+ MAKE_TAG('c','r','y','p'),
+ MAKE_TAG('h','e','a','d'),
+ MAKE_TAG('f','p','g','m'),
+ MAKE_TAG('g','d','i','r'),
+ MAKE_TAG('g','l','y','f'),
+ MAKE_TAG('h','d','m','x'),
+ MAKE_TAG('h','h','e','a'),
+ MAKE_TAG('h','m','t','x'),
+ MAKE_TAG('l','o','c','a'),
+ MAKE_TAG('k','e','r','n'),
+ MAKE_TAG('L','T','S','H'),
+ MAKE_TAG('m','a','x','p'),
+ MAKE_TAG('n','a','m','e'),
+ MAKE_TAG('O','S','/','2'),
+ MAKE_TAG('p','o','s','t'),
+ MAKE_TAG('p','r','e','p'),
+ MAKE_TAG('F','e','a','t'),
+ MAKE_TAG('G','l','a','t'),
+ MAKE_TAG('G','l','o','c'),
+ MAKE_TAG('S','i','l','f'),
+ MAKE_TAG('S','i','l','e'),
+ MAKE_TAG('S','i','l','l')
+ };
+
+
+/*----------------------------------------------------------------------------------------------
+ Table of standard Postscript glyph names. From Martin Hosken. Disagress with ttfdump.exe
+---------------------------------------------------------------------------------------------*/
+ const int kcPostNames = 258;
+
+ const char * rgPostName[kcPostNames] = {
+ ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign",
+ "dollar", "percent", "ampersand", "quotesingle", "parenleft",
+ "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash",
+ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
+ "nine", "colon", "semicolon", "less", "equal", "greater", "question",
+ "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ "bracketleft", "backslash", "bracketright", "asciicircum",
+ "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i",
+ "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
+ "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis",
+ "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde",
+ "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis",
+ "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
+ "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave",
+ "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
+ "section", "bullet", "paragraph", "germandbls", "registered",
+ "copyright", "trademark", "acute", "dieresis", "notequal", "AE",
+ "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen",
+ "mu", "partialdiff", "summation", "product", "pi", "integral",
+ "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown",
+ "exclamdown", "logicalnot", "radical", "florin", "approxequal",
+ "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace",
+ "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash",
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
+ "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
+ "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered",
+ "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
+ "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
+ "circumflex", "tilde", "macron", "breve", "dotaccent", "ring",
+ "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
+ "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
+ "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply",
+ "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter",
+ "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla",
+ "scedilla", "Cacute", "cacute", "Ccaron", "ccaron",
+ "dcroat" };
+
+} // end of namespace
+
+/***********************************************************************************************
+ Methods
+***********************************************************************************************/
+
+/* Note on error processing: The code guards against bad glyph ids being used to look up data
+in open ended tables (loca, hmtx). If the glyph id comes from a cmap this shouldn't happen
+but it seems prudent to check for user errors here. The code does assume that data obtained
+from the TTF file is valid otherwise (though the CheckTable method seeks to check for
+obvious problems that might accompany a change in table versions). For example an invalid
+offset in the loca table which could exceed the size of the glyf table is NOT trapped.
+Likewise if numberOf_LongHorMetrics in the hhea table is wrong, this will NOT be trapped,
+which could cause a lookup in the hmtx table to exceed the table length. Of course, TTF tables
+that are completely corrupt will cause unpredictable results. */
+
+/* Note on composite glyphs: Glyphs that have components that are themselves composites
+are not supported. IsDeepComposite can be used to test for this. False is returned from many
+of the methods in this cases. It is unclear how to build composite glyphs in some cases,
+so this code represents my best guess until test cases can be found. See notes on the high-
+level GlyfPoints method. */
+
+namespace TtfUtil
+{
+
+
+/*----------------------------------------------------------------------------------------------
+ Get offset and size of the offset table needed to find table directory
+ Return true if success, false otherwise
+ lSize excludes any table directory entries
+----------------------------------------------------------------------------------------------*/
+bool GetHeaderInfo(size_t & lOffset, size_t & lSize)
+{
+ lOffset = 0;
+ lSize = offsetof(Sfnt::OffsetSubTable, table_directory);
+ assert(sizeof(uint32) + 4*sizeof (uint16) == lSize);
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check the offset table for expected data
+ Return true if success, false otherwise
+----------------------------------------------------------------------------------------------*/
+bool CheckHeader(const void * pHdr)
+{
+ const Sfnt::OffsetSubTable * pOffsetTable
+ = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
+
+ return read(pOffsetTable->scaler_type) == Sfnt::OffsetSubTable::TrueTypeWin;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get offset and size of the table directory
+ Return true if successful, false otherwise
+----------------------------------------------------------------------------------------------*/
+bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize)
+{
+ const Sfnt::OffsetSubTable * pOffsetTable
+ = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
+
+ lOffset = offsetof(Sfnt::OffsetSubTable, table_directory);
+ lSize = read(pOffsetTable->num_tables)
+ * sizeof(Sfnt::OffsetSubTable::Entry);
+
+ return true;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Get offset and size of the specified table
+ Return true if successful, false otherwise. On false, offset and size will be 0
+----------------------------------------------------------------------------------------------*/
+bool GetTableInfo(TableId ktiTableId, const void * pHdr, const void * pTableDir,
+ size_t & lOffset, size_t & lSize)
+{
+ gr::fontTableId32 lTableTag = TableIdTag(ktiTableId);
+ if (!lTableTag)
+ {
+ lOffset = 0;
+ lSize = 0;
+ return false;
+ }
+
+ const Sfnt::OffsetSubTable * pOffsetTable
+ = reinterpret_cast<const Sfnt::OffsetSubTable *>(pHdr);
+ const Sfnt::OffsetSubTable::Entry
+ * entry_itr = reinterpret_cast<const Sfnt::OffsetSubTable::Entry *>(
+ pTableDir),
+ * const dir_end = entry_itr + read(pOffsetTable->num_tables);
+
+ assert(read(pOffsetTable->num_tables) < 40);
+ if (read(pOffsetTable->num_tables) > 40)
+ return false;
+
+ for (;entry_itr != dir_end; ++entry_itr) // 40 - safe guard
+ {
+ if (read(entry_itr->tag) == lTableTag)
+ {
+ lOffset = read(entry_itr->offset);
+ lSize = read(entry_itr->length);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check the specified table. Tests depend on the table type.
+ Return true if successful, false otherwise
+----------------------------------------------------------------------------------------------*/
+bool CheckTable(TableId ktiTableId, const void * pTable, size_t lTableSize)
+{
+ using namespace Sfnt;
+
+ switch(ktiTableId)
+ {
+ case ktiCmap: // cmap
+ {
+ const Sfnt::CharacterCodeMap * const pCmap
+ = reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable);
+ assert(read(pCmap->version) == 0);
+ return read(pCmap->version) == 0;
+ }
+
+ case ktiHead: // head
+ {
+ const Sfnt::FontHeader * const pHead
+ = reinterpret_cast<const Sfnt::FontHeader *>(pTable);
+ bool r = read(pHead->version) == OneFix
+ && read(pHead->magic_number) == FontHeader::MagicNumber
+ && read(pHead->glyph_data_format)
+ == FontHeader::GlypDataFormat
+ && (read(pHead->index_to_loc_format)
+ == FontHeader::ShortIndexLocFormat
+ || read(pHead->index_to_loc_format)
+ == FontHeader::LongIndexLocFormat)
+ && sizeof(FontHeader) <= lTableSize;
+ assert(r); return r;
+ }
+
+ case ktiPost: // post
+ {
+ const Sfnt::PostScriptGlyphName * const pPost
+ = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable);
+ const fixed format = read(pPost->format);
+ bool r = format == PostScriptGlyphName::Format1
+ || format == PostScriptGlyphName::Format2
+ || format == PostScriptGlyphName::Format3
+ || format == PostScriptGlyphName::Format25;
+ assert(r); return r;
+ }
+
+ case ktiHhea: // hhea
+ {
+ const Sfnt::HorizontalHeader * pHhea =
+ reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable);
+ bool r = read(pHhea->version) == OneFix
+ && read(pHhea->metric_data_format) == 0
+ && sizeof (Sfnt::HorizontalHeader) <= lTableSize;
+ assert(r); return r;
+ }
+
+ case ktiMaxp: // maxp
+ {
+ const Sfnt::MaximumProfile * pMaxp =
+ reinterpret_cast<const Sfnt::MaximumProfile *>(pTable);
+ bool r = read(pMaxp->version) == OneFix
+ && sizeof(Sfnt::MaximumProfile) <= lTableSize;
+ assert(r); return r;
+ }
+
+ case ktiOs2: // OS/2
+ {
+ const Sfnt::Compatibility * pOs2
+ = reinterpret_cast<const Sfnt::Compatibility *>(pTable);
+ if (read(pOs2->version) == 0)
+ { // OS/2 table version 1 size
+// if (sizeof(Sfnt::Compatibility)
+// - sizeof(uint32)*2 - sizeof(int16)*2
+// - sizeof(uint16)*3 <= lTableSize)
+ if (sizeof(Sfnt::Compatibility0) <= lTableSize)
+ return true;
+ }
+ else if (read(pOs2->version) == 1)
+ { // OS/2 table version 2 size
+// if (sizeof(Sfnt::Compatibility)
+// - sizeof(int16) *2
+// - sizeof(uint16)*3 <= lTableSize)
+ if (sizeof(Sfnt::Compatibility1) <= lTableSize)
+ return true;
+ }
+ else if (read(pOs2->version) == 2)
+ { // OS/2 table version 3 size
+ if (sizeof(Sfnt::Compatibility2) <= lTableSize)
+ return true;
+ }
+ else if (read(pOs2->version) == 3)
+ { // OS/2 table version 4 size - version 4 changed the meaning of some fields which we don't use
+ if (sizeof(Sfnt::Compatibility3) <= lTableSize)
+ return true;
+ }
+ else
+ return false;
+ }
+
+ case ktiName:
+ {
+ const Sfnt::FontNames * pName
+ = reinterpret_cast<const Sfnt::FontNames *>(pTable);
+ assert(read(pName->format) == 0);
+ return read(pName->format) == 0;
+ }
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of glyphs in the font. Should never be less than zero.
+----------------------------------------------------------------------------------------------*/
+size_t GlyphCount(const void * pMaxp)
+{
+ const Sfnt::MaximumProfile * pTable =
+ reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
+ return read(pTable->num_glyphs);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the maximum number of components for any composite glyph in the font
+----------------------------------------------------------------------------------------------*/
+size_t MaxCompositeComponentCount(const void * pMaxp)
+{
+ const Sfnt::MaximumProfile * pTable =
+ reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
+ return read(pTable->max_component_elements);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Composite glyphs can be composed of glyphs that are themselves composites.
+ This method returns the maximum number of levels like this for any glyph in the font.
+ A non-composite glyph has a level of 1
+----------------------------------------------------------------------------------------------*/
+size_t MaxCompositeLevelCount(const void * pMaxp)
+{
+ const Sfnt::MaximumProfile * pTable =
+ reinterpret_cast<const Sfnt::MaximumProfile *>(pMaxp);
+ return read(pTable->max_component_depth);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of glyphs in the font according to a differt source.
+ Should never be less than zero. Return -1 on failure.
+----------------------------------------------------------------------------------------------*/
+size_t LocaGlyphCount(size_t lLocaSize, const void * pHead) throw(std::domain_error)
+{
+
+ const Sfnt::FontHeader * pTable
+ = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ if (read(pTable->index_to_loc_format)
+ == Sfnt::FontHeader::ShortIndexLocFormat)
+ // loca entries are two bytes and have been divided by two
+ return (lLocaSize >> 1) - 1;
+
+ if (read(pTable->index_to_loc_format)
+ == Sfnt::FontHeader::LongIndexLocFormat)
+ // loca entries are four bytes
+ return (lLocaSize >> 2) - 1;
+
+ //return -1;
+ throw std::domain_error("head table in inconsistent state. The font may be corrupted");
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the design units the font is designed with
+----------------------------------------------------------------------------------------------*/
+int DesignUnits(const void * pHead)
+{
+ const Sfnt::FontHeader * pTable =
+ reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ return read(pTable->units_per_em);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the checksum from the head table, which serves as a unique identifer for the font.
+----------------------------------------------------------------------------------------------*/
+int HeadTableCheckSum(const void * pHead)
+{
+ const Sfnt::FontHeader * pTable =
+ reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ return read(pTable->check_sum_adjustment);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the create time from the head table. This consists of a 64-bit integer, which
+ we return here as two 32-bit integers.
+----------------------------------------------------------------------------------------------*/
+void HeadTableCreateTime(const void * pHead,
+ unsigned int * pnDateBC, unsigned int * pnDateAD)
+{
+ const Sfnt::FontHeader * pTable =
+ reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ *pnDateBC = read(pTable->created[0]);
+ *pnDateAD = read(pTable->created[1]);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the modify time from the head table.This consists of a 64-bit integer, which
+ we return here as two 32-bit integers.
+----------------------------------------------------------------------------------------------*/
+void HeadTableModifyTime(const void * pHead,
+ unsigned int * pnDateBC, unsigned int *pnDateAD)
+{
+ const Sfnt::FontHeader * pTable =
+ reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ *pnDateBC = read(pTable->modified[0]);
+ *pnDateAD = read(pTable->modified[1]);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the font is italic.
+----------------------------------------------------------------------------------------------*/
+bool IsItalic(const void * pHead)
+{
+ const Sfnt::FontHeader * pTable =
+ reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ return read(((pTable->mac_style) & 0x00000002) != 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the ascent for the font
+----------------------------------------------------------------------------------------------*/
+int FontAscent(const void * pOs2)
+{
+ const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
+
+ return read(pTable->win_ascent);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the descent for the font
+----------------------------------------------------------------------------------------------*/
+int FontDescent(const void * pOs2)
+{
+ const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
+
+ return read(pTable->win_descent);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the bold and italic style bits.
+ Return true if successful. false otherwise.
+ In addition to checking the OS/2 table, one could also check
+ the head table's macStyle field (overridden by the OS/2 table on Win)
+ the sub-family name in the name table (though this can contain oblique, dark, etc too)
+----------------------------------------------------------------------------------------------*/
+bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic)
+{
+ const Sfnt::Compatibility * pTable = reinterpret_cast<const Sfnt::Compatibility *>(pOs2);
+
+ fBold = (read(pTable->fs_selection) & Sfnt::Compatibility::Bold) != 0;
+ fItalic = (read(pTable->fs_selection) & Sfnt::Compatibility::Italic) != 0;
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Method for searching name table.
+----------------------------------------------------------------------------------------------*/
+bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
+ int nLangId, int nNameId, size_t & lOffset, size_t & lSize)
+{
+ lOffset = 0;
+ lSize = 0;
+
+ const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName);
+ uint16 cRecord = read(pTable->count);
+ uint16 nRecordOffset = read(pTable->string_offset);
+ const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1);
+
+ for (int i = 0; i < cRecord; ++i)
+ {
+ if (read(pRecord->platform_id) == nPlatformId &&
+ read(pRecord->platform_specific_id) == nEncodingId &&
+ read(pRecord->language_id) == nLangId &&
+ read(pRecord->name_id) == nNameId)
+ {
+ lOffset = read(pRecord->offset) + nRecordOffset;
+ lSize = read(pRecord->length);
+ return true;
+ }
+ pRecord++;
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return all the lang-IDs that have data for the given name-IDs. Assume that there is room
+ in the return array (langIdList) for 128 items. The purpose of this method is to return
+ a list of all possible lang-IDs.
+----------------------------------------------------------------------------------------------*/
+int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
+ int * nameIdList, int cNameIds, short * langIdList)
+{
+ const Sfnt::FontNames * pTable = reinterpret_cast<const Sfnt::FontNames *>(pName);
+ uint16 cRecord = read(pTable->count);
+ //uint16 nRecordOffset = swapw(pTable->stringOffset);
+ const Sfnt::NameRecord * pRecord = reinterpret_cast<const Sfnt::NameRecord *>(pTable + 1);
+
+ int cLangIds = 0;
+ for (int i = 0; i < cRecord; ++i)
+ {
+ if (read(pRecord->platform_id) == nPlatformId &&
+ read(pRecord->platform_specific_id) == nEncodingId)
+ {
+ bool fNameFound = false;
+ int nLangId = read(pRecord->language_id);
+ int nNameId = read(pRecord->name_id);
+ for (int j = 0; j < cNameIds; j++)
+ {
+ if (nNameId == nameIdList[j])
+ {
+ fNameFound = true;
+ break;
+ }
+ }
+ if (fNameFound)
+ {
+ // Add it if it's not there.
+ int ilang;
+ for (ilang = 0; ilang < cLangIds; ilang++)
+ if (langIdList[ilang] == nLangId)
+ break;
+ if (ilang >= cLangIds)
+ {
+ langIdList[cLangIds] = short(nLangId);
+ cLangIds++;
+ }
+ if (cLangIds == 128)
+ return cLangIds;
+ }
+ }
+ pRecord++;
+ }
+
+ return cLangIds;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the offset and size of the font family name in English for the MS Platform with Unicode
+ writing system. The offset is within the pName data. The string is double byte with MSB first.
+----------------------------------------------------------------------------------------------*/
+bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize)
+{
+ return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033,
+ Sfnt::NameRecord::Family, lOffset, lSize);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the offset and size of the full font name in English for the MS Platform with Unicode
+ writing system. The offset is within the pName data. The string is double byte with MSB first.
+----------------------------------------------------------------------------------------------*/
+bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize)
+{
+ return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 1, 1033,
+ Sfnt::NameRecord::Fullname, lOffset, lSize);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the offset and size of the font family name in English for the MS Platform with Symbol
+ writing system. The offset is within the pName data. The string is double byte with MSB first.
+----------------------------------------------------------------------------------------------*/
+bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize)
+{
+ return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033,
+ Sfnt::NameRecord::Family, lOffset, lSize);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the offset and size of the full font name in English for the MS Platform with Symbol
+ writing system. The offset is within the pName data. The string is double byte with MSB first.
+----------------------------------------------------------------------------------------------*/
+bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize)
+{
+ return GetNameInfo(pName, Sfnt::NameRecord::Microsoft, 0, 1033,
+ Sfnt::NameRecord::Fullname, lOffset, lSize);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the Glyph ID for a given Postscript name. This method finds the first glyph which
+ matches the requested Postscript name. Ideally every glyph should have a unique Postscript
+ name (except for special names such as .notdef), but this is not always true.
+ On failure return value less than zero.
+ -1 - table search failed
+ -2 - format 3 table (no Postscript glyph info)
+ -3 - other failures
+----------------------------------------------------------------------------------------------*/
+int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
+ const char * pPostName)
+{
+ using namespace Sfnt;
+
+ const Sfnt::PostScriptGlyphName * pTable
+ = reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pPost);
+ fixed format = read(pTable->format);
+
+ if (format == PostScriptGlyphName::Format3)
+ { // format 3 - no Postscript glyph info in font
+ return -2;
+ }
+
+ // search for given Postscript name among the standard names
+ int iPostName = -1; // index in standard names
+ for (int i = 0; i < kcPostNames; i++)
+ {
+ if (!strcmp(pPostName, rgPostName[i]))
+ {
+ iPostName = i;
+ break;
+ }
+ }
+
+ if (format == PostScriptGlyphName::Format1)
+ { // format 1 - use standard Postscript names
+ return iPostName;
+ }
+
+ if (format == PostScriptGlyphName::Format25)
+ {
+ if (iPostName == -1)
+ return -1;
+
+ const PostScriptGlyphName25 * pTable25
+ = static_cast<const PostScriptGlyphName25 *>(pTable);
+ int cnGlyphs = GlyphCount(pMaxp);
+ for (gr::gid16 nGlyphId = 0; nGlyphId < cnGlyphs && nGlyphId < kcPostNames;
+ nGlyphId++)
+ { // glyph_name_index25 contains bytes so no byte swapping needed
+ // search for first glyph id that uses the standard name
+ if (nGlyphId + pTable25->offset[nGlyphId] == iPostName)
+ return nGlyphId;
+ }
+ }
+
+ if (format == PostScriptGlyphName::Format2)
+ { // format 2
+ const PostScriptGlyphName2 * pTable2
+ = static_cast<const PostScriptGlyphName2 *>(pTable);
+
+ int cnGlyphs = read(pTable2->number_of_glyphs);
+
+ if (iPostName != -1)
+ { // did match a standard name, look for first glyph id mapped to that name
+ for (gr::gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
+ {
+ if (read(pTable2->glyph_name_index[nGlyphId]) == iPostName)
+ return nGlyphId;
+ }
+ return -1; // no glyph with this standard name
+ }
+
+ else
+ { // did not match a standard name, search font specific names
+ size_t nStrSizeGoal = strlen(pPostName);
+ const char * pFirstGlyphName = reinterpret_cast<const char *>(
+ &pTable2->glyph_name_index[0] + cnGlyphs);
+ const char * pGlyphName = pFirstGlyphName;
+ int iInNames = 0; // index in font specific names
+ bool fFound = false;
+ const char * const endOfTable
+ = reinterpret_cast<const char *>(pTable2) + lPostSize;
+ while (pGlyphName < endOfTable && !fFound)
+ { // search Pascal strings for first matching name
+ size_t nStringSize = size_t(*pGlyphName);
+ if (nStrSizeGoal != nStringSize ||
+ strncmp(pGlyphName + 1, pPostName, nStringSize))
+ { // did not match
+ ++iInNames;
+ pGlyphName += nStringSize + 1;
+ }
+ else
+ { // did match
+ fFound = true;
+ }
+ }
+ if (!fFound)
+ return -1; // no font specific name matches request
+
+ iInNames += kcPostNames;
+ for (gr::gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
+ { // search for first glyph id that maps to the found string index
+ if (read(pTable2->glyph_name_index[nGlyphId]) == iInNames)
+ return nGlyphId;
+ }
+ return -1; // no glyph mapped to this index (very strange)
+ }
+ }
+
+ return -3;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert a Unicode character string from big endian (MSB first, Motorola) format to little
+ endian (LSB first, Intel) format.
+ nSize is the number of Unicode characters in the string. It should not include any
+ terminating null. If nSize is 0, it is assumed the string is null terminated. nSize
+ defaults to 0.
+ Return true if successful, false otherwise.
+----------------------------------------------------------------------------------------------*/
+void SwapWString(void * pWStr, size_t nSize /* = 0 */) throw (std::invalid_argument)
+{
+ if (pWStr == 0)
+ throw std::invalid_argument("null pointer given");
+
+ uint16 * pStr = reinterpret_cast<uint16 *>(pWStr);
+ uint16 * const pStrEnd = pStr + (nSize == 0 ? gr::utf16len(pStr) : nSize);
+
+ std::transform(pStr, pStrEnd, pStr, read<uint16>);
+
+// for (int i = 0; i < nSize; i++)
+// { // swap the wide characters in the string
+// pStr[i] = gr::utf16(read(uint16(pStr[i])));
+// }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the left-side bearing and and advance width based on the given tables and Glyph ID
+ Return true if successful, false otherwise. On false, one or both value could be INT_MIN
+----------------------------------------------------------------------------------------------*/
+bool HorMetrics(gr::gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void * pHhea,
+ int & nLsb, unsigned int & nAdvWid)
+{
+ const Sfnt::HorizontalMetric * phmtx =
+ reinterpret_cast<const Sfnt::HorizontalMetric *>(pHmtx);
+
+ const Sfnt::HorizontalHeader * phhea =
+ reinterpret_cast<const Sfnt::HorizontalHeader *>(pHhea);
+
+ size_t cLongHorMetrics = read(phhea->num_long_hor_metrics);
+ if (nGlyphId < cLongHorMetrics)
+ { // glyph id is acceptable
+ nAdvWid = read(phmtx[nGlyphId].advance_width);
+ nLsb = read(phmtx[nGlyphId].left_side_bearing);
+ }
+ else
+ {
+ nAdvWid = read(phmtx[cLongHorMetrics - 1].advance_width);
+
+ // guard against bad glyph id
+ size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics +
+ sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes
+ if (lLsbOffset + 1 >= lHmtxSize) // + 1 because entries are two bytes wide
+ {
+ nLsb = 0;
+ return false;
+ }
+ const int16 * pLsb = reinterpret_cast<const int16 *>(phmtx) +
+ lLsbOffset / sizeof(int16);
+ nLsb = read(*pLsb);
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pointer to the requested cmap subtable. By default find the Microsoft Unicode
+ subtable. Pass nEncoding as -1 to find first table that matches only nPlatformId.
+ Return NULL if the subtable cannot be found.
+----------------------------------------------------------------------------------------------*/
+void * FindCmapSubtable(const void * pCmap,
+ int nPlatformId, /* =3 */
+ int nEncodingId) /* = 1 */
+{
+ const Sfnt::CharacterCodeMap * pTable =
+ reinterpret_cast<const Sfnt::CharacterCodeMap *>(pCmap);
+
+ uint16 csuPlatforms = read(pTable->num_subtables);
+ for (int i = 0; i < csuPlatforms; i++)
+ {
+ if (read(pTable->encoding[i].platform_id) == nPlatformId &&
+ (nEncodingId == -1 || read(pTable->encoding[i].platform_specific_id) == nEncodingId))
+ {
+ const void * pRtn = reinterpret_cast<const uint8 *>(pCmap) +
+ read(pTable->encoding[i].offset);
+ return const_cast<void *>(pRtn);
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check the Microsoft Unicode subtable for expected values
+----------------------------------------------------------------------------------------------*/
+bool CheckCmap31Subtable(const void * pCmap31)
+{
+ const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmap31);
+ // Bob H says ome freeware TT fonts have version 1 (eg, CALIGULA.TTF)
+ // so don't check subtable version. 21 Mar 2002 spec changes version to language.
+
+ return read(pTable->format) == 4;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the Glyph ID for the given Unicode ID in the Microsoft Unicode subtable.
+ (Actually this code only depends on subtable being format 4.)
+ Return 0 if the Unicode ID is not in the subtable.
+----------------------------------------------------------------------------------------------*/
+gr::gid16 Cmap31Lookup(const void * pCmap31, int nUnicodeId)
+{
+ const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmap31);
+
+ uint16 nSeg = read(pTable->seg_count_x2) >> 1;
+
+ uint16 n;
+ const uint16 * pLeft, * pMid;
+ uint16 cMid, chStart, chEnd;
+
+ // Binary search of the endCode[] array
+ pLeft = &(pTable->end_code[0]);
+ n = nSeg;
+ while (n > 0)
+ {
+ cMid = n >> 1; // Pick an element in the middle
+ pMid = pLeft + cMid;
+ chEnd = read(*pMid);
+ if (nUnicodeId <= chEnd)
+ {
+ if (cMid == 0 || nUnicodeId > read(pMid[-1]))
+ break; // Must be this seg or none!
+ n = cMid; // Continue on left side, omitting mid point
+ }
+ else
+ {
+ pLeft = pMid + 1; // Continue on right side, omitting mid point
+ n -= (cMid + 1);
+ }
+ }
+
+ if (!n)
+ return 0;
+
+ // Ok, we're down to one segment and pMid points to the endCode element
+ // Either this is it or none is.
+
+ chStart = read(*(pMid += nSeg + 1));
+ if (chEnd >= nUnicodeId && nUnicodeId >= chStart)
+ {
+ // Found correct segment. Find Glyph Id
+ int16 idDelta = read(*(pMid += nSeg));
+ uint16 idRangeOffset = read(*(pMid += nSeg));
+
+ if (idRangeOffset == 0)
+ return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16
+
+ // Look up value in glyphIdArray
+ gr::gid16 nGlyphId = read(*(pMid + (nUnicodeId - chStart) + (idRangeOffset >> 1)));
+ // If this value is 0, return 0. Else add the idDelta
+ return nGlyphId ? nGlyphId + idDelta : 0;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the next Unicode value in the cmap. Pass 0 to obtain the first item.
+ Returns 0xFFFF as the last item.
+ pRangeKey is an optional key that is used to optimize the search; its value is the range
+ in which the character is found.
+----------------------------------------------------------------------------------------------*/
+unsigned int Cmap31NextCodepoint(const void *pCmap31, unsigned int nUnicodeId, int * pRangeKey)
+{
+ const Sfnt::CmapSubTableFormat4 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmap31);
+
+ uint16 nRange = read(pTable->seg_count_x2) >> 1;
+
+ uint32 nUnicodePrev = (uint32)nUnicodeId;
+
+ const uint16 * pStartCode = &(pTable->end_code[0])
+ + nRange // length of end code array
+ + 1; // reserved word
+
+ if (nUnicodePrev == 0)
+ {
+ // return the first codepoint.
+ if (pRangeKey)
+ *pRangeKey = 0;
+ return read(pStartCode[0]);
+ }
+ else if (nUnicodePrev >= 0xFFFF)
+ {
+ if (pRangeKey)
+ *pRangeKey = nRange - 1;
+ return 0xFFFF;
+ }
+
+ int iRange = (pRangeKey) ? *pRangeKey : 0;
+ // Just in case we have a bad key:
+ while (iRange > 0 && read(pStartCode[iRange]) > nUnicodePrev)
+ iRange--;
+ while (read(pTable->end_code[iRange]) < nUnicodePrev)
+ iRange++;
+
+ // Now iRange is the range containing nUnicodePrev.
+ unsigned int nStartCode = read(pStartCode[iRange]);
+ unsigned int nEndCode = read(pTable->end_code[iRange]);
+
+ if (nStartCode > nUnicodePrev)
+ // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
+ // answer this time around.
+ nUnicodePrev = nStartCode - 1;
+
+ if (nEndCode > nUnicodePrev)
+ {
+ // Next is in the same range; it is the next successive codepoint.
+ if (pRangeKey)
+ *pRangeKey = iRange;
+ return nUnicodePrev + 1;
+ }
+
+ // Otherwise the next codepoint is the first one in the next range.
+ // There is guaranteed to be a next range because there must be one that
+ // ends with 0xFFFF.
+ if (pRangeKey)
+ *pRangeKey = iRange + 1;
+ return read(pStartCode[iRange + 1]);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check the Microsoft UCS-4 subtable for expected values
+----------------------------------------------------------------------------------------------*/
+bool CheckCmap310Subtable(const void *pCmap310)
+{
+ const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmap310);
+ return read(pTable->format) == 12;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the Glyph ID for the given Unicode ID in the Microsoft UCS-4 subtable.
+ (Actually this code only depends on subtable being format 12.)
+ Return 0 if the Unicode ID is not in the subtable.
+----------------------------------------------------------------------------------------------*/
+gr::gid16 Cmap310Lookup(const void * pCmap310, unsigned int uUnicodeId)
+{
+ const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310);
+
+ //uint32 uLength = read(pTable->length); //could use to test for premature end of table
+ uint32 ucGroups = read(pTable->num_groups);
+
+ for (unsigned int i = 0; i < ucGroups; i++)
+ {
+ uint32 uStartCode = read(pTable->group[i].start_char_code);
+ uint32 uEndCode = read(pTable->group[i].end_char_code);
+ if (uUnicodeId >= uStartCode && uUnicodeId <= uEndCode)
+ {
+ uint32 uDiff = uUnicodeId - uStartCode;
+ uint32 uStartGid = read(pTable->group[i].start_glyph_id);
+ return static_cast<gr::gid16>(uStartGid + uDiff);
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the next Unicode value in the cmap. Pass 0 to obtain the first item.
+ Returns 0x10FFFF as the last item.
+ pRangeKey is an optional key that is used to optimize the search; its value is the range
+ in which the character is found.
+----------------------------------------------------------------------------------------------*/
+unsigned int Cmap310NextCodepoint(const void *pCmap310, unsigned int nUnicodeId, int * pRangeKey)
+{
+ const Sfnt::CmapSubTableFormat12 * pTable = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmap310);
+
+ int nRange = read(pTable->num_groups);
+
+ uint32 nUnicodePrev = (uint32)nUnicodeId;
+
+ if (nUnicodePrev == 0)
+ {
+ // return the first codepoint.
+ if (pRangeKey)
+ *pRangeKey = 0;
+ return read(pTable->group[0].start_char_code);
+ }
+ else if (nUnicodePrev >= 0x10FFFF)
+ {
+ if (pRangeKey)
+ *pRangeKey = nRange;
+ return 0x10FFFF;
+ }
+
+ int iRange = (pRangeKey) ? *pRangeKey : 0;
+ // Just in case we have a bad key:
+ while (iRange > 0 && read(pTable->group[iRange].start_char_code) > nUnicodePrev)
+ iRange--;
+ while (read(pTable->group[iRange].end_char_code) < nUnicodePrev)
+ iRange++;
+
+ // Now iRange is the range containing nUnicodePrev.
+
+ unsigned int nStartCode = read(pTable->group[iRange].start_char_code);
+ unsigned int nEndCode = read(pTable->group[iRange].end_char_code);
+
+ if (nStartCode > nUnicodePrev)
+ // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
+ // answer this time around.
+ nUnicodePrev = nStartCode - 1;
+
+ if (nEndCode > nUnicodePrev)
+ {
+ // Next is in the same range; it is the next successive codepoint.
+ if (pRangeKey)
+ *pRangeKey = iRange;
+ return nUnicodePrev + 1;
+ }
+
+ // Otherwise the next codepoint is the first one in the next range, or 10FFFF if we're done.
+ if (pRangeKey)
+ *pRangeKey = iRange + 1;
+ return (iRange + 1 >= nRange) ? 0x10FFFF : read(pTable->group[iRange + 1].start_char_code);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the offset stored in the loca table for the given Glyph ID.
+ (This offset is into the glyf table.)
+ Return -1 if the lookup failed.
+ Technically this method should return an unsigned long but it is unlikely the offset will
+ exceed 2^31.
+----------------------------------------------------------------------------------------------*/
+size_t LocaLookup(gr::gid16 nGlyphId,
+ const void * pLoca, size_t lLocaSize,
+ const void * pHead) throw (std::out_of_range)
+{
+ const Sfnt::FontHeader * pTable = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ // CheckTable verifies the index_to_loc_format is valid
+ if (read(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
+ { // loca entries are two bytes and have been divided by two
+ if (nGlyphId <= (lLocaSize >> 1) - 1) // allow sentinel value to be accessed
+ {
+ const uint16 * pTable = reinterpret_cast<const uint16 *>(pLoca);
+ return (read(pTable[nGlyphId]) << 1);
+ }
+ }
+
+ if (read(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
+ { // loca entries are four bytes
+ if (nGlyphId <= (lLocaSize >> 2) - 1)
+ {
+ const uint32 * pTable = reinterpret_cast<const uint32 *>(pLoca);
+ return read(pTable[nGlyphId]);
+ }
+ }
+
+ // only get here if glyph id was bad
+ //return -1;
+ throw std::out_of_range("glyph id out of range for font");
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pointer into the glyf table based on the given offset (from LocaLookup).
+ Return NULL on error.
+----------------------------------------------------------------------------------------------*/
+void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset)
+{
+ const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
+ return const_cast<uint8 *>(pByte + nGlyfOffset);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the bounding box coordinates for a simple glyf entry (non-composite)
+ Return true if successful, false otherwise
+----------------------------------------------------------------------------------------------*/
+bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
+ int & xMax, int & yMax)
+{
+ const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf);
+
+ xMin = read(pGlyph->x_min);
+ yMin = read(pGlyph->y_min);
+ xMax = read(pGlyph->x_max);
+ yMax = read(pGlyph->y_max);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of contours for a simple glyf entry (non-composite)
+ Returning -1 means this is a composite glyph
+----------------------------------------------------------------------------------------------*/
+int GlyfContourCount(const void * pSimpleGlyf)
+{
+ const Sfnt::Glyph * pGlyph = reinterpret_cast<const Sfnt::Glyph *>(pSimpleGlyf);
+ return read(pGlyph->number_of_contours); // -1 means composite glyph
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the point numbers for the end points of the glyph contours for a simple
+ glyf entry (non-composite).
+ cnPointsTotal - count of contours from GlyfContourCount(); (same as number of end points)
+ prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers
+ cnPoints - count of points placed in above range
+ Return true if successful, false otherwise.
+ False could indicate a multi-level composite glyphs.
+----------------------------------------------------------------------------------------------*/
+bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
+ int cnPointsTotal, int & cnPoints)
+{
+ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
+
+ int cContours = read(pGlyph->number_of_contours);
+ if (cContours < 0)
+ return false; // this method isn't supposed handle composite glyphs
+
+ for (int i = 0; i < cContours && i < cnPointsTotal; i++)
+ {
+ prgnContourEndPoint[i] = read(pGlyph->end_pts_of_contours[i]);
+ }
+
+ cnPoints = cContours;
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the points for a simple glyf entry (non-composite)
+ cnPointsTotal - count of points from largest end point obtained from GlyfContourEndPoints
+ prgnX & prgnY - should point to buffers large enough to hold cnPointsTotal integers
+ The ranges are parallel so that coordinates for point(n) are found at offset n in both
+ ranges. This is raw point data with relative coordinates.
+ prgbFlag - should point to a buffer a large enough to hold cnPointsTotal bytes
+ This range is parallel to the prgnX & prgnY
+ cnPoints - count of points placed in above ranges
+ Return true if successful, false otherwise.
+ False could indicate a composite glyph
+ TODO: implement
+----------------------------------------------------------------------------------------------*/
+bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
+ char * prgbFlag, int cnPointsTotal, int & cnPoints)
+{
+ using namespace Sfnt;
+
+ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
+ int cContours = read(pGlyph->number_of_contours);
+ // return false for composite glyph
+ if (cContours <= 0)
+ return false;
+ int cPts = read(pGlyph->end_pts_of_contours[cContours - 1]) + 1;
+ if (cPts > cnPointsTotal)
+ return false;
+
+ // skip over bounding box data & point to byte count of instructions (hints)
+ const uint8 * pbGlyph = reinterpret_cast<const uint8 *>
+ (&pGlyph->end_pts_of_contours[cContours]);
+
+ // skip over hints & point to first flag
+ int cbHints = read(*(const uint16 *)pbGlyph);
+ pbGlyph += sizeof(uint16);
+ pbGlyph += cbHints;
+
+ // load flags & point to first x coordinate
+ int iFlag = 0;
+ while (iFlag < cPts)
+ {
+ if (!(*pbGlyph & SimpleGlyph::Repeat))
+ { // flag isn't repeated
+ prgbFlag[iFlag] = (char)*pbGlyph;
+ pbGlyph++;
+ iFlag++;
+ }
+ else
+ { // flag is repeated; count specified by next byte
+ char chFlag = (char)*pbGlyph;
+ pbGlyph++;
+ int cFlags = (int)*pbGlyph;
+ pbGlyph++;
+ prgbFlag[iFlag] = chFlag;
+ iFlag++;
+ for (int i = 0; i < cFlags; i++)
+ {
+ prgbFlag[iFlag + i] = chFlag;
+ }
+ iFlag += cFlags;
+ }
+ }
+ if (iFlag != cPts)
+ return false;
+
+ // load x coordinates
+ iFlag = 0;
+ while (iFlag < cPts)
+ {
+ if (prgbFlag[iFlag] & SimpleGlyph::XShort)
+ {
+ prgnX[iFlag] = *pbGlyph;
+ if (!(prgbFlag[iFlag] & SimpleGlyph::XIsPos))
+ {
+ prgnX[iFlag] = -prgnX[iFlag];
+ }
+ pbGlyph++;
+ }
+ else
+ {
+ if (prgbFlag[iFlag] & SimpleGlyph::XIsSame)
+ {
+ prgnX[iFlag] = 0;
+ // do NOT increment pbGlyph
+ }
+ else
+ {
+ prgnX[iFlag] = read(*(const int16 *)pbGlyph);
+ pbGlyph += sizeof(int16);
+ }
+ }
+ iFlag++;
+ }
+
+ // load y coordinates
+ iFlag = 0;
+ while (iFlag < cPts)
+ {
+ if (prgbFlag[iFlag] & SimpleGlyph::YShort)
+ {
+ prgnY[iFlag] = *pbGlyph;
+ if (!(prgbFlag[iFlag] & SimpleGlyph::YIsPos))
+ {
+ prgnY[iFlag] = -prgnY[iFlag];
+ }
+ pbGlyph++;
+ }
+ else
+ {
+ if (prgbFlag[iFlag] & SimpleGlyph::YIsSame)
+ {
+ prgnY[iFlag] = 0;
+ // do NOT increment pbGlyph
+ }
+ else
+ {
+ prgnY[iFlag] = read(*(const int16 *)pbGlyph);
+ pbGlyph += sizeof(int16);
+ }
+ }
+ iFlag++;
+ }
+
+ cnPoints = cPts;
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill prgnCompId with the component Glyph IDs from pSimpleGlyf.
+ Client must allocate space before calling.
+ pSimpleGlyf - assumed to point to a composite glyph
+ cCompIdTotal - the number of elements in prgnCompId
+ cCompId - the total number of Glyph IDs stored in prgnCompId
+ Return true if successful, false otherwise
+ False could indicate a non-composite glyph or the input array was not big enough
+----------------------------------------------------------------------------------------------*/
+bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
+ size_t cnCompIdTotal, size_t & cnCompId)
+{
+ using namespace Sfnt;
+
+ if (GlyfContourCount(pSimpleGlyf) >= 0)
+ return false;
+
+ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
+ // for a composite glyph, the special data begins here
+ const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
+
+ uint16 GlyphFlags;
+ size_t iCurrentComp = 0;
+ do
+ {
+ GlyphFlags = read(*((const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ prgnCompId[iCurrentComp++] = read(*((const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ if (iCurrentComp >= cnCompIdTotal)
+ return false;
+ int nOffset = 0;
+ nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2;
+ nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0;
+ pbGlyph += nOffset;
+ } while (GlyphFlags & CompoundGlyph::MoreComponents);
+
+ cnCompId = iCurrentComp;
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return info on how a component glyph is to be placed
+ pSimpleGlyph - assumed to point to a composite glyph
+ nCompId - glyph id for component of interest
+ bOffset - if true, a & b are the x & y offsets for this component
+ if false, b is the point on this component that is attaching to point a on the
+ preceding glyph
+ Return true if successful, false otherwise
+ False could indicate a non-composite glyph or that component wasn't found
+----------------------------------------------------------------------------------------------*/
+bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
+ bool fOffset, int & a, int & b)
+{
+ using namespace Sfnt;
+
+ if (GlyfContourCount(pSimpleGlyf) >= 0)
+ return false;
+
+ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
+ // for a composite glyph, the special data begins here
+ const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
+
+ uint16 GlyphFlags;
+ do
+ {
+ GlyphFlags = read(*((const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ if (read(*((const uint16 *)pbGlyph)) == nCompId)
+ {
+ pbGlyph += sizeof(uint16); // skip over glyph id of component
+ fOffset = (GlyphFlags & CompoundGlyph::ArgsAreXYValues) == CompoundGlyph::ArgsAreXYValues;
+
+ if (GlyphFlags & CompoundGlyph::Arg1Arg2Words )
+ {
+ a = read(*(const int16 *)pbGlyph);
+ pbGlyph += sizeof(int16);
+ b = read(*(const int16 *)pbGlyph);
+ pbGlyph += sizeof(int16);
+ }
+ else
+ { // args are signed bytes
+ a = *pbGlyph++;
+ b = *pbGlyph++;
+ }
+ return true;
+ }
+ pbGlyph += sizeof(uint16); // skip over glyph id of component
+ int nOffset = 0;
+ nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2;
+ nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0;
+ pbGlyph += nOffset;
+ } while (GlyphFlags & CompoundGlyph::MoreComponents);
+
+ // didn't find requested component
+ fOffset = true;
+ a = 0;
+ b = 0;
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return info on how a component glyph is to be transformed
+ pSimpleGlyph - assumed to point to a composite glyph
+ nCompId - glyph id for component of interest
+ flt11, flt11, flt11, flt11 - a 2x2 matrix giving the transform
+ bTransOffset - whether to transform the offset from above method
+ The spec is unclear about the meaning of this flag
+ Currently - initialize to true for MS rasterizer and false for Mac rasterizer, then
+ on return it will indicate whether transform should apply to offset (MSDN CD 10/99)
+ Return true if successful, false otherwise
+ False could indicate a non-composite glyph or that component wasn't found
+----------------------------------------------------------------------------------------------*/
+bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
+ float & flt11, float & flt12, float & flt21, float & flt22,
+ bool & fTransOffset)
+{
+ using namespace Sfnt;
+
+ if (GlyfContourCount(pSimpleGlyf) >= 0)
+ return false;
+
+ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
+ // for a composite glyph, the special data begins here
+ const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
+
+ uint16 GlyphFlags;
+ do
+ {
+ GlyphFlags = read(*((const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ if (read(*((const uint16 *)pbGlyph)) == nCompId)
+ {
+ pbGlyph += sizeof(uint16); // skip over glyph id of component
+ pbGlyph += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; // skip over placement data
+
+ if (fTransOffset) // MS rasterizer
+ fTransOffset = !(GlyphFlags & CompoundGlyph::UnscaledOffset);
+ else // Apple rasterizer
+ fTransOffset = (GlyphFlags & CompoundGlyph::ScaledOffset) != 0;
+
+ if (GlyphFlags & CompoundGlyph::HaveScale)
+ {
+ flt11 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ flt12 = 0;
+ flt21 = 0;
+ flt22 = flt11;
+ }
+ else if (GlyphFlags & CompoundGlyph::HaveXAndYScale)
+ {
+ flt11 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ flt12 = 0;
+ flt21 = 0;
+ flt22 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ }
+ else if (GlyphFlags & CompoundGlyph::HaveTwoByTwo)
+ {
+ flt11 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ flt12 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ flt21 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ flt22 = fixed_to_float<14>(read(*(const uint16 *)pbGlyph));
+ pbGlyph += sizeof(uint16);
+ }
+ else
+ { // identity transform
+ flt11 = 1.0;
+ flt12 = 0.0;
+ flt21 = 0.0;
+ flt22 = 1.0;
+ }
+ return true;
+ }
+ pbGlyph += sizeof(uint16); // skip over glyph id of component
+ int nOffset = 0;
+ nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2;
+ nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0;
+ nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0;
+ pbGlyph += nOffset;
+ } while (GlyphFlags & CompoundGlyph::MoreComponents);
+
+ // didn't find requested component
+ fTransOffset = false;
+ flt11 = 1;
+ flt12 = 0;
+ flt21 = 0;
+ flt22 = 1;
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pointer into the glyf table based on the given tables and Glyph ID
+ Since this method doesn't check for spaces, it is good to call IsSpace before using it.
+ Return NULL on error
+----------------------------------------------------------------------------------------------*/
+void * GlyfLookup(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead)
+{
+ // test for valid glyph id
+ // CheckTable verifies the index_to_loc_format is valid
+
+ const Sfnt::FontHeader * pTable
+ = reinterpret_cast<const Sfnt::FontHeader *>(pHead);
+
+ if (read(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
+ { // loca entries are two bytes (and have been divided by two)
+ if (nGlyphId >= (lLocaSize >> 1) - 1) // don't allow nGlyphId to access sentinel
+ throw std::out_of_range("glyph id out of range for font");
+ }
+ if (read(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
+ { // loca entries are four bytes
+ if (nGlyphId >= (lLocaSize >> 2) - 1)
+ throw std::out_of_range("glyph id out of range for font");
+ }
+
+ long lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead);
+ void * pSimpleGlyf = GlyfLookup(pGlyf, lGlyfOffset); // invalid loca offset returns null
+ return pSimpleGlyf;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Determine if a particular Glyph ID has any data in the glyf table. If it is white space,
+ there will be no glyf data, though there will be metric data in hmtx, etc.
+----------------------------------------------------------------------------------------------*/
+bool IsSpace(gr::gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead)
+{
+ size_t lGlyfOffset = LocaLookup(nGlyphId, pLoca, lLocaSize, pHead);
+
+ // the +1 should always work because there is a sentinel value at the end of the loca table
+ size_t lNextGlyfOffset = LocaLookup(nGlyphId + 1, pLoca, lLocaSize, pHead);
+
+ return (lNextGlyfOffset - lGlyfOffset) == 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Determine if a particular Glyph ID is a multi-level composite.
+----------------------------------------------------------------------------------------------*/
+bool IsDeepComposite(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ long lLocaSize, const void * pHead)
+{
+ if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
+
+ void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL)
+ return false; // no way to really indicate an error occured here
+
+ if (GlyfContourCount(pSimpleGlyf) >= 0)
+ return false;
+
+ int rgnCompId[kMaxGlyphComponents]; // assumes only a limited number of glyph components
+ size_t cCompIdTotal = kMaxGlyphComponents;
+ size_t cCompId = 0;
+
+ if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
+ return false;
+
+ for (size_t i = 0; i < cCompId; i++)
+ {
+ void * pSimpleGlyf = GlyfLookup(static_cast<gr::gid16>(rgnCompId[i]),
+ pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL) {return false;}
+
+ if (GlyfContourCount(pSimpleGlyf) < 0)
+ return true;
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the bounding box coordinates based on the given tables and Glyph ID
+ Handles both simple and composite glyphs.
+ Return true if successful, false otherwise. On false, all point values will be INT_MIN
+ False may indicate a white space glyph
+----------------------------------------------------------------------------------------------*/
+bool GlyfBox(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax)
+{
+ xMin = yMin = xMax = yMax = INT_MIN;
+
+ if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
+
+ void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL) {return false;}
+
+ return GlyfBox(pSimpleGlyf, xMin, yMin, xMax, yMax);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the number of contours based on the given tables and Glyph ID
+ Handles both simple and composite glyphs.
+ Return true if successful, false otherwise. On false, cnContours will be INT_MIN
+ False may indicate a white space glyph or a multi-level composite glyph.
+----------------------------------------------------------------------------------------------*/
+bool GlyfContourCount(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead, size_t & cnContours)
+{
+ cnContours = static_cast<size_t>(INT_MIN);
+
+ if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
+
+ void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL) {return false;}
+
+ int cRtnContours = GlyfContourCount(pSimpleGlyf);
+ if (cRtnContours >= 0)
+ {
+ cnContours = size_t(cRtnContours);
+ return true;
+ }
+
+ //handle composite glyphs
+
+ int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
+ size_t cCompIdTotal = kMaxGlyphComponents;
+ size_t cCompId = 0;
+
+ if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
+ return false;
+
+ cRtnContours = 0;
+ int cTmp = 0;
+ for (size_t i = 0; i < cCompId; i++)
+ {
+ if (IsSpace(static_cast<gr::gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
+ pSimpleGlyf = GlyfLookup(static_cast<gr::gid16>(rgnCompId[i]),
+ pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == 0) {return false;}
+ // return false on multi-level composite
+ if ((cTmp = GlyfContourCount(pSimpleGlyf)) < 0)
+ return false;
+ cRtnContours += cTmp;
+ }
+
+ cnContours = size_t(cRtnContours);
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the point numbers for the end points of the glyph contours based on the given tables
+ and Glyph ID
+ Handles both simple and composite glyphs.
+ cnPoints - count of contours from GlyfContourCount (same as number of end points)
+ prgnContourEndPoints - should point to a buffer large enough to hold cnPoints integers
+ Return true if successful, false otherwise. On false, all end points are INT_MIN
+ False may indicate a white space glyph or a multi-level composite glyph.
+----------------------------------------------------------------------------------------------*/
+bool GlyfContourEndPoints(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead,
+ int * prgnContourEndPoint, size_t cnPoints)
+{
+ std::fill_n(prgnContourEndPoint, cnPoints, INT_MIN);
+
+ if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead)) {return false;}
+
+ void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL) {return false;}
+
+ int cContours = GlyfContourCount(pSimpleGlyf);
+ int cActualPts = 0;
+ if (cContours > 0)
+ return GlyfContourEndPoints(pSimpleGlyf, prgnContourEndPoint, cnPoints, cActualPts);
+
+ // handle composite glyphs
+
+ int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
+ size_t cCompIdTotal = kMaxGlyphComponents;
+ size_t cCompId = 0;
+
+ if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
+ return false;
+
+ int * prgnCurrentEndPoint = prgnContourEndPoint;
+ int cCurrentPoints = cnPoints;
+ int nPrevPt = 0;
+ for (size_t i = 0; i < cCompId; i++)
+ {
+ if (IsSpace(static_cast<gr::gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
+ pSimpleGlyf = GlyfLookup(static_cast<gr::gid16>(rgnCompId[i]), pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL) {return false;}
+ // returns false on multi-level composite
+ if (!GlyfContourEndPoints(pSimpleGlyf, prgnCurrentEndPoint, cCurrentPoints, cActualPts))
+ return false;
+ // points in composite are numbered sequentially as components are added
+ // must adjust end point numbers for new point numbers
+ for (int j = 0; j < cActualPts; j++)
+ prgnCurrentEndPoint[j] += nPrevPt;
+ nPrevPt = prgnCurrentEndPoint[cActualPts - 1] + 1;
+
+ prgnCurrentEndPoint += cActualPts;
+ cCurrentPoints -= cActualPts;
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the points for a glyph based on the given tables and Glyph ID
+ Handles both simple and composite glyphs.
+ cnPoints - count of points from largest end point obtained from GlyfContourEndPoints
+ prgnX & prgnY - should point to buffers large enough to hold cnPoints integers
+ The ranges are parallel so that coordinates for point(n) are found at offset n in
+ both ranges. These points are in absolute coordinates.
+ prgfOnCurve - should point to a buffer a large enough to hold cnPoints bytes (bool)
+ This range is parallel to the prgnX & prgnY
+ Return true if successful, false otherwise. On false, all points may be INT_MIN
+ False may indicate a white space glyph, a multi-level composite, or a corrupt font
+ // TODO: doesn't support composite glyphs whose components are themselves components
+ It's not clear from the TTF spec when the transforms should be applied. Should the
+ transform be done before or after attachment point calcs? (current code - before)
+ Should the transform be applied to other offsets? (currently - no; however commented
+ out code is in place so that if CompoundGlyph::UnscaledOffset on the MS rasterizer is
+ clear (typical) then yes, and if CompoundGlyph::ScaledOffset on the Apple rasterizer is
+ clear (typical?) then no). See GetComponentTransform.
+ It's also unclear where point numbering with attachment poinst starts
+ (currently - first point number is relative to whole glyph, second point number is
+ relative to current glyph).
+----------------------------------------------------------------------------------------------*/
+bool GlyfPoints(gr::gid16 nGlyphId, const void * pGlyf,
+ const void * pLoca, size_t lLocaSize, const void * pHead,
+ const int * prgnContourEndPoint, size_t cnEndPoints,
+ int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints)
+{
+ std::fill_n(prgnX, cnPoints, INT_MAX);
+ std::fill_n(prgnY, cnPoints, INT_MAX);
+
+ if (IsSpace(nGlyphId, pLoca, lLocaSize, pHead))
+ return false;
+
+ void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lLocaSize, pHead);
+ if (pSimpleGlyf == NULL)
+ return false;
+
+ int cContours = GlyfContourCount(pSimpleGlyf);
+ int cActualPts;
+ if (cContours > 0)
+ {
+ if (!GlyfPoints(pSimpleGlyf, prgnX, prgnY, (char *)prgfOnCurve, cnPoints, cActualPts))
+ return false;
+ CalcAbsolutePoints(prgnX, prgnY, cnPoints);
+ SimplifyFlags((char *)prgfOnCurve, cnPoints);
+ return true;
+ }
+
+ // handle composite glyphs
+ int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
+ size_t cCompIdTotal = kMaxGlyphComponents;
+ size_t cCompId = 0;
+
+ // this will fail if there are more components than there is room for
+ if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId))
+ return false;
+
+ int * prgnCurrentX = prgnX;
+ int * prgnCurrentY = prgnY;
+ char * prgbCurrentFlag = (char *)prgfOnCurve; // converting bool to char should be safe
+ int cCurrentPoints = cnPoints;
+ bool fOffset = true, fTransOff = true;
+ int a, b;
+ float flt11, flt12, flt21, flt22;
+ // int * prgnPrevX = prgnX; // in case first att pt number relative to preceding glyph
+ // int * prgnPrevY = prgnY;
+ for (size_t i = 0; i < cCompId; i++)
+ {
+ if (IsSpace(static_cast<gr::gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {return false;}
+ void * pCompGlyf = GlyfLookup(static_cast<gr::gid16>(rgnCompId[i]), pGlyf, pLoca, lLocaSize, pHead);
+ if (pCompGlyf == NULL) {return false;}
+ // returns false on multi-level composite
+ if (!GlyfPoints(pCompGlyf, prgnCurrentX, prgnCurrentY, prgbCurrentFlag,
+ cCurrentPoints, cActualPts))
+ return false;
+ if (!GetComponentPlacement(pSimpleGlyf, rgnCompId[i], fOffset, a, b))
+ return false;
+ if (!GetComponentTransform(pSimpleGlyf, rgnCompId[i],
+ flt11, flt12, flt21, flt22, fTransOff))
+ return false;
+ bool fIdTrans = flt11 == 1.0 && flt12 == 0.0 && flt21 == 0.0 && flt22 == 1.0;
+
+ // convert points to absolute coordinates
+ // do before transform and attachment point placement are applied
+ CalcAbsolutePoints(prgnCurrentX, prgnCurrentY, cActualPts);
+
+ // apply transform - see main method note above
+ // do before attachment point calcs
+ if (!fIdTrans)
+ for (int j = 0; j < cActualPts; j++)
+ {
+ int x = prgnCurrentX[j]; // store before transform applied
+ int y = prgnCurrentY[j];
+ prgnCurrentX[j] = (int)(x * flt11 + y * flt12);
+ prgnCurrentY[j] = (int)(x * flt21 + y * flt22);
+ }
+
+ // apply placement - see main method note above
+ int nXOff, nYOff;
+ if (fOffset) // explicit x & y offsets
+ {
+ /* ignore fTransOff for now
+ if (fTransOff && !fIdTrans)
+ { // transform x & y offsets
+ nXOff = (int)(a * flt11 + b * flt12);
+ nYOff = (int)(a * flt21 + b * flt22);
+ }
+ else */
+ { // don't transform offset
+ nXOff = a;
+ nYOff = b;
+ }
+ }
+ else // attachment points
+ { // in case first point is relative to preceding glyph and second relative to current
+ // nXOff = prgnPrevX[a] - prgnCurrentX[b];
+ // nYOff = prgnPrevY[a] - prgnCurrentY[b];
+ // first point number relative to whole composite, second relative to current glyph
+ nXOff = prgnX[a] - prgnCurrentX[b];
+ nYOff = prgnY[a] - prgnCurrentY[b];
+ }
+ for (int j = 0; j < cActualPts; j++)
+ {
+ prgnCurrentX[j] += nXOff;
+ prgnCurrentY[j] += nYOff;
+ }
+
+ // prgnPrevX = prgnCurrentX;
+ // prgnPrevY = prgnCurrentY;
+ prgnCurrentX += cActualPts;
+ prgnCurrentY += cActualPts;
+ prgbCurrentFlag += cActualPts;
+ cCurrentPoints -= cActualPts;
+ }
+
+ SimplifyFlags((char *)prgfOnCurve, cnPoints);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Simplify the meaning of flags to just indicate whether point is on-curve or off-curve
+---------------------------------------------------------------------------------------------*/
+bool SimplifyFlags(char * prgbFlags, int cnPoints)
+{
+ for (int i = 0; i < cnPoints; i++)
+ prgbFlags[i] = static_cast<char>(prgbFlags[i] & Sfnt::SimpleGlyph::OnCurve);
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert relative point coordinates to absolute coordinates
+ Points are stored in the font such that they are offsets from one another except for the
+ first point of a glyph.
+---------------------------------------------------------------------------------------------*/
+bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints)
+{
+ int nX = prgnX[0];
+ int nY = prgnY[0];
+ for (int i = 1; i < cnPoints; i++)
+ {
+ prgnX[i] += nX;
+ nX = prgnX[i];
+ prgnY[i] += nY;
+ nY = prgnY[i];
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert a numerical table ID to a string containing the actual name of the table.
+ Returns native order unsigned long.
+---------------------------------------------------------------------------------------------*/
+gr::fontTableId32 TableIdTag(const TableId tid)
+{
+ assert(sizeof(mapIdToTag) == sizeof(gr::fontTableId32) * ktiLast);
+ assert(tid < ktiLast);
+
+ return mapIdToTag[tid];
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the length of the 'name' table in bytes.
+ Currently used.
+---------------------------------------------------------------------------------------------*/
+#if 0
+size_t NameTableLength(const gr::byte * pTable)
+{
+ gr::byte * pb = (const_cast<gr::byte *>(pTable)) + 2; // skip format
+ size_t cRecords = *pb++ << 8; cRecords += *pb++;
+ int dbStringOffset0 = (*pb++) << 8; dbStringOffset0 += *pb++;
+ int dbMaxStringOffset = 0;
+ for (size_t irec = 0; irec < cRecords; irec++)
+ {
+ int nPlatform = (*pb++) << 8; nPlatform += *pb++;
+ int nEncoding = (*pb++) << 8; nEncoding += *pb++;
+ int nLanguage = (*pb++) << 8; nLanguage += *pb++;
+ int nName = (*pb++) << 8; nName += *pb++;
+ int cbStringLen = (*pb++) << 8; cbStringLen += *pb++;
+ int dbStringOffset = (*pb++) << 8; dbStringOffset += *pb++;
+ if (dbMaxStringOffset < dbStringOffset + cbStringLen)
+ dbMaxStringOffset = dbStringOffset + cbStringLen;
+ }
+ return dbStringOffset0 + dbMaxStringOffset;
+}
+#endif
+
+} // end of namespace TtfUtil
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.h b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.h
new file mode 100644
index 00000000000..bf437ff3475
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/font/TtfUtil.h
@@ -0,0 +1,147 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2000, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TtfUtil.h
+Responsibility: Alan Ward
+Last reviewed: Not yet.
+
+Description:
+ Utility class for handling TrueType font files.
+----------------------------------------------------------------------------------------------*/
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef TTFUTIL_H
+#define TTFUTIL_H
+
+#include <cstddef>
+#include <stdexcept>
+#include "GrPlatform.h"
+
+// Enumeration used to specify a table in a TTF file
+enum TableId
+{
+ ktiCmap, ktiCvt, ktiCryp, ktiHead, ktiFpgm, ktiGdir, ktiGlyf,
+ ktiHdmx, ktiHhea, ktiHmtx, ktiLoca, ktiKern, ktiLtsh, ktiMaxp,
+ ktiName, ktiOs2, ktiPost, ktiPrep, ktiFeat, ktiGlat, ktiGloc,
+ ktiSilf, ktiSile, ktiSill,
+ ktiLast /*This gives the enum length - it is not a real table*/
+};
+
+/*----------------------------------------------------------------------------------------------
+ Class providing utility methods to parse a TrueType font file (TTF).
+ Callling application handles all file input and memory allocation.
+ Assumes minimal knowledge of TTF file format.
+----------------------------------------------------------------------------------------------*/
+namespace TtfUtil
+{
+ ////////////////////////////////// tools to find & check TTF tables
+ bool GetHeaderInfo(size_t & lOffset, size_t & lSize);
+ bool CheckHeader(const void * pHdr);
+ bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize);
+ bool GetTableInfo(TableId ktiTableId, const void * pHdr, const void * pTableDir,
+ size_t & lOffset, size_t & lSize);
+ bool CheckTable(TableId ktiTableId, const void * pTable, size_t lTableSize);
+
+ ////////////////////////////////// simple font wide info
+ size_t GlyphCount(const void * pMaxp);
+ size_t MaxCompositeComponentCount(const void * pMaxp);
+ size_t MaxCompositeLevelCount(const void * pMaxp);
+ size_t LocaGlyphCount(size_t lLocaSize, const void * pHead) throw (std::domain_error);
+ int DesignUnits(const void * pHead);
+ int HeadTableCheckSum(const void * pHead);
+ void HeadTableCreateTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
+ void HeadTableModifyTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
+ bool IsItalic(const void * pHead);
+ int FontAscent(const void * pOs2);
+ int FontDescent(const void * pOs2);
+ bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic);
+ bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
+ bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
+ bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
+ bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
+ int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
+ const char * pPostName);
+
+ ////////////////////////////////// utility methods helpful for name table
+ bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
+ int nLangId, int nNameId, size_t & lOffset, size_t & lSize);
+ //size_t NameTableLength(const gr::byte * pTable);
+ int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
+ int *nameIdList, int cNameIds, short *langIdList);
+ void SwapWString(void * pWStr, size_t nSize = 0) throw (std::invalid_argument);
+
+ ////////////////////////////////// cmap lookup tools
+ void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
+ int nEncodingId = 1);
+ bool CheckCmap31Subtable(const void * pCmap31);
+ gr::gid16 Cmap31Lookup(const void * pCmap31, int nUnicodeId);
+ unsigned int Cmap31NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
+ int * pRangeKey = 0);
+ bool CheckCmap310Subtable(const void *pCmap310);
+ gr::gid16 Cmap310Lookup(const void * pCmap310, unsigned int uUnicodeId);
+ unsigned int Cmap310NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
+ int * pRangeKey = 0);
+
+ ///////////////////////////////// horizontal metric data for a glyph
+ bool HorMetrics(gr::gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize,
+ const void * pHhea, int & nLsb, unsigned int & nAdvWid);
+
+ ///////////////////////////////// convert our TableId enum to standard TTF tags
+ gr::fontTableId32 TableIdTag(const TableId);
+
+ ////////////////////////////////// primitives for loca and glyf lookup
+ size_t LocaLookup(gr::gid16 nGlyphId, const void * pLoca, size_t lLocaSize,
+ const void * pHead) throw (std::out_of_range);
+ void * GlyfLookup(const void * pGlyf, size_t lGlyfOffset);
+
+ ////////////////////////////////// primitves for simple glyph data
+ bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
+ int & xMax, int & yMax);
+
+ int GlyfContourCount(const void * pSimpleGlyf);
+ bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
+ int cnPointsTotal, size_t & cnPoints);
+ bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
+ char * prgbFlag, int cnPointsTotal, int & cnPoints);
+
+ // primitive to find the glyph ids in a composite glyph
+ bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
+ size_t cnCompIdTotal, size_t & cnCompId);
+ // primitive to find the placement data for a component in a composite glyph
+ bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
+ bool fOffset, int & a, int & b);
+ // primitive to find the transform data for a component in a composite glyph
+ bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
+ float & flt11, float & flt12, float & flt21, float & flt22, bool & fTransOffset);
+
+ ////////////////////////////////// operate on composite or simple glyph (auto glyf lookup)
+ void * GlyfLookup(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead); // primitive used by below methods
+
+ // below are primary user methods for handling glyf data
+ bool IsSpace(gr::gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead);
+ bool IsDeepComposite(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead);
+
+ bool GlyfBox(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca, size_t lLocaSize,
+ const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax);
+ bool GlyfContourCount(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void *pHead, size_t & cnContours);
+ bool GlyfContourEndPoints(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead, int * prgnContourEndPoint, size_t cnPoints);
+ bool GlyfPoints(gr::gid16 nGlyphId, const void * pGlyf, const void * pLoca,
+ size_t lLocaSize, const void * pHead, const int * prgnContourEndPoint, size_t cnEndPoints,
+ int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints);
+
+ // utitily method used by high-level GlyfPoints
+ bool SimplifyFlags(char * prgbFlags, int cnPoints);
+ bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints);
+
+} // end of namespace TtfUtil
+
+#endif
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree.h b/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree.h
new file mode 100644
index 00000000000..a487df03770
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree.h
@@ -0,0 +1,71 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: BinTree.h
+Responsibility: Darrell Zook
+Last reviewed: 9/8/99
+
+Description:
+ This file provides declarations of binary tree class(es).
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef BINTREE_H_INCLUDED
+#define BINTREE_H_INCLUDED
+
+/*----------------------------------------------------------------------------------------------
+ This template class implements a balanced tree, which is a binary tree where the height of
+ the two children of any node in the tree can only be different by +/- 1 or 0.
+
+ The class of objects to be stored in the tree should be derived from BalTreeBase, because
+ the constructor of BalTreeBase adds an object to the tree in sorted order without
+ allocating any memory.
+
+ Classes that derive from BalTreeBase must have a CompareKey member function that compares
+ a given key with this->key to determine which should be first when sorting the tree.
+ The declaration of CompareKey should be as follows:
+ int CompareKey(const Key & key);
+ and it should return:
+ <0 if key is less than the key in the current node (this->key)
+ 0 if key is equal to the key in the current node (this->key)
+ >0 if key is greater than the key in the current node (this->key)
+
+ CAUTION: Classes that use this template should never be dynamically instantiated (by using
+ local variables or new/NewObj). This class is meant to be used only for global
+ instances of a class. The reason for this restriction is that the tree is never
+ destroyed, so using dynamic instantiations of objects would result in stale pointers
+ in the tree.
+
+ Hungarian: btb
+----------------------------------------------------------------------------------------------*/
+
+template<typename Obj, typename Key> class BalTreeBase
+{
+protected:
+ // Pointers to the left and right subtrees.
+ Obj * m_rgpobj[2];
+
+ // The difference between the height of the right sub tree and the height of the left
+ // sub tree. This should be -1, 0, or +1. Insert may temporarily set it to -2 or +2.
+ short m_dht;
+
+ // Which way we went from this node when inserting the new node.
+ short m_ipobj;
+
+ // Inserts this in the balanced tree.
+ BalTreeBase(Obj ** ppobjRoot, const Key & key);
+
+ // Returns a node with the given key from the tree rooted at pobjRoot.
+ static Obj * Find(Obj * pobjRoot, const Key & key);
+
+private:
+ // Inserts a node in the tree rooted at *ppobjRoot, sorting it based on key.
+ void Insert(Obj ** ppobjRoot, const Key & key);
+};
+
+#endif // !BINTREE_H_INCLUDED
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree_i.cpp b/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree_i.cpp
new file mode 100644
index 00000000000..5929bf0bab1
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/BinTree_i.cpp
@@ -0,0 +1,225 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: BinTree_i.cpp
+Responsibility: Darrell Zook
+Last reviewed: 9/8/99
+
+Description:
+ This file provides implementations of binary tree class(es).
+ It is used as an #include file in any file which derives from one of the classes.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef BINTREE_I_CPP_INCLUDED
+#define BINTREE_I_CPP_INCLUDED
+
+#include "BinTree.h"
+////#include <algorithm>
+////#include "GrPlatform.h"
+#include "GrCommon.h"
+
+
+//using namespace gr;
+
+/***********************************************************************************************
+ BalTreeBase<Obj, Key> methods
+***********************************************************************************************/
+
+/*----------------------------------------------------------------------------------------------
+ Constructor.
+ This calls Insert to add this node to the tree in the correct (sorted) position.
+
+ Arguments:
+ [in] ppobjRoot -> The address of the pointer to the root node of the tree.
+ [in] key -> References the key of the node to insert.
+----------------------------------------------------------------------------------------------*/
+template<typename Obj, typename Key>
+ BalTreeBase<Obj, Key>::BalTreeBase(Obj ** ppobjRoot, const Key & key)
+{
+ AssertPtr(ppobjRoot);
+ AssertPtrN(*ppobjRoot);
+
+ m_rgpobj[0] = NULL;
+ m_rgpobj[1] = NULL;
+ m_dht = 0;
+
+ Insert(ppobjRoot, key);
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method finds a node with the given key within the tree. If the key is not found in
+ the tree, NULL is returned.
+
+ Arguments:
+ [in] pobjRoot -> Points to the root node of the tree.
+ [in] key -> References the key of the node to search for.
+----------------------------------------------------------------------------------------------*/
+template<typename Obj, typename Key>
+ Obj * BalTreeBase<Obj, Key>::Find(Obj * pobjRoot, const Key & key)
+{
+ AssertPtrN(pobjRoot);
+
+ for (Obj * pobj = pobjRoot; pobj; )
+ {
+ int nT = pobj->CompareKey(key);
+ if (0 == nT)
+ return pobj;
+ pobj = pobj->m_rgpobj[nT > 0];
+ }
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method inserts a node within the tree, sorting it based on key. It does not allocate
+ any memory.
+
+ Arguments:
+ [in] ppobjRoot -> The address of the pointer to the root node of the tree.
+ [in] key -> References the key of the node to insert into the tree.
+ Note: "this" is the node that is being inserted into the tree.
+----------------------------------------------------------------------------------------------*/
+template<typename Obj, typename Key>
+ void BalTreeBase<Obj, Key>::Insert(Obj ** ppobjRoot, const Key & key)
+{
+ AssertPtr(ppobjRoot);
+ AssertPtrN(*ppobjRoot);
+
+ Assert(m_dht == 0);
+ Assert(!m_rgpobj[0]);
+ Assert(!m_rgpobj[1]);
+
+ Obj * pobjThis = static_cast<Obj *>(this);
+
+ // If the tree is empty, set the root of the tree to this and return.
+ if (!*ppobjRoot)
+ {
+ *ppobjRoot = pobjThis;
+ return;
+ }
+
+ Obj ** ppobjRebal = ppobjRoot;
+ Obj * pobjCur;
+
+ // Place this in the tree. Mark each node indicating which branch we took.
+ // Remember the lowest node with non-zero m_dht in ppobjRebal. If we have to do
+ // rebalancing, this is where we'll do it.
+ for (pobjCur = *ppobjRoot; ; )
+ {
+ AssertPtr(pobjCur);
+
+ int nT = pobjCur->CompareKey(key);
+ Assert(nT != 0);
+
+ // if nT is positive go right, otherwise go left.
+ pobjCur->m_ipobj = nT > 0;
+
+ Obj ** ppobjNext = &pobjCur->m_rgpobj[pobjCur->m_ipobj];
+ if (!*ppobjNext)
+ {
+ // Place the node and break.
+ *ppobjNext = pobjThis;
+ break;
+ }
+
+ // Remember this location if m_dht is non-zero.
+ if ((*ppobjNext)->m_dht != 0)
+ ppobjRebal = ppobjNext;
+
+ // Move on down.
+ pobjCur = *ppobjNext;
+ }
+
+ // Adjust m_dht from *ppobjRebal to pobjThis.
+ for (pobjCur = *ppobjRebal; pobjCur != pobjThis; )
+ {
+ AssertPtr(pobjCur);
+ Assert((unsigned int)pobjCur->m_ipobj < (unsigned int)2);
+
+ // Recall that ppobjRebal is the lowest node on the path which has non-zero m_dht.
+ Assert(pobjCur->m_dht == 0 || pobjCur == *ppobjRebal);
+
+ // If we went left (m_ipobj == 0) we need to subtract one. If we went right
+ // (m_ipobj == 1) we need to add one.
+ pobjCur->m_dht = (short)(pobjCur->m_dht + (pobjCur->m_ipobj << 1) - 1);
+ pobjCur = pobjCur->m_rgpobj[pobjCur->m_ipobj];
+ }
+
+ if ((unsigned int)((*ppobjRebal)->m_dht + 1) <= (unsigned int)2)
+ {
+ // No need to rebalance since the new m_dht for *ppobjRebal is within -1 to 1.
+ return;
+ }
+
+ // We need to rebalance.
+ Obj * pobjRebal = *ppobjRebal;
+ Assert(pobjRebal->m_dht == -2 || pobjRebal->m_dht == 2);
+
+ // Get the direction from pobjRebal and the next lower node.
+ int ipobj = pobjRebal->m_ipobj;
+ Obj * pobjChd = pobjRebal->m_rgpobj[ipobj];
+
+ if (pobjChd->m_ipobj == ipobj)
+ {
+ // We branched the same way at pobjRebal and pobjChd.
+ // Do a single rotation: make pobjChd the parent of pobjRebal.
+ Assert(pobjChd->m_dht << 1 == pobjRebal->m_dht);
+ pobjRebal->m_rgpobj[ipobj] = pobjChd->m_rgpobj[1 - ipobj];
+ pobjChd->m_rgpobj[1 - ipobj] = pobjRebal;
+ *ppobjRebal = pobjChd;
+
+ // Fix the m_dht values.
+ pobjChd->m_dht = 0;
+ pobjRebal->m_dht = 0;
+ return;
+ }
+
+ // We branched opposite ways at pobjRebal and pobjChd.
+ // Do a double rotation.
+ Assert(pobjChd->m_ipobj == 1 - ipobj);
+ pobjCur = pobjChd->m_rgpobj[1 - ipobj];
+ AssertPtr(pobjCur);
+
+ // Let (A own[ipobj] B) mean that A->m_rgpobj[ipobj] == B.
+ // Currently, (pobjRebal own[ipobj] pobjChd) and (pobjChd own[1 - ipobj] pobjCur).
+ // Make (pobjCur own[ipobj] pobjChd) and (pobjCur own[1 - ipobj] pobjRebal).
+
+ // Rotate pobjChd and pobjCur.
+ Assert(pobjCur == pobjChd->m_rgpobj[1 - ipobj]);
+ pobjChd->m_rgpobj[1 - ipobj] = pobjCur->m_rgpobj[ipobj];
+ pobjCur->m_rgpobj[ipobj] = pobjChd;
+
+ // Rotate pobjRebal and pobjCur.
+ Assert(pobjRebal->m_rgpobj[ipobj] == pobjChd);
+ pobjRebal->m_rgpobj[ipobj] = pobjCur->m_rgpobj[1 - ipobj];
+ pobjCur->m_rgpobj[1 - ipobj] = pobjRebal;
+
+ // Fix *ppobjRebal.
+ *ppobjRebal = pobjCur;
+
+ // Fix the m_dht values. Note that we don't compare with pobjRebal->m_dht since it
+ // currently has absolute value 2.
+ Assert(pobjChd->m_dht);
+ if (pobjCur->m_dht == pobjChd->m_dht)
+ {
+ pobjRebal->m_dht = 0;
+ pobjChd->m_dht = (short)-pobjChd->m_dht;
+ }
+ else if (pobjCur->m_dht == -pobjChd->m_dht)
+ {
+ pobjRebal->m_dht = pobjChd->m_dht;
+ pobjChd->m_dht = 0;
+ }
+ else
+ {
+ pobjRebal->m_dht = 0;
+ pobjChd->m_dht = 0;
+ }
+ pobjCur->m_dht = 0;
+}
+
+#endif // !BINTREE_I_CPP_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/Debug.cpp b/Build/source/libs/graphite/engine-2.3.1/src/generic/Debug.cpp
new file mode 100644
index 00000000000..d1f2a67e364
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/Debug.cpp
@@ -0,0 +1,83 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: Debug.cpp
+Responsibility: Darrell Zook
+Last reviewed: Not yet.
+
+Description:
+ This file provides the standard debug error functions.
+----------------------------------------------------------------------------------------------*/
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+//#include "common.h"
+//#include "Main.h"
+#include "GrDebug.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//#include "ModuleEntry.h"
+#include <stdio.h>
+#ifdef _MSC_VER
+#include <crtdbg.h>
+#endif
+
+
+#if 0
+//#ifdef DEBUG
+
+extern HMODULE Win32DllGetModuleHandle();
+
+void WINAPI AssertProcLocal(const char * pszExp, const char * pszFile, int nLine,
+ bool fCritical)
+{
+ AssertProc(pszExp, pszFile, nLine, fCritical, Win32DllGetModuleHandle());
+}
+
+void WINAPI WarnProcLocal(const char * pszExp, const char * pszFile, int nLine,
+ bool fCritical)
+{
+ WarnProc(pszExp, pszFile, nLine, fCritical, Win32DllGetModuleHandle());
+}
+
+void WINAPI WarnHrProc(HRESULT hr, const char * pszFile, int nLine, bool fCritical)
+{
+ char szBuffer[MAX_PATH + 25];
+ sprintf(szBuffer, "HRESULT[0x%08x]--", hr);
+ int cch = lstrlen(szBuffer);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szBuffer + cch,
+ sizeof(szBuffer) - cch, NULL);
+ szBuffer[max(lstrlen(szBuffer) - 2, 0)] = 0;
+ WarnProcLocal(szBuffer, pszFile, nLine, fCritical);
+}
+
+
+OLECHAR * DebugWatch::WatchNV()
+{
+ // JT: we need this, otherwise if dealing with a deleted object or null pointer
+ // we may try to call a virtual function where there is no valid VTABLE pointer.
+ // In the debugger we can't be sure of not dereferencing a bad pointer.
+ if (!::_CrtIsValidPointer(this, isizeof(this), TRUE ))
+ return L"A very bad object pointer";
+ // We could also be referencing memory that is trashed (e.g., the object has
+ // been deleted, or deleted and replaced by something else).
+ if (!dynamic_cast<DebugWatch *>(this))
+ return L"A bad object pointer";
+ return Watch();
+}
+
+void DebugWatch::Output (char *fmt, ...) // LIMITED to 10 pointer-sized arguments
+{
+ struct args { void * pv[10]; };
+ _CrtDbgReport (_CRT_WARN, NULL, NULL, __FILE__, fmt, *(args*)(&fmt+1));
+}
+
+#endif // DEBUG
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/GenericResource.h b/Build/source/libs/graphite/engine-2.3.1/src/generic/GenericResource.h
new file mode 100644
index 00000000000..119c6317bcd
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/GenericResource.h
@@ -0,0 +1,86 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GenericResource.h
+Responsibility: John Thomson
+Last reviewed:
+
+ Resources needed by certain generic components (but must be created in app's or AppCore's
+ resource file).
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GenericResource_H
+#define GenericResource_H 1
+// Create suitable resources for these if your app uses StackDumper.
+// For example
+// STRINGTABLE DISCARDABLE
+// BEGIN
+// "A programming error (%s) has been detected in module %s.\n Please report this to the developers", kstidInternalError
+// "Out of memory. To attempt Save, close other apps and click OK. To quit without saving click Cancel", kstidOutOfMemory
+// END
+
+
+// Date qualifier string IDs:
+#define kstidDateQualBefore 24200
+#define kstidDateQualOn 24201
+#define kstidDateQualAbout 24202
+#define kstidDateQualAfter 24203
+#define kstidDateQualAbt 24204
+#define kstidDateQualBC 24205
+#define kstidDateQualAD 24206
+#define kstidDateBlank 24207
+#define kstidDateBlankM 24208
+#define kstidDateBlankD 24209
+
+
+#define kstidInternalError 25900
+#define khcidHelpOutOfMemory 25901
+#define khcidNoHelpAvailable 25902 // default help module when there is no specific one.
+#define kstidOutOfMemory 25903
+#define kstidUndoFrame 25904
+#define kstidRedoFrame 25905
+
+#define kstidFileErrUnknown 25920
+#define kstidFileErrNotFound 25921
+#define kstidFileErrPathNotFound 25922
+#define kstidFileErrTooManyFiles 25923
+#define kstidFileErrAccDenied 25924
+#define kstidFileErrBadHandle 25925
+#define kstidFileErrBadDrive 25926
+#define kstidFileErrWriteProtect 25927
+#define kstidFileErrBadUnit 25928
+#define kstidFileErrNotReady 25929
+#define kstidFileErrSeek 25930
+#define kstidFileErrNotDosDisk 25931
+#define kstidFileErrBadSector 25932
+#define kstidFileErrWriteFault 25933
+#define kstidFileErrReadFault 25934
+#define kstidFileErrGeneral 25935
+#define kstidFileErrSharing 25936
+#define kstidFileErrLock 25937
+#define kstidFileErrEof 25938
+#define kstidFileErrHandleDiskFull 25939
+#define kstidFileErrBadNetPath 25940
+#define kstidFileErrNetworkBusy 25941
+#define kstidFileErrNoDevice 25942
+#define kstidFileErrNoNetAccess 25943
+#define kstidFileErrBadDevice 25944
+#define kstidFileErrBadNetName 25945
+#define kstidFileErrExists 25946
+#define kstidFileErrCantMake 25947
+#define kstidFileErrBadPassword 25948
+#define kstidFileErrNetWriteFault 25949
+#define kstidFileErrDriveLocked 25950
+#define kstidFileErrOpenFailed 25951
+#define kstidFileErrBufOverflow 25952
+#define kstidFileErrDiskFull 25953
+#define kstidFileErrBadName 25954
+#define kstidFileErrNoVolLabel 25955
+#define kstidFileErrAlreadyExists 25956
+
+#endif // !GenericResource_H
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap.h b/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap.h
new file mode 100644
index 00000000000..dc2de9d0af7
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap.h
@@ -0,0 +1,328 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: HashMap.h
+Responsibility: Steve McConnel
+Last reviewed: Not yet.
+
+Description:
+ This provides a set of template collection classes to replace std::map. Their primary
+ reason to exist is to allow explicit checking for internal memory allocation failures.
+----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef HASHMAP_H_INCLUDED
+#define HASHMAP_H_INCLUDED
+//:End Ignore
+
+/*----------------------------------------------------------------------------------------------
+ Functor class for computing a hash value from an arbitrary object.
+
+ Hungarian: hsho
+----------------------------------------------------------------------------------------------*/
+class HashObj
+{
+public:
+ int operator () (void * pKey, int cbKey);
+};
+
+/*----------------------------------------------------------------------------------------------
+ Functor class for comparing two arbitrary objects (of the same class) for equality.
+
+ Hungarian: eqlo
+----------------------------------------------------------------------------------------------*/
+class EqlObj
+{
+public:
+ bool operator () (void * pKey1, void * pKey2, int cbKey);
+};
+
+/*----------------------------------------------------------------------------------------------
+ Hash map template collection class whose keys are objects of an arbitrary class.
+
+ Hungarian: hm[K][T]
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H = HashObj, class Eq = EqlObj> class HashMap
+{
+public:
+ //:> Member classes
+
+ /*------------------------------------------------------------------------------------------
+ This is the basic data structure for storing one key-value pair in a hash map. In
+ order to handle hash collisions, this structure is a member of a linked list.
+ Hungarian: hsnd
+ ------------------------------------------------------------------------------------------*/
+ class HashNode
+ {
+ public:
+ //:> Constructors/destructors/etc.
+
+ HashNode(void)
+ : m_key(K()), m_value(T()), m_nHash(0), m_ihsndNext(0)
+ {
+ }
+ HashNode(K & key, T & value, int nHash, int ihsndNext = -1)
+ : m_key(key), m_value(value), m_nHash(nHash), m_ihsndNext(ihsndNext)
+ {
+ }
+ ~HashNode()
+ {
+ }
+
+ //:> Member variable access
+
+ void PutKey(K & key)
+ {
+ m_key = key;
+ }
+ K & GetKey()
+ {
+ return m_key;
+ }
+ void PutValue(T & value)
+ {
+ m_value = value;
+ }
+ T & GetValue()
+ {
+ return m_value;
+ }
+ void PutHash(int nHash)
+ {
+ m_nHash = nHash;
+ }
+ int GetHash()
+ {
+ return m_nHash;
+ }
+ void PutNext(int ihsndNext)
+ {
+ m_ihsndNext = ihsndNext;
+ }
+ int GetNext()
+ {
+ return m_ihsndNext;
+ }
+
+ /*--------------------------------------------------------------------------------------
+ Check whether the given HashNode is being used.
+ --------------------------------------------------------------------------------------*/
+ bool InUse()
+ {
+ return m_ihsndNext >= -1;
+ }
+
+ protected:
+ //:> Member variables
+
+ K m_key;
+ T m_value;
+ int m_nHash;
+ int m_ihsndNext; // -1 means end of list, -(ihsnd + 3) for free list members
+ };
+
+ /*------------------------------------------------------------------------------------------
+ This provides an iterator for stepping through all HashNodes stored in the hash map.
+ This is useful primarily for saving the contents of a hash map to a file.
+
+ Hungarian: ithm[K][T]
+ ------------------------------------------------------------------------------------------*/
+ class iterator
+ {
+ public:
+ // Constructors/destructors/etc.
+
+ iterator() : m_phmParent(NULL), m_ihsnd(0)
+ {
+ }
+ iterator(HashMap<K,T,H,Eq> * phm, int ihsnd) : m_phmParent(phm), m_ihsnd(ihsnd)
+ {
+ }
+ iterator(const iterator & v) : m_phmParent(v.m_phmParent), m_ihsnd(v.m_ihsnd)
+ {
+ }
+ ~iterator()
+ {
+ }
+
+ // Other public methods
+
+ iterator & operator = (const iterator & ithm)
+ {
+ m_phmParent = ithm.m_phmParent;
+ m_ihsnd = ithm.m_ihsnd;
+ return *this;
+ }
+ T & operator * (void)
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ return m_phmParent->m_prghsnd[m_ihsnd].GetValue();
+ }
+ HashNode * operator -> (void)
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ return &m_phmParent->m_prghsnd[m_ihsnd];
+ }
+ iterator & operator ++ (void)
+ {
+ Assert(m_phmParent);
+ ++m_ihsnd;
+ // make sure that this new HashNode is actually in use
+ while (m_ihsnd < m_phmParent->m_ihsndLim)
+ {
+ if (m_phmParent->m_prghsnd[m_ihsnd].InUse())
+ return *this;
+ // skip to the next one and check it
+ ++m_ihsnd;
+ }
+ if (m_ihsnd > m_phmParent->m_ihsndLim)
+ m_ihsnd = m_phmParent->m_ihsndLim;
+ return *this;
+ }
+ bool operator == (const iterator & ithm)
+ {
+ return (m_phmParent == ithm.m_phmParent) && (m_ihsnd == ithm.m_ihsnd);
+ }
+ bool operator != (const iterator & ithm)
+ {
+ return (m_phmParent != ithm.m_phmParent) || (m_ihsnd != ithm.m_ihsnd);
+ }
+ T & GetValue(void)
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ Assert(m_phmParent->m_prghsnd[m_ihsnd].InUse());
+ return m_phmParent->m_prghsnd[m_ihsnd].GetValue();
+ }
+ K & GetKey(void)
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ Assert(m_phmParent->m_prghsnd[m_ihsnd].InUse());
+ return m_phmParent->m_prghsnd[m_ihsnd].GetKey();
+ }
+ int GetHash()
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ Assert(m_phmParent->m_prghsnd[m_ihsnd].InUse());
+ return m_phmParent->m_prghsnd[m_ihsnd].GetHash();
+ }
+ int GetIndex()
+ {
+ Assert(m_phmParent);
+ Assert(m_phmParent->m_prghsnd);
+ Assert(m_ihsnd < m_phmParent->m_ihsndLim);
+ Assert(m_phmParent->m_prghsnd[m_ihsnd].InUse());
+ return m_ihsnd;
+ }
+
+ protected:
+ //:> Member variables
+
+ HashMap<K,T,H,Eq> * m_phmParent;
+ int m_ihsnd;
+ };
+ friend class iterator;
+
+ //:> Constructors/destructors/etc.
+
+ HashMap();
+ ~HashMap();
+ HashMap(HashMap<K,T,H,Eq> & hm);
+
+ //:> Other public methods
+
+ iterator Begin();
+ iterator End();
+ void Insert(K & key, T & value, bool fOverwrite = false, int * pihsndOut = NULL);
+ bool Retrieve(K & key, T * pvalueRet);
+ bool Delete(K & key);
+ void Clear();
+ void CopyTo(HashMap<K,T,H,Eq> & hmKT);
+ void CopyTo(HashMap<K,T,H,Eq> * phmKT);
+
+ bool GetIndex(K & key, int * pihsndRet);
+ bool IndexKey(int ihsnd, K * pkeyRet);
+ bool IndexValue(int ihsnd, T * pvalueRet);
+
+ int Size();
+
+ /*------------------------------------------------------------------------------------------
+ The assignment operator allows an entire hashmap to be assigned as the value of another
+ hashmap. It throws an error if it runs out of memory.
+
+ @return a reference to this hashmap. (That is how the assignment operator is defined!)
+
+ @param hm is a reference to the other hashmap.
+ ------------------------------------------------------------------------------------------*/
+ HashMap<K,T,H,Eq> & operator = (HashMap<K,T,H,Eq> & hm)
+ {
+ hm.CopyTo(this);
+ return *this;
+ }
+
+ //:Ignore
+#ifdef DEBUG
+ int _BucketCount();
+ int _EmptyBuckets();
+ int _BucketsUsed();
+ int _FullestBucket();
+ bool AssertValid()
+ {
+ AssertPtrN(m_prgihsndBuckets);
+ Assert(m_prgihsndBuckets || !m_cBuckets);
+ Assert(!m_prgihsndBuckets || m_cBuckets);
+ AssertArray(m_prgihsndBuckets, m_cBuckets);
+ AssertPtrN(m_prghsnd);
+ Assert(m_prghsnd || !m_ihsndMax);
+ Assert(!m_prghsnd || m_ihsndMax);
+ AssertArray(m_prghsnd, m_ihsndMax);
+ Assert(0 <= m_ihsndLim && m_ihsndLim <= m_ihsndMax);
+ Assert(-1 <= FreeListIdx(m_ihsndFirstFree));
+ Assert(FreeListIdx(m_ihsndFirstFree) < m_ihsndLim);
+ return true;
+ }
+#endif
+ //:End Ignore
+
+protected:
+ //:> Member variables
+
+ int * m_prgihsndBuckets;
+ int m_cBuckets;
+ HashNode * m_prghsnd;
+ int m_ihsndLim;
+ int m_ihsndMax;
+ int m_ihsndFirstFree; // stores -(ihsnd + 3)
+
+ //:> Protected methods
+ //:Ignore
+
+ /*------------------------------------------------------------------------------------------
+ Map between real index and "free list" index. Note that this mapping is bidirectional.
+ ------------------------------------------------------------------------------------------*/
+ int FreeListIdx(int ihsnd)
+ {
+ return -(ihsnd + 3);
+ }
+ //:End Ignore
+};
+
+
+// Local Variables:
+// mode:C++
+// c-file-style:"cellar"
+// tab-width:4
+// End:
+
+#endif /*HASHMAP_H_INCLUDED*/
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap_i.cpp b/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap_i.cpp
new file mode 100644
index 00000000000..baebe427a4e
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/HashMap_i.cpp
@@ -0,0 +1,561 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: HashMap_i.cpp
+Responsibility: Steve McConnel
+Last reviewed: Not yet.
+
+Description:
+ This file provides the implementations of methods for the HashMap template collection
+ classes. It is used as an #include file in any file which explicitly instantiates any
+ particular type of HashMap<K,T>, HashMapStrUni<T>, or HashMapChars<T>.
+----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef HASHMAP_I_C_INCLUDED
+#define HASHMAP_I_C_INCLUDED
+
+#include "HashMap.h"
+////#include <algorithm>
+////#include "GrPlatform.h"
+#include "GrCommon.h"
+
+/***********************************************************************************************
+ Methods
+***********************************************************************************************/
+//:End Ignore
+
+/*----------------------------------------------------------------------------------------------
+ Constructor.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ HashMap<K,T,H,Eq>::HashMap()
+{
+ m_prgihsndBuckets = NULL;
+ m_cBuckets = 0;
+ m_prghsnd = NULL;
+ m_ihsndLim = 0;
+ m_ihsndMax = 0;
+ m_ihsndFirstFree = FreeListIdx(-1);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy constructor. It throws an error if it runs out of memory.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ HashMap<K,T,H,Eq>::HashMap(HashMap<K,T,H,Eq> & hm)
+{
+ m_prgihsndBuckets = NULL;
+ m_cBuckets= 0;
+ m_prghsnd = NULL;
+ m_ihsndLim = 0;
+ m_ihsndMax = 0;
+ m_ihsndFirstFree = FreeListIdx(-1);
+ hm.CopyTo(this);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructor.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ HashMap<K,T,H,Eq>::~HashMap()
+{
+ Clear();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return an iterator that references the first key and value stored in the HashMap.
+ If the hash map is empty, Begin returns the same value as End.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ typename HashMap<K,T,H,Eq>::iterator HashMap<K,T,H,Eq>::Begin()
+{
+ AssertObj(this);
+ int ihsnd;
+ for (ihsnd = 0; ihsnd < m_ihsndLim; ++ihsnd)
+ {
+ if (m_prghsnd[ihsnd].InUse())
+ {
+ iterator ithm(this, ihsnd);
+ return ithm;
+ }
+ }
+ return End();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return an iterator that marks the end of the set of keys and values stored in the HashMap.
+ If the HashMap is empty, End returns the same value as Begin.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ typename HashMap<K,T,H,Eq>::iterator HashMap<K,T,H,Eq>::End()
+{
+ AssertObj(this);
+ iterator ithm(this, m_ihsndLim);
+ return ithm;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add one key and value to the HashMap. Insert potentially invalidates existing iterators
+ for this HashMap. An exception is thrown if there are any errors.
+
+ @param key Reference to the key object. An internal copy is made of this object.
+ @param value Reference to the object associated with the key. An internal copy is
+ made of this object.
+ @param fOverwrite Optional flag (defaults to false) to allow a value already associated
+ with this key to be replaced by this value.
+ @param pihsndOut Optional pointer to an integer for returning the internal index where the
+ key-value pair is stored.
+
+ @exception E_INVALIDARG if fOverwrite is not true and the key already is stored with a value
+ in this HashMap.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ void HashMap<K,T,H,Eq>::Insert(K & key, T & value, bool fOverwrite, int * pihsndOut)
+{
+ AssertObj(this);
+ // Check for initial allocation of memory.
+ if (!m_cBuckets)
+ {
+ int cBuckets = GetPrimeNear(10);
+ m_prgihsndBuckets = (int *)malloc(cBuckets * isizeof(int));
+ if (!m_prgihsndBuckets)
+ ThrowHr(WarnHr(E_OUTOFMEMORY));
+ std::fill_n(m_prgihsndBuckets, cBuckets, -1);
+ m_cBuckets = cBuckets;
+ }
+ if (!m_ihsndMax)
+ {
+ int iMax = 32;
+ m_prghsnd = (HashNode *)malloc(iMax * isizeof(HashNode));
+ if (!m_prghsnd)
+ ThrowHr(WarnHr(E_OUTOFMEMORY));
+ std::fill_n(m_prghsnd, iMax, 0);
+ m_ihsndLim = 0;
+ m_ihsndMax = iMax;
+ m_ihsndFirstFree = FreeListIdx(-1);
+ }
+ // Check whether this key is already used.
+ // If it is, store the value if overwriting is allowed, otherwise return an error value.
+ H hasher;
+ Eq equal;
+ int ihsnd;
+ int nHash = hasher(&key, isizeof(K));
+ int ie = (unsigned)nHash % m_cBuckets;
+ for (ihsnd = m_prgihsndBuckets[ie]; ihsnd != -1; ihsnd = m_prghsnd[ihsnd].GetNext())
+ {
+ if ((nHash == m_prghsnd[ihsnd].GetHash()) &&
+ equal(&key, &m_prghsnd[ihsnd].GetKey(), isizeof(K)))
+ {
+ if (fOverwrite)
+ {
+ m_prghsnd[ihsnd].PutValue(value);
+ if (pihsndOut)
+ *pihsndOut = ihsnd;
+ AssertObj(this);
+ return;
+ }
+ else
+ {
+ ThrowHr(WarnHr(E_INVALIDARG));
+ }
+ }
+ }
+ // Check whether to increase the number of buckets to redistribute the wealth.
+ // Calculate the average depth of hash collection chains.
+ // If greater than or equal to two, increase the number of buckets.
+ int chsndFree = 0;
+ int i;
+ for (i = m_ihsndFirstFree; i != FreeListIdx(-1); i = m_prghsnd[FreeListIdx(i)].GetNext())
+ ++chsndFree;
+ int chsndAvgDepth = (m_ihsndLim - chsndFree) / m_cBuckets;
+ if (chsndAvgDepth > 2)
+ {
+ int cNewBuckets = GetPrimeNear(4 * m_cBuckets);
+ if (cNewBuckets && cNewBuckets > m_cBuckets)
+ {
+ int * pNewBuckets = (int *)realloc(m_prgihsndBuckets, cNewBuckets * isizeof(int));
+ if (pNewBuckets)
+ {
+ std::fill_n(pNewBuckets, cNewBuckets, -1);
+ m_cBuckets = cNewBuckets;
+ m_prgihsndBuckets = pNewBuckets;
+ for (ihsnd = 0; ihsnd < m_ihsndLim; ++ihsnd)
+ {
+ if (m_prghsnd[ihsnd].InUse())
+ {
+ ie = (unsigned)m_prghsnd[ihsnd].GetHash() % m_cBuckets;
+ m_prghsnd[ihsnd].PutNext(m_prgihsndBuckets[ie]);
+ m_prgihsndBuckets[ie] = ihsnd;
+ }
+ }
+ // Recompute the new entry's slot so that it can be stored properly.
+ ie = (unsigned)nHash % m_cBuckets;
+ }
+ }
+ }
+ if (m_ihsndLim < m_ihsndMax)
+ {
+ ihsnd = m_ihsndLim;
+ ++m_ihsndLim;
+ }
+ else if (m_ihsndFirstFree != FreeListIdx(-1))
+ {
+ ihsnd = FreeListIdx(m_ihsndFirstFree);
+ m_ihsndFirstFree = m_prghsnd[ihsnd].GetNext();
+ }
+ else
+ {
+ int iNewMax = (!m_ihsndMax) ? 32 : 2 * m_ihsndMax;
+ HashNode * pNewNodes = (HashNode *)realloc(m_prghsnd, iNewMax * isizeof(HashNode));
+ if (!pNewNodes && iNewMax > 32)
+ {
+ iNewMax = m_ihsndMax + (m_ihsndMax / 2);
+ pNewNodes = (HashNode *)realloc(m_prghsnd, iNewMax * isizeof(HashNode));
+ if (!pNewNodes)
+ ThrowHr(WarnHr(E_OUTOFMEMORY));
+ }
+ m_prghsnd = pNewNodes;
+ m_ihsndMax = iNewMax;
+ Assert(m_ihsndLim < m_ihsndMax);
+ ihsnd = m_ihsndLim;
+ ++m_ihsndLim;
+ }
+ // Call constructor on previously allocated memory.
+ new((void *)&m_prghsnd[ihsnd]) HashNode(key, value, nHash, m_prgihsndBuckets[ie]);
+ m_prgihsndBuckets[ie] = ihsnd;
+ if (pihsndOut)
+ *pihsndOut = ihsnd;
+ AssertObj(this);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Search the HashMap for the given key, and return true if the key is found or false if the
+ key is not found. If the key is found and the given pointer is not NULL, copy the
+ associated value to that memory location.
+
+ @param key Reference to a key object.
+ @param pvalueRet Pointer to an empty object for storing a copy of the value associated with
+ the key, if one exists.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ bool HashMap<K,T,H,Eq>::Retrieve(K & key, T * pvalueRet)
+{
+ AssertObj(this);
+ if (!m_prgihsndBuckets)
+ return false;
+ H hasher;
+ Eq equal;
+ int nHash = hasher(&key, isizeof(K));
+ int ie = (unsigned)nHash % m_cBuckets;
+ int ihsnd;
+ for (ihsnd = m_prgihsndBuckets[ie]; ihsnd != -1; ihsnd = m_prghsnd[ihsnd].GetNext())
+ {
+ if ((nHash == m_prghsnd[ihsnd].GetHash()) &&
+ equal(&key, &m_prghsnd[ihsnd].GetKey(), isizeof(K)))
+ {
+ if (pvalueRet)
+ *pvalueRet = m_prghsnd[ihsnd].GetValue();
+ return true;
+ }
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Remove the element with the given key from the stored HashMap. This potentially
+ invalidates existing iterators for this HashMap. If the key is not found in the
+ HashMap, then nothing is deleted.
+
+ @param key Reference to a key object.
+
+ @return True if the key is found, and something is actually deleted; otherwise, false.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ bool HashMap<K,T,H,Eq>::Delete(K & key)
+{
+ AssertObj(this);
+ if (!m_prgihsndBuckets)
+ return false;
+ H hasher;
+ Eq equal;
+ int nHash = hasher(&key, isizeof(K));
+ int ie = (unsigned)nHash % m_cBuckets;
+ int ihsnd;
+ int ihsndPrev = -1;
+ for (ihsnd = m_prgihsndBuckets[ie]; ihsnd != -1; ihsnd = m_prghsnd[ihsnd].GetNext())
+ {
+ if ((nHash == m_prghsnd[ihsnd].GetHash()) &&
+ equal(&key, &m_prghsnd[ihsnd].GetKey(), isizeof(K)))
+ {
+ if (ihsndPrev == -1)
+ m_prgihsndBuckets[ie] = m_prghsnd[ihsnd].GetNext();
+ else
+ m_prghsnd[ihsndPrev].PutNext(m_prghsnd[ihsnd].GetNext());
+ m_prghsnd[ihsnd].~HashNode(); // Ensure member destructors are called.
+ memset(&m_prghsnd[ihsnd], 0, isizeof(HashNode));
+ m_prghsnd[ihsnd].PutNext(m_ihsndFirstFree);
+ m_ihsndFirstFree = FreeListIdx(ihsnd);
+ AssertObj(this);
+ return true;
+ }
+ ihsndPrev = ihsnd;
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Free all the memory used by the HashMap. When done, only the minimum amount of
+ bookkeeping memory is still taking up space, and any internal pointers all been set
+ to NULL. The appropriate destructor is called for all key and value objects stored
+ in the HashMap before the memory space is freed.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ void HashMap<K,T,H,Eq>::Clear()
+{
+ AssertObj(this);
+ if (!m_prgihsndBuckets)
+ return;
+ int ihsnd;
+ for (ihsnd = 0; ihsnd < m_ihsndLim; ++ihsnd)
+ {
+ if (m_prghsnd[ihsnd].InUse())
+ m_prghsnd[ihsnd].~HashNode(); // Ensure member destructors are called.
+ }
+ free(m_prgihsndBuckets);
+ free(m_prghsnd);
+ m_prgihsndBuckets = NULL;
+ m_cBuckets = 0;
+ m_prghsnd = NULL;
+ m_ihsndLim = 0;
+ m_ihsndMax = 0;
+ m_ihsndFirstFree = FreeListIdx(-1);
+ AssertObj(this);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the content of one HashMap to another. An exception is thrown if there are any errors.
+
+ @param hmKT Reference to the other HashMap.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ void HashMap<K,T,H,Eq>::CopyTo(HashMap<K,T,H,Eq> & hmKT)
+{
+ AssertObj(this);
+ AssertObj(&hmKT);
+ hmKT.Clear();
+ iterator itmm;
+ for (itmm = Begin(); itmm != End(); ++itmm)
+ hmKT.Insert(itmm->GetKey(), itmm->GetValue());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the content of one HashMap to another. An exception is thrown if there are any errors.
+
+ @param phmKT Pointer to the other HashMap.
+
+ @exception E_POINTER if phmKT is NULL.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ void HashMap<K,T,H,Eq>::CopyTo(HashMap<K,T,H,Eq> * phmKT)
+{
+ if (!phmKT)
+ ThrowHr(WarnHr(E_POINTER));
+ CopyTo(*phmKT);
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the given key is found in the HashMap, return true, and if the provided index pointer
+ is not NULL, also store the internal index value in the indicated memory location.
+ If the given key is NOT found in the HashMap, return false and ignore the provided index
+ pointer.
+
+ @param key Reference to a key object.
+ @param pihsndRet Pointer to an integer for returning the internal index where the
+ key-value pair is stored.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ bool HashMap<K,T,H,Eq>::GetIndex(K & key, int * pihsndRet)
+{
+ AssertObj(this);
+ if (!m_prgihsndBuckets)
+ return false;
+ H hasher;
+ Eq equal;
+ int nHash = hasher(&key, isizeof(K));
+ int ie = (unsigned)nHash % m_cBuckets;
+ int ihsnd;
+ for (ihsnd = m_prgihsndBuckets[ie]; ihsnd != -1; ihsnd = m_prghsnd[ihsnd].GetNext())
+ {
+ if ((nHash == m_prghsnd[ihsnd].GetHash()) &&
+ equal(&key, &m_prghsnd[ihsnd].GetKey(), isizeof(K)))
+ {
+ if (pihsndRet)
+ *pihsndRet = ihsnd;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the given internal HashMap index is valid, return true, and if the provided pointer to a
+ key object is not NULL, also copy the indexed key to the indicated memory location.
+ If the given internal index is NOT valid, return false, and ignore the provided key
+ object pointer.
+
+ @param ihsnd Internal index value returned earlier by GetIndex or Insert.
+ @param pkeyRet Pointer to an empty key object for storing a copy of the key found at the
+ indexed location.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ bool HashMap<K,T,H,Eq>::IndexKey(int ihsnd, K * pkeyRet)
+{
+ AssertObj(this);
+ if ((ihsnd < 0) || (ihsnd >= m_ihsndLim))
+ return false;
+ if (m_prghsnd[ihsnd].InUse())
+ {
+ if (pkeyRet)
+ *pkeyRet = m_prghsnd[ihsnd].GetKey();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the given internal HashMap index is valid, return true, and if the provided pointer to an
+ object is not NULL, also copy the indexed value to the indicated memory location.
+ If the given internal index is NOT valid, return false, and ignore the provided
+ object pointer.
+
+ @param ihsnd Internal index value returned earlier by GetIndex or Insert.
+ @param pvalueRet Pointer to an empty object for storing a copy of the value found at the
+ indexed location.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ bool HashMap<K,T,H,Eq>::IndexValue(int ihsnd, T * pvalueRet)
+{
+ AssertObj(this);
+ if (ihsnd < 0 || ihsnd >= m_ihsndLim)
+ return false;
+ if (m_prghsnd[ihsnd].InUse())
+ {
+ if (pvalueRet)
+ *pvalueRet = m_prghsnd[ihsnd].GetValue();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of items (key-value pairs) stored in the HashMap.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ int HashMap<K,T,H,Eq>::Size()
+{
+ AssertObj(this);
+ if (!m_prgihsndBuckets)
+ return 0;
+ int chsndFree = 0;
+ int ihsnd;
+ for (ihsnd = m_ihsndFirstFree;
+ ihsnd != FreeListIdx(-1);
+ ihsnd = m_prghsnd[FreeListIdx(ihsnd)].GetNext())
+ {
+ ++chsndFree;
+ }
+ return m_ihsndLim - chsndFree;
+}
+
+//:Ignore
+#ifdef DEBUG
+/*----------------------------------------------------------------------------------------------
+ Return the number of buckets (hash slots) currently allocated for the hash map. This is
+ useful only for debugging the hash map mechanism itself.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ int HashMap<K,T,H,Eq>::_BucketCount()
+{
+ AssertObj(this);
+ return m_cBuckets;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of buckets (hash slots) that do not point to a list of HashNode objects.
+ This is useful only for debugging the hash map mechanism itself.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ int HashMap<K,T,H,Eq>::_EmptyBuckets()
+{
+ AssertObj(this);
+ int ceUnused = 0;
+ int ie;
+ for (ie = 0; ie < m_cBuckets; ++ie)
+ {
+ if (m_prgihsndBuckets[ie] == -1)
+ ++ceUnused;
+ }
+ return ceUnused;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of buckets (hash slots) that currently point to a list of HashNode
+ objects in the hash map. This is useful only for debugging the hash map mechanism itself.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ int HashMap<K,T,H,Eq>::_BucketsUsed()
+{
+ AssertObj(this);
+ int ceUsed = 0;
+ int ie;
+ for (ie = 0; ie < m_cBuckets; ++ie)
+ {
+ if (m_prgihsndBuckets[ie] != -1)
+ ++ceUsed;
+ }
+ return ceUsed;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the length of the longest list of HashNode objects stored in any bucket (hash slot)
+ of the hash map. This is useful only for debugging the hash map mechanism itself.
+----------------------------------------------------------------------------------------------*/
+template<class K, class T, class H, class Eq>
+ int HashMap<K,T,H,Eq>::_FullestBucket()
+{
+ AssertObj(this);
+ int chsndMax = 0;
+ int chsnd;
+ int ie;
+ int ihsnd;
+ for (ie = 0; ie < m_cBuckets; ++ie)
+ {
+ chsnd = 0;
+ for (ihsnd = m_prgihsndBuckets[ie]; ihsnd != -1; ihsnd = m_prghsnd[ihsnd].GetNext())
+ ++chsnd;
+ if (chsndMax < chsnd)
+ chsndMax = chsnd;
+ }
+ return chsndMax;
+}
+#endif
+//:End Ignore
+
+
+
+// Local Variables:
+// mode:C++
+// c-file-style:"cellar"
+// tab-width:4
+// End:
+
+#endif /*HASHMAP_I_C_INCLUDED*/
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/Makefile.am b/Build/source/libs/graphite/engine-2.3.1/src/generic/Makefile.am
new file mode 100644
index 00000000000..ec60b09be3a
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/Makefile.am
@@ -0,0 +1,8 @@
+genericdir = $(top_srcdir)/src/generic
+
+libgraphite_la_SOURCES += $(genericdir)/Debug.cpp
+libgraphite_la_SOURCES += $(genericdir)/Util.cpp
+
+EXTRA_DIST += $(genericdir)/*.h
+EXTRA_DIST += $(genericdir)/BinTree_i.cpp
+EXTRA_DIST += $(genericdir)/HashMap_i.cpp
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/generic/Util.cpp b/Build/source/libs/graphite/engine-2.3.1/src/generic/Util.cpp
new file mode 100644
index 00000000000..aabd6563d3e
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/generic/Util.cpp
@@ -0,0 +1,261 @@
+
+#include "GrCommon.h"
+#include "GrDebug.h"
+
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ Swap two blocks of size cb starting at pv1 and pv2. Doesn't handle overlapping blocks.
+----------------------------------------------------------------------------------------------*/
+void SwapBytes(void * pv1, void * pv2, int cb)
+{
+ Assert((byte *)pv1 + cb <= (byte *)pv2 || (byte *)pv2 + cb <= (byte *)pv1);
+ AssertPtrSize(pv1, cb);
+ AssertPtrSize(pv2, cb);
+
+#ifdef NO_ASM
+
+ byte *pb1 = (byte *)pv1;
+ byte *pb2 = (byte *)pv2;
+ byte b;
+
+ while (--cb >= 0)
+ {
+ b = *pb1;
+ *pb1++ = *pb2;
+ *pb2++ = b;
+ }
+
+#else // !NO_ASM
+
+ __asm
+ {
+ // edi -> memory to swap, first pointer
+ // esi -> memory to swap, second pointer
+
+ mov edi,pv1
+ mov esi,pv2
+
+ mov ecx,cb
+ shr ecx,2
+ jz LBytes
+
+LIntLoop:
+ mov eax,[edi]
+ mov ebx,[esi]
+ mov [edi],ebx
+ mov [esi],eax
+
+ add edi,4
+ add esi,4
+ dec ecx
+ jnz LIntLoop;
+
+LBytes:
+ mov ecx,cb
+ and ecx,3
+ jz LDone
+
+LByteLoop:
+ mov al,[edi]
+ mov bl,[esi]
+ mov [edi],bl
+ mov [esi],al
+ inc edi
+ inc esi
+ dec ecx
+ jnz LByteLoop
+
+LDone:
+ }
+
+#endif //!NO_ASM
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fills a block of memory with the given short value.
+----------------------------------------------------------------------------------------------*/
+void FillShorts(void * pv, short sn, int csn)
+{
+ AssertPtrSize(pv, csn * isizeof(short));
+
+#ifdef NO_ASM
+
+ short * psn = (short *)pv;
+ short * psnLim = psn + csn;
+
+ while (psn < psnLim)
+ *psn++ = sn;
+
+#else // !NO_ASM
+
+ __asm
+ {
+ // Setup the registers for using REP STOS instruction to set memory.
+ // NOTE: Alignment does not effect the speed of STOS.
+ //
+ // edi -> memory to set
+ // eax = value to store in destination
+ // direction flag is clear for auto-increment
+
+ mov edi,pv
+ mov ax,sn
+ mov ecx,csn
+
+ mov edx,ecx
+ and edx,1
+ jz LInts
+
+ // set 1 short
+ stosw
+
+LInts:
+ shr ecx,1
+ jz LDone
+
+ mov ebx,eax
+ shl eax,16
+ mov ax,bx
+
+ rep stosd
+LDone:
+ }
+
+#endif //!NO_ASM
+}
+
+/***********************************************************************************************
+ Integer utilities.
+***********************************************************************************************/
+
+/*
+ * table of powers of 2, and largest prime smaller than each power of 2
+ * n 2**n prime diff
+ * --- ---------- ---------- ----
+ * 2: 4 3 ( -1)
+ * 3: 8 7 ( -1)
+ * 4: 16 13 ( -3)
+ * 5: 32 31 ( -1)
+ * 6: 64 61 ( -3)
+ * 7: 128 127 ( -1)
+ * 8: 256 251 ( -5)
+ * 9: 512 509 ( -3)
+ * 10: 1024 1021 ( -3)
+ * 11: 2048 2039 ( -9)
+ * 12: 4096 4093 ( -3)
+ * 13: 8192 8191 ( -1)
+ * 14: 16384 16381 ( -3)
+ * 15: 32768 32749 (-19)
+ * 16: 65536 65521 (-15)
+ * 17: 131072 131071 ( -1)
+ * 18: 262144 262139 ( -5)
+ * 19: 524288 524287 ( -1)
+ * 20: 1048576 1048573 ( -3)
+ * 21: 2097152 2097143 ( -9)
+ * 22: 4194304 4194301 ( -3)
+ * 23: 8388608 8388593 (-15)
+ * 24: 16777216 16777213 ( -3)
+ * 25: 33554432 33554393 (-39)
+ * 26: 67108864 67108859 ( -5)
+ * 27: 134217728 134217689 (-39)
+ * 28: 268435456 268435399 (-57)
+ * 29: 536870912 536870909 ( -3)
+ * 30: 1073741824 1073741789 (-35)
+ * 31: 2147483648 2147483647 ( -1)
+ * 32: 4294967296 4294967291 ( -5)
+ */
+const static unsigned int g_rguPrimes[] = {
+ 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071,
+ 262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
+ 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291U
+};
+
+
+/*----------------------------------------------------------------------------------------------
+ Returns the prime in g_rguPrimes that is closest to u.
+----------------------------------------------------------------------------------------------*/
+unsigned int GetPrimeNear(unsigned int u)
+{
+ int cu = isizeof(g_rguPrimes) / isizeof(unsigned int);
+ int iuMin;
+ int iuLim;
+ int iu;
+
+ for (iuMin = 0, iuLim = cu; iuMin < iuLim; )
+ {
+ iu = (iuMin + iuLim) / 2;
+ if (u > g_rguPrimes[iu])
+ iuMin = iu + 1;
+ else
+ iuLim = iu;
+ }
+ Assert(iuMin == cu || iuMin < cu && u <= g_rguPrimes[iuMin]);
+ Assert(iuMin == 0 || iuMin > 0 && u > g_rguPrimes[iuMin - 1]);
+
+ if (!iuMin)
+ return g_rguPrimes[0];
+ if (iuMin == cu)
+ return g_rguPrimes[cu - 1];
+ if (g_rguPrimes[iuMin] - u < u - g_rguPrimes[iuMin - 1])
+ return g_rguPrimes[iuMin];
+ return g_rguPrimes[iuMin - 1];
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Returns the prime in g_rguPrimes that is larger than u or is the largest in the list.
+----------------------------------------------------------------------------------------------*/
+unsigned int GetLargerPrime(unsigned int u)
+{
+ int cu = isizeof(g_rguPrimes) / isizeof(unsigned int);
+ int iuMin;
+ int iuLim;
+ int iu;
+
+ for (iuMin = 0, iuLim = cu; iuMin < iuLim; )
+ {
+ iu = (iuMin + iuLim) / 2;
+ if (u >= g_rguPrimes[iu])
+ iuMin = iu + 1;
+ else
+ iuLim = iu;
+ }
+ Assert(iuMin == cu || iuMin < cu && u < g_rguPrimes[iuMin]);
+ Assert(iuMin == 0 || iuMin > 0 && u >= g_rguPrimes[iuMin - 1]);
+
+ if (iuMin == cu)
+ return g_rguPrimes[cu - 1];
+ return g_rguPrimes[iuMin];
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Returns the prime in g_rguPrimes that is smaller than u or is the smallest in the list.
+----------------------------------------------------------------------------------------------*/
+unsigned int GetSmallerPrime(unsigned int u)
+{
+ int cu = isizeof(g_rguPrimes) / isizeof(unsigned int);
+ int iuMin;
+ int iuLim;
+ int iu;
+
+ for (iuMin = 0, iuLim = cu; iuMin < iuLim; )
+ {
+ iu = (iuMin + iuLim) / 2;
+ if (u > g_rguPrimes[iu])
+ iuMin = iu + 1;
+ else
+ iuLim = iu;
+ }
+ Assert(iuMin == cu || iuMin < cu && u <= g_rguPrimes[iuMin]);
+ Assert(iuMin == 0 || iuMin > 0 && u > g_rguPrimes[iuMin - 1]);
+
+ if (!iuMin)
+ return g_rguPrimes[0];
+ return g_rguPrimes[iuMin - 1];
+}
+
+}
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/painter/Makefile.am b/Build/source/libs/graphite/engine-2.3.1/src/painter/Makefile.am
new file mode 100644
index 00000000000..497d31bd018
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/painter/Makefile.am
@@ -0,0 +1,5 @@
+painterdir = $(top_srcdir)/src/painter
+
+libgraphite_la_SOURCES += $(painterdir)/SegmentPainter.cpp
+
+#EXTRA_DIST += $(painterdir)/*.h
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/painter/SegmentPainter.cpp b/Build/source/libs/graphite/engine-2.3.1/src/painter/SegmentPainter.cpp
new file mode 100644
index 00000000000..149366eb4b3
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/painter/SegmentPainter.cpp
@@ -0,0 +1,3004 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: SegmentPainter.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the object that handles drawing, mouse clicks, and other UI-related behavior
+ for a Graphite segment.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+#include <math.h>
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+namespace
+{
+
+static bool g_fDrawing;
+
+} // namespace
+
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Constructors.
+----------------------------------------------------------------------------------------------*/
+//SegmentPainter::SegmentPainter(Segment * pseg)
+//{
+// m_pseg = pseg;
+//
+// m_xsOrigin = 0;
+// m_ysOrigin = 0;
+// m_xdPosition = 0;
+// m_ydPosition = 0;
+// m_xFactor = 1.0;
+// m_yFactor = 1.0;
+//}
+
+SegmentPainter::SegmentPainter(Segment * pseg, float xsOrigin, float ysOrigin)
+{
+ m_pseg = pseg;
+
+ m_xsOrigin = xsOrigin;
+ m_ysOrigin = ysOrigin;
+ m_xdPosition = m_xsOrigin;
+ m_ydPosition = m_ysOrigin;
+ m_xFactor = 1.0;
+ m_yFactor = 1.0;
+
+ //m_xsOriginInt = GrEngine::RoundFloat(xsOrigin);
+ //m_xdPositionInt = m_xsOriginInt;
+ //m_xFactor64 = 64;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructor.
+----------------------------------------------------------------------------------------------*/
+SegmentPainter::~SegmentPainter()
+{
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialization.
+
+ The correspondence with the old rectangle approach is:
+ m_xsOrigin = sourceRect.left;
+ m_ysOrigin = sourceRect.top;
+ m_xdPosition = destRect.left;
+ m_ydPosition = destRect.top;
+
+ m_xFactor = (destRect.right - destRect.left) / (sourceRect.right - sourceRect.left);
+ m_yFactor = (destRect.top - destRect.bottom) / (sourceRect.top - sourceRect.bottom);
+
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::setOrigin(float xsOrigin, float ysOrigin)
+{
+ m_xsOrigin = xsOrigin;
+ m_ysOrigin = ysOrigin;
+
+ //m_xsOriginInt = GrEngine::RoundFloat(xsOrigin);
+}
+
+void SegmentPainter::setPosition(float xdPosition, float ydPosition)
+{
+ m_xdPosition = xdPosition;
+ m_ydPosition = ydPosition;
+
+ //m_xdPositionInt = GrEngine::RoundFloat(xdPosition);
+}
+
+void SegmentPainter::setScalingFactors(float xFactor, float yFactor)
+{
+ m_xFactor = xFactor;
+ m_yFactor = yFactor;
+
+ //int temp = GrEngine::RoundFloat(xFactor);
+ //m_xFactor64 = GrEngine::RoundFloat(xFactor * 64);
+}
+
+
+//:>********************************************************************************************
+//:> SegmentPainter interface methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Draw the text of the segment at the specified point in the graphics context.
+ This method must be implemented by a concrete subclass for painters that really need
+ to paint.
+----------------------------------------------------------------------------------------------*/
+//void SegmentPainter::paint()
+//{
+// Assert(false);
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Indicate if the character position is a valid place for an insertion point.
+
+ @oaram ich - position to test
+ @param pipvr - answer: kipvrOK = IP here is valid;
+ kipvrBad = IP here no good;
+ kipvrUnknown = this seg can't decide, ask the next
+----------------------------------------------------------------------------------------------*/
+LgIpValidResult SegmentPainter::isValidInsertionPoint(int ichw)
+{
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ int ichwSegOffset = ichw - m_pseg->m_ichwMin;
+ if (ichwSegOffset < m_pseg->m_ichwAssocsMin || ichwSegOffset >= m_pseg->m_ichwAssocsLim)
+ {
+ // If we're pointing at a hard line break character (Unicode 2028), then we know
+ // that it's a good insertion point in spite of missing the other conditions.
+ utf16 ch;
+ m_pseg->m_pgts->fetch(ichw, 1, &ch);
+ if (ch != knLineSep)
+ return kipvrUnknown; // Definitely in a different segment of the paragraph.
+ return kipvrOK;
+ }
+
+ int isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ if (isloutLig != kNegInfinity)
+ {
+ // Ligature.
+ int isloutLigAfter = m_pseg->m_prgisloutLigature[ichwSegOffset - 1 - m_pseg->m_ichwAssocsMin];
+ if (isloutLig == isloutLigAfter)
+ {
+ int icompBefore = m_pseg->m_prgiComponent[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ int icompAfter = m_pseg->m_prgiComponent[ichwSegOffset - 1 - m_pseg->m_ichwAssocsMin];
+ if (icompBefore == icompAfter)
+ // If inserting before this character yields the same visible component
+ // as inserting after the previous, then this character is invisible, or has
+ // been merged with the previous, and it doesn't make sense to put an insertion
+ // point here.
+ return kipvrBad;
+ }
+ return kipvrOK;
+ }
+
+ // TODO: do we need to test ALL the associated glyphs? Here we just test the first.
+
+ LgIpValidResult ipvrRet;
+
+ int isloutBefore = m_pseg->UnderlyingToLogicalSurface(ichw, true); // leading edge
+ int isloutAfter = m_pseg->UnderlyingToLogicalSurface(ichw - 1, false); // trailing edge of previous
+ int isloutTest = m_pseg->UnderlyingToLogicalInThisSeg(ichw);
+ if (isloutBefore == isloutAfter)
+ // If inserting before this character yields the same visible glyph as
+ // inserting after the previous, then this character is invisible, or has
+ // been merged with the previous, and it doesn't make sense to put an insertion
+ // point here.
+ ipvrRet = kipvrBad;
+ else if (isloutTest == kNegInfinity || isloutTest == kPosInfinity)
+ ipvrRet = kipvrBad; // can't figure it out
+ else if (!m_pseg->OutputSlot(isloutTest)->InsertBefore())
+ ipvrRet = kipvrBad;
+ else if (m_pseg->SameSurfaceGlyphs(ichw - 1, ichw))
+ // The insertion point would be between two characters that map to the same
+ // set of glyphs. Not a good place.
+ ipvrRet = kipvrBad;
+ else
+ ipvrRet = kipvrOK;
+
+ return ipvrRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Answer whether the logical and physical boundaries of the string coincide.
+ This method is called by the application to handle writing system boundaries, and by
+ other segments in a writing-system chain to handle line-breaks.
+
+ @param fBoundaryEnd - asking about the logical end boundary?
+ @param fBoundaryRight - asking about the physical right boundary?
+ @param pfResult - return value
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::doBoundariesCoincide(bool fBoundaryEnd, bool fBoundaryRight)
+{
+ float xsBefore, ysBeforeTop, ysBeforeBottom;
+ float xsAfter, ysAfterTop, ysAfterBottom;
+ bool fRtlBefore, fRtlAfter;
+
+ if (m_pseg->m_cginf == 0)
+ {
+ // Empty segment.
+ return true;
+ }
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ if (fBoundaryEnd)
+ {
+ CalcIP(m_pseg->m_ichwMin + m_pseg->m_dichwLim, true,
+ &xsBefore, &ysBeforeTop, &ysBeforeBottom, &fRtlBefore);
+ CalcIP(m_pseg->m_ichwMin + m_pseg->m_dichwLim, false,
+ &xsAfter, &ysAfterTop, &ysAfterBottom, &fRtlAfter);
+ }
+ else
+ {
+ CalcIP(m_pseg->m_ichwMin, true,
+ &xsBefore, &ysBeforeTop, &ysBeforeBottom, &fRtlBefore);
+ CalcIP(m_pseg->m_ichwMin, false,
+ &xsAfter, &ysAfterTop, &ysAfterBottom, &fRtlAfter);
+ }
+
+ // We allow for rounding errors which might cause differences between the expected
+ // and the actual values, hence the test for a difference of <= 1.
+ bool fRet;
+ if (fBoundaryRight)
+ {
+ // right edge
+ if (fBoundaryEnd) // logical end
+ fRet = (!fRtlAfter && fabsf(xsAfter - (m_pseg->m_dxsTotalWidth + m_pseg->m_dxsStretch)) <= 1);
+ else // logical start
+ fRet = (fRtlBefore && fabsf(xsBefore - (m_pseg->m_dxsTotalWidth + m_pseg->m_dxsStretch)) <= 1);
+ }
+ else
+ {
+ // left edge
+ if (fBoundaryEnd) // logical end
+ fRet = (fRtlAfter && fabsf(xsAfter) <= 1);
+ else // logical start
+ fRet = (!fRtlBefore && fabsf(xsBefore) <= 1);
+ }
+
+ return fRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Draw an insertion point at an appropriate position.
+
+ @param twx, twy - same origin used to Draw segment
+ @param ich - character position; must be valid
+ @param fAssocPrev - associated with previous character?
+ @param bOn - turning on or off? Caller should alternate, first turning on
+ (ignored in this implementation)
+ @param dm - draw mode:
+ kdmNormal = draw complete insertion pt (I-beam or split cursor);
+ kdmPrimary = only draw primary half of split cursor;
+ kdmSecondary = only draw secondary half of split cursor
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::drawInsertionPoint(int ichwIP, bool fAssocPrev,
+ bool bOn, bool fForceSplit) // LgIPDrawMode dm)
+{
+ if (g_fDrawing)
+ return;
+
+ g_fDrawing = true;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ CalcOrDrawInsertionPoint(ichwIP,
+ fAssocPrev, bOn, fForceSplit,
+ NULL, NULL); // passing NULLs here means we want to draw
+
+ //RestoreFont(pgg);
+
+ g_fDrawing = false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in bounding rectangles for the (possibly 2-part) IP, in destination device coordinates.
+ Return flags indicating which of the 2 parts where rendered here.
+
+ @param rs,rd - source/destination coordinates, for scaling
+ @param ichwIP - insertion point
+ @param fAssocPrev - is the IP "leaning" backward?
+ @param dm - draw mode:
+ kdmNormal = draw complete insertion pt (I-beam or split cursor);
+ kdmPrimary = only draw primary half of split cursor;
+ kdmSecondary = only draw secondary half of split cursor
+ @param prdPrimary - return location of primary selection, in dest coords
+ @param prdSecondary - return location of secondary selection, in dest coords
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::positionsOfIP(
+ int ichwIP, bool fAssocPrev, bool fForceSplit,
+ Rect * prdPrimary, Rect * prdSecondary)
+{
+ ChkGrArgPtr(prdPrimary);
+ ChkGrArgPtr(prdSecondary);
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ CalcOrDrawInsertionPoint(ichwIP, fAssocPrev, true, fForceSplit,
+ prdPrimary, prdSecondary);
+
+ //RestoreFont(pgg);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Highlight a range of text.
+
+ @param ichwAnchor/End - selected range
+ @param ydLineTop/Bottom - top/bottom of area to highlight if whole line height;
+ includes half of inter-line spacing.
+ @param bOn - true if we are turning on (ignored in this implementation)
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::drawSelectionRange(int ichwAnchor, int ichwEnd,
+ float ydLineTop, float ydLineBottom, bool bOn)
+{
+ if (g_fDrawing)
+ return true;
+
+ g_fDrawing = true;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ float xsSegLeft = 0;
+ float ysSegTop = 0;
+
+ float xdSegRight = ScaleXToDest(m_pseg->m_dxsTotalWidth);
+
+ int ichwMinSel = min(ichwAnchor, ichwEnd);
+ int ichwLimSel = max(ichwAnchor, ichwEnd);
+
+ int ichwMinSeg = max(ichwMinSel, m_pseg->m_ichwMin + m_pseg->m_ichwAssocsMin);
+ int ichwLimSeg = min(ichwLimSel, m_pseg->m_ichwMin + m_pseg->m_ichwAssocsLim);
+
+ std::vector<Rect> vrs;
+ std::vector<bool> vfEntireHt;
+
+ bool * prgfAllCompsSelected = new bool[m_pseg->m_dichwLim];
+ std::fill_n(prgfAllCompsSelected, m_pseg->m_dichwLim, false);
+ CalcPartialLigatures(prgfAllCompsSelected, ichwMinSeg, ichwLimSeg,
+ ichwMinSel, ichwLimSel);
+
+ // Array to keep track of which glyphs were highlighted.
+ int cginf = m_pseg->m_cginf;
+ bool * prgfHighlighted = new bool[cginf];
+ std::fill_n(prgfHighlighted, cginf, false);
+
+ for (int ichwLp = ichwMinSeg; ichwLp < ichwLimSeg; ichwLp++)
+ {
+ CalcHighlightRect(ichwLp, vrs, vfEntireHt,
+ !prgfAllCompsSelected[ichwLp - m_pseg->m_ichwMin], prgfHighlighted, false);
+ }
+
+ // If all the glyphs of a given cluster were highlighted, highlight the whole cluster
+ // as a unit.
+ for (int islout = 0; islout < m_pseg->m_cslout; islout++)
+ {
+ CalcCompleteCluster(islout, vrs, vfEntireHt, prgfHighlighted);
+ }
+
+ // Convert to destination coordinates; also extend full-line rectangles to the top
+ // and bottom of the line height.
+ std::vector<Rect> vrd;
+ for (size_t irs = 0; irs < vrs.size(); irs++)
+ {
+ Rect rsTmp = vrs[irs];
+ Rect rdTmp;
+ if (vfEntireHt[irs])
+ {
+ rdTmp.top = ydLineTop;
+ rdTmp.bottom = ydLineBottom;
+ }
+ else
+ {
+ float ydTmp = ScaleYToDest(rsTmp.top + ysSegTop);
+ rdTmp.top = min(ydLineBottom, max(ydLineTop, ydTmp));
+ ydTmp = ScaleYToDest(rsTmp.bottom + ysSegTop);
+ rdTmp.bottom = max(ydLineTop, min(ydLineBottom, ydTmp));
+ }
+ float xdTmp = ScaleXToDest(rsTmp.left + xsSegLeft);
+ rdTmp.left = min(xdSegRight, max(float(0), xdTmp));
+ xdTmp = ScaleXToDest(rsTmp.right + xsSegLeft);
+ rdTmp.right = max(float(0), min(xdSegRight, xdTmp));
+ if (rdTmp.left > rdTmp.right)
+ {
+ // I think this can happen due to rounding errors.
+ float tmp = rdTmp.left;
+ rdTmp.left = rdTmp.right;
+ rdTmp.right = tmp;
+ }
+ vrd.push_back(rdTmp);
+ }
+
+ // Create a list of rectangles with no overlaps, so the selection draws cleanly.
+ std::vector<Rect> vrdNoOverlaps;
+ size_t irect;
+ for (irect = 0; irect < vrd.size(); irect++)
+ AddRectWithoutOverlaps(vrdNoOverlaps, vrd[irect]);
+
+ AssertNoOverlaps(vrdNoOverlaps);
+
+ // Draw the highlight.
+ for (irect = 0; irect < vrdNoOverlaps.size(); irect++)
+ {
+ Rect rdTmp = vrdNoOverlaps[irect];
+ InvertRect(rdTmp.left, rdTmp.top, rdTmp.right, rdTmp.bottom);
+ }
+
+ delete[] prgfAllCompsSelected;
+ delete[] prgfHighlighted;
+
+ //RestoreFont(pgg);
+
+ g_fDrawing = false;
+
+ return (vrdNoOverlaps.size() > 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get a bounding rectangle that will contain the area highlighted by this segment
+ when drawing the specified range.
+
+ @param ichwAnchor/End - selected range
+ @param ydLineTop/Bottom - top/bottom of area to highlight if whole line height;
+ includes half of inter-line spacing.
+ @param prdBounds - return location of range
+ @return - true if the return rectange has a meaningful value
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::positionsOfRange(int ichwAnchor, int ichwEnd,
+ float ydLineTop, float ydLineBottom, Rect * prdBounds)
+{
+ ChkGrArgPtr(prdBounds);
+
+ std::vector<Rect> vrs;
+ std::vector<bool> vfEntireHt;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ int ichwMin = min(ichwAnchor, ichwEnd);
+ int ichwLim = max(ichwAnchor, ichwEnd);
+
+ for (int ichwLp = ichwMin; ichwLp < ichwLim; ichwLp++)
+ {
+ CalcHighlightRect(ichwLp, vrs, vfEntireHt, true, NULL, false);
+ }
+
+ if (vrs.size() == 0)
+ {
+ return false;
+ }
+
+ Rect * prsBounds = &(vrs[0]);
+ for (size_t irect = 1; irect < vrs.size(); irect++)
+ {
+ Rect * prs = &(vrs[irect]);
+ prsBounds->left = min(prsBounds->left, prs->left);
+ prsBounds->right = max(prsBounds->right, prs->right);
+ }
+
+ prdBounds->top = ydLineTop;
+ prdBounds->bottom = ydLineBottom;
+ prdBounds->left = ScaleXToDest(prsBounds->left);
+ prdBounds->right = ScaleXToDest(prsBounds->right);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert a click position to a character position.
+
+ @param zptdClickPosition - relative to the segment draw origin
+ @param pichw - return character clicked before
+ @param pfAssocPrev - return true if they clicked on the trailing half of
+ the previous char, false if click was on the
+ leading half of the following
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::pointToChar(Point zptdClickPosition, int * pichw, bool * pfAssocPrev)
+{
+ ChkGrOutPtr(pichw);
+ ChkGrOutPtr(pfAssocPrev);
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ bool fRtl = m_pseg->rightToLeft();
+
+ if (m_pseg->m_dysAscent < 0 || m_pseg->m_dxsWidth < 0)
+ m_pseg->ComputeDimensions();
+
+ if (m_pseg->m_dichwLim == 0 || m_pseg->m_cginf == 0)
+ {
+ *pichw = m_pseg->m_ichwMin;
+ *pfAssocPrev = false;
+ //RestoreFont(pgg);
+ return;
+ }
+
+ float xsClick = ScaleXToSource(zptdClickPosition.x);
+ float ysClick = ScaleYToSource(zptdClickPosition.y);
+ ysClick = m_pseg->m_dysAscent - ysClick; // make relative to common base line
+
+ float xsTry = xsClick;
+ float ysTry = ysClick;
+
+ float xysInc = 1.0;
+ //res = pgg->LogUnitsFromXPixels(1, &xysInc);
+ //if (ResultFailed(res)) xysInc = 20;
+ int cTries = 1;
+ int nAdjustDir = 0;
+
+ while (true)
+ {
+ float xsGlyphOffset;
+ float xsGlyphWidth;
+ int iginfLoc = PointToCharAux(xsTry, ysTry, &xsGlyphOffset, &xsGlyphWidth);
+
+ bool fClickedAfter;
+ int ichwCharClicked;
+ if (xsTry < m_pseg->m_prgginf[m_pseg->LeftMostGlyph()].bb().left)
+ {
+ fClickedAfter = fRtl;
+ ichwCharClicked = (fClickedAfter) ?
+ m_pseg->m_ichwMin + m_pseg->m_ichwAssocsLim - 1 :
+ m_pseg->m_ichwMin + m_pseg->m_ichwAssocsMin;
+ }
+ else if (xsTry > m_pseg->m_prgginf[m_pseg->RightMostGlyph()].bb().right)
+ {
+ fClickedAfter = !fRtl;
+ ichwCharClicked = (fClickedAfter) ?
+ m_pseg->m_ichwMin + m_pseg->m_ichwAssocsLim - 1 :
+ m_pseg->m_ichwMin + m_pseg->m_ichwAssocsMin;
+ }
+ else
+ {
+ ichwCharClicked = m_pseg->PhysicalSurfaceToUnderlying(iginfLoc,
+ xsTry - xsGlyphOffset, m_pseg->m_dysAscent - ysClick,
+ xsGlyphWidth, m_pseg->m_dysHeight, &fClickedAfter); // handles ligature components
+ }
+
+ if (fClickedAfter)
+ {
+ *pichw = ichwCharClicked + 1;
+ while (!GrCharStream::AtUnicodeCharBoundary(m_pseg->GetString(), *pichw))
+ *pichw = *pichw + 1;
+ *pfAssocPrev = true;
+ }
+ else
+ {
+ *pichw = ichwCharClicked;
+ *pfAssocPrev = false;
+ }
+
+ if (*pichw < m_pseg->m_ichwMin + m_pseg->m_ichwAssocsMin)
+ {
+ //RestoreFont(pgg);
+ return;
+ }
+ else if (*pichw >= m_pseg->m_ichwMin + m_pseg->m_ichwAssocsLim)
+ {
+ //RestoreFont(pgg);
+ return;
+ }
+
+ //int islout = UnderlyingToLogicalInThisSeg(ichwBase, ichwCharClicked);
+ int isloutBefore = m_pseg->UnderlyingToLogicalInThisSeg(*pichw);
+ if (isloutBefore == kNegInfinity || isloutBefore == kPosInfinity)
+ { }
+ else
+ {
+ Assert(0 <= isloutBefore && isloutBefore < m_pseg->m_cslout);
+ if (m_pseg->OutputSlot(isloutBefore)->InsertBefore())
+ {
+ // Legal insertion point
+ //RestoreFont(pgg);
+ return;
+ }
+ }
+
+ // Gradually adjust the click position in various directions and try again
+ // until we find a legal insertion point.
+ switch (nAdjustDir)
+ {
+ case 0: // Adjust to the left
+ case 4:
+ xsTry = xsClick - (xysInc * cTries);
+ ysTry = ysClick;
+ nAdjustDir = 0;
+ break;
+ case 1: // Adjust to the right
+ xsTry = xsClick + (xysInc * cTries);
+ ysTry = ysClick;
+ break;
+ case 2: // Adjust up
+ xsTry = xsClick;
+ ysTry = ysClick - (xysInc * cTries);
+ break;
+ case 3: // Adjust down
+ xsTry = xsClick;
+ ysTry = ysClick + (xysInc * cTries);
+ cTries++;
+ break;
+ default:
+ Assert(false);
+ nAdjustDir = 0;
+ cTries++;
+ }
+ nAdjustDir++;
+
+ if (cTries > 50)
+ { // Safety net
+ *pichw = 0;
+ *pfAssocPrev = false;
+ THROW(kresFail);
+ }
+ else if (cTries > 20)
+ xysInc = xysInc * 2;
+ }
+
+ //RestoreFont(pgg);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert a click position to a glyph bounding-box position.
+----------------------------------------------------------------------------------------------*/
+int SegmentPainter::PointToCharAux(float xsTry, float ysTry,
+ float * pxsGlyphOffset, float * pxsGlyphWidth)
+{
+ int iginfLoc = m_pseg->GlyphHit(xsTry, ysTry);
+
+ GlyphInfo * pginf = m_pseg->m_prgginf + iginfLoc;
+ *pxsGlyphOffset = pginf->bb().left;
+ *pxsGlyphWidth = pginf->bb().right - *pxsGlyphOffset;
+
+ return iginfLoc;
+}
+
+// Review: may need a way to do this and subsequent methods with one result per method?
+/*----------------------------------------------------------------------------------------------
+ Returns a value what logical position an arrow key should move the IP to.
+
+ @param ichwIP - initial position
+ @param pfAssocPrev - is the IP "leaning" backwards? input and output
+ @param fRight - direction of desired movement (physical or logical?)
+ @param pfInThisSeg - initially true if ichwIP is in the current segment;
+ return value is true if there is a legitimate output
+----------------------------------------------------------------------------------------------*/
+int SegmentPainter::arrowKeyPosition(int ichwIP, bool * pfAssocPrev,
+ bool fRight, bool * pfInThisSeg)
+//GrResult SegmentPainter::arrowKeyPosition(
+// int * pichwIP, bool * pfAssocPrev,
+// bool fRight, bool fMovingIn,
+// bool * pfResult)
+{
+ ChkGrArgPtr(pfAssocPrev);
+ //ChkGrOutPtr(pfInThisSeg);
+
+ bool fMovingIn = !*pfInThisSeg;
+ int ichwTmp = ichwIP;
+ bool fResult;
+ ArrowKeyPositionAux(&ichwTmp, pfAssocPrev, fRight, fMovingIn, false, false, &fResult);
+ *pfInThisSeg = fResult;
+ return ichwTmp;
+
+ //return ArrowKeyPositionAux(pichwIP, pfAssocPrev,
+ // fRight, fMovingIn, false, false, pfResult);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Indicate what logical position a shift-arrow-key combination should move the
+ end of the selection to.
+
+ @param pichw - initial endpoint and also adjusted result
+ @param fAssocPrevMatch - true if we need a certain orientation for the result;
+ should be false when *pichw = 0 and we are moving within the
+ same segment
+ @param fAssocPrevNeeded - association of the end-point, ie, true if it follows the anchor
+ @param ichAnchor - -1 if anchor is in a different segment
+ @param fRight - direction of desired movement
+ @param fMovingIn - true if we are moving in to this segment;
+ if so, initial pichw meaningless
+ @param pfRet - if false try next seg or string
+----------------------------------------------------------------------------------------------*/
+int SegmentPainter::extendSelectionPosition(int ichwEnd, bool fAssocPrevMatch, bool fAssocPrevNeeded,
+ int ichwAnchor, bool fRight, bool * pfInThisSeg)
+//GrResult SegmentPainter::extendSelectionPosition(
+// int * pichw, bool fAssocPrevMatch, bool fAssocPrevNeeded, int ichwAnchor,
+// bool fRight, bool fMovingIn,
+// bool* pfRet)
+{
+ //ChkGrArgPtr(pichw);
+ //ChkGrOutPtr(pfRet);
+
+ // Make the same adjustment as for an insertion point.
+ bool fAssocPrevCopy = fAssocPrevMatch;
+ bool fMovingIn = !*pfInThisSeg;
+ int ichwOld = ichwEnd;
+ int ichwNew = ichwEnd;
+ bool fResult;
+ ArrowKeyPositionAux(&ichwNew, &fAssocPrevCopy,
+ fRight, fMovingIn, fAssocPrevMatch, fAssocPrevNeeded, &fResult);
+ *pfInThisSeg = fResult;
+
+ //int ichwNew = *pichw;
+ //bool fAssocPrevCopy = fAssocPrevMatch;
+ //// TODO: adjust fAssocPrevCopy based on assoc-prev value of IP
+ //*pfRet = false;
+ //int ichwOld = *pichw;
+ //GrResult res = ArrowKeyPositionAux(&ichwNew, &fAssocPrevCopy,
+ // fRight, fMovingIn,
+ // fAssocPrevMatch, fAssocPrevNeeded,
+ // pfRet);
+
+// if (*pfRet && ichwNew == *pichw)
+// {
+// // The selection wasn't actually moved, just switched the direction it leans.
+// // Try one more time.
+// res = ArrowKeyPositionAux(&ichwNew, &fAssocPrevCopy,
+// fRight, fMovingIn,
+// (ichwAnchor != *pichw && fAssocPrevNeeded), fAssocPrevNeeded,
+// pfRet);
+// }
+ if (ichwAnchor != -1 && fResult &&
+ ((ichwNew < ichwAnchor && ichwAnchor < ichwOld) ||
+ (ichwOld < ichwAnchor && ichwAnchor < ichwNew)))
+ {
+ // Don't switch directions in one operation--force to an insertion point.
+ ichwNew = ichwAnchor;
+ }
+ return ichwNew;
+ //*pichw = ichwNew;
+ //ReturnResult(res);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Handle arrow key movement for both plain and shifted arrows.
+
+ @param pichw - initial endpoint and also adjusted result
+ @param pfAssocPrev - association of the end-point, ie, true if it follows the anchor
+ @param fRight - direction of desired movement
+ @param fMovingIn - true if we are moving in to this segment;
+ if so, initial pichw meaningless
+ @param fAssocPrevMatch - true if the direction of the result should
+ match the requested orientation, to avoid flipping around and
+ infinite loops
+ @param fAssocPrevNeeded - what is needed for the result, if fAssocPrevMatch == true
+ @param pfRet - if false try next segment or string
+----------------------------------------------------------------------------------------------*/
+GrResult SegmentPainter::ArrowKeyPositionAux(
+ int * pichwIP, bool * pfAssocPrev,
+ bool fRight, bool fMovingIn,
+ bool fAssocPrevMatch, bool fAssocPrevNeeded,
+ bool * pfResult)
+{
+ ChkGrArgPtr(pfResult);
+
+ //bool fAssocPrevTmp = *pfAssocPrev;
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ int nNextOrPrevSeg;
+ if (!fMovingIn)
+ {
+ *pfResult = ArrowKeyPositionInternal(pichwIP, pfAssocPrev, fRight,
+ fAssocPrevMatch, fAssocPrevNeeded, &nNextOrPrevSeg);
+ ReturnResult(kresOk);
+ }
+ else
+ {
+ int ichw;
+ bool fAssocPrevNew;
+ if (fRight)
+ {
+ // Moving right: make selection at left edge.
+ int iginf = m_pseg->LeftMostGlyph();
+ bool fBefore = !m_pseg->rightToLeft();
+ ichw = m_pseg->PhysicalSurfaceToUnderlying(iginf, fBefore) +
+ ((fBefore) ? 0 : 1);
+ fAssocPrevNew = !fBefore; // Review: should it be based on the char dir?
+ }
+ else
+ {
+ // Moving left: make selection at right edge;
+ int iginf = m_pseg->RightMostGlyph();
+ bool fBefore = m_pseg->rightToLeft();
+ ichw = m_pseg->PhysicalSurfaceToUnderlying(iginf, fBefore) +
+ ((fBefore) ? 0 : 1);
+ fAssocPrevNew = !fBefore; // Review: should it be based on the char dir?
+ }
+
+ // Okay, now we have a selection at the edge of the segment. Try moving inside by
+ // one glyph.
+ *pfResult = ArrowKeyPositionInternal(&ichw, &fAssocPrevNew, fRight,
+ fAssocPrevMatch, fAssocPrevNeeded, &nNextOrPrevSeg);
+ if (*pfResult)
+ {
+ *pichwIP = ichw;
+ *pfAssocPrev = fAssocPrevNew;
+ }
+
+ }
+
+ ReturnResult(kresOk);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Used to find out where underlines should be drawn.
+
+ @param ichwMin/Lim - range of text of interest
+ @param rs, rd - source/destination coordinates, for scaling
+ @param fSkipSpace - true if white space should not be underlined; some renderers may
+ ignore this
+ @param cxdMax - number of ranges allowed
+ @param prgxdLefts/Rights/UnderTops
+ - arrays of corresponding values indicating where an underline
+ should be drawn, in logical order
+
+ TODO: fix the bug where if you have trailing spaces in different segments (eg,
+ at different sizes), the spaces all but the last segment will be erroneously included
+ in the underline result.
+----------------------------------------------------------------------------------------------*/
+size_t SegmentPainter::getUnderlinePlacement(int ichwMin, int ichwLim,
+ bool fSkipSpace, size_t cxdMax,
+ float * prgxdLefts, float * prgxdRights, float * prgydUnderTops)
+{
+ ChkGrArrayArg(prgxdLefts, cxdMax);
+ ChkGrArrayArg(prgxdRights, cxdMax);
+ //ChkGrArrayArg(prgydUnderTops, cxdMax);
+
+ GrResult res = kresOk;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_pseg->m_dxsWidth >= 0);
+ Assert(m_pseg->m_dysAscent >= 0);
+
+ float xsSegLeft = m_pseg->m_dxsTotalWidth;
+ for (int iginf = 0; iginf < m_pseg->m_cginf; iginf++)
+ {
+ xsSegLeft = min(xsSegLeft, m_pseg->GlyphLeftEdge(iginf));
+ }
+
+ float xdSegLeft = this->ScaleXToDest(xsSegLeft);
+ float xdSegRight = xdSegLeft + m_pseg->m_dxsTotalWidth;
+
+ int ichwMinSel = min(ichwMin, ichwLim);
+ int ichwLimSel = max(ichwMin, ichwLim);
+
+ int ichwMinSeg = max(ichwMinSel, m_pseg->m_ichwMin + m_pseg->m_ichwAssocsMin);
+ int ichwLimSeg = min(ichwLimSel, m_pseg->m_ichwMin + m_pseg->m_ichwAssocsLim);
+
+ std::vector<Rect> vrs;
+ std::vector<bool> vfEntireHt;
+
+ bool * prgfAllCompsSelected = new bool[m_pseg->m_dichwLim];
+ std::fill_n(prgfAllCompsSelected, m_pseg->m_dichwLim, false);
+ CalcPartialLigatures(prgfAllCompsSelected, ichwMinSeg, ichwLimSeg,
+ ichwMinSel, ichwLimSel);
+
+ // Array to keep track of which glyphs were highlighted:
+ int cginf = m_pseg->m_cginf;
+ bool * prgfHighlighted = new bool[cginf];
+ std::fill_n(prgfHighlighted, cginf, false);
+
+ for (int ichwLp = ichwMinSeg; ichwLp < ichwLimSeg; ichwLp++)
+ {
+ CalcHighlightRect(ichwLp, vrs, vfEntireHt,
+ !prgfAllCompsSelected[ichwLp - m_pseg->m_ichwMin], prgfHighlighted,
+ (m_pseg->m_fEndLine && fSkipSpace));
+ }
+
+ // If all the glyphs of a given cluster were highlighted, highlight the whole cluster
+ // as a unit.
+ for (int islout = 0; islout < m_pseg->m_cslout; islout++)
+ {
+ CalcCompleteCluster(islout, vrs, vfEntireHt, prgfHighlighted);
+ }
+
+ // Convert rectangles in source coordinates to line segments in destination
+ // coordinates.
+ std::vector<LineSeg> vlsd;
+ for (size_t irs = 0; irs < vrs.size(); irs++)
+ {
+ Rect rsTmp = vrs[irs];
+ LineSeg lsdTmp;
+ lsdTmp.left = min(xdSegRight, max(xdSegLeft, ScaleXToDest(rsTmp.left)));
+ lsdTmp.right = max(xdSegLeft, min(xdSegRight, ScaleXToDest(rsTmp.right)));
+ vlsd.push_back(lsdTmp);
+ }
+
+ // Create a list of line segments with no overlaps.
+ std::vector<LineSeg> vlsdNoOverlaps;
+ size_t ils;
+ for (ils = 0; ils < vlsd.size(); ils++)
+ AddLineSegWithoutOverlaps(vlsdNoOverlaps, vlsd[ils]);
+
+ AssertNoOverlaps(vlsdNoOverlaps);
+
+ // The gap between the baseline and underlining is one pixel, on a normal screen
+ // at standard magnification, and as near as we can get to the equivalent in any
+ // special case.
+ //float dydGap = rdHeight / 96;
+ //float dydSubscript = max(float(0), (-1 * GrEngine::GrFloatMulDiv(m_pseg->m_dysOffset, rsHeight, rdHeight)));
+ float dydGap = 1;
+ float dydSubscript = max(float(0), (-1 * (m_pseg->m_dysOffset * m_yFactor)));
+ float ydBottom = ScaleYToDest(m_pseg->m_dysAscent) + dydGap + dydSubscript;
+
+ // Put the results in the output buffers.
+ size_t cxdRet = vlsdNoOverlaps.size();
+ for (ils = 0; ils < min(cxdRet, size_t(cxdMax)); ils++)
+ {
+ prgxdLefts[ils] = vlsdNoOverlaps[ils].left;
+ prgxdRights[ils] = vlsdNoOverlaps[ils].right;
+ if (prgydUnderTops)
+ prgydUnderTops[ils] = ydBottom;
+ }
+ delete[] prgfAllCompsSelected;
+ delete[] prgfHighlighted;
+
+ //RestoreFont(pgg);
+
+ if (vlsdNoOverlaps.size() > cxdMax)
+ res = kresFail;
+
+ return cxdRet;
+}
+
+
+//:>********************************************************************************************
+//:> Other methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Handle either drawing an insertion point or returning the position at which it
+ would be drawn.
+
+ @param ichwIP - character position
+ @param fAssocPrev - true if selection is associated with previous character
+ @param bOn - turning on or off? (ignored in this implementation)
+ @param fForceSplit - force a split insertion point
+ @param prdPrimary - if NULL, do drawing; otherwise, return location of primary IP
+ in destination device coordinates
+ @param prdSecondary - return location of secondary IP in dest device coordinates
+ @param pfPrimaryHere - true if primary selection is rendered in this segment
+ @param pfSecHere - true if (distinct) secondary selection is rendered in this segment;
+ false if it is in a different segment, or we are rendering
+ an I-beam (std selection)
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::CalcOrDrawInsertionPoint(
+ int ichwIP, bool fAssocPrev, bool bOn, bool fForceSplit,
+ Rect * prdPrimary, Rect * prdSecondary)
+{
+ GrResult res = kresOk;
+
+ float xsSegLeft = 0;
+ float ysSegTop = 0;
+
+ if (prdPrimary)
+ {
+ prdPrimary->top = 0;
+ prdPrimary->bottom = 0;
+ prdPrimary->left = 0;
+ prdPrimary->right = 0;
+ }
+ if (prdSecondary)
+ {
+ prdSecondary->top = 0;
+ prdSecondary->bottom = 0;
+ prdSecondary->left = 0;
+ prdSecondary->right = 0;
+ }
+
+ int ichwLim = m_pseg->m_ichwMin + m_pseg->m_dichwLim;
+ bool fRtl = m_pseg->rightToLeft();
+
+ if (m_pseg->m_dxsWidth < 0)
+ m_pseg->ComputeDimensions();
+
+ // Get the locations for the before and after selections.
+
+ float xsBefore, ysBeforeTop, ysBeforeBottom;
+ float xsAfter, ysAfterTop, ysAfterBottom;
+ bool fRtlBefore, fRtlAfter;
+ CalcIP(ichwIP, true, &xsBefore, &ysBeforeTop, &ysBeforeBottom, &fRtlBefore);
+ CalcIP(ichwIP, false, &xsAfter, &ysAfterTop, &ysAfterBottom, &fRtlAfter);
+
+ if (m_pseg->m_cginf == 0 && ichwIP == ichwLim)
+ {
+ Assert(kPosInfFloat == xsBefore && kPosInfFloat == xsAfter);
+ xsBefore = 0;
+ xsAfter = 0;
+ }
+ else if ((kPosInfFloat == xsBefore || kNegInfFloat == xsBefore) &&
+ (kPosInfFloat == xsAfter || kNegInfFloat == xsAfter))
+ {
+ return; // quick exit for nothing-to-draw case
+ }
+
+ bool fPrimary = true;
+ if (fForceSplit)
+ {
+ // Supposedly we can't find both halves of the IP in this segment.
+ Assert(xsBefore == kPosInfFloat || xsBefore == kNegInfFloat
+ || xsAfter == kPosInfFloat || xsAfter == kNegInfFloat);
+ if (xsBefore == kPosInfFloat || xsBefore == kNegInfFloat)
+ {
+ // Can't find the char the IP is before.
+ fPrimary = fAssocPrev;
+ }
+ else // if (xsAfter == kPosInfinity || xsAfter == kNegInfinity)
+ {
+ // Can't find the char the IP is after.
+ fPrimary = !fAssocPrev;
+ }
+ ////Assert((dm == kdmSplitPrimary) == fPrimary);
+ }
+
+ if (xsBefore == kPosInfinity || xsBefore == kNegInfinity)
+ {
+ ysBeforeTop = ysSegTop;
+ ysBeforeBottom = ysSegTop + m_pseg->m_dysHeight;
+ }
+ else
+ {
+ xsBefore += xsSegLeft;
+ ysBeforeTop += ysSegTop;
+ ysBeforeBottom += ysSegTop;
+ }
+ if (xsAfter == kNegInfinity || xsAfter == kPosInfinity)
+ {
+ ysAfterTop = ysSegTop;
+ ysAfterBottom = ysSegTop + m_pseg->m_dysHeight;
+ }
+ else
+ {
+ xsAfter += xsSegLeft;
+ ysAfterTop += ysSegTop;
+ ysAfterBottom += ysSegTop;
+ }
+
+ float xsLeft = xsSegLeft
+ + ((fRtl && m_pseg->m_fEndLine) ? (m_pseg->m_dxsVisibleWidth - m_pseg->m_dxsTotalWidth) :0);
+ float xsRight = xsSegLeft
+ + ((fRtl && m_pseg->m_fEndLine) ? m_pseg->m_dxsVisibleWidth : m_pseg->m_dxsTotalWidth)
+ + m_pseg->m_dxsStretch;
+ float dysMinSplitHeight = m_pseg->m_dysHeight / 4;
+
+ if (!fForceSplit) // kdmNormal == dm)
+ {
+ // Standard I-beam, or both halves of split IP.
+
+ bool fIBeam = false;
+
+ if (xsBefore == xsAfter)
+ // Positions coincide within this segment: make an I-beam.
+ fIBeam = true;
+
+ else if (fabsf(xsBefore - xsLeft) <= 1 && ichwIP == m_pseg->m_ichwMin)
+ {
+ // Logical start is at a left edge: allow I-beam if previous segment has one
+ // at the end (or there is no previous segment).
+ //Assert(!fRtlBefore);
+ //if (m_pseg->m_psegPrev)
+ //{
+ // SegmentPainter segpPrev(m_pseg->m_psegPrev);
+ // fIBeam = segpPrev.doBoundariesCoincide(true, true);
+ //}
+ //else
+
+ fIBeam = true;
+ }
+ else if (fabsf(xsBefore - xsRight) <= 1 && ichwIP == m_pseg->m_ichwMin)
+ {
+ // Logical start is at a right edge: allow I-beam if previous segment has one
+ // at the end (or there is no previous segment).
+ //Assert(fRtlBefore);
+ //if (m_pseg->m_psegPrev)
+ //{
+ // SegmentPainter segpPrev(m_pseg->m_psegPrev);
+ // fIBeam = segpPrev.doBoundariesCoincide(true, false);
+ //}
+ //else
+
+ fIBeam = true;
+ }
+ else if (fabsf(xsAfter - xsLeft) <= 1 && ichwIP == ichwLim)
+ {
+ // Logical end is at a left edge: allow I-beam if next segment has one
+ // at the beginning (or there is no next segment).
+ //Assert(fRtlAfter);
+ //if (m_pseg->m_psegNext == NULL)
+ //{
+ // SegmentPainter segpPrev(m_pseg->m_psegPrev);
+ // fIBeam = segpPrev.doBoundariesCoincide(false, true);
+ //}
+ //else
+
+ fIBeam = true;
+ }
+ else if (fabsf(xsAfter - xsRight) <= 1 && ichwIP == ichwLim)
+ {
+ // Logical end is at a right edge: allow I-beam if next segment has one
+ // at the beginning (or there is no next segment).
+ //Assert(!fRtlAfter);
+ //if (m_pseg->m_psegNext == NULL)
+ //{
+ // SegmentPainter segpPrev(m_pseg->m_psegPrev);
+ // fIBeam = segpPrev.doBoundariesCoincide(false, false);
+ //}
+ //else
+
+ fIBeam = true;
+ }
+ else
+ {
+ // If the horizontal positions of the two halves are sufficiently close,
+ // make an I-beam.
+ fIBeam = CloseIPPositions(
+ &xsBefore, ysBeforeTop, ysBeforeBottom,
+ &xsAfter, ysAfterTop, ysAfterBottom);
+ }
+ if (ResultFailed(res))
+ THROW(WARN(res));
+
+ if (fIBeam &&
+ ((ichwIP == m_pseg->m_ichwMin && fAssocPrev) || (ichwIP == ichwLim && !fAssocPrev)))
+ {
+ // Adjacent segment will show the I-beam, so don't show it here.
+ if (m_pseg->m_cginf == 0)
+ {
+ // Empty segment--assume no adjacent segment.
+ }
+ else
+ return;
+ }
+
+ if (fIBeam)
+ { // I-beam caret
+
+ float ysTop = min(ysBeforeTop, ysAfterTop);
+ float ysBottom = max(ysBeforeBottom, ysAfterBottom);
+ float xsMid = (xsBefore == kPosInfFloat) ? xsAfter : xsBefore;
+ InvertIBeam(xsMid, ysTop, ysBottom, fAssocPrev, prdPrimary);
+ }
+ else
+ { // split caret
+ if (fAssocPrev)
+ { // xsAfter is primary, xsBefore is secondary
+ if (xsAfter != kNegInfinity)
+ {
+ InvertSplitIP(xsAfter, ysAfterTop, ysAfterBottom,
+ true, fRtlAfter, false, dysMinSplitHeight, prdPrimary);
+ }
+ if (xsBefore != kPosInfFloat)
+ {
+ InvertSplitIP(xsBefore, ysBeforeTop, ysBeforeBottom,
+ false, !fRtlBefore, true, dysMinSplitHeight, prdSecondary);
+ }
+ }
+ else
+ { // xsBefore is primary, xsAfter is secondary
+ if (xsBefore != kPosInfinity)
+ {
+ InvertSplitIP(xsBefore, ysBeforeTop, ysBeforeBottom,
+ false, !fRtlBefore, false, dysMinSplitHeight, prdPrimary);
+ }
+ if (xsAfter != kNegInfinity)
+ {
+ InvertSplitIP(xsAfter, ysAfterTop, ysAfterBottom,
+ true, fRtlAfter, true, dysMinSplitHeight, prdSecondary);
+ }
+ }
+ //*pfSecHere = true;
+ }
+ //*pfPrimaryHere = true;
+ }
+ else if (fForceSplit && fPrimary) // kdmSplitPrimary == dm)
+ {
+ // Draw just the primary caret.
+ if (fAssocPrev)
+ { // xsAfter is primary
+ if (xsAfter == kNegInfinity)
+ {} // no primary
+ else
+ InvertSplitIP(xsAfter, ysAfterTop, ysAfterBottom,
+ true, fRtlAfter, false, dysMinSplitHeight, prdPrimary);
+ }
+ else
+ { // xsBefore is primary
+ if (xsBefore == kPosInfinity)
+ {} // no primary
+ else
+ InvertSplitIP(xsBefore, ysBeforeTop, ysBeforeBottom,
+ false, !fRtlBefore, false, dysMinSplitHeight, prdPrimary);
+ }
+ }
+ else // fForceSplit && !fPrimary
+ {
+ // Draw just the secondary caret.
+ //Assert(kdmSplitSecondary == dm);
+ if (fAssocPrev)
+ { // xsBefore is secondary
+ if (xsBefore == kPosInfinity)
+ {} // no secondary
+ else
+ InvertSplitIP(xsBefore, ysBeforeTop, ysBeforeBottom,
+ false, !fRtlBefore, true, dysMinSplitHeight, prdSecondary);
+ }
+ else
+ { // xsAfter is secondary
+ if (xsAfter == kNegInfinity)
+ {} // no secondary
+ else
+ InvertSplitIP(xsAfter, ysAfterTop, ysAfterBottom,
+ true, fRtlAfter, true, dysMinSplitHeight, prdSecondary);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Draw an I-beam cursor, or return the location at which it would be drawn.
+
+ Note that currently we do not draw a true I-beam, but rather just a vertical line.
+
+ @param xs - horizontal center of IP
+ @param ysTop - top of glyph (or ligature component) box
+ @param ysBottom - bottom of glyph (or ligature component) box
+ @param fAssocRight - true if the IP is associated with the text to the right
+ @param rs, rd - source/destination device coordinates
+ @param prdRet - return location to be drawn in dest device coords;
+ if NULL, do the drawing
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::InvertIBeam(float xs, float ysTop, float ysBottom,
+ bool fAssocPrev, Rect * prdRet)
+{
+ float xd = ScaleXToDest(xs);
+ float ydTop = ScaleYToDest(ysTop);
+ float ydBottom = ScaleYToDest(ysBottom);
+
+ // For now, assume that destination coordinates are in terms of pixels.
+ float dxdTwoXPixels = 2;
+
+ float dxdLeftAdjust = dxdTwoXPixels / 2;
+ float dxdRightAdjust = dxdTwoXPixels - dxdLeftAdjust;
+
+// int dysFontAscent;
+// pgg->GetFontAscentSourceUnits(pgg, &dysFontAscent);
+// dysFontAscent += m_dysXAscent;
+// if (dysFontAscent < 20)
+// {
+// dxdRightAdjust--;
+// dxdRightHook = 1;
+// }
+
+ if (prdRet)
+ {
+ prdRet->left = xd - dxdLeftAdjust;
+ prdRet->right = xd + dxdRightAdjust;
+ prdRet->top = ydTop;
+ prdRet->bottom = ydBottom;
+ }
+ else
+ {
+ InvertRect(xd-dxdLeftAdjust, ydTop,
+ xd+dxdRightAdjust, ydBottom);
+
+ // To make a true I-beam:
+// InvertRect(xd-dxdTwoXPixels, ydTop-dydOneYPixel,
+// xd+dxdRightHook, ydTop);
+// InvertRect(xd-dxdTwoXPixels, ydBottom,
+// xd+dxdRightHook, ydBottom+dydOneYPixel);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Draw a split insertion point, or return the location at which it would be drawn.
+
+ @param xs - horizontal center of IP
+ @param ysTop - top of glyph (or ligature component) box
+ @param ysBottom - bottom of glyph (or ligature component) box
+ @param fTop - true if the IP is to be drawn at the top of the line of text
+ @param fAssocRight - true if the IP is associated with the text to the right
+ @param fSecondary - true if the IP is secondary, false if it is primary
+ @param dysMinSplitHeight
+ - minimum split cursor height
+ @param rs, rd - source/destination device coordinates
+ @param prdRet - return location to be drawn in dest device coords;
+ if NULL, do the drawing
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::InvertSplitIP(float xs, float ysTop, float ysBottom,
+ bool fTop, bool fAssocRight, bool fSecondary, float dysMinSplitHeight,
+ Rect * prdRet)
+{
+ if (prdRet == NULL && ysTop == ysBottom)
+ return; // invisible IP
+
+ float xd = ScaleXToDest(xs);
+ float ydTop = ScaleYToDest(ysTop);
+ float ydBottom = ScaleYToDest(ysBottom);
+ float dydMinSplitHeight = dysMinSplitHeight * m_yFactor;
+
+ float ydMid = (ydTop + ydBottom) / 2;
+
+ // For now, assume that destination coordinates are in terms of pixels.
+ float dxdOneXPixel = 1;
+ float dydOneYPixel = 1;
+ float dxdTwoXPixels = 2;
+
+ float xdLeft, xdRight, dxdHookLen;
+ if (fSecondary)
+ {
+ xdLeft = xd - (dxdOneXPixel / 2);
+ xdRight = xdLeft + 1;
+ dxdHookLen = 2;
+ }
+ else
+ {
+ xdLeft = xd - (dxdTwoXPixels / 2);
+ xdRight = xdLeft + 2;
+ dxdHookLen = 3;
+ }
+
+ float yd1, yd2;
+ if (fTop)
+ {
+ yd1 = ydTop;
+ if (ydMid - ydTop < dydMinSplitHeight)
+ ydMid = ydTop + dydMinSplitHeight;
+ yd2 = (fSecondary) ? ydMid : ydMid + 3;
+ }
+ else
+ {
+ yd2 = ydBottom;
+ if (ydBottom - ydMid < dydMinSplitHeight)
+ ydMid = ydBottom - dydMinSplitHeight;
+ yd1 = (fSecondary) ? ydMid : ydMid - 3;
+ }
+
+ if (prdRet)
+ {
+ prdRet->left = xdLeft;
+ prdRet->right = xdRight;
+ // The most common reason for returning the positions of the IP is to scroll it into
+ // view, in which case we want to return the entire line height, not just the
+ // height of the IP itself.
+ prdRet->top = ydTop; // yd1;
+ prdRet->bottom = ydBottom; // yd2;
+ }
+ else
+ {
+ InvertRect(xdLeft, yd1, xdRight, yd2);
+ }
+
+ if (fAssocRight)
+ {
+ if (prdRet)
+ prdRet->right = xdRight + dxdHookLen;
+ else
+ {
+ if (fTop)
+ InvertRect(xdRight, ydTop,
+ xdRight + dxdHookLen, ydTop + dydOneYPixel);
+ else
+ InvertRect(xdRight, ydBottom-dydOneYPixel,
+ xdRight + dxdHookLen, ydBottom);
+ }
+ }
+ else
+ {
+ if (prdRet)
+ prdRet->left = xdLeft - dxdHookLen;
+ else
+ {
+ if (fTop)
+ InvertRect(xdLeft - dxdHookLen, ydTop,
+ xdLeft, ydTop + dydOneYPixel);
+ else
+ InvertRect(xdLeft - dxdHookLen, ydBottom - dydOneYPixel,
+ xdLeft, ydBottom);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given a character position (relative to the beginning of the string), return the
+ position for the insertion point, relative to the top-left of the segment.
+ Notice that these are before/after positions, not left/right positions.
+ Return an infinity value to indicate no appropriate IP.
+
+ @param ichwSel - selection position, relative to beginning of string
+ @param fBefore - true if we are interested in the character the IP is before.
+ @param pxs, pysTop, pysBottom
+ - return locations for drawing the IP (top and bottom are not
+ adjusted for half-selections)
+ @param pfRtl - return true if the character is right-to-left
+
+ Review: it might be useful to figure out if the two surface glyphs are physically adjacent
+ in such a way that their IPs can be combined into one I-beam. For now we use a simple
+ rule that assumes that any glyph or ligature component is at least 10% as wide as the
+ height of the font (see CloseIPPositions).
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::CalcIP(int ichwSel, bool fBefore,
+ float * pxs, float * pysTop, float * pysBottom, bool * pfRtl)
+{
+ Font & font = this->m_pseg->getFont();
+
+ int ichw = (fBefore) ? ichwSel : ichwSel - 1;
+
+ int iginfOutput;
+
+ *pfRtl = m_pseg->CharIsRightToLeft(ichw, fBefore);
+
+ GrEngine * pgreng = m_pseg->EngineImpl();
+ GrGlyphTable * pgtbl = (pgreng) ? pgreng->GlyphTable() : NULL;
+
+ float dysFontAscent = m_pseg->m_dysFontAscent;
+ ////GrResult res = GetFontAscentSourceUnits(pgg, &dysFontAscent);
+ ////if (ResultFailed(res))
+ //// THROW(WARN(res));
+ dysFontAscent += m_pseg->m_dysXAscent;
+
+ *pysTop = 0;
+ *pysBottom = m_pseg->m_dysHeight;
+
+ int ichwSegOffset = ichw - m_pseg->m_ichwMin;
+ int isloutLig;
+ if (ichwSegOffset < m_pseg->m_ichwAssocsMin || ichwSegOffset >= m_pseg->m_ichwAssocsLim)
+ isloutLig = kNegInfinity;
+ else
+ isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ bool fOkLig = (isloutLig != kNegInfinity);
+ if (pgtbl && fOkLig)
+ {
+ // Ligature component; place the IP at the boundary
+ // of the component box.
+
+ GrSlotOutput * pslout = m_pseg->OutputSlot(isloutLig);
+ int icomp = m_pseg->m_prgiComponent[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+
+ iginfOutput = m_pseg->LogicalToPhysicalSurface(isloutLig);
+
+ float xsGlyphOffset = m_pseg->GlyphLeftEdge(iginfOutput);
+
+ float xsLeft, xsRight, ysTop, ysBottom;
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ fOkLig = pgtbl->ComponentBoxLogUnits(m_pseg->m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_pseg->m_mFontEmUnits, m_pseg->m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom);
+ if (fOkLig)
+ {
+ if (fBefore == *pfRtl)
+ // Position of interest is to the right.
+ *pxs = xsGlyphOffset + xsRight;
+ else
+ // Position of interest is to the left.
+ *pxs = xsGlyphOffset + xsLeft;
+
+ GlyphInfo * pginf = m_pseg->m_prgginf + iginfOutput;
+ float ysGlyph = pginf->yOffset();
+
+ *pysTop = ysTop + (m_pseg->m_dysAscent - dysFontAscent) - ysGlyph;
+ *pysBottom = ysBottom + (m_pseg->m_dysAscent - dysFontAscent) - ysGlyph;
+ }
+ }
+
+ if (!fOkLig)
+ {
+ // Not a ligature component.
+
+ int islout = m_pseg->UnderlyingToLogicalSurface(ichw, fBefore);
+ GrSlotOutput * psloutTmp = m_pseg->OutputSlot(islout);
+ iginfOutput = m_pseg->LogicalToPhysicalSurface(islout);
+
+ if (kPosInfinity == iginfOutput || kNegInfinity == iginfOutput)
+ *pxs = kPosInfFloat;
+
+ else
+ {
+ bool fCluster = (psloutTmp->IsPartOfCluster());
+ bool fHighlightBB = fCluster;
+ // Test below should match the one in CalcHighlightRect:
+ if ((psloutTmp->ClusterAdvance() == 0
+ || psloutTmp->GlyphMetricLogUnits(&font, kgmetAdvWidth) == 0)
+ && !psloutTmp->IsSpace())
+ {
+ fHighlightBB = true; // use bounding box for zero-advance glyph
+ }
+ if (fHighlightBB)
+ {
+ // Cluster member or zero-width glyph.
+
+ if (fCluster && AtEdgeOfCluster(psloutTmp, islout, fBefore) &&
+ !CanInsertIntoCluster(psloutTmp, islout))
+ {
+ // Place the IP at the edge of the whole cluster.
+
+ int isloutBase = psloutTmp->ClusterBase();
+ GrSlotOutput * psloutBase = m_pseg->OutputSlot(isloutBase);
+ //int igbbBase = psloutBase->GlyphBbIndex();
+ int iginfBase = m_pseg->LogicalToPhysicalSurface(isloutBase);
+
+ float xsBase = m_pseg->GlyphLeftEdge(iginfBase);
+
+ float xsLeft = xsBase + psloutBase->ClusterXOffset();
+ float xsRight = xsBase + psloutBase->ClusterAdvance();
+
+ if (fBefore == *pfRtl)
+ // Position of interest is to the right
+ *pxs = xsRight;
+ else
+ // Position of interest is to the left.
+ *pxs = xsLeft;
+ }
+ else
+ {
+ // Place the IP on the perimeter of the bounding box of the cluster member.
+
+ float xsGlyphStart = m_pseg->GlyphLeftEdge(iginfOutput);
+
+// float dysFontAscent;
+// res = GetFontAscentSourceUnits(pgg, &dysFontAscent);
+// if (ResultFailed(res)) THROW(WARN(res));
+// dysFontAscent += m_dysXAscent;
+
+ float ysBbTop = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbTop);
+ float ysBbBottom = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbBottom);
+ float xsBbLeft = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbLeft);
+ float xsBbRight = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbRight);
+
+ int twoPixels = 2; // assume dest coords are in pixels
+
+ if (fBefore == *pfRtl)
+ // Position of interest is to the right
+ *pxs = xsGlyphStart + xsBbRight + twoPixels;
+ else
+ // Position of interest is to the left.
+ *pxs = xsGlyphStart + xsBbLeft - twoPixels;
+
+ GlyphInfo * pginf = m_pseg->m_prgginf + iginfOutput;
+ float ysGlyph = pginf->yOffset();
+ float ysGlyphBaseline = m_pseg->m_dysAscent - ysGlyph; // relative to top
+
+ *pysTop = ysGlyphBaseline - ysBbTop - twoPixels;
+ *pysBottom = ysGlyphBaseline - ysBbBottom + twoPixels;
+ }
+ }
+ else
+ {
+ // Insertion point goes at origin or advance width of glyph.
+
+ *pxs = m_pseg->GlyphLeftEdge(iginfOutput);
+ if (fBefore == *pfRtl)
+ {
+ // Position of interest is to the right
+ //*pxs += psloutTmp->GlyphMetricLogUnits(&font, kgmetAdvWidth);
+ *pxs += psloutTmp->ClusterAdvance();
+ }
+ // else position of interest is to the left
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the two positions for the insertion point are close enough, merge them into
+ one insertion point, and return true to indicate that we want an I-beam.
+
+ @param pxsBefore, pxsAfter - for comparing, and also adjusted results
+ @param ysBeforeTop/Bottom, ysAfterTop/Bottom - for comparing
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::CloseIPPositions(float * pxsBefore, float ysBeforeTop, float ysBeforeBottom,
+ float * pxsAfter, float ysAfterTop, float ysAfterBottom)
+{
+ // No adjustment if vertical positions are disjoint.
+ if (ysBeforeBottom <= ysAfterTop)
+ return false;
+ if (ysAfterBottom <= ysBeforeTop)
+ return false;
+
+ float dysHt = max(ysBeforeBottom, ysAfterBottom) - min(ysBeforeTop, ysAfterTop);
+ float dxsDiff = fabsf(*pxsBefore - *pxsAfter);
+
+ // If the difference in the x positions is less than 10% of the height,
+ // we want an I-beam--use the average.
+ if (dxsDiff * 10 < dysHt)
+ {
+ *pxsBefore = (*pxsBefore + *pxsAfter) / 2;
+ *pxsAfter = *pxsBefore;
+ return true;
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the slot in question is the first or last slot of its cluster,
+ or if it is not part of a cluster at all. Return false if the specified side
+ of the slot is interior to a cluster.
+
+ @param fBefore - if true, we are examining the slot the insertion point is before,
+ so we are interested in whether this slot is at the
+ leading edge of the cluster.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AtEdgeOfCluster(GrSlotOutput * pslout, int islout, bool fBefore)
+{
+ if (!pslout->IsPartOfCluster())
+ return true;
+
+ if (fBefore && (islout == 0))
+ return true;
+ if (!fBefore && (m_pseg->m_cslout == islout + 1))
+ return true;
+
+ // If the adjacent slot in whatever direction we're interested in has the same
+ // cluster base, this slot is not on the edge of the cluster.
+ // -- NO, because you could have an intervening glyph that is not part of the
+ // cluster.
+ //int isloutAdjacentBase = (fBefore) ?
+ // m_pseg->OutputSlot(islout - 1)->ClusterBase() :
+ // m_pseg->OutputSlot(islout + 1)->ClusterBase();
+ //return (isloutAdjacentBase != m_pseg->OutputSlot(islout)->ClusterBase());
+
+ // Ask the cluster base.
+ return AtEdgeOfCluster(m_pseg->OutputSlot(pslout->ClusterBase()), pslout->ClusterBase(),
+ pslout, islout, fBefore);
+}
+
+bool SegmentPainter::AtEdgeOfCluster(GrSlotOutput * psloutBase, int isloutBase,
+ GrSlotOutput * pslout, int islout, bool fBefore)
+{
+ // Compare pslout to all the members of the cluster. If it is the minimum or maximum, it
+ // is at an edge.
+ if (fBefore && isloutBase < islout)
+ return false;
+ if (!fBefore && isloutBase > islout)
+ return false;
+
+ std::vector<int> visloutCluster;
+ m_pseg->ClusterMembersForGlyph(isloutBase, psloutBase->ClusterRange(), visloutCluster);
+
+ for (size_t iislout = 0; iislout < visloutCluster.size(); iislout++)
+ {
+ int isloutMember = visloutCluster[iislout];
+ if (fBefore && isloutMember < islout)
+ return false;
+ if (!fBefore && isloutMember > islout)
+ return false;
+ }
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if it is permitted to put an insertion point somewhere in the middle of
+ the given slot's cluster.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::CanInsertIntoCluster(GrSlotOutput * pslout, int islout)
+{
+ if (!pslout->IsPartOfCluster())
+ return false;
+
+ int isloutBase = pslout->ClusterBase();
+ if (islout != isloutBase)
+ {
+ // Ask the cluster base.
+ Assert(pslout->ClusterRange() == 0);
+ return CanInsertIntoCluster(m_pseg->OutputSlot(isloutBase), isloutBase);
+ }
+
+ if (!AtEdgeOfCluster(pslout, islout, true) && pslout->InsertBefore())
+ return true;
+
+ std::vector<int> visloutCluster;
+ m_pseg->ClusterMembersForGlyph(isloutBase, pslout->ClusterRange(), visloutCluster);
+
+ for (size_t iislout = 0; iislout < visloutCluster.size(); iislout++)
+ {
+ int isloutMember = visloutCluster[iislout];
+ if (AtEdgeOfCluster(m_pseg->OutputSlot(isloutMember), isloutMember, true))
+ // Inserting before the first member of the cluster doesn't count.
+ continue;
+
+ if (m_pseg->OutputSlot(isloutMember)->InsertBefore())
+ return true;
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Determine which characters in the selected range are part of ligatures that are fully
+ selected vs. those that are only partially selected. Those that are only partially selected
+ must have their components highlighted individually, but those that are fully selected
+ should be highlighted fully, to avoid blank spots in the case that the components do not
+ fully cover the surface of the glyph.
+
+ @param prgfAllSelected - array of flags to fill in with results
+ @param ichwMin/LimSeg - range of characters to examine
+ @param ichwMin/LimSel - range of characters that are selected
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::CalcPartialLigatures(bool * prgfAllSelected,
+ int ichwMinSeg, int ichwLimSeg,
+ int ichwMinSel, int ichwLimSel)
+{
+ GrEngine * pgreng = m_pseg->EngineImpl();
+ GrGlyphTable * pgtbl = (pgreng) ? pgreng->GlyphTable() : NULL;
+
+ for (int ichw = ichwMinSeg; ichw < ichwLimSeg; ichw++)
+ {
+ int ichwSegOffset = ichw - m_pseg->m_ichwMin;
+ int isloutLig;
+ if (ichwSegOffset < m_pseg->m_ichwAssocsMin || ichwSegOffset >= m_pseg->m_ichwAssocsLim)
+ isloutLig = kNegInfinity;
+ else
+ isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ bool fLigComp = (pgtbl && isloutLig != kNegInfinity);
+ if (fLigComp && !prgfAllSelected[ichwSegOffset])
+ {
+ GrSlotOutput * pslout = m_pseg->OutputSlot(isloutLig);
+ bool fAll = true;
+ int icomp;
+ for (icomp = 0; icomp < pslout->NumberOfComponents(); icomp++)
+ {
+ int ichwUnderlying = pslout->FirstUnderlyingComponent(icomp); // is it possible to select one char of a component and not another?
+ if (ichwUnderlying < ichwMinSel - m_pseg->m_ichwMin ||
+ ichwUnderlying >= ichwLimSel - m_pseg->m_ichwMin)
+ {
+ fAll = false; // found a component that is not selected
+ }
+ }
+ for (icomp = 0; icomp < pslout->NumberOfComponents(); icomp++)
+ {
+ for (int ichw = pslout->FirstUnderlyingComponent(icomp) ;
+ ichw <= pslout->LastUnderlyingComponent(icomp) ;
+ ichw++)
+ {
+ if (m_pseg->m_prgiComponent[ichw - m_pseg->m_ichwAssocsMin] == icomp)
+ prgfAllSelected[ichw] = fAll;
+ }
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ The given character is part of the selected range. Add to the vector a rectangle (or
+ eventually, several) indicating the corresponding screen area(s) of the character.
+ The rectangle is relative to the top left of the segment.
+
+ @param ichw - selected char, relative to beginning of string
+ @param vrs - list of rectangles to highlight, in source coords, relative to
+ segment draw position (top-left)
+ @param vfEntireHt - for each of the above rectangles, true if the rect should be
+ extended to include the entire line
+ @param fJustComponent - true if we want to highlight just the single ligature component
+ this character maps to; false if the entire ligature is selected
+ @param rgfHighlighted - for each glyph in this segment, whether it is being highlighted
+ by this operation
+ @param fSkipTrSpace - should we skip trailing white space?
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::CalcHighlightRect(int ichw,
+ std::vector<Rect> & vrs, std::vector<bool> & vfEntireHt,
+ bool fJustComponent, bool * rgfHighlighted, bool fSkipTrSpace)
+{
+ GrResult res;
+
+ GrEngine * pgreng = m_pseg->EngineImpl();
+ GrGlyphTable * pgtbl = (pgreng) ? pgreng->GlyphTable() : NULL;
+ //bool fRtl = m_pseg->rightToLeft();
+
+ Font & font = m_pseg->getFont();
+
+ if (!GrCharStream::AtUnicodeCharBoundary(m_pseg->GetString(), ichw))
+ // Second half of a surrogate pair, or UTF-8: ignore.
+ return;
+
+ // Calculate the location for the glyph that this IP is before.
+
+ int ichwSegOffset = ichw - m_pseg->m_ichwMin;
+ int isloutLig;
+ if (ichwSegOffset < m_pseg->m_ichwAssocsMin || ichwSegOffset >= m_pseg->m_ichwAssocsLim)
+ isloutLig = kNegInfinity;
+ else
+ isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ bool fLigComp = (pgtbl && isloutLig != kNegInfinity);
+ if (fLigComp && fJustComponent)
+ {
+ // Character is a ligature component.
+
+ GrSlotOutput * pslout = m_pseg->OutputSlot(isloutLig);
+ int icomp = m_pseg->m_prgiComponent[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ int iginfOutput = m_pseg->LogicalToPhysicalSurface(isloutLig);
+
+ float xsGlyphStart = m_pseg->GlyphLeftEdge(iginfOutput);
+
+ float xsLeft, xsRight, ysTop, ysBottom;
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ pgtbl->ComponentBoxLogUnits(m_pseg->m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_pseg->m_mFontEmUnits, m_pseg->m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom);
+
+ float dysFontAscent = m_pseg->m_dysFontAscent;
+ ////GetFontAscentSourceUnits(pgg, &dysFontAscent);
+ dysFontAscent += m_pseg->m_dysXAscent;
+ GlyphInfo * pginf = m_pseg->m_prgginf + iginfOutput;
+ float ysForGlyph = pginf->yOffset();
+ float dysGlyphTop = (m_pseg->m_dysAscent - dysFontAscent) - ysForGlyph; // rel. to common baseline
+
+ Rect rsNew;
+ rsNew.top = ysTop + dysGlyphTop;
+ rsNew.bottom = ysBottom + dysGlyphTop;
+ rsNew.left = xsGlyphStart + xsLeft;
+ rsNew.right = xsGlyphStart + xsRight;
+ vrs.push_back(rsNew);
+
+ vfEntireHt.push_back(false);
+ }
+ else
+ {
+ std::vector<int> vislout = m_pseg->UnderlyingToLogicalAssocs(ichw);
+ if (vislout.size() == 0)
+ return;
+
+ float xsGlyphLeft, xsGlyphRight;
+
+ res = kresOk;
+
+ for (size_t iislout = 0; iislout < vislout.size(); iislout++)
+ {
+ int islout = vislout[iislout];
+ if (islout == kNegInfinity || islout == kPosInfinity)
+ continue;
+ int iginfTmp = m_pseg->LogicalToPhysicalSurface(islout);
+ Assert(iginfTmp != kNegInfinity);
+ Assert(iginfTmp != kPosInfinity);
+
+ if (fSkipTrSpace && islout >= m_pseg->m_isloutVisLim)
+ continue;
+
+ Rect rsNew;
+ GrSlotOutput * psloutTmp = m_pseg->OutputSlot(islout);
+ bool fHighlightBB = psloutTmp->IsPartOfCluster();
+ // Test below should match the one in CalcIP--
+ // If the glyph has no advance width but does have a real bounding box,
+ // highlight the bounding box. Review: do we want this???
+ if ((psloutTmp->ClusterAdvance() == 0
+ || psloutTmp->GlyphMetricLogUnits(&font, kgmetAdvWidth) == 0)
+ && !psloutTmp->IsSpace())
+ {
+ fHighlightBB = true;
+ }
+ xsGlyphLeft = m_pseg->GlyphLeftEdge(iginfTmp);
+ if (fHighlightBB)
+ {
+ // For now, highlight just the bounding box of this glyph. After we finish
+ // highlighting all glyphs individually, we'll go back and highlight
+ // as one unit any clusters that are completely selected.
+
+// int dysFontAscent;
+// res = GetFontAscentSourceUnits(pgg, &dysFontAscent); // if we restore this code, add in ExtraAscent
+// if (ResultFailed(res)) THROW(WARN(res));
+// dysFontAscent += m_dysXAscent;
+
+ GlyphInfo * pginf = m_pseg->m_prgginf + iginfTmp;
+ float ysForGlyph = pginf->yOffset();
+ float ysGlyphBaseline = m_pseg->m_dysAscent - ysForGlyph; // relative to top
+
+ float ysBbTop = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbTop);
+ float ysBbBottom = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbBottom);
+ float xsBbLeft = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbLeft);
+ float xsBbRight = psloutTmp->GlyphMetricLogUnits(&font, kgmetBbRight);
+
+ rsNew.top = ysGlyphBaseline - ysBbTop - 2;
+ rsNew.bottom = ysGlyphBaseline - ysBbBottom + 2;
+ rsNew.left = xsGlyphLeft + xsBbLeft - 2;
+ rsNew.right = xsGlyphLeft + xsBbRight + 2;
+
+ vfEntireHt.push_back(false);
+ }
+ else
+ {
+ // Highlight entire width of the glyph from the top of the line to the bottom.
+ // Horizontally, highlight from the origin of the glyph to the advance width.
+
+ //xsGlyphRight = xsGlyphLeft + psloutTmp->GlyphMetricLogUnits(&font, kgmetAdvWidth);
+ xsGlyphRight = xsGlyphLeft + psloutTmp->ClusterAdvance();
+
+ if (xsGlyphLeft > xsGlyphRight)
+ std::swap(xsGlyphLeft, xsGlyphRight);
+
+ rsNew.top = 0;
+ rsNew.bottom = m_pseg->m_dysHeight;
+ rsNew.left = xsGlyphLeft;
+ rsNew.right = xsGlyphRight;
+
+ vfEntireHt.push_back(true);
+ }
+ vrs.push_back(rsNew);
+
+ if (rgfHighlighted)
+ rgfHighlighted[iginfTmp] = true;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the output slot is a cluster base and all the members of the cluster are highlighted,
+ simply highlight the cluster as a single rectangle, to avoid unslightly gaps
+ between glyphs. (Note that this does not remove the rectangles that were already included
+ to handle the individual members.)
+ The rectangles are relative to the top left of the segment.
+
+ @param islout - output slot index
+ @param vrect - list of rectangles to highlight; add result here
+ @param prgfHighlighted - flags indicating which glyphs have been highlighted, indexed by
+ physical surface position
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::CalcCompleteCluster(int islout,
+ std::vector<Rect> & vrs, std::vector<bool> & vfEntireHt, bool * prgfHighlighted)
+{
+ //GrEngine * pgreng = m_pseg->EngineImpl();
+
+ GrSlotOutput * pslout = m_pseg->OutputSlot(islout);
+ if (pslout->ClusterRange() == 0)
+ return;
+
+ int iginfDraw = m_pseg->LogicalToPhysicalSurface(islout);
+ if (!prgfHighlighted[iginfDraw])
+ return;
+
+ bool fAllHighlighted = true;
+
+ std::vector<int> visloutCluster;
+ m_pseg->ClusterMembersForGlyph(islout, pslout->ClusterRange(), visloutCluster);
+ for (size_t i = 0; i < visloutCluster.size(); i++)
+ {
+ int iginfMemberDraw = m_pseg->LogicalToPhysicalSurface(visloutCluster[i]);
+ if (!prgfHighlighted[iginfMemberDraw])
+ {
+ fAllHighlighted = false;
+ break;
+ }
+ }
+
+ if (!fAllHighlighted)
+ return;
+
+ // All the members of this cluster are highlighted.
+
+ float xsGlyphStart = m_pseg->GlyphLeftEdge(iginfDraw);
+
+ Rect rsNew;
+ rsNew.top = 0;
+ rsNew.bottom = m_pseg->m_dysHeight;
+ rsNew.left = xsGlyphStart + pslout->ClusterXOffset();
+ rsNew.right = xsGlyphStart + pslout->ClusterAdvance();
+ vrs.push_back(rsNew);
+
+ vfEntireHt.push_back(true);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add the given rectangle to the vector, eliminating any overlapping areas.
+
+ Note this method can be recursive: if we have to break the current rectangle into
+ two, we'll call the method again the for new
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::AddRectWithoutOverlaps(std::vector<Rect> & vrect, Rect rectToAdd)
+{
+ std::vector<Rect> vrectMoreToAdd;
+
+ bool fAnythingToAdd = AnyArea(&rectToAdd);
+
+ size_t irect;
+ for (irect = 0; irect < vrect.size(); irect++)
+ {
+ bool f = AdjustRectsToNotOverlap(vrect, irect, &rectToAdd, vrectMoreToAdd);
+ if (!AnyArea(&vrect[irect]))
+ {
+ vrect.erase(vrect.begin() + irect);
+ irect--;
+ }
+ if (!f)
+ {
+ fAnythingToAdd = false;
+ break;
+ }
+ }
+
+ // Now rectToAdd is in a state that it does not intersect with any other rectangles
+ // in the list.
+
+ if (fAnythingToAdd)
+ vrect.push_back(rectToAdd);
+
+ // Add in any extra rectangles that are needed to handle overlaps.
+
+ for (irect = 0; irect < vrectMoreToAdd.size(); irect++)
+ AddRectWithoutOverlaps(vrect, vrectMoreToAdd[irect]);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the rectangle has an area greater than 0.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AnyArea(Rect * prect)
+{
+ Assert(prect->left <= prect->right);
+ Assert(prect->top <= prect->bottom);
+
+ return (prect->left < prect->right && prect->top < prect->bottom);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Adjust the rectangle prect2 to avoid overlaps with the given one in the vector.
+ Return false if the rectangle does not need to be added after all.
+
+ If we have to split this rectangle into two, add the second one to vrectMoreToAdd, so
+ we can do the same process on it.
+
+ If we can merge the two rectangles, add the result to vrectMoreToAdd (so it can be properly
+ checked for further overlaps), and adjust the rectangle in the vector so it will be
+ deleted.
+
+ @param vrect - current list of valid rectangles
+ @param irect - item in vrect we're comparing with prect2
+ @param prect2 - rectangle to add
+ @param vrectMoreToAdd - list of accumulated rectangles that need to be added
+ (caused by splitting one into two)
+
+ @return True if we want to add prect2 (possibly adjusted) to the list;
+ false it it is completely subsumed by vrect[irect], or has been merged with it,
+ or has no area.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AdjustRectsToNotOverlap(std::vector<Rect> & vrect, int irect, Rect * prect2,
+ std::vector<Rect> & vrectMoreToAdd)
+{
+ Rect * prect1 = &(vrect[irect]);
+
+ float xLeft1 = prect1->left;
+ float xRight1 = prect1->right;
+ float yTop1 = prect1->top;
+ float yBottom1 = prect1->bottom;
+ Assert(xLeft1 < xRight1);
+ Assert(yTop1 < yBottom1);
+
+ float xLeft2 = prect2->left;
+ float xRight2 = prect2->right;
+ float yTop2 = prect2->top;
+ float yBottom2 = prect2->bottom;
+ Assert(xLeft2 <= xRight2);
+ Assert(yTop2 <= yBottom2);
+
+ if (!AnyArea(prect2))
+ return false;
+
+ // No overlap: keep both as they are.
+ if (yBottom2 < yTop1 || yBottom1 < yTop2)
+ return true;
+ if (xRight2 < xLeft1 || xRight1 < xLeft2)
+ return true;
+
+ // Present rect subsumes new: ignore new
+ if (xLeft1 <= xLeft2 && xRight2 <= xRight1 && yTop1 <= yTop2 && yBottom2 <= yBottom1)
+ return false;
+
+ // New rect subsumes present: replace.
+ if (xLeft2 <= xLeft1 && xRight1 <= xRight2 && yTop2 <= yTop1 && yBottom1 <= yBottom2)
+ {
+ prect1->bottom = prect1->top; // delete
+ return true; // keep this one
+ }
+
+ // Abutting rectangles of same height or width: merge.
+ if (yTop1 == yTop2 && yBottom1 == yBottom2)
+ {
+ if (xRight1 == xLeft2)
+ {
+ // prect2 is to the right
+ prect2->left = prect1->left;
+ vrectMoreToAdd.push_back(*prect2);
+ prect1->bottom = prect1->top; // delete previous
+ return false;
+ }
+ else if (xRight2 == xLeft1)
+ {
+ // prect2 is to the left
+ prect2->right = prect1->right;
+ vrectMoreToAdd.push_back(*prect2);
+ prect1->bottom = prect1->top; // delete
+ return false;
+ }
+ }
+ if (xLeft1 == xLeft2 && xRight1 == xRight2)
+ {
+ if (yBottom1 == yTop2)
+ {
+ // prect2 is below
+ prect2->top = prect1->top;
+ vrectMoreToAdd.push_back(*prect2);
+ prect1->bottom = prect1->top; // delete
+ return false;
+ }
+ else if (yBottom2 == yTop1)
+ {
+ // prect2 is above
+ prect2->bottom = prect1->bottom;
+ vrectMoreToAdd.push_back(*prect2);
+ prect1->bottom = prect1->top; // delete
+ return false;
+ }
+ }
+
+ // Abutting rectangles of different heights or widths: leave as they are.
+ if (xRight1 == xLeft2 || xRight2 == xLeft1)
+ return true;
+ if (yBottom1 == yTop2 || yBottom2 == yTop1)
+ return true;
+
+ // Overlapping on one axis: adjust smaller rectangle
+ if (yTop1 <= yTop2 && yBottom2 <= yBottom1)
+ {
+ if (xLeft1 <= xLeft2 && xLeft2 < xRight1)
+ {
+ Assert(xRight1 < xRight2); // otherwise rect2 is subsumed
+ prect2->left = prect1->right;
+ return true;
+ }
+ else if (xLeft1 < xRight2 && xRight2 <= xRight1)
+ {
+ Assert(xLeft2 < xLeft1); // otherwise rect2 is subsumed
+ prect2->right = prect1->left;
+ return true;
+ }
+ }
+ else if (yTop2 <= yTop1 && yBottom1 <= yBottom2)
+ {
+ if (xLeft2 <= xLeft1 && xLeft1 < xRight2)
+ {
+ Assert(xRight2 < xRight1); // otherwise rect1 is subsumed
+ prect1->left = prect2->right;
+ return true;
+ }
+ else if (xLeft2 < xRight1 && xRight1 <= xRight2)
+ {
+ Assert(xLeft1 < xLeft2); // otherwise rect1 is subsumed
+ prect1->right = prect2->left;
+ return true;
+ }
+ }
+
+ if (xLeft1 <= xLeft2 && xRight2 <= xRight1)
+ {
+ if (yTop1 <= yTop2 && yTop2 < yBottom1)
+ {
+ Assert(yBottom1 < yBottom2); // otherwise rect2 is subsumed
+ prect2->top = prect1->bottom;
+ return true;
+ }
+ else if (yTop1 < yBottom2 && yBottom2 <= yBottom1)
+ {
+ Assert(yTop2 < yTop1); // otherwise rect2 is subsumed
+ prect2->bottom = prect1->top;
+ return true;
+ }
+ }
+ else if (xLeft2 <= xLeft1 && xRight1 <= xRight2)
+ {
+ if (yTop2 <= yTop1 && yTop1 < yBottom2)
+ {
+ Assert(yBottom2 < yBottom1); // otherwise rect1 is subsumed
+ prect1->top = prect2->bottom;
+ return true;
+ }
+ else if (yTop2 < yBottom1 && yBottom1 <= yBottom2)
+ {
+ Assert(yTop1 < yTop2); // otherwise rect1 is subsumed
+ prect1->bottom = prect2->top;
+ return true;
+ }
+ }
+
+ // Centers overlap: break prect2 into two disjoint rectangles.
+ if (xLeft1 < xLeft2 && xRight2 < xRight1 && yTop2 < yTop1 && yBottom1 < yBottom2)
+ {
+ // create a new rectangle for the bottom of prect2 that is below prect1
+ Rect rectNew = *prect2;
+ rectNew.top = prect1->bottom;
+ prect2->bottom = prect1->top;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+ else if (xLeft2 < xLeft1 && xRight1 < xRight2 && yTop1 < yTop2 && yBottom2 < yBottom1)
+ {
+ // create a new rectangle for the right of prect2 that is to the right of prect1
+ Rect rectNew = *prect2;
+ rectNew.left = prect1->right;
+ prect2->right = prect1->left;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+
+ // Corners overlap: break prect2 into two adjacent rectangles.
+ if (xLeft1 < xLeft2 && xRight1 < xRight2)
+ {
+ // prect2 is partially to the right
+ if (yTop1 < yTop2 && yBottom1 < yBottom2)
+ {
+ // prect2 is partially below
+ Rect rectNew = *prect2;
+ rectNew.left = prect1->right;
+ prect2->top = prect1->bottom;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+ else if (yTop2 < yTop1 && yBottom2 < yBottom1)
+ {
+ // prect2 is partially above
+ Rect rectNew = *prect2;
+ rectNew.left = prect1->right;
+ prect2->bottom = prect1->top;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+ }
+ else if (xLeft2 < xLeft1 && xRight2 < xRight1)
+ {
+ // prect2 is partially to the left
+ if (yTop1 < yTop2 && yBottom1 < yBottom2)
+ {
+ // prect2 is partially below
+ Rect rectNew = *prect2;
+ rectNew.right = prect1->left;
+ prect2->top = prect1->bottom;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+ else if (yTop2 < yTop1 && yBottom2 < yBottom1)
+ {
+ // prect2 is partially above
+ Rect rectNew = *prect2;
+ rectNew.right = prect1->left;
+ prect2->bottom = prect1->top;
+ vrectMoreToAdd.push_back(rectNew);
+ return true;
+ }
+ }
+
+ // No overlap.
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Assert that there are no overlaps among all the rectangles in the array, which should
+ be the case if AdjustRectsToNotOverlap is working properly.
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::AssertNoOverlaps(std::vector<Rect> & vrect)
+{
+#ifdef _DEBUG
+ for (int irect1 = 0; irect1 < signed(vrect.size() - 1); irect1++)
+ {
+ for (int irect2 = irect1 + 1; irect2 < signed(vrect.size()); irect2++)
+ {
+ float xLeft1 = vrect[irect1].left;
+ float xRight1 = vrect[irect1].right;
+ float yTop1 = vrect[irect1].top;
+ float yBottom1 = vrect[irect1].bottom;
+ Assert(xLeft1 < xRight1);
+ Assert(yTop1 < yBottom1);
+
+ float xLeft2 = vrect[irect2].left;
+ float xRight2 = vrect[irect2].right;
+ float yTop2 = vrect[irect2].top;
+ float yBottom2 = vrect[irect2].bottom;
+ Assert(xLeft2 <= xRight2);
+ Assert(yTop2 <= yBottom2);
+
+ Assert(xRight1 <= xLeft2 || xRight2 <= xLeft1 ||
+ yBottom1 <= yTop2 || yBottom2 <= yTop1);
+ }
+ }
+#endif
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add the given line segment to the vector, eliminating any overlapping areas.
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::AddLineSegWithoutOverlaps(std::vector<LineSeg> & vls, LineSeg lsToAdd)
+{
+ std::vector<LineSeg> vlsMoreToAdd;
+
+ bool fAnythingToAdd = AnyLength(&lsToAdd);
+
+ size_t ils;
+ for (ils = 0; ils < vls.size(); ils++)
+ {
+ bool f = AdjustLineSegsToNotOverlap(vls, ils, &lsToAdd, vlsMoreToAdd);
+ if (!AnyLength(&vls[ils]))
+ {
+ vls.erase(vls.begin() + ils);
+ ils--;
+ }
+ if (!f)
+ {
+ fAnythingToAdd = false;
+ break;
+ }
+ }
+
+ // Now lsToAdd is in a state that it does not overlap with any other line segments
+ // in the list.
+
+ if (fAnythingToAdd)
+ vls.push_back(lsToAdd);
+
+ // Add in any extra line segments that are needed to handle overlaps.
+
+ for (ils = 0; ils < vlsMoreToAdd.size(); ils++)
+ AddLineSegWithoutOverlaps(vls, vlsMoreToAdd[ils]);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the rectangle has an area greater than 0.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AnyLength(LineSeg * pls)
+{
+ Assert(pls->left <= pls->right);
+ return (pls->left < pls->right);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Adjust the line segment pls2 to avoid overlaps with the given one in the vector.
+ Return false if the line segment does not need to be added after all.
+
+ If we can merge the two line segments, add the result to vrectMoreToAdd (so it can be properly
+ checked for further overlaps), and adjust the rectangle in the vector so it will be
+ deleted.
+
+ @param vls - current list of valid line segments
+ @param ils - item in vrect we're comparing with pls2
+ @param pls2 - line segment to add
+ @param vlsMoreToAdd - list of accumulated line segments that need to be added
+ (caused by splitting one into two)
+
+ @return True if we want to add pls2 (possibly adjusted) to the list;
+ false it it is completely subsumed by vls[ils], or has been merged with it,
+ or has no length.
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AdjustLineSegsToNotOverlap(std::vector<LineSeg> & vls, int ils, LineSeg * pls2,
+ std::vector<LineSeg> & vlsMoreToAdd)
+{
+ LineSeg * pls1 = &(vls[ils]);
+
+ float xLeft1 = pls1->left;
+ float xRight1 = pls1->right;
+ Assert(xLeft1 < xRight1);
+
+ float xLeft2 = pls2->left;
+ float xRight2 = pls2->right;
+ Assert(xLeft2 <= xRight2);
+
+ if (!AnyLength(pls2))
+ return false;
+
+ // No overlap: keep both as they are.
+ if (xRight2 < xLeft1 || xRight1 < xLeft2)
+ return true;
+
+ // Present line segment subsumes new: ignore new
+ if (xLeft1 <= xLeft2 && xRight2 <= xRight1)
+ return false;
+
+ // New line segment subsumes present: replace.
+ if (xLeft2 <= xLeft1 && xRight1 <= xRight2)
+ {
+ pls1->left = pls1->right; // delete previous
+ return true; // keep this one
+ }
+
+ // Adjacent or partially overlapping line segments: merge.
+ if (xLeft1 <= xLeft2 && xLeft2 <= xRight1 && xRight1 <= xRight2)
+ {
+ pls2->left = xLeft1;
+ vlsMoreToAdd.push_back(*pls2);
+ pls1->left = pls1->right; // delete previous
+ return false;
+ }
+ else if (xLeft2 <= xLeft1 && xLeft1 <= xRight2 && xRight2 <= xRight1)
+ {
+ pls2->right = xRight1;
+ vlsMoreToAdd.push_back(*pls2);
+ pls1->left = pls1->right; // delete previous
+ return false;
+ }
+ else
+ Assert(false);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Assert that there are no overlaps among all the rectangles in the array, which should
+ be the case if AdjustRectsToNotOverlap is working properly.
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::AssertNoOverlaps(std::vector<LineSeg> & vls)
+{
+#ifdef _DEBUG
+ for (int ils1 = 0; ils1 < (int)vls.size() - 1; ils1++)
+ {
+ for (int ils2 = ils1 + 1; ils2 < (int)vls.size(); ils2++)
+ {
+ float xLeft1 = vls[ils1].left;
+ float xRight1 = vls[ils1].right;
+ Assert(xLeft1 < xRight1);
+
+ float xLeft2 = vls[ils2].left;
+ float xRight2 = vls[ils2].right;
+ Assert(xLeft2 <= xRight2);
+
+ Assert(xRight1 <= xLeft2 || xRight2 <= xLeft1);
+ }
+ }
+#endif
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find the next physical location for the IP. Return true if we found one.
+
+ @param pichw - current insertion point, and adjusted result to return
+ @param pfAssocPrev - is the IP "leaning" backwards? adjust to return
+ @param fRight - true if we are moving right
+ @param fAssocPrevMatch - the assoc-prev of the result must match the original selection.
+ This is used when extending range selections; the orientation
+ of the resulting end-point must be the same as previously.
+ This helps avoids circular loops when dealing with reordering.
+ @param fAssocPrevNeeded - value needed for result; ignored if fAssocPrevMatch == false
+ @param pnNextOrPrevSeg - return 1 if we need to try the following segment, -1 if we
+ need to try the previous - CURRENTLY NOT USED for anything
+ practical
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::ArrowKeyPositionInternal(
+ int * pichw, bool * pfAssocPrev,
+ bool fRight, bool fAssocPrevMatch, bool fAssocPrevNeeded, int * pnNextOrPrevSeg)
+{
+ int kBefore = true;
+ int kAfter = false;
+
+ bool fResult = false;
+
+ // Handle ligatures.
+
+ fResult = AdjacentLigComponent(pichw, pfAssocPrev, fRight, true);
+ if (fResult)
+ return true;
+
+ // Not within a ligature, or on the outside edge of one.
+
+ int iginfStart;
+ bool fCharRtl;
+ if (*pfAssocPrev)
+ {
+ iginfStart = m_pseg->UnderlyingToPhysicalSurface(*pichw - 1, kAfter);
+ fCharRtl = m_pseg->CharIsRightToLeft(*pichw - 1, kAfter);
+ }
+ else
+ {
+ iginfStart = m_pseg->UnderlyingToPhysicalSurface(*pichw, kBefore);
+ fCharRtl = m_pseg->CharIsRightToLeft(*pichw, kBefore);
+ }
+ if (kNegInfinity == iginfStart || kPosInfinity == iginfStart)
+ {
+ *pnNextOrPrevSeg = 0;
+ return false;
+ }
+
+ //if (*pfAssocPrev)
+ // fCharRtl ? iginfStart : iginfStart++;
+ //else
+ // fCharRtl ? iginfStart++ : iginfStart;
+
+ if (*pfAssocPrev)
+ iginfStart++;
+
+ // At this point iginfStart indicates the index of the glyph we are before.
+
+ int ichwNewIndex;
+ bool fAPNew;
+
+ bool fRtl = m_pseg->rightToLeft();
+ bool fForward = (fRtl) ? !fRight : fRight;
+ int dir = (fForward) ? 1 : -1;
+ int diginf = 0;
+
+ // When moving forward, we first move to the opposite side of the current glyph,
+ // so initially diginf should be zero.
+ if (fForward)
+ diginf = -1;
+
+ while (true)
+ {
+ diginf++;
+ int iginfTry = iginfStart + (dir * diginf);
+
+ if (iginfTry < 0)
+ {
+ *pnNextOrPrevSeg = -1;
+ return false;
+ }
+ if (iginfTry > m_pseg->m_cginf)
+ {
+ *pnNextOrPrevSeg = 1;
+ return false;
+ }
+ if (iginfTry == m_pseg->m_cginf && fForward)
+ {
+ *pnNextOrPrevSeg = 1;
+ return false;
+ }
+
+ bool fAfter;
+ int ichwTryChar;
+ if (iginfTry == m_pseg->m_cginf)
+ {
+ ichwTryChar = m_pseg->PhysicalSurfaceToUnderlying(iginfTry - 1,
+ kPosInfFloat, kPosInfFloat, 0, 0, &fAfter);
+ }
+ else
+ {
+ ichwTryChar = m_pseg->PhysicalSurfaceToUnderlying(iginfTry,
+ (fRight) ? kPosInfFloat : kNegInfFloat,
+ (fRight) ? kPosInfFloat : kNegInfFloat,
+ 0, 0, &fAfter);
+ }
+
+ if (fAfter)
+ {
+ ichwNewIndex = ichwTryChar + 1;
+ fAPNew = true;
+ }
+ else
+ {
+ ichwNewIndex = ichwTryChar;
+ fAPNew = false;
+ }
+
+ if (ichwNewIndex == *pichw)
+ continue; // didn't make any progress
+
+ LgIpValidResult ipvr = isValidInsertionPoint(ichwNewIndex);
+ if (ipvr == kipvrBad)
+ continue; // bad insertion point
+
+ if (fAssocPrevMatch && (fAssocPrevNeeded != fAPNew))
+ {
+ // Try switching fAPNew and see if that gives the right result
+ bool fAPAlt = !fAPNew;
+ int iginfAlt = m_pseg->UnderlyingToPhysicalSurface(
+ fAPAlt ? ichwTryChar - 1 : ichwTryChar + 1,
+ fAPAlt ? kAfter : kBefore);
+ fCharRtl = m_pseg->CharIsRightToLeft(
+ fAPAlt ? ichwTryChar - 1 : ichwTryChar + 1,
+ fAPAlt ? kAfter : kBefore);
+
+ if (fAPAlt)
+ fCharRtl ? iginfAlt : iginfAlt++;
+ else
+ fCharRtl ? iginfAlt++ : iginfAlt;
+
+ if ((fForward && iginfAlt <= iginfStart)
+ || (!fForward && iginfAlt >= iginfStart))
+ {
+ // Switching fAPNew would cause us to move in the opposite direction, so
+ // that's not a good solution. Keep going.
+ if ((iginfStart == 0 && !fForward) || (iginfStart == m_pseg->m_cginf && fForward))
+ {
+ // Can't go any further, so go with this even though AP is wrong.
+ }
+ else
+ continue;
+ }
+ fAPNew = fAPAlt;
+ }
+ break;
+ }
+
+ // If we have a selection within a ligature, adjust to either the right-most or the
+ // left-most.
+ AdjacentLigComponent(&ichwNewIndex, &fAPNew, fRight, false);
+
+ *pichw = ichwNewIndex;
+ *pfAssocPrev = fAPNew;
+ return true;
+}
+
+/****** OLD VERSION
+bool Segment::ArrowKeyPositionInternal(
+ int * pichw, bool * pfAssocPrev,
+ bool fRight, bool fAssocPrevMatch, bool fAssocPrevNeeded, int * pnNextOrPrevSeg)
+{
+ int kBefore = true;
+ int kAfter = false;
+
+ bool fResult = false;
+
+ // Handle ligatures.
+
+ fResult = AdjacentLigComponent(pichw, pfAssocPrev, fRight, true);
+ if (fResult)
+ return true;
+
+ // Not within a ligature, or on the outside edge of one.
+
+ int igbbOutput;
+ bool fCharRtl;
+ if (*pfAssocPrev)
+ {
+ igbbOutput = UnderlyingToPhysicalSurface(*pichw - 1, kAfter);
+ fCharRtl = CharIsRightToLeft(*pichw - 1, kAfter);
+ }
+ else
+ {
+ igbbOutput = UnderlyingToPhysicalSurface(*pichw, kBefore);
+ fCharRtl = CharIsRightToLeft(*pichw, kBefore);
+ }
+ if (kNegInfinity == igbbOutput || kPosInfinity == igbbOutput)
+ {
+ *pnNextOrPrevSeg = 0;
+ return false;
+ }
+
+ if (*pfAssocPrev)
+ fCharRtl ? igbbOutput : igbbOutput++;
+ else
+ fCharRtl ? igbbOutput++ : igbbOutput;
+
+ bool fBackward = (fRight == m_fWsRtl);
+
+ // Try to find an underlying position that would produce an IP in the expected place.
+ // First look in the same direction in the underlying text, then, if necessary, try the
+ // opposite direction (which may be necessary when reordering occurred).
+
+ int igbbNeed = (fRight) ? igbbOutput + 1 : igbbOutput - 1;
+ int ichwNew;
+ bool fAssocPrevNew;
+
+ while (0 <= igbbNeed && igbbNeed <= NumGbb()) // include end-points--we may need to
+ // be before or after them.
+ {
+ int dichwInc = fBackward ? -1 : 1;
+ int dichwLim = m_ichwMin + (fBackward ? 0 : m_dichwLim);
+
+ int nDirectionsTried = 0;
+// while (nDirectionsTried < 2) -- Nope, for now we are being very strict above moving
+ while (nDirectionsTried < 1) // only in the desired direction
+ {
+ for (int ichwTry = *pichw;
+ ((dichwInc == 1 && ichwTry <= dichwLim) ||
+ (dichwInc == -1 && ichwTry >= dichwLim));
+ ichwTry += dichwInc)
+ {
+ int igbbTry = UnderlyingToPhysicalSurface(ichwTry, kBefore);
+ fCharRtl = CharIsRightToLeft(ichwTry, kBefore);
+ igbbTry = fCharRtl ? igbbTry + 1 : igbbTry;
+ if (igbbTry == igbbNeed &&
+ (ichwTry != *pichw || *pfAssocPrev) &&
+ (!fAssocPrevMatch || !fAssocPrevNeeded))
+ {
+ ichwNew = ichwTry;
+ fAssocPrevNew = false;
+ goto LFixLigatures;
+ }
+
+ igbbTry = UnderlyingToPhysicalSurface(ichwTry - 1, kAfter);
+ fCharRtl = CharIsRightToLeft(ichwTry - 1, kAfter);
+ igbbTry = fCharRtl ? igbbTry : igbbTry + 1;
+ if (igbbTry == igbbNeed &&
+ (ichwTry != *pichw || !*pfAssocPrev) &&
+ (!fAssocPrevMatch || fAssocPrevNeeded))
+ {
+ ichwNew = ichwTry;
+ fAssocPrevNew = true;
+ goto LFixLigatures;
+ }
+ }
+
+ nDirectionsTried++;
+
+ // Didn't find an answer going the expected way; try the opposite direction.
+ dichwInc = (fRight) ? -1 : 1;
+ dichwLim = m_ichwMin + ((fRight) ? 0 : m_dichwLim);
+ }
+
+ // Didn't find an underlying position that would produce an IP in the next glyph;
+ // try the glyph after that.
+
+ igbbNeed = (fRight) ? igbbNeed + 1 : igbbNeed - 1;
+ }
+
+ if (igbbNeed >= NumGbb())
+ *pnNextOrPrevSeg = 1; // try next segment
+ else if (igbbNeed < 0)
+ *pnNextOrPrevSeg = -1; // try previous segment
+ else
+ {
+ Assert(false);
+ *pnNextOrPrevSeg = 0;
+ }
+
+ return false;
+
+LFixLigatures:
+
+ // If we have a selection within a ligature, adjust to either the right-most or the
+ // left-most.
+ AdjacentLigComponent(&ichwNew, &fAssocPrevNew, fRight, false);
+
+ *pichw = ichwNew;
+ *pfAssocPrev = fAssocPrevNew;
+ return true;
+}
+******************/
+
+/*----------------------------------------------------------------------------------------------
+ Return position for the physically next or previous ligature component, or the right-most
+ or left-most. Return true if this routine handled it.
+
+ @param pichw - starting underlying position
+ @param pfAssocPrev - is selection leaning backwards?
+ @param fMovingRight - true if right arrow key was pressed, false if left
+ @param fMove - if true, we want to find the next one over from *pichw;
+ if false, we want to find either the right-most
+ (fMovingRight = false)
+ or the left-most (fMovingRight = true)
+----------------------------------------------------------------------------------------------*/
+bool SegmentPainter::AdjacentLigComponent(int * pichw, bool * pfAssocPrev,
+ bool fMovingRight, bool fMove)
+{
+ int kBefore = true;
+ int kAfter = false;
+
+ GrEngine * pgreng = m_pseg->EngineImpl();
+ GrGlyphTable * pgtbl = (pgreng) ? pgreng->GlyphTable() : NULL;
+
+ if (!pgtbl)
+ {
+ return false;
+ }
+
+ // Find the slot containing the ligature glyph.
+
+ int ichwSegOffset = *pichw - m_pseg->m_ichwMin;
+ int isloutLig = kNegInfinity;
+ if (*pfAssocPrev)
+ {
+ if (ichwSegOffset - 1 >= m_pseg->m_ichwAssocsMin && ichwSegOffset - 1 < m_pseg->m_ichwAssocsLim)
+ isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - 1 - m_pseg->m_ichwAssocsMin];
+ }
+ else
+ {
+ if (ichwSegOffset >= m_pseg->m_ichwAssocsMin && ichwSegOffset < m_pseg->m_ichwAssocsLim)
+ isloutLig = m_pseg->m_prgisloutLigature[ichwSegOffset - m_pseg->m_ichwAssocsMin];
+ }
+
+ if (isloutLig == kNegInfinity)
+ {
+ return false;
+ }
+
+ if (*pfAssocPrev)
+ ichwSegOffset--;
+
+ bool fGlyphRtl = (*pfAssocPrev) ?
+ m_pseg->CharIsRightToLeft(*pichw - 1, kAfter) :
+ m_pseg->CharIsRightToLeft(*pichw, kBefore);
+
+ // Comparing right-sides.
+ bool fIPOnRight = (fGlyphRtl != *pfAssocPrev);
+
+ // When two ligatures are horizontally equal, take vertical position into account.
+ // In left-to-right writing systems, moving right means moving down.
+ bool fMovingDown = (fMovingRight != m_pseg->m_fWsRtl);
+
+ // Get the coordinates for all the ligatures.
+
+ std::vector<float> vysTops;
+ std::vector<float> vysBottoms;
+ std::vector<float> vxsLefts;
+ std::vector<float> vxsRights;
+
+ float ysTopCurr, ysBottomCurr, xsLeftCurr, xsRightCurr;
+ int icompCurr = -1;
+ if (fMovingRight)
+ ysTopCurr = ysBottomCurr = xsLeftCurr = xsRightCurr = kNegInfFloat;
+ else
+ ysTopCurr = ysBottomCurr = xsLeftCurr = xsRightCurr = kPosInfFloat;
+
+ GrSlotOutput * pslout = m_pseg->OutputSlot(isloutLig);
+ //int iginfOutput = m_pseg->LogicalToPhysicalSurface(isloutLig);
+
+ int icomp;
+ for (icomp = 0; icomp < pslout->NumberOfComponents(); icomp++)
+ {
+ float xsLeft, ysTop, xsRight, ysBottom;
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ pgtbl->ComponentBoxLogUnits(m_pseg->m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_pseg->m_mFontEmUnits, m_pseg->m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom);
+
+ vysTops.push_back(ysTop);
+ vysBottoms.push_back(ysBottom);
+ vxsLefts.push_back(xsLeft);
+ vxsRights.push_back(xsRight);
+
+ // If we're moving, record this component as the one we're moving relative to.
+ if (fMove && icomp == m_pseg->m_prgiComponent[ichwSegOffset - m_pseg->m_ichwAssocsMin])
+ {
+ icompCurr = icomp;
+ ysTopCurr = ysTop;
+ ysBottomCurr = ysBottom;
+ xsLeftCurr = xsLeft;
+ xsRightCurr = xsRight;
+ }
+ }
+
+ float xsHorizCurr = (fIPOnRight) ? xsRightCurr : xsLeftCurr;
+ float xsHorizNext;
+
+ // Find the first ligature that is in the proper direction.
+ int icompNext;
+ for (icompNext = 0; icompNext < pslout->NumberOfComponents(); icompNext++)
+ {
+ if (icompNext != icompCurr)
+ {
+ float xsHorizNext = (fIPOnRight) ? vxsRights[icompNext] : vxsLefts[icompNext];
+ if (fMovingRight && xsHorizNext > xsHorizCurr)
+ break;
+ else if (!fMovingRight && xsHorizNext < xsHorizCurr)
+ break;
+ }
+ }
+ if (icompNext == pslout->NumberOfComponents())
+ {
+ bool fResult;
+ // No component in the proper direction. Can we switch to the opposite edge of the
+ // current component?
+ if (fMovingRight && !fIPOnRight)
+ {
+ if (fGlyphRtl)
+ --(*pichw);
+ else
+ ++(*pichw);
+ *pfAssocPrev = !*pfAssocPrev;
+ fResult = true;
+ }
+ else if (!fMovingRight && fIPOnRight)
+ {
+ if (fGlyphRtl)
+ ++(*pichw);
+ else
+ --(*pichw);
+
+ *pfAssocPrev = !*pfAssocPrev;
+ fResult = true;
+ }
+ else
+ fResult = false;
+ return fResult;
+ }
+
+ xsHorizNext = (fIPOnRight) ? vxsRights[icompNext] : vxsLefts[icompNext];
+
+ // Now find the closest one in the proper direction.
+ for (icomp = icompNext + 1; icomp < pslout->NumberOfComponents(); icomp++)
+ {
+ if (icomp != icompCurr)
+ {
+ float xsHorizTry = (fIPOnRight) ? vxsRights[icomp] : vxsLefts[icomp];
+
+ if (fMovingRight && xsHorizTry > xsHorizCurr &&
+ (xsHorizTry < xsHorizNext ||
+ (xsHorizTry == xsHorizNext &&
+ (vysTops[icomp] > vysTops[icompNext]) == fMovingDown)))
+ {
+ icompNext = icomp;
+ xsHorizNext = xsHorizTry;
+ }
+ else if (!fMovingRight && xsHorizTry < xsHorizCurr &&
+ (xsHorizTry > xsHorizNext ||
+ (xsHorizTry == xsHorizNext &&
+ (vysTops[icomp] > vysTops[icompNext]) == fMovingDown)))
+ {
+ icompNext = icomp;
+ xsHorizNext = xsHorizTry;
+ }
+ }
+ }
+
+ *pichw = pslout->FirstUnderlyingComponent(icompNext) + m_pseg->m_ichwMin; // TODO: handle multiple components per ligature
+ if (*pfAssocPrev)
+ ++(*pichw);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Scale the x-coordinate by the scaling factors for this painter.
+----------------------------------------------------------------------------------------------*/
+float SegmentPainter::ScaleX(float xs, Rect rs, Rect rd)
+{
+ //return rs.MapXTo(xs, rd);
+
+ float dxs = rs.right - rs.left;
+ float dxd = rd.right - rd.left;
+ Assert(dxs > 0);
+ if (dxs == dxd)
+ return xs + rd.left - rs.left;
+
+ float xd = rd.left + GrEngine::GrFloatMulDiv((xs - rs.left), dxd, dxs);
+ return xd;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Scale the y-coordinate by the scaling factors for this painter.
+----------------------------------------------------------------------------------------------*/
+float SegmentPainter::ScaleY(float ys, Rect rs, Rect rd)
+{
+ //return rs.MapYTo(ys, rd);
+
+ float dys = rs.bottom - rs.top;
+ float dyd = rd.bottom - rd.top;
+ Assert(dys > 0);
+ if (dys == dyd)
+ return ys + rd.top - rs.top;
+ float yd = rd.top + GrEngine::GrFloatMulDiv((ys - rs.top), dyd, dys);
+ return yd;
+}
+
+
+//:>********************************************************************************************
+//:> Low-level platform-specific drawing methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Make sure the font is set to use the character properties required by this segment.
+----------------------------------------------------------------------------------------------*/
+void SegmentPainter::SetFontProps(unsigned long clrFore, unsigned long clrBack)
+{
+ return;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.cpp
new file mode 100644
index 00000000000..69be6b408c3
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.cpp
@@ -0,0 +1,266 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FileInput.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Contains the functions for reading from a TT file. (These are functions, not methods
+ associated with a class.)
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+
+#include "GrCommon.h"
+#include "GrData.h"
+#ifndef _WIN32
+#include "GrMstypes.h"
+#endif
+#include "GrDebug.h"
+#include <fstream>
+#include <iostream>
+#include <string>
+#include "FileInput.h"
+#include "GrResult.h"
+
+//#ifndef _MSC_VER
+//#include "config.h"
+//#endif
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods of GrBufferIStream
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Constructor.
+----------------------------------------------------------------------------------------------*/
+GrBufferIStream::GrBufferIStream()
+{
+ m_pbStart = NULL;
+ m_pbNext = NULL;
+ m_pbLim = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructor.
+----------------------------------------------------------------------------------------------*/
+GrBufferIStream::~GrBufferIStream()
+{
+ Close();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the stream.
+----------------------------------------------------------------------------------------------*/
+#ifdef GR_FW
+bool GrBufferIStream::Open(std::wstring stuFileName, int kMode)
+#else
+bool GrBufferIStream::Open(const char * pcFileName, std::ios::openmode kMode)
+#endif
+{
+ Assert(false); // use OpenBuffer
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the stream to a buffer.
+----------------------------------------------------------------------------------------------*/
+bool GrBufferIStream::OpenBuffer(const byte * pbBuffer, int cb)
+{
+ Assert(m_pbStart == NULL);
+ Assert(m_pbNext == NULL);
+ Assert(m_pbLim == NULL);
+
+ m_pbStart = pbBuffer;
+ m_pbNext = pbBuffer;
+ if (cb > 0)
+ m_pbLim = m_pbStart + cb;
+ // otherwise we don't know the length
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Close the stream.
+----------------------------------------------------------------------------------------------*/
+void GrBufferIStream::Close()
+{
+ m_pbStart = NULL;
+ m_pbNext = NULL;
+ m_pbLim = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read a byte from the stream.
+----------------------------------------------------------------------------------------------*/
+byte GrBufferIStream::ReadByteFromFont()
+{
+ byte bInput = *m_pbNext;
+ m_pbNext += isizeof(byte);
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+ return bInput;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read a short (signed 16-bit) word from the stream. Switch the bytes from big-endian
+ to little-endian format.
+----------------------------------------------------------------------------------------------*/
+short GrBufferIStream::ReadShortFromFont()
+{
+ short snInput = *(const short *)m_pbNext;
+ m_pbNext += isizeof(short);
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+ snInput = lsbf(snInput);
+ return snInput;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read a wide character (unsigned 16-bit word) from the stream.
+ Switch the bytes from big-endian to little-endian format.
+----------------------------------------------------------------------------------------------*/
+utf16 GrBufferIStream::ReadUShortFromFont()
+{
+ utf16 chwInput = *(const utf16 *)m_pbNext;
+ m_pbNext += isizeof(utf16);
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+ chwInput = lsbf(chwInput);
+ return chwInput;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read a standard (32-bit) word from the stream. Switch the bytes from big-endian
+ to little-endian format.
+----------------------------------------------------------------------------------------------*/
+int GrBufferIStream::ReadIntFromFont()
+{
+ int nInput = *(const int *)m_pbNext;
+ m_pbNext += isizeof(int);
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+ nInput = lsbf(nInput);
+ return nInput;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read a block of data from the stream. DON'T switch the bytes from big-endian
+ to little-endian format.
+----------------------------------------------------------------------------------------------*/
+void GrBufferIStream::ReadBlockFromFont(void * pvInput, int cb)
+{
+ std::copy(m_pbNext, m_pbNext + cb, reinterpret_cast<byte*>(pvInput));
+ m_pbNext += cb;
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the absolute position of the font-file stream (relative to the beginning of
+ the file). For buffers, we just return the byte position in the buffer.
+----------------------------------------------------------------------------------------------*/
+void GrBufferIStream::GetPositionInFont(long * plPos)
+{
+ *plPos = (m_pbNext - m_pbStart);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the position of the font-file stream to the given absolute position (relative
+ to the beginning of the file). For buffers, assume the position is relative to the
+ beginning of the buffer.
+----------------------------------------------------------------------------------------------*/
+void GrBufferIStream::SetPositionInFont(long lPos)
+{
+ m_pbNext = m_pbStart + lPos;
+ if (m_pbLim && m_pbNext > m_pbLim)
+ THROW(kresReadFault);
+}
+
+
+//:>********************************************************************************************
+//:> Swap byte order.
+//:>********************************************************************************************
+int swapb(int nArg)
+{
+#if WORDS_BIGENDIAN
+return nArg;
+#else
+ int b1, b2, b3, b4;
+ b1 = ((nArg & 0xFF000000) >> 24) & 0x000000FF; // remove sign extension
+ b2 = ((nArg & 0x00FF0000) >> 8); // & 0x0000FF00;
+ b3 = ((nArg & 0x0000FF00) << 8); // & 0x00FF0000;
+ b4 = ((nArg & 0x000000FF) << 24); // & 0xFF000000;
+ int nRet = b1 | b2 | b3 | b4;
+ return nRet;
+#endif
+}
+
+unsigned int swapb(unsigned int nArg)
+{
+#if WORDS_BIGENDIAN
+return nArg;
+#else
+ int b1, b2, b3, b4;
+ b1 = ((nArg & 0xFF000000) >> 24) & 0x000000FF; // remove sign extension
+ b2 = ((nArg & 0x00FF0000) >> 8); // & 0x0000FF00;
+ b3 = ((nArg & 0x0000FF00) << 8); // & 0x00FF0000;
+ b4 = ((nArg & 0x000000FF) << 24); // & 0xFF000000;
+ int nRet = b1 | b2 | b3 | b4;
+ return nRet;
+#endif
+}
+
+utf16 swapb(utf16 chwArg)
+{
+#if WORDS_BIGENDIAN
+return chwArg;
+#else
+ utf16 b1, b2;
+ b1 = ((chwArg & 0xFF00) >> 8) & 0x00FF; // remove sign extension
+ b2 = ((chwArg & 0x00FF) << 8); // & 0xFF00;
+ utf16 chwRet = b1 | b2;
+ return chwRet;
+#endif
+}
+
+short swapb(short snArg)
+{
+#if WORDS_BIGENDIAN
+return snArg;
+#else
+ short b1, b2;
+ b1 = ((snArg & 0xFF00) >> 8) & 0x00FF; // remove sign extension
+ b2 = ((snArg & 0x00FF) << 8); // & 0xFF00;
+ short snRet = b1 | b2;
+ return snRet;
+#endif
+}
+
+} //namespace gr
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.h
new file mode 100644
index 00000000000..022206b06a4
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FileInput.h
@@ -0,0 +1,104 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FileInput.h
+Responsibility: Sharon Correll
+Last reviewed: not yet
+
+Description:
+ Defines utility functions for reading from a font file.
+----------------------------------------------------------------------------------------------*/
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef FILEINPUT_INCLUDED
+#define FILEINPUT_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+int swapb(int nArg);
+unsigned int swapb(unsigned int nArg);
+utf16 swapb(utf16 chwArg);
+short swapb(short snArg);
+
+// Most significant byte first (converting from least-sig-first):
+inline int msbf(int nArg) { return swapb(nArg); }
+inline unsigned int msbf(unsigned int nArg) { return swapb(nArg); }
+inline utf16 msbf(utf16 chwArg) { return swapb(chwArg); }
+inline short msbf(short chwArg) { return swapb(chwArg); }
+
+// Least significant byte first (converting from most-sig first):
+inline int lsbf(int nArg) { return swapb(nArg); }
+inline unsigned int lsbf(unsigned int nArg) { return swapb(nArg); };
+inline utf16 lsbf(utf16 chwArg) { return swapb(chwArg); }
+inline short lsbf(short chwArg) { return swapb(chwArg); }
+
+class GrIStream
+{
+public:
+ virtual void Close() = 0;
+
+ virtual byte ReadByteFromFont() = 0;
+ virtual short ReadShortFromFont() = 0;
+ virtual utf16 ReadUShortFromFont() = 0;
+ virtual int ReadIntFromFont() = 0;
+ virtual void ReadBlockFromFont(void * pvInput, int cb) = 0;
+
+ virtual void GetPositionInFont(long * plPos) = 0;
+ virtual void SetPositionInFont(long lPos) = 0;
+
+ virtual bool OpenBuffer(const byte * pbBuffer, int cb) = 0;
+ virtual void CloseBuffer() = 0;
+
+protected:
+ virtual ~GrIStream() {}
+};
+
+
+/*----------------------------------------------------------------------------------------------
+ A stream that reads from a buffer rather than a file.
+----------------------------------------------------------------------------------------------*/
+class GrBufferIStream : public GrIStream
+{
+public:
+ GrBufferIStream();
+ ~GrBufferIStream();
+
+ #ifdef GR_FW
+ virtual bool Open(std::wstring stuFileName, std::ios::openmode kMode);
+ #else
+ virtual bool Open(const char * pcFileName, std::ios::openmode kMode);
+ #endif
+ virtual void Close();
+
+ virtual byte ReadByteFromFont();
+ virtual short ReadShortFromFont();
+ virtual utf16 ReadUShortFromFont();
+ virtual int ReadIntFromFont();
+ virtual void ReadBlockFromFont(void * pvInput, int cb);
+
+ virtual void GetPositionInFont(long * plPos);
+ virtual void SetPositionInFont(long lPos);
+
+ virtual bool OpenBuffer(const byte * pbBuffer, int cb);
+ virtual void CloseBuffer()
+ {
+ Close();
+ }
+
+protected:
+ const byte * m_pbStart;
+ const byte * m_pbNext;
+ const byte * m_pbLim;
+};
+
+} // namespace gr
+
+#endif // !FILEINPUT_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.cpp
new file mode 100644
index 00000000000..f0540463e3b
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.cpp
@@ -0,0 +1,308 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FontCache.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ A cache of all the font-face objects.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ Store the given font-face in the cache. Overwrite whatever was there before.
+ Return NULL if there is nothing appropriate there.
+----------------------------------------------------------------------------------------------*/
+void FontCache::GetFontFace(std::wstring strFaceName, bool fBold, bool fItalic,
+ FontFace ** ppfface)
+{
+ int ifci = FindCacheItem(strFaceName);
+ if (ifci < 0) // no fonts of that family present
+ {
+ *ppfface = NULL;
+ return;
+ }
+
+ CacheItem * pfci = m_prgfci + ifci;
+ if (fBold)
+ {
+ if (fItalic)
+ *ppfface = pfci->pffaceBI;
+ else
+ *ppfface = pfci->pffaceBold;
+ }
+ else
+ {
+ if (fItalic)
+ *ppfface = pfci->pffaceItalic;
+ else
+ *ppfface = pfci->pffaceRegular;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Store the given font-face in the cache. Overwrite whatever was there before.
+----------------------------------------------------------------------------------------------*/
+void FontCache::CacheFontFace(std::wstring strFaceName, bool fBold, bool fItalic,
+ FontFace * pfface)
+{
+ if (m_prgfci == NULL)
+ Initialize();
+
+ int ifciIns = FindCacheItem(strFaceName);
+ int ifci = ifciIns;
+ if (ifciIns < 0)
+ {
+ ifci = (ifciIns + 1) * -1;
+ InsertCacheItem(ifci);
+ std::copy(strFaceName.c_str(), strFaceName.c_str() +
+ (strFaceName.size() + 1), m_prgfci[ifci].szFaceName);
+ }
+
+ CacheItem * pfci = m_prgfci + ifci;
+
+ bool fPrevNull;
+ if (fBold)
+ {
+ if (fItalic)
+ {
+ fPrevNull = (pfci->pffaceBI == NULL);
+ pfci->pffaceBI = pfface;
+ }
+ else
+ {
+ fPrevNull = (pfci->pffaceBold == NULL);
+ pfci->pffaceBold = pfface;
+ }
+ }
+ else
+ {
+ if (fItalic)
+ {
+ fPrevNull = (pfci->pffaceItalic == NULL);
+ pfci->pffaceItalic = pfface;
+ }
+ else
+ {
+ fPrevNull = (pfci->pffaceRegular == NULL);
+ pfci->pffaceRegular = pfface;
+ }
+ }
+
+ if (fPrevNull && (pfface != NULL))
+ m_cfface++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Remove the given font-face from the cache. Return false if it couldn't be found.
+----------------------------------------------------------------------------------------------*/
+bool FontCache::RemoveFontFace(std::wstring strFaceName, bool fBold, bool fItalic,
+ bool fZapCache)
+{
+ int ifci = FindCacheItem(strFaceName);
+ if (ifci < 0)
+ {
+ return false;
+ }
+
+ bool fPrevVal;
+ CacheItem * pfci = m_prgfci + ifci;
+ if (fBold)
+ {
+ if (fItalic)
+ {
+ fPrevVal = (pfci->pffaceBI != NULL);
+ pfci->pffaceBI = NULL;
+ }
+ else
+ {
+ fPrevVal = (pfci->pffaceBold != NULL);
+ pfci->pffaceBold = NULL;
+ }
+ }
+ else
+ {
+ if (fItalic)
+ {
+ fPrevVal = (pfci->pffaceItalic != NULL);
+ pfci->pffaceItalic = NULL;
+ }
+ else
+ {
+ fPrevVal = (pfci->pffaceRegular != NULL);
+ pfci->pffaceRegular = NULL;
+ }
+ }
+
+ if (fPrevVal)
+ m_cfface--;
+
+ Assert(m_cfface >= 0);
+
+ if (m_flush == kflushAuto && fZapCache)
+ {
+ DeleteIfEmpty();
+ }
+
+ return fPrevVal;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Search for the font-family in the cache and return its index.
+ If not present, return a negative number indicating where it was expected.
+----------------------------------------------------------------------------------------------*/
+int FontCache::FindCacheItem(std::wstring strFaceName)
+{
+ if (m_cfci == 0)
+ return -1;
+
+ Assert(m_prgfci);
+
+ // Use a binary-chop search.
+
+ int ifciLow = 0;
+ int ifciHigh = m_cfci;
+ while (true)
+ {
+ int ifciMid = (ifciHigh + ifciLow) >> 1; // divide by 2
+ CacheItem * pfci = m_prgfci + ifciMid;
+ int tst = wcscmp(strFaceName.c_str(), (const wchar_t *)pfci->szFaceName);
+ if (tst == 0)
+ return ifciMid; // found it
+ if (ifciLow + 1 == ifciHigh)
+ {
+ // not there; return where expected: 0 -> -1, 1 -> -2
+ Assert(ifciMid == ifciLow);
+ if (tst < 0)
+ return (ifciLow * -1) - 1;
+ else
+ return (ifciHigh * -1) - 1;
+ }
+
+ // Keep looking.
+ if (tst < 0)
+ ifciHigh = ifciMid;
+ else
+ ifciLow = ifciMid;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Insert space in the cache at location ifci.
+----------------------------------------------------------------------------------------------*/
+void FontCache::InsertCacheItem(int ifci)
+{
+ if (m_cfci == m_cfciMax)
+ {
+ // Cache is full; double the space.
+ CacheItem * m_prgfciOld = m_prgfci;
+ m_prgfci = new CacheItem[m_cfciMax * 2];
+ std::copy(m_prgfciOld, m_prgfciOld + m_cfciMax, m_prgfci);
+ delete[] m_prgfciOld;
+ m_cfciMax *= 2;
+ }
+
+ // This copy involves overlapping ranges, so we need copy_backward not copy
+ // to satisfy the preconditions
+ std::copy_backward(m_prgfci + ifci, m_prgfci + m_cfci, m_prgfci + m_cfci + 1);
+ m_cfci++;
+
+ // Initialize inserted item.
+ CacheItem * pfci = m_prgfci + ifci;
+ pfci->pffaceRegular = NULL;
+ pfci->pffaceBold = NULL;
+ pfci->pffaceItalic = NULL;
+ pfci->pffaceBI = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Delete the cache if it is empty.
+----------------------------------------------------------------------------------------------*/
+void FontCache::DeleteIfEmpty()
+{
+ if (m_cfface <= 0)
+ // All items are NULL; delete this cache. Probably this is because
+ // the program is exiting.
+ FontFace::ZapFontCache();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check that the cache is indeed empty.
+----------------------------------------------------------------------------------------------*/
+void FontCache::AssertEmpty()
+{
+#ifdef _DEBUG
+ for (int ifci = 0; ifci < m_cfci; ifci++)
+ {
+ CacheItem * pfci = m_prgfci + ifci;
+ Assert(pfci->pffaceRegular == NULL);
+ Assert(pfci->pffaceBold == NULL);
+ Assert(pfci->pffaceItalic == NULL);
+ Assert(pfci->pffaceBI == NULL);
+ }
+#endif // _DEBUG
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the flush mode on the cache to indicate whether or not it should be deleted when
+ it becomes empty.
+----------------------------------------------------------------------------------------------*/
+void FontCache::SetFlushMode(int flush)
+{
+ m_flush = flush;
+
+ if (m_flush == kflushAuto)
+ {
+ // Delete any font faces that have no remaining corresponding fonts.
+ // Work backwards so as we remove items the loop still works.
+ for (int ifci = m_cfci; --ifci >= 0; )
+ {
+ CacheItem * pfci = m_prgfci + ifci;
+ if (pfci->pffaceRegular && pfci->pffaceRegular->NoFonts())
+ RemoveFontFace(pfci->szFaceName, false, false, false);
+ if (pfci->pffaceBold && pfci->pffaceBold->NoFonts())
+ RemoveFontFace(pfci->szFaceName, true, false, false);
+ if (pfci->pffaceItalic && pfci->pffaceItalic->NoFonts())
+ RemoveFontFace(pfci->szFaceName, false, true, false);
+ if (pfci->pffaceBI && pfci->pffaceBI->NoFonts())
+ RemoveFontFace(pfci->szFaceName, true, true, false);
+ }
+
+ if (m_cfface <= 0)
+ FontFace::ZapFontCache();
+ }
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.h
new file mode 100644
index 00000000000..56da5ab26b8
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontCache.h
@@ -0,0 +1,105 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FontCache.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ A cache of all the font-face objects known to mankind. There is exactly one instance
+ of a FontCache.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef FONTCACHE_INCLUDED
+#define FONTCACHE_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+class FontFace;
+class FontMemoryUsage;
+
+/*----------------------------------------------------------------------------------------------
+ TODO: change from a sorted list to a hash table, if performance so requires.
+----------------------------------------------------------------------------------------------*/
+class FontCache {
+ friend class FontMemoryUsage;
+
+public:
+ FontCache()
+ {
+ m_cfci = 0;
+ m_prgfci = NULL;
+ m_cfciMax = 0;
+ m_cfface = 0;
+ m_flush = kflushAuto;
+ }
+
+ ~FontCache()
+ {
+ delete[] m_prgfci;
+ m_prgfci = NULL;
+ m_cfci = 0;
+ m_cfciMax = 0;
+ m_cfface = 0;
+ }
+
+ void Initialize()
+ {
+ m_cfci = 0;
+ m_prgfci = new CacheItem[12];
+ m_cfciMax = 12;
+ m_cfface = 0;
+ }
+
+ struct CacheItem
+ {
+ wchar_t szFaceName[32]; // type should match std::wstring
+ FontFace * pffaceRegular;
+ FontFace * pffaceBold;
+ FontFace * pffaceItalic;
+ FontFace * pffaceBI;
+ };
+
+ void GetFontFace(std::wstring strFaceName, bool fBold, bool fItalic, FontFace ** ppfface);
+ void CacheFontFace(std::wstring strFaceName, bool fBold, bool fItalic, FontFace * pfface);
+ bool RemoveFontFace(std::wstring strFaceName, bool fBold, bool fItalic, bool fZapCache = true);
+ void DeleteIfEmpty();
+ void AssertEmpty();
+
+ int GetFlushMode()
+ {
+ return m_flush;
+ }
+ void SetFlushMode(int);
+
+ // Debugging:
+ //bool DbgCheckFontCache();
+
+ void calculateMemoryUsage(FontMemoryUsage & fmu);
+
+protected:
+ int FindCacheItem(std::wstring strFaceName);
+ void InsertCacheItem(int ifci);
+
+protected:
+ // member variables;
+ int m_cfci; // number of items (font-families)
+ int m_cfciMax; // amount of space available
+ int m_cfface; // number of font-faces
+ CacheItem * m_prgfci;
+
+ int m_flush;
+};
+
+} // namespace gr
+
+
+#endif // !FONTCACHE_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.cpp
new file mode 100644
index 00000000000..8750f20c9b4
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.cpp
@@ -0,0 +1,598 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrEngine.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description: Contains the implementation of the FontFace class.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#include <functional>
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+FontCache * FontFace::s_pFontCache = 0;
+
+//:>********************************************************************************************
+//:> New interface
+//:>********************************************************************************************
+/*----------------------------------------------------------------------------------------------
+ Return the appropriate FontFace, initialized with Graphite tables.
+ Called from the font constructor.
+----------------------------------------------------------------------------------------------*/
+FontFace * FontFace::GetFontFace(Font * pfont,
+ std::wstring strFaceName, bool fBold, bool fItalic,
+ bool fDumbFallback)
+{
+ if (s_pFontCache == NULL)
+ s_pFontCache = new FontCache;
+
+ FontFace * pfface;
+ s_pFontCache->GetFontFace(strFaceName, fBold, fItalic, &pfface);
+ if (pfface)
+ return pfface;
+
+ // Create a new font face.
+ pfface = new FontFace();
+ pfface->InitFontFace(pfont, strFaceName, fBold, fItalic, fDumbFallback);
+ return pfface;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the engine using the given Graphite font.
+----------------------------------------------------------------------------------------------*/
+GrResult FontFace::InitFontFace(Font * pfont,
+ std::wstring stuFaceName, bool fBold, bool fItalic,
+ bool fDumbFallback)
+{
+ AssertPtrN(pfont);
+
+ m_pgreng = new GrEngine;
+ m_pgreng->m_pfface = this;
+
+ m_pgreng->m_nScriptTag = 0; // not currently used, but set it to something
+
+ std::wstring stuFeatures;
+
+ //stuFeatures = stuFeaturesArg;
+
+ if (wcscmp(stuFaceName.c_str(), m_pgreng->m_stuFaceName.c_str()) != 0)
+ {
+ s_pFontCache->RemoveFontFace(m_pgreng->FaceName(), m_pgreng->Bold(), m_pgreng->Italic());
+
+ m_pgreng->DestroyEverything(); // nothing we've cached is safe or useful.
+ m_pgreng->m_stuFaceName = stuFaceName; // if this is buggy, using assign might fix it
+ }
+
+ //GrResult res = kresFail;
+//#ifdef GR_FW
+// // Read from the control file indicated by the registry, if any.
+// std::wstring stuFaceNameTmp;
+// stuFaceNameTmp.assign(rgchFaceName, wcslen(rgchFaceName));
+// res = InitFromControlFile(pfont, stuFaceName.c_str(), fBold, fItalic);
+//#endif // GR_FW
+
+ // Read directly from the font.
+ m_pgreng->DestroyContents();
+ GrResult res = kresUnexpected;
+ try {
+ res = m_pgreng->ReadFontTables(pfont, fItalic);
+ }
+ catch (...)
+ {
+ if (fDumbFallback && m_pgreng->DumbFallback() && !m_pgreng->BadFont())
+ {
+ // If we have a basically good font but can't do Graphite,
+ // just go with empty tables, which should be set up.
+ res = m_pgreng->m_resFontRead;
+ }
+ else
+ {
+ if (m_cfonts == 0)
+ {
+ //s_pFontCache->DeleteIfEmpty();
+ //Assert(s_pFontCache == 0);
+ delete this; // will also delete GrEngine
+ }
+ else
+ {
+ delete m_pgreng;
+ }
+ m_pgreng = NULL;
+ throw; // throw original exception
+ }
+ }
+
+ m_pgreng->m_resFontValid = res;
+
+ m_pgreng->m_fBold = fBold;
+ m_pgreng->m_fItalic = fItalic;
+
+ s_pFontCache->CacheFontFace(m_pgreng->FaceName(), fBold, fItalic, this);
+
+ return m_pgreng->m_resFontValid;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the cmap and Graphite tables from the font that is selected into the graphics
+ device.
+
+ @return A GrResult indicating whether we were successful in loading the Graphite font:
+ - kresOk means success
+ - kresFail means the Graphite font could not be found or the basic font tables
+ (head, name, cmap) could not be loaded
+ - kresUnexpected means the Graphite tables could not be loaded
+ - kresFalse means it is not a Graphite font at all (has no Silf table).
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::ReadFontTables(Font * pfont, bool fItalic)
+{
+ GrResult res = kresOk;
+ m_ferr = kferrOkay;
+ GrBufferIStream grstrm;
+
+ FontException fexptn;
+ fexptn.version = -1;
+ fexptn.subVersion = -1;
+
+ bool fOk = false;
+
+ const void * pHeadTbl; const void * pSileTbl; const void * pSilfTbl;
+ const void * pFeatTbl; const void * pGlatTbl; const void * pGlocTbl; const void * pSillTbl;
+ //const void * pCmapTbl; const void * pNameTbl;
+ size_t cbHeadSz, cbSilfSz, cbFeatSz, cbGlatSz, cbGlocSz, cbSillSz;
+ //size_t cbCmapSz, cbSileSz, cbNameSz;
+
+ m_fFakeItalic = false;
+
+ bool fBasicTables = false;
+ bool fSilf = false; // does the font have some sort of Silf table?
+ int nCheckSum = 0;
+
+ bool fBadBase = false,
+ fMismatchedBase = false,
+ fFontIsItalic = false;
+
+ // First read the head table. This gives us the checksum that we are using as a
+ // unique identifer. If it is the same as the one stored, and things appear set up,
+ // don't reload the tables.
+ res = (pHeadTbl = pfont->getTable(TtfUtil::TableIdTag(ktiHead), &cbHeadSz)) ? kresOk : kresFail;
+ fOk = pHeadTbl && (cbHeadSz == 0 || TtfUtil::CheckTable(ktiHead, pHeadTbl, cbHeadSz));
+ if (res == kresFail)
+ {
+ m_stuInitError = L"could not locate head table for Graphite rendering";
+ m_ferr = kferrFindHeadTable;
+ goto LUnexpected;
+ }
+ if (!fOk)
+ {
+ m_stuInitError = L"could not read design units for Graphite rendering";
+ m_ferr = kferrReadDesignUnits;
+ goto LUnexpected;
+ }
+ m_mFontEmUnits = TtfUtil::DesignUnits(pHeadTbl);
+ nCheckSum = TtfUtil::HeadTableCheckSum(pHeadTbl);
+ fFontIsItalic = TtfUtil::IsItalic(pHeadTbl);
+
+ if (m_nFontCheckSum == nCheckSum && m_ptman)
+ return m_resFontRead; // already initialized in some form
+
+ DestroyContents();
+
+ Assert(!m_ptman);
+ Assert(!m_pctbl);
+ Assert(!m_pgtbl);
+ Assert(!m_prgpsd);
+ m_prgpsd = NULL;
+ m_cpsd = 0;
+
+ m_ptman = new GrTableManager(this);
+
+ m_fFakeItalic = (fItalic && !fFontIsItalic);
+
+ // Look for an Sile table. If there is one, this is an extension font containing only
+ // the Graphite tables. Read the base font name out of the Sile table, and use it to
+ // read the cmap. Then replace the original font name to read the Graphite tables.
+
+ m_fUseSepBase = false;
+ m_stuBaseFaceName.erase();
+
+ // TODO: rework the handling of the Sile table.
+ pSileTbl = NULL;
+ //pSileTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSile));
+ //if (pSileTbl)
+ //{
+ // pgg->get_FontCharProperties(&chrpOriginal);
+ // grstrm.OpenBuffer(pSileTbl, sile_tbl.size());
+ // m_fUseSepBase = ReadSileTable(pgg, grstrm, 0, &m_mFontEmUnits, &fMismatchedBase);
+ // grstrm.Close();
+
+ // if (!m_fUseSepBase)
+ // {
+ // SwitchGraphicsFont(pgg, false); // back to Graphite table font
+ // m_stuBaseFaceName.erase();
+ // fBadBase = true;
+ // m_fUseSepBase = false;
+ // }
+ // // Otherwise leave the GrGraphics in a state to read from the base font.
+ //}
+
+ // We don't need the offset table, and there's no way to get it anyway
+ // without a font file.
+
+ // cmap and name
+ Assert(!m_fCmapTblCopy);
+ Assert(!m_fNameTblCopy);
+ fOk = SetCmapAndNameTables(pfont);
+ if (!fOk)
+ {
+ goto LUnexpected;
+ }
+
+ fBasicTables = true;
+
+ // If we have a bad base file, don't do Graphite stuff.
+ if (fBadBase || fMismatchedBase)
+ goto LUnexpected;
+
+ /****
+ Obtain font name from InitNew() now instead of reading from font file. InitNew should
+ should have a correct font name passed to it since it should come from a font registered
+ by GrFontInst.exe. This commented code could be use to verify name in font file matches.
+ NOTE: if we ever use this code again, make sure we're using the base font name table,
+ not the Graphite wrapper font name table.
+ // find the font family name
+ if (!TtfUtil::Get31EngFamilyInfo(vbName.Begin(), lnNameOff, lnNameSz))
+ { // use Name table which is Symbol encode instead
+ // this could cause problems if a real Symbol writing system is used in the name table
+ // however normally real Unicode values are used instead a Symbol writing system
+ if (!TtfUtil::Get30EngFamilyInfo(vbName.Begin(), lnNameOff, lnNameSz))
+ {
+ ReturnResult(kresFail);
+ }
+ // test for Symbol writing system. first byte of Unicode id should be 0xF0
+ if (vbName[lnNameOff + 1] == (unsigned char)0xF0) // 1 - Unicode id is big endian
+ ReturnResult(kresFail);
+ }
+ if (!TtfUtil::SwapWString(vbName.Begin() + lnNameOff, lnNameSz / isizeof(utf16)))
+ ReturnResult(kresFail);
+
+ m_stuFaceName = std::wstring((utf16 *)(vbName.begin() + lnNameOff), lnNameSz / isizeof(utf16));
+ ****/
+
+ // Silf
+ res = (pSilfTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSilf), &cbSilfSz)) ? kresOk : kresFail;
+ fOk = pSilfTbl && (cbSilfSz == 0 || TtfUtil::CheckTable(ktiSilf, pSilfTbl, cbSilfSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Silf table for Graphite rendering";
+ m_ferr = kferrLoadSilfTable;
+ goto LUnexpected;
+ }
+
+ // Feat
+ res = (pFeatTbl = pfont->getTable(TtfUtil::TableIdTag(ktiFeat), &cbFeatSz)) ? kresOk : kresFail;
+ fOk = pFeatTbl && (cbFeatSz == 0 || TtfUtil::CheckTable(ktiFeat, pFeatTbl, cbFeatSz));
+ if (!fOk)
+ {
+ // TODO: just create an empty set of features, since this is not disastrous.
+ m_stuInitError = L"could not load Feat table for Graphite rendering";
+ m_ferr = kferrLoadFeatTable;
+ goto LUnexpected;
+ }
+
+ // Glat
+ res = (pGlatTbl = pfont->getTable(TtfUtil::TableIdTag(ktiGlat), &cbGlatSz)) ? kresOk : kresFail;
+ fOk = pGlatTbl && (cbGlatSz == 0 || TtfUtil::CheckTable(ktiGlat, pGlatTbl, cbGlatSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Glat table for Graphite rendering";
+ m_ferr = kferrLoadGlatTable;
+ goto LUnexpected;
+ }
+
+ // Gloc
+ res = (pGlocTbl = pfont->getTable(TtfUtil::TableIdTag(ktiGloc), &cbGlocSz)) ? kresOk : kresFail;
+ fOk = pGlocTbl && (cbGlocSz == 0 || TtfUtil::CheckTable(ktiGloc, pGlocTbl, cbGlocSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Gloc table for Graphite rendering";
+ m_ferr = kferrLoadGlocTable;
+ goto LUnexpected;
+ }
+
+ // Sill
+ try {
+ res = (pSillTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSill), &cbSillSz)) ? kresOk : kresFail;
+ fOk = pSillTbl && (cbSillSz == 0 || TtfUtil::CheckTable(ktiSill, pSillTbl, cbSillSz));
+ }
+ catch (...)
+ {
+ fOk = true;
+ pSillTbl = NULL;
+ }
+ // if table couldn't be loaded, this is not disastrous.
+
+// ibGlocStart = cbGlatTbl;
+ fOk = CheckTableVersions(&grstrm,
+ (const byte *)pSilfTbl, 0,
+ (const byte *)pGlocTbl, 0,
+ (const byte *)pFeatTbl, 0,
+ &m_fxdBadVersion);
+ if (!fOk)
+ {
+// wchar_t rgch1[50];
+// wchar_t rgch2[50];
+//#if defined(_WIN32)
+// // This version does not work in Windows, in spite of being documented:
+// // swprintf(rgch, 50, L"%d", (m_fxdBadVersion >> 16));
+// // Removing the size argument make it work.
+// swprintf(rgch1, L"%d", (m_fxdBadVersion >> 16));
+// swprintf(rgch2, L"%d", (m_fxdBadVersion & 0x0000FFFF));
+//#else
+// swprintf(rgch1, 50, L"%d", (m_fxdBadVersion >> 16));
+// swprintf(rgch2, 50, L"%d", (m_fxdBadVersion & 0x0000FFFF));
+//#endif
+ char rgch[50]; // more than enough space to print two 16-bit ints
+ char *pch = &rgch[0];
+ sprintf(rgch, "%d.%d", (m_fxdBadVersion >> 16), (m_fxdBadVersion & 0x0000FFFF));
+ std::wstring stu = L"unsupported version (";
+ //stu.append(rgch1);
+ //stu.append(L".");
+ //stu.append(rgch2);
+ while (*pch != 0)
+ stu.push_back((wchar_t)*pch++);
+ stu.append(L") of Graphite tables");
+ m_stuInitError.assign(stu.c_str());
+ m_ferr = kferrBadVersion;
+ goto LUnexpected;
+ }
+
+ try
+ {
+ // Parse the "Silf" table.
+ grstrm.OpenBuffer((const byte*)pSilfTbl, cbSilfSz);
+ int chwGlyphIDMax, fxdVersion;
+ bool f = ReadSilfTable(grstrm, 0, 0, &chwGlyphIDMax, &fxdVersion);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadSilfTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+
+ // Parse the "Gloc" and "Glat" tables.
+ {
+ GrBufferIStream grstrmGlat;
+
+ grstrm.OpenBuffer((const byte *)pGlocTbl, cbGlocSz);
+ grstrmGlat.OpenBuffer((const byte *)pGlatTbl, cbGlatSz);
+ f = ReadGlocAndGlatTables(grstrm, 0, grstrmGlat, 0, chwGlyphIDMax, fxdVersion);
+ grstrm.Close();
+ grstrmGlat.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadGlocGlatTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+ }
+
+ // Parse the "Feat" table.
+ grstrm.OpenBuffer((const byte *)pFeatTbl, cbFeatSz);
+ f = ReadFeatTable(grstrm, 0);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadFeatTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+
+ // Parse the "Sill" table.
+ if (pSillTbl)
+ {
+ grstrm.OpenBuffer((const byte *)pSillTbl, cbFeatSz);
+ f = ReadSillTable(grstrm, 0);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadSillTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+ }
+ else
+ m_langtbl.CreateEmpty();
+ }
+ catch (...)
+ {
+ fSilf = false;
+ m_resFontRead = kresUnexpected;
+ try {
+ DestroyContents(false);
+ }
+ catch (...)
+ {}
+ goto LUnexpected;
+ }
+
+ m_stuErrCtrlFile.erase();
+ m_nFontCheckSum = nCheckSum;
+ m_resFontRead = kresOk;
+ m_ferr = kferrOkay;
+ ReturnResult(kresOk);
+
+LUnexpected:
+ // Don't do this, because it is possible to use a base font with an empty Graphite
+ // engine:
+ //if (m_fUseSepBase || m_stuBaseFaceName.Length() > 0)
+ //{
+ // SwitchGraphicsFont(pgg, false); // back to Graphite table font
+ // m_stuBaseFaceName.erase();
+ // m_fUseSepBase = false;
+ //}
+
+ CreateEmpty();
+ m_nFontCheckSum = nCheckSum;
+ if (!fBasicTables)
+ m_resFontRead = kresFail; // bad font
+ else if (!fSilf)
+ m_resFontRead = kresFalse; // no Silf table--not a Graphite font
+ else
+ m_resFontRead = kresUnexpected; // couldn't read the Graphite tables
+
+ fexptn.errorCode = m_ferr;
+ fexptn.version = m_fxdBadVersion >> 16;
+ fexptn.subVersion = m_fxdBadVersion & 0x0000FFFF;
+ throw fexptn;
+
+ ReturnResult(m_resFontRead);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the cmap and name tables.
+
+ This is called from two places. One is when we first initialize the engine. Also, if the
+ font tables have not been actually copied from the font, they may have been deleted
+ when the font was deleted. So when reusing the engine, set them to something valid based
+ on the current font.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::SetCmapAndNameTables(Font * pfont)
+{
+ GrResult res = kresOk;
+ bool fOk;
+ const void * pCmapTbl;
+ const void * pNameTbl;
+ size_t cbCmapSz, cbNameSz;
+
+ // cmap
+ if (!m_fCmapTblCopy)
+ {
+ res = (pCmapTbl = pfont->getTable(TtfUtil::TableIdTag(ktiCmap), &cbCmapSz)) ? kresOk : kresFail;
+ fOk = pCmapTbl && (cbCmapSz == 0 || TtfUtil::CheckTable(ktiCmap, pCmapTbl, cbCmapSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not locate cmap table";
+ m_ferr = kferrFindCmapTable;
+ return false;
+ }
+
+ if (pCmapTbl && cbCmapSz > 0)
+ {
+ // Make a private copy of the cmap for the engine's use.
+ m_pCmapTbl = new byte[cbCmapSz];
+ std::copy(reinterpret_cast<const byte*>(pCmapTbl),
+ reinterpret_cast<const byte*>(pCmapTbl) + cbCmapSz, m_pCmapTbl);
+ m_fCmapTblCopy = true;
+ m_cbCmapTbl = cbCmapSz;
+ }
+ else
+ {
+ m_pCmapTbl = const_cast<byte*>(reinterpret_cast<const byte*>(pCmapTbl));
+ m_fCmapTblCopy = false;
+ }
+
+ // MS Unicode cmap
+ m_pCmap_3_1 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 1);
+ m_pCmap_3_10 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 10);
+ if (!m_pCmap_3_1)
+ m_pCmap_3_1 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 0);
+ if (!m_pCmap_3_1)
+ {
+ m_stuInitError = L"failure to load cmap subtable";
+ m_ferr = kferrLoadCmapSubtable;
+ return false;
+ }
+ if (!TtfUtil::CheckCmap31Subtable(m_pCmap_3_1))
+ {
+ m_stuInitError = L"checking cmap subtable failed";
+ m_ferr = kferrCheckCmapSubtable;
+ return false;
+ }
+ }
+ else
+ {
+ Assert(m_pCmapTbl);
+ }
+
+ // name table - eventually need feature label strings
+
+ // Currently the only stuff we're getting from the name table are our feature names,
+ // so use the version from the Graphite font (not the base font if any).
+ //////if (m_fUseSepBase)
+ ////// pgg->SetupGraphics(&chrpOriginal);
+
+ if (!m_fNameTblCopy)
+ {
+ res = (pNameTbl = (const byte *)pfont->getTable(TtfUtil::TableIdTag(ktiName), &cbNameSz)) ? kresOk : kresFail;
+ fOk = pNameTbl && (cbNameSz == 0 || TtfUtil::CheckTable(ktiName, pNameTbl, cbNameSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not locate name table";
+ m_ferr = kferrFindNameTable;
+ return false;
+ }
+
+ if (pNameTbl && cbNameSz > 0)
+ {
+ // Make a private copy of the name table for the engine's use.
+ m_pNameTbl = new byte[cbNameSz];
+ std::copy(reinterpret_cast<const byte*>(pNameTbl),
+ reinterpret_cast<const byte*>(pNameTbl) + cbNameSz, m_pNameTbl);
+ m_fNameTblCopy = true;
+ m_cbNameTbl = cbNameSz;
+ }
+ else
+ {
+ m_pNameTbl = const_cast<byte*>(reinterpret_cast<const byte*>(pNameTbl));
+ m_fNameTblCopy = false;
+ }
+ }
+ else
+ {
+ Assert(m_pNameTbl);
+ }
+
+ return true;
+}
+
+
+//void FontFace::DbgCheckFontFace()
+//{
+// Assert(m_cfonts < 5000);
+// Assert(m_cfonts >= 0);
+// wchar_t chw0 = m_pgreng->m_stuFaceName[0];
+// Assert(chw0 >= 0x0040); // A
+// Assert(chw0 <= 0x007A); // z
+//}
+
+} // namespace gr
+
+//:End Ignore
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.h
new file mode 100644
index 00000000000..7f2684a5908
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/FontFace.h
@@ -0,0 +1,246 @@
+/*--------------------------------------------------------------------
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: FontFace.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Contains the definition of the FontFace class.
+ TODO: Merge with GrEngine.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef FONTFACE_INCLUDED
+#define FONTFACE_INCLUDED
+#include <limits>
+
+#ifdef _MSC_VER
+#include <crtdbg.h>
+#endif
+
+namespace gr
+{
+
+class IGrJustifier;
+class Segment;
+
+
+/*----------------------------------------------------------------------------------------------
+ The GrEngine serves as the top level object that knows how to run Graphite tables
+ and generate Graphite segments.
+
+ Primarily, this class implements IRenderEngine, which allows it to serve as a FW
+ rendering engine. It also implements ISimpleInit, a general interface for initializing
+ using a string. Finally, it implements ITraceControl, a very simple interface which
+ allows a client to flip a flag indicating whether or not we want to output a log of
+ the Graphite transduction process.
+
+ Hungarian: greng
+----------------------------------------------------------------------------------------------*/
+class FontFace
+{
+ friend class gr::FontMemoryUsage;
+
+public:
+ FontFace()
+ {
+ m_cfonts = 0;
+ }
+
+ ~FontFace()
+ {
+ if (s_pFontCache)
+ s_pFontCache->RemoveFontFace(m_pgreng->FaceName(), m_pgreng->Bold(), m_pgreng->Italic());
+ delete m_pgreng;
+ }
+
+ void IncFontCount()
+ {
+ m_cfonts++;
+ }
+ void DecFontCount()
+ {
+ m_cfonts--;
+ if (m_cfonts <= 0 && (s_pFontCache == NULL || s_pFontCache->GetFlushMode() == kflushAuto))
+ delete this;
+ }
+
+ bool NoFonts()
+ {
+ return (m_cfonts <= 0);
+ }
+
+ static FontFace * GetFontFace(Font * pfont,
+ std::wstring strFaceName, bool fBold, bool fItalic,
+ bool fDumbFallback = false);
+
+ GrResult InitFontFace(Font * pfont,
+ std::wstring stuFaceName, bool fBold, bool fItalic,
+ bool fDumbLayout);
+
+ FontErrorCode IsValidForGraphite(int * pnVersion, int * pnSubVersion)
+ {
+ return m_pgreng->IsValidForGraphite(pnVersion, pnSubVersion);
+ }
+
+ static void ZapFontCache()
+ {
+ if (s_pFontCache)
+ {
+ s_pFontCache->AssertEmpty();
+ delete s_pFontCache;
+ }
+ s_pFontCache = NULL;
+ }
+
+ static void SetFlushMode(int flush)
+ {
+ if (s_pFontCache == NULL)
+ s_pFontCache = new FontCache;
+ s_pFontCache->SetFlushMode(flush);
+ }
+ static int GetFlushMode()
+ {
+ if (s_pFontCache == NULL)
+ s_pFontCache = new FontCache;
+ return s_pFontCache->GetFlushMode();
+ }
+
+ // Temporary, until interface gets thoroughly reworked:
+ GrEngine * GraphiteEngine()
+ {
+ return m_pgreng;
+ }
+
+ // Feature access:
+ size_t NumberOfFeatures()
+ {
+ return m_pgreng->NumberOfFeatures_ff();
+ }
+ featid FeatureID(size_t ifeat)
+ {
+ return m_pgreng->FeatureID_ff(ifeat);
+ }
+ size_t FeatureWithID(featid id)
+ {
+ return m_pgreng->FeatureWithID_ff(id);
+ }
+ bool GetFeatureLabel(size_t ifeat, lgid language, utf16 * label)
+ {
+ return m_pgreng->GetFeatureLabel_ff(ifeat, language, label);
+ }
+ int GetFeatureDefault(size_t ifeat) // index of default setting
+ {
+ return m_pgreng->GetFeatureDefault_ff(ifeat);
+ }
+ size_t NumberOfSettings(size_t ifeat)
+ {
+ return m_pgreng->NumberOfSettings_ff(ifeat);
+ }
+ int GetFeatureSettingValue(size_t ifeat, size_t ifset)
+ {
+ return m_pgreng->GetFeatureSettingValue_ff(ifeat, ifset);
+ }
+ bool GetFeatureSettingLabel(size_t ifeat, size_t ifset, lgid language, utf16 * label)
+ {
+ return m_pgreng->GetFeatureSettingLabel_ff(ifeat, ifset, language, label);
+ }
+ // Feature-label language access:
+ size_t NumberOfFeatLangs()
+ {
+ return m_pgreng->NumberOfFeatLangs_ff();
+ }
+ short FeatLabelLang(int ilang)
+ {
+ return m_pgreng->GetFeatLabelLang_ff(ilang);
+ }
+ // Language access:
+ size_t NumberOfLanguages()
+ {
+ return m_pgreng->NumberOfLanguages_ff();
+ }
+ isocode LanguageCode(size_t ilang)
+ {
+ return m_pgreng->GetLanguageCode_ff(ilang);
+ }
+
+ // Script Direction access:
+ ScriptDirCode ScriptDirection() const throw()
+ {
+ unsigned int script_dirs = 0;
+ OLECHAR err_dummy = 0;
+ m_pgreng->get_ScriptDirection(&script_dirs, &err_dummy, 1);
+ return ScriptDirCode(script_dirs);
+ }
+
+ bool BadFont(FontErrorCode * pferr = NULL)
+ {
+ return m_pgreng->BadFont(pferr);
+ }
+ bool DumbFallback(FontErrorCode * pferr = NULL)
+ {
+ return m_pgreng->DumbFallback(pferr);
+ }
+
+public:
+ // For use in segment creation:
+ void RenderLineFillSegment(Segment * pseg, Font * pfont, ITextSource * pts,
+ LayoutEnvironment & layout,
+ toffset ichStart, toffset ichStop, float xsMaxWidth, bool fBacktracking)
+ {
+ m_pgreng->MakeSegment(pseg, pfont, pts, NULL, layout,
+ ichStart, ichStop, xsMaxWidth, fBacktracking, false, 0, kestMoreLines);
+ }
+ void RenderRangeSegment(Segment * pseg, Font * pfont,
+ ITextSource * pts, LayoutEnvironment & layout,
+ toffset ichStart, toffset ichStop)
+ {
+ m_pgreng->MakeSegment(pseg, pfont, pts, NULL, layout,
+ ichStart, ichStop, kPosInfFloat, false, false, 0, kestMoreLines);
+ }
+ void RenderJustifiedSegment(Segment * pseg, Font * pfont,
+ ITextSource * pts, LayoutEnvironment & layout,
+ toffset ichStart, toffset ichStop, float xsCurrentWidth, float xsDesiredWidth)
+ {
+ m_pgreng->MakeSegment(pseg, pfont, pts, NULL, layout,
+ ichStart, ichStop, xsCurrentWidth, false, true, xsDesiredWidth, kestMoreLines);
+ }
+
+ // Debugging.
+ //static bool DbgCheckFontCache()
+ //{
+ // if (s_pFontCache)
+ // return s_pFontCache->DbgCheckFontCache();
+ // else
+ // return true;
+ //}
+ //void DbgCheckFontFace();
+
+ static void calculateAllMemoryUsage(FontMemoryUsage & fmu);
+ void calculateMemoryUsage(FontMemoryUsage & fmu);
+
+protected:
+ // Number of fonts in existence that use this face; when it goes to zero, delete.
+ int m_cfonts;
+
+ // Static variable:
+ static FontCache * s_pFontCache;
+
+ // Member variables:
+ GrEngine * m_pgreng;
+};
+
+} // namespace gr
+
+
+#if defined(GR_NO_NAMESPACE)
+using namespace gr;
+#endif
+
+
+#endif // !FONTFACE_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.cpp
new file mode 100644
index 00000000000..20b5a46ab76
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.cpp
@@ -0,0 +1,652 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrCharStream.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the GrCharStream class.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Constructor.
+----------------------------------------------------------------------------------------------*/
+GrCharStream::GrCharStream(ITextSource * pgts, int ichrMin, int ichrLim,
+ bool fStartLine, bool fEndLine)
+ : m_pgts(pgts),
+ m_ichrMin(ichrMin),
+ m_ichrLim(ichrLim),
+ m_ichrPos(ichrMin),
+ m_fStartLine(fStartLine),
+ m_fEndLine(fEndLine),
+ m_cchrBackedUp(0),
+ m_ichrRunMin(0),
+ m_ichrRunLim(0),
+ m_ichlRunOffset(kPosInfinity),
+ m_ichrRunOffset(kPosInfinity)
+{
+ #if 0 // ??? surely m_cnRunMax and m_prgnRunText are undefined at this point
+ if (m_cchlRunMax > -1)
+ delete[] m_prgchlRunText;
+ #endif
+ m_cchlRunMax = -1;
+ m_prgchlRunText = NULL;
+
+ m_vislotNextChunkMap.clear();
+
+ m_utf = m_pgts->utfEncodingForm();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Restart the stream when an error has a occurred and we need to fall back to dumb rendering.
+----------------------------------------------------------------------------------------------*/
+void GrCharStream::Restart()
+{
+ if (m_cchlRunMax > -1)
+ delete[] m_prgchlRunText;
+
+ m_ichrPos = m_ichrMin;
+ m_cchrBackedUp = 0;
+ m_ichrRunMin = 0;
+ m_ichrRunLim = 0;
+ m_ichlRunOffset = kPosInfinity;
+ m_ichrRunOffset = kPosInfinity;
+
+ m_cchlRunMax = -1;
+ m_prgchlRunText = NULL;
+
+ m_vislotNextChunkMap.clear();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the next character from the stream.
+
+ @param pichwSegOffset - index of this character from the beginning of the segment
+ @param pcchRaw - number of raw (UTF-16 or UTF-8) chars consumed to get one complete
+ Unicode codepoint.
+----------------------------------------------------------------------------------------------*/
+int GrCharStream::NextGet(GrTableManager * ptman,
+ GrFeatureValues * pfval, int * pichrSegOffset, int * pcchr)
+{
+ if (AtEnd())
+ {
+ Assert(m_ichrPos == m_ichrLim);
+ return 0;
+ }
+
+ int m_ichrMinBackedUp = m_ichrMin - m_cchrBackedUp;
+
+ if ((m_ichrRunOffset + m_ichrRunMin) >= m_ichrRunLim)
+ {
+ // Get the next run of characters
+
+ std::pair<toffset, toffset> pairRange = m_pgts->propertyRange(m_ichrPos);
+ m_ichrRunMin = pairRange.first;
+ m_ichrRunLim = pairRange.second;
+
+ // The only time the run extends before what we want is on the first run.
+ Assert((m_ichrRunMin == m_ichrPos) // m_ichwPos is beginning of run
+ || (m_ichrPos == m_ichrMinBackedUp)); // first run
+ // Pretend like the run starts where we need it:
+ m_ichrRunMin = max(m_ichrRunMin, m_ichrMinBackedUp);
+ Assert(m_ichrRunMin == m_ichrPos);
+
+ if (m_cchlRunMax != -1 && m_cchlRunMax < m_ichrRunLim - m_ichrRunMin)
+ {
+ // Text buffer is too small: delete it and create a new one.
+ delete[] m_prgchlRunText;
+ m_cchlRunMax = -1;
+ }
+
+ if (m_cchlRunMax == -1)
+ {
+ // Note that combining surrogates or UTF-8 will always result in the same or fewer
+ // number of characters needed in m_prgchlRunText, so the following is safe:
+ m_cchlRunMax = m_ichrRunLim - m_ichrRunMin;
+ m_prgchlRunText = new int[m_cchlRunMax];
+ }
+
+ utf32 * prgchlRunText32 = NULL;
+ utf16 * prgchwRunText16 = NULL;
+ utf8 * prgchsRunText8 = NULL;
+
+ int cchGot;
+ switch (m_utf)
+ {
+ case kutf8:
+ prgchsRunText8 = new utf8[m_ichrRunLim - m_ichrRunMin];
+ cchGot = m_pgts->fetch(m_ichrRunMin, m_ichrRunLim - m_ichrRunMin, prgchsRunText8);
+ break;
+ case kutf16:
+ prgchwRunText16 = new utf16[m_ichrRunLim - m_ichrRunMin];
+ cchGot = m_pgts->fetch(m_ichrRunMin, m_ichrRunLim - m_ichrRunMin, prgchwRunText16);
+ break;
+ default:
+ Assert(false);
+ // Assume UTF-32: fall through
+ case kutf32:
+ prgchlRunText32 = new utf32[m_ichrRunLim - m_ichrRunMin];
+ cchGot = m_pgts->fetch(m_ichrRunMin, m_ichrRunLim - m_ichrRunMin, prgchlRunText32);
+ break;
+ }
+
+ int ichlUtf32 = 0;
+ for (int ichr = 0; ichr < m_ichrRunLim - m_ichrRunMin; ichr++)
+ {
+ if (ichr == m_ichrPos - m_ichrRunMin)
+ {
+ m_ichrRunOffset = ichr;
+ m_ichlRunOffset = ichlUtf32;
+ }
+ Assert(m_ichrRunOffset != kPosInfinity || ichr < m_ichrPos - m_ichrRunMin);
+
+ int cchrUsed;
+ switch (m_utf)
+ {
+ case kutf8:
+ m_prgchlRunText[ichlUtf32] = Utf8ToUtf32(prgchsRunText8 + ichr,
+ m_ichrRunLim - m_ichrRunMin - ichr, &cchrUsed);
+ break;
+ case kutf16:
+ m_prgchlRunText[ichlUtf32] = Utf16ToUtf32(prgchwRunText16 + ichr,
+ m_ichrRunLim - m_ichrRunMin - ichr, &cchrUsed);
+ break;
+ default:
+ Assert(false);
+ // Assume UTF-32: fall through
+ case kutf32:
+ m_prgchlRunText[ichlUtf32] = prgchlRunText32[ichlUtf32];
+ cchrUsed = 1;
+ break;
+ }
+
+ m_vislotNextChunkMap.push_back(ichlUtf32);
+ for (int i = 1; i < cchrUsed; i++)
+ m_vislotNextChunkMap.push_back(-1);
+ ichr += cchrUsed - 1;
+ ichlUtf32++;
+ }
+ delete[] prgchlRunText32;
+ delete[] prgchwRunText16;
+ delete[] prgchsRunText8;
+
+ while (m_ichrLim - m_ichrRunMin < signed(m_vislotNextChunkMap.size())
+ && m_vislotNextChunkMap[m_ichrLim - m_ichrRunMin] == -1)
+ {
+ // Invalid surrogate boundary; this is really a bug in the application program,
+ // but adjust here to avoid a crash!
+ m_ichrLim--;
+ }
+
+ SetUpFeatureValues(ptman, m_ichrPos);
+
+ Assert(m_ichrRunOffset >= 0);
+ Assert(m_ichrRunOffset < m_ichrRunLim - m_ichrRunMin);
+ Assert(m_vislotNextChunkMap.size() == (unsigned) m_ichrRunLim - m_ichrMinBackedUp);
+ }
+
+ int chlRet = m_prgchlRunText[m_ichlRunOffset];
+ *pfval = m_fvalRunFeats;
+ *pichrSegOffset = m_ichrPos - m_ichrMin; // offset from the official start of the segment
+ // of the first 16-bit char
+ int ichrPosPrev = m_ichrPos;
+ ++m_ichlRunOffset;
+ do {
+ ++m_ichrPos;
+ ++m_ichrRunOffset;
+ } while (m_ichrPos - m_ichrMinBackedUp < signed(m_vislotNextChunkMap.size())
+ && m_vislotNextChunkMap[m_ichrPos - m_ichrMinBackedUp] == -1);
+
+ *pcchr = m_ichrPos - ichrPosPrev; // number of raw chars consumed
+ Assert(m_utf != kutf8 || *pcchr <= 6);
+ Assert(m_utf != kutf16 || *pcchr <= 2);
+
+ Assert(m_ichrPos == (m_ichrRunMin + m_ichrRunOffset));
+ Assert(m_ichrPos <= m_ichrLim);
+
+ /* KLUDGE for debugging
+ if (m_ichrPos == 1)
+ nRet = 0x1018;
+ else if (m_ichrPos == 2)
+ nRet = 0x1039;
+ else if (m_ichrPos == 3)
+ nRet = 0x101b;
+ else if (m_ichrPos == 4)
+ nRet = 0x1032;
+ else if (m_ichrPos == 5)
+ nRet = 0x1037;
+ else if (m_ichrPos == 6)
+ nRet = 0x1037;
+ */
+
+ return chlRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert UTF-8 to UTF-32--a single character's worth. Also pass back the number of 8-bit
+ items consumed.
+----------------------------------------------------------------------------------------------*/
+utf32 GrCharStream::Utf8ToUtf32(utf8 * prgchs, int cchs, int * pcchsUsed)
+{
+ if (cchs <= 0)
+ {
+ *pcchsUsed = 0;
+ return 0;
+ }
+
+ long chlRet = DecodeUtf8(prgchs, cchs, pcchsUsed);
+ Assert(chlRet > 0);
+ if (chlRet == -1)
+ {
+ // Some error occurred. Just treat the UTF-8 as UTF-32.
+ *pcchsUsed = 1;
+ return (utf32)prgchs[0];
+ }
+ else
+ return chlRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert UTF-16 to UTF-32--a single character's worth. Also pass back the number of 16-bit
+ items consumed.
+----------------------------------------------------------------------------------------------*/
+utf32 GrCharStream::Utf16ToUtf32(utf16 * prgchw, int cchw, int * pcchwUsed)
+{
+ if (cchw <= 0)
+ {
+ *pcchwUsed = 0;
+ return 0;
+ }
+
+ unsigned int nUtf32;
+ bool fSurrogate = FromSurrogatePair(prgchw[0], ((cchw < 2) ? 0 : prgchw[1]), &nUtf32);
+ *pcchwUsed = (fSurrogate) ? 2 : 1;
+ return (int)nUtf32;
+
+/*
+ // For testing:
+ int nCharRet;
+ if (cchw >= 2 && prgchw[0] == '^' && prgchw[1] == 'a')
+ {
+ nCharRet = 'A';
+ *pcchwUsed = 2;
+ }
+ else if (cchw >= 3 && prgchw[0] == '#' && prgchw[1] == '#' &&
+ prgchw[2] == 'B')
+ {
+ nCharRet = 'b';
+ *pcchwUsed = 3;
+ }
+ else if (cchw >= 1)
+ {
+ nCharRet = prgchw[0];
+ *pcchwUsed = 1;
+ }
+ else
+ {
+ nCharRet = 0;
+ *pcchwUsed = 0;
+ }
+ return nCharRet;
+*/
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the given position is at the boundary of a Unicode character; return false
+ if it is between two parts of pair of surrogates.
+----------------------------------------------------------------------------------------------*/
+bool GrCharStream::AtUnicodeCharBoundary(ITextSource * pgts, int ichr)
+{
+ int cchr = pgts->getLength();
+ if (ichr <= 0 || ichr >= cchr)
+ return true;
+
+ UtfType utf = pgts->utfEncodingForm();
+
+ // Note that we never need more than a handful of characters.
+ int ichrMinGet = max(0, ichr - 1);
+ int ichrLimGet = ichr + 1;
+ utf16 rgchwText16[3];
+ utf8 rgchsText8[3];
+ bool fRet;
+ switch (utf)
+ {
+ case kutf8:
+ pgts->fetch(ichrMinGet, ichrLimGet - ichrMinGet, rgchsText8);
+ fRet = AtUnicodeCharBoundary(rgchsText8, ichrLimGet - ichrMinGet,
+ ichr - ichrMinGet, utf);
+ break;
+ case kutf16:
+ pgts->fetch(ichrMinGet, ichrLimGet - ichrMinGet, rgchwText16);
+ fRet = AtUnicodeCharBoundary(rgchwText16, ichrLimGet - ichrMinGet,
+ ichr - ichrMinGet, utf);
+ break;
+ default:
+ Assert(false);
+ case kutf32:
+ fRet = true;
+ break;
+ }
+
+ return fRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the given position is at the boundary of a Unicode character; return false
+ if it is between two parts of pair of surrogates.
+----------------------------------------------------------------------------------------------*/
+bool GrCharStream::AtUnicodeCharBoundary(utf16 * prgchw, int cchw, int ichr, UtfType utf)
+{
+ Assert(ichr >= 0);
+ Assert(ichr <= cchw);
+
+ if (ichr == 0)
+ return true;
+ if (ichr >= cchw)
+ return true;
+
+ switch (utf)
+ {
+ case kutf16:
+ {
+ unsigned int nUtf32;
+ bool fMiddleOfPair = FromSurrogatePair(prgchw[ichr - 1], prgchw[ichr], &nUtf32);
+ return !fMiddleOfPair;
+ }
+ case kutf8:
+ {
+ // 16-bit buffer being treated like UTF-8.
+ utf8 rgchs[2];
+ rgchs[1] = (utf8)prgchw[ichr];
+ return AtUnicodeCharBoundary(rgchs, 2, 1, kutf8);
+ }
+ case kutf32:
+ default:
+ return true;
+ }
+
+/*
+ // temp stuff for debugging:
+ if (ichr > 0 && cchw >= 1 && prgchw[ichr-1] == '^' && prgchw[ichr] == 'a')
+ {
+ return false;
+ }
+ if (ichr > 0 && cchw >= 2 && prgchw[ichr-1] == '#' && prgchw[ichr] == '#' &&
+ prgchw[ichr+1] == 'B')
+ {
+ return false;
+ }
+ if (ichr > 1 && cchw >= 1 && prgchw[ichr-2] == '#' && prgchw[ichr-1] == '#' &&
+ prgchw[ichr] == 'B')
+ {
+ return false;
+ }
+
+ return true;
+*/
+}
+
+bool GrCharStream::AtUnicodeCharBoundary(utf8 * prgchs, int cchs, int ichs, UtfType utf)
+{
+ Assert(ichs >= 0);
+ Assert(ichs <= cchs);
+
+ Assert(utf == kutf8);
+
+ if (ichs == 0)
+ return true;
+ if (ichs >= cchs)
+ return true;
+
+ if (cchs == 0)
+ return true;
+
+ // A bit pattern of 10xxxxxx indicates a continuation of a sequence
+ // (11xxxxxx means the first byte of a sequence, 0xxxxxxx means a single character).
+
+ utf8 chsTest = prgchs[ichs] & 0xC0;
+ return (chsTest != 0x80);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert the given pair of characters into a single 32-bit Unicode character. Return
+ true if they are a legitimate surrogate pair. If not, just return the first of the
+ two 16-bit characters.
+----------------------------------------------------------------------------------------------*/
+bool GrCharStream::FromSurrogatePair(utf16 chwIn1, utf16 chwIn2, unsigned int * pchlOut)
+{
+ if ((chwIn1 < kzUtf16HighFirst) || (chwIn1 > kzUtf16HighLast)
+ || (chwIn2 < kzUtf16LowFirst) || (chwIn2 > kzUtf16LowLast))
+ {
+ // Not a surrogate
+ *pchlOut = (unsigned int)chwIn1;
+ return false;
+ }
+ else
+ {
+ *pchlOut = ((chwIn1 - kzUtf16HighFirst) << kzUtf16Shift) + chwIn2 + kzUtf16Inc;
+ return true;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Decode 1-6 bytes in the character string from UTF-8 format to Unicode (UCS-4).
+ As a side-effect, cbOut is set to the number of UTF-8 bytes consumed.
+
+ @param rgchUtf8 Pointer to a a character array containing UTF-8 data.
+ @param cchUtf8 Number of characters in the array.
+ @param cbOut Reference to an integer for holding the number of input (8-bit) characters
+ consumed to produce the single output Unicode character.
+
+ @return A single Unicode (UCS-4) character. If an error occurs, return -1.
+----------------------------------------------------------------------------------------------*/
+long GrCharStream::DecodeUtf8(const utf8 * rgchUtf8, int cchUtf8, int * pcbOut)
+{
+ // check for valid input
+ AssertArray(rgchUtf8, cchUtf8);
+ if ((cchUtf8 == 0) || (rgchUtf8[0] == '\0'))
+ {
+ *pcbOut = (cchUtf8) ? 1 : 0;
+ return 0;
+ }
+ //
+ // decode the first byte of the UTF-8 sequence
+ //
+ long lnUnicode;
+ int cbExtra;
+ int chsUtf8 = *rgchUtf8++ & 0xFF;
+ if (chsUtf8 >= kzUtf8Flag6) // 0xFC
+ {
+ lnUnicode = chsUtf8 & kzUtf8Mask6;
+ cbExtra = 5;
+ }
+ else if (chsUtf8 >= kzUtf8Flag5) // 0xF8
+ {
+ lnUnicode = chsUtf8 & kzUtf8Mask5;
+ cbExtra = 4;
+ }
+ else if (chsUtf8 >= kzUtf8Flag4) // 0xF0
+ {
+ lnUnicode = chsUtf8 & kzUtf8Mask4;
+ cbExtra = 3;
+ }
+ else if (chsUtf8 >= kzUtf8Flag3) // 0xE0
+ {
+ lnUnicode = chsUtf8 & kzUtf8Mask3;
+ cbExtra = 2;
+ }
+ else if (chsUtf8 >= kzUtf8Flag2) // 0xC0
+ {
+ lnUnicode = chsUtf8 & kzUtf8Mask2;
+ cbExtra = 1;
+ }
+ else // 0x00
+ {
+ lnUnicode = chsUtf8;
+ cbExtra = 0;
+ }
+ if (cbExtra >= cchUtf8)
+ {
+ return -1;
+ }
+
+ switch (cbExtra)
+ {
+ case 5:
+ lnUnicode <<= kzUtf8ByteShift;
+ chsUtf8 = *rgchUtf8++ & 0xFF;
+ if ((chsUtf8 & ~kzByteMask) != 0x80)
+ return -1;
+ lnUnicode += chsUtf8 & kzByteMask;
+ // fall through
+ case 4:
+ lnUnicode <<= kzUtf8ByteShift;
+ chsUtf8 = *rgchUtf8++ & 0xFF;
+ if ((chsUtf8 & ~kzByteMask) != 0x80)
+ return -1;
+ lnUnicode += chsUtf8 & kzByteMask;
+ // fall through
+ case 3:
+ lnUnicode <<= kzUtf8ByteShift;
+ chsUtf8 = *rgchUtf8++ & 0xFF;
+ if ((chsUtf8 & ~kzByteMask) != 0x80)
+ return -1;
+ lnUnicode += chsUtf8 & kzByteMask;
+ // fall through
+ case 2:
+ lnUnicode <<= kzUtf8ByteShift;
+ chsUtf8 = *rgchUtf8++ & 0xFF;
+ if ((chsUtf8 & ~kzByteMask) != 0x80)
+ return -1;
+ lnUnicode += chsUtf8 & kzByteMask;
+ // fall through
+ case 1:
+ lnUnicode <<= kzUtf8ByteShift;
+ chsUtf8 = *rgchUtf8++ & 0xFF;
+ if ((chsUtf8 & ~kzByteMask) != 0x80)
+ return -1;
+ lnUnicode += chsUtf8 & kzByteMask;
+ break;
+ case 0:
+ // already handled
+ break;
+ default:
+ Assert(false);
+ }
+ if ((unsigned long)lnUnicode > kzUnicodeMax)
+ {
+ return -1;
+ }
+ *pcbOut = cbExtra + 1;
+ return lnUnicode;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the current feature values and character properties from the stream.
+----------------------------------------------------------------------------------------------*/
+void GrCharStream::CurrentFeatures(GrTableManager * ptman, GrFeatureValues * pfval)
+{
+ if (m_ichrRunOffset == kPosInfinity)
+ {
+ // Not yet set up.
+ if (AtEnd())
+ {
+ // Empty stream; no valid values.
+ Assert(false);
+ return;
+ }
+
+ // Get the settings from the first character.
+ int ichrSegOffset;
+ int ichrPosSave = m_ichrPos;
+ int ichrRunOffsetSave = m_ichrRunOffset;
+ int ichlRunOffsetSave = m_ichlRunOffset;
+ int cMapSize = m_vislotNextChunkMap.size();
+ int cchrConsumed;
+ NextGet(ptman, pfval, &ichrSegOffset, &cchrConsumed);
+ // Put the character back.
+ m_ichrPos = ichrPosSave;
+ m_ichrRunOffset = ichrRunOffsetSave;
+ m_ichlRunOffset = ichlRunOffsetSave;
+ while (signed(m_vislotNextChunkMap.size()) > cMapSize)
+ m_vislotNextChunkMap.pop_back();
+ }
+ else
+ {
+ *pfval = m_fvalRunFeats;
+ //*ppchrp = &m_chrpRun;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the feature settings from the text properties.
+
+ Eventually, handle style index here?
+----------------------------------------------------------------------------------------------*/
+void GrCharStream::SetUpFeatureValues(GrTableManager * ptman, int ichr)
+{
+ // Set all the features to their default values.
+ for (int i = 0; i < kMaxFeatures; ++i)
+ {
+ m_fvalRunFeats.m_rgnFValues[i] = ptman->DefaultForFeatureAt(i);
+ }
+ m_fvalRunFeats.m_nStyleIndex = 0;
+
+ // Add in the defaults for the language of the text.
+ std::vector<featid> vnFeats;
+ std::vector<int> vnValues;
+ isocode lgcode = m_pgts->getLanguage(ichr);
+ ptman->DefaultsForLanguage(lgcode, vnFeats, vnValues);
+ size_t ifeatLp;
+ int ifeat;
+ for (ifeatLp = 0; ifeatLp < vnFeats.size(); ifeatLp++)
+ {
+ ptman->FeatureWithID(vnFeats[ifeatLp], &ifeat);
+ m_fvalRunFeats.m_rgnFValues[ifeat] = vnValues[ifeatLp];
+ }
+
+ // Add in the explicit feature settings.
+ FeatureSetting rgfset[kMaxFeatures];
+ int cfeat = m_pgts->getFontFeatures(ichr, rgfset);
+
+ for (ifeatLp = 0; ifeatLp < (size_t)cfeat; ifeatLp++)
+ {
+ ptman->FeatureWithID(rgfset[ifeatLp].id, &ifeat);
+ if (ifeat >= 0)
+ m_fvalRunFeats.m_rgnFValues[ifeat] = rgfset[ifeatLp].value;
+ }
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.h
new file mode 100644
index 00000000000..bb91cf54eba
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrCharStream.h
@@ -0,0 +1,183 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrCharStream.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+
+
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_CHARSTREAM_INCLUDED
+#define GR_CHARSTREAM_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ Makes a stream out of a text string that is serving as input to the process.
+
+ Hungarian: chstrm
+----------------------------------------------------------------------------------------------*/
+class GrCharStream
+{
+public:
+ // Constructor and destructor:
+ GrCharStream(ITextSource * pgts, int ichrMin, int ichrLim,
+ bool fStartLine, bool fEndLine);
+
+ ~GrCharStream()
+ {
+ if (m_cchlRunMax >= 0)
+ delete[] m_prgchlRunText;
+ }
+
+ // Getters:
+ ITextSource * TextSrc() { return m_pgts; }
+ int Min() { return m_ichrMin; }
+ int Pos() { return m_ichrPos; }
+ int Lim() { return m_ichrLim; }
+ bool StartLine() { return m_fStartLine; }
+ bool EndLine() { return m_fEndLine; }
+
+ // offset from the beginning of the segment
+ int SegOffset() { return m_ichrPos - m_ichrMin; }
+ int SegOffset(int ichr) { return ichr - m_ichrMin; }
+
+ bool AtEnd()
+ {
+ return (m_ichrPos >= m_ichrLim);
+ }
+
+ // The input string is empty.
+ bool IsEmpty()
+ {
+ return (m_ichrLim - m_ichrMin == 0);
+ }
+
+ // When we are restarting in order to create a segment other than the first,
+ // back up the position in the stream slightly in order to reprocess a few characters
+ // before the line-break.
+ void Backup(int cchrToReprocess)
+ {
+ Assert(m_ichrPos >= cchrToReprocess);
+ m_ichrPos -= cchrToReprocess;
+ m_ichrRunOffset = kPosInfinity;
+ m_cchrBackedUp = cchrToReprocess;
+ }
+
+ // When we found a hard-break in the input stream, we need to put it back, and since
+ // we're done, we set the end of the stream to that position.
+ void HitHardBreak()
+ {
+ m_ichrPos -= 1;
+ m_ichrRunOffset -= 1;
+ m_ichrLim = m_ichrPos;
+ }
+
+ void Restart();
+
+ int NextGet(GrTableManager *, GrFeatureValues * pfval, int * ichrSegOffset, int * pcchr);
+
+ void CurrentFeatures(GrTableManager * ptman, GrFeatureValues * pfval);
+
+ // For transduction logging:
+ int GetLogData(GrTableManager * ptman, int * rgnChars, bool * rgfNewRun,
+ GrFeatureValues * rgfval, int cchwBackup,
+ int * pcchwMaxRaw);
+ void GetLogDataRaw(GrTableManager * ptman, int cchw, int cchwBackup,
+ int cchwMax16bit, int * prgnChars,
+ utf16 * prgchw2, utf16 * prgchw3, utf16 * prgchw4, utf16 * prgchw5, utf16 * prgchw6,
+ int * prgichwRaw);
+
+protected:
+ void SetUpFeatureValues(GrTableManager * ptman, int ichr);
+public:
+ static utf32 Utf8ToUtf32(utf8 * prgchs8bit, int cchs, int * pcchsUsed);
+ static utf32 Utf16ToUtf32(utf16 * prgchw16bit, int cchw, int * pcchwUsed);
+ bool AtUnicodeCharBoundary(int cchr)
+ {
+ return AtUnicodeCharBoundary(m_pgts, cchr);
+ }
+ static bool AtUnicodeCharBoundary(ITextSource * pgts, int ichr);
+ static bool AtUnicodeCharBoundary(utf8 * prgchs, int cchs, int ichs, UtfType utf);
+ static bool AtUnicodeCharBoundary(utf16 * prgchw, int cchw, int ichr, UtfType utf);
+ static bool FromSurrogatePair(utf16 chwIn1, utf16 chwIn2, unsigned int * pch32Out);
+ static long DecodeUtf8(const utf8 * rgchUtf8, int cchUtf8, int * pcbOut);
+
+protected:
+ // Instance variables:
+ // Hungarian note: chr = raw characters, chl = long characters (UTF-32)
+ // chs = short characters (UTF-8), chw = wide characters (UTF-16)
+ ITextSource * m_pgts; // string to render
+ UtfType m_utf; // what encoding form the text-source uses
+ int m_ichrMin; // official start of segment relative to beginning of string
+ int m_ichrLim; // end of stream (potential end of seg) relative to beginning of string
+ int m_ichrPos; // stream position (0 = start of string)
+ bool m_fStartLine; // true if a line-break character should be prepended
+ bool m_fEndLine; // true if a line-break character should be appended
+ int m_cchrBackedUp; // number of characters backed up before beginning of segment
+
+ // We read a run's worth of data at a time and cache it in the following variables:
+ int m_cchlRunMax; // size of buffer allocated
+ int * m_prgchlRunText; // buffer containing current run
+ int m_ichrRunMin; // start of run relative to beginning of string
+ int m_ichrRunLim; // end of run relative to beginning of string
+ int m_ichlRunOffset; // index into m_prgchlRunText; kPosInfinity if nothing set up
+ int m_ichrRunOffset; // corresponding index into text source
+ GrFeatureValues m_fvalRunFeats;
+
+ std::vector<int> m_vislotNextChunkMap; // maps from 16-bit chars to 32-bit chars & glyphs
+
+ enum
+ {
+ kzUtf8Mask1 = 0x7F,
+ kzUtf8Mask2 = 0x1F,
+ kzUtf8Mask3 = 0x0F,
+ kzUtf8Mask4 = 0x07,
+ kzUtf8Mask5 = 0x03,
+ kzUtf8Mask6 = 0x01
+ };
+
+ enum
+ {
+ kzUtf8Flag1 = 0x00,
+ kzUtf8Flag2 = 0xC0,
+ kzUtf8Flag3 = 0xE0,
+ kzUtf8Flag4 = 0xF0,
+ kzUtf8Flag5 = 0xF8,
+ kzUtf8Flag6 = 0xFC
+ };
+
+ enum
+ {
+ kzByteMask = 0x3F,
+ kzByteMark = 0x80,
+ kzUtf8ByteShift = 6,
+ kzUnicodeMax = 0x7FFFFFFF
+ };
+
+ enum
+ {
+ kzUtf16Shift = 10,
+ kzUtf16Inc = 0x2400,
+ kzUtf16HighFirst = 0xD800,
+ kzUtf16HighLast = 0xDBFF,
+ kzUtf16LowFirst = 0xDC00,
+ kzUtf16LowLast = 0xDFFF
+ };
+};
+
+} // namespace gr
+
+#endif // !GR_CHARSTREAM_INCLUDED
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.cpp
new file mode 100644
index 00000000000..43316fdc04a
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.cpp
@@ -0,0 +1,382 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrClassTable.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the GrClassTable class and related classes.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Fill in by reading from the file stream.
+----------------------------------------------------------------------------------------------*/
+bool GrClassTable::ReadFromFont(GrIStream & grstrm, int fxdVersion)
+{
+ long lClassMapStart;
+ grstrm.GetPositionInFont(&lClassMapStart);
+
+ // number of classes
+ m_ccls = grstrm.ReadUShortFromFont();
+ if (m_ccls >= kMaxReplcmtClasses)
+ return false; // bad table
+ if (fxdVersion < 0x00030000 && m_ccls > kMaxReplcmtClassesV1_2)
+ return false; // bad table
+
+ // number of linear classes
+ m_cclsLinear = grstrm.ReadUShortFromFont();
+ if (m_cclsLinear > m_ccls)
+ return false; // bad table
+
+ // class offsets
+ m_prgichwOffsets = new data16[m_ccls + 1];
+ gAssert(m_prgichwOffsets);
+ if (!m_prgichwOffsets)
+ return false; // bad table
+
+ data16 * pchw = m_prgichwOffsets;
+ int icls;
+ for (icls = 0; icls <= m_ccls; icls++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // Offsets are relative to the start class map; make them relative to the class list
+ // itself, and in terms of utf16s, not bytes.
+ long lClassesPos;
+ grstrm.GetPositionInFont(&lClassesPos);
+ int cbDiff = lClassesPos - lClassMapStart;
+ for (icls = 0; icls <= m_ccls; icls++)
+ {
+ m_prgichwOffsets[icls] = data16(int(m_prgichwOffsets[icls]) - cbDiff);
+ gAssert((m_prgichwOffsets[icls] & 0x00000001) == 0);
+ if ((m_prgichwOffsets[icls] & 0x00000001) != 0)
+ return false; // bad table
+ m_prgichwOffsets[icls] >>= 1; // divide by 2
+ }
+
+ // classes - slurp entire block (data remains in big-endian format)
+ m_prgchwBIGGlyphList = new data16[m_prgichwOffsets[m_ccls]];
+ gAssert(m_prgchwBIGGlyphList);
+ if (!m_prgchwBIGGlyphList)
+ return false; // bad table
+ grstrm.ReadBlockFromFont(m_prgchwBIGGlyphList,
+ m_prgichwOffsets[m_ccls] * isizeof(data16));
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set up an empty class table.
+----------------------------------------------------------------------------------------------*/
+void GrClassTable::CreateEmpty()
+{
+ // number of classes
+ m_ccls = 0;
+ // number of linear classes
+ m_cclsLinear = 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Search for the glyph ID using a fast binary search, and return the matching index.
+----------------------------------------------------------------------------------------------*/
+int GrInputClass::FindIndex(gid16 gid)
+{
+ int digixInit = InitialSearchRange();
+ int igixStart = StartSearch();
+#ifdef _DEBUG
+ int cgix = NumberOfGlyphs();
+ int nPowerOf2 = 1;
+ while (nPowerOf2 <= cgix)
+ nPowerOf2 <<= 1;
+ nPowerOf2 >>= 1;
+ // Now nPowerOf2 is the max power of 2 <= cgix
+ gAssert((1 << LoopCount()) == nPowerOf2); // LoopCount() == log2(nPowerOf2)
+ gAssert(digixInit == nPowerOf2);
+ gAssert(igixStart == cgix - digixInit);
+#endif // _DEBUG
+
+ int digixCurr = digixInit;
+
+ GrGlyphIndexPair * pgixCurr = m_pgixFirst + igixStart;
+ while (digixCurr > 0)
+ {
+ int nTest;
+ if (pgixCurr < m_pgixFirst)
+ nTest = -1;
+ else
+ nTest = pgixCurr->GlyphID() - gid;
+
+ if (nTest == 0)
+ return pgixCurr->Index();
+
+ digixCurr >>= 1; // divide by 2
+ if (nTest < 0)
+ pgixCurr += digixCurr;
+ else // (nTest > 0)
+ pgixCurr -= digixCurr;
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the selector index for the given glyph ID.
+----------------------------------------------------------------------------------------------*/
+int GrClassTable::FindIndex(int icls, gid16 chwGlyphID)
+{
+ if (icls >= m_ccls)
+ {
+ gAssert(false); // bad compiler problem
+ return 0;
+ }
+
+ if (icls < m_cclsLinear)
+ {
+ // The class is an output class--uses linear format--and is being used as an
+ // input class. Shouldn't happen if the compiler is working right.
+ gAssert(false); // comment out for test procedures
+
+ // Do a slow linear search to find the glyph ID.
+ int ichwMin = m_prgichwOffsets[icls];
+ int ichwLim = m_prgichwOffsets[icls+1];
+ int cchw = ichwLim - ichwMin;
+
+ for (int ichw = 0; ichw < cchw; ichw++)
+ {
+ if (GlyphAt(ichwMin + ichw) == chwGlyphID)
+ return ichw;
+ }
+ return -1;
+ }
+
+ // Slurp the class into an instance so we can see what's there.
+ GrInputClass clsin;
+ int ichwMin = m_prgichwOffsets[icls];
+ int ichwLim = m_prgichwOffsets[icls+1];
+ clsin.CopyFrom(GlyphListLoc(ichwMin), (ichwLim - ichwMin));
+
+ // Do a fast binary search to find our glyph.
+ int iRet = clsin.FindIndex(chwGlyphID);
+ return iRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the glyph ID at the selector index.
+----------------------------------------------------------------------------------------------*/
+gid16 GrClassTable::GetGlyphID(int icls, int ichw)
+{
+ if (ichw < 0)
+ {
+ gAssert(false);
+ return 0;
+ }
+
+ if (icls >= m_cclsLinear)
+ {
+ // The class is an input class--sorted by glyph ID--and is being used as an
+ // output class. Shouldn't happen if the compiler is working right.
+ gAssert(false); // comment out for test procedures
+
+ if (icls >= m_ccls) // bad compiler problem
+ return 0;
+
+ // Do a slow linear search to find the index and answer the matching glyph.
+ // Slurp the class into an instance so we can see what's there.
+ GrInputClass clsin;
+ int ichwMin = m_prgichwOffsets[icls];
+ int ichwLim = m_prgichwOffsets[icls+1];
+ clsin.CopyFrom(GlyphListLoc(ichwMin), (ichwLim - ichwMin));
+
+ int cgix = clsin.NumberOfGlyphs();
+ for (int igix = 0; igix < cgix; igix++)
+ {
+ GrGlyphIndexPair * m_pgix = clsin.m_pgixFirst + igix;
+ if (m_pgix->Index() == ichw)
+ return m_pgix->GlyphID();
+ }
+ return 0;
+ }
+
+ int ichwMin = m_prgichwOffsets[icls];
+ int ichwLim = m_prgichwOffsets[icls+1];
+
+ if (ichw >= ichwLim - ichwMin)
+ return 0;
+ else
+ return GlyphAt(ichwMin + ichw);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of glyphs in the class.
+----------------------------------------------------------------------------------------------*/
+int GrClassTable::NumberOfGlyphsInClass(int icls)
+{
+ int ichwMin = m_prgichwOffsets[icls];
+ int ichwLim = m_prgichwOffsets[icls+1];
+
+ if (icls >= m_cclsLinear)
+ {
+ if (icls >= m_ccls) // bad compiler problem
+ return 0;
+
+ GrInputClass clsin;
+ clsin.CopyFrom(GlyphListLoc(ichwMin), (ichwLim - ichwMin));
+
+ int cgix = clsin.NumberOfGlyphs();
+ return cgix;
+ }
+ else
+ {
+ gAssert(false); // this method should not be used for output classes.
+ return ichwLim - ichwMin;
+ }
+}
+
+//:>********************************************************************************************
+//:> For test procedures
+//:>********************************************************************************************
+
+//:Ignore
+
+#ifdef OLD_TEST_STUFF
+/*----------------------------------------------------------------------------------------------
+ General test of class table.
+----------------------------------------------------------------------------------------------*/
+void GrClassTable::SetUpTestData()
+{
+ m_ccls = 7; // number of classes
+ m_cclsLinear = 4; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new gid16[100];
+
+ m_prgichwOffsets = new data16[7+1];
+
+ gid16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: uppercase consonants B - H
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(gid16(66)); *pchw++ = msbf(utf16(67)); *pchw++ = msbf(utf16(68));
+ *pchw++ = msbf(gid16(70)); *pchw++ = msbf(utf16(71)); *pchw++ = msbf(utf16(72));
+
+ // Output class 1: grave vowels
+ m_prgichwOffsets[1] = 6;
+ *pchw++ = msbf(gid16(192)); // A
+ *pchw++ = msbf(gid16(224)); // a
+ *pchw++ = msbf(gid16(200)); // E
+ *pchw++ = msbf(gid16(232)); // e
+ *pchw++ = msbf(gid16(204)); // I
+ *pchw++ = msbf(gid16(236)); // i
+ *pchw++ = msbf(gid16(210)); // O
+ *pchw++ = msbf(gid16(243)); // o
+ *pchw++ = msbf(gid16(217)); // U
+ *pchw++ = msbf(gid16(249)); // u
+
+ // Output class 2: circumflex vowels
+ m_prgichwOffsets[2] = 6 + 10;
+ *pchw++ = msbf(gid16(194)); // A
+ *pchw++ = msbf(gid16(226)); // a
+ *pchw++ = msbf(gid16(202)); // E
+ *pchw++ = msbf(gid16(234)); // e
+ *pchw++ = msbf(gid16(206)); // I
+ *pchw++ = msbf(gid16(238)); // i
+ *pchw++ = msbf(gid16(212)); // O
+ *pchw++ = msbf(gid16(244)); // o
+ *pchw++ = msbf(gid16(219)); // U
+ *pchw++ = msbf(gid16(251)); // u
+
+ // Output class 3: diaeresis vowels, uppercase
+ m_prgichwOffsets[3] = 16 + 10;
+ *pchw++ = msbf(gid16(196)); // A
+ *pchw++ = msbf(gid16(196)); // A
+ *pchw++ = msbf(gid16(203)); // E
+ *pchw++ = msbf(gid16(203)); // E
+ *pchw++ = msbf(gid16(207)); // I
+ *pchw++ = msbf(gid16(207)); // I
+ *pchw++ = msbf(gid16(214)); // O
+ *pchw++ = msbf(gid16(214)); // O
+ *pchw++ = msbf(gid16(220)); // U
+ *pchw++ = msbf(gid16(220)); // U
+
+ // Input class 4: lowercase consonants b - h
+ m_prgichwOffsets[4] = 26 + 10; // = 36
+ *pchw++ = msbf(gid16(6));
+ *pchw++ = msbf(gid16(4)); *pchw++ = msbf(gid16(2)); *pchw++ = msbf(gid16(6-4));
+ *pchw++ = msbf(gid16(98)); *pchw++ = msbf(gid16(0));
+ *pchw++ = msbf(gid16(99)); *pchw++ = msbf(gid16(1));
+ *pchw++ = msbf(gid16(100)); *pchw++ = msbf(gid16(2));
+ *pchw++ = msbf(gid16(102)); *pchw++ = msbf(gid16(3));
+ *pchw++ = msbf(gid16(103)); *pchw++ = msbf(gid16(4));
+ *pchw++ = msbf(gid16(104)); *pchw++ = msbf(gid16(5));
+
+ // Input class 5: vowels
+ m_prgichwOffsets[5] = 36 + 4 + 6*2; // = 52
+ *pchw++ = msbf(gid16(10));
+ *pchw++ = msbf(gid16(8)); *pchw++ = msbf(utf16(3)); *pchw++ = msbf(utf16(10-8));
+ *pchw++ = msbf(gid16(65)); *pchw++ = msbf(gid16(0)); // A
+ *pchw++ = msbf(gid16(69)); *pchw++ = msbf(gid16(2)); // E
+ *pchw++ = msbf(gid16(73)); *pchw++ = msbf(gid16(4)); // I
+ *pchw++ = msbf(gid16(79)); *pchw++ = msbf(gid16(6)); // O
+ *pchw++ = msbf(gid16(85)); *pchw++ = msbf(gid16(8)); // U
+ *pchw++ = msbf(gid16(97)); *pchw++ = msbf(gid16(1)); // a
+ *pchw++ = msbf(gid16(101)); *pchw++ = msbf(gid16(3)); // e
+ *pchw++ = msbf(gid16(105)); *pchw++ = msbf(gid16(5)); // i
+ *pchw++ = msbf(gid16(111)); *pchw++ = msbf(gid16(7)); // o
+ *pchw++ = msbf(gid16(117)); *pchw++ = msbf(gid16(9)); // u
+
+ // Input class 6: acute vowels
+ m_prgichwOffsets[6] = 52 + 4 + 10*2; // = 76
+ *pchw++ = msbf(gid16(10));
+ *pchw++ = msbf(gid16(8)); *pchw++ = msbf(gid16(3)); *pchw++ = msbf(gid16(10-8));
+ *pchw++ = msbf(gid16(193)); *pchw++ = msbf(gid16(0)); // A
+ *pchw++ = msbf(gid16(201)); *pchw++ = msbf(gid16(2)); // E
+ *pchw++ = msbf(gid16(205)); *pchw++ = msbf(gid16(4)); // I
+ *pchw++ = msbf(gid16(211)); *pchw++ = msbf(gid16(6)); // O
+ *pchw++ = msbf(gid16(218)); *pchw++ = msbf(gid16(8)); // U
+ *pchw++ = msbf(gid16(225)); *pchw++ = msbf(gid16(1)); // a
+ *pchw++ = msbf(gid16(233)); *pchw++ = msbf(gid16(3)); // e
+ *pchw++ = msbf(gid16(237)); *pchw++ = msbf(gid16(5)); // i
+ *pchw++ = msbf(gid16(243)); *pchw++ = msbf(gid16(7)); // o
+ *pchw++ = msbf(gid16(250)); *pchw++ = msbf(gid16(9)); // u
+
+ m_prgichwOffsets[7] = 76 + 4 + 10*2; // = 100
+};
+
+#endif // OLD_TEST_STUFF
+
+} // namespace gr
+
+//:End Ignore
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.h
new file mode 100644
index 00000000000..67d6940862c
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrClassTable.h
@@ -0,0 +1,188 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrClassTable.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ The GrClassTable and related classes that store the classes that are used in substitutions.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_CTABLE_INCLUDED
+#define GR_CTABLE_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ A glyph ID / index pair, a member of the GrInputClass where the items are sorted
+ by glyph ID.
+
+ Hungarian: gix
+----------------------------------------------------------------------------------------------*/
+class GrGlyphIndexPair
+{
+ friend class GrInputClass;
+ friend class GrClassTable;
+
+ gid16 GlyphID() { return lsbf(m_gidBIG); }
+ data16 Index() { return lsbf(m_nBIGIndex); }
+
+ gid16 m_gidBIG;
+ data16 m_nBIGIndex;
+};
+
+/*----------------------------------------------------------------------------------------------
+ A class consisting of a mapping from glyph ID to index, used for classes that
+ function as input classes (eg, occurrng in the left-hand side of a rule).
+
+ Hungarian: clsin
+----------------------------------------------------------------------------------------------*/
+class GrInputClass
+{
+ friend class GrClassTable;
+
+protected:
+ /*------------------------------------------------------------------------------------------
+ Copy the raw memory into the instance.
+ ------------------------------------------------------------------------------------------*/
+ void CopyFrom(data16 * pchwStart, int cchw)
+ {
+ m_cgixBIG = pchwStart[0];
+ m_digixBIGInit = pchwStart[1];
+ m_cBIGLoop = pchwStart[2];
+ m_igixBIGStart = pchwStart[3];
+
+ int cgix = NumberOfGlyphs();
+ m_pgixFirst = m_prggixBuffer;
+ if (cgix > 64)
+ {
+ m_vgix.resize(cgix);
+ m_pgixFirst = &m_vgix[0];
+ }
+ gAssert((4 + (cgix * 2)) == cchw);
+ #ifdef _DEBUG
+ memset(m_pgixFirst, 0, cgix * isizeof(GrGlyphIndexPair));
+ #endif
+ Assert(sizeof(GrGlyphIndexPair) == sizeof(gid16) + sizeof(data16));
+ GrGlyphIndexPair * pgixStart = reinterpret_cast<GrGlyphIndexPair*>(pchwStart + 4);
+ std::copy(pgixStart, pgixStart + cgix, m_pgixFirst);
+ }
+
+ int NumberOfGlyphs() { return lsbf(m_cgixBIG); }
+ int LoopCount() { return lsbf(m_cBIGLoop); }
+ int InitialSearchRange() { return lsbf(m_digixBIGInit); }
+ int StartSearch() { return lsbf(m_igixBIGStart); }
+
+ int FindIndex(gid16 gid);
+
+protected:
+ // Instance variables:
+ data16 m_cgixBIG; // number of glyphs in the class
+
+ // constants for fast binary search
+ data16 m_digixBIGInit; // (max power of 2 <= m_cgix);
+ // size of initial range to consider
+ data16 m_cBIGLoop; // log2(max power of 2 <= m_cgix);
+ // indicates how many iterations are necessary
+ data16 m_igixBIGStart; // m_cgix - m_digixInit;
+ // where to start search
+
+ GrGlyphIndexPair m_prggixBuffer[64];
+ std::vector<GrGlyphIndexPair> m_vgix;
+ GrGlyphIndexPair * m_pgixFirst;
+};
+
+
+/*----------------------------------------------------------------------------------------------
+ Contains all the classes used for substitution rules.
+
+ Hungarian: ctbl
+----------------------------------------------------------------------------------------------*/
+
+class GrClassTable
+{
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor & destructor:
+ GrClassTable()
+ : m_prgichwOffsets(NULL),
+ m_prgchwBIGGlyphList(NULL)
+ {
+ }
+
+ ~GrClassTable()
+ {
+ delete[] m_prgichwOffsets;
+ delete[] m_prgchwBIGGlyphList;
+ }
+
+ int NumberOfClasses() { return m_ccls; }
+ int NumberOfInputClasses() { return m_ccls - m_cclsLinear; }
+ int NumberOfOutputClasses() { return m_cclsLinear; }
+
+ bool ReadFromFont(GrIStream & grstrm, int fxdVersion);
+ void CreateEmpty();
+
+ int FindIndex(int icls, gid16 chwGlyphID);
+ gid16 GetGlyphID(int icls, int ichw);
+ int NumberOfGlyphsInClass(int icls);
+
+ gid16 GlyphAt(int ichw)
+ {
+ return lsbf(m_prgchwBIGGlyphList[ichw]);
+ }
+ data16 * GlyphListLoc(int ichw)
+ {
+ return m_prgchwBIGGlyphList + ichw;
+ }
+
+protected:
+ // Instance variables:
+ int m_ccls; // number of classes
+ int m_cclsLinear; // number of classes in linear format
+
+ data16 * m_prgichwOffsets;
+
+ // Two formats are included in the following array: the first section consists of
+ // flat ordered lists of glyphs, used for the "output" classes that use linear format.
+ // This provides an index-to-glyph mapping.
+ // The second section contains data in the format of GrInputClasses, used for "input"
+ // classes that need a binary-search format. This provides a glyph-to-index mapping.
+ // We don't create instances of GrInputClasses, because that would make reading
+ // from the ECF file slow. Instead we just set up a single instance at the time
+ // we're interested in it.
+ // NOTE that all this data has been slurped directly from the ECF file and therefore
+ // uses BIG-ENDIAN format.
+ gid16 * m_prgchwBIGGlyphList;
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+public:
+ // For test procedures:
+ void SetUpTestData();
+ void SetUpRuleActionTest();
+ void SetUpRuleAction2Test();
+ void SetUpAssocTest();
+ void SetUpAssoc2Test();
+ void SetUpDefaultAssocTest();
+ void SetUpFeatureTest();
+ void SetUpLigatureTest();
+ void SetUpLigature2Test();
+#endif // OLD_TEST_STUFF
+//:End Ignore
+};
+
+} // namespace gr
+
+#endif // !GR_CTABLE_INCLUDED
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.cpp
new file mode 100644
index 00000000000..91db0dfb80a
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.cpp
@@ -0,0 +1,2031 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrEngine.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description: Contains the implementation of the GrEngine class.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#include <functional>
+#include <cstring>
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+
+//:>********************************************************************************************
+//:> General functions
+//:>********************************************************************************************
+
+bool compareCmap(const byte *lhs, const byte *rhs)
+{
+ using namespace gr;
+
+ typedef const struct index {data16 version; data16 numberSubtables;} *const IndexPtr;
+ typedef const struct enc {data16 platID; data16 platSpecID; data32 offset;} *const EncPtr;
+
+ // Calculate the size of the cmap.
+
+ IndexPtr rhsIndex = IndexPtr(rhs);
+ size_t numSubTbl = lsbf(rhsIndex->numberSubtables);
+ size_t cbCmapSz = sizeof(index) + sizeof(enc) * numSubTbl;
+ EncPtr encTbl = EncPtr(rhs + sizeof(index));
+
+ for (size_t iSubTbl = 0; iSubTbl < numSubTbl; iSubTbl++)
+ //for (int iSubTbl = numSubTbl - 1; iSubTbl >= 0; --iSubTbl)
+ {
+ const data16 *const mapTbl = reinterpret_cast<const data16 *>(rhs + lsbf((int)encTbl[iSubTbl].offset));
+ int format = lsbf(*mapTbl);
+ switch (format)
+ {
+ // 16-bit lengths
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ cbCmapSz += lsbf((data16)unsigned(mapTbl[1]));
+ break;
+ // 32-bit lengths
+ case 8:
+ case 10:
+ case 12:
+ cbCmapSz += lsbf((int)unsigned(reinterpret_cast<const data32 *>(mapTbl)[1]));
+ break;
+ default:
+ Assert(false);
+ }
+ }
+
+ // Do the comparison.
+ return (memcmp(lhs, rhs, cbCmapSz) ? false : true);
+}
+
+
+//:>********************************************************************************************
+//:> GrEngine class.
+//:>********************************************************************************************
+
+GrEngine::GrEngine()
+{
+ /////////////_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF); ////////////////
+
+
+ m_cref = 1;
+ BasicInit();
+}
+
+void GrEngine::BasicInit()
+{
+ m_pfface = NULL;
+
+ m_ptman = NULL;
+ m_pctbl = NULL;
+ m_pgtbl = NULL;
+ m_prgpsd = NULL;
+ m_cpsd = 0;
+ m_cfeat = 0;
+ m_mFontEmUnits = -1;
+ m_dysOffset = 0;
+
+ ////m_tbufCmap.reset();
+ m_pCmap_3_1 = NULL;
+ m_pCmap_3_10 = NULL;
+ ////m_tbufNameTbl.reset();
+ // new interface stuff:
+ m_pCmapTbl = NULL;
+ m_pNameTbl = NULL;
+ m_fCmapTblCopy = false;
+ m_fNameTblCopy = false;
+
+ m_fLogXductn = false;
+
+ m_resFontValid = kresInvalidArg; // not yet initialized
+ m_ferr = kferrUninitialized;
+ m_fxdBadVersion = 0;
+
+ m_fSmartReg = false;
+ m_fSmartBold = false;
+ m_fSmartItalic = false;
+ m_fSmartBI = false;
+ m_fFakeItalicCache = false;
+ m_fFakeBICache = false;
+ m_strCtrlFileReg.erase();
+ m_strCtrlFileBold.erase();
+ m_strCtrlFileItalic.erase();
+ m_strCtrlFileBI.erase();
+ m_fFakeItalic = false;
+ m_stuCtrlFile.erase();
+ m_stuInitError.erase();
+ m_stuErrCtrlFile.erase();
+ m_stuFaceName.erase();
+ m_stuBaseFaceName.erase();
+ m_fUseSepBase = false;
+ m_stuFeatures.erase();
+
+ m_nFontCheckSum = 0;
+
+ m_fInErrorState = false;
+
+ m_rglcidFeatLabelLangs = NULL; // initialize lazily, when needed
+ m_clcidFeatLabelLangs = 0;
+}
+
+GrEngine::~GrEngine()
+{
+ DestroyEverything();
+ #ifdef _MSC_VER
+ if (!_CrtCheckMemory())
+ {
+ OutputDebugString(L"bad memory");
+ }
+ #endif
+}
+
+/*----------------------------------------------------------------------------------------------
+ Clean everything out (destructor or reinitializing with a different face name).
+----------------------------------------------------------------------------------------------*/
+void GrEngine::DestroyEverything()
+{
+ DestroyContents();
+ #ifdef _MSC_VER
+ if (!_CrtCheckMemory())
+ {
+ OutputDebugString(L"bad memory");
+ }
+ #endif
+
+ m_strCtrlFileReg.erase();
+ m_strCtrlFileBold.erase();
+ m_strCtrlFileItalic.erase();
+ m_strCtrlFileBI.erase();
+ m_fSmartReg = false;
+ m_fSmartBold = false;
+ m_fSmartItalic = false;
+ m_fSmartBI = false;
+ m_fFakeItalicCache = false;
+ m_fFakeBICache = false;
+ m_stuBaseFaceName.erase();
+
+ //m_stuFaceName.erase();
+ //m_stuFaceName = L"this is not a usable or valid string";
+ m_fUseSepBase = false;
+ m_stuFeatures.erase();
+}
+
+void GrEngine::DestroyContents(bool fDestroyCmap)
+{
+ if (fDestroyCmap)
+ {
+ ////m_tbufCmap.reset();
+ m_pCmap_3_1 = NULL;
+ m_pCmap_3_10 = NULL;
+
+ if (m_fCmapTblCopy)
+ delete[] m_pCmapTbl;
+ if (m_fNameTblCopy)
+ delete[] m_pNameTbl;
+ m_pCmapTbl = NULL;
+ m_pNameTbl = NULL;
+ m_fCmapTblCopy = false;
+ m_fNameTblCopy = false;
+ }
+
+ delete m_ptman;
+ delete m_pctbl;
+ delete m_pgtbl;
+ delete[] m_prgpsd;
+ m_ptman = NULL;
+ m_pctbl = NULL;
+ m_pgtbl = NULL;
+ m_prgpsd = NULL;
+
+ ////m_tbufNameTbl.reset();
+
+ m_stuCtrlFile.erase();
+ m_stuInitError.erase();
+
+ m_resFontValid = kresInvalidArg;
+ m_ferr = kferrUninitialized;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the number of features.
+----------------------------------------------------------------------------------------------*/
+size_t GrEngine::NumberOfFeatures_ff()
+{
+ return (size_t)m_cfeat;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the feature ID for the ifeat-th feature.
+----------------------------------------------------------------------------------------------*/
+featid GrEngine::FeatureID_ff(size_t ifeat)
+{
+ return (featid)m_rgfeat[ifeat].ID();
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the index of the feature with the given ID.
+----------------------------------------------------------------------------------------------*/
+size_t GrEngine::FeatureWithID_ff(featid fid)
+{
+ int ifeatRet;
+ /* GrFeature * pfeat = */
+ FeatureWithID(fid, &ifeatRet);
+ return (size_t)ifeatRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the label for the ifeat-th feature.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::GetFeatureLabel_ff(size_t ifeat, lgid nLanguage, utf16 * rgchwLabel)
+{
+ std::wstring stu = m_rgfeat[ifeat].Label(this, nLanguage);
+
+ int cch = stu.size();
+ cch = min(cch, 127); // 1 char for zero-termination
+ std::copy(stu.data(), stu.data() + cch, rgchwLabel);
+ rgchwLabel[cch] = 0;
+
+ return (cch > 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the index of the default setting. Return -1 if it cannot be found.
+----------------------------------------------------------------------------------------------*/
+int GrEngine::GetFeatureDefault_ff(size_t ifeat)
+{
+ GrFeature * pfeat = m_rgfeat + ifeat;
+ int defaultValue = pfeat->DefaultValue();
+ int cfset = pfeat->NumberOfSettings();
+ int rgnSettings[100];
+ pfeat->Settings(100, rgnSettings);
+ Assert(cfset < 100); // TODO: improve this
+ for (int ifset = 0; ifset < cfset; ifset++)
+ {
+ if (rgnSettings[ifset] == defaultValue)
+ return ifset;
+ }
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the number of settings for the ifeat-th feature.
+----------------------------------------------------------------------------------------------*/
+size_t GrEngine::NumberOfSettings_ff(size_t ifeat)
+{
+ return m_rgfeat[ifeat].NumberOfSettings();
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the value of the ifset-th setting for the ifeat-th feature.
+----------------------------------------------------------------------------------------------*/
+int GrEngine::GetFeatureSettingValue_ff(size_t ifeat, size_t ifset)
+{
+ return m_rgfeat[ifeat].NthSetting(ifset);
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the UI label for the given feature setting.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::GetFeatureSettingLabel_ff(size_t ifeat, size_t ifset, lgid language,
+ utf16 * rgchwLabel)
+{
+ std::wstring stu = m_rgfeat[ifeat].NthSettingLabel(this, ifset, language);
+
+ int cch = stu.size();
+ cch = min(cch, 127); // 1 char for zero-termination
+ // Note: the wchar_t label was originally assigned from utf16 data, so although wchar_t is
+ // utf32 on some platforms the conversion back to utf16 should still give correct results.
+ std::copy(stu.data(), stu.data() + cch, rgchwLabel);
+ rgchwLabel[cch] = 0;
+
+ return (cch > 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the number of languages that are possible among the feature labels.
+----------------------------------------------------------------------------------------------*/
+size_t GrEngine::NumberOfFeatLangs_ff()
+{
+ SetUpFeatLangList();
+ return m_clcidFeatLabelLangs;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the language LCID for the feature-label language with the given index.
+----------------------------------------------------------------------------------------------*/
+short GrEngine::GetFeatLabelLang_ff(size_t ilang)
+{
+ SetUpFeatLangList();
+ return m_rglcidFeatLabelLangs[ilang];
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the number of supported languages.
+----------------------------------------------------------------------------------------------*/
+size_t GrEngine::NumberOfLanguages_ff()
+{
+ return (size_t)m_langtbl.NumberOfLanguages();
+}
+
+/*----------------------------------------------------------------------------------------------
+ For FontFace: return the language code for the language with the given index.
+----------------------------------------------------------------------------------------------*/
+isocode GrEngine::GetLanguageCode_ff(size_t ilang)
+{
+ return m_langtbl.LanguageCode(ilang);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set up the list of all the languages that are present in the feature labels.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpFeatLangList()
+{
+ if (m_rglcidFeatLabelLangs)
+ return;
+
+ int rgnNameIDs[kMaxFeatures];
+ for (int ifeat = 0; ifeat < m_cfeat; ifeat++)
+ rgnNameIDs[ifeat] = m_rgfeat[ifeat].NameId();
+ short rglcid[128]; // 128 is the number expected by TtfUtil::GetLangsForNames
+ m_clcidFeatLabelLangs = TtfUtil::GetLangsForNames(m_pNameTbl, 3, 1, rgnNameIDs, m_cfeat, rglcid);
+ m_rglcidFeatLabelLangs = new short[m_clcidFeatLabelLangs];
+ memcpy(m_rglcidFeatLabelLangs, rglcid, sizeof(short) * m_clcidFeatLabelLangs);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the maximum size needed for the block of data to pass between segments, that is,
+ to reinitialize the engine based on the results of the previously generated segment.
+ This value must match what is in GrTableManager::InitializeStreams() and
+ InitializeForNextSeg(). 256 is an absolute maximum imposed by the interface.
+
+ In Graphite, what this block of data will contain is information about cross-line
+ contextualization and some directionality information.
+
+ Assumes InitNew() has already been called to set the font name.
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::get_SegDatMaxLength(int * pcb)
+{
+ ChkGrOutPtr(pcb);
+
+ if (m_resFontValid == kresInvalidArg)
+ ReturnResult(kresUnexpected); // engine not initialized
+
+ GrResult res = m_resFontValid;
+ if (m_resFontValid == kresFail || m_resFontValid == kresUnexpected || m_resFontValid == kresFalse)
+ res = kresOk; // invalid font
+ if (ResultFailed(res))
+ ReturnResult(res);
+
+ Assert(m_ptman);
+ if (!m_ptman)
+ *pcb = 256;
+ else
+ *pcb = m_ptman->NumberOfPasses() + 4;
+
+ ReturnResult(res);
+}
+
+/*----------------------------------------------------------------------------------------------
+ @return The supported script direction(s). If more than one, the application is
+ responsible for choosing the most appropriate.
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::get_ScriptDirection(unsigned int * pgrfsdc, OLECHAR * prgchwErrMsg, int cchMaxErrMsg)
+{
+ ChkGrOutPtr(pgrfsdc);
+ ChkGrArrayArg(prgchwErrMsg, cchMaxErrMsg);
+
+ if (m_resFontValid == kresInvalidArg)
+ ReturnResult(kresUnexpected); // engine not initialized
+
+ GrResult res = m_resFontValid;
+
+ *pgrfsdc = m_grfsdc;
+
+// ClearFontError(prgchwErrMsg, cchMaxErrMsg);
+// try
+// {
+// if (m_resFontValid == kresFail || m_resFontValid == kresUnexpected || m_resFontValid == kresFalse)
+// {
+// RecordFontLoadError(prgchwErrMsg, cchMaxErrMsg);
+// res = kresOk;
+// }
+// *pgrfsdc = m_grfsdc;
+// }
+// catch (Throwable & thr)
+// {
+// res = (GrResult)thr.Error();
+// *pgrfsdc = kfsdcHorizLtr;
+// }
+// catch (...)
+// {
+// res = WARN(kresFail);
+// *pgrfsdc = kfsdcHorizLtr;
+// }
+
+ ReturnResult(res);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get an glyph attribute from the engine that will help the GrJustifier in its work.
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::getGlyphAttribute(int iGlyph, int jgat, int nLevel, float * pValueRet)
+{
+ return m_ptman->State()->GetGlyphAttrForJustification(iGlyph, jgat, nLevel, pValueRet);
+}
+
+GrResult GrEngine::getGlyphAttribute(int iGlyph, int jgat, int nLevel, int * pValueRet)
+{
+ return m_ptman->State()->GetGlyphAttrForJustification(iGlyph, jgat, nLevel, pValueRet);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set an glyph attribute in the engine as a result of the decisions made by the
+ GrJustifier.
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::setGlyphAttribute(int iGlyph, int jgat, int nLevel, float value)
+{
+ return m_ptman->State()->SetGlyphAttrForJustification(iGlyph, jgat, nLevel, value);
+}
+
+GrResult GrEngine::setGlyphAttribute(int iGlyph, int jgat, int nLevel, int value)
+{
+ return m_ptman->State()->SetGlyphAttrForJustification(iGlyph, jgat, nLevel, value);
+}
+
+//:>********************************************************************************************
+//:> Non-FieldWorks interface methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Make a complete segment that can be used to measure and do line-breaking.
+
+ OBSOLETE - delete
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult GrEngine::MakeMeasuredSegment(
+ Font * pfont, ITextSource * pgts,
+ int ichMin, int ichLim,
+ bool fParaRtl,
+ Segment ** ppsegRet, SegEnd * pest,
+ std::ostream * pstrmLog,
+ OLECHAR * prgchwErrMsg, int cchMaxErrMsg)
+{
+ int dichContext, dichLimSeg;
+ float dxWidth;
+ return MakeSegment(ksegmodeMsfr,
+ pfont, pgts, NULL, ichMin, ichLim, false, false,
+ 100000, klbClipBreak, ktwshAll, // not used
+ fParaRtl,
+ ppsegRet, &dxWidth,
+ 0, NULL, 0, NULL, NULL, &dichContext, // not used
+ pstrmLog,
+ prgchwErrMsg, cchMaxErrMsg,
+ -1, false, false, klbClipBreak, // not used
+ &dichLimSeg, pest,
+ false, 100000, kestMoreLines); // not used
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ Make a segment from the given range, regardless of the kind of line-break that results.
+
+ OBSOLETE - delete
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult GrEngine::MakeSegmentFromRange(
+ Font * pfont, ITextSource * pgts, IGrJustifier * pgj,
+ int ichMin, int ichLim,
+ bool fStartLine, bool fEndLine,
+ TrWsHandling twsh, bool fParaRtl,
+ Segment ** ppsegRet, float * pdxWidth, SegEnd * pest,
+ int cbPrev, byte * pbPrevSegDat, int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat,
+ int * pdichwContext,
+ std::ostream * pstrmLog,
+ OLECHAR * prgchwErrMsg, int cchwMaxErrMsg)
+{
+ int dichLimSegBogus;
+ return MakeSegment(ksegmodeMsfr, pfont, pgts, pgj,
+ ichMin, ichLim,
+ fStartLine, fEndLine,
+ 10000, klbWordBreak, // not used
+ twsh, fParaRtl,
+ ppsegRet, pdxWidth,
+ //cbPrev, pbPrevSegDat, cbNextMax, pbNextSegDat, pcbNextSegDat, pdichwContext,
+ 0, NULL, 0, NULL, NULL, NULL,
+ pstrmLog,
+ prgchwErrMsg, cchwMaxErrMsg,
+ ichLim, false, false, klbClipBreak, // not used
+ &dichLimSegBogus, pest,
+ 10000, kestMoreLines); // not used
+}
+*/
+
+
+//:>********************************************************************************************
+//:> Other methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Create a segment.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::MakeSegment(
+ // Common parameters
+ Segment * psegNew,
+ Font * pfont, ITextSource * pgts, IGrJustifier * pjus,
+ LayoutEnvironment & layout,
+ int ichMin, int ichLim,
+ // for finding a break point
+ float dxMaxWidth,
+ bool fBacktracking,
+ // for justification
+ bool fJust, float dxJustifiedWidthJ, SegEnd estJ)
+{
+ ChkGrArgPtr(pgts);
+ ChkGrArgPtrN(pjus);
+ ChkGrOutPtr(psegNew);
+ Assert(layout.bestBreak() <= layout.worstBreak());
+
+ if (pjus == NULL)
+ pjus = layout.justifier();
+
+ if (m_resFontValid == kresInvalidArg)
+ // Uninitialized.
+ return; // ReturnResult(kresUnexpected);
+
+ SetCmapAndNameTables(pfont);
+
+ int segmode = ksegmodeRange; // segment from range
+ if (fJust)
+ segmode = ksegmodeJust; // justified segment
+ else if (dxMaxWidth < kPosInfFloat)
+ segmode = ksegmodeBreak; // find break point
+
+ // Temporary:
+ if (!this->m_ptman)
+ {
+ Warn("No Graphite tables");
+ m_ptman = new GrTableManager(this);
+ CreateEmpty();
+ }
+
+ // GrResult hr = kresOk;
+ m_fInErrorState = false;
+
+ bool fBold, fItalic;
+ GetStyles(pfont, ichMin, &fBold, &fItalic);
+
+ GetWritingSystemDirection(pgts, ichMin);
+
+ // Find the end of the range to render with the current font.
+ int nDirDepth = 0;
+ int ichFontLim = FindFontLim(pgts, ichMin, &nDirDepth);
+ int ichStrmLim = 0;
+ int ichSegLim = 0;
+ switch (segmode)
+ {
+ case ksegmodeBreak: // find break point
+ // Here ichLim should be the end of the text-source, unless we're backtracking.
+ ichStrmLim = min(ichFontLim, ichLim);
+ ichSegLim = -1; // unknown
+ break;
+ case ksegmodeJust: // stretching an existing segment to achieve justification
+ ichStrmLim = ichFontLim;
+ ichSegLim = ichLim;
+ break;
+ //case ksegmodeMms: // MakeMeasuredSegment
+ // ichLim = ichFontLim;
+ // ichStrmLim = ichFontLim;
+ // ichSegLim = -1; // process to the end of the stream
+ // break;
+ case ksegmodeRange: // segment from range
+ ichLim = min(ichLim, ichFontLim);
+ ichStrmLim = ichFontLim;
+ ichSegLim = (ichLim == kPosInfinity) ? -1 : ichLim;
+ break;
+ default:
+ Assert(false);
+ }
+
+ // Initialize the graphics object with the font and character properties.
+ // SILE
+ ////if (m_fUseSepBase)
+ ////{
+ //// Assert(m_stuBaseFaceName.size() > 0);
+ //// SetUpGraphics(pgg, pgts, ichMin, m_stuBaseFaceName);
+ ////}
+ ////else
+ //// SetUpGraphics(pgg, pgts, ichMin, m_stuFaceName);
+
+ GrResult res = kresOk;
+
+ Assert(m_ptman);
+ m_ptman->State()->SetFont(pfont);
+
+ // Create a character stream on the text source.
+ GrCharStream * pchstrm = new GrCharStream(pgts, ichMin, ichStrmLim,
+ layout.startOfLine(), layout.endOfLine());
+
+ // TODO: change vertical offset to work on a character-by-character basis
+ m_dysOffset = (pgts->getVerticalOffset(ichMin) * pfont->getDPIy()) / 72;
+
+ // Run the tables and get back a segment.
+
+ bool fMoreText = false;
+ int ichCallerBtLim = -1;
+ bool fInfiniteWidth = false;
+ switch (segmode)
+ {
+ //case ksegmodeMms:
+ case ksegmodeBreak:
+ case ksegmodeRange:
+ if (segmode == ksegmodeBreak)
+ {
+ fMoreText = ((ichFontLim < ichLim) || fBacktracking);
+ ichCallerBtLim = (fBacktracking) ? ichLim : -1;
+ fInfiniteWidth = false;
+ }
+ //else if (segmode == ksegmodeMms)
+ //{
+ // fMoreText = false;
+ // ichCallerBtLim = -1;
+ // fInfiniteWidth = true;
+ // Assert(twsh == ktwshAll);
+ //}
+ else if (segmode == ksegmodeRange)
+ {
+ int ichTextLim;
+ ichTextLim = pgts->getLength();
+ fMoreText = (ichLim < ichTextLim);
+ ichCallerBtLim = -1;
+ fInfiniteWidth = true;
+ }
+ try {
+ m_ptman->Run(psegNew, pfont, pchstrm, pjus,
+ ((pjus) ? kjmodiCanShrink : kjmodiNormal),
+ layout,
+ ichSegLim, dxMaxWidth, 0,
+ fBacktracking, fMoreText, ichFontLim, fInfiniteWidth, false,
+ ichCallerBtLim,
+ nDirDepth, estJ);
+ }
+ catch (...)
+ {
+ // Disastrous problem in rendering.
+ if (!layout.dumbFallback())
+ throw; // throws original exception
+
+ // Try dumb rendering.
+ if (m_fUseSepBase)
+ SwitchGraphicsFont(true); // use the base font, which has real glyphs
+
+ m_fInErrorState = true;
+ res = RunUsingEmpty(psegNew, pfont, pchstrm, layout,
+ ichSegLim,
+ dxMaxWidth,
+ fBacktracking, fMoreText, fInfiniteWidth,
+ ichCallerBtLim,
+ nDirDepth, estJ);
+ }
+ break;
+
+ case ksegmodeJust: // justified segment
+ {
+ m_ptman->Run(psegNew, pfont, pchstrm, pjus, kjmodiJustify, layout,
+ ichSegLim,
+ dxJustifiedWidthJ, dxMaxWidth,
+ false, false, // not used
+ ichFontLim,
+ true, // infinite width
+ false, // kludge
+ -1,
+ nDirDepth, estJ);
+ //&dxWidth, &est);
+ Assert((ichLim - ichMin) == (psegNew->stopCharacter() - psegNew->startCharacter()));
+ break;
+ }
+
+ default:
+ Assert(false);
+ }
+
+ delete pchstrm;
+
+ if (m_fUseSepBase)
+ SwitchGraphicsFont(false);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return an indication of whether an error happened in trying to load Graphite tables.
+----------------------------------------------------------------------------------------------*/
+FontErrorCode GrEngine::IsValidForGraphite(int * pnVersion, int * pnSubVersion)
+{
+ if (pnVersion)
+ *pnVersion = m_fxdBadVersion >> 16;
+ if (pnSubVersion)
+ *pnSubVersion = m_fxdBadVersion & 0x0000FFFF;
+
+ return m_ferr;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record a system error indicating that the font could not be loaded properly.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void GrEngine::RecordFontLoadError(OLECHAR * prgchwErrMsg, int cchMax)
+{
+ if (prgchwErrMsg == NULL || cchMax == 0)
+ return;
+
+ std::wstring stuMessage = L"Error in initializing Graphite font \"";
+ stuMessage.append(m_stuFaceName);
+ if (m_stuErrCtrlFile.size())
+ {
+ stuMessage.append(L"\" (");
+ stuMessage.append(m_stuErrCtrlFile);
+ stuMessage.append(L")");
+ }
+ else
+ stuMessage.append(L"\"");
+ if (m_stuInitError.size())
+ {
+ stuMessage.append(L"--\n");
+ stuMessage.append(m_stuInitError);
+ }
+
+ std::fill_n(prgchwErrMsg, cchMax, 0);
+ std::copy(stuMessage.data(), stuMessage.data() + min(cchMax - 1, signed(stuMessage.size())),
+ prgchwErrMsg);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record a system error indicating a bad error in rendering using a supposedly valid font.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void GrEngine::RecordFontRunError(OLECHAR * prgchwErrMsg, int cchMax, GrResult res)
+{
+ if (prgchwErrMsg == NULL || cchMax == 0)
+ return;
+
+ std::wstring stuMessage = L"Error in rendering using Graphite font \"";
+ stuMessage.append(m_stuFaceName);
+ if (m_stuErrCtrlFile.size())
+ {
+ stuMessage.append(L"\" (");
+ stuMessage.append(m_stuErrCtrlFile);
+ stuMessage.append(L")");
+ }
+ else
+ stuMessage.append(L"\"");
+
+ std::fill_n(prgchwErrMsg, cchMax, 0);
+ std::copy(stuMessage.data(), stuMessage.data() + min(cchMax - 1, signed(stuMessage.size())),
+ prgchwErrMsg);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the font error message buffer to zero. This way we can be sure to recognize
+ an error condition by the fact that the buffer is non-zero.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void GrEngine::ClearFontError(OLECHAR * prgchwErrMsg, int cchMaxErrMsg)
+{
+ std::fill_n(prgchwErrMsg, cchMaxErrMsg, 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the overall direction of the writing system based on the text properties.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::GetWritingSystemDirection(ITextSource * pgts, int ichwMin)
+{
+#ifdef OLD_TEST_STUFF
+ // for test procedures:
+ if (m_stuInitialize == "RightToLeftLayout")
+ {
+ m_fRightToLeft = true;
+ return;
+ }
+#endif // OLD_TEST_STUFF
+
+ m_fRightToLeft = pgts->getRightToLeft(ichwMin);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find the end of the range that uses the current font.
+
+ @param pgts - contains text to render
+ @param ichwMinFont - beginning of range to render with this font
+ @param pnDirDepth - return direction depth: 0=LTR, 1=RTL
+
+ @return The lim of the range that could be rendered by this font. Also the direction depth.
+----------------------------------------------------------------------------------------------*/
+int GrEngine::FindFontLim(ITextSource * pgts, int ichwMinFont, int * pnDirDepth)
+{
+ int ichwTextLen = (int)pgts->getLength();
+
+ int ichwLimRange; // range that can be rendered without breaking contextualization.
+ int ichwMinNext = ichwMinFont;
+
+ while (true)
+ {
+ std::pair<toffset, toffset> pairRange = pgts->propertyRange(ichwMinNext);
+ // int ichwMinRun = pairRange.first;
+ int ichwLimRun = pairRange.second;
+ *pnDirDepth = pgts->getDirectionDepth(ichwMinNext);
+
+ //if (ichwLim > -1 && ichwLim < ichwLimRun)
+ //{
+ // // Stopping in the middle of a run
+ // return ichwLim;
+ //}
+
+ // We can at least go to the end of this run.
+ ichwLimRange = ichwLimRun;
+ if (ichwLimRun >= ichwTextLen)
+ {
+ // Hit the end of the text-source
+ return ichwLimRange;
+ }
+ else
+ {
+ // If the following run is the same as this run except for color and underlining,
+ // we don't have to break here.
+ if (!pgts->sameSegment(ichwMinNext, ichwLimRun))
+ return ichwLimRange;
+ }
+ ichwMinNext = ichwLimRun;
+ }
+
+ return ichwLimRange;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the version number from the tables, and return false if any are a version this
+ implementation of the engine can't handle.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::CheckTableVersions(GrIStream * pgrstrm,
+ const byte *pSilfTbl, int lSilfStart,
+ const byte *pGlobTbl, int lGlocStart,
+ const byte *pFeatTbl, int lFeatStart,
+ int * pfxdBadVersion)
+{
+ pgrstrm->OpenBuffer(pSilfTbl, isizeof(int));
+ pgrstrm->SetPositionInFont(lSilfStart);
+ *pfxdBadVersion = ReadVersion(*pgrstrm);
+ pgrstrm->CloseBuffer();
+ if (*pfxdBadVersion > kSilfVersion)
+ return false;
+
+ pgrstrm->OpenBuffer(pGlobTbl, lGlocStart + isizeof(int));
+ pgrstrm->SetPositionInFont(lGlocStart);
+ *pfxdBadVersion = ReadVersion(*pgrstrm);
+ pgrstrm->CloseBuffer();
+ if (*pfxdBadVersion > kGlocVersion)
+ return false;
+
+ pgrstrm->OpenBuffer(pFeatTbl, isizeof(int));
+ pgrstrm->SetPositionInFont(lFeatStart);
+ *pfxdBadVersion = ReadVersion(*pgrstrm);
+ pgrstrm->CloseBuffer();
+ if (*pfxdBadVersion > kFeatVersion)
+ return false;
+
+ *pfxdBadVersion = 0;
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reinterpret the version number from a font table.
+----------------------------------------------------------------------------------------------*/
+int GrEngine::ReadVersion(GrIStream & grstrm)
+{
+ int fxdVersion = grstrm.ReadIntFromFont();
+
+ if (fxdVersion < 0x00010000)
+ fxdVersion = 0x00010000; // kludge for bug with which some fonts were generated
+
+ return fxdVersion;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the engine from the test file. Used for test procedures.
+----------------------------------------------------------------------------------------------*/
+//:Ignore
+#ifdef OLD_TEST_STUFF
+void GrEngine::InitFromControlFileTest()
+{
+ IStreamPtr qstrm;
+ FileStream::Create(m_stuCtrlFile, STGM_READ, &qstrm);
+
+ int nSilfOffset, nGlocOffset, nGlatOffset, nFeatOffset;
+
+ nSilfOffset = ReadIntFromFont(qstrm);
+ nGlocOffset = ReadIntFromFont(qstrm);
+ nGlatOffset = ReadIntFromFont(qstrm);
+ nFeatOffset = ReadIntFromFont(qstrm);
+ nSill
+
+ // Read the "Silf" table.
+ int chwMaxGlyphID;
+ int fxdVersion;
+ ReadSilfTable(qstrm, nSilOffset, 0, &chwMaxGlyphID, &fxdVersion);
+
+ // Read the "Gloc" and "Glat" tables.
+ ReadGlocAndGlatTables(qstrm, nGlocOffset, qstrm, nGlatOffset, chwMaxGlyphID, fxdVersion);
+
+ // Read the "Feat" table.
+ ReadFeatTable(qstrm, nFeatOffset);
+}
+#endif // OLD_TEST_STUFF
+//:End Ignore
+
+
+/*----------------------------------------------------------------------------------------------
+ Return whether the text is asking for bold and/or italic text.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::GetStyles(Font * pfont, int ichwMin, bool * pfBold, bool * pfItalic)
+{
+ *pfBold = pfont->bold();
+ *pfItalic = pfont->italic();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Switch the Graphics object between the Graphite table file and the base font.
+ Should only be called when we know we are using a base font, or when we are reading
+ the base font to see if it is valid.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SwitchGraphicsFont(bool fBase)
+{
+ Assert(!fBase || m_stuBaseFaceName.size() > 0);
+
+ //LgCharRenderProps chrp;
+ //pgg->get_FontCharProperties(&chrp);
+ //if (fBase)
+ //{
+ // wcsncpy(chrp.szFaceName, m_stuBaseFaceName.data(), m_stuBaseFaceName.size() + 1);
+ // chrp.szFaceName[31] = 0;
+ //}
+ //else
+ //{
+ // wcsncpy(chrp.szFaceName, m_stuFaceName.data(), m_stuFaceName.size() + 1);
+ // chrp.szFaceName[31] = 0;
+ //}
+ //pgg->SetupGraphics(&chrp);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the contents of the "Silf" table from the stream, which is on an extended
+ TrueType font file. Specifically, read the iSubTable-th sub-table (for now there is
+ only one).
+
+ WARNING: any changes to this method must be accompanied by equivalent changes to
+ CreateEmpty().
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::ReadSilfTable(GrIStream & grstrm, long lTableStart, int iSubTable,
+ int * pchwMaxGlyphID, int * pfxdSilfVersion)
+{
+ grstrm.SetPositionInFont(lTableStart);
+
+ // version
+ *pfxdSilfVersion = ReadVersion(grstrm);
+ if (*pfxdSilfVersion > kSilfVersion)
+ // Version we don't know how to handle.
+ return false;
+
+ if (*pfxdSilfVersion >= 0x00030000)
+ // compiler version
+ grstrm.ReadIntFromFont();
+
+ // number of tables
+ unsigned short cSubTables = grstrm.ReadUShortFromFont();
+ Assert(cSubTables == 1); // for now
+ Assert(cSubTables <= kMaxSubTablesInFont);
+ if (cSubTables != 1 || cSubTables > kMaxSubTablesInFont)
+ return false;
+
+ if (*pfxdSilfVersion >= 0x00020000)
+ // reserved
+ grstrm.ReadShortFromFont();
+
+ // subtable offsets
+ int nSubTableOffsets[kMaxSubTablesInFont];
+ int i;
+ for (i = 0; i < cSubTables; i++)
+ {
+ nSubTableOffsets[i] = grstrm.ReadIntFromFont();
+ }
+
+ grstrm.SetPositionInFont(lTableStart + nSubTableOffsets[iSubTable]);
+
+ // Now we are at the beginning of the desired sub-table.
+
+ // Get the position of the start of the table.
+ long lSubTableStart;
+ grstrm.GetPositionInFont(&lSubTableStart);
+
+ // rule version
+ int fxdRuleVersion = (*pfxdSilfVersion >= 0x00030000) ?
+ ReadVersion(grstrm) :
+ *pfxdSilfVersion;
+
+ long lPassBlockPos = -1;
+ long lPseudosPos = -1;
+ if (*pfxdSilfVersion >= 0x00030000)
+ {
+ lPassBlockPos = grstrm.ReadUShortFromFont() + lSubTableStart;
+ lPseudosPos = grstrm.ReadUShortFromFont() + lSubTableStart;
+ }
+
+ // maximum glyph ID
+ data16 chwTmp;
+ *pchwMaxGlyphID = grstrm.ReadUShortFromFont();
+
+ // extra ascent and descent
+ m_mXAscent = grstrm.ReadShortFromFont();
+ m_mXDescent = grstrm.ReadShortFromFont();
+
+ // TODO: decide whether we want these:
+ m_mXAscent = 0;
+ m_mXDescent = 0;
+
+ // number of passes
+ byte cPasses = grstrm.ReadByteFromFont();
+ // index of first substitution pass
+ byte ipassSub1 = grstrm.ReadByteFromFont();
+ // index of first positioning pass
+ byte ipassPos1 = grstrm.ReadByteFromFont();
+ // index of first justification pass
+ byte ipassJust1 = grstrm.ReadByteFromFont();
+ // index of first reordered pass, or 0xFF if no reordering
+ byte ipassReordered1 = grstrm.ReadByteFromFont();
+ if (*pfxdSilfVersion < 0x00020000)
+ {
+ Assert(ipassJust1 == cPasses || ipassJust1 == ipassPos1);
+ ipassJust1 = ipassPos1;
+ }
+
+ // Sanity checks.
+ if (cPasses > kMaxPasses || ipassSub1 > cPasses || ipassPos1 > cPasses)
+ return false; // bad table
+
+ // line-break flag
+ int nLineBreak = grstrm.ReadByteFromFont();
+ if (nLineBreak != 0 && nLineBreak != 1)
+ return false; // bad table
+ m_fLineBreak = (bool)nLineBreak;
+
+ // range of possible cross-line-boundary contextualization
+ m_cchwPreXlbContext = grstrm.ReadByteFromFont();
+ m_cchwPostXlbContext = grstrm.ReadByteFromFont();
+
+ // actual glyph ID for pseudo-glyph (ID of bogus attribute)
+ byte bTmp; // unsigned
+ bTmp = grstrm.ReadByteFromFont();
+ m_chwPseudoAttr = bTmp;
+ // breakweight
+ bTmp = grstrm.ReadByteFromFont();
+ m_chwBWAttr = bTmp;
+ // directionality
+ bTmp = grstrm.ReadByteFromFont();
+ m_chwDirAttr = bTmp;
+
+ // Sanity checks--don't bother with these, I don't seem to be able to know what are reasonable values.
+ //if (m_chwPseudoAttr > 200 || m_chwBWAttr > 200 || m_chwDirAttr > 200)
+ // return false; // bad table
+
+ if (*pfxdSilfVersion >= 0x00020000)
+ {
+ // reserved
+ grstrm.ReadByteFromFont();
+ grstrm.ReadByteFromFont();
+
+ // justification levels
+ m_cJLevels = grstrm.ReadByteFromFont();
+ if (m_cJLevels > kMaxJLevels)
+ return false; // bad table
+ m_fBasicJust = (m_cJLevels == 0);
+ m_chwJStretch0 = 0xffff; // if no justification
+ m_chwJShrink0 = 0xffff;
+ m_chwJStep0 = 0xffff;
+ m_chwJWeight0 = 0xffff;
+ for (int i = 0; i < m_cJLevels; i++)
+ {
+ // justification glyph attribute IDs
+ bTmp = grstrm.ReadByteFromFont();
+ if (i == 0)
+ m_chwJStretch0 = bTmp;
+ bTmp = grstrm.ReadByteFromFont();
+ if (i == 0)
+ m_chwJShrink0 = bTmp;
+ bTmp = grstrm.ReadByteFromFont();
+ if (i == 0)
+ m_chwJStep0 = bTmp;
+ bTmp = grstrm.ReadByteFromFont();
+ if (i == 0)
+ m_chwJWeight0 = bTmp;
+ bTmp = grstrm.ReadByteFromFont(); // runto
+ // reserved
+ grstrm.ReadByteFromFont();
+ grstrm.ReadByteFromFont();
+ grstrm.ReadByteFromFont();
+ }
+ }
+ else
+ {
+ m_cJLevels = 0;
+ m_fBasicJust = true;
+ m_chwJStretch0 = 0xffff;
+ m_chwJShrink0 = 0xffff;
+ m_chwJStep0 = 0xffff;
+ m_chwJWeight0 = 0xffff;
+ }
+
+ // number of component attributes
+ chwTmp = grstrm.ReadUShortFromFont();
+ m_cComponents = chwTmp;
+
+ // number of user-defined slot attributes
+ m_cnUserDefn = grstrm.ReadByteFromFont();
+ if (m_cnUserDefn > kMaxUserDefinableSlotAttrs)
+ return false; // bad table
+
+ // max number of ligature components per glyph
+ m_cnCompPerLig = grstrm.ReadByteFromFont();
+ if (m_cnCompPerLig > 16)
+ return false; // bad table
+
+ // directions supported
+ bTmp = grstrm.ReadByteFromFont();
+ m_grfsdc = bTmp;
+ if (m_grfsdc > kfsdcHorizLtr + kfsdcHorizRtl + kfsdcVertFromLeft + kfsdcVertFromRight)
+ return false; // bad table
+
+ // reserved
+ bTmp = grstrm.ReadByteFromFont();
+ bTmp = grstrm.ReadByteFromFont();
+ bTmp = grstrm.ReadByteFromFont();
+
+ // critical features
+ int cCriticalFeatures;
+ if (*pfxdSilfVersion >= 0x00020000)
+ {
+ // reserved
+ bTmp = grstrm.ReadByteFromFont();
+
+ cCriticalFeatures = grstrm.ReadByteFromFont();
+ Assert(cCriticalFeatures == 0);
+ if (cCriticalFeatures != 0)
+ return false; // bad table
+
+ // reserved
+ bTmp = grstrm.ReadByteFromFont();
+ }
+
+ // rendering behaviors--ignore for now
+ byte cBehaviors = grstrm.ReadByteFromFont();
+ unsigned int nBehaviors[kMaxRenderingBehavior];
+ for (i = 0; i < cBehaviors; i++)
+ {
+ nBehaviors[i] = unsigned(grstrm.ReadIntFromFont());
+ }
+
+ // linebreak glyph ID
+ m_chwLBGlyphID = grstrm.ReadUShortFromFont();
+
+ // Jump to the beginning of the pass offset block, if we have this information.
+ if (*pfxdSilfVersion >= 0x00030000)
+ grstrm.SetPositionInFont(lPassBlockPos);
+ else
+ // Otherwise assume that's where we are!
+ Assert(lPassBlockPos == -1);
+
+ // offsets to passes, relative to the start of this subtable;
+ // note that we read (cPasses + 1) of these
+ int nPassOffsets[kMaxPasses];
+ for (i = 0; i <= cPasses; i++)
+ {
+ nPassOffsets[i] = grstrm.ReadIntFromFont();
+ }
+
+ // Jump to the beginning of the pseudo-glyph info block, if we have this information.
+ if (*pfxdSilfVersion >= 0x00030000)
+ grstrm.SetPositionInFont(lPseudosPos);
+ else
+ // Otherwise assume that's where we are!
+ Assert(lPseudosPos == -1);
+
+ // number of pseudo-glyphs and search constants
+ short snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_cpsd = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_dipsdInit = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_cPsdLoop = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_ipsdStart = snTmp;
+
+ // unicode-to-pseudo map
+ m_prgpsd = new GrPseudoMap[m_cpsd];
+ for (i = 0; i < m_cpsd; i++)
+ {
+ if (*pfxdSilfVersion <= 0x00010000)
+ {
+ utf16 chwUnicode = grstrm.ReadUShortFromFont();
+ m_prgpsd[i].SetUnicode(chwUnicode);
+ }
+ else
+ {
+ int nUnicode = grstrm.ReadIntFromFont();
+ m_prgpsd[i].SetUnicode(nUnicode);
+ }
+ gid16 chwPseudo = grstrm.ReadUShortFromFont();
+ m_prgpsd[i].SetPseudoGlyph(chwPseudo);
+ }
+
+ // class table
+ m_pctbl = new GrClassTable();
+ if (!m_pctbl->ReadFromFont(grstrm, *pfxdSilfVersion))
+ return false;
+
+ // passes
+ return m_ptman->CreateAndReadPasses(grstrm, *pfxdSilfVersion, fxdRuleVersion,
+ cPasses, lSubTableStart, nPassOffsets,
+ ipassSub1, ipassPos1, ipassJust1, ipassReordered1);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set up the engine with no Graphite smarts at all, just dummy tables.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::CreateEmpty()
+{
+ // Silf table
+
+ m_mXAscent = 0;
+ m_mXDescent = 0;
+
+ m_fLineBreak = false;
+
+ // range of possible cross-line-boundary contextualization
+ m_cchwPreXlbContext = 0;
+ m_cchwPostXlbContext = 0;
+
+ // Bogus attribute IDs:
+ m_chwPseudoAttr = 1; // actual glyph ID for pseudo-glyph (ID of bogus attribute)
+ m_chwBWAttr = 2; // breakweight
+ m_chwDirAttr = 3; // directionality
+
+ m_cComponents = 0; // number of component attributes
+
+ m_cnUserDefn = 0; // number of user-defined slot attributes
+ m_cnCompPerLig = 0; // max number of ligature components
+
+ m_grfsdc = kfsdcHorizLtr; // supported script direction
+
+ // linebreak glyph ID
+ m_chwLBGlyphID = 0xFFFE;
+
+ // number of pseudo-glyphs and search constants
+ m_cpsd = 0;
+ m_dipsdInit = 0;
+ m_cPsdLoop = 0;
+ m_ipsdStart = 0;
+
+ // class table
+ m_pctbl = new GrClassTable();
+ m_pctbl->CreateEmpty();
+
+ // passes
+ if (m_ptman != 0)
+ m_ptman->CreateEmpty();
+
+ // Gloc and Glat tables
+ m_pgtbl = new GrGlyphTable();
+ m_pgtbl->SetNumberOfGlyphs(0);
+ m_pgtbl->SetNumberOfComponents(0);
+ m_pgtbl->SetNumberOfStyles(1); // for now
+
+ m_pgtbl->CreateEmpty();
+
+ // Feat table
+ m_cfeat = 0;
+ m_rglcidFeatLabelLangs = NULL;
+ m_clcidFeatLabelLangs = 0;
+
+ // Language table
+ m_langtbl.CreateEmpty();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create the glyph table and fill it in from the font stream.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::ReadGlocAndGlatTables(GrIStream & grstrmGloc, long lGlocStart,
+ GrIStream & grstrmGlat, long lGlatStart,
+ int chwGlyphIDMax, int fxdSilfVersion)
+{
+ // Determine the highest used glyph ID number.
+// int chwGlyphIDMax = m_chwLBGlyphID;
+// for (int ipsd = 0; ipsd < m_cpsd; ipsd++)
+// {
+// if (m_prgpsd[ipsd].PseudoGlyph() > chwGlyphIDMax)
+// chwGlyphIDMax = m_prgpsd[ipsd].PseudoGlyph();
+// }
+
+ // Create the glyph table.
+ m_pgtbl = new GrGlyphTable();
+ m_pgtbl->SetNumberOfGlyphs(chwGlyphIDMax + 1);
+ m_pgtbl->SetNumberOfComponents(m_cComponents);
+ m_pgtbl->SetNumberOfStyles(1); // for now
+
+ return m_pgtbl->ReadFromFont(grstrmGloc, lGlocStart, grstrmGlat, lGlatStart,
+ m_chwBWAttr, m_chwJStretch0, m_cJLevels, m_cnCompPerLig, fxdSilfVersion);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the contents of the "Feat" table from the stream, which is on an extended
+ TrueType font file.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::ReadFeatTable(GrIStream & grstrm, long lTableStart)
+{
+ short snTmp;
+ data16 chwTmp;
+ int nTmp;
+
+ grstrm.SetPositionInFont(lTableStart);
+
+ // version
+ int fxdVersion = ReadVersion(grstrm);
+ if (fxdVersion > kFeatVersion)
+ return false;
+
+ // number of features
+ int cfeat;
+ cfeat = grstrm.ReadUShortFromFont();
+ if (cfeat > kMaxFeatures)
+ return false; // bad table;
+
+ // reserved
+ chwTmp = grstrm.ReadUShortFromFont();
+ nTmp = grstrm.ReadIntFromFont();
+
+ std::vector<featid> vnIDs; // unsigned ints
+ std::vector<int> vnOffsets;
+ std::vector<int> vcfset;
+
+ m_cfeat = 0;
+ int ifeat;
+ for (ifeat = 0; ifeat < cfeat; ifeat++)
+ {
+ // ID
+ featid nID;
+ if (fxdVersion >= 0x00020000)
+ nID = (unsigned int)grstrm.ReadIntFromFont();
+ else
+ nID = grstrm.ReadUShortFromFont();
+ vnIDs.push_back(nID);
+ // number of settings
+ data16 cfset = grstrm.ReadUShortFromFont();
+ vcfset.push_back(cfset);
+ if (fxdVersion >= 0x00020000)
+ grstrm.ReadShortFromFont(); // pad bytes
+ // offset to settings list
+ nTmp = grstrm.ReadIntFromFont();
+ vnOffsets.push_back(nTmp);
+ // flags
+ chwTmp = grstrm.ReadUShortFromFont();
+ Assert(chwTmp == 0x8000); // mutually exclusive
+ // index into name table of UI label
+ int nNameId = grstrm.ReadShortFromFont();
+
+ if (fxdVersion <= 0x00020000 && nID == GrFeature::knLangFeatV2)
+ {
+ // Ignore the obsolete "lang" feature which has ID = 1
+ vnIDs.pop_back();
+ vcfset.pop_back();
+ vnOffsets.pop_back();
+ continue;
+ }
+ AddFeature(nID, nNameId, cfset);
+ }
+
+ // default feature setting value and name strings;
+ for (ifeat = 0; ifeat < m_cfeat; ifeat++)
+ {
+ GrFeature * pfeat = m_rgfeat + ifeat;
+ Assert(pfeat->ID() == vnIDs[ifeat]);
+
+ grstrm.SetPositionInFont(lTableStart + vnOffsets[ifeat]);
+
+ // Each feature has been initialized with blank spots for the number of settings
+ // it has.
+ int cfset = vcfset[ifeat];
+ Assert(pfeat->NumberOfSettings() == cfset);
+ for (int ifset = 0; ifset < cfset; ifset++)
+ {
+ snTmp = grstrm.ReadShortFromFont(); // yes, signed (TT feat table spec says unsigned)
+ short snTmp2 = grstrm.ReadShortFromFont();
+ pfeat->AddSetting(snTmp, snTmp2);
+
+ if (ifset == 0)
+ {
+ // default setting value--first in list
+ pfeat->SetDefault(snTmp);
+ }
+ }
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the contents of the "Sill" table from the stream, which is on an extended
+ TrueType font file.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::ReadSillTable(GrIStream & grstrm, long lTableStart)
+{
+ grstrm.SetPositionInFont(lTableStart);
+
+ // version
+ int fxdVersion = ReadVersion(grstrm);
+ if (fxdVersion > kSillVersion)
+ return false;
+
+ return m_langtbl.ReadFromFont(&grstrm, fxdVersion);
+}
+
+/*----------------------------------------------------------------------------------------------
+ An error happened in running the tables. Set up temporary dummy tables, and try running
+ with dumb rendering.
+ Return kresUnexpected if even running the empty tables crashed, kresFail otherwise.
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::RunUsingEmpty(Segment * psegNew, Font * pfont,
+ GrCharStream * pchstrm, LayoutEnvironment & layout,
+ int ichStop,
+ float dxMaxWidth,
+ bool fNeedFinalBreak, bool fMoreText, bool fInfiniteWidth,
+ int ichwCallerBtLim,
+ int nDirDepth, SegEnd estJ)
+{
+ // Save the current state of the engine.
+ int mXAscentSave = m_mXAscent;
+ int mXDescentSave = m_mXDescent;
+ bool fLineBreakSave = m_fLineBreak;
+ int cchwPreXlbContextSave = m_cchwPreXlbContext;
+ int cchwPostXlbContextSave = m_cchwPostXlbContext;
+ data16 chwPseudoAttrSave = m_chwPseudoAttr;
+ data16 chwBWAttrSave = m_chwBWAttr;
+ data16 chwDirAttrSave = m_chwDirAttr;
+ int cComponentsSave = m_cComponents;
+ int cnUserDefnSave = m_cnUserDefn;
+ int cnCompPerLigSave = m_cnCompPerLig;
+ unsigned int grfsdcSave = m_grfsdc;
+ gid16 chwLBGlyphIDSave = m_chwLBGlyphID;
+ int cpsdSave = m_cpsd;
+ int dipsdInitSave = m_dipsdInit;
+ int cPsdLoopSave = m_cPsdLoop;
+ int ipsdStartSave = m_ipsdStart;
+ GrTableManager * ptmanSave = m_ptman;
+ GrClassTable * pctblSave = m_pctbl;
+ GrGlyphTable * pgtblSave = m_pgtbl;
+ int cfeatSave = m_cfeat;
+ GrResult resFontReadSave = m_resFontRead;
+
+ GrResult res = kresFail;
+
+ pchstrm->Restart();
+
+ // Create dummy versions of the tables and run them.
+ m_pctbl = NULL;
+ m_pgtbl = NULL;
+ m_ptman = new GrTableManager(this);
+ m_ptman->State()->SetFont(pfont);
+ CreateEmpty();
+
+ try
+ {
+ m_ptman->Run(psegNew, pfont, pchstrm, NULL, kjmodiNormal, layout,
+ ichStop, dxMaxWidth, 0,
+ fNeedFinalBreak, fMoreText, -1, fInfiniteWidth, false,
+ ichwCallerBtLim,
+ nDirDepth, estJ);
+ }
+ catch(...)
+ {
+ // Still didn't work. Oh, well, not much we can do.
+ res = kresUnexpected;
+ }
+
+ psegNew->SetErroneous(true);
+
+ if (m_ptman)
+ delete m_ptman;
+ if (m_pctbl)
+ delete m_pctbl;
+ if (m_pgtbl)
+ delete m_pgtbl;
+
+ // Put everything back the way it was.
+ m_mXAscent = mXAscentSave;
+ m_mXDescent = mXDescentSave;
+ m_fLineBreak = fLineBreakSave;
+ m_cchwPreXlbContext = cchwPreXlbContextSave;
+ m_cchwPostXlbContext = cchwPostXlbContextSave;
+ m_chwPseudoAttr = chwPseudoAttrSave;
+ m_chwBWAttr = chwBWAttrSave;
+ m_chwDirAttr = chwDirAttrSave;
+ m_cComponents = cComponentsSave;
+ m_cnUserDefn = cnUserDefnSave;
+ m_cnCompPerLig = cnCompPerLigSave;
+ m_grfsdc = grfsdcSave;
+ m_chwLBGlyphID = chwLBGlyphIDSave;
+ m_cpsd = cpsdSave;
+ m_dipsdInit = dipsdInitSave;
+ m_cPsdLoop = cPsdLoopSave;
+ m_ipsdStart = ipsdStartSave;
+ m_ptman = ptmanSave;
+ m_pctbl = pctblSave;
+ m_pgtbl = pgtblSave;
+ m_cfeat = cfeatSave;
+ m_resFontRead = resFontReadSave;
+
+ return res;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the glyph ID for the given Unicode value.
+----------------------------------------------------------------------------------------------*/
+gid16 GrEngine::GetGlyphIDFromUnicode(int nUnicode)
+{
+ gid16 chwGlyphID = MapToPseudo(nUnicode);
+ if (chwGlyphID != 0)
+ return chwGlyphID; // return a pseudo-glyph
+
+#ifdef OLD_TEST_STUFF
+ if (!m_pCmap31)
+ // test procedures
+ return chwUnicode;
+#endif // OLD_TEST_STUFF
+
+ // Otherwise, get the glyph ID from the font's cmap.
+
+ if (m_pCmap_3_10)
+ return gid16(TtfUtil::Cmap310Lookup(m_pCmap_3_10, nUnicode));
+ else if (m_pCmap_3_1)
+ return gid16(TtfUtil::Cmap31Lookup(m_pCmap_3_1, nUnicode));
+ else
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the pseudo-glyph corresponding to the given Unicode input, or 0 if none.
+----------------------------------------------------------------------------------------------*/
+gid16 GrEngine::MapToPseudo(int nUnicode)
+{
+ if (m_cpsd == 0)
+ return 0;
+
+#ifdef _DEBUG
+ int nPowerOf2 = 1;
+ while (nPowerOf2 <= m_cpsd)
+ nPowerOf2 <<= 1;
+ nPowerOf2 >>= 1;
+ // Now nPowerOf2 is the max power of 2 <= m_cpds
+ Assert((1 << m_cPsdLoop) == nPowerOf2); // m_cPsdLoop == log2(nPowerOf2)
+ Assert(m_dipsdInit == nPowerOf2);
+ Assert(m_ipsdStart == m_cpsd - m_dipsdInit);
+#endif // _DEBUG
+
+ int dipsdCurr = m_dipsdInit;
+
+ GrPseudoMap * ppsdCurr = m_prgpsd + m_ipsdStart;
+ while (dipsdCurr > 0)
+ {
+ int nTest;
+ if (ppsdCurr < m_prgpsd)
+ nTest = -1;
+ else
+ nTest = ppsdCurr->Unicode() - nUnicode;
+
+ if (nTest == 0)
+ return ppsdCurr->PseudoGlyph();
+
+ dipsdCurr >>= 1; // divide by 2
+ if (nTest < 0)
+ ppsdCurr += dipsdCurr;
+ else // (nTest > 0)
+ ppsdCurr -= dipsdCurr;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the actual glyph ID to use for glyph metrics and output. For most glyphs, this
+ is just the glyph ID we're already working with, but for pseudo-glyphs it will something
+ different.
+----------------------------------------------------------------------------------------------*/
+gid16 GrEngine::ActualGlyphForOutput(gid16 chwGlyphID)
+{
+ gid16 chwActual = gid16(GlyphAttrValue(chwGlyphID, m_chwPseudoAttr));
+ if (chwActual == 0)
+ return chwGlyphID; // not a pseudo, we're already working with the actual glyph ID
+ else
+ return chwActual;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Look up name based on lang id and name id in name table.
+ Currently used to look up feature names.
+----------------------------------------------------------------------------------------------*/
+std::wstring GrEngine::StringFromNameTable(int nLangID, int nNameID)
+{
+ std::wstring stuName;
+ stuName.erase();
+ size_t lOffset = 0;
+ size_t lSize = 0;
+
+ // The Graphite compiler stores our names in either
+ // the MS (platform id = 3) Unicode (writing system id = 1) table
+ // or the MS Symbol (writing system id = 0) table. Try MS Unicode first.
+ // lOffset & lSize are in bytes.
+ // new interface:
+ if (!TtfUtil::GetNameInfo(m_pNameTbl, 3, 1, nLangID, nNameID, lOffset, lSize))
+ {
+ if (!TtfUtil::GetNameInfo(m_pNameTbl, 3, 0, nLangID, nNameID, lOffset, lSize))
+ {
+ return stuName;
+ }
+ }
+
+ size_t cchw = (unsigned(lSize) / sizeof(utf16));
+ utf16 * pchwName = new utf16[cchw+1]; // lSize - byte count for Uni str
+ const utf16 *pchwSrcName = reinterpret_cast<const utf16*>(m_pNameTbl + lOffset);
+ std::transform(pchwSrcName, pchwSrcName + cchw, pchwName, std::ptr_fun<utf16,utf16>(lsbf));
+ pchwName[cchw] = 0; // zero terminate
+ #ifdef _WIN32
+ stuName.assign((const wchar_t*)pchwName, cchw);
+ #else
+ wchar_t * pchwName32 = new wchar_t[cchw+1]; // lSize - byte count for Uni str
+ for (int i = 0; i <= signed(cchw); i++) {
+ pchwName32[i] = pchwName[i];
+ }
+ stuName.assign(pchwName32, cchw);
+ delete [] pchwName32;
+ #endif
+
+ delete [] pchwName;
+ return stuName;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add a feature (eg, when loading from the font).
+----------------------------------------------------------------------------------------------*/
+void GrEngine::AddFeature(featid nID, int nNameId, int cfset, int nDefault)
+{
+ if (m_cfeat >= kMaxFeatures)
+ return;
+
+ int ifeat = m_cfeat;
+ m_rgfeat[ifeat].Initialize(nID, nNameId, cfset, nDefault);
+// m_hmnifeat.Insert(nID, ifeat);
+ m_cfeat++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the feature with the given ID, or NULL if none.
+----------------------------------------------------------------------------------------------*/
+GrFeature * GrEngine::FeatureWithID(featid nID, int * pifeat)
+{
+ for (int ifeat = 0; ifeat < m_cfeat; ifeat++)
+ {
+ if (m_rgfeat[ifeat].ID() == nID)
+ {
+ *pifeat = ifeat;
+ return m_rgfeat + ifeat;
+ }
+ }
+ *pifeat = -1;
+ return NULL;
+
+
+ // Alternate implementation if we end up with so many features that we need to use
+ // a hash map:
+// int ifeat;
+// if (m_hmnifeat.Retrieve(nID, &ifeat))
+// {
+// Assert(ifeat < kMaxFeatures);
+// return m_rgfeat + ifeat; // may be NULL
+// }
+// else
+// return NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the default for the feature at the given index in the array.
+----------------------------------------------------------------------------------------------*/
+int GrEngine::DefaultForFeatureAt(int ifeat)
+{
+ Assert(ifeat < kMaxFeatures);
+ if (ifeat >= m_cfeat || ifeat < 0)
+ return 0; // undefined feature
+
+ return m_rgfeat[ifeat].DefaultValue();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the default for the feature at the given index in the array.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetDefaultForFeatureAt(int ifeat, int nValue)
+{
+ Assert(ifeat < kMaxFeatures);
+ Assert(ifeat < m_cfeat);
+ if (ifeat >= 0)
+ m_rgfeat[ifeat].SetDefault(nValue);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the default feature settings for the given language.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::DefaultsForLanguage(isocode lgcode,
+ std::vector<featid> & vnFeats, std::vector<int> & vnValues)
+{
+ m_langtbl.LanguageFeatureSettings(lgcode, vnFeats, vnValues);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the directionality and breakweight attributes of a new slot based on its
+ glyph ID.
+ REVIEW: we could optimize by not initializing from the glyph table right away,
+ but waiting until we need the value.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::InitSlot(GrSlotState * pslot, int nUnicode)
+{
+ gid16 chwGlyphID = pslot->GlyphID();
+
+ if (m_ptman->InternalJustificationMode() != kjmodiNormal)
+ {
+ if (m_cJLevels > 0)
+ {
+ Assert(m_cJLevels == 1); // for now
+ // TODO: do this at level 0.
+ pslot->SetJStretch(m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwJStretch0));
+ pslot->SetJShrink( m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwJShrink0));
+ pslot->SetJStep( m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwJStep0));
+ pslot->SetJWeight( m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwJWeight0));
+ }
+ else if (nUnicode == knSpace)
+ {
+ // Basic stretch/shrink for whitespace.
+ // TODO: do this at level 0.
+ Assert(m_fBasicJust);
+ int mAdv = pslot->AdvanceX(m_ptman);
+ pslot->SetJStretch(mAdv * 100); // stretch up to 100 times natural width
+ pslot->SetJShrink(mAdv / 4); // shrink to 75%
+ pslot->SetJWeight(1);
+ }
+ }
+
+ if (m_pgtbl && !m_pgtbl->IsEmpty())
+ {
+ // Initialize from glyph table.
+ pslot->SetBreakWeight(m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwBWAttr));
+
+ DirCode dirc = DirCode(m_pgtbl->GlyphAttrValue(chwGlyphID, m_chwDirAttr));
+ if (BidiCode(nUnicode) && (chwGlyphID == 0 || dirc == kdircNeutral))
+ // A built-in character for the bidi algorithm that is not defined in the font but
+ // must be given a special directionality:
+ goto LDefaults;
+
+ pslot->SetDirectionality(dirc);
+
+ return;
+ }
+
+LDefaults:
+ // Otherwise, in fill defaults for some basic values.
+ if (pslot->BreakWeight() == GrSlotState::kNotYetSet8)
+ {
+ switch (nUnicode)
+ {
+ case knSpace:
+ pslot->SetBreakWeight(klbWordBreak);
+ break;
+ case knHyphen:
+ pslot->SetBreakWeight(klbHyphenBreak);
+ break;
+ default:
+ pslot->SetBreakWeight(klbLetterBreak);
+ }
+ }
+
+ if ((int)pslot->Directionality() == GrSlotState::kNotYetSet8)
+ {
+ switch (nUnicode)
+ {
+ case knSpace:
+ pslot->SetDirectionality(kdircWhiteSpace);
+ break;
+ case knLRM:
+ pslot->SetDirectionality(kdircL);
+ break;
+ case knRLM:
+ pslot->SetDirectionality(kdircR);
+ break;
+ case knLRO:
+ pslot->SetDirectionality(kdircLRO);
+ break;
+ case knRLO:
+ pslot->SetDirectionality(kdircRLO);
+ break;
+ case knLRE:
+ pslot->SetDirectionality(kdircLRE);
+ break;
+ case knRLE:
+ pslot->SetDirectionality(kdircRLE);
+ break;
+ case knPDF:
+ pslot->SetDirectionality(kdircPDF);
+ break;
+ default:
+ if (chwGlyphID == LBGlyphID())
+ pslot->SetDirectionality(kdircNeutral);
+ else
+ pslot->SetDirectionality(kdircL);
+ }
+ }
+ else
+ Assert(false); // currently no way to set directionality ahead of time
+}
+
+/*----------------------------------------------------------------------------------------------
+ We have just changed this slot's glyph ID. Change the directionality and breakweight
+ attributes of a new slot based on its glyph ID.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetSlotAttrsFromGlyphAttrs(GrSlotState * pslot)
+{
+ InitSlot(pslot);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create a new segment.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::NewSegment(Segment ** ppseg)
+{
+ *ppseg = new Segment;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Methods to pass on to the tables.
+----------------------------------------------------------------------------------------------*/
+gid16 GrEngine::GetClassGlyphIDAt(int nClass, int nIndex)
+{
+ if (nIndex < 0)
+ return 0;
+ if (nClass < 0)
+ return 0;
+
+ try {
+ return m_pctbl->GetGlyphID(nClass, nIndex);
+ }
+ catch (...)
+ {
+ return 0;
+ }
+}
+
+int GrEngine::GetIndexInGlyphClass(int nClass, gid16 chwGlyphID)
+{
+ try {
+ return m_pctbl->FindIndex(nClass, chwGlyphID);
+ }
+ catch (...)
+ {
+ return -1;
+ }
+}
+
+size_t GrEngine::NumberOfGlyphsInClass(int nClass)
+{
+ try {
+ return m_pctbl->NumberOfGlyphsInClass(nClass);
+ }
+ catch (...)
+ {
+ return 0;
+ }
+}
+
+int GrEngine::GlyphAttrValue(gid16 chwGlyphID, int nAttrID)
+{
+#ifdef OLD_TEST_STUFF
+ if (!m_pgtbl) // test procedures
+ return 0;
+#endif // OLD_TEST_STUFF
+
+ return m_pgtbl->GlyphAttrValue(chwGlyphID, nAttrID);
+}
+
+int GrEngine::ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID)
+{
+#ifdef OLD_TEST_STUFF
+ if (!m_pgtbl) // test procedures
+ return -1;
+#endif // OLD_TEST_STUFF
+
+ return m_pgtbl->ComponentIndexForGlyph(chwGlyphID, nCompID);
+}
+
+
+//:>********************************************************************************************
+//:> For test procedures
+//:>********************************************************************************************
+
+//:Ignore
+
+#ifdef OLD_TEST_STUFF
+
+void GrEngine::SetUpPseudoGlyphTest()
+{
+ m_cpsd = 5;
+
+ m_prgpsd = new GrPseudoMap[m_cpsd];
+
+ m_prgpsd[0].SetUnicode(65);
+ m_prgpsd[0].SetPseudoGlyph(1065);
+
+ m_prgpsd[1].SetUnicode(66);
+ m_prgpsd[1].SetPseudoGlyph(1066);
+
+ m_prgpsd[2].SetUnicode(67);
+ m_prgpsd[2].SetPseudoGlyph(1067);
+
+ m_prgpsd[3].SetUnicode(68);
+ m_prgpsd[3].SetPseudoGlyph(1068);
+
+ m_prgpsd[4].SetUnicode(69);
+ m_prgpsd[4].SetPseudoGlyph(1069);
+
+ m_dipsdInit = 4;
+ m_cPsdLoop = 2;
+ m_ipsdStart = 1;
+}
+
+#endif // OLD_TEST_STUFF
+
+
+//:>********************************************************************************************
+//:> New interface
+//:>********************************************************************************************
+/*----------------------------------------------------------------------------------------------
+ Store the default features values as specified by the client.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::AssignDefaultFeatures(int cfeat, FeatureSetting * prgfset)
+{
+ for (int ifeatIn = 0; ifeatIn < cfeat; ifeatIn++)
+ {
+ int ifeat;
+ FeatureWithID(prgfset[ifeatIn].id, &ifeat);
+ if (ifeat >= 0 )
+ SetDefaultForFeatureAt(ifeat, prgfset[ifeatIn].value);
+ }
+}
+
+bool GrEngine::LoggingTransduction()
+{
+ Assert(false);
+ //return m_pfface->getLogging();
+ //return m_fLogXductn;
+ return true;
+}
+
+} // namespace gr
+
+//:End Ignore
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.h
new file mode 100644
index 00000000000..6dc270a38af
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrEngine.h
@@ -0,0 +1,622 @@
+/*--------------------------------------------------------------------
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrEngine.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Contains the definition of the GrEngine class.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_ENGINE_INCLUDED
+#define GR_ENGINE_INCLUDED
+#include <limits>
+
+#ifdef _MSC_VER
+#include <crtdbg.h>
+#endif
+
+namespace gr
+{
+class IGrJustifier;
+class Segment;
+
+
+/*----------------------------------------------------------------------------------------------
+ The GrEngine serves as the top level object that knows how to run Graphite tables
+ and generate Graphite segments.
+
+ Primarily, this class implements IRenderEngine, which allows it to serve as a FW
+ rendering engine. It also implements ISimpleInit, a general interface for initializing
+ using a string. Finally, it implements ITraceControl, a very simple interface which
+ allows a client to flip a flag indicating whether or not we want to output a log of
+ the Graphite transduction process.
+
+ Hungarian: greng
+----------------------------------------------------------------------------------------------*/
+class GrEngine : public GraphiteProcess
+{
+ friend class FontFace;
+ friend class FontMemoryUsage;
+
+public:
+ // Constructors & destructors:
+ GrEngine();
+ void BasicInit();
+ virtual ~GrEngine();
+ void DestroyContents(bool fDestroyCmap = true);
+
+ // ISimpleInit methods:
+ ////GrResult InitNew(const byte * prgb, int cb); -- obsolete
+ ////GrResult get_InitializationData(int cchMax, OLECHAR * rgchw, int * pcch); -- obsolete
+
+ // ITraceControl methods:
+ //GrResult SetTracing(int n);
+ //GrResult GetTracing(int * pnOptions);
+
+ // IRenderingFeatures methods:
+ //GrResult GetFeatureIDs(int cMax, int * prgFids, int * pcfid);
+ //GrResult GetFeatureLabel(int fid, int nLanguage, int cchMax, OLECHAR * rgchw, int * pcch);
+ //GrResult GetFeatureValues(int fid, int cfvalMax,
+ // int * prgfval, int * pcfval, int * pfvalDefault);
+ //GrResult GetFeatureValueLabel(int fid, int fval, int nLanguage,
+ // int cchMax, OLECHAR * rgchw, int * pcch);
+
+ // IRenderEngine methods:
+ ////GrResult InitRenderer(IGrGraphics * pgg, OLECHAR * prgchData, int cchData); -- obsolete
+ ////GrResult FontIsValid(OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ GrResult get_SegDatMaxLength(int * pcb);
+
+ //GrResult FindBreakPoint(Font * pfont, ITextSource * pgts, DELETE
+ // int ichMin, int ichLim, int ichLimBacktrack,
+ // bool fNeedFinalBreak,
+ // bool fStartLine,
+ // float dxMaxWidth,
+ // LineBrk lbPref, LineBrk lbMax,
+ // TrWsHandling twsh, bool fParaRtoL,
+ // Segment ** ppsegRet,
+ // int * pdichwLimSeg, float * pdxWidth, SegEnd * pest,
+ // int cbPrev, byte * pbPrevSegDat,
+ // int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat,
+ // int * pdichwContext,
+ // std::ostream * pstrmLog,
+ // OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ //GrResult FindBreakPointWJust(Font * pfont, ITextSource * pgts, IGrJustifier * pgjus,
+ // int ichMin, int ichLim, int ichLimBacktrack, DELETE
+ // bool fNeedFinalBreak,
+ // bool fStartLine,
+ // float dxMaxWidth,
+ // LineBrk lbPref, LineBrk lbMax,
+ // TrWsHandling twsh, bool fParaRtoL,
+ // Segment ** ppsegRet,
+ // int * pdichwLimSeg, float * pdxWidth, SegEnd * pest,
+ // int cbPrev, byte * pbPrevSegDat,
+ // int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat,
+ // int * pdichwContext,
+ // std::ostream * pstrmLog,
+ // OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ GrResult get_ScriptDirection(unsigned int * pgrfsdc, OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ // DELETE
+ //GrResult MakeJustifiedSegment(Font * pfont, ITextSource * pgts, IGrJustifier * pgj,
+ // int ichMin, int ichLim,
+ // bool fStartLine, bool fEndLine,
+ // float dxUnjustifiedWidth, float dxJustifiedWidth,
+ // TrWsHandling twsh, SegEnd est, LineBrk lb,
+ // bool fParaRtl,
+ // Segment ** ppsegRet, float * pdxWidth,
+ // //int cbPrev, byte * pbPrevSegDat, int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat, int * pdichwContext,
+ // std::ostream * pstrmLog,
+ // OLECHAR * prgchwErrMsg, int cchwMaxErrMsg);
+
+ // IJustifyingRenderer methods:
+ // These methods return kresInvalidArg if the attribute ID is invalid or inappropriate;
+ // kresFail if the engine is not in an appropriate state to return the information.
+ virtual GrResult getGlyphAttribute(int iGlyph, int jgat, int nLevel, float * pValueRet);
+ virtual GrResult getGlyphAttribute(int iGlyph, int jgat, int nLevel, int * pValueRet);
+ virtual GrResult setGlyphAttribute(int iGlyph, int jgat, int nLevel, float value);
+ virtual GrResult setGlyphAttribute(int iGlyph, int jgat, int nLevel, int value);
+
+ // Interface methods not used by FW:
+
+ ////GrResult IsGraphiteFont(IGrGraphics * pgg); -- obsolete
+
+ ////GrResult FontAscentAndDescent(IGrGraphics * pgg, int * pysAscent, int * pysDescent); -- obsolete
+
+ //GrResult MakeMeasuredSegment(
+ // Font * pfont, ITextSource * pgts,
+ // int ichMin, int ichLim,
+ // bool fParaRtl,
+ // Segment ** ppsegRet, SegEnd * pest,
+ // std::ostream * pstrmLog,
+ // OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ //GrResult MakeSegmentFromRange(Font * pfont, ITextSource * pgts, IGrJustifier * pgj,
+ // int ichMin, int ichLim,
+ // bool fStartLine, bool fEndLine,
+ // TrWsHandling twsh, bool fParaRtl,
+ // Segment ** ppsegRet, float * pdxWidth, SegEnd * pest,
+ // int cbPrev, byte * pbPrevSegDat, int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat,
+ // int * pdichwContext,
+ // std::ostream * pstrmLog,
+ // OLECHAR * prgchwErrMsg, int cchwMaxErrMsg);
+
+ // NEW interface
+
+ GrResult ReadFontTables(Font * pfont, bool fItalic);
+
+ FontErrorCode IsValidForGraphite(int * pnVersion, int * pnSubVersion);
+
+ // Other public methods
+
+ GrResult FindBreakPointAux(Font * pfont, ITextSource * pgts, IGrJustifier * pgjus,
+ int ichwMin, int ichwLim, int ichwLimBacktrack,
+ bool fNeedFinalBreakArg, bool fStartLine, bool fEndLine,
+ float dxMaxWidth, bool fWidthIsCharCount,
+ LineBrk lbPref, LineBrk lbMax, TrWsHandling twsh, bool fParaRtl,
+ Segment ** ppsegRet,
+ int * pdichwLimSeg,
+ float * pdxWidth, SegEnd * pest,
+ int cbPrev, byte * pbPrevSegDat,
+ int cbNextMax, byte * pbNextSegDat, int * pcbNextSegDat,
+ int * pdichwContext,
+ std::ostream * pstrmLog,
+ OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+
+ gid16 GetGlyphIDFromUnicode(int nUnicode);
+ gid16 ActualGlyphForOutput(utf16 chwGlyphID);
+
+ int GetFontEmUnits()
+ {
+ return m_mFontEmUnits;
+ }
+
+ gid16 LBGlyphID()
+ {
+ return m_chwLBGlyphID;
+ }
+
+ gid16 GetClassGlyphIDAt(int nClass, int nIndex);
+ int GetIndexInGlyphClass(int nClass, gid16 chwGlyphID);
+ size_t NumberOfGlyphsInClass(int nClass);
+ int GlyphAttrValue(gid16 chwGlyphID, int nAttrID);
+ int ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID);
+
+ ////void InitFontName(std::wstring stuInitialize, std::wstring & stuFaceName, std::wstring & stuFeatures); -- obsolete
+ void RecordFontLoadError(OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+ void RecordFontRunError(OLECHAR * prgchwErrMsg, int cchMaxErrMsg, GrResult res);
+ void ClearFontError(OLECHAR * prgchwErrMsg, int cchMaxErrMsg);
+ void GetWritingSystemDirection(ITextSource * pgts, int ichwMin);
+ ////GrResult SetUp(IGrGraphics * pgg, std::wstring stuFeatures); -- obsolete
+ ////GrResult SetUp(IGrGraphics * pgg, std::wstring stuFeaturesArg, bool fBold, bool fItalic); -- obsolete
+
+ GrResult RunUsingEmpty(Segment * psegNew, Font * pfont,
+ GrCharStream * pchstrm, LayoutEnvironment & layout,
+ int ichStop,
+ float dxMaxWidth,
+ bool fNeedFinalBreak, bool fMoreText, bool fInfiniteWidth,
+ int ichwCallerBtLim,
+ int nDirDepth, SegEnd estJ);
+ bool InErrorState()
+ {
+ return m_fInErrorState;
+ }
+
+ std::wstring FaceName()
+ {
+ return m_stuFaceName;
+ }
+ std::wstring BaseFaceName()
+ {
+ Assert(m_stuBaseFaceName.size() == 0 || m_fUseSepBase);
+ return m_stuBaseFaceName; // empty if not using separate base font
+ }
+ bool Bold()
+ {
+ return m_fBold;
+ }
+ bool Italic()
+ {
+ return m_fItalic;
+ }
+
+ void GetStyles(Font * pfont, int ichwMin, bool * pfBold, bool * pfItalic);
+ void SwitchGraphicsFont(bool fBase);
+
+ void AddFeature(featid nID, int nNameId, int cfset, int nDefault = 0);
+ GrFeature * FeatureWithID(featid nID, int * pifeat);
+ int DefaultForFeatureAt(int ifeat);
+ void SetDefaultForFeatureAt(int ifeat, int nValue);
+ GrFeature * Feature(int ifeat)
+ {
+ if (ifeat >= kMaxFeatures)
+ return NULL;
+ return m_rgfeat + ifeat;
+ }
+ void DefaultsForLanguage(isocode lgcode,
+ std::vector<featid> & vnFeats, std::vector<int> & vnValues);
+ std::wstring StringFromNameTable(int nNameId, int nLang);
+
+ void InitSlot(GrSlotState *, int nUnicode = -1);
+ void SetSlotAttrsFromGlyphAttrs(GrSlotState *);
+
+ bool RightToLeft()
+ {
+ return m_fRightToLeft;
+ }
+ int TopDirectionLevel()
+ {
+ return (m_fRightToLeft) ? 1 : 0;
+ }
+
+ GrGlyphTable * GlyphTable()
+ {
+ return m_pgtbl;
+ }
+
+ GrClassTable * ClassTable()
+ {
+ return m_pctbl;
+ }
+
+ int NumFeat()
+ {
+ return m_cfeat;
+ }
+
+ bool LineBreakFlag()
+ {
+ return m_fLineBreak;
+ }
+
+ int PreXlbContext()
+ {
+ return m_cchwPreXlbContext;
+ }
+
+ int PostXlbContext()
+ {
+ return m_cchwPostXlbContext;
+ }
+
+ int ExtraAscent()
+ {
+ return m_mXAscent;
+ }
+
+ int ExtraDescent()
+ {
+ return m_mXDescent;
+ }
+
+ float VerticalOffset()
+ {
+ return m_dysOffset;
+ }
+
+ int NumUserDefn()
+ {
+ return m_cnUserDefn;
+ }
+
+ int NumCompPerLig()
+ {
+ return m_cnCompPerLig;
+ }
+
+ bool BasicJustification()
+ {
+ return m_fBasicJust;
+ }
+
+ bool LoggingTransduction();
+ //{
+ // return m_pfface->getLogging();
+ // //return m_fLogXductn;
+ //}
+
+ bool FakeItalic()
+ {
+ return m_fFakeItalic;
+ }
+
+ void NewSegment(Segment ** ppseg);
+
+ static int ReadVersion(GrIStream & grstrm);
+
+ /*----------------------------------------------------------------------------------------------
+ Function to convert between coordinate systems.
+ This is identical to the built-in MulDiv function except that it rounds with better
+ precision.
+
+ TODO: move these out of GrEngine to someplace more general.
+ ----------------------------------------------------------------------------------------------*/
+ inline static int GrIntMulDiv(const int v, const int n, const int d)
+ {
+ return int(n < 0 ?
+ (double(v * n)/double(d)) - 0.5 :
+ (double(v * n)/double(d)) + 0.5);
+ }
+ inline static float GrFloatMulDiv(const float v, const float n, const float d)
+ {
+ return v * n / d;
+ }
+ inline static float GrIFIMulDiv(const int v, const float n, const int d)
+ {
+ return float(double(v) * n / double(d));
+ }
+ inline static int GrFIFMulDiv(const float v, const int n, const float d)
+ {
+ return int(n < 0 ?
+ (v * double(n) / double(d)) - 0.5 :
+ (v * double(n) / double(d)) + 0.5);
+ }
+ inline static int RoundFloat(const float n)
+ {
+ return int(n < 0 ? n - 0.5 : n + 0.5);
+ }
+
+protected:
+ // Member variables:
+
+ long m_cref;
+
+ //////////// Font information ////////////
+
+ bool m_fBold;
+ bool m_fItalic;
+
+ // do we have the capacity to perform smart rendering for the various styles?
+ bool m_fSmartReg;
+ bool m_fSmartBold;
+ bool m_fSmartItalic;
+ bool m_fSmartBI;
+ // are the italics faked using a slant?
+ bool m_fFakeItalicCache;
+ bool m_fFakeBICache;
+ // control files for styled text; empty means not yet determined
+ std::wstring m_strCtrlFileReg; // regular
+ std::wstring m_strCtrlFileBold; // bold
+ std::wstring m_strCtrlFileItalic; // italic
+ std::wstring m_strCtrlFileBI; // bold-italic
+
+ bool m_fFakeItalic; // true if we are simulating an italic slant in positioning
+
+ std::wstring m_stuCtrlFile; // control file (.ttf file) from which we got
+ // currently loaded files
+
+ std::wstring m_stuInitError; // description of any error that happened while initializing
+ // the engine
+ std::wstring m_stuErrCtrlFile; // file for which the error occurred
+
+ std::wstring m_stuFaceName; // eg, "Times New Roman"
+ std::wstring m_stuFeatures;
+
+ bool m_fUseSepBase;
+ std::wstring m_stuBaseFaceName; // from Sile table; empty if we are not using a separate
+ // control file
+
+ GrResult m_resFontRead; // kresOk if the Graphite font was loaded successfully;
+ // kresFail if the font could not be found or basic tables couldn't be read;
+ // kresFalse if the Silf table is not present;
+ // kresUnexpected if the Graphite tables could not be loaded
+
+ GrResult m_resFontValid; // kresInvalidArg if the engine is not yet initialized
+ // Originally:
+ // kresOk if Graphite font & dc font match cmaps
+ // kresUnexpected/kresFalse if dumb rendering
+ // kresFail if dumb rendering with no cmap
+ // But now it is apparently just = to m_resFontRead otherwise.
+ FontErrorCode m_ferr;
+ int m_fxdBadVersion;
+
+ int m_nFontCheckSum; // when loading a font using the GrGraphics, remember the
+ // check sum as a unique identifer
+
+ int m_nScriptTag; // from the pertinent writing system; currently not used
+ unsigned int m_grfsdc; // supported script directions
+
+ bool m_fRightToLeft; // overall writing-system direction
+
+ int m_mXAscent; // extra ascent, in font's em-units
+ int m_mXDescent; // extra descent, in font's em_units
+
+ float m_dysOffset; // vertical offset, in logical units (eg, for super/subscript)
+
+ bool m_fBasicJust; // true if there are no complex justification tables/rules in the
+ // font, so we use basic whitespace justification
+ int m_cJLevels; // number of justification levels
+
+ GrTableManager * m_ptman;
+ GrClassTable * m_pctbl;
+ GrGlyphTable * m_pgtbl;
+
+ FontFace * m_pfface;
+
+ GrFeature m_rgfeat[kMaxFeatures];
+// HashMap<int, int> m_hmnifeat; // maps from feature IDs to indices in the array
+// // Review: do we need this, or is a linear search adequate?
+ int m_cfeat; // number of features present
+
+ short * m_rglcidFeatLabelLangs; // LCIDs (language IDs) for all the labels in the feature table
+ size_t m_clcidFeatLabelLangs;
+
+ GrLangTable m_langtbl;
+
+ // are line-breaks relevant at all?
+ bool m_fLineBreak;
+ // ranges for possible cross-line-boundary contextualization
+ int m_cchwPreXlbContext;
+ int m_cchwPostXlbContext;
+
+ // magic glyph attribute numbers
+ data16 m_chwPseudoAttr; // actual-for-pseudo fake glyph attribute
+ data16 m_chwBWAttr; // break-weight
+ data16 m_chwDirAttr; // directionality
+ data16 m_chwJStretch0; // justify.0.stretch
+ data16 m_chwJShrink0; // justify.0.shrink
+ data16 m_chwJStep0; // justify.0.step
+ data16 m_chwJWeight0; // justify.0.weight
+
+ gid16 m_chwLBGlyphID; // magic line-break glyph ID
+
+ int m_cComponents; // number of glyph attributes at the beginning of the glyph table
+ // that actually represent ligature components
+
+ int m_cnUserDefn; // number of user-defined slot attributes
+ int m_cnCompPerLig; // max number of components needed per ligature
+
+ int m_mFontEmUnits; // number of design units in the Em square for the font
+
+ // for pseudo-glyph mappings
+ int m_cpsd; // number of psuedo-glyphs
+ GrPseudoMap * m_prgpsd;
+ int m_dipsdInit; // (max power of 2 <= m_cpsd);
+ // size of initial range to consider
+ int m_cPsdLoop; // log2(max power of 2 <= m_cpsd);
+ // indicates how many iterations are necessary
+ int m_ipsdStart; // m_cpsd - m_dipsdInit;
+ // where to start search
+
+ // for Unicode to glyph ID mapping
+ ////TableBuffer m_tbufCmap; // hold the full cmap table
+ void * m_pCmap_3_1; // point to the MS Unicode cmap subtable
+ // uses platform 3 writing system 1 or 0, preferably 1
+ // use for Unicode to Glyph ID conversion
+ void * m_pCmap_3_10;
+ byte * m_pCmapTbl;
+ bool m_fCmapTblCopy;
+ int m_cbCmapTbl; // needed only for memory instrumentation
+
+ // for feature names and maybe other strings from font later
+ ////TableBuffer m_tbufNameTbl; // hold full name table; use Name() method to access
+ byte * m_pNameTbl;
+ bool m_fNameTblCopy;
+ int m_cbNameTbl; // needed only for memory instrumentation
+
+ bool m_fLogXductn; // true if we want to log the transduction process
+
+ bool m_fInErrorState; // true if we are handling a rendering error
+
+ // Other protected methods:
+
+ enum {
+ ksegmodeBreak = 0, // FindBreakPoint
+ ksegmodeJust, // MakeJustifiedSegment
+ //ksegmodeMms, // MakeMeasuredSegment
+ ksegmodeRange // MakeSegmentFromRange
+ };
+
+ void MakeSegment(
+ // Common parameters
+ Segment * psegRet,
+ Font * pfont, ITextSource * pgts, IGrJustifier * pjus,
+ LayoutEnvironment & layout,
+ int ichMin, int ichLim,
+ // for finding a line break
+ float dxMaxWidth,
+ bool fBacktracking,
+ // for making a justified segment
+ bool fJust, float dxJustifiedWidthJ, SegEnd estJ);
+
+ int FindFontLim(ITextSource * pgts, int ichFontMin, int * pnDirDepth);
+
+#ifdef GR_FW
+ ////GrResult InitFromControlFile(IGrGraphics * pgg, std::wstring stuFaceName,
+ //// bool fBold, bool fItalic); -- obsolete
+ ////GrResult ReadFromControlFile(std::wstring stuFontFile); -- obsolete
+// GrResult GetFallBackFont(std::wstring * pstu);
+#endif
+
+ ////GrResult ReadFromGraphicsFont(IGrGraphics * pgg, bool fItalic); -- obsolete
+ void DestroyEverything();
+
+ bool CheckTableVersions(GrIStream * pgrstrm,
+ const byte *silf_tbl, int lSilfStart,
+ const byte *gloc_tbl, int lGlocStart,
+ const byte *feat_tbl, int lFeatStart,
+ int * pfxdBadVersion);
+ //bool ReadSileTable(GrIStream & grstrm, long lTableSTart,
+ // int * pmFontEmUnits, bool * pfMismatchedBase);
+ bool ReadSilfTable(GrIStream & grstrm, long lTableStart, int iSubTable,
+ int * pchwMaxGlyphID, int * pfxdVersion);
+ bool ReadGlocAndGlatTables(GrIStream & grstrm, long lGlocStart, GrIStream & glat_strm, long lGlatStart,
+ int chwMaxGlyphID, int fxdSilfVersion);
+ bool ReadFeatTable(GrIStream & grstrm, long lTableStart);
+ bool ReadSillTable(GrIStream & grstrm, long lTableStart);
+ bool SetCmapAndNameTables(Font * pfont);
+
+ void CreateEmpty();
+
+ bool BadFont(FontErrorCode * pferr = NULL)
+ {
+ if (pferr)
+ *pferr = m_ferr;
+ return (m_resFontValid == kresFail || m_resFontRead == kresFail);
+ }
+ bool DumbFallback(FontErrorCode * pferr = NULL)
+ {
+ if (pferr)
+ *pferr = m_ferr;
+ return (m_resFontValid != kresOk || m_resFontRead != kresOk);
+ }
+
+ gid16 MapToPseudo(int nUnicode);
+
+ // NEW interface
+ void AssignDefaultFeatures(int cfeat, FeatureSetting * prgfset);
+
+ // Feature access for FontFace:
+ size_t NumberOfFeatures_ff();
+ featid FeatureID_ff(size_t ifeat);
+ size_t FeatureWithID_ff(featid id);
+ bool GetFeatureLabel_ff(size_t ifeat, lgid language, utf16 * label);
+ int GetFeatureDefault_ff(size_t ifeat);
+ size_t NumberOfSettings_ff(size_t ifeat);
+ int GetFeatureSettingValue_ff(size_t ifeat, size_t ifset);
+ bool GetFeatureSettingLabel_ff(size_t ifeat, size_t ifset, lgid language, utf16 * label);
+ // Feature-label languages:
+ size_t NumberOfFeatLangs_ff();
+ short GetFeatLabelLang_ff(size_t ilang);
+ // Language access for FontFace:
+ size_t NumberOfLanguages_ff();
+ isocode GetLanguageCode_ff(size_t ilang);
+
+ void SetUpFeatLangList();
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+ // For test procedures:
+ void SetUpCrossLineContextTest();
+ void SetUpPseudoGlyphTest();
+ void SetUpRuleActionTest();
+ void SetUpRuleAction2Test();
+ void SetUpAssocTest();
+ void SetUpAssoc2Test();
+ void SetUpDefaultAssocTest();
+ void SetUpFeatureTest();
+ void SetUpLigatureTest();
+ void SetUpLigature2Test();
+
+ void InitFromControlFileTest();
+#endif // OLD_TEST_STUFF
+//:End Ignore
+};
+
+} // namespace gr
+
+#if defined(GR_NO_NAMESPACE)
+using namespace gr;
+#endif
+
+
+#endif // !GR_ENGINE_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.cpp
new file mode 100644
index 00000000000..53182edab0d
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.cpp
@@ -0,0 +1,526 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrFSM.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the finite state machine.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#include <cstring>
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the FSM by reading from the font stream.
+ Assumes the stream is in the correct position.
+----------------------------------------------------------------------------------------------*/
+bool GrFSM::ReadFromFont(GrIStream & grstrm, int fxdVersion)
+{
+ short snTmp;
+
+ // number of FSM states
+ snTmp = grstrm.ReadShortFromFont();
+ m_crow = snTmp;
+ // number of transitional states
+ snTmp = grstrm.ReadShortFromFont();
+ int crowTransitional = snTmp;
+ // number of success states
+ snTmp = grstrm.ReadShortFromFont();
+ int crowSuccess = snTmp;
+ m_crowFinal = m_crow - crowTransitional;
+ m_crowNonAcpt = m_crow - crowSuccess;
+ m_rowFinalMin = crowTransitional;
+ // number of columns
+ snTmp = grstrm.ReadShortFromFont();
+ m_ccol = snTmp;
+
+ // Sanity checks.
+ if (crowTransitional > m_crow || crowSuccess > m_crow)
+ return false; // bad table
+ // TODO: add a sanity check for m_ccol.
+
+ // number of FSM glyph ranges and search constants
+ snTmp = grstrm.ReadShortFromFont();
+ m_cmcr = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_dimcrInit = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_cLoop = snTmp;
+ snTmp = grstrm.ReadShortFromFont();
+ m_imcrStart = snTmp;
+
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ for (int imcr = 0; imcr < m_cmcr; imcr++)
+ {
+ m_prgmcr[imcr].m_chwFirst = grstrm.ReadUShortFromFont();
+ m_prgmcr[imcr].m_chwLast = grstrm.ReadUShortFromFont();
+ m_prgmcr[imcr].m_col = grstrm.ReadUShortFromFont();
+ }
+
+ // rule map and offsets (extra item at end gives final offset, ie, total)
+ m_prgirulnMin = new data16[crowSuccess + 1];
+ data16 * pchw = m_prgirulnMin;
+ int i;
+ for (i = 0; i < (crowSuccess + 1); i++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // Last offset functions as the total length of the rule list.
+ // Note that the number of rules in the map is not necessarily equal to the number of
+ // rules in the pass; some rules may be listed multiply, if they are matched by more
+ // than one state.
+ int crulInMap = m_prgirulnMin[crowSuccess];
+ m_prgrulnMatched = new data16[crulInMap];
+ m_crulnMatched = crulInMap;
+ pchw = m_prgrulnMatched;
+ for (i = 0; i < crulInMap; i++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // min rule pre-context number of items
+ byte bTmp = grstrm.ReadByteFromFont();
+ m_critMinRulePreContext = bTmp;
+ // max rule pre-context number of items
+ bTmp = grstrm.ReadByteFromFont();
+ m_critMaxRulePreContext = bTmp;
+
+ if (m_critMinRulePreContext > kMaxSlotsPerRule || m_critMaxRulePreContext > kMaxSlotsPerRule)
+ return false; // bad table
+
+ int cStartStates = m_critMaxRulePreContext - m_critMinRulePreContext + 1;
+
+ // start states
+ m_prgrowStartStates = new short[cStartStates];
+ short * psn = m_prgrowStartStates;
+ for (int ic = 0; ic < cStartStates; ic++, psn++)
+ {
+ *psn = grstrm.ReadShortFromFont();
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the FSM's state table by reading from the font stream.
+ Assumes the stream is in the correct position.
+----------------------------------------------------------------------------------------------*/
+bool GrFSM::ReadStateTableFromFont(GrIStream & grstrm, int fxdVersion)
+{
+ int cCells = ((m_crow - m_crowFinal) * m_ccol);
+ m_prgrowTransitions = new short[cCells];
+ short * psn = m_prgrowTransitions;
+ for (int iCell = 0; iCell < cCells; iCell++, psn++)
+ {
+ *psn = grstrm.ReadShortFromFont();
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Use the transition table to find a rule or rules that match; then run the contraint
+ code to see if the rule is active. Return the rule number of the rule to be applied.
+
+ @param ppass - pass, which knows how to run constraint code
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream (from which to get recently output slots)
+----------------------------------------------------------------------------------------------*/
+int GrFSM::GetRuleToApply(GrTableManager * ptman, GrPass * ppass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // List of accepting states and corresponding count of slots that were
+ // matched by each.
+ int prgrowAccepting[kMaxSlotsPerRule];
+ int prgcslotMatched[kMaxSlotsPerRule];
+
+ // Run the transition table until it jams.
+ int crowAccepting = RunTransitionTable(ppass, psstrmIn, psstrmOut,
+ prgrowAccepting, prgcslotMatched);
+
+ // Nothing matched; fail quickly.
+ if (crowAccepting == 0)
+ return -1;
+
+ int * prow = prgrowAccepting + crowAccepting - 1;
+ int * pcslot = prgcslotMatched + crowAccepting - 1; // # of slots matched AFTER the curr pos
+
+ // Quick test for common case of exactly one rule matched.
+ if (crowAccepting == 1 &&
+ (m_prgirulnMin[*prow - m_crowNonAcpt + 1] - m_prgirulnMin[*prow - m_crowNonAcpt]) == 1)
+ {
+ int iruln = m_prgirulnMin[*prow - m_crowNonAcpt];
+ int ruln = m_prgrulnMatched[iruln];
+ if (RunConstraintAndRecordLog(ptman, ppass, ruln, psstrmIn, psstrmOut,
+ ppass->PreModContextForRule(ruln), *pcslot))
+ {
+ return ruln;
+ }
+ else
+ return -1;
+ }
+
+ // Several rules were matched. We need to sort them and then run the constraints
+ // for each rule, accepting the first one whose constraints succeed.
+
+ // Count up the number of rules that matched and allocate a buffer of the right size.
+ int crulMatched = 0;
+ while (prow >= prgrowAccepting)
+ {
+ crulMatched +=
+ m_prgirulnMin[*prow - m_crowNonAcpt + 1] - m_prgirulnMin[*prow - m_crowNonAcpt];
+ --prow;
+ }
+ MatchedRule * prgmr = new MatchedRule[crulMatched];
+
+ prow = prgrowAccepting + crowAccepting - 1;
+
+ // Do a dumb insertion sort, ordering primarily by sort key (largest first)
+ // and secondarily by the order in the original file (rule number).
+ // Review: is this kind of sort fast enough? We assuming that we usually only
+ // have a handful of matched rules.
+ int cmr = 0;
+ while (prow >= prgrowAccepting)
+ {
+ int iruln = m_prgirulnMin[*prow - m_crowNonAcpt];
+ // Get all the rules matches by a single state.
+ while (iruln < m_prgirulnMin[*prow - m_crowNonAcpt + 1])
+ {
+ int ruln = m_prgrulnMatched[iruln];
+ int nSortKey = ppass->SortKeyForRule(ruln);
+ int cslot = *pcslot;
+ int imr;
+ for (imr = 0; imr < cmr; imr++)
+ {
+ if (nSortKey > prgmr[imr].nSortKey ||
+ (nSortKey == prgmr[imr].nSortKey && ruln < prgmr[imr].ruln))
+ {
+ // Insert here.
+ memmove(prgmr+imr+1, prgmr+imr, (isizeof(MatchedRule) * (cmr - imr)));
+ prgmr[imr].ruln = ruln;
+ prgmr[imr].nSortKey = nSortKey;
+ prgmr[imr].cslot = cslot;
+ break;
+ }
+ }
+ if (imr >= cmr)
+ {
+ prgmr[cmr].ruln = ruln;
+ prgmr[cmr].nSortKey = nSortKey;
+ prgmr[cmr].cslot = cslot;
+ }
+ cmr++;
+
+ iruln++;
+ }
+ --prow;
+ --pcslot;
+ }
+
+
+ for (int imr = 0; imr < cmr; imr++)
+ {
+ int ruln = prgmr[imr].ruln;
+ if (RunConstraintAndRecordLog(ptman, ppass, ruln, psstrmIn, psstrmOut,
+ ppass->PreModContextForRule(ruln), prgmr[imr].cslot))
+ {
+ // Success!
+ delete[] prgmr;
+ return ruln;
+ }
+ }
+
+ // No rule matched or the constraints failed.
+ delete[] prgmr;
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Run the transition table, generating a list of rows corresponding to accepting states.
+
+ @param psstrmIn - input stream
+ @param prgrowAccepting - array to fill in with accepting rows
+ @param prgcslotMatched - corresponding array with number of slots matched
+----------------------------------------------------------------------------------------------*/
+int GrFSM::RunTransitionTable(GrPass * ppass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int * prgrowAccepting, int * prgcslotMatched)
+{
+ int ipass = ppass->PassNumber();
+
+ // Remember we're reading the pre-context items from the output stream, not the input.
+ int cslotPreContextAvail = psstrmOut->WritePos();
+
+ if (cslotPreContextAvail < m_critMinRulePreContext)
+ return 0; // not enough input to match any rule
+
+ // Look backwards by the number of pre-context items for this pass, but not earlier
+ // than the beginning of the stream.
+ int cslot = -1 * min(cslotPreContextAvail, m_critMaxRulePreContext);
+
+ // Normally the start state is state 0. But if we are near the beginning of the stream,
+ // we may need to adjust due to the fact that we don't have enough input yet to
+ // match the pre-context items in all the rules. So in effect we skip some states
+ // corresponding to the earlier items that aren't present.
+ int row = m_prgrowStartStates[max(0, m_critMaxRulePreContext - cslotPreContextAvail)];
+
+ int * prowTop = prgrowAccepting;
+ int * pcslotTop = prgcslotMatched;
+ while (true)
+ {
+ if (row >= m_rowFinalMin)
+ // final state--jammed
+ return (prowTop - prgrowAccepting);
+
+ if (psstrmIn->SlotsPendingInContext() <= cslot)
+ // no more input
+ return (prowTop - prgrowAccepting);
+
+ // Figure out what column the input glyph belong in.
+ // Since this is a time-critical routine, we cache the results for the current pass.
+ GrSlotState * pslot = (cslot < 0) ?
+ psstrmOut->PeekBack(cslot) :
+ psstrmIn->Peek(cslot);
+ int col;
+ if (pslot->PassNumberForColumn() == ipass)
+ {
+ col = pslot->FsmColumn();
+ }
+ else
+ {
+ gid16 chwGlyphID = (cslot < 0) ?
+ psstrmOut->PeekBack(cslot)->GlyphID() :
+ psstrmIn->Peek(cslot)->GlyphID();
+ col = FindColumn(chwGlyphID);
+ pslot->CacheFsmColumn(ipass, col);
+ }
+ int rowNext;
+ if (col < 0)
+ rowNext = 0;
+ else
+ rowNext = m_prgrowTransitions[(row * m_ccol) + col];
+
+ if (rowNext == 0) // jammed
+ return (prowTop - prgrowAccepting);
+
+ cslot++;
+ if (rowNext >= m_crowNonAcpt) // or (rowNext < 0)
+ {
+ // Accepting state--push it on the stack.
+ //rowNext *= -1;
+ gAssert((prowTop - prgrowAccepting) < kMaxSlotsPerRule);
+ *prowTop++ = rowNext;
+ *pcslotTop++ = cslot;
+ }
+ row = rowNext;
+
+ gAssert((prowTop - prgrowAccepting) == (pcslotTop - prgcslotMatched));
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Run the transition table, generating a list of rows corresponding to accepting states.
+ Optimized to avoid matrix arithmetic for non-accepting states.
+
+ Review: do we need to use this version?
+
+ @param psstrmIn - input stream
+ @param prgrowAccepting - array to fill in with accepting rows
+ @param prgcslotMatched - corresponding array with number of slots matched
+----------------------------------------------------------------------------------------------*/
+#if 0
+
+int GrFSM::RunTransitionTableOptimized(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int * prgrowAccepting, int * prgcslotMatched)
+{
+ int cslot = 0;
+ int ichwRowOffset = 0;
+ int ichwRowOffsetLim = m_crowFinal * m_ccol; // number of cells
+ int * prowTop = prgrowAccepting;
+ int * pcslotTop = prgcslotMatched;
+ while (true)
+ {
+ if (ichwRowOffset >= ichwRowOffsetLim)
+ // final state--jammed
+ return (prowTop - prgrowAccepting);
+
+ if (psstrmIn->SlotsPendingInContext() < cslot)
+ // no more input
+ return (prowTop - prgrowAccepting);
+
+ gid16 chwGlyphID = psstrmIn->Peek(cslot)->GlyphID();
+ int col = FindColumn(chwGlyphID);
+ short cellValue = *(m_prgprgrowXitions + ichwRowOffset + col);
+
+ if (cellValue == 0) // jammed
+ return (prowTop - prgrowAccepting);
+
+ cslot++;
+ if (cellValue < 0)
+ {
+ // Accepting state--push it on the stack.
+ int rowNext = cellValue * -1;
+ gAssert((prowTop - prgrowAccepting) < kMaxSlotsPerRule);
+ *prowTop++ = rowNext;
+ *pcslotTop++ = cslot;
+ ichwRowOffset = rowNext * m_ccol;
+ }
+ else
+ ichwRowOffset = cellValue;
+
+ gAssert((prowTop - prgrowAccepting) == (pcslotTop - prgcslotMatched));
+ }
+}
+
+#endif // 0
+
+
+/*----------------------------------------------------------------------------------------------
+ Run all the constraints for the rules matched by the state that we have reached.
+ The rules are ordered as they were in the GDL file. When we hit a constraint that
+ matches, return the corresponding rule number. Return -1 if no rule passed.
+
+ @param ppass - pass, which knows how to actually run the constraints
+ @param psstrmIn - input stream
+ @param cslotMatched - number of slots matched; constraints must be run for each of these
+----------------------------------------------------------------------------------------------*/
+//:Ignore
+int GrFSM::RunConstraints_Obsolete(GrTableManager * ptman, GrPass * ppass, int row,
+ GrSlotStream * psstrmIn, int cslotMatched)
+{
+ int iruln = m_prgirulnMin[row - m_crowNonAcpt];
+ while (iruln < m_prgirulnMin[row - m_crowNonAcpt + 1])
+ {
+ int ruln = m_prgrulnMatched[iruln];
+ bool fSuccess = ppass->RunConstraint(ptman, ruln, psstrmIn, NULL, 0, cslotMatched);
+ if (fSuccess)
+ {
+ if (ptman->LoggingTransduction())
+ ppass->RecordRuleFired(psstrmIn->ReadPosForNextGet(), ruln);
+ return ruln;
+ }
+ else
+ {
+ if (ptman->LoggingTransduction())
+ ppass->RecordRuleFailed(psstrmIn->ReadPosForNextGet(), ruln);
+ }
+
+ iruln++;
+ }
+ return -1; // no rule succeeded
+}
+//:End Ignore
+
+/*----------------------------------------------------------------------------------------------
+ Run the constraints for the given rule, and record whether it failed or succeeded in the
+ transduction log.
+
+ @param ppass - pass, which knows how to actually run the constraints
+ @param psstrmIn - input stream
+ @param cslotPreModContext - number of slots before the current position that must be tested
+ @param islotLimMatched - number of slots matched AFTER the current position
+
+ @return True if the constraints succeeded.
+----------------------------------------------------------------------------------------------*/
+bool GrFSM::RunConstraintAndRecordLog(GrTableManager * ptman, GrPass * ppass, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotPreModContext, int islotLimMatched)
+{
+ bool fSuccess = ppass->RunConstraint(ptman, ruln, psstrmIn, psstrmOut,
+ cslotPreModContext, islotLimMatched);
+
+ if (ptman->LoggingTransduction())
+ {
+ if (fSuccess)
+ ppass->RecordRuleFired(psstrmIn->ReadPosForNextGet(), ruln);
+ else
+ ppass->RecordRuleFailed(psstrmIn->ReadPosForNextGet(), ruln);
+ }
+
+ return fSuccess;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Search for the class range containing the glyph ID, and return the matching FSM column.
+ Does a fast binary search that uses only shifts, no division.
+----------------------------------------------------------------------------------------------*/
+int GrFSM::FindColumn(gid16 chwGlyphID)
+{
+ #ifdef _DEBUG
+ // Check that the pre-calculated constants are correct.
+ int nPowerOf2 = 1;
+ while (nPowerOf2 <= m_cmcr)
+ nPowerOf2 <<= 1;
+ nPowerOf2 >>= 1;
+ // Now nPowerOf2 is the max power of 2 <= m_cclsrg.
+ // m_cLoop is not needed for our purposes, but it is included because it is part of
+ // the TrueType standard.
+ gAssert(1 << m_cLoop == nPowerOf2); // m_cloop == log2(nPowerOf2)
+ gAssert(m_dimcrInit == nPowerOf2);
+ gAssert(m_imcrStart == m_cmcr - m_dimcrInit);
+ #endif
+
+ int dimcrCurr = m_dimcrInit;
+
+ GrFSMClassRange * pmcrCurr = m_prgmcr + m_imcrStart;
+ while (dimcrCurr > 0)
+ {
+ int nTest;
+ if (pmcrCurr < m_prgmcr)
+ nTest = -1;
+ else
+ {
+ nTest = pmcrCurr->m_chwFirst - chwGlyphID;
+ if (nTest < 0 && chwGlyphID <= pmcrCurr->m_chwLast)
+ //nTest = 0;
+ // This is a tiny bit more efficient:
+ return pmcrCurr->m_col;
+ }
+
+ if (nTest == 0)
+ // found it
+ return pmcrCurr->m_col;
+
+ dimcrCurr >>= 1; // divide by 2
+ if (nTest < 0)
+ pmcrCurr += dimcrCurr;
+ else // (nTest > 0)
+ pmcrCurr -= dimcrCurr;
+ }
+
+ return -1;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.h
new file mode 100644
index 00000000000..b1909553daa
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFSM.h
@@ -0,0 +1,245 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrFSM.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ The GrFSM class, which is the mechanism that examines input in a glyph stream and
+ determines which rule matches and should be run.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef FSM_INCLUDED
+#define FSM_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+class GrPass;
+
+/*----------------------------------------------------------------------------------------------
+ A machine class range consists of a range of contiguous glyph IDs that map to
+ a single column in the FSM (a machine class). (Note that there might be more than one
+ range mapping to a given column.)
+
+ Keep in mind that these "classes" are completely different from the classes that
+ are used for substitution. These are used only for matching by the FSM.
+
+ Hungarian: mcr
+----------------------------------------------------------------------------------------------*/
+class GrFSMClassRange
+{
+ friend class GrFSM;
+
+protected:
+ gid16 m_chwFirst; // first glyph ID in range
+ gid16 m_chwLast; // last glyph ID in range
+ data16 m_col; // column (machine class) to which this range maps
+};
+
+/*----------------------------------------------------------------------------------------------
+ The finite state machine that is used to match sequences of glyphs and
+ determine which rule to apply. There is one FSM per pass.
+
+ The states in the FSM are grouped and ordered in the following way:
+ - non-accepting states (no rule completely matched)
+ - accepting non-final states (a rule matched, but a longer rule is possible)
+ - final states (a rule matched and no longer rule is possible)
+ In other words, we have:
+ - transition, non-accepting
+ - transition, accepting
+ - non-transition, accepting
+ The transition states have information about the next state to transition to;
+ the accepting states have information about the rule(s) that matched.
+
+ There are three main data structures that are part of the finite state machine:
+
+ (1) the transition matrix: m_prgprgrowXitions. It contains a row for each transition
+ state (non-accepting states plus accepting non-final states), and a column for each
+ machine class. The cell values indicate the next state to transition to for the
+ matched input. A positive number indicates that the next state is a non-accepting state;
+ a negative value indicates an accepting state. Zero means there is no next state;
+ no more matches are possible; machine has "jammed."
+
+ (2) the matched-rule list: m_prgrulnMatched. This is a list of rule numbers,
+ which are indices into the pass's action- and constraint-code arrays.
+ It contains the numbers of the rules matched by the first accepting state,
+ followed by those matched by the second accepting state, etc. For each state,
+ the rules must be ordered using the same order of the rules in the RDL file.
+
+ (3) the matched-rule-offsets list: m_prgirulnMin. This gives the starting index into
+ the matched-rule list for each accepting state. (Non-accepting states are not included,
+ so the first item is for state m_crowNonAcpt.)
+
+ In addition, the FSM interacts with the action- and constraint-code lists in the pass
+ itself. These lists are indexed by rule number (the values of m_prgrulnMatched).
+ When some input matches the rule, the constraint-code is run; if it succeeds,
+ the rule number is returned to the caller and that rule is applied (ie, the action-code
+ is run).
+
+ Hungarian: fsm
+
+ Other hungarian:
+ row - row (state)
+ col - column (machine class)
+ ruln - rule number
+
+ REVIEW: This is quite a time-critical class, and there are two potential optimizations
+ that have been proposed for the value of a cell:
+
+ (1) use a negative cell number to indicate an accepting state and a positive number
+ to indicate a non-accepting state. So this gives a comparison with zero rather than
+ some arbitrary number
+
+ (2) have the positive numbers--the most common case--be the actual byte offset into the
+ table rather than the row number. This saves matrix multiplication at each step,
+ ie, "m_prgsnTransitions[(row * m_ccol) + col]".
+
+ The two versions are implemented in RunTransitionTable and RunTransitionTableOptimized.
+ Do these seem to be worth the inconvenience of added complexity in understanding
+ and debugging?
+----------------------------------------------------------------------------------------------*/
+class GrFSM
+{
+ friend class FontMemoryUsage;
+
+public:
+ GrFSM() :
+ m_prgirulnMin(NULL),
+ m_prgrulnMatched(NULL),
+ m_prgrowTransitions(NULL),
+ m_prgibStateDebug(NULL),
+ m_prgmcr(NULL),
+ m_prgrowStartStates(NULL)
+ {
+ }
+
+ ~GrFSM()
+ {
+ delete[] m_prgirulnMin;
+ delete[] m_prgrulnMatched;
+
+ delete[] m_prgrowTransitions;
+
+ delete[] m_prgibStateDebug;
+
+ delete[] m_prgmcr;
+
+ delete[] m_prgrowStartStates;
+ }
+
+ bool ReadFromFont(GrIStream & grstrm, int fxdVersion);
+ bool ReadStateTableFromFont(GrIStream & grstrm, int fxdVersion);
+
+ int GetRuleToApply(GrTableManager *, GrPass * ppass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+
+ int RunTransitionTable(GrPass * ppass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int * prgrowAccepting, int * prgcslotMatched);
+ int RunTransitionTableOptimized(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int * prgrowAccepting, int * prgcslotMatched);
+ bool RunConstraintAndRecordLog(GrTableManager *, GrPass * ppass, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotPreModContext, int cslotMatched);
+
+ int RunConstraints_Obsolete(GrTableManager *, GrPass * ppass, int row, GrSlotStream * psstrmIn,
+ int cslotMatched);
+
+ // For sorting matched rules
+ struct MatchedRule // mr
+ {
+ int ruln;
+ int nSortKey;
+ int cslot; // number of slots matched AFTER the current stream position
+ };
+
+ int MaxRulePreContext()
+ {
+ return m_critMaxRulePreContext;
+ }
+
+protected:
+ int FindColumn(gid16 chwGlyphID);
+protected:
+ // Instance variables:
+ int m_crow; // number of rows (states)
+ int m_crowFinal; // number of final states; no transitions for these
+ int m_rowFinalMin; // index of first final row
+ int m_crowNonAcpt; // number of non-accepting states; no rule indices for these
+
+ int m_ccol; // number of columns (machine classes)
+
+ data16 * m_prgirulnMin; // m_crow-m_crowNonAcpt+1 of these;
+ // index within m_prgrulnMatched, start of matched
+ // rules for each accepting state
+
+ data16 * m_prgrulnMatched; // long ordered list of rule indices matched by
+ // subsequent states; total length is sum of number
+ // of rules matched for each accepting state
+ int m_crulnMatched; // needed only for memory instrumentation
+
+ // Transition matrix--for optimized version:
+// short ** m_prgprgrowXitions; // ((m_crow-m_crowFinal) * m_ccol) of these;
+ // positive number indicates
+ // next state is non-accepting; negative number is
+ // negative of accepting state.
+
+ // Transition matrix--for current version:
+ short * m_prgrowTransitions; // ((m_crow-m_crowFinal) * m_ccol) of these
+
+ // debugger string offsets
+ data16 * m_prgibStateDebug; // for transition states; (m_crow-m_crul+1) of these
+
+ // constants for fast binary search; these are generated by the compiler so that the
+ // engine doesn't have to take time to do it
+ data16 m_dimcrInit; // (max power of 2 <= m_cmcr);
+ // size of initial range to consider
+ data16 m_cLoop; // log2(max power of 2 <= m_cmcr);
+ // indicates how many iterations are necessary
+ data16 m_imcrStart; // m_cmcr - m_dimcrInit;
+ // where to start search
+
+ int m_cmcr; // number of machine-class-ranges
+ GrFSMClassRange * m_prgmcr; // array of class ranges; we search these to find the
+ // mapping to the machine-class-column
+
+ // minimum and maximum number of items in the rule contexts before the first modified
+ // item.
+ int m_critMinRulePreContext;
+ int m_critMaxRulePreContext;
+
+ // start states--row in the FSM to start on depending on how many bogus slots we
+ // are skipping; (max rule-precontext - min rule-precontext + 1) of these;
+ // first always = zero
+ short * m_prgrowStartStates;
+
+//:Ignore
+#if OLD_TEST_STUFF
+public:
+ // For test procedures:
+ void SetUpSimpleFSMTest();
+ void SetUpRuleActionTest();
+ void SetUpRuleAction2Test(int);
+ void SetUpAssocTest(int);
+ void SetUpAssoc2Test(int);
+ void SetUpDefaultAssocTest();
+ void SetUpFeatureTest();
+ void SetUpLigatureTest(int);
+ void SetUpLigature2Test(int);
+#endif // OLD_TEST_STUFF
+//:End Ignore
+
+};
+
+} // namespace gr
+
+
+#endif // !FSM_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeature.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeature.cpp
new file mode 100644
index 00000000000..61970d56949
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeature.cpp
@@ -0,0 +1,321 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrFeature.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the GrFeature class.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#include <cstring>
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> GrFeature Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the feature.
+----------------------------------------------------------------------------------------------*/
+void GrFeature::Initialize(featid nID, int nNameId, int cfset, int nDefault)
+{
+ m_nID = nID;
+ m_nNameId = nNameId;
+ m_nDefault = nDefault;
+
+ m_vnVal.resize(cfset);
+ for (unsigned int ifset = 0; ifset < m_vnVal.size(); ifset++)
+ m_vnVal[ifset] = INT_MAX;
+ m_vnNameId.resize(cfset);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the feature settings.
+----------------------------------------------------------------------------------------------*/
+int GrFeature::Settings(int cMax, int * prgnVal)
+{
+ int cRet = min(cMax, signed(m_vnVal.size()));
+ for (int ifset = 0; ifset < cRet; ifset++)
+ prgnVal[ifset] = m_vnVal[ifset];
+ return cRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add a feature setting.
+----------------------------------------------------------------------------------------------*/
+void GrFeature::AddSetting(int nVal, int nNameId)
+{
+ Assert(nVal != INT_MAX);
+ unsigned int ifset;
+ for (ifset = 0; ifset < m_vnVal.size(); ifset++)
+ {
+ if (m_vnVal[ifset] == nVal)
+ return; // already there
+ }
+ for (ifset = 0; ifset < m_vnVal.size(); ifset++)
+ {
+ if (m_vnVal[ifset] == INT_MAX)
+ {
+ m_vnVal[ifset] = nVal;
+ m_vnNameId[ifset] = nNameId;
+ return;
+ }
+ }
+ m_vnVal.push_back(nVal);
+ m_vnNameId.push_back(nNameId);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the given setting is valid according to the font's feature table.
+----------------------------------------------------------------------------------------------*/
+bool GrFeature::IsValidSetting(int nVal)
+{
+ for (unsigned int ifset = 0; ifset < m_vnVal.size(); ifset++)
+ {
+ if (m_vnVal[ifset] == nVal)
+ return true;
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the feature label from the name table.
+----------------------------------------------------------------------------------------------*/
+std::wstring GrFeature::Label(GrEngine * pgreng, int nLang)
+{
+ std::wstring stu = pgreng->StringFromNameTable(nLang, m_nNameId);
+ if (stu == L"NoName")
+ stu.erase();
+ return stu;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the feature value label from the name table.
+----------------------------------------------------------------------------------------------*/
+std::wstring GrFeature::SettingLabel(GrEngine * pgreng, int nVal, int nLang)
+{
+ for (unsigned int ifset = 0; ifset < m_vnVal.size(); ifset++)
+ {
+ if (m_vnVal[ifset] == nVal)
+ {
+ std::wstring stu = pgreng->StringFromNameTable(nLang, m_vnNameId[ifset]);
+ if (stu == L"NoName")
+ stu.erase();
+ return stu;
+ }
+ }
+ Assert(false); // setting is not valid
+ return L"";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the given setting value.
+----------------------------------------------------------------------------------------------*/
+int GrFeature::NthSetting(int ifset)
+{
+ if (ifset >= (int)m_vnVal.size())
+ return -1;
+ else
+ return m_vnVal[ifset];
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the feature value label for the given index.
+----------------------------------------------------------------------------------------------*/
+std::wstring GrFeature::NthSettingLabel(GrEngine * pgreng, int ifset, int nLang)
+{
+ std::wstring stu;
+
+ if (ifset >= (int)m_vnVal.size())
+ stu.erase();
+ else
+ {
+ stu = pgreng->StringFromNameTable(nLang, m_vnNameId[ifset]);
+ if (stu == L"NoName")
+ stu.erase();
+ }
+ return stu;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the feature setting label.
+----------------------------------------------------------------------------------------------*/
+// void GrFeature::SetSettingLabel(int nVal, std::wstring stuLabel, int nLang)
+// {
+// for (int ifset = 0; ifset < m_vfset.size(); ifset++)
+// {
+// if (m_vfset[ifset].m_nVal == nVal)
+// {
+// m_vfset[ifset].m_hmnstuLabels.Insert(nLang, stuLabel, true);
+// return;
+// }
+// }
+// Assert(false); // setting is not valid
+// }
+
+
+//:>********************************************************************************************
+//:> GrLangTable Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Read the languages from the font.
+----------------------------------------------------------------------------------------------*/
+bool GrLangTable::ReadFromFont(GrIStream * pgrstrm, int fxdVersion)
+{
+ GrIStream & grstrm = *pgrstrm;
+
+ // number of languages
+ m_clang = (size_t)grstrm.ReadUShortFromFont();
+
+ // search constants
+ m_dilangInit = grstrm.ReadUShortFromFont();
+ m_cLoop = grstrm.ReadUShortFromFont();
+ m_ilangStart = grstrm.ReadUShortFromFont();
+
+ // Slurp the data into the buffers. The "+1" represents a bogus ending entry that quickly
+ // gives us the size of the feature list. Note that the resulting data is all big-endian.
+ int cb = (m_clang + 1) * sizeof(LangEntry);
+ m_prglang = new LangEntry[m_clang + 1];
+ grstrm.ReadBlockFromFont(m_prglang, cb);
+
+ m_cbOffset0 = (lsbf)(m_prglang[0].cbOffsetBIG);
+
+ Assert((lsbf)(m_prglang[m_clang].cFeaturesBIG) == 0); // bogus entry has no settings
+ cb = (lsbf)(m_prglang[m_clang].cbOffsetBIG) - m_cbOffset0;
+ Assert(cb % sizeof(FeatSet) == 0); // # of bytes fits nicely into FeatSet class
+ int cfset = cb / sizeof(FeatSet);
+ m_prgfset = new FeatSet[cfset];
+ m_cfset = cfset;
+ grstrm.ReadBlockFromFont(m_prgfset, cb);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create an empty language table to use for dumb rendering, or when there is no valid
+ Sill table.
+----------------------------------------------------------------------------------------------*/
+void GrLangTable::CreateEmpty()
+{
+ m_prglang = NULL;
+ m_prgfset = NULL;
+ m_clang = 0;
+ m_dilangInit = 0;
+ m_cLoop = 0;
+ m_ilangStart = 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return information about the language with the given ID by filling in the given vectors
+ with the feature ids and values. Will wipe out any data in the vectors already.
+----------------------------------------------------------------------------------------------*/
+void GrLangTable::LanguageFeatureSettings(isocode lgcode,
+ std::vector<featid> & vnFeatId, std::vector<int> & vnValues)
+{
+ vnFeatId.clear();
+ vnValues.clear();
+
+ int ilang = FindIndex(lgcode);
+ if (ilang == -1)
+ return; // no such language: leave vectors empty
+
+ LangEntry * plang = m_prglang + ilang;
+ int cbOffset = lsbf(plang->cbOffsetBIG) - m_cbOffset0;
+ Assert(cbOffset % sizeof(FeatSet) == 0);
+ byte * pbFeatSet = reinterpret_cast<byte*>(m_prgfset) + cbOffset;
+ FeatSet * pfset = reinterpret_cast<FeatSet*>(pbFeatSet);
+ for (int ifset = 0; ifset < lsbf(plang->cFeaturesBIG); ifset++)
+ {
+ vnFeatId.push_back(lsbf(pfset[ifset].featidBIG));
+ vnValues.push_back(lsbf(pfset[ifset].valueBIG));
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the code for the language at the given index.
+----------------------------------------------------------------------------------------------*/
+isocode GrLangTable::LanguageCode(size_t ilang)
+{
+ isocode lgcodeRet;
+ if (ilang > m_clang)
+ {
+ std::fill_n(lgcodeRet.rgch, 4, '\0');
+ return lgcodeRet;
+ }
+ LangEntry * plang = m_prglang + ilang;
+ std::copy(plang->rgchCode, plang->rgchCode + 4, lgcodeRet.rgch);
+ return lgcodeRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the index of the language in the list.
+----------------------------------------------------------------------------------------------*/
+int GrLangTable::FindIndex(isocode lgcode)
+{
+ if (m_clang == 0)
+ return -1;
+#ifdef _DEBUG
+ int nPowerOf2 = 1;
+ while (nPowerOf2 <= signed(m_clang))
+ nPowerOf2 <<= 1;
+ nPowerOf2 >>= 1;
+ // Now nPowerOf2 is the max power of 2 <= m_clang
+ gAssert((1 << m_cLoop) == nPowerOf2); // m_cLoop == log2(nPowerOf2)
+ gAssert(m_dilangInit == nPowerOf2);
+ gAssert(m_ilangStart == m_clang - m_dilangInit);
+#endif // _DEBUG
+
+ int dilangCurr = m_dilangInit;
+
+ int ilangCurr = m_ilangStart; // may become < 0
+ while (dilangCurr > 0)
+ {
+ int nTest;
+ if (ilangCurr < 0)
+ nTest = -1;
+ else
+ {
+ LangEntry * plangCurr = m_prglang + ilangCurr;
+ nTest = strcmp(plangCurr->rgchCode, lgcode.rgch);
+ }
+
+ if (nTest == 0)
+ return ilangCurr;
+
+ dilangCurr >>= 1; // divide by 2
+ if (nTest < 0)
+ ilangCurr += dilangCurr;
+ else // (nTest > 0)
+ ilangCurr -= dilangCurr;
+ }
+
+ return -1;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeatureValues.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeatureValues.h
new file mode 100644
index 00000000000..97e6a1fe33c
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrFeatureValues.h
@@ -0,0 +1,66 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrFeatureValues.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+
+
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_FEATVAL_INCLUDED
+#define GR_FEATVAL_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ A convenient way to group together style and feature information that interacts
+ with the rules.
+
+ Hungarian: fval
+----------------------------------------------------------------------------------------------*/
+class GrFeatureValues
+{
+ friend class GrCharStream;
+ friend class GrSlotAbstract;
+ friend class GrSlotState;
+
+public:
+ // Standard constructor:
+ GrFeatureValues()
+ {
+ m_nStyleIndex = 0;
+ std::fill(m_rgnFValues, m_rgnFValues + kMaxFeatures, 0);
+ }
+
+ // Copy constructor:
+ GrFeatureValues(const GrFeatureValues & fval)
+ {
+ m_nStyleIndex = fval.m_nStyleIndex;
+ std::copy(fval.m_rgnFValues, fval.m_rgnFValues + kMaxFeatures, m_rgnFValues);
+ }
+
+ // For transduction logging:
+#ifdef TRACING
+ void WriteXductnLog(GrTableManager * ptman, std::ostream &);
+#endif // TRACING
+
+protected:
+ int m_nStyleIndex;
+ int m_rgnFValues[kMaxFeatures];
+};
+
+} // namespace gr
+
+
+#endif // !GR_FEATVAL_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.cpp
new file mode 100644
index 00000000000..8643eae8cb8
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.cpp
@@ -0,0 +1,650 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrGlyphTable.cpp
+Responsibility: Sharon Correll
+Last reviewed: 10Aug99, JT, quick look over
+
+Description:
+ Implements the GrGlyphTable class and related classes.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the glyph table from the font stream.
+----------------------------------------------------------------------------------------------*/
+bool GrGlyphTable::ReadFromFont(GrIStream & grstrmGloc, long lGlocStart,
+ GrIStream & grstrmGlat, long lGlatStart,
+ data16 chwBWAttr, data16 chwJStrAttr, int cJLevels, int cnCompPerLig,
+ int fxdSilfVersion)
+{
+ // Create the glyph sub-table for the single style.
+ GrGlyphSubTable * pgstbl = new GrGlyphSubTable();
+
+ // Gloc table--offsets into Glat table
+ grstrmGloc.SetPositionInFont(lGlocStart);
+
+ // version
+ int fxdGlocVersion = GrEngine::ReadVersion(grstrmGloc);
+ if (fxdGlocVersion > kGlocVersion)
+ return false;
+
+ // flags
+ short snFlags = grstrmGloc.ReadShortFromFont();
+
+ // number of attributes
+ unsigned short cAttrs = grstrmGloc.ReadUShortFromFont();
+
+ // Create a single sub-table for the single style.
+ pgstbl->Initialize(fxdSilfVersion, snFlags, chwBWAttr, chwJStrAttr, data16(chwJStrAttr + cJLevels),
+ m_cglf, cAttrs, cnCompPerLig);
+
+ SetSubTable(0, pgstbl);
+
+ return pgstbl->ReadFromFont(grstrmGloc, m_cglf, grstrmGlat, lGlatStart);
+}
+
+bool GrGlyphSubTable::ReadFromFont(GrIStream & grstrmGloc, int cGlyphs,
+ GrIStream & grstrmGlat, long lGlatStart)
+{
+ // attribute value offsets--slurp
+ if (m_fGlocShort)
+ {
+ grstrmGloc.ReadBlockFromFont(m_prgibBIGAttrValues, ((cGlyphs + 1) * sizeof(data16)));
+ }
+ else
+ {
+ grstrmGloc.ReadBlockFromFont(m_prgibBIGAttrValues, ((cGlyphs + 1) * sizeof(data32)));
+ }
+
+ // length of buffer needed for glyph attribute values:
+ int cbBufLen = GlocLookup(data16(cGlyphs));
+
+ // TODO: slurp debugger offsets: 'm_prgibBIGGlyphAttrDebug'
+
+ m_pgatbl = new GrGlyphAttrTable();
+ m_pgatbl->Initialize(m_fxdSilfVersion, cbBufLen);
+
+ // Glat table
+ grstrmGlat.SetPositionInFont(lGlatStart);
+
+ // version
+ int fxdGlatVersion = grstrmGlat.ReadIntFromFont();
+ if (fxdGlatVersion > kGlatVersion)
+ return false;
+
+ // Back up over the version number and include it right in the attribute value entry
+ // buffer, since the offsets take it into account.
+ grstrmGlat.SetPositionInFont(lGlatStart);
+
+ // Slurp the entire block of entries.
+ grstrmGlat.ReadBlockFromFont(m_pgatbl->m_prgbBIGEntries, cbBufLen);
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create an empty glyph table with no glyph attributes.
+----------------------------------------------------------------------------------------------*/
+void GrGlyphTable::CreateEmpty()
+{
+ // Create the glyph sub-table for the single style.
+ GrGlyphSubTable * pgstbl = new GrGlyphSubTable();
+
+ // Create a single sub-table for the single style.
+ pgstbl->Initialize(0, 0, 0, 0, 0, m_cglf, 0, 0);
+
+ SetSubTable(0, pgstbl);
+
+ pgstbl->CreateEmpty();
+}
+
+void GrGlyphSubTable::CreateEmpty()
+{
+ m_pgatbl = new GrGlyphAttrTable();
+ m_pgatbl->Initialize(0, 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialization.
+----------------------------------------------------------------------------------------------*/
+void GrGlyphSubTable::Initialize(int fxdSilfVersion, utf16 chwFlags,
+ data16 chwBWAttr, data16 chwJStrAttr, data16 chwJStrHWAttr,
+ int cGlyphs, int cAttrs, int cnCompPerLig)
+{
+ m_fxdSilfVersion = fxdSilfVersion;
+ m_fHasDebugStrings = HasAttrNames(chwFlags);
+ m_nAttrIDLim = cAttrs;
+ m_chwBWAttr = chwBWAttr;
+ m_chwJStrAttr = chwJStrAttr;
+ m_chwJStrHWAttr = chwJStrHWAttr;
+ m_fGlocShort = !LongFormat(chwFlags);
+
+ if (m_fGlocShort)
+ { // item # cGlyphs holds length, which is convenient for dealing with last item
+ m_prgibBIGAttrValues = new byte[(cGlyphs + 1) * sizeof(data16)];
+ }
+ else
+ {
+ m_prgibBIGAttrValues = new byte[(cGlyphs + 1) * sizeof(data32)];
+ }
+
+
+ if (m_fHasDebugStrings)
+ {
+ m_prgibBIGGlyphAttrDebug = new data16[cAttrs + 1];
+ }
+
+ // Make a cache to hold a list of defined components for each glyph. This is
+ // calculated lazily, as needed, so we also include (as the first item) a flag to
+ // indicate whether or not it has been calculated; hence the "+1".
+ m_cnCompPerLig = cnCompPerLig;
+ m_prgnDefinedComponents = new int[(m_cnCompPerLig + 1) * cGlyphs];
+ std::fill_n(m_prgnDefinedComponents, (m_cnCompPerLig + 1) * cGlyphs, 0);
+
+ // Now the instance is ready to have the locations and the debug strings
+ // read from the file.
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the attribute value for the given glyph.
+----------------------------------------------------------------------------------------------*/
+int GrGlyphSubTable::GlyphAttrValue(gid16 chwGlyphID, int nAttrID)
+{
+ if (m_nAttrIDLim == 0)
+ {
+ // No attributes defined (eg, invalid font)
+ return 0;
+ }
+ if (nAttrID >= m_nAttrIDLim || nAttrID >= 0xFF)
+ {
+ gAssert(false);
+ return 0;
+ }
+ int ibMin = GlocLookup(chwGlyphID); // where this glyph's attrs start
+ int ibLim = GlocLookup(chwGlyphID + 1); // where next glyph starts
+
+ int nRet = m_pgatbl->GlyphAttr16BitValue(ibMin, ibLim, byte(nAttrID));
+ if ((data16)nAttrID == m_chwJStrAttr)
+ {
+ // For justify.stretch, which can be a 32-bit value, add on the high word.
+ unsigned int nRetHW = m_pgatbl->GlyphAttr16BitValue(ibMin, ibLim, byte(m_chwJStrHWAttr));
+ nRet = (nRetHW << 16) | nRet;
+ }
+ return ConvertValueForVersion(nRet, nAttrID);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert the glyph attribute value from the version of the font table to what is
+ expected by the engine.
+----------------------------------------------------------------------------------------------*/
+int GrGlyphSubTable::ConvertValueForVersion(int nValue, int nAttrID)
+{
+ return ConvertValueForVersion(nValue, nAttrID, (int)m_chwBWAttr, m_fxdSilfVersion);
+}
+
+int GrGlyphSubTable::ConvertValueForVersion(int nValue, int nAttrID, int nBWAttr, int fxdVersion)
+{
+ if ((nBWAttr >= 0 && nAttrID == (int)nBWAttr) ||
+ (nBWAttr == -1 && nAttrID == (int)kslatBreak))
+ {
+ if (fxdVersion < 0x00020000)
+ {
+ //switch (nValue)
+ //{
+ //case klbv1WordBreak: return klbWordBreak;
+ //case klbv1HyphenBreak: return klbHyphenBreak;
+ //case klbv1LetterBreak: return klbLetterBreak;
+ //case klbv1ClipBreak: return klbClipBreak;
+ //default:
+ // break;
+ //}
+ //switch (nValue * -1)
+ //{
+ //case klbv1WordBreak: return (klbWordBreak * -1);
+ //case klbv1HyphenBreak: return (klbHyphenBreak * -1);
+ //case klbv1LetterBreak: return (klbLetterBreak * -1);
+ //case klbv1ClipBreak: return (klbClipBreak * -1);
+ //default:
+ // break;
+ //}
+
+ // Breakweight values in version 2 are 10 times what they were in version 1.
+ if (abs(nValue) <= 7)
+ return nValue * 10;
+ }
+ }
+ return nValue;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the attribute value a glyph. Loop through the attribute runs, looking
+ for the one containing the given attribute. Assume the value is 0 if not found.
+
+ @param ibMin - byte offset of first run for the glyph of interest
+ @param ibLim - byte offset of first run for the following glyph
+ @param bAttrID - attribute to find
+----------------------------------------------------------------------------------------------*/
+int GrGlyphAttrTable::GlyphAttr16BitValue(int ibMin, int ibLim, byte bAttrID)
+{
+ GrGlyphAttrRun gatrun;
+ byte * pbBIGEnt = m_prgbBIGEntries + ibMin;
+
+ while (pbBIGEnt < m_prgbBIGEntries + ibLim)
+ {
+ // Suck the run of attribute values into the instance, so we can see
+ // what's there.
+ gatrun.CopyFrom(pbBIGEnt);
+
+ if (bAttrID < gatrun.m_bMinAttrID)
+ // Attribute not found--assume value is 0.
+ return 0;
+ else if (gatrun.m_bMinAttrID + gatrun.m_cAttrs > bAttrID)
+ {
+ // Found the value in this run.
+ data16 chw = lsbf(gatrun.m_rgchwBIGValues[bAttrID - gatrun.m_bMinAttrID]);
+ if ((chw & 0x8000) == 0)
+ return (int)chw;
+ else
+ return 0xFFFF0000 | chw; // sign extension
+ }
+ else
+ // Go to next run.
+ pbBIGEnt += gatrun.ByteCount();
+ }
+
+ // Attribute not found--assume value is 0;
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given a point on the glyph, determine which component (if any) the point is in, and return
+ its index relative to the components that are defined for this glyph; ie, the index within
+ the compRef array.
+ Return -1 if the click with not inside any component, or if there are no components
+ defined for this glyph.
+ CURRENTLY NOT USED - if ever used, need to incorporate floating point
+----------------------------------------------------------------------------------------------*/
+int GrGlyphSubTable::ComponentContainingPoint(gid16 chwGlyphID, int x, int y)
+{
+ int i = CalculateDefinedComponents(chwGlyphID);
+ for (int inComp = 0; inComp < m_cnCompPerLig; inComp++)
+ {
+ // The m_pnComponents list holds a list of the component attributes that are defined
+ // for this glyph, padded with -1's.
+ int nCompID = m_prgnDefinedComponents[i + inComp];
+ if (nCompID == -1)
+ break; // hit the end of the list
+
+ // The value of the component attribute is actually the attribute ID for the
+ // first of the component box fields--the top. There should a contiguous group of
+ // four fields: top, bottom, left, right.
+ int nFieldIDMin = GlyphAttrValue(chwGlyphID, nCompID);
+ gAssert(nFieldIDMin != 0);
+ int nTop = GlyphAttrValue(chwGlyphID, nFieldIDMin);
+ int nBottom = GlyphAttrValue(chwGlyphID, nFieldIDMin + 1);
+ int nLeft = GlyphAttrValue(chwGlyphID, nFieldIDMin + 2);
+ int nRight = GlyphAttrValue(chwGlyphID, nFieldIDMin + 3);
+
+ if (nLeft <= x && x < nRight &&
+ nBottom <= y && y < nTop)
+ {
+ return inComp;
+ }
+ }
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the box with the source-device coordinates corresponding to the given component.
+ The rectangle is relative to the top-left of the glyph.
+ Return false if the component is not defined.
+
+ @param xysEmSquare - of the font, in logical units
+ @param chwGlyphID - the glyph of interest
+ @param icomp - the component of interest (eg, for the "oe" ligature,
+ the index for component.o would be 0,
+ and the index for component.e would be 1);
+ these is as defined by the glyph, not as used in the rules
+ @param mFontEmUnits - the number of em-units in the font, for scaling
+ @param dysFontAscent - ascent of the font, for adjusting coordinate systems
+ @param pxsLeft, pxsRight, pysTop, pysBottom
+ - return values, in source device coordinates
+ @param fTopOrigin - convert values to a coordinate system where the origin is the
+ top of the line, not the baseline
+----------------------------------------------------------------------------------------------*/
+bool GrGlyphSubTable::ComponentBoxLogUnits(float xysEmSquare,
+ gid16 chwGlyphID, int icomp, int mFontEmUnits, float dysFontAscent,
+ float * pxsLeft, float * pysTop, float * pxsRight, float * pysBottom,
+ bool fTopOrigin)
+{
+ int i = CalculateDefinedComponents(chwGlyphID);
+
+ // The m_pnComponents list holds a list of the component attributes that are defined
+ // for this glyph, padded with -1's.
+ int nCompID = m_prgnDefinedComponents[i + icomp];
+ if (nCompID == -1)
+ {
+ // Ooops, the component is undefined for this glyph.
+ *pxsLeft = 0;
+ *pxsRight = 0;
+ *pysTop = 0;
+ *pysBottom = 0;
+ return false;
+ }
+
+ // The value of the component attribute is actually the attribute ID for the
+ // first of the component box fields--the top. There should a contiguous group of
+ // four fields: top, bottom, left, right.
+ int nFieldIDMin = GlyphAttrValue(chwGlyphID, nCompID);
+ if (nFieldIDMin == 0)
+ {
+ // Component inadequately defined. This can happen when we defined components
+ // for a glyph and then substituted another glyph for it.
+ *pxsLeft = 0;
+ *pxsRight = 0;
+ *pysTop = 0;
+ *pysBottom = 0;
+ return false;
+ }
+ int mTop = GlyphAttrValue(chwGlyphID, nFieldIDMin);
+ int mBottom = GlyphAttrValue(chwGlyphID, nFieldIDMin + 1);
+ int mLeft = GlyphAttrValue(chwGlyphID, nFieldIDMin + 2);
+ int mRight = GlyphAttrValue(chwGlyphID, nFieldIDMin + 3);
+
+ ////int xysFontEmUnits;
+ ////// ysHeight should correspond to the pixels in the font's em square
+ ////GrResult res = pgg->GetFontEmSquare(&xysFontEmUnits);
+ ////if (ResultFailed(res))
+ //// return false;
+
+ *pxsLeft = GrEngine::GrIFIMulDiv(mLeft, xysEmSquare, mFontEmUnits);
+ *pxsRight = GrEngine::GrIFIMulDiv(mRight, xysEmSquare, mFontEmUnits);
+ *pysTop = GrEngine::GrIFIMulDiv(mTop, xysEmSquare, mFontEmUnits);
+ *pysBottom = GrEngine::GrIFIMulDiv(mBottom, xysEmSquare, mFontEmUnits);
+
+ if (*pxsLeft > *pxsRight)
+ {
+ float xsTmp = *pxsLeft;
+ *pxsLeft = *pxsRight;
+ *pxsRight = xsTmp;
+ }
+ if (*pysTop < *pysBottom)
+ {
+ float ysTmp = *pysTop;
+ *pysTop = *pysBottom;
+ *pysBottom = ysTmp;
+ }
+
+ if (fTopOrigin)
+ {
+ // Currently top and bottom coordinates are such that 0 is the baseline and positive is
+ // upwards, while for the box we want to return, 0 is the top of the glyph and positive
+ // is downwards. So switch systems.
+ *pysTop = (dysFontAscent - *pysTop);
+ *pysBottom = (dysFontAscent - *pysBottom);
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the list of defined components for the given glyph, if any.
+ Return the index to the first relevant item in the array.
+ Private.
+ TODO: With the current implementation that stores the glyph ids in each slot, this
+ mechanism is redundant and obsolete, and should be removed.
+----------------------------------------------------------------------------------------------*/
+int GrGlyphSubTable::CalculateDefinedComponents(gid16 chwGlyphID)
+{
+ // The first item is a flag indicating whether the list has been calculated.
+ int iFlag = chwGlyphID * (m_cnCompPerLig + 1); // index of has-been-calculated flag
+ int iMin = iFlag + 1; // first actual value; +1 in order to skip the flag
+ if (m_prgnDefinedComponents[iFlag] == 0)
+ {
+ int iTmp = iMin;
+ for (int nCompID = 0; nCompID < m_cComponents; nCompID++)
+ {
+ if (ComponentIsDefined(chwGlyphID, nCompID))
+ m_prgnDefinedComponents[iTmp++] = nCompID;
+ if (iTmp - iMin >= m_cnCompPerLig)
+ break; // ignore any components beyond the maximum allowed
+ }
+ // Fill in the rest of the list with -1.
+ for( ; iTmp < iMin + m_cnCompPerLig; iTmp++)
+ m_prgnDefinedComponents[iTmp] = -1;
+
+ m_prgnDefinedComponents[iFlag] = 1; // has been calculated
+ }
+ return iMin;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the given attr ID, which is a component definition attribute, indicates
+ that that component is defined for the given glyph.
+
+ @param chwGlyphID - the glyph of interest
+ @param nAttrID - the attribute of interest, assumed to be a component glyph
+ attribute (eg. component.e.top)
+----------------------------------------------------------------------------------------------*/
+bool GrGlyphSubTable::ComponentIsDefined(gid16 chwGlyphID, int nAttrID)
+{
+ gAssert(nAttrID < m_cComponents);
+ if (nAttrID >= m_cComponents)
+ return false;
+
+ return (GlyphAttrValue(chwGlyphID, nAttrID) != 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the index of the given component as defined for the given glyph ID. that is,
+ convert the global ID for the component to the one within this glyph. Return -1
+ if the component is not defined for the given glyph.
+ For instance, given the glyph ID "oe" (the oe ligature) and the attr ID for component.o,
+ the result would be 0; for component.e the result would be 1.
+----------------------------------------------------------------------------------------------*/
+int GrGlyphSubTable::ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID)
+{
+ int i = CalculateDefinedComponents(chwGlyphID);
+
+ for (int iLp = 0; iLp < m_cnCompPerLig; iLp++)
+ {
+ if (m_prgnDefinedComponents[i + iLp] == nCompID)
+ return iLp;
+ }
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the ID of the nth defined component attribute for the given glyph.
+----------------------------------------------------------------------------------------------*/
+//int GrGlyphSubTable::NthComponentID(gid16 chwGlyphID, int n)
+//{
+// int i = CalculateDefinedComponents(chwGlyphID);
+// return m_pnComponents[i + 1 + n];
+//}
+
+
+//:>********************************************************************************************
+//:> For test procedures
+//:>********************************************************************************************
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+
+void GrGlyphTable::SetUpTestData()
+{
+ SetNumberOfGlyphs(5);
+ SetNumberOfStyles(1);
+
+ GrGlyphSubTable * pgstbl = new GrGlyphSubTable();
+ gAssert(pgstbl);
+
+ pgstbl->Initialize(1, 0, 5, 10, 4);
+ SetSubTable(0, pgstbl);
+
+ pgstbl->SetUpTestData();
+}
+
+/***********************************************************************************************
+ TODO: This method is BROKEN because m_prgibBIGAttrValues has been changed. It is no
+ longer a utf16 *. The Gloc table can contain 16-bit or 32-bit entries and must be
+ accessed accordingly.
+***********************************************************************************************/
+void GrGlyphSubTable::SetUpTestData()
+{
+ m_pgatbl = new GrGlyphAttrTable();
+ m_pgatbl->Initialize(0, 48);
+
+ m_prgibBIGAttrValues[0] = byte(msbf(data16(0)));
+ m_prgibBIGAttrValues[1] = byte(msbf(data16(6))));
+ m_prgibBIGAttrValues[2] = byte(msbf(data16(20)));
+ m_prgibBIGAttrValues[3] = byte(msbf(data16(20)));
+ m_prgibBIGAttrValues[4] = byte(msbf(data16(40)));
+ m_prgibBIGAttrValues[5] = byte(msbf(data16(48)));
+
+ m_pgatbl->SetUpTestData();
+}
+
+void GrGlyphAttrTable::SetUpTestData()
+{
+ // Glyph 0 (1 run; offset = 0):
+ // 1 = 11 = 0x0B
+ // 2 = 22 = 0x16
+ // 0102 000B 0016
+ //
+ // Glyph 1 (2 runs; offset = 3*2 = 6):
+ // 0 = 5
+ // 1 = 6
+ // 2 = 7
+ // 8 = 8
+ // 9 = 9
+ // 0003 0005 0006 0007
+ // 0802 0008 0009
+ //
+ // Glyph 2 (0 runs; offset = 6 + 7*2 = 20):
+ // all values = 0
+ //
+ // Glyph 3 (5 runs; offset = 20):
+ // 1 = 111 = 0x006F
+ // 3 = 333 = 0x00DE
+ // 5 = 555 = 0x022B
+ // 7 = 777 = 0x0309
+ // 9 = 999 = 0x03E7
+ // 0101 006F
+ // 0301 00DE
+ // 0501 022B
+ // 0701 0309
+ // 0901 03E7
+ //
+ // Glyph 4 (1 run; offset = 20 + 10*2 = 40):
+ // 5 = 4
+ // 6 = 4
+ // 7 = 4
+ // 0503 0004 0004 0004
+ //
+ // Glyph 5 (offset = 40 + 4*2 = 48)
+
+ byte * pbBIG = m_prgbBIGEntries;
+
+ GrGlyphAttrRun gatrun;
+
+ // Glyph 0
+ gatrun.m_bMinAttrID = 1;
+ gatrun.m_cAttrs = 2;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(11));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(22));
+ memcpy(pbBIG, &gatrun, 6);
+ pbBIG += 6;
+
+ // Glyph 1
+ gatrun.m_bMinAttrID = 0;
+ gatrun.m_cAttrs = 3;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(5));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(6));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(7));
+ memcpy(pbBIG, &gatrun, 8);
+ pbBIG += 8;
+ gatrun.m_bMinAttrID = 8;
+ gatrun.m_cAttrs = 2;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(8));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(9));
+ memcpy(pbBIG, &gatrun, 6);
+ pbBIG += 6;
+
+ // Glyph 2: no data
+
+ // Glyph 3
+ gatrun.m_bMinAttrID = 1;
+ gatrun.m_cAttrs = 1;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(111));
+ memcpy(pbBIG, &gatrun, 4);
+ pbBIG += 4;
+ gatrun.m_bMinAttrID = 3;
+ gatrun.m_cAttrs = 1;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(333));
+ memcpy(pbBIG, &gatrun, 4);
+ pbBIG += 4;
+ gatrun.m_bMinAttrID = 5;
+ gatrun.m_cAttrs = 1;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(555));
+ memcpy(pbBIG, &gatrun, 4);
+ pbBIG += 4;
+ gatrun.m_bMinAttrID = 7;
+ gatrun.m_cAttrs = 1;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(777));
+ memcpy(pbBIG, &gatrun, 4);
+ pbBIG += 4;
+ gatrun.m_bMinAttrID = 9;
+ gatrun.m_cAttrs = 1;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(999));
+ memcpy(pbBIG, &gatrun, 4);
+ pbBIG += 4;
+
+ // Glyph 4
+ gatrun.m_bMinAttrID = 5;
+ gatrun.m_cAttrs = 3;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(4));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(4));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(4));
+ memcpy(pbBIG, &gatrun, 8);
+ pbBIG += 8;
+
+ gAssert(pbBIG == m_prgbBIGEntries + 48);
+}
+
+#endif // OLD_TEST_STUFF
+
+} // namespace gr
+
+//:End Ignore
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.h
new file mode 100644
index 00000000000..bec0e518dee
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrGlyphTable.h
@@ -0,0 +1,429 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrGlyphTable.h
+Responsibility: Sharon Correll
+Last reviewed: 10Aug99, JT, quick look over
+
+Description:
+ The GrGlyphTable and related classes that store the values of glyph attributes.
+
+ For each glyph in a TrueType font, Graphite has a list of glyph attributes (which
+ are defined in the GDL script file). Since most of the values will be zero, we save space
+ by only storing the non-zero values.
+
+ Eventually it may be possible to have more than one TrueType font compiled into a single
+ glyph table, hence the need for multiple sub-tables. For now we assume that there is only
+ one font file and only one sub-table.
+
+ Note that BIG in a variable name means that the data is in big-endian format, or is a range
+ of bytes that must be interpreted as a run of wide chars or ints in big-endian format.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:Ignore
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_GTABLE_INCLUDED
+#define GR_GTABLE_INCLUDED
+//:End Ignore
+
+namespace gr
+{
+
+class Font;
+
+/*----------------------------------------------------------------------------------------------
+ A run of non-zero attribute values for a single glyph, where the attribute IDs
+ are contiguous.
+
+ NOTE: it is assumed that the format of this class matches the byte order of the data as it
+ is read directly from the TTF/ECF file--that is, it is big-endian.
+
+ Hungarian: gatrun
+----------------------------------------------------------------------------------------------*/
+
+class GrGlyphAttrRun
+{
+ friend class GrGlyphTable;
+ friend class GrGlyphSubTable;
+ friend class GrGlyphAttrTable;
+
+ enum {
+ kMaxAttrsPerRun = 255
+ };
+
+ /*------------------------------------------------------------------------------------------
+ Copy the raw memory (starting at the given byte) into the instance. This method must
+ reflect the format of the "Glat_entry" as it is stored in the file and slurped into
+ memory.
+ ------------------------------------------------------------------------------------------*/
+ void CopyFrom(byte * pbBIGEnt)
+ {
+ m_bMinAttrID = *pbBIGEnt;
+ m_cAttrs = *(pbBIGEnt + 1);
+ if (m_cAttrs >= kMaxAttrsPerRun)
+ {
+ gAssert(false);
+ m_cAttrs = kMaxAttrsPerRun;
+ }
+ #ifdef _DEBUG
+ // Probably not strictly necessary to zero the array, but convenient for debugging.
+ // Removed from release build for optimization
+ std::fill(m_rgchwBIGValues, m_rgchwBIGValues + kMaxAttrsPerRun, 0);
+ #endif
+ // this is mixing types of data16 and byte pointers!
+ const data16 * prgchw = reinterpret_cast<const data16*>(pbBIGEnt + 2);
+ std::copy(prgchw, prgchw + m_cAttrs, m_rgchwBIGValues);
+ }
+
+ int ByteCount()
+ {
+ return (2 + (m_cAttrs * isizeof(data16)));
+ }
+
+protected:
+ byte m_bMinAttrID; // ID of first attribute in the run
+ byte m_cAttrs; // number of attributes in the run
+ data16 m_rgchwBIGValues[kMaxAttrsPerRun];
+};
+
+/*----------------------------------------------------------------------------------------------
+ Contains runs of attribute values for all the glyphs in the font; corresponds to
+ the "Glat" table in the font.
+
+ Hungarian: gatbl
+----------------------------------------------------------------------------------------------*/
+
+class GrGlyphAttrTable
+{
+ friend class GrGlyphTable;
+ friend class GrGlyphSubTable;
+ friend class FontMemoryUsage;
+
+protected:
+ // Constructor:
+ GrGlyphAttrTable()
+ {
+ m_prgbBIGEntries = NULL;
+ }
+
+ // Destructor:
+ ~GrGlyphAttrTable()
+ {
+ delete[] m_prgbBIGEntries;
+ }
+
+ // Initialization:
+ void Initialize(int fxdSilfVersion, int cbBufLen)
+ {
+ m_fxdSilfVersion = fxdSilfVersion;
+ m_cbEntryBufLen = cbBufLen;
+ m_prgbBIGEntries = new byte[cbBufLen];
+ // Now the instance is ready to have all the glyph attr entries slurped into
+ // the byte array from the file.
+ }
+
+ int GlyphAttr16BitValue(int ibMin, int ibLim, byte bAttrID);
+
+protected:
+ int m_fxdSilfVersion; // version number of the Silf table, which is used
+ // to interpret the attribute values
+
+ // Block of variable-length glyph attribute runs, matching the format of
+ // GrGlyphAttrRun. We don't store instances of that class here because they
+ // are variable length, and it would be too slow to read them individually from the
+ // font. Instead, we set up a single instance in the method that accesses the values;
+ // having this instance will help debugging. Eventually we may want to do without it,
+ // if it would help efficiency.
+ int m_cbEntryBufLen; // needed only for memory instrumentation
+ byte * m_prgbBIGEntries;
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+public:
+ // For test procedures:
+ void SetUpTestData();
+ void SetUpLigatureTest();
+ void SetUpLigature2Test();
+#endif // OLD_TEST_STUFF
+
+//:End Ignore
+
+};
+
+/*----------------------------------------------------------------------------------------------
+ One glyph table per font (style) file; corresponds to the "Gloc" table in the font.
+ Currently there is only considered to be one style per file, so there is only one of
+ these. It holds the (non-zero) glyph attribute values for every glyph in the font.
+
+ Hungarian: gstbl
+
+ Review: Eventually we may need to make a subclass that uses 32-bit values for the offsets,
+ or just use a separate array pointer in this class. Which would be preferable?
+----------------------------------------------------------------------------------------------*/
+
+class GrGlyphSubTable
+{
+ friend class GrGlyphTable;
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor:
+ GrGlyphSubTable() :
+ m_pgatbl(NULL),
+ m_prgibBIGAttrValues(NULL),
+ m_prgibBIGGlyphAttrDebug(NULL),
+ m_prgnDefinedComponents(NULL)
+ {
+ }
+ // Destructor:
+ ~GrGlyphSubTable()
+ {
+ delete m_pgatbl;
+ delete[] m_prgibBIGAttrValues;
+ if (m_fHasDebugStrings)
+ delete[] m_prgibBIGGlyphAttrDebug;
+ delete[] m_prgnDefinedComponents;
+ }
+
+ // Initialization:
+ bool ReadFromFont(GrIStream & gloc_strm, int cGlyphs,
+ GrIStream & glat_strm, long lGlatStart);
+ void Initialize(int fxdSilfVersion, data16 chwFlags,
+ data16 chwBWAttr, data16 chwJStrAttr, data16 chwJStrHWAttr,
+ int cGlyphs, int cAttrs, int cnCompPerLig);
+
+ void CreateEmpty();
+
+ void SetNumberOfComponents(int c)
+ {
+ m_cComponents = c;
+ }
+
+ // General:
+ int NumberOfGlyphAttrs() { return m_nAttrIDLim; } // 0..(m_nAttrIDLim-1)
+
+ int GlyphAttrValue(gid16 chwGlyphID, int nAttrID);
+
+ // Ligatures:
+ int ComponentContainingPoint(gid16 chwGlyphID, int x, int y);
+ bool ComponentBoxLogUnits(float xysEmSquare, gid16 chwGlyphID, int icomp,
+ int mFontEmUnits, float dysAscent,
+ float * pxsLeft, float * pysTop, float * pxsRight, float * pysBottom,
+ bool fTopOrigin = true);
+protected:
+ int CalculateDefinedComponents(gid16 chwGlyphID);
+ bool ComponentIsDefined(gid16 chwGlyphID, int nAttrID);
+ int ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID);
+// int NthComponentID(gid16 chwGlyphID, int n);
+ int ConvertValueForVersion(int nRet, int nAttrID);
+
+public:
+ static int ConvertValueForVersion(int nRet, int nAttrID, int nBWAttr, int fxdVersion);
+
+ // Flags:
+ bool LongFormat(data16 chwFlags) // 32-bit values?
+ {
+ return ((chwFlags & 0x01) == 0x01); // bit 0
+ }
+ bool HasAttrNames(data16 chwFlags)
+ {
+ return ((chwFlags & 0x02) == 0x02); // bit 1
+ }
+ int GlocLookup(data16 chwGlyphId)
+ {
+ if (m_fGlocShort)
+ {
+ unsigned short su = ((unsigned short *)m_prgibBIGAttrValues)[chwGlyphId];
+ return lsbf(su);
+ }
+ else
+ { unsigned int u = ((unsigned int *)m_prgibBIGAttrValues)[chwGlyphId];
+ return lsbf((int)u);
+ }
+ }
+
+protected:
+ int m_fxdSilfVersion; // version number of the Silf table, which is used
+ // to interpret the attribute values
+ bool m_fHasDebugStrings; // are debugging strings loaded into memory?
+
+ int m_nAttrIDLim; // number of glyph attributes
+ int m_cComponents; // number of initial glyph attributes that
+ // represent ligature components
+ int m_cnCompPerLig;
+
+ GrGlyphAttrTable * m_pgatbl;
+ byte * m_prgibBIGAttrValues; // byte offsets for glyph attr values - BIG endian
+ bool m_fGlocShort; // flag for Gloc table format
+ data16 * m_prgibBIGGlyphAttrDebug; // byte offsets for glyph attr debug strings - BIG endian
+
+ data16 m_chwBWAttr; // breakweight attr ID; needed for converting
+ // between versions
+
+ // Attr IDs for justify.0.stretch and justify.0.stretchHW; these must always be looked
+ // up in tandem.
+ data16 m_chwJStrAttr;
+ data16 m_chwJStrHWAttr;
+
+ int * m_prgnDefinedComponents; // for each glyph, cache list of component attributes that
+ // are defined
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+public:
+ // For test procedures:
+ void SetUpTestData();
+ void SetUpLigatureTest();
+ void SetUpLigature2Test();
+#endif // OLD_TEST_STUFF
+
+//:End Ignore
+};
+
+/*----------------------------------------------------------------------------------------------
+ Holds all the information about glyph attributes.
+
+ Hungarian: gtbl
+----------------------------------------------------------------------------------------------*/
+
+class GrGlyphTable
+{
+ friend class GrGlyphSubTable;
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor:
+ GrGlyphTable()
+ {
+ m_cglf = 0;
+ m_cComponents = 0;
+ m_cgstbl = 0;
+ m_vpgstbl.clear();
+ }
+
+ // Destructor:
+ ~GrGlyphTable()
+ {
+ for (int i = 0; i < m_cgstbl; ++i)
+ delete m_vpgstbl[i];
+ }
+
+ bool ReadFromFont(GrIStream & gloc_strm, long lGlocStart,
+ GrIStream & glat_strm, long lGlatStart,
+ data16 chwBWAttr, data16 chwJStrAttr, int cJLevels, int cnCompPerLig,
+ int fxdSilfVersion);
+
+ void CreateEmpty();
+
+ // Setters:
+ void SetNumberOfGlyphs(int c)
+ {
+ m_cglf = c;
+ }
+ void SetNumberOfStyles(int c)
+ {
+ m_cgstbl = c;
+ m_vpgstbl.resize(c);
+ }
+ void SetNumberOfComponents(int c)
+ {
+ m_cComponents = c;
+ for (unsigned int ipgstbl = 0; ipgstbl < m_vpgstbl.size(); ipgstbl++)
+ m_vpgstbl[ipgstbl]->SetNumberOfComponents(c);
+ }
+ void SetSubTable(int i, GrGlyphSubTable * pgstbl)
+ {
+ if (signed(m_vpgstbl.size()) <= i)
+ {
+ gAssert(false);
+ m_vpgstbl.resize(i+1);
+ }
+ m_vpgstbl[i] = pgstbl;
+ m_vpgstbl[i]->SetNumberOfComponents(m_cComponents);
+ }
+
+ // Getters:
+ int NumberOfGlyphs() { return m_cglf; }
+ int NumberOfStyles() { return m_cgstbl; }
+
+ int NumberOfGlyphAttrs()
+ {
+ // All of the sub-tables should have the same number of glyph attributes,
+ // so just ask the first.
+ return m_vpgstbl[0]->NumberOfGlyphAttrs();
+ }
+
+ int GlyphAttrValue(gid16 chwGlyphID, int nAttrID)
+ {
+ gAssert(m_cgstbl == 1);
+ return m_vpgstbl[0]->GlyphAttrValue(chwGlyphID, nAttrID);
+ }
+ // Eventually:
+ //int GlyphAttrValue(gid16 chwGlyphID, int nAttrID, int nStyleIndex)
+ //{
+ // return m_vpgstbl[nStyleIndex]->GlyphAttrValue(chwGlyphID, nAttrID);
+ //}
+
+ int ComponentContainingPoint(gid16 chwGlyphID, int x, int y)
+ {
+ gAssert(m_cgstbl == 1);
+ return m_vpgstbl[0]->ComponentContainingPoint(chwGlyphID, x, y);
+ }
+ // Eventually:
+ //int ComponentContainingPoint(gid16 chwGlyphID, int nStyleIndex, int x, int y)
+ //{
+ // gAssert(m_cgstbl == 1);
+ // return m_vpgstbl[nStyleIndex]->ComponentContainingPoint(chwGlyphID, nAttrID);
+ //}
+
+ bool ComponentBoxLogUnits(float xysEmSquare, gid16 chwGlyphID, int icomp,
+ int mFontEmUnits, float dysAscent,
+ float * pxsLeft, float * pysTop, float * pxsRight, float * pysBottom,
+ bool fTopOrigin = true)
+ {
+ gAssert(m_cgstbl == 1);
+ return m_vpgstbl[0]->ComponentBoxLogUnits(xysEmSquare,
+ chwGlyphID, icomp, mFontEmUnits, dysAscent,
+ pxsLeft, pysTop, pxsRight, pysBottom,
+ fTopOrigin);
+ }
+
+ int ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID)
+ {
+ gAssert(m_cgstbl == 1);
+ return m_vpgstbl[0]->ComponentIndexForGlyph(chwGlyphID, nCompID);
+ }
+
+ bool IsEmpty()
+ {
+ return (m_cglf == 0);
+ }
+
+protected:
+ int m_cglf; // number of glyphs
+ int m_cComponents; // number of defined components
+ int m_cgstbl; // number of sub-tables, corresponding to font files;
+ // for now there is only one
+
+ std::vector<GrGlyphSubTable *> m_vpgstbl;
+
+//:Ignore
+#ifdef OLD_TEST_STUFF
+public:
+ // For test procedures:
+ void SetUpTestData();
+ void SetUpLigatureTest();
+ void SetUpLigature2Test();
+#endif // OLD_TEST_STUFF
+//:End Ignore
+
+};
+
+} // namespace gr
+
+#endif // !GR_GTABLE_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.cpp
new file mode 100644
index 00000000000..ce8094744eb
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.cpp
@@ -0,0 +1,2030 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrPass.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the GrPass class and subclasses.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+/*----------------------------------------------------------------------------------------------
+ Constructors and initializers
+----------------------------------------------------------------------------------------------*/
+GrPass::GrPass(int i)
+ : m_ipass(i),
+ m_fxdVersion(0),
+ m_nMaxRuleContext(0),
+ m_pfsm(NULL),
+ m_nMaxRuleLoop(0),
+ m_nMaxBackup(0),
+ m_crul(0),
+ m_prgchwRuleSortKeys(NULL),
+ m_prgcritRulePreModContext(NULL),
+ m_cbPassConstraint(0),
+ m_prgibConstraintStart(NULL),
+ m_prgibActionStart(NULL),
+ m_prgbPConstraintBlock(NULL),
+ m_prgbConstraintBlock(NULL),
+ m_prgbActionBlock(NULL),
+ m_cbConstraints(0),
+ m_cbActions(0),
+ m_prgibConstraintDebug(NULL),
+ m_prgibRuleDebug(NULL),
+ m_fCheckRules(false),
+ m_prgfRuleOkay(NULL),
+ m_vnStack(128),
+ m_pzpst(NULL)
+{
+}
+
+void PassState::InitForNewSegment(int ipass, int nMaxChunk)
+{
+ m_ipass = ipass;
+ m_nRulesSinceAdvance = 0;
+ m_nMaxChunk = nMaxChunk;
+ m_cslotSkipToResync = 0;
+ m_fDidResyncSkip = false;
+ InitializeLogInfo();
+}
+
+void PassState::InitializeLogInfo()
+{
+ m_crulrec = 0;
+ std::fill_n(m_rgcslotDeletions, 128, 0);
+ std::fill_n(m_rgfInsertion, 128, false);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructors
+----------------------------------------------------------------------------------------------*/
+GrPass::~GrPass()
+{
+ delete m_pfsm;
+
+ delete[] m_prgchwRuleSortKeys;
+
+ delete[] m_prgcritRulePreModContext;
+
+ delete[] m_prgibConstraintStart;
+ delete[] m_prgibActionStart;
+
+ delete[] m_prgbPConstraintBlock;
+ delete[] m_prgbConstraintBlock;
+ delete[] m_prgbActionBlock;
+
+ delete[] m_prgfRuleOkay;
+
+ delete[] m_prgibConstraintDebug;
+ delete[] m_prgibRuleDebug;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the pass by reading from the font stream.
+----------------------------------------------------------------------------------------------*/
+bool GrPass::ReadFromFont(GrIStream & grstrm, int fxdSilfVersion, int fxdRuleVersion,
+ int nOffset)
+{
+ long lPassInfoStart;
+ grstrm.GetPositionInFont(&lPassInfoStart);
+
+ m_fxdVersion = fxdSilfVersion;
+
+ m_fCheckRules = (fxdRuleVersion > kRuleVersion);
+
+// Assert(nOffset == lPassInfoStart);
+ if (lPassInfoStart != nOffset)
+ {
+ grstrm.SetPositionInFont(nOffset);
+ }
+
+ // flags - ignore for now
+ //byte bTmp = grstrm.ReadByteFromFont();
+ grstrm.ReadByteFromFont();
+
+ // MaxRuleLoop
+ m_nMaxRuleLoop = grstrm.ReadByteFromFont();
+
+ // max rule context
+ m_nMaxRuleContext = grstrm.ReadByteFromFont();
+
+ // MaxBackup
+ m_nMaxBackup = grstrm.ReadByteFromFont();
+
+ // number of rules
+ m_crul = grstrm.ReadShortFromFont();
+ // TODO: add a sanity check for the number of rules.
+
+ // offset to pass constraint code, relative to start of subtable
+ int nPConstraintOffset = 0;
+ long lFsmPos = -1;
+ if (fxdSilfVersion >= 0x00020000)
+ {
+ if (fxdSilfVersion >= 0x00030000)
+ lFsmPos = grstrm.ReadUShortFromFont() + nOffset; // offset to row info
+ else
+ grstrm.ReadShortFromFont(); // pad bytes
+ nPConstraintOffset = grstrm.ReadIntFromFont();
+ }
+ // offset to rule constraint code, relative to start of subtable
+ //int nConstraintOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+ // offset to action code, relative to start of subtable
+ //int nActionOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+ // offset to debug strings; 0 if stripped
+ //int nDebugOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+
+ // Jump to beginning of FSM, if we have this information.
+ if (fxdSilfVersion >= 0x00030000)
+ grstrm.SetPositionInFont(lFsmPos);
+ else
+ // Otherwise assume that's where we are!
+ Assert(lFsmPos == -1);
+
+ m_pfsm = new GrFSM();
+
+ m_pfsm->ReadFromFont(grstrm, fxdSilfVersion);
+
+ // rule sort keys
+ m_prgchwRuleSortKeys = new data16[m_crul];
+ data16 * pchw = m_prgchwRuleSortKeys;
+ int irul;
+ for (irul = 0; irul < m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // rule pre-mod-context item counts
+ m_prgcritRulePreModContext = new byte[m_crul];
+ byte * pb = m_prgcritRulePreModContext;
+ for (irul = 0; irul < m_crul; irul++, pb++)
+ {
+ *pb = grstrm.ReadByteFromFont();
+ }
+
+ // constraint offset for pass-level constraints
+ if (fxdSilfVersion >= 0x00020000)
+ {
+ // reserved - pad byte
+ grstrm.ReadByteFromFont();
+ // Note: pass constraints have not been fully implemented.
+ m_cbPassConstraint = grstrm.ReadUShortFromFont();
+ }
+ else
+ m_cbPassConstraint = 0;
+
+ // constraint and action offsets for rules
+ m_prgibConstraintStart = new data16[m_crul + 1];
+ pchw = m_prgibConstraintStart;
+ for (irul = 0; irul <= m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ m_prgibActionStart = new data16[m_crul + 1];
+ pchw = m_prgibActionStart;
+ for (irul = 0; irul <= m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // FSM state table
+ m_pfsm->ReadStateTableFromFont(grstrm, fxdSilfVersion);
+
+ if (fxdSilfVersion >= 0x00020000)
+ // reserved - pad byte
+ grstrm.ReadByteFromFont();
+
+ // Constraint and action blocks
+ int cb = m_cbPassConstraint;
+ m_prgbPConstraintBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbPConstraintBlock, cb);
+ m_cbConstraints = cb;
+
+ cb = m_prgibConstraintStart[m_crul];
+ m_prgbConstraintBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbConstraintBlock, cb);
+ m_cbConstraints += cb;
+
+ cb = m_prgibActionStart[m_crul];
+ m_prgbActionBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbActionBlock, cb);
+ m_cbActions = cb;
+
+ // Rule-validity flags
+ m_prgfRuleOkay = new bool[m_crul];
+ for (irul = 0; irul < m_crul; irul++)
+ m_prgfRuleOkay[irul] = !m_fCheckRules;
+
+ // TODO SharonC/AlanW: debuggers
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize a bogus pass with no rules. Currently this is used to make a single positioning
+ pass if there was none in the font.
+----------------------------------------------------------------------------------------------*/
+void GrPass::InitializeWithNoRules()
+{
+ m_crul = 0;
+ m_nMaxRuleContext = 1;
+ m_nMaxRuleLoop = 1;
+ m_nMaxBackup = 0;
+ m_pfsm = NULL;
+ m_prgchwRuleSortKeys = NULL;
+ m_prgcritRulePreModContext = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream by the given number of characters.
+ (Overridden by GrBidiPass.)
+
+ @param ptman - table manager
+ @param psstrmIn/Out - streams being processed
+ @param cslotNeededByNext - the number of slots being requested by the following pass
+ @param twsh - how we are handling trailing white-space
+ @param pnRet - return value
+ @param pcslotGot - return the number of slots gotten
+ @param pislotFinalBreak - return the index of the final slot, when we are removing
+ the trailing white-space and so the end of the segment
+ will be before the any actual line-break slot
+
+ @return kNextPass if we were able to generated the number requested, or processing is
+ complete; otherwise return the number of slots needed from the previous pass.
+----------------------------------------------------------------------------------------------*/
+void GrPass::ExtendOutput(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotNeededByNext, TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak)
+{
+ // Kludge to generate an error in rendering:
+ //int z = 50;
+ //int t = ((5 * 10) / z) - 1;
+ //if (this->m_ipass == 4)
+ //{
+ // int x; x = z / t;
+ //}
+
+ int islotInitReadPos = psstrmIn->ReadPos();
+ int islotInitWritePos = psstrmOut->WritePos();
+
+ int cslotToGet = max(cslotNeededByNext,
+ m_pzpst->NeededToResync() - psstrmOut->WritePos());
+ int cslotGot = 0;
+
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // While we haven't got the number of slot we've been asked for, and there is enough
+ // available in the input, run rules, filling up the output.
+
+ while ((cslotToGet > 0 && cslotGot < cslotToGet)
+ // Don't leave this pass until we've got the index offset. This is especially
+ // needed for input to the positioning pass, but it doesn't hurt to make it a
+ // general rule.
+ || !psstrmOut->GotIndexOffset()
+ // Don't leave this pass until all the slots to reprocess have been
+ // completely handled.
+ || (psstrmIn->SlotsToReprocess() > 0)
+ // Don't leave this pass until there is a complete cluster in the output
+ || (islotInitWritePos == psstrmOut->WritePos())
+ || (psstrmOut->MaxClusterSlot(islotInitWritePos, psstrmOut->WritePos()) > 0))
+ {
+ int cslotAvailable = psstrmIn->TotalSlotsPending();
+ int cslotNeedMore = MaxRuleContext() - cslotAvailable + ptman->PrevPassMaxBackup(m_ipass);
+
+ // This test should not be necessary, but just in case.
+ if (psstrmIn->PastEndOfPositioning(false))
+ cslotNeedMore = 0; // the input stream is done
+
+ if (// Not enough available in the input:
+ (cslotNeedMore > 0 && !psstrmIn->FullyWritten())
+
+ // && psstrmIn->SegLimIfKnown() == -1) && -- no, because substitution passes may need
+ // to consider slots beyond the seg limit
+
+ // Positioning passes need to know where they are in relation to the initial
+ // line-break.
+ || (IsPosPass() && !psstrmIn->GotIndexOffset())
+
+ // The following can happen on backtracking, when we undo stuff before the
+ // beginning of the segment:
+ || !ptman->Pass(m_ipass - 1)->DidResyncSkip())
+ {
+ // Ask previous pass for more input.
+ *pnRet = max(cslotNeedMore, 1);
+ *pnRet = max(*pnRet, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ Assert(ptman->Pass(m_ipass - 1)->DidResyncSkip());
+
+ bool fDoneThisPass = (cslotAvailable == 0);
+ if (psstrmIn->SlotsToReprocess() == 0)
+ {
+ fDoneThisPass = fDoneThisPass ||
+ psstrmIn->PastEndOfPositioning(false) ||
+ psstrmOut->PastEndOfPositioning(true);
+ }
+
+ if (fDoneThisPass)
+ {
+ // No more input to process--this pass is done.
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+ psstrmIn->ClearReprocBuffer();
+
+ if (twsh == ktwshNoWs && m_ipass == ptman->NumberOfLbPasses())
+ {
+ *pnRet = RemoveTrailingWhiteSpace(ptman, psstrmOut, twsh, pislotFinalBreak);
+ if (*pnRet == kBacktrack) // entire segment was white-space:
+ return; // backtrack, which will fail
+ }
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+ DoCleanUpSegLim(ptman, psstrmOut, twsh);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ if (twsh == ktwshOnlyWs && m_ipass == ptman->NumberOfLbPasses() + 1)
+ {
+ // Note that this is the first pass after the linebreak pass, so psstrmInput
+ // is the output of the linebreak pass.
+ GrSlotState * pslotNext = psstrmIn->Peek();
+ if (!pslotNext->IsLineBreak(chwLB) &&
+ pslotNext->Directionality() != kdircWhiteSpace &&
+ psstrmIn->SegMin() > -1 && psstrmIn->SegMin() <= psstrmIn->ReadPos())
+ {
+ // We are only allowing white-space in this segment and we hit
+ // something else. Don't process any further.
+ if (psstrmIn->SegLimIfKnown() > -1 &&
+ psstrmIn->SegLimIfKnown() <= psstrmIn->ReadPos())
+ {
+ // Already inserted a line-break; we're done.
+ DoResyncSkip(psstrmOut);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+ while (psstrmIn->SlotsToReprocess() > 0)
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, IsPosPass());
+ }
+ psstrmIn->ClearReprocBuffer();
+ *pnRet = kBacktrack;
+ return;
+ }
+ }
+
+ // Otherwise, we have enough input to run a rule.
+
+ psstrmIn->SetRuleStartReadPos();
+ psstrmOut->SetRuleStartWritePos();
+
+ int ruln = -1;
+ if (m_pfsm)
+ ruln = m_pfsm->GetRuleToApply(ptman, this, psstrmIn, psstrmOut);
+ ruln = CheckRuleValidity(ruln);
+ RunRule(ptman, ruln, psstrmIn, psstrmOut);
+
+ cslotGot = psstrmOut->WritePos() - islotInitWritePos;
+ psstrmOut->CalcIndexOffset(ptman);
+ }
+
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+
+ // We're past the point where we care about anything in the reprocessing buffer.
+ Assert(psstrmIn->NoReproc());
+ psstrmIn->ClearReprocBuffer();
+
+ if (psstrmOut->PastEndOfPositioning(true))
+ {
+ DoCleanUpSegLim(ptman, psstrmOut, twsh);
+ psstrmOut->MarkFullyWritten();
+ }
+
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream by the given number of characters.
+ For a GrBidiPass, if we are at a direction change, get the entire
+ range of upstream glyphs, reverse them, and treat them as one chunk.
+ Otherwise just pass one slot through.
+
+ @param ptman - table manager
+ @param psstrmInput/Output - streams being processed
+ @param cslotNeededByNext - the number of slots being requested by the following pass
+ @param twsh - how we are handling trailing white-space
+ @param pnRet - return value
+ @param pcslotGot - return the number of slots gotten
+ @param pislotFinalBreak - not used in this version
+
+ @return 1 if we need more glyphs from the previous pass
+----------------------------------------------------------------------------------------------*/
+void GrBidiPass::ExtendOutput(GrTableManager * ptman,
+ GrSlotStream* psstrmIn, GrSlotStream* psstrmOut,
+ int cslotNeededByNext, TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak)
+{
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+
+ int islotInitReadPos = psstrmIn->ReadPos();
+ int islotInitWritePos = psstrmOut->WritePos();
+
+ Assert(m_pzpst->NeededToResync() == 0);
+
+ int cslotToGet = max(cslotNeededByNext,
+ m_pzpst->NeededToResync() - psstrmOut->WritePos());
+ int cslotGot = 0;
+ int nTopDir;
+ if (twsh == ktwshOnlyWs)
+ nTopDir = (ptman->State()->ParaRightToLeft()) ? 1 : 0;
+ else
+ nTopDir = ptman->TopDirectionLevel();
+
+ while (cslotToGet > 0 && cslotGot < cslotToGet)
+ {
+ int islotChunkO = psstrmOut->WritePos();
+ int islotChunkI = psstrmIn->ReadPos();
+
+ // Need at least one character to test.
+ if (psstrmIn->SlotsPending() < 1 || !ptman->Pass(m_ipass-1)->DidResyncSkip())
+ {
+ if (!psstrmIn->FullyWritten())
+ {
+ // Ask previous pass for more input.
+ *pnRet = max(cslotToGet - psstrmIn->SlotsPending(), 1);
+ *pnRet = max(*pnRet, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+ else
+ {
+ Assert(ptman->Pass(m_ipass-1)->DidResyncSkip());
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+ psstrmIn->ClearReprocBuffer();
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+ DoCleanUpSegLim(ptman, psstrmOut, twsh);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+ }
+
+ std::vector<int> vislotStarts;
+ std::vector<int> vislotStops;
+ int islotReverseLim = psstrmIn->DirLevelRange(ptman->State(),
+ psstrmIn->ReadPos(), nTopDir,
+ vislotStarts, vislotStops);
+ //int islotReverseLim = psstrmIn->OldDirLevelRange(pengst, psstrmIn->ReadPos(), nTopDir);
+ if (islotReverseLim == -1)
+ {
+ // We haven't got the full range of reversed text yet--
+ // ask for more input.
+ *pnRet = max(1, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ // Okay, we have enough input to do the reversal, if any.
+
+ int cslotToReverse = islotReverseLim - psstrmIn->ReadPos();
+
+ // Never reverse the final linebreak; leave it at the end.
+ if (cslotToReverse > 0 && islotReverseLim > 0)
+ {
+ GrSlotState * pslotLast = psstrmIn->SlotAt(islotReverseLim - 1);
+ if (pslotLast->IsFinalLineBreak(ptman->LBGlyphID()))
+ {
+ for (size_t i = 0; i < vislotStops.size(); i++)
+ if (vislotStops.back() == islotReverseLim - 1)
+ vislotStops.back() = islotReverseLim - 2;
+ islotReverseLim--;
+ cslotToReverse--;
+ }
+ }
+
+ psstrmIn->SetRuleStartReadPos();
+ psstrmOut->SetRuleStartWritePos();
+
+ if (cslotToReverse == 0)
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ }
+ else
+ {
+ int islotNextWritePos = psstrmOut->WritePos() + cslotToReverse;
+ int islotNextReadPos = psstrmIn->ReadPos() + cslotToReverse;
+ if (vislotStarts.size() == 0)
+ {
+ Assert(false); // this should have been done by DirLevelRange
+ vislotStarts.push_back(psstrmIn->ReadPos());
+ vislotStops.push_back(islotNextReadPos - 1);
+ }
+ Assert(vislotStarts.back() == psstrmIn->ReadPos());
+ Assert(vislotStops.back() == islotNextReadPos - 1);
+ int cslotNotCopied = Reverse(ptman, psstrmIn, psstrmOut, vislotStarts, vislotStops);
+ //Reverse(nTopDir + 1,
+ // psstrmIn, psstrmIn->ReadPos(), islotReverseLim,
+ // psstrmOut, psstrmOut->WritePos() + cslotToReverse - 1, psstrmOut->WritePos()-1);
+
+ islotNextWritePos -= cslotNotCopied; // bidi markers that are not passed through
+
+ psstrmIn->SetReadPos(islotNextReadPos);
+ psstrmOut->SetWritePos(islotNextWritePos);
+
+ // It's quite strange to have the segment start or end in the middle of stuff to
+ // reverse (because the LB forms a natural terminator), but at any rate,
+ // if that happens, record the segment lim at the corresponding place in the
+ // output stream.
+ int islotSegMinIn = psstrmIn->SegMin();
+ if (islotSegMinIn > -1 &&
+ psstrmIn->ReadPos() - cslotToReverse <= islotSegMinIn &&
+ islotSegMinIn < psstrmIn->ReadPos())
+ {
+ Assert(islotSegMinIn == psstrmIn->ReadPos() - cslotToReverse); // normal situation
+ psstrmOut->SetSegMin(
+ psstrmOut->WritePos() - (psstrmIn->ReadPos() - islotSegMinIn));
+ }
+ int islotSegLimIn = psstrmIn->SegLimIfKnown();
+ if (islotSegLimIn > -1 &&
+ psstrmIn->ReadPos() - cslotToReverse <= islotSegLimIn &&
+ islotSegLimIn < psstrmIn->ReadPos())
+ {
+ Assert(islotSegLimIn == psstrmIn->ReadPos() - cslotToReverse); // normal situation
+ psstrmOut->SetSegLim(
+ psstrmOut->WritePos() - (psstrmIn->ReadPos() - islotSegLimIn));
+ }
+ }
+
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+
+ // Record the chunk mappings:
+ MapChunks(psstrmIn, psstrmOut, islotChunkI, islotChunkO, 0);
+
+ cslotGot = psstrmOut->WritePos() - islotInitWritePos;
+ psstrmOut->CalcIndexOffset(ptman);
+ }
+
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+
+ // We're past the point where we care about anything in the reprocessing buffer.
+ Assert(psstrmIn->NoReproc());
+ psstrmIn->ClearReprocBuffer();
+
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+
+ if (psstrmOut->PastEndOfPositioning(true))
+ {
+ DoCleanUpSegLim(ptman, psstrmOut, twsh);
+ psstrmOut->MarkFullyWritten();
+ }
+
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Generate slots containing glyph IDs for the underlying character data,
+ incrementing the input pointer as we go.
+
+ @param ptman - table manager
+ @param pchstrm - input character stream
+ @param psstrmOutput - output slot stream
+ @param ichSegLim - known end of segment, index into the text; or -1;
+ the lim of the of char-stream itself represents
+ the end of the text-source; this lim is the
+ known desired end of the segment
+ @param cchwPostXlbContext - number of characters that may be needed from the following line;
+ valid when ichSegLim > -1
+ @param lb - breakweight to use for inserted LB
+ @param cslotToGet - the number of slots being requested by the following pass
+ @param fNeedFinalBreak - true if the end of the segment needs to be a valid break point
+ @param pislotFinalBreak - the end of this segment
+----------------------------------------------------------------------------------------------*/
+int GrPass::ExtendGlyphIDOutput(GrTableManager * ptman,
+ GrCharStream * pchstrm, GrSlotStream * psstrmOut, int ichSegLim, int cchwPostXlbContext,
+ LineBrk lb, int cslotToGet, bool fNeedFinalBreak, TrWsHandling twsh,
+ int * pislotFinalBreak)
+{
+ EngineState * pengst = ptman->State();
+
+ // This pass should be the glyph-generation pass.
+ Assert(dynamic_cast<GrGlyphGenPass*>(this));
+ Assert(m_pzpst->m_cslotSkipToResync == 0);
+ m_pzpst->m_fDidResyncSkip = true;
+
+ for (int islot = 0; islot < cslotToGet; ++islot)
+ {
+ int islotChunkO = psstrmOut->WritePos();
+ int islotChunkI = pchstrm->SegOffset();
+
+ if (pchstrm->AtEnd()
+ || (ichSegLim > -1 && pchstrm->Pos() == ichSegLim))
+ {
+ if (psstrmOut->SegLimIfKnown() > -1 &&
+ psstrmOut->SegLimIfKnown() <= psstrmOut->WritePos())
+ {
+ // Already found the end of this stream.
+ }
+ else
+ {
+ if (pchstrm->EndLine() && !fNeedFinalBreak)
+ // (if we need a good final break, don't just append an LB;
+ // make it backtrack and find a valid break point)
+ {
+ // Only need to get a good break when we're backtracking; otherwise we
+ // already know it.
+ Assert(ichSegLim == -1 || !fNeedFinalBreak);
+ // Notice that we're cheating here: we're putting the LB in the zeroth
+ // stream instead of in the output of the linebreak table.
+ psstrmOut->AppendLineBreak(ptman, pchstrm,
+ (pchstrm->AtEnd() ? klbWordBreak : lb),
+ ((ptman->RightToLeft()) ? kdircRlb : kdircLlb), -1, false,
+ pchstrm->SegOffset());
+ if (pchstrm->AtEnd())
+ pengst->SetFinalLB();
+ else
+ pengst->SetInsertedLB(true);
+ }
+ else
+ {
+ // Don't actually insert a line-break glyph.
+ psstrmOut->SetSegLimToWritePos();
+ }
+ *pislotFinalBreak = psstrmOut->WritePos() - 1;
+ if (ptman->NumberOfLbPasses() > 0 && pengst->HasInitialLB())
+ {
+ // Because we cheated above: the output stream of the linekbreak table
+ // has an initial LB, which this stream doesn't have. Adjust the position
+ // of the final break to match what it will be in the output of the
+ // lb table.
+ *pislotFinalBreak += 1;
+ }
+ }
+
+ if (twsh == ktwshNoWs && m_ipass == ptman->NumberOfLbPasses())
+ {
+ int nRet = RemoveTrailingWhiteSpace(ptman, psstrmOut, twsh, pislotFinalBreak);
+ if (nRet == kBacktrack) // entire segment was white-space:
+ return kBacktrack; // backtrack, which will fail
+ }
+ if (pchstrm->AtEnd())
+ {
+ psstrmOut->MarkFullyWritten();
+ return kNextPass;
+ }
+ // otherwise we may need a few more characters for line-boundary contextualization.
+ }
+
+ int ichwSegOffset; // offset from the official start of the segment
+ int cchw; // number of 16-bit chars consumed
+ GrFeatureValues fval;
+ int nUnicode = pchstrm->NextGet(ptman, &fval, &ichwSegOffset, &cchw);
+ gid16 chwGlyphID = ptman->GetGlyphIDFromUnicode(nUnicode);
+
+ if (nUnicode == knCR || nUnicode == knLF || nUnicode == knLineSep || nUnicode == knParaSep ||
+ nUnicode == knORC)
+ {
+ // Hard line-break: we're done.
+ // Note that we don't include the hard-break character in this segment.
+ pchstrm->HitHardBreak();
+ pengst->SetHitHardBreak();
+ psstrmOut->MarkFullyWritten();
+ return kNextPass;
+ }
+
+ GrSlotState * pslotNew;
+ ptman->State()->NewSlot(chwGlyphID, fval, 0, ichwSegOffset, nUnicode, &pslotNew);
+
+ psstrmOut->NextPut(pslotNew);
+ psstrmOut->MapInputChunk(islotChunkI, islotChunkO, pchstrm->SegOffset(), false, false);
+ // Mapping the output chunks of the char stream has already been handled by the
+ // char stream.
+
+ }
+
+ psstrmOut->CalcIndexOffset(ptman);
+
+ if (psstrmOut->PastEndOfPositioning(true)
+ || (ichSegLim > -1 && pchstrm->Pos() > ichSegLim + cchwPostXlbContext))
+ {
+ // We have enough for this segment.
+ psstrmOut->MarkFullyWritten();
+ }
+
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream until it is using up the allotted amount of
+ physical space. Return kNextPass when all data has been processed successfully.
+ Return kBacktrack when space overflows, indicating that we need to backtrack
+ and find a break point. Otherwise, return the number of slots we
+ need from the previous pass.
+
+ @param fWidthIsCharCount - kludge for test procedures
+ @param fInfiniteWidth - don't test for more space
+ @param fMustBacktrack - true if we need a good final break and haven't found one yet
+ @param lbMax - max allowed for the final slot
+ @param twsh - how we are handling trailing white-space
+----------------------------------------------------------------------------------------------*/
+int GrPass::ExtendFinalOutput(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput,
+ float xsSpaceAllotted, bool fWidthIsCharCount, bool fInfiniteWidth,
+ bool fHaveLineBreak, bool fMustBacktrack, LineBrk lbMax, TrWsHandling twsh,
+ int * pislotLB, float * pxsWidth)
+{
+ EngineState * pengst = ptman->State();
+
+ // This pass should be the final positioning pass.
+ Assert(dynamic_cast<GrPosPass*>(this));
+
+ // It would be very strange to be positioning based on something that happened in
+ // previous line. -- not true any more, since this will include the max-precontext-length.
+// Assert(m_cslotSkipToResync == 0);
+
+ int islotOutputLB = -1;
+ //int islotInitWritePos = psstrmOutput->WritePos();
+ int islotNoLbUpTo = psstrmOutput->WritePos();;
+
+ while (true)
+ {
+ // Do this right up front, so we are only measuring actual output.
+ if (m_pzpst->CanResyncSkip(psstrmOutput))
+ m_pzpst->DoResyncSkip(psstrmOutput);
+
+ bool fMoreSpace;
+ if (!m_pzpst->DidResyncSkip())
+ fMoreSpace = true;
+ else if (fInfiniteWidth)
+ fMoreSpace = true;
+ else
+ fMoreSpace = psstrmOutput->MoreSpace(ptman,
+ xsSpaceAllotted, fWidthIsCharCount,
+ true, // always ignore trailing white space when we are first making the segment
+ twsh,
+ pxsWidth);
+ if (!fMoreSpace)
+ {
+ // Overflowed available space; backtrack and find a line break.
+ while (psstrmInput->SlotsToReprocess() > 0)
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, IsPosPass());
+ }
+ psstrmInput->ClearReprocBuffer();
+
+ *pislotLB = -1;
+ pengst->SetExceededSpace();
+ pengst->SetHitHardBreak(false);
+ return kBacktrack;
+ }
+
+ if (islotOutputLB != -1 && psstrmInput->SlotsToReprocess() == 0)
+ {
+ // Hit the inserted line break--we're done.
+ psstrmInput->ClearReprocBuffer();
+ *pislotLB = islotOutputLB;
+ return kNextPass;
+ }
+
+ int nslotAvailable = psstrmInput->SlotsPending();
+ if ((nslotAvailable - ptman->PrevPassMaxBackup(m_ipass)
+ < MaxRuleContext() && !psstrmInput->FullyWritten())
+ || !ptman->Pass(m_ipass-1)->DidResyncSkip())
+ {
+ // Not enough available in the input--ask previous pass for more input.
+ // Ten is an arbitrary value--we ask for more that we really need to cut down
+ // on the number of times we loop between passes.
+ return max(MaxRuleContext() - (nslotAvailable - 10), 1);
+ }
+
+ Assert(ptman->Pass(m_ipass - 1)->DidResyncSkip());
+
+ if (nslotAvailable == 0)
+ {
+ // No more input to process. If we have a valid line-break, or we don't care,
+ // we're done. Otherwise backtrack to find a valid break point.
+ Assert(psstrmInput->SlotsToReprocess() == 0);
+ psstrmInput->ClearReprocBuffer();
+ if (fMustBacktrack)
+ {
+ *pislotLB = -1;
+ return kBacktrack;
+ }
+ else
+ {
+ psstrmOutput->MarkFullyWritten();
+ return kNextPass;
+ }
+ }
+
+ // Otherwise, we have enough input to run a rule.
+
+ psstrmInput->SetRuleStartReadPos();
+ psstrmOutput->SetRuleStartWritePos();
+
+ int ruln = -1;
+ if (m_pfsm)
+ ruln = m_pfsm->GetRuleToApply(ptman, this, psstrmInput, psstrmOutput);
+ ruln = CheckRuleValidity(ruln);
+ RunRule(ptman, ruln, psstrmInput, psstrmOutput);
+
+ if (fHaveLineBreak)
+ {
+ islotOutputLB =
+ psstrmOutput->FindFinalLineBreak(ptman->LBGlyphID(),
+ islotNoLbUpTo, psstrmOutput->WritePos());
+ islotNoLbUpTo = psstrmOutput->WritePos();
+ }
+
+ psstrmOutput->CalcIndexOffset(ptman);
+ }
+
+ Assert(false);
+
+ psstrmInput->ClearReprocBuffer();
+ *pislotLB = -1;
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Remove undesirable trailing white-space.
+----------------------------------------------------------------------------------------------*/
+int GrPass::RemoveTrailingWhiteSpace(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh, int * pislotFinalBreak)
+{
+ EngineState * pengst = ptman->State();
+
+ Assert(twsh == ktwshNoWs);
+ Assert(m_ipass == ptman->NumberOfLbPasses()); // output of (final) lb pass
+
+ int islotTmp = psstrmOut->FinalSegLim();
+ if (islotTmp <= 0)
+ return kNextPass;
+
+ GrSlotState * pslotLast = psstrmOut->SlotAt(islotTmp-1);
+ if (islotTmp > 0 && pslotLast->IsFinalLineBreak(ptman->LBGlyphID()))
+ {
+ islotTmp--;
+ pslotLast = (islotTmp > 0) ? psstrmOut->SlotAt(islotTmp-1) : NULL;
+ }
+ bool fRemovedWs = false;
+ while (islotTmp > 0 && pslotLast->Directionality() == kdircWhiteSpace)
+ {
+ islotTmp--;
+ pslotLast = (islotTmp > 0) ? psstrmOut->SlotAt(islotTmp-1) : NULL;
+ fRemovedWs = true;
+ }
+ if (fRemovedWs)
+ {
+ if (islotTmp <= 0)
+ {
+ // Entire segment was white-space: backtrack, which will fail.
+ return kBacktrack;
+ }
+ psstrmOut->SetSegLim(islotTmp);
+ *pislotFinalBreak = islotTmp - 1;
+ pengst->SetFinalLB(false);
+ pengst->SetRemovedTrWhiteSpace();
+ ptman->UnwindAndReinit(islotTmp - 1);
+ }
+
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Keep track of whether we're advancing through the input satisfactorily;
+ if not, forcibly advance. This is a safety net to avoid infinite loops; it
+ should never be necessary if they've set up their tables right.
+----------------------------------------------------------------------------------------------*/
+void GrPass::CheckInputProgress(GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput,
+ int islotOrigInput)
+{
+ int islotInput = psstrmInput->ReadPosForNextGet();
+// Assert(islotInput >= islotOrigInput); -- no longer true now that we can back up
+
+ if (islotInput <= psstrmInput->ReadPosMax())
+ {
+ // Didn't advance.
+ if (m_pzpst->m_nRulesSinceAdvance >= m_nMaxRuleLoop)
+ {
+ bool fAdvanced = false;
+ // Forcibly advance. First try to advance to where we backed up from.
+ while (!psstrmInput->AtEnd() &&
+ psstrmInput->ReadPosForNextGet() < psstrmInput->ReadPosMax())
+ {
+ RecordHitMaxRuleLoop(psstrmInput->ReadPosForNextGet());
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ fAdvanced = true;
+ }
+ // If that didn't do anything productive, just advance one slot.
+ if (!fAdvanced && !psstrmInput->AtEndOfContext())
+ {
+ RecordHitMaxRuleLoop(psstrmInput->ReadPosForNextGet());
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ }
+
+ m_pzpst->m_nRulesSinceAdvance = 0;
+ }
+ else m_pzpst->m_nRulesSinceAdvance++;
+ }
+ else m_pzpst->m_nRulesSinceAdvance = 0;
+
+ psstrmInput->SetReadPosMax(islotInput);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record the chunks in the streams' chunk maps.
+
+ psstrmIn/Out - streams being processed
+ islotChunkIn/Out - start of chunks
+ cslotReprocessed - number of slots to reprocess before the rule was run
+----------------------------------------------------------------------------------------------*/
+void GrPass::MapChunks(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int islotChunkIn, int islotChunkOut, int cslotReprocessed)
+{
+ if (islotChunkOut > psstrmOut->WritePos())
+ {
+ // backing up
+ int islotReadPosTmp = psstrmIn->ReadPosForNextGet();
+/// Assert((islotChunkIn - islotReadPosTmp) == (islotChunkOut - psstrmOut->WritePos()));
+// psstrmIn->MapOutputChunk(psstrmOut->WritePos() - 1, islotReadPosTmp - 1,
+// islotChunkOut, true, 0, true);
+// psstrmOut->MapInputChunk(islotReadPosTmp - 1, psstrmOut->WritePos() - 1,
+// islotChunkIn, true, true);
+
+ // Resync.
+ if (psstrmOut->WritePos() == 0)
+ {
+ // Clear all the chunks.
+ psstrmIn->MapOutputChunk(-1, -1, 0, true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, islotReadPosTmp, true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+ else if (islotReadPosTmp == 0)
+ {
+ // Clear all the chunks.
+ psstrmIn->MapOutputChunk(-1, -1, psstrmOut->WritePos(), true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, 0, true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+ // Find the beginning of the current chunk.
+ int islotChunkOutAdj = min(islotChunkOut, psstrmOut->WritePos() - 1);
+ int islotChunkInAdj = psstrmOut->ChunkInPrev(islotChunkOutAdj);
+ while (islotChunkInAdj == -1 && islotChunkOutAdj > 0)
+ islotChunkInAdj = psstrmOut->ChunkInPrev(--islotChunkOutAdj);
+
+ if (islotChunkInAdj == -1)
+ {
+ // Couldn't find the beginning of any chunk; zap them all.
+ psstrmIn->MapOutputChunk(-1, -1, psstrmOut->WritePos(), true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, psstrmOut->ReadPos(), true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+
+ if (psstrmIn->ChunkInNext(islotChunkInAdj) != islotChunkOutAdj)
+ {
+ islotChunkOutAdj = psstrmIn->ChunkInNext(islotChunkInAdj);
+ while (islotChunkOutAdj == -1 && islotChunkInAdj > 0)
+ islotChunkOutAdj = psstrmIn->ChunkInNext(--islotChunkInAdj);
+ }
+
+ psstrmIn->MapOutputChunk(islotChunkOutAdj, islotChunkInAdj,
+ psstrmOut->WritePos(), false, 0, true);
+ psstrmOut->MapInputChunk(islotChunkInAdj, islotChunkOutAdj,
+ psstrmIn->ReadPos(), false, true);
+ }
+ else if (islotChunkOut == psstrmOut->WritePos())
+ // no output generated--continue the previous chunk
+ ;
+ else if (islotChunkIn == psstrmIn->ReadPos())
+ // no input consumed
+ ;
+ else
+ {
+ psstrmIn->MapOutputChunk(islotChunkOut, islotChunkIn, psstrmOut->WritePos(),
+ (cslotReprocessed > 0), cslotReprocessed, false);
+ psstrmOut->MapInputChunk(islotChunkIn, islotChunkOut, psstrmIn->ReadPos(),
+ (cslotReprocessed > 0), false);
+ }
+
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+
+ m_pzpst->m_nMaxChunk = max(m_pzpst->m_nMaxChunk, psstrmIn->LastNextChunkLength());
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method is something of a kludge. During the course of running the rules we try to
+ keep track of the seg-min location, but sometimes that gets confused due to insertions
+ and deletions at the segment boundaries.
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::DoCleanUpSegMin(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut)
+{
+ int islotSegMinIn = psstrmIn->SegMin();
+ if (islotSegMinIn == -1)
+ return; // input doesn't even know it
+ if (islotInitReadPos > islotSegMinIn)
+ return; // should already have figured it out
+
+ // Otherwise this batch of processing likely set the seg-min on the output stream,
+ // so check it out.
+
+ // First, if the seg-min of the input stream is zero, it should be zero on the output.
+ if (islotSegMinIn == 0)
+ {
+ psstrmOut->SetSegMin(0, true);
+ return;
+ }
+
+ // If there is an initial line-break, the seg-min should be just before it.
+ int islot;
+ if (ptman->State()->HasInitialLB())
+ {
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // Unfortunately, the seg-min from the previous segment can get off, too. :-(
+ // Fix it, while we're at it.
+ if (!psstrmIn->SlotAt(islotSegMinIn)->IsInitialLineBreak(chwLB))
+ {
+ for (islot = 0; islot < psstrmIn->ReadPos(); islot++)
+ if (psstrmIn->SlotAt(islot)->IsInitialLineBreak(chwLB))
+ {
+ psstrmIn->SetSegMin(islot, true);
+ break;
+ }
+ }
+ if (psstrmOut->SegMin() > -1
+ && psstrmOut->SlotAt(psstrmOut->SegMin())->IsInitialLineBreak(chwLB))
+ {
+ return; // already okay
+ }
+ for (islot = 0; islot < psstrmOut->WritePos(); islot++)
+ if (psstrmOut->SlotAt(islot)->IsInitialLineBreak(chwLB))
+ {
+ psstrmOut->SetSegMin(islot, true);
+ return;
+ }
+ Assert(false); // couldn't find it
+ }
+
+ // Otherwise, figure it out using the associations. First observe that the seg-min
+ // will be in the corresponding chunk to the seg-min of the previous pass.
+ int islotChunkMinIn = psstrmIn->ChunkInNextMin(islotSegMinIn);
+ int islotChunkLimIn = psstrmIn->ChunkInNextLim(islotSegMinIn);
+ if (islotChunkMinIn == -1) islotChunkMinIn = 0;
+ if (islotChunkLimIn == -1) islotChunkLimIn = 1;
+
+ int islotChunkMinOut = psstrmIn->ChunkInNext(islotChunkMinIn);
+ int islotChunkLimOut = psstrmIn->ChunkInNext(islotChunkLimIn);
+ if (islotChunkMinOut == -1) islotChunkMinOut = 0;
+ if (islotChunkLimOut == -1) islotChunkLimOut = 1;
+
+ int islotSegMinOut = psstrmOut->SegMin();
+ if (islotSegMinOut == -1)
+ {
+ // No reasonable guess; try to figure it out.
+ for (islot = islotChunkMinOut; islot < islotChunkLimOut; islot++)
+ {
+// GrSlotState * pslotOut = psstrmOut->SlotAt(islot);
+ if (psstrmOut->SlotAt(islot)->BeforeAssoc() == 0)
+ {
+ islotSegMinOut = islot;
+ break;
+ }
+ }
+ if (islotSegMinOut == -1)
+ {
+ // Ick, couldn't figure it out. Let's hope we set it to something reasonable earlier.
+ Assert(psstrmOut->SegMin() > -1);
+ return;
+ }
+ }
+ // else we have a reasonable guess
+
+ // islotSegMinOut is the best or at leastfirst slot in the chunk that maps into the segment.
+ // But if there is an adjacent slot inserted before it and it is in the chunk,
+ // we want to include that also.
+ while (islotSegMinOut > islotChunkMinOut
+ && psstrmOut->SlotAt(islotSegMinOut-1)->BeforeAssoc() >= 0)
+ {
+ islotSegMinOut--;
+ }
+ psstrmOut->SetSegMin(islotSegMinOut, true);
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method is something of a kludge. We try to put inserted glyphs after the final
+ line-break, but if we don't have line break, they should go inside the segment.
+ This method is only called after the pass is fully written.
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::DoCleanUpSegLim(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh)
+{
+ int islotSegLimOut = psstrmOut->SegLimIfKnown();
+ if (islotSegLimOut == -1)
+ return; // output hasn't set it; nothing to fix
+
+ if (twsh == ktwshNoWs)
+ return; // we just stripped off the whitespace; don't put it back!
+
+ //gid16 chwLB = ptman->LBGlyphID();
+ // If there is a LB glyph, it should be at islotSegLimOut--
+ // unless we backtracked an inserted one earlier.
+ if (ptman->State()->HasInsertedLB()) // && psstrmOut->SlotAt(islotSegLimOut)->IsFinalLineBreak(chwLB))
+ return;
+
+ // Okay, no LB; make sure all output glyphs are included in this segment.
+ psstrmOut->SetSegLimToWritePos(true);
+}
+
+/*----------------------------------------------------------------------------------------------
+ If we are in a state where we are supposed to skip some of the initial output,
+ do so. The purpose of this is to resync when restarting for a segment other than the
+ first. Caller should ensure that there are enough slots to skip.
+----------------------------------------------------------------------------------------------*/
+int PassState::DoResyncSkip(GrSlotStream * psstrmOutput)
+{
+ if (m_fDidResyncSkip)
+ return 0;
+
+ if (m_cslotSkipToResync == 0)
+ {
+ m_fDidResyncSkip = true;
+ return 0;
+ }
+
+ if (!CanResyncSkip(psstrmOutput))
+ {
+ Assert(false); // caller makes sure this doesn't happen
+ return (m_cslotSkipToResync - psstrmOutput->WritePos());
+ }
+
+ psstrmOutput->ResyncSkip(m_cslotSkipToResync);
+ m_fDidResyncSkip = true;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Run a constraint for a single rule.
+
+ @param ruln - rule to test
+ @param psstrmIn - input stream
+ @param psstrmOut - for accessing items in the pre-context
+ @param cslotPreModContext - the number of items that need to be tested prior to the
+ current stream position
+ @param cslotMatched - the number of items matched after the current stream position
+----------------------------------------------------------------------------------------------*/
+bool GrPass::RunConstraint(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotPreModContext, int cslotMatched)
+{
+ int nRet = 0;
+
+ if (m_prgibConstraintStart == NULL)
+ return true;
+
+ int biStart = int(m_prgibConstraintStart[ruln]);
+ if (biStart == 0)
+ return true; // no constraints
+
+ for (int islot = -cslotPreModContext; islot < cslotMatched; islot++)
+ {
+ nRet = RunCommandCode(ptman, m_prgbConstraintBlock + biStart, true,
+ psstrmIn, psstrmOut, islot);
+
+ if (nRet == 0) // one slot failed
+ return false;
+ }
+
+ return (nRet != 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check that we can interpret all the commands in the rule. If not, return -1 indicating
+ that we don't want to run a rule after all. This can happen when the version of the compiler
+ that generated the font is later than this engine.
+----------------------------------------------------------------------------------------------*/
+int GrPass::CheckRuleValidity(int ruln)
+{
+ if (ruln == -1)
+ return -1;
+
+ if (m_prgfRuleOkay[ruln])
+ return ruln;
+
+ int biStart = m_prgibActionStart[ruln];
+ byte * pbNext = m_prgbActionBlock + biStart;
+
+ // General purpose variables:
+// int arg1, arg2, arg3, arg4;
+ int nSlotRef;
+ int nInputClass;
+ int nOutputClass;
+ int c;
+ int islotArg;
+ int nIndex;
+ int nGlyphAttr;
+ int nAttLevel;
+ int nFeat;
+ int nPState;
+// SlotAttrName slat;
+
+ int i;
+
+// int nRet = 0;
+
+ while (true) // exit by encountering PopRet or RetTrue or RetZero
+ {
+ ActionCommand op = ActionCommand(*pbNext++);
+
+ switch (op)
+ {
+ case kopNop:
+ break;
+
+ case kopPushByte:
+ pbNext++;
+ break;
+ case kopPushByteU:
+ pbNext++;
+ break;
+ case kopPushShort:
+ pbNext++;
+ pbNext++;
+ break;
+ case kopPushShortU:
+ pbNext++;
+ pbNext++;
+ break;
+ case kopPushLong:
+ pbNext++;
+ pbNext++;
+ pbNext++;
+ pbNext++;
+ break;
+
+ case kopNeg:
+ case kopTrunc8: case kopTrunc16:
+ case kopNot:
+ break;
+
+ case kopAdd: case kopSub:
+ case kopMul: case kopDiv:
+ case kopMin: case kopMax:
+ case kopAnd: case kopOr:
+ case kopEqual: case kopNotEq:
+ case kopLess: case kopGtr:
+ case kopLessEq: case kopGtrEq:
+ break;
+
+ case kopCond:
+ break;
+
+ case kopNext:
+ break;
+ case kopNextN:
+ c = *pbNext; pbNext++; // count
+ break;
+ case kopPutGlyph8bitObs:
+ nOutputClass = *pbNext++;
+ break;
+ case kopPutGlyph:
+ pbNext += 2;
+ break;
+ case kopPutCopy:
+ nSlotRef = *pbNext++;
+ break;
+ case kopPutSubs8bitObs:
+ nSlotRef = *pbNext++;
+ nInputClass = *pbNext++;
+ nOutputClass = *pbNext++;
+ break;
+ case kopPutSubs:
+ nSlotRef = *pbNext++;
+ pbNext += 4; // 2 bytes each for classes
+ break;
+ case kopCopyNext:
+ break;
+ case kopInsert:
+ break;
+ case kopDelete:
+ break;
+ case kopAssoc:
+ c = *pbNext; pbNext++;
+ for (i = 0; i < c; i++)
+ pbNext++;
+ break;
+ case kopCntxtItem:
+ islotArg = *pbNext++;
+ c = *pbNext++;
+ break;
+
+ case kopAttrSet:
+ case kopAttrAdd:
+ case kopAttrSub:
+ case kopAttrSetSlot:
+ pbNext++; // slot attribute ID
+ break;
+ case kopIAttrSet:
+ case kopIAttrAdd:
+ case kopIAttrSub:
+ case kopIAttrSetSlot:
+ pbNext++; // slot attribute ID
+ nIndex = *pbNext++; // index; eg, global ID for component
+ break;
+
+ case kopPushSlotAttr:
+ pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+ case kopPushISlotAttr:
+ pbNext++;
+ nSlotRef = *pbNext++;
+ nIndex = *pbNext++;
+ break;
+
+ case kopPushGlyphAttrObs:
+ case kopPushAttToGAttrObs:
+ nGlyphAttr = *pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+ case kopPushGlyphAttr:
+ case kopPushAttToGlyphAttr:
+ *pbNext += 3;
+ break;
+ case kopPushGlyphMetric:
+ case kopPushAttToGlyphMetric:
+ nGlyphAttr = *pbNext++;
+ nSlotRef = *pbNext++;
+ nAttLevel = *pbNext++;
+ break;
+ case kopPushFeat:
+ nFeat = *pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+
+ case kopPushProcState:
+ nPState = *pbNext++;
+ break;
+ case kopPushVersion:
+ break;
+
+ case kopPopRet:
+ case kopRetZero:
+ case kopRetTrue:
+ m_prgfRuleOkay[ruln] = true;
+ return ruln;
+
+ default:
+ // Uninterpretable command:
+ return -1;
+ }
+ }
+
+ return ruln; // to keep compiler from griping
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just passes one character through.
+ The rule does nothing but set the line-break weights for the slots.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn/Out - input/output stream
+----------------------------------------------------------------------------------------------*/
+void GrLineBreakPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPos();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ if (ruln == -1)
+ {
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ // Just pass one glyph through.
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+ }
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ {
+ int biStart = m_prgibActionStart[ruln];
+ int iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, false);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just passes one character through.
+ Keeps track of the association information in the slots and chunk
+ mappings for backtracking.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn/Out - input / output streams
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPosForNextGet();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ if (ruln == -1)
+ {
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ // Just pass one glyph through.
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+ }
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ /****************************/
+ {
+ int biStart = m_prgibActionStart[ruln];
+ int iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, false);
+
+ // Restore if we need line-boundary contextualization based on physical locations
+ ////psstrmOut->SetLBContextFlag(ptman, islotOut);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just positions one character in the standard way.
+ Keeps track of (among other things) the overall physical size of the output
+ and chunk mappings.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn / Out - input / output streams
+----------------------------------------------------------------------------------------------*/
+void GrPosPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPosForNextGet();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ int iResult = 0;
+
+ Assert(psstrmIn->GotIndexOffset());
+ // Don't do any positioning in anything being processed from the previous line.
+ if (psstrmIn->ReadPosForNextGet() < psstrmIn->IndexOffset())
+ ruln = -1;
+
+ if (ruln == -1)
+ {
+ // Just position one glyph in the standard way.
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ iResult = 0;
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ {
+ int biStart = m_prgibActionStart[ruln];
+ iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ }
+ }
+
+ // Make sure an entire cluster is present in the output stream. Actually there might be
+ // interleaved clusters, which is the purpose for the loop.
+ int dislotClusterMax = 0;
+ do {
+ dislotClusterMax = psstrmIn->MaxClusterSlot(islotIn, psstrmIn->ReadPos());
+ Assert(dislotClusterMax >= 0);
+ for (int islot = 0; islot < dislotClusterMax; islot++)
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ iResult -= dislotClusterMax;
+ } while (dislotClusterMax > 0);
+
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, true);
+
+ // Restore if we need line-boundary contextualization based on physical locations
+ ////psstrmOut->SetLBContextFlag(ptman, islotOut);
+
+ if (ruln > -1)
+ {
+ psstrmOut->CalcIndexOffset(ptman);
+ // Update the attachment trees and cluster metrics for slots modified by this rule.
+ // Note that this loop assumes that the reprocess buffer points to the identical
+ // slot objects as the output stream (not copies of the slots).
+ for (int islot = islotIn - psstrmIn->SlotsSkippedToResync();
+ islot < psstrmOut->WritePos() + psstrmIn->SlotsToReprocess();
+ islot++)
+ {
+ psstrmOut->SlotAt(islot)->HandleModifiedPosition(ptman, psstrmIn, psstrmOut, islot);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+
+ psstrmOut->AssertStreamIndicesValid(psstrmIn);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform the reversal for internal bidirectionality.
+ Caller is responsible for updating the read- and write-positions.
+ Private.
+
+ OBSOLETE
+
+ @param nCurrDirection - direction level of range of reverse
+ @param psstrmIn, psstrmOut - streams
+ @param islotInMin, islotInLim - range to reverse
+ @param islotOutMin,islotOutLim - corresponding output positions; note that islotOutMin
+ will be greater than islotOutLim if we are reversing
+ reversing the slots (direction is odd)
+----------------------------------------------------------------------------------------------*/
+#if 0
+void GrBidiPass::OldReverse(int nCurrDirection,
+ GrSlotStream * psstrmIn, int islotInMin, int islotInLim,
+ GrSlotStream * psstrmOut, int islotOutMin, int islotOutLim)
+{
+ int oInc = (islotOutLim > islotOutMin)? 1: -1; // which direction output is moving in
+ // buffer (if dir is even, oInc == 1;
+ // if odd, oInc == -1)
+
+ int islotITmp = islotInMin;
+ int islotOTmp = islotOutMin;
+
+ while (islotITmp != islotInLim) {
+ // Find end of sub-range at current level to reverse.
+ int islotSubLim = psstrmIn->OldDirLevelRange(NULL, islotITmp, nCurrDirection);
+ Assert(islotSubLim >= 0);
+
+ if (islotSubLim == islotITmp) {
+ // Current slot is at this level--just copy it.
+ psstrmOut->SimpleCopyFrom(psstrmIn, islotITmp, islotOTmp);
+ islotOTmp += oInc;
+ islotITmp++;
+ }
+ else {
+ // There is a sub-range that needs to be reversed.
+ int islotONext = islotOTmp + ((islotSubLim-islotITmp) * oInc);
+ OldReverse(nCurrDirection+1,
+ psstrmIn, islotITmp, islotSubLim,
+ psstrmOut, islotONext - oInc, islotOTmp - oInc);
+ islotOTmp = islotONext;
+ islotITmp = islotSubLim;
+ }
+ }
+}
+#endif
+
+/*----------------------------------------------------------------------------------------------
+ Perform the reversal for internal bidirectionality.
+ Caller is responsible for updating the read- and write-positions.
+ Return the number of slots NOT copied because they were markers.
+ Private.
+
+ @param psstrmIn, psstrmOut - streams
+ @param vislotStarts, vislotStops - indices of ranges to reverse, from inner to outer
+----------------------------------------------------------------------------------------------*/
+int GrBidiPass::Reverse(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops)
+{
+ Assert(vislotStarts.size() == vislotStops.size());
+
+ std::vector<int> vislotMap; // list of slot indices in the order they should be copied
+ // into the output
+
+ int islotOuterStart = vislotStarts.back();
+ int islotOuterStop = vislotStops.back();
+
+ // Initialize map as if nothing is reversed; eg for [2, 9]: (2 3 4 5 6 7 8 9)
+ int islot;
+ for (islot = 0; islot <= (islotOuterStop - islotOuterStart); islot++)
+ vislotMap.push_back(islot + islotOuterStart);
+
+ // Do the inner reversals first, followed by the outer reversals.
+ size_t iislot;
+ for (iislot = 0; iislot < vislotStarts.size(); iislot++)
+ {
+ // Reverse the run.
+ int islotStart = vislotStarts[iislot] - islotOuterStart;
+ int islotStop = vislotStops[iislot] - islotOuterStart;
+ int islot1, islot2;
+ for (islot1 = islotStart, islot2 = islotStop; islot1 < islot2; islot1++, islot2--)
+ {
+ int islotTmp = vislotMap[islot1];
+ vislotMap[islot1] = vislotMap[islot2];
+ vislotMap[islot2] = islotTmp;
+ }
+ }
+
+ // With vislotStarts = [7, 5, 2] and vislotStops = [8, 8, 9], we get
+ // first: (2 3 4 5 6 8 7 9)
+ // then: (2 3 4 7 8 5 6 9)
+ // and finally: (9 6 5 8 7 4 3 2)
+
+ // Now copy the slots.
+
+ int islotOutStart = psstrmOut->WritePos();
+ int cslotNotCopied = 0;
+ for (iislot = 0; iislot < vislotMap.size(); iislot++)
+ {
+ GrSlotState * pslot = psstrmIn->SlotAt(vislotMap[iislot]);
+ // Don't copy bidi markers unless they have been set to use a specific glyph.
+ if (pslot->IsBidiMarker() && pslot->ActualGlyphForOutput(ptman) == 0)
+ cslotNotCopied++;
+ else
+ psstrmOut->SimpleCopyFrom(psstrmIn, vislotMap[iislot],
+ iislot + islotOutStart - cslotNotCopied);
+ }
+ return cslotNotCopied;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Unwind the output for this pass, given that a change was assumed to have occurred
+ in the input at the given position. Return the position to which we unwound.
+----------------------------------------------------------------------------------------------*/
+int GrPass::Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ bool fFirst)
+{
+ // Back up the number of slots required for the longest rule context,
+ // but if we land in the middle of a chunk, go forward to its boundary.
+ int islotIn = max(islotChanged - m_pzpst->MaxChunk(), 0);
+ if (!psstrmIn->NoReproc())
+ islotIn = min(islotIn, psstrmIn->ReprocMin());
+ psstrmIn->ClearReprocBuffer();
+ int islotOut = 0;
+ if (islotIn < psstrmIn->SlotsSkippedToResync() ||
+ islotIn == 0 ||
+ psstrmIn->ReadPos() == 0)
+ {
+ // The next-chunk-map is invalid. The beginning of the chunk is 0.
+ islotIn = 0;
+ islotOut = 0;
+ }
+ else if (islotIn >= psstrmIn->ReadPos())
+ {
+ // No need to unwind.
+ Assert(psstrmIn->NoReproc());
+ return psstrmOut->WritePos();
+ }
+ else
+ {
+ Assert(islotIn < psstrmIn->ReadPos());
+ islotIn = min(islotIn, psstrmIn->ReadPos() - 1);
+ while (islotIn < psstrmIn->ReadPos() &&
+ (islotOut = psstrmIn->ChunkInNext(islotIn)) == -1)
+ {
+ ++islotIn;
+ }
+ if (islotIn == psstrmIn->ReadPos())
+ islotOut = psstrmOut->WritePos();
+ }
+
+ Assert(islotOut != -2); // because the chunk size must be <= than the max-chunk,
+ // so we should never hit the end of the output stream
+
+ // Now we've found a chunk boundary.
+
+// if (fFirst)
+// Unattach(psstrmIn, islotIn, psstrmOut, islotOut, islotChanged);
+// else
+// Unattach(psstrmIn, islotIn, psstrmOut, islotOut, -1);
+
+ psstrmIn->UnwindInput(islotIn, PreBidiPass());
+ psstrmOut->UnwindOutput(islotOut, IsPosPass());
+
+ if (psstrmIn->ReadPos() < psstrmIn->SlotsSkippedToResync())
+ {
+ ptman->Pass(m_ipass - 1)->UndoResyncSkip();
+ psstrmIn->ClearSlotsSkippedToResync();
+ }
+ if (psstrmOut->WritePos() < psstrmOut->SlotsSkippedToResync())
+ {
+ Assert(psstrmOut->SlotsSkippedToResync() == m_pzpst->m_cslotSkipToResync);
+ UndoResyncSkip();
+ psstrmOut->ClearSlotsSkippedToResync();
+ }
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->UnwindLogInfo(islotIn, islotOut);
+
+ return islotOut;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For a GrBidiPass, just unwind to the beginning of the reordered chunk.
+----------------------------------------------------------------------------------------------*/
+int GrBidiPass::Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ bool fFirst)
+{
+ int islotIn;
+ int islotOut;
+
+ if (islotChanged == 0)
+ {
+ islotIn = 0;
+ islotOut = 0;
+ }
+ else {
+ islotIn = min(islotChanged, psstrmIn->ReadPos());
+ islotIn = max(islotIn - 1, 0);
+ while (islotIn > 0 && !StrongDir(psstrmIn->SlotAt(islotIn)->Directionality()))
+ {
+ // Slightly redundant with ZapCalculatedDirLevels, but possibly needed for slots
+ // that have been modified by the substitution passes.
+ psstrmIn->SlotAt(islotIn)->ZapDirLevel();
+ islotIn--;
+ }
+ Assert(islotIn == 0 || psstrmIn->SlotAt(islotIn)->DirHasBeenProcessed());
+ islotOut = 0;
+ while (islotIn > 0 && (islotOut = psstrmIn->ChunkInNext(islotIn)) == -1)
+ --islotIn;
+ }
+
+ if (islotOut == -1 || islotOut == -2)
+ islotOut = 0;
+
+ // Now we've found a chunk boundary; islotI and islotO are the positions in the
+ // input and output streams, respectively.
+
+ psstrmIn->UnwindInput(islotIn, false);
+ psstrmOut->UnwindOutput(islotOut, false);
+
+ if (psstrmOut->WritePos() < m_pzpst->m_cslotSkipToResync)
+ {
+ Assert(false); // shouldn't be any of this mess for the Bidi pass
+ m_pzpst->m_fDidResyncSkip = false;
+ }
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->UnwindLogInfo(islotIn, islotOut);
+
+ return islotOut;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reinitialize part of the transduction logging information when we unwind the pass.
+----------------------------------------------------------------------------------------------*/
+void PassState::UnwindLogInfo(int islotIn, int islotOut)
+{
+ while (m_crulrec > 0 && m_rgrulrec[m_crulrec-1].m_islot >= islotIn)
+ {
+ m_crulrec--;
+ m_rgrulrec[m_crulrec].m_islot = 0;
+ m_rgrulrec[m_crulrec].m_irul = 0;
+ m_rgrulrec[m_crulrec].m_fFired = false;
+ }
+
+ for (int islot = islotOut; islot < 128; islot++)
+ {
+ m_rgcslotDeletions[islot] = 0;
+ m_rgfInsertion[islot] = false;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Undo the side effects of attachments, ie, fix up the attachment trees as we unwind.
+
+ @param islotLB the index of the line-break that was just inserted, or -1 if this is
+ not the first pass to include line-breaks; we want to skip this slot
+ in the processing in this method
+
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+//:Ignore
+void GrPosPass::Unattach(GrSlotStream * psstrmIn, int islotIn,
+ GrSlotStream * psstrmOut, int islotOut, int islotLB)
+{
+ // Because this is a positioning pass, there is a one-to-one correspondence between
+ // the slots in the input and the slots in the output. Thus we can make simplifying
+ // assumptions. Specifically, the chunk sizes are equal, except for the possiblity
+ // of a LB slot that we just inserted in the input stream.
+#if 0
+
+#ifdef _DEBUG
+ int islotDiff = (psstrmIn->ReadPos() - islotIn) - (psstrmOut->WritePos() - islotOut);
+ if (islotLB == -1)
+ Assert(islotDiff == 0);
+ else
+ Assert(islotDiff == 1);
+#endif // _DEBUG
+
+ int islotInLp = psstrmIn->ReadPos();
+ int islotOutLp = psstrmOut->WritePos();
+ for ( ; islotInLp-- > islotIn && islotOutLp-- > islotOut; )
+ {
+ if (islotLB == islotInLp)
+ {
+ GrSlotState * pslotTmp = psstrmIn->SlotAt(islotInLp);
+ islotInLp--;
+ }
+
+ GrSlotState * pslotIn = psstrmIn->SlotAt(islotInLp);
+ GrSlotState * pslotOut = psstrmOut->SlotAt(islotOutLp);
+
+ if (pslotIn != pslotOut)
+ {
+ GrSlotState * pslotInRoot = pslotIn->AttachRoot();
+ GrSlotState * pslotOutRoot = pslotOut->AttachRoot();
+
+ if (pslotOutRoot)
+ pslotOutRoot->RemoveLeaf(pslotOut);
+ if (pslotInRoot)
+ pslotInRoot->AddLeaf(pslotIn);
+ }
+ }
+#endif // 0
+}
+//:End Ignore
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given rule's constraint failed, for the purpose of logging
+ the transduction process.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordRuleFailed(int islot, int irul)
+{
+ m_pzpst->RecordRule(islot, irul, false);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given rule fired, for the purpose of logging
+ the transduction process.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordRuleFired(int islot, int irul)
+{
+ m_pzpst->RecordRule(islot, irul, true);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that we forcibly advanced due to the max-rule-loop.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordHitMaxRuleLoop(int islot)
+{
+ m_pzpst->RecordRule(islot, PassState::kHitMaxRuleLoop);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that we forcibly advanced due to the max-backup.
+
+ In theory it should be possible to call this, but in reality, it is pretty hard to be
+ able to say that there is a rule that would have fired except it was prevent by
+ MaxBackup. So currently this method is not called.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordHitMaxBackup(int islot)
+{
+ m_pzpst->RecordRule(islot, PassState::kHitMaxBackup);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record some rule-related activity on a slot.
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordRule(int islot, int irul, bool fFired)
+{
+ if (m_crulrec >= 128)
+ return;
+
+ m_rgrulrec[m_crulrec].m_irul = irul;
+ m_rgrulrec[m_crulrec].m_islot = islot;
+ m_rgrulrec[m_crulrec].m_fFired = true;
+ m_rgrulrec[m_crulrec].m_fFired = fFired;
+ m_crulrec++;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that a slot was deleted before the given slot (in the output).
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordDeletionBefore(int islot)
+{
+ if (islot >= 128)
+ return;
+
+ (m_rgcslotDeletions[islot])++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given slot was inserted into the output.
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordInsertionAt(int islot)
+{
+ if (islot >= 128)
+ return;
+
+ m_rgfInsertion[islot] = true;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.h
new file mode 100644
index 00000000000..446bfa1fb83
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPass.h
@@ -0,0 +1,747 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrPass.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ The GrPass class and subclasses.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef PASS_INCLUDED
+#define PASS_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ This class stores the state of processing in a single pass.
+
+ Hungarian: zpst
+----------------------------------------------------------------------------------------------*/
+
+class PassState {
+ friend class GrPass;
+ friend class GrGlyphGenPass;
+ friend class GrLineBreakPass;
+ friend class GrSubPass;
+ friend class GrBidiPass;
+ friend class GrPosPass;
+ friend class FontMemoryUsage;
+
+public:
+ PassState()
+ {
+ }
+
+ void InitForNewSegment(int ipass, int nMaxChunk);
+ void InitializeLogInfo();
+
+ int MaxChunk()
+ {
+ return m_nMaxChunk;
+ }
+
+ void SetResyncSkip(int c)
+ {
+ m_cslotSkipToResync = c;
+ m_fDidResyncSkip = false;
+ }
+ int NeededToResync()
+ {
+ if (m_fDidResyncSkip)
+ return 0;
+ return m_cslotSkipToResync;
+ }
+ bool DidResyncSkip()
+ {
+ return m_fDidResyncSkip;
+ }
+ bool CanResyncSkip(GrSlotStream * psstrmOutput)
+ {
+ if (m_fDidResyncSkip)
+ return true; // already did it
+ // Are we in the position to do the resync-skip?
+ return m_cslotSkipToResync <= psstrmOutput->WritePos();
+ }
+ int DoResyncSkip(GrSlotStream * psstrmOutput);
+ void UndoResyncSkip()
+ {
+ m_fDidResyncSkip = false;
+ }
+
+ void UnwindLogInfo(int islotIn, int islotOut);
+ void RecordRule(int islot, int irul, bool fFired = false);
+ void RecordDeletionBefore(int islot);
+ void RecordInsertionAt(int islot);
+#ifdef TRACING
+ void LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn);
+ void LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut);
+#endif // TRACING
+
+protected:
+ int m_ipass;
+
+ // Used to avoid infinite loops. If m_nRulesSinceAdvance > m_nMaxRuleLoop,
+ // and we have not passed the stream's ReadPosMax, forcibly advance.
+ int m_nRulesSinceAdvance;
+
+ // Maximum length of chunk, used when unwinding the streams during backtracking. This
+ // must be initialized to m_nMaxRuleContext, but that is not always adequate, because
+ // when there is reprocessing going on the chunks may be longer.
+ int m_nMaxChunk;
+
+ // Indicates how much of the pass's initial output should be automatically
+ // skipped over in order to resync with a chunk boundary. This handles the situation
+ // where we are reprocessing a little of the previous segment in order to handle
+ // cross-line-boundary contextuals. The goal is to skip over the output until we hit
+ // what we know (from processing the previous segment) is a chunk boundary.
+ //
+ // In most cases (and always when this is the first segment of the
+ // writing system) this number is 0.
+ int m_cslotSkipToResync;
+ bool m_fDidResyncSkip;
+
+ enum {
+ kHitMaxBackup = -1,
+ kHitMaxRuleLoop = -2
+ };
+
+ // For logging transduction process: record of one rule matched or fired
+ struct RuleRecord
+ {
+ int m_irul; // rule index, or kHitMaxBackup or kHitMaxRuleLoop
+ int m_islot; // slot index of input stream
+ bool m_fFired;
+ };
+ RuleRecord m_rgrulrec[128];
+ int m_crulrec;
+
+ int m_rgcslotDeletions[128]; // number of deletions before slot i in output
+ bool m_rgfInsertion[128]; // true if slot i in output was inserted
+};
+
+/*----------------------------------------------------------------------------------------------
+ This class handles finding and applying rules from the pass and storing
+ the results in the appropriate stream.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrPass {
+ friend class FontMemoryUsage;
+
+protected:
+ // Action command codes; these MUST match the corresponding definitions in the compiler:
+ enum ActionCommand {
+ kopNop = 0,
+
+ kopPushByte, kopPushByteU, kopPushShort, kopPushShortU, kopPushLong,
+
+ kopAdd, kopSub, kopMul, kopDiv,
+ kopMin, kopMax,
+ kopNeg,
+ kopTrunc8, kopTrunc16,
+
+ kopCond,
+
+ kopAnd, kopOr, kopNot,
+ kopEqual, kopNotEq,
+ kopLess, kopGtr, kopLessEq, kopGtrEq,
+
+ kopNext, kopNextN, kopCopyNext,
+ kopPutGlyph8bitObs, kopPutSubs8bitObs, kopPutCopy,
+ kopInsert, kopDelete,
+ kopAssoc,
+ kopCntxtItem,
+
+ kopAttrSet, kopAttrAdd, kopAttrSub,
+ kopAttrSetSlot,
+ kopIAttrSetSlot,
+ kopPushSlotAttr, kopPushGlyphAttrObs,kopPushGlyphMetric, kopPushFeat,
+ kopPushAttToGAttrObs, kopPushAttToGlyphMetric,
+ kopPushISlotAttr,
+
+ kopPushIGlyphAttr, // not implemented
+
+ kopPopRet, kopRetZero, kopRetTrue,
+ kopIAttrSet, kopIAttrAdd, kopIAttrSub,
+ kopPushProcState, kopPushVersion,
+ kopPutSubs, kopPutSubs2, kopPutSubs3,
+ kopPutGlyph, kopPushGlyphAttr, kopPushAttToGlyphAttr
+
+ };
+
+ enum StackMachineFlag {
+ ksmfDone = 0,
+ ksmfContinue,
+ ksmfUnderflow,
+ ksmfStackNotEmptied
+ };
+
+public:
+ // Constructor:
+ GrPass(int i);
+ // Destructor:
+ virtual ~GrPass();
+
+ int PassNumber() { return m_ipass; }
+
+ bool ReadFromFont(GrIStream & grstrm, int fxdSilfVersion, int fxdRuleVersion, int nOffset);
+ void InitializeWithNoRules();
+
+ virtual void SetTopDirLevel(int n)
+ { // only GrBidiPass does anything interesting
+ }
+
+ void SetPassState(PassState * pzpst)
+ {
+ m_pzpst = pzpst;
+ }
+
+ virtual void ExtendOutput(GrTableManager *,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput, int nslotToGet,
+ TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak);
+
+ int ExtendGlyphIDOutput(GrTableManager *, GrCharStream *,
+ GrSlotStream *, int ichSegLim, int cchwPostXlbContext,
+ LineBrk lb, int cslotToGet, bool fNeedFinalBreak,
+ TrWsHandling twsh, int * pislotFinalBreak);
+
+ int ExtendFinalOutput(GrTableManager *, GrSlotStream * psstrmInput,
+ GrSlotStream * psstrmOutput,
+ float xsSpaceAllotted, bool fWidthIsCharCount, bool fInfiniteWidth,
+ bool fHaveLineBreak, bool fMustBacktrack,
+ LineBrk lbMax, TrWsHandling twsh,
+ int * pislotLB, float * pxsWidth);
+
+ int RemoveTrailingWhiteSpace(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh, int * pislotFinalBreak);
+
+ virtual int Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream *psstrmInput, GrSlotStream * psstrmOutput,
+ bool fFirst);
+
+ int MaxBackup()
+ {
+ return m_nMaxBackup;
+ }
+
+ bool DidResyncSkip()
+ {
+ return m_pzpst->DidResyncSkip();
+ }
+ int DoResyncSkip(GrSlotStream * psstrmOutput)
+ {
+ return m_pzpst->DoResyncSkip(psstrmOutput);
+ }
+
+ void UndoResyncSkip()
+ {
+ m_pzpst->UndoResyncSkip();
+ }
+ void SetResyncSkip(int n)
+ {
+ m_pzpst->SetResyncSkip(n);
+ }
+
+ virtual void DoCleanUpSegMin(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut)
+ {
+ }
+
+ virtual void DoCleanUpSegLim(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh)
+ {
+ }
+
+ virtual bool IsPosPass()
+ {
+ return false;
+ }
+
+ virtual bool PreBidiPass() = 0;
+
+ bool RunConstraint(GrTableManager *, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotPreModContext, int cslotMatched);
+
+ int RunCommandCode(GrTableManager * ptman,
+ byte * pbStart, bool fConstraints,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot);
+
+protected:
+ int RunOneCommand(GrTableManager * ptman, bool fConstraints,
+ ActionCommand op, byte ** ppbArg, bool * pfMustGet, bool * pfInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot,
+ std::vector<int> & vnStack, StackMachineFlag * psmf);
+ void DoStackArithmetic2Args(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf);
+ void DoStackArithmetic1Arg(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf);
+ void DoConditional(std::vector<int> & vnStack, StackMachineFlag * psmf);
+ StackMachineFlag CheckStack(std::vector<int> & vnStack, int cn);
+ void DoNext(GrTableManager * ptman,
+ int cslot, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutGlyph(GrTableManager * ptman, bool fInserting, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutCopy(GrTableManager * ptman, bool fInserting, int cslotCopyFrom,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutSubs(GrTableManager * ptman, bool fInserting,
+ int cslotSel, int nSelClass, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutSubs2(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutSubs3(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int cslotSel3, int nSelClass3,
+ int nReplacementClass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPutSubsInit(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, bool fInserting,
+ GrSlotState ** ppslotNextPut, bool * pfAtSegMin, bool * pfAtSegLim);
+ void DoPutSubsAux(GrTableManager * ptman, bool fInserting, gid16 nGlyphReplacement,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, GrSlotState * pslotNextInput,
+ bool fAtSegMin, bool fAtSegLim);
+ void SetNeutralAssocs(GrSlotState * pslotNew, GrSlotStream * psstrmIn);
+ void DoDelete(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoAssoc(int cnAssocs, std::vector<int> & vnAssocs, bool fInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoSetAttr(GrTableManager * ptman,
+ ActionCommand op, bool fInserrting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushSlotAttr(GrTableManager * ptman,
+ int nSlotRef, bool fInserting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushAttToGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushAttToGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushFeatValue(GrTableManager * ptman, int islot, bool fInsering,
+ int nFeat, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ void DoPushProcState(GrTableManager * ptman, int nPState, std::vector<int> & vnStack);
+protected:
+ void DoPushGlyphMetricAux(GrTableManager * ptman,
+ GrSlotState * pslot, int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn);
+public:
+ int SortKeyForRule(int ruln)
+ {
+ Assert(ruln < m_crul);
+ return m_prgchwRuleSortKeys[ruln];
+ }
+ int PreModContextForRule(int ruln)
+ {
+ Assert(ruln < m_crul);
+ return m_prgcritRulePreModContext[ruln];
+ }
+
+ int MaxRulePreContext()
+ {
+ if (m_pfsm)
+ return m_pfsm->MaxRulePreContext();
+ else
+ return 0;
+ }
+
+ void RecordRuleFailed(int islot, int irul);
+ void RecordRuleFired(int islot, int irul);
+ void RecordHitMaxRuleLoop(int islot);
+ void RecordHitMaxBackup(int islot);
+#ifdef TRACING
+ void LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn);
+ void LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut);
+#endif // TRACING
+
+protected:
+ int CheckRuleValidity(int ruln);
+
+ virtual void RunRule(GrTableManager *, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput) = 0;
+
+ void CheckInputProgress(GrSlotStream* input, GrSlotStream* psstrmOutput,
+ int islotOrigInput);
+
+ void MapChunks(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int islotChunkI, int islotChunkO, int cslotReprocessed);
+
+ virtual void Unattach(GrSlotStream * psstrmIn, int islotIn, // GrPosPass overrides
+ GrSlotStream * psstrmOut, int islotOut, int islotLB)
+ {
+ }
+
+ friend class EngineState; // let it call the method below
+ virtual int MaxRuleContext() // GrBidiPass overrides
+ {
+ return m_nMaxRuleContext;
+ }
+
+protected:
+ // Instance variables:
+
+ int m_ipass; // index of pass
+
+ int m_fxdVersion;
+
+ // number of items required from previous pass; don't access directly, use the getter
+ // method, because GrBidiPass overrides to always use 1.
+ int m_nMaxRuleContext;
+
+ GrFSM * m_pfsm; // Finite State Machine to give next rule
+
+ int m_nMaxRuleLoop; // maximum number of rules to process before forcibly
+ // advancing input position
+
+ int m_nMaxBackup;
+
+ int m_crul; // number of rules
+
+ // rule sort keys, indicating precedence of rules; m_crul of these
+ data16 * m_prgchwRuleSortKeys;
+
+ // for each rule, the number of items in the context before the first modified item
+ // that the constraints need to be tested on
+ byte * m_prgcritRulePreModContext;
+
+ // offset for pass-level constraints; just 1 of these
+ data16 m_cbPassConstraint;
+ // offsets for constraint and action code; m_crul+1 of each of these (the last
+ // indicates the total byte count)
+ data16 * m_prgibConstraintStart;
+ data16 * m_prgibActionStart;
+
+ // blocks of constraint and action code
+ byte * m_prgbPConstraintBlock; // pass-level constraints
+ byte * m_prgbConstraintBlock; // rule constraints
+ byte * m_prgbActionBlock;
+
+ int m_cbConstraints; // needed for memory instrumentation only
+ int m_cbActions; // needed for memory instrumentation only
+
+ bool m_fHasDebugStrings;
+ data16 * m_prgibConstraintDebug; // m_crul+1 of these
+ data16 * m_prgibRuleDebug; // m_crul+1 of these
+
+ bool m_fCheckRules;
+ bool * m_prgfRuleOkay;
+
+ std::vector<int> m_vnStack; // for stack machine processing (more efficient than creating the
+ // vector each time)
+
+ // state of process for this pass
+ PassState * m_pzpst;
+
+public:
+#ifdef OLD_TEST_STUFF
+ // For test procedures:
+ StrAnsi m_staBehavior;
+
+ virtual void SetUpTestData();
+
+ // overridden on appropriate subclasses:
+ virtual void SetUpReverseNumbersTest() { Assert(false); }
+ virtual void SetUpBidiNumbersTest() { Assert(false); }
+
+ virtual void SetUpCrossLineContextTest() { Assert(false); }
+ virtual void SetUpReprocessTest() { Assert(false); }
+ virtual void SetUpLineEdgeContextTest(int ipass) { Assert(false); }
+ virtual void SetUpBidiAlgorithmTest() { Assert(false); }
+ virtual void SetUpPseudoGlyphsTest() { Assert(false); }
+ virtual void SetUpSimpleFSMTest() { Assert(false); }
+ virtual void SetUpRuleActionTest() { Assert(false); }
+ virtual void SetUpRuleAction2Test() { Assert(false); }
+ virtual void SetUpAssocTest() { Assert(false); }
+ virtual void SetUpAssoc2Test() { Assert(false); }
+ virtual void SetUpDefaultAssocTest() { Assert(false); }
+ virtual void SetUpFeatureTest() { Assert(false); }
+ virtual void SetUpLigatureTest() { Assert(false); }
+ virtual void SetUpLigature2Test() { Assert(false); }
+#endif // OLD_TEST_STUFF
+
+}; // end of class GrPass
+
+
+/*----------------------------------------------------------------------------------------------
+ The initial pass that generates glyph IDs from Unicode input.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrGlyphGenPass : public GrPass
+{
+ friend class FontMemoryUsage;
+
+public:
+ GrGlyphGenPass(int ipass) : GrPass(ipass)
+ {
+ }
+
+ virtual bool PreBidiPass()
+ {
+ return true;
+ }
+
+protected:
+ // Irrelevant when generating glyphs.
+ virtual void RunRule(GrTableManager *, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+ {
+ Assert(false);
+ }
+
+}; // end of class GrGlyphGenPass
+
+
+/*----------------------------------------------------------------------------------------------
+ A pass containing rules that set the break weight values.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrLineBreakPass : public GrPass
+{
+ friend class FontMemoryUsage;
+
+public:
+ GrLineBreakPass(int ipass) : GrPass(ipass)
+ {
+ }
+
+ virtual bool PreBidiPass()
+ {
+ return true;
+ }
+
+protected:
+ virtual void RunRule(GrTableManager *, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput);
+
+public:
+#ifdef OLD_TEST_STUFF
+ // For test procedures:
+ bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+ bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpCrossLineContextTest();
+ bool RunCrossLineContextTest(GrTableManager*, GrSlotStream* psstrmIn,
+ GrSlotStream* psstrmOut);
+
+ virtual void SetUpReprocessTest();
+ bool RunReprocessTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut);
+
+ virtual void SetUpAssocTest();
+ virtual void SetUpLigatureTest();
+#endif // OLD_TEST_STUFF
+
+}; // end of class GrLineBreakPass
+
+
+/*----------------------------------------------------------------------------------------------
+ A pass containing substitution rules.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrSubPass : public GrPass
+{
+ friend class FontMemoryUsage;
+
+public:
+ GrSubPass(int ipass) : GrPass(ipass)
+ {
+ }
+
+ virtual bool PreBidiPass()
+ {
+ return true;
+ }
+
+protected:
+ virtual void RunRule(GrTableManager *, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput);
+
+ virtual void DoCleanUpSegMin(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut);
+ virtual void DoCleanUpSegLim(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh);
+
+public:
+#ifdef OLD_TEST_STUFF
+ // For test procedures:
+ bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+ bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpReverseNumbersTest();
+ bool RunReverseNumbersTest(GrTableManager*, GrSlotStream* psstrmIn,
+ GrSlotStream* psstrmOut);
+
+ virtual void SetUpBidiNumbersTest();
+ bool RunBidiNumbersTest(GrTableManager*, GrSlotStream* psstrmIn,
+ GrSlotStream* psstrmOut);
+
+ virtual void SetUpCrossLineContextTest();
+ bool RunCrossLineContextTest(GrTableManager*, GrSlotStream* psstrmIn,
+ GrSlotStream* psstrmOut);
+
+ virtual void SetUpReprocessTest();
+ bool RunReprocessTest(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpLineEdgeContextTest(int ipass);
+ bool RunLineEdgeContextTest(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpBidiAlgorithmTest();
+ bool RunBidiAlgorithmTest(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpPseudoGlyphsTest();
+ bool RunPseudoGlyphsTest(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+
+ virtual void SetUpSimpleFSMTest();
+ bool RunSimpleFSMTest(GrTableManager *, int ruln, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+ virtual void SetUpRuleActionTest();
+ virtual void SetUpRuleAction2Test();
+ virtual void SetUpAssocTest();
+ virtual void SetUpAssoc2Test();
+ virtual void SetUpDefaultAssocTest();
+ virtual void SetUpFeatureTest();
+ virtual void SetUpLigatureTest();
+ virtual void SetUpLigature2Test();
+#endif // OLD_TEST_STUFF
+
+}; // end of class GrSubPass
+
+
+/*----------------------------------------------------------------------------------------------
+ This class is the one the knows how to handle bidi reordering, including backtracking.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrBidiPass : public GrSubPass
+{
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor:
+ GrBidiPass(int ipass)
+ : GrSubPass(ipass),
+ m_nTopDirection(0)
+ {
+ }
+
+ virtual void SetTopDirLevel(int n)
+ {
+ m_nTopDirection = n;
+ }
+
+ virtual bool PreBidiPass()
+ {
+ return false;
+ }
+
+ virtual void ExtendOutput(GrTableManager *,
+ GrSlotStream * psstrmI, GrSlotStream * psstrmO, int nslotToGet,
+ TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak);
+
+ virtual int Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ bool fFirst);
+protected:
+ virtual int MaxRuleContext()
+ {
+ return 1;
+ }
+
+private:
+ //void OldReverse(int nCurrDirection,
+ // GrSlotStream * psstrmI, int islotI1, int islotI2,
+ // GrSlotStream * psstrmO, int islotO1, int islotO2);
+
+ int Reverse(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops);
+
+protected:
+ // Instance variables:
+ int m_nTopDirection; // 0 for LTR, 1 for RTL -- CURRENTLY NOT USED; need to
+ // initialize it when we set the writing system direction
+
+#ifdef OLD_TEST_STUFF
+public:
+ // For test procedures:
+ ////virtual void SetUpTestData();
+ virtual void SetUpBidiNumbersTest();
+ virtual void SetUpBidiAlgorithmTest();
+#endif // OLD_TEST_STUFF
+
+}; // end of class GrBidiPass
+
+
+/*----------------------------------------------------------------------------------------------
+ A pass containing positioning rules.
+
+ Hungarian: pass
+----------------------------------------------------------------------------------------------*/
+class GrPosPass : public GrPass
+{
+ friend class FontMemoryUsage;
+
+public:
+ GrPosPass(int ipass) : GrPass(ipass)
+ {
+ }
+
+ virtual bool IsPosPass()
+ {
+ return true;
+ }
+
+ virtual bool PreBidiPass()
+ {
+ return false;
+ }
+
+protected:
+ virtual void RunRule(GrTableManager *, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput);
+
+ virtual void Unattach(GrSlotStream * psstrmIn, int islotIn,
+ GrSlotStream * psstrmOut, int islotOut, int islotLB);
+
+public:
+#ifdef OLD_TEST_STUFF
+ // For test procedures:
+ bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+ bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn,
+ GrSlotStream * psstrmOut);
+#endif // OLD_TEST_STUFF
+
+}; // end of class GrPosPass
+
+} // namespace gr
+
+
+#endif // PASS_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPassActionCode.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPassActionCode.cpp
new file mode 100644
index 00000000000..38868e52477
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPassActionCode.cpp
@@ -0,0 +1,1490 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrPassActionCode.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ A continution of the GrPass file, including functions to run the action commands.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local type definitions
+//:>********************************************************************************************
+
+typedef signed char Int8; // signed value
+typedef unsigned char Uint8; // unsigned value
+
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ The main function to run a block of action or constraint code and return a result.
+
+ @param ptman - table manager, for generating new slots; NULL when
+ running constraints
+ @param pbStart - address of the first command
+ @param fConstraints - true if we are running constraint tests;
+ false if we are running rule actions
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream; when running constraints, used to access items
+ in the precontext
+ @param islot - slot being processed relative to the start of the rule;
+ used only for constraints; must be 0 for rule actions
+----------------------------------------------------------------------------------------------*/
+int GrPass::RunCommandCode(GrTableManager * ptman,
+ byte * pbStart, bool fConstraints,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot)
+{
+ byte * pbNext = pbStart;
+
+// std::vector<int> vnStack;
+// vnStack.EnsureSpace(128); // make it nice and big
+ m_vnStack.clear();
+
+ gAssert(fConstraints || islot == 0);
+
+ // There are two states: fMustGet = true means we need to get a slot to work on from
+ // the input; fMustGet = false means we have a slot and we need to do a Next before
+ // we can get the next one.
+ bool fMustGet = !fConstraints;
+
+ bool fInserting = false; // set to true by an Insert command
+
+ int nRet = 0;
+
+ while (true)
+ {
+ ActionCommand op = ActionCommand(*pbNext++);
+ StackMachineFlag smf;
+ nRet = RunOneCommand(ptman, fConstraints, op,
+ &pbNext, &fMustGet, &fInserting,
+ psstrmIn, psstrmOut, islot,
+ m_vnStack, &smf);
+
+ if (smf == ksmfDone)
+ return nRet;
+
+ if (smf == ksmfUnderflow)
+ {
+ Warn("Underflow in Graphite stack machine");
+ gAssert(false);
+ FontException fexptn;
+ fexptn.version = -1;
+ fexptn.subVersion = -1;
+ fexptn.errorCode = kferrUnknown;
+ throw fexptn; // disastrous error in rendering; fall back to dumb rendering
+ }
+ }
+ return nRet; // not needed, but to avoid compiler warning
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform a single command. Specifically, read the arguments from the byte buffer and the
+ run the appropriate functions.
+
+ @param ptman - table manager, for generating new slots; or NULL
+ @param fConstraints - true if we are running constraints; false if we are running
+ rule actions
+ @param op - command operator
+ @param ppbArg - pointer to first argument
+ @param pfMustGet - state: getting input or processing it; when running constraints,
+ always false
+ @param pfInserting - true if current item is to be inserted, or was inserted
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+ @param islot - the slot being processed relative to the beginning of the rule;
+ only relevant for constraint testing, must be 0 for rule actions
+ @param vnStack - the stack of values being manipulated
+ @param psmf - error code, done flag, or continue flag
+----------------------------------------------------------------------------------------------*/
+int GrPass::RunOneCommand(GrTableManager * ptman, bool fConstraints,
+ ActionCommand op, byte ** ppbArg, bool * pfMustGet, bool * pfInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot,
+ std::vector<int> & vnStack, StackMachineFlag * psmf)
+{
+ *psmf = ksmfContinue;
+
+ // General purpose variables:
+ int arg1, arg2, arg3, arg4;
+ int nSlotRef;
+ int nInputClass;
+ int nOutputClass;
+ int c;
+ int islotArg;
+ int nIndex;
+ int nGlyphAttr;
+ int nAttLevel;
+ int nFeat;
+ int nPState;
+ SlotAttrName slat;
+
+ int i;
+ std::vector<int> vnTmp;
+
+ byte * pbNext = *ppbArg;
+
+ int nRet = 0;
+
+ switch (op)
+ {
+ case kopNop:
+ break;
+
+ case kopPushByte:
+ arg1 = Int8(*pbNext++);
+ vnStack.push_back(arg1);
+ break;
+ case kopPushByteU:
+ arg1 = Uint8(*pbNext++);
+ vnStack.push_back(arg1);
+ break;
+ case kopPushShort:
+ arg1 = Int8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 8) + arg2);
+ break;
+ case kopPushShortU:
+ arg1 = Uint8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 8) + arg2);
+ break;
+ case kopPushLong:
+ arg1 = Int8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ arg3 = Uint8(*pbNext++);
+ arg4 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 24) + (arg2 << 16) + (arg3 << 8) + arg4);
+ break;
+
+ case kopNeg:
+ case kopTrunc8: case kopTrunc16:
+ case kopNot:
+ DoStackArithmetic1Arg(op, vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopAdd: case kopSub:
+ case kopMul: case kopDiv:
+ case kopMin: case kopMax:
+ case kopAnd: case kopOr:
+ case kopEqual: case kopNotEq:
+ case kopLess: case kopGtr:
+ case kopLessEq: case kopGtrEq:
+ DoStackArithmetic2Args(op, vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopCond:
+ DoConditional(vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopNext:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoNext(ptman, 1, psstrmIn, psstrmOut);
+ *pfMustGet = true;
+ *pfInserting = false;
+ }
+ break;
+ case kopNextN:
+ c = Int8(*pbNext++);
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(false); // for now we don't allow anything other than moving one slot
+ gAssert(!*pfMustGet); // forward at a time
+ DoNext(ptman, c, psstrmIn, psstrmOut);
+ *pfMustGet = true;
+ }
+ break;
+ case kopPutGlyph8bitObs:
+ case kopPutGlyph:
+ if (op == kopPutGlyph8bitObs)
+ nOutputClass = Uint8(*pbNext++);
+ else
+ {
+ nOutputClass = (Uint8(*pbNext++) << 8);
+ nOutputClass += Uint8(*pbNext++);
+ }
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutGlyph(ptman, *pfInserting, nOutputClass, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopPutCopy:
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutCopy(ptman, *pfInserting, nSlotRef, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopPutSubs8bitObs:
+ case kopPutSubs:
+ nSlotRef = Int8(*pbNext++);
+ if (op == kopPutSubs8bitObs)
+ {
+ nInputClass = Uint8(*pbNext++);
+ nOutputClass = Uint8(*pbNext++);
+ }
+ else
+ {
+ nInputClass = (Uint8(*pbNext++) << 8);
+ nInputClass += Uint8(*pbNext++);
+ nOutputClass = (Uint8(*pbNext++) << 8);
+ nOutputClass += Uint8(*pbNext++);
+ }
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutSubs(ptman, *pfInserting, nSlotRef, nInputClass, nOutputClass,
+ psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopCopyNext:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ gAssert(!*pfInserting); // 0 means copy this slot
+ DoPutCopy(ptman, *pfInserting, 0, psstrmIn, psstrmOut);
+ DoNext(ptman, 1, psstrmIn, psstrmOut);
+ // *pfMustGet still = true
+ }
+ break;
+ case kopInsert:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ *pfInserting = true;
+ // *pfMustGet still = true
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->RecordInsertionAt(psstrmOut->WritePos());
+ }
+ break;
+ case kopDelete:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoDelete(ptman, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopAssoc:
+ c = Uint8(*pbNext++);
+ // std::vector<int> vnTmp;
+ for (i = 0; i < c; i++)
+ vnTmp.push_back(Int8(*pbNext++));
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoAssoc(c, vnTmp, *pfInserting, psstrmIn, psstrmOut);
+ }
+ break;
+ case kopCntxtItem:
+ islotArg = Int8(*pbNext++);
+ c = Uint8(*pbNext++);
+ if (fConstraints)
+ {
+ // Old approach:
+ // If this is NOT the relevant item, push TRUE, which causes the subsequent tests
+ // (which are eventually ORed with it) to become irrelevant.
+ //vnStack.Push((int)(islotArg != islot));
+
+ // If this is not the relevant item, skip the specified number of bytes.
+ if (islotArg != islot)
+ {
+ pbNext += c;
+ vnStack.push_back(1);
+ }
+ }
+ else
+ {
+ gAssert(false);
+ }
+ break;
+
+ case kopAttrSet:
+ case kopAttrAdd:
+ case kopAttrSub:
+ case kopAttrSetSlot:
+ slat = SlotAttrName(Uint8(*pbNext++)); // slot attribute ID
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoSetAttr(ptman, op, *pfInserting, slat, -1, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ }
+ break;
+ case kopIAttrSet:
+ case kopIAttrAdd:
+ case kopIAttrSub:
+ case kopIAttrSetSlot:
+ slat = SlotAttrName(Uint8(*pbNext++)); // slot attribute ID
+ nIndex = Uint8(*pbNext++); // index; eg, global ID for component
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoSetAttr(ptman, op, *pfInserting, slat, nIndex, vnStack,
+ psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ }
+ break;
+
+ case kopPushSlotAttr:
+ slat = SlotAttrName(Uint8(*pbNext++));
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ DoPushSlotAttr(ptman, nSlotRef, *pfInserting, slat, -1, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushISlotAttr:
+ slat = SlotAttrName(Uint8(*pbNext++));
+ nSlotRef = Int8(*pbNext++);
+ nIndex = Uint8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ DoPushSlotAttr(ptman, nSlotRef, *pfInserting, slat, nIndex, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopPushGlyphAttrObs:
+ case kopPushAttToGAttrObs:
+ case kopPushGlyphAttr:
+ case kopPushAttToGlyphAttr:
+ if (op == kopPushGlyphAttrObs || op == kopPushAttToGAttrObs)
+ nGlyphAttr = Uint8(*pbNext++);
+ else {
+ nGlyphAttr = (Uint8(*pbNext++) << 8);
+ nGlyphAttr += Uint8(*pbNext++);
+ }
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ if (op == kopPushAttToGlyphAttr || op == kopPushAttToGAttrObs)
+ DoPushAttToGlyphAttr(ptman, nSlotRef, *pfInserting, nGlyphAttr,
+ vnStack, psstrmIn, psstrmOut);
+ else
+ DoPushGlyphAttr(ptman, nSlotRef, *pfInserting, nGlyphAttr, vnStack,
+ psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushGlyphMetric:
+ case kopPushAttToGlyphMetric:
+ nGlyphAttr = Uint8(*pbNext++);
+ nSlotRef = Int8(*pbNext++);
+ nAttLevel = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ if (op == kopPushAttToGlyphMetric)
+ DoPushAttToGlyphMetric(ptman, nSlotRef, *pfInserting, nGlyphAttr, nAttLevel,
+ vnStack, psstrmIn, psstrmOut);
+ else
+ DoPushGlyphMetric(ptman, nSlotRef, *pfInserting, nGlyphAttr, nAttLevel,
+ vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushFeat:
+ nFeat = Uint8(*pbNext++);
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+// else
+// nSlotRef = 0;
+ DoPushFeatValue(ptman, nSlotRef, *pfInserting, nFeat, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushProcState:
+ nPState = Uint8(*pbNext++);
+ gAssert(fConstraints);
+ DoPushProcState(ptman, nPState, vnStack);
+ break;
+ case kopPushVersion:
+ vnStack.push_back(kRuleVersion);
+ break;
+ case kopPopRet:
+ if ((*psmf = CheckStack(vnStack, 1)) != ksmfContinue)
+ return 0;
+ nRet = vnStack.back();
+ vnStack.pop_back();
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+ case kopRetZero:
+ nRet = 0;
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+ case kopRetTrue:
+ nRet = 1;
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+
+ default:
+ gAssert(false);
+ }
+
+ *ppbArg = pbNext;
+ return nRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform arithmetic functions that take two arguments.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoStackArithmetic2Args(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 2)) != ksmfContinue)
+ return;
+
+ int nArg2 = vnStack.back();
+ vnStack.pop_back();
+ int nArg1 = vnStack.back();
+ vnStack.pop_back();
+
+ int nResult;
+
+ switch (op)
+ {
+ case kopAdd: nResult = nArg1 + nArg2; break;
+ case kopSub: nResult = nArg1 - nArg2; break;
+ case kopMul: nResult = nArg1 * nArg2; break;
+ case kopDiv: nResult = nArg1 / nArg2; break;
+ case kopMin: nResult = min(nArg1, nArg2); break;
+ case kopMax: nResult = max(nArg1, nArg2); break;
+ case kopAnd: nResult = (nArg1 != 0 && nArg2 != 0)? 1: 0; break;
+ case kopOr: nResult = (nArg1 != 0 || nArg2 != 0)? 1: 0; break;
+ case kopEqual: nResult = (nArg1 == nArg2)? 1: 0; break;
+ case kopNotEq: nResult = (nArg1 != nArg2)? 1: 0; break;
+ case kopLess: nResult = (nArg1 < nArg2)? 1: 0; break;
+ case kopLessEq: nResult = (nArg1 <= nArg2)? 1: 0; break;
+ case kopGtr: nResult = (nArg1 > nArg2)? 1: 0; break;
+ case kopGtrEq: nResult = (nArg1 >= nArg2)? 1: 0; break;
+ default:
+ Assert(false);
+ }
+
+ vnStack.push_back(nResult);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform arithmetic functions that take one argument.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoStackArithmetic1Arg(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 1)) != ksmfContinue)
+ return;
+
+ int nArg = vnStack.back();
+ vnStack.pop_back();
+ int nResult;
+
+ switch (op)
+ {
+ case kopNeg: nResult = nArg * -1; break;
+ case kopTrunc8: nResult = nArg & 0xFF; break;
+ case kopTrunc16: nResult = nArg & 0xFFFF; break;
+ case kopNot: nResult = (nArg == 0)? 1: 0; break;
+ default:
+ Assert(false);
+ }
+
+ vnStack.push_back(nResult);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform the conditional statement.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoConditional(std::vector<int> & vnStack, StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 3)) != ksmfContinue)
+ return;
+
+ int nArg3 = vnStack.back();
+ vnStack.pop_back();
+ int nArg2 = vnStack.back();
+ vnStack.pop_back();
+ int nArg1 = vnStack.back();
+ vnStack.pop_back();
+
+ if (nArg1 == 0)
+ vnStack.push_back(nArg3);
+ else
+ vnStack.push_back(nArg2);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check to make sure the stack has the appropriate number of items on it; if not,
+ return a stack error flag.
+----------------------------------------------------------------------------------------------*/
+GrPass::StackMachineFlag GrPass::CheckStack(std::vector<int> & vnStack, int cn)
+{
+ if (signed(vnStack.size()) < cn)
+ return ksmfUnderflow;
+ else
+ return ksmfContinue;
+}
+
+/*----------------------------------------------------------------------------------------------
+ We are finished processing a slot; go on to the next slot, or possibly go backwards.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoNext(GrTableManager * ptman,
+ int cslot, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert(cslot == 1); // for now anyway
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the next glyph to be the given class. There should only be one member of the class,
+ but if there happens to be more than one, just use the first member.
+ All the slot attributes remain unchanged from the current input slot; associations are
+ neutralized.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutGlyph(GrTableManager * ptman, bool fInserting, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary
+ // (you DON'T want them between the segment boundary and the LB slot!).
+ bool fSetSegMin = psstrmIn->AtSegMin() && !fInserting;
+ bool fSetSegLim = psstrmIn->AtSegLim();
+
+ // Slot to copy features and text properties from:
+ GrSlotState * pslotNextInput;
+ if (psstrmIn->AtEndOfContext())
+ {
+ gAssert(fInserting);
+ pslotNextInput = psstrmIn->RuleInputSlot(0, psstrmOut);
+ }
+ else
+ pslotNextInput = (fInserting)? psstrmIn->Peek(): psstrmIn->NextGet();
+
+ gid16 nGlyphReplacement = ptman->GetClassGlyphIDAt(nReplacementClass, 0);
+
+ GrSlotState * pslotNew;
+ if (fInserting)
+ {
+ pengst->NewSlot(nGlyphReplacement, pslotNextInput, m_ipass, &pslotNew);
+ // leave associations empty; eventually they will be "neutralized"
+ }
+ else
+ {
+ pengst->NewSlotCopy(pslotNextInput, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(nGlyphReplacement);
+ ptman->SetSlotAttrsFromGlyphAttrs(pslotNew);
+ }
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy a glyph from the given slot in the input to the output. All the associations and slot
+ attributes are copied from the specified slot as well. Consume a slot from the input
+ (which may or may not be the slot we're copying).
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotCopyFrom - slot to copy from
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutCopy(GrTableManager * ptman, bool fInserting, int cslotCopyFrom,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary.
+ bool fSetSegMin = psstrmIn->AtSegMin() && !fInserting;
+ bool fSetSegLim = psstrmIn->AtSegLim();
+
+ if (!fInserting)
+ {
+ gAssert(!psstrmIn->AtEndOfContext());
+ // Absorb next slot
+ psstrmIn->NextGet();
+ }
+
+ GrSlotState * pslotCopyFrom = psstrmIn->RuleInputSlot(cslotCopyFrom, psstrmOut);
+
+ GrSlotState * pslotNew;
+ pengst->NewSlotCopy(pslotCopyFrom, m_ipass, &pslotNew);
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class. All the associations and slot attributes remain unchanged from the
+ current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs(GrTableManager * ptman, bool fInserting,
+ int cslotSel, int nSelClass, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector = psstrmIn->RuleInputSlot(cslotSel, psstrmOut);
+
+ gid16 gidSelector = pslotInSelector->GlyphID();
+ int nSelIndex = ptman->GetIndexInGlyphClass(nSelClass, gidSelector);
+ gAssert(nSelIndex != -1);
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class based on 2 input classes. All the associations and slot attributes
+ remain unchanged from the current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs2(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector1 = psstrmIn->RuleInputSlot(cslotSel1, psstrmOut);
+ gid16 gidSelector1 = pslotInSelector1->GlyphID();
+ int nSelIndex1 = ptman->GetIndexInGlyphClass(nSelClass1, gidSelector1);
+ gAssert(nSelIndex1 != -1);
+ //size_t cClassLen1 = ptman->NumberOfGlyphsInClass(nSelClass1);
+
+ GrSlotState * pslotInSelector2 = psstrmIn->RuleInputSlot(cslotSel2, psstrmOut);
+ gid16 gidSelector2 = pslotInSelector2->GlyphID();
+ int nSelIndex2 = ptman->GetIndexInGlyphClass(nSelClass2, gidSelector2);
+ gAssert(nSelIndex2 != -1);
+ size_t cClassLen2 = ptman->NumberOfGlyphsInClass(nSelClass2);
+
+ int nSelIndex = (nSelIndex1 == -1 || nSelIndex2 == -1) ?
+ -1 :
+ (nSelIndex1 * static_cast<int>(cClassLen2)) + nSelIndex2;
+
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector1:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class based on 2 input classes. All the associations and slot attributes
+ remain unchanged from the current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs3(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int cslotSel3, int nSelClass3,
+ int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector1 = psstrmIn->RuleInputSlot(cslotSel1, psstrmOut);
+ gid16 gidSelector1 = pslotInSelector1->GlyphID();
+ int nSelIndex1 = ptman->GetIndexInGlyphClass(nSelClass1, gidSelector1);
+ gAssert(nSelIndex1 != -1);
+ //size_t cClassLen1 = ptman->NumberOfGlyphsInClass(nSelClass1);
+
+ GrSlotState * pslotInSelector2 = psstrmIn->RuleInputSlot(cslotSel2, psstrmOut);
+ gid16 gidSelector2 = pslotInSelector2->GlyphID();
+ int nSelIndex2 = ptman->GetIndexInGlyphClass(nSelClass2, gidSelector2);
+ gAssert(nSelIndex2 != -1);
+ size_t cClassLen2 = ptman->NumberOfGlyphsInClass(nSelClass2);
+
+// GrSlotState * pslotInSelector3 = psstrmIn->RuleInputSlot(cslotSel3, psstrmOut);
+// gid16 gidSelector3 = pslotInSelector3->GlyphID();
+ int nSelIndex3 = ptman->GetIndexInGlyphClass(nSelClass3, gidSelector2);
+ gAssert(nSelIndex3 != -1);
+ size_t cClassLen3 = ptman->NumberOfGlyphsInClass(nSelClass3);
+
+ int nSelIndex = (nSelIndex1 == -1 || nSelIndex2 == -1 || nSelIndex3 == -1) ?
+ -1 :
+ (((nSelIndex1 * static_cast<int>(cClassLen2)) + nSelIndex2) * static_cast<int>(cClassLen3)) + nSelIndex3;
+
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector1:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Initial common part of all the DoPutSubs... methods.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubsInit(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, bool fInserting,
+ GrSlotState ** ppslotNextInput, bool * pfAtSegMin, bool * pfAtSegLim)
+{
+ // Do this before reading from stream.
+ *pfAtSegMin = psstrmIn->AtSegMin();
+ *pfAtSegLim = psstrmIn->AtSegLim();
+
+ // Slot to copy features and text properties from:
+ if (psstrmIn->AtEndOfContext())
+ {
+ gAssert(fInserting);
+ *ppslotNextInput = psstrmIn->RuleInputSlot(0, psstrmOut);
+ }
+ else
+ *ppslotNextInput = (fInserting)? psstrmIn->Peek(): psstrmIn->NextGet();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Common part of all the DoPutSubs... methods.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubsAux(GrTableManager * ptman, bool fInserting, gid16 nGlyphReplacement,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, GrSlotState * pslotNextInput,
+ bool fAtSegMin, bool fAtSegLim)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary.
+ bool fSetSegMin = fAtSegMin && !fInserting;
+ bool fSetSegLim = fAtSegLim;
+
+ GrSlotState * pslotNew;
+ if (fInserting)
+ {
+ pengst->NewSlot(nGlyphReplacement, pslotNextInput, m_ipass, &pslotNew);
+ // leave associations empty; eventually they will be "neutralized"
+ }
+ else
+ {
+ pengst->NewSlotCopy(pslotNextInput, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(nGlyphReplacement);
+ ptman->SetSlotAttrsFromGlyphAttrs(pslotNew);
+ }
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ A slot has just been inserted. Clear all the associations; eventually (unless we go on
+ to set the associations explicitly) we will set its before-assoc to the slot after it
+ and its after-assoc to the slot before it. This makes it basically unselectable.
+ OBSOLETE - handled by slot initialization code
+----------------------------------------------------------------------------------------------*/
+void GrPass::SetNeutralAssocs(GrSlotState * pslotNew, GrSlotStream * psstrmIn)
+{
+ pslotNew->ClearAssocs();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Delete the next slot in the input.
+
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoDelete(GrTableManager * ptman, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ if (psstrmIn->AtSegMin())
+ psstrmOut->SetSegMinToWritePos();
+ if (psstrmIn->AtSegLim())
+ psstrmOut->SetSegLimToWritePos();
+
+ GrSlotState * pslot = psstrmIn->NextGet();
+ pslot->MarkDeleted();
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->RecordDeletionBefore(psstrmOut->WritePos());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the associations for the current slot. Any previous associations will be overwritten.
+
+ @param cn - number of associations
+ @param vnAssoc - list of associations
+ @param fInserting - whether current slot was inserted
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoAssoc(int cnAssocs, std::vector<int> & vnAssocs, bool fInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert((unsigned)cnAssocs == vnAssocs.size());
+
+ // Sort the list of associations. It's okay to use a simple bubble sort
+ // since we expect the list to be very short. Ideally we should remove duplicates
+ // too but I don't think duplicates actually hurt anything.
+ for (int i1 = 0; i1 < cnAssocs - 1; i1++)
+ {
+ for (int i2 = i1 + 1; i2 < cnAssocs; i2++)
+ {
+ if (vnAssocs[i2] < vnAssocs[i1])
+ {
+ int nTmp = vnAssocs[i2];
+ vnAssocs[i2] = vnAssocs[i1];
+ vnAssocs[i1] = nTmp;
+ }
+ }
+ }
+
+ std::vector<GrSlotState *> vpslotAssocs;
+ vpslotAssocs.resize(cnAssocs);
+ for (int i = 0; i < cnAssocs; i++)
+ vpslotAssocs[i] = psstrmIn->RuleInputSlot(vnAssocs[i], psstrmOut);
+
+ GrSlotState * pslot = psstrmOut->RuleOutputSlot();
+ pslot->Associate(vpslotAssocs);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set a slot attribute for the current slot; the value is on the stack.
+
+ @param op - command
+ @param fInserting - whether current slot was inserted
+ @param slat - slot attribute to set
+ @param slati - slot attribute index, or -1 for non-indexed attribute
+ @param vnStack - stack to read value from
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoSetAttr(GrTableManager * ptman, ActionCommand op, bool fInserting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ int nVal = vnStack.back();
+ vnStack.pop_back();
+
+ if (slat == kslatUserDefnV1)
+ slat = kslatUserDefn;
+
+ if (slati != -1 && slat != kslatCompRef && slat != kslatUserDefn)
+ {
+ // Invalid slot attribute index.
+ gAssert(false);
+ slati = -1;
+ }
+
+ if (slati == -1 && (slat == kslatCompRef || slat == kslatUserDefn))
+ {
+ // Missing slot attribute index.
+ gAssert(false);
+ slati = 0;
+ }
+
+ if (slat == kslatPosX || slat == kslatPosY)
+ {
+ // Doesn't make sense to set the pos attribute.
+ gAssert(false);
+ return;
+ }
+
+ GrSlotState * pslotIn = psstrmIn->RuleInputSlot(0, psstrmOut);
+
+ GrSlotState * pslotComp;
+
+ int nOldVal;
+
+ if (op == kopAttrAdd || op == kopAttrSub || op == kopIAttrAdd || op == kopIAttrSub)
+ {
+ // Incrementing or decrementing.
+
+ gAssert(!fInserting);
+
+ switch (slat)
+ {
+ case kslatAdvX: nOldVal = pslotIn->AdvanceX(ptman); break;
+ case kslatAdvY: nOldVal = pslotIn->AdvanceY(ptman); break;
+ case kslatShiftX: nOldVal = pslotIn->ShiftX(); break;
+ case kslatShiftY: nOldVal = pslotIn->ShiftY(); break;
+
+ case kslatAttAtX: nOldVal = pslotIn->AttachAtX(ptman, psstrmIn); break;
+ case kslatAttAtY: nOldVal = pslotIn->AttachAtY(); break;
+ case kslatAttAtXoff: nOldVal = pslotIn->AttachAtXOffset(); break;
+ case kslatAttAtYoff: nOldVal = pslotIn->AttachAtYOffset(); break;
+
+ case kslatAttWithX: nOldVal = pslotIn->AttachWithX(ptman, psstrmIn); break;
+ case kslatAttWithY: nOldVal = pslotIn->AttachWithY(); break;
+ case kslatAttWithXoff: nOldVal = pslotIn->AttachWithXOffset(); break;
+ case kslatAttWithYoff: nOldVal = pslotIn->AttachWithYOffset(); break;
+
+ case kslatUserDefn: nOldVal = pslotIn->UserDefn(slati); break;
+
+ case kslatMeasureSol: nOldVal = pslotIn->MeasureSol(); break;
+ case kslatMeasureEol: nOldVal = pslotIn->MeasureEol(); break;
+
+ case kslatJStretch: nOldVal = pslotIn->JStretch(); break;
+ case kslatJShrink: nOldVal = pslotIn->JShrink(); break;
+ case kslatJStep: nOldVal = pslotIn->JStep(); break;
+ case kslatJWeight: nOldVal = pslotIn->JWeight(); break;
+ case kslatJWidth: nOldVal = pslotIn->JWidth(); break;
+
+ // These are kind of odd, but maybe.
+ case kslatAttLevel: nOldVal = pslotIn->AttachLevel(); break;
+ case kslatBreak: nOldVal = pslotIn->BreakWeight(); break;
+ case kslatDir: nOldVal = pslotIn->Directionality(); break;
+
+ default:
+ // Kind of attribute that it makes no sense to increment.
+ gAssert(false);
+ return;
+ }
+
+ if (op == kopAttrAdd || op == kopIAttrAdd)
+ nVal = nOldVal + nVal;
+ else
+ {
+ gAssert(op == kopAttrSub || op == kopIAttrSub);
+ nVal = nOldVal - nVal;
+ }
+ }
+
+ GrSlotState * pslotOut = psstrmOut->RuleOutputSlot();
+
+ if (pslotOut->IsLineBreak(ptman->LBGlyphID()))
+ {
+ switch (slat)
+ {
+ case kslatAdvX:
+ case kslatAdvY:
+ case kslatShiftX:
+ case kslatShiftY:
+
+ case kslatAttTo:
+ case kslatAttLevel:
+ case kslatAttAtX:
+ case kslatAttAtY:
+ case kslatAttAtGpt:
+ case kslatAttAtXoff:
+ case kslatAttAtYoff:
+ case kslatAttWithX:
+ case kslatAttWithY:
+ case kslatAttWithGpt:
+ case kslatAttWithXoff:
+ case kslatAttWithYoff:
+
+ case kslatMeasureSol:
+ case kslatMeasureEol:
+
+ case kslatJStretch:
+ case kslatJShrink:
+ case kslatJStep:
+ case kslatJWeight:
+ case kslatJWidth:
+ slat = kslatNoEffect;
+ break;
+ default:
+ ; // okay, do nothing
+ }
+ }
+
+ nVal = GrGlyphSubTable::ConvertValueForVersion(nVal, slat, -1, m_fxdVersion);
+
+ switch (slat)
+ {
+ case kslatAdvX: pslotOut->SetAdvanceX(nVal); break;
+ case kslatAdvY: pslotOut->SetAdvanceY(nVal); break;
+ case kslatShiftX: pslotOut->SetShiftX(nVal); break;
+ case kslatShiftY: pslotOut->SetShiftY(nVal); break;
+
+ case kslatAttTo: pslotOut->SetAttachTo(nVal); break;
+ case kslatAttLevel: pslotOut->SetAttachLevel(nVal); break;
+ case kslatAttAtX: pslotOut->SetAttachAtX(nVal); break;
+ case kslatAttAtY: pslotOut->SetAttachAtY(nVal); break;
+ case kslatAttAtGpt: pslotOut->SetAttachAtGpoint(nVal); break;
+ case kslatAttAtXoff: pslotOut->SetAttachAtXOffset(nVal); break;
+ case kslatAttAtYoff: pslotOut->SetAttachAtYOffset(nVal); break;
+ case kslatAttWithX: pslotOut->SetAttachWithX(nVal); break;
+ case kslatAttWithY: pslotOut->SetAttachWithY(nVal); break;
+ case kslatAttWithGpt: pslotOut->SetAttachWithGpoint(nVal); break;
+ case kslatAttWithXoff: pslotOut->SetAttachWithXOffset(nVal); break;
+ case kslatAttWithYoff: pslotOut->SetAttachWithYOffset(nVal); break;
+
+ case kslatUserDefn: pslotOut->SetUserDefn(slati, nVal); break;
+
+ case kslatCompRef:
+ gAssert(nVal - 1 >= psstrmIn->RuleStartReadPos() - psstrmIn->ReadPosForNextGet());
+ pslotComp = psstrmIn->RuleInputSlot(nVal, psstrmOut);
+ pslotOut->SetCompRefSlot(ptman, slati, pslotComp);
+ break;
+
+ case kslatMeasureSol: pslotOut->SetMeasureSol(nVal); break;
+ case kslatMeasureEol: pslotOut->SetMeasureEol(nVal); break;
+
+ case kslatJStretch: pslotOut->SetJStretch(nVal); break;
+ case kslatJShrink: pslotOut->SetJShrink(nVal); break;
+ case kslatJStep: pslotOut->SetJStep(nVal); break;
+ case kslatJWeight: pslotOut->SetJWeight(nVal); break;
+ case kslatJWidth: pslotOut->SetJWidth(nVal); break;
+
+ case kslatBreak: pslotOut->SetBreakWeight(nVal); break;
+ case kslatDir: pslotOut->SetDirectionality(DirCode(nVal)); break;
+ case kslatInsert: pslotOut->SetInsertBefore(bool(nVal)); break;
+
+ case kslatNoEffect:
+ // Do nothing.
+ break;
+
+ default:
+ // Kind of attribute that it makes no sense to set.
+ gAssert(false);
+ return;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a slot attribute onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param slat - slot attribute to get
+ @param slati - slot attribute index, or -1 for non-indexed attribute
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushSlotAttr(GrTableManager * ptman,
+ int nSlotRef, bool fInserting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ int nVal;
+ int xyBogus;
+
+ if (slat == kslatUserDefnV1)
+ slat = kslatUserDefn;
+
+ if (slati != -1 && slat != kslatCompRef && slat != kslatUserDefn)
+ {
+ // Invalid slot attribute index.
+ gAssert(false);
+ slati = -1;
+ }
+
+ if (slati == -1 && (slat == kslatCompRef || slat == kslatUserDefn))
+ {
+ // Missing slot attribute index.
+ gAssert(false);
+ slati = 0;
+ }
+
+ switch (slat)
+ {
+ case kslatAdvX: nVal = pslot->AdvanceX(ptman); break;
+ case kslatAdvY: nVal = pslot->AdvanceY(ptman); break;
+ case kslatShiftX: nVal = pslot->ShiftX(); break;
+ case kslatShiftY: nVal = pslot->ShiftY(); break;
+
+ case kslatPosX: pslot->Position(ptman, psstrmIn, &nVal, &xyBogus); break;
+ case kslatPosY: pslot->Position(ptman, psstrmIn, &xyBogus, &nVal); break;
+
+ case kslatAttTo: nVal = pslot->AttachTo(); break;
+ case kslatAttLevel: nVal = pslot->AttachLevel(); break;
+ case kslatAttAtX: nVal = pslot->AttachAtX(ptman, psstrmIn); break;
+ case kslatAttAtY: nVal = pslot->AttachAtY(); break;
+ case kslatAttAtGpt: nVal = pslot->AttachAtGpoint(); break;
+ case kslatAttAtXoff: nVal = pslot->AttachAtXOffset(); break;
+ case kslatAttAtYoff: nVal = pslot->AttachAtYOffset(); break;
+ case kslatAttWithX: nVal = pslot->AttachWithX(ptman, psstrmIn); break;
+ case kslatAttWithY: nVal = pslot->AttachWithY(); break;
+ case kslatAttWithGpt: nVal = pslot->AttachWithGpoint(); break;
+ case kslatAttWithXoff: nVal = pslot->AttachWithXOffset(); break;
+ case kslatAttWithYoff: nVal = pslot->AttachWithYOffset(); break;
+
+ case kslatMeasureSol: nVal = pslot->MeasureSol(); break;
+ case kslatMeasureEol: nVal = pslot->MeasureEol(); break;
+
+ case kslatJStretch: nVal = pslot->JStretch(); break;
+ case kslatJShrink: nVal = pslot->JShrink(); break;
+ case kslatJStep: nVal = pslot->JStep(); break;
+ case kslatJWeight: nVal = pslot->JWeight(); break;
+ case kslatJWidth: nVal = pslot->JWidth(); break;
+
+ case kslatBreak: nVal = pslot->BreakWeight(); break;
+ case kslatDir: nVal = pslot->Directionality(); break;
+ case kslatInsert: nVal = pslot->InsertBefore(); break;
+
+ case kslatUserDefn: nVal = pslot->UserDefn(slati); break;
+
+ // Currently no way to look up component.X.ref.
+
+ default:
+ // Invalid attribute.
+ gAssert(false);
+ nVal = 0;
+ }
+
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph attribute onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+ int nVal = pslot->GlyphAttrValueEmUnits(ptman, nGlyphAttr);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph attribute onto the stack. The slot of interest is the slot to
+ which the current slot is attached.
+
+ @param nSlotRef - leaf slot
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushAttToGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Note that it is the slot in the output stream that has
+ // the relevant attach.to attribute set.
+ GrSlotState * pslotLeaf = psstrmOut->RuleOutputSlot(0);
+ int srAttTo = pslotLeaf->AttachTo();
+ if (srAttTo == 0)
+ {
+ gAssert(false);
+ vnStack.push_back(0);
+ return;
+ }
+
+ GrSlotState * pslotRoot = psstrmIn->RuleInputSlot(nSlotRef + srAttTo, psstrmOut);
+ int nVal = pslotRoot->GlyphAttrValueEmUnits(ptman, nGlyphAttr);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph metric onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param nAttLevel - for accessing composite metrics
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ DoPushGlyphMetricAux(ptman, pslot, nGlyphAttr, nAttLevel, vnStack, psstrmIn);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph metric onto the stack. The slot of interest is the slot to
+ which the current slot is attached.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param nAttLevel - for accessing composite metrics
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushAttToGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Note that it is the slot in the output stream that has
+ // the relevant attach.to attribute set.
+ GrSlotState * pslotLeaf = psstrmOut->RuleOutputSlot(0);
+ int srAttTo = pslotLeaf->AttachTo();
+ if (srAttTo == 0)
+ {
+ gAssert(false);
+ vnStack.push_back(0);
+ return;
+ }
+
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef + srAttTo, psstrmOut);
+
+ DoPushGlyphMetricAux(ptman, pslot, nGlyphAttr, nAttLevel, vnStack, psstrmIn);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+void GrPass::DoPushGlyphMetricAux(GrTableManager * ptman,
+ GrSlotState * pslot, int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn)
+{
+ int mVal;
+ GlyphMetric gmet = GlyphMetric(nGlyphAttr);
+ if (nAttLevel == 0 || gmet == kgmetAscent || gmet == kgmetDescent)
+ {
+ mVal = pslot->GlyphMetricEmUnits(ptman, nGlyphAttr);
+ }
+ else
+ {
+ pslot->CalcCompositeMetrics(ptman, psstrmIn, nAttLevel, true);
+
+ float xy;
+ switch (gmet)
+ {
+ case kgmetLsb: xy = pslot->ClusterLsb(psstrmIn); break;
+ case kgmetRsb: xy = pslot->ClusterRsb(psstrmIn); break;
+ case kgmetBbTop: xy = pslot->ClusterBbTop(psstrmIn); break;
+ case kgmetBbBottom: xy = pslot->ClusterBbBottom(psstrmIn); break;
+ case kgmetBbLeft: xy = pslot->ClusterBbLeft(psstrmIn); break;
+ case kgmetBbRight: xy = pslot->ClusterBbRight(psstrmIn); break;
+ case kgmetBbHeight: xy = pslot->ClusterBbHeight(psstrmIn); break;
+ case kgmetBbWidth: xy = pslot->ClusterBbWidth(psstrmIn); break;
+// case kgmetAdvHeight: xy = pslot->ClusterAdvHeight(psstrmIn); break;
+ case kgmetAdvWidth: xy = pslot->ClusterAdvWidth(psstrmIn); break;
+ default:
+ gAssert(false);
+ xy = 0;
+ }
+ mVal = ptman->LogToEmUnits(xy);
+ }
+
+ vnStack.push_back(mVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push a feature value onto the stack. For rule actions, the slot of interest is the
+ current slot.
+
+ @param nSlotRef - slot being examined
+ @param fInserting - whether current slot was inserted
+ @param nFeat - feature of interest
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushFeatValue(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nFeat, std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert(!fInserting);
+
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ int nVal = pslot->FeatureValue(nFeat);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push a processing-state value onto the stack.
+
+ @param nFeat - feature of interest
+ @param vnStack - stack to push onto
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushProcState(GrTableManager * ptman, int nPState, std::vector<int> & vnStack)
+{
+ int nValue;
+ if (nPState == kpstatJustifyMode)
+ {
+ // Convert from internal modes to user modes.
+ int jmodi = ptman->InternalJustificationMode();
+ switch (jmodi)
+ {
+ case kjmodiNormal:
+ case kjmodiCanShrink:
+ nValue = kjmoduNormal;
+ break;
+ case kjmodiMeasure:
+ nValue = kjmoduMeasure;
+ break;
+ case kjmodiJustify:
+ nValue = kjmoduJustify;
+ break;
+ default:
+ gAssert(false);
+ nValue = kjmoduNormal;
+ }
+ }
+ else if (nPState == kpstatJustifyLevel)
+ nValue = 1; // TODO: get justify level from ptman
+ vnStack.push_back(nValue);
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPseudoMap.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPseudoMap.h
new file mode 100644
index 00000000000..c6fec210808
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrPseudoMap.h
@@ -0,0 +1,48 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrPseudoMap.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ The GrPseudoMap class.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_PSEUDOMAP_INCLUDED
+#define GR_PSEUDOMAP_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+/*----------------------------------------------------------------------------------------------
+ A mapping between a Unicode value and a pseudo-glyph.
+
+ Hungarian: psd
+----------------------------------------------------------------------------------------------*/
+
+class GrPseudoMap
+{
+public:
+ unsigned int Unicode() { return m_nUnicode; }
+ gid16 PseudoGlyph() { return m_chwPseudo; }
+
+ void SetUnicode(int n) { m_nUnicode = n; }
+ void SetPseudoGlyph(gid16 chw) { m_chwPseudo = chw; }
+
+protected:
+ // Instance variables:
+ unsigned int m_nUnicode;
+ gid16 m_chwPseudo;
+};
+
+} // namespace gr
+
+#endif // !GR_PSEUDOMAP_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.cpp
new file mode 100644
index 00000000000..9879bc0516f
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.cpp
@@ -0,0 +1,1540 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrSlotState.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ GrSlotState class implementation.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Initialize slots.
+----------------------------------------------------------------------------------------------*/
+// standard for pass 0 slots
+void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng,
+ GrFeatureValues fval, int ipass, int ichwSegOffset, int nUnicode)
+{
+ Assert(ipass == 0);
+ m_chwGlyphID = chw;
+ m_chwActual = kInvalidGlyph;
+ m_xysGlyphWidth = kNegInfFloat;
+ m_bStyleIndex = byte(fval.m_nStyleIndex);
+ u_intslot nullSlot;
+ nullSlot.pslot = NULL;
+ std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot);
+ std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot);
+ std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot);
+ u_intslot * pFeatBuf = PFeatureBuf();
+ for (size_t i = 0; i < m_cnFeat; i++)
+ pFeatBuf[i].nValue = fval.m_rgnFValues[i];
+ m_ipassFsmCol = -1;
+ m_colFsm = -1;
+
+ m_ipassModified = ipass;
+ m_ichwSegOffset = ichwSegOffset;
+ m_nUnicode = nUnicode;
+ m_vpslotAssoc.clear();
+ pgreng->InitSlot(this, nUnicode);
+
+ switch (nUnicode)
+ {
+ case knLRM: m_spsl = kspslLRM; break;
+ case knRLM: m_spsl = kspslRLM; break;
+ case knLRO: m_spsl = kspslLRO; break;
+ case knRLO: m_spsl = kspslRLO; break;
+ case knLRE: m_spsl = kspslLRE; break;
+ case knRLE: m_spsl = kspslRLE; break;
+ case knPDF: m_spsl = kspslPDF; break;
+ default:
+ Assert(m_spsl == kspslNone);
+ m_spsl = kspslNone;
+ break;
+ }
+}
+
+// line-break slots
+void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng,
+ GrSlotState * pslotFeat, int ipass, int ichwSegOffset)
+{
+ m_chwGlyphID = chw;
+ m_chwActual = kInvalidGlyph;
+ m_xysGlyphWidth = kNegInfFloat;
+ u_intslot nullSlot;
+ nullSlot.pslot = NULL;
+ std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot);
+ std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot);
+ std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot);
+ CopyFeaturesFrom(pslotFeat);
+ m_ipassModified = ipass;
+ m_ichwSegOffset = ichwSegOffset;
+ m_nUnicode = -1;
+ m_vpslotAssoc.clear();
+ pgreng->InitSlot(this);
+ // Caller is responsible for setting m_spsl.
+ m_ipassFsmCol = -1;
+ m_colFsm = -1;
+}
+
+// for inserting new slots after pass 0 (under-pos and unicode are irrelevant)
+void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng,
+ GrSlotState * pslotFeat, int ipass)
+{
+ m_chwGlyphID = chw;
+ m_chwActual = kInvalidGlyph;
+ m_xysGlyphWidth = kNegInfFloat;
+ u_intslot nullSlot;
+ nullSlot.pslot = NULL;
+ std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot);
+ std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot);
+ std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot);
+ CopyFeaturesFrom(pslotFeat);
+ m_ipassModified = ipass;
+ m_ichwSegOffset = kInvalid;
+ m_nUnicode = kInvalid;
+ m_vpslotAssoc.clear();
+ pgreng->InitSlot(this);
+ m_spsl = kspslNone;
+ m_ipassFsmCol = -1;
+ m_colFsm = -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ The slot has been modified by the given pass and therefore is in a new state;
+ make a new SlotState initialized from the old one.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::InitializeFrom(GrSlotState * pslotOld, int ipass)
+{
+ CopyFrom(pslotOld, false);
+
+ m_ipassModified = ipass;
+ m_pslotPrevState = pslotOld;
+ m_ichwSegOffset = kInvalid;
+ m_vpslotAssoc.clear();
+ m_vpslotAssoc.push_back(pslotOld);
+
+ m_dircProc = pslotOld->m_dircProc;
+ m_fDirProcessed = pslotOld->m_fDirProcessed;
+
+ // Since we're going on to a new pass, no point in copying these:
+ m_ipassFsmCol = -1;
+ m_colFsm = -1;
+
+ ////FixAttachmentTree(pslotOld);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the features and style information from the given slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::CopyFeaturesFrom(GrSlotState * pslotSrc)
+{
+ m_bStyleIndex = pslotSrc->m_bStyleIndex;
+ Assert(m_cnFeat == pslotSrc->m_cnFeat);
+ std::copy(pslotSrc->PFeatureBuf(), pslotSrc->PFeatureBuf() + m_cnFeat, PFeatureBuf());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the basic information.
+ Warning: the functions below will break if GrSlotState and subclasses are given virtual
+ methods. In that case, we will need to copy from the address of the first variable in
+ GrSlotAbstract.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::CopyFrom(GrSlotState * pslot, bool fCopyEverything)
+{
+ GrSlotAbstract::CopyAbstractFrom(pslot);
+ std::copy(pslot->m_prgnVarLenBuf, pslot->m_prgnVarLenBuf + CExtraSpace(), m_prgnVarLenBuf);
+
+ if (fCopyEverything)
+ {
+ Assert(false);
+ m_ipassModified = pslot->m_ipassModified;
+ m_pslotPrevState = pslot->m_pslotPrevState;
+ m_ichwSegOffset = pslot->m_ichwSegOffset;
+ m_colFsm = pslot->m_colFsm;
+ m_ipassFsmCol = pslot->m_ipassFsmCol;
+ // TODO: copy m_vpslotAssocs.
+ m_fNeutralAssocs = pslot->m_fNeutralAssocs;
+ }
+
+ m_dislotRootFixed = pslot->m_dislotRootFixed;
+
+ m_vdislotAttLeaves.resize(pslot->m_vdislotAttLeaves.size());
+ for (size_t i = 0; i < pslot->m_vdislotAttLeaves.size(); i++)
+ m_vdislotAttLeaves[i] = pslot->m_vdislotAttLeaves[i];
+
+ m_islotPosPass = pslot->m_islotPosPass;
+ m_nUnicode = pslot->m_nUnicode;
+ m_dircProc = pslot->m_dircProc;
+ m_fDirProcessed = pslot->m_fDirProcessed;
+ m_cnUserDefn = pslot->m_cnUserDefn;
+ m_cnFeat = pslot->m_cnFeat;
+ m_bStyleIndex = pslot->m_bStyleIndex;
+ m_mAdvanceX = pslot->m_mAdvanceX;
+ m_mAdvanceY = pslot->m_mAdvanceY;
+ m_mShiftX = pslot->m_mShiftX;
+ m_mShiftY = pslot->m_mShiftY;
+ m_srAttachTo = pslot->m_srAttachTo;
+ m_nAttachLevel = pslot->m_nAttachLevel;
+ m_mAttachAtX = pslot->m_mAttachAtX;
+ m_mAttachAtY = pslot->m_mAttachAtY;
+ m_mAttachAtXOffset = pslot->m_mAttachAtXOffset;
+ m_mAttachAtYOffset = pslot->m_mAttachAtYOffset;
+ m_mAttachWithX = pslot->m_mAttachWithX;
+ m_mAttachWithY = pslot->m_mAttachWithY;
+ m_mAttachWithXOffset = pslot->m_mAttachWithXOffset;
+ m_mAttachWithYOffset = pslot->m_mAttachWithYOffset;
+ m_nAttachAtGpoint = pslot->m_nAttachAtGpoint;
+ m_nAttachWithGpoint = pslot->m_nAttachWithGpoint;
+ m_fAttachMod = pslot->m_fAttachMod;
+ m_fShiftMod = pslot->m_fShiftMod;
+ m_fIgnoreAdvance = pslot->m_fIgnoreAdvance;
+
+ m_nCompositeLevel = kNegInfinity; // uncalculated, so don't need to copy the positions??
+}
+
+void GrSlotAbstract::CopyAbstractFrom(GrSlotState * pslot)
+{
+ u_intslot * pnBufSave = m_prgnVarLenBuf;
+ *this = *pslot;
+ m_prgnVarLenBuf = pnBufSave;
+ Assert(m_prgnVarLenBuf);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the output slot from the one use within the passes, with the basic information.
+ Warning: this function will break if GrSlotState and subclasses are given virtual
+ methods. In that case, we will need to copy from the address of the first variable in
+ GrSlotAbstract.
+----------------------------------------------------------------------------------------------*/
+void GrSlotOutput::InitializeOutputFrom(GrSlotState * pslot)
+{
+ CopyAbstractFrom(pslot);
+
+ // Copy just the component information, which is of length (m_cnCompPerLig * 2)
+ //std::copy(pslot->PCompRefBuf(),
+ // pslot->PCompRefBuf() + (m_cnCompPerLig * 2),
+ // this->PCompRefBufSlout());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the ID of the actual glyph that will be used for output and metrics. This is the
+ same for most glyphs, but will be different for pseudo-glyphs.
+----------------------------------------------------------------------------------------------*/
+gid16 GrSlotAbstract::ActualGlyphForOutput(GrTableManager * ptman)
+{
+ if (m_chwActual == kInvalidGlyph)
+ m_chwActual = ptman->ActualGlyphForOutput(m_chwGlyphID);
+ return m_chwActual;
+}
+/*----------------------------------------------------------------------------------------------
+ We are replacing the old slot with the recipient. Replace the pointers in any attachment
+ root or attached leaf slots.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::FixAttachmentTree(GrSlotState * pslotOld)
+{
+#if 0
+ pslotOld->m_vpslotAttLeaves.CopyTo(m_vpslotAttLeaves);
+ for (int islot = 0; islot < m_vpslotAttLeaves.Size(); islot++)
+ {
+ Assert(m_vpslotAttLeaves[islot]->m_pslotAttRoot == pslotOld);
+ m_vpslotAttLeaves[islot]->m_pslotAttRoot = this;
+ }
+
+ m_pslotAttRoot = pslotOld->m_pslotAttRoot;
+ if (m_pslotAttRoot)
+ {
+ for (int islot = 0; islot < m_pslotAttRoot->m_vpslotAttLeaves.Size(); islot++)
+ {
+ if (m_pslotAttRoot->m_vpslotAttLeaves[islot] == pslotOld)
+ {
+ m_pslotAttRoot->m_vpslotAttLeaves.Delete(islot);
+ m_pslotAttRoot->m_vpslotAttLeaves.Push(this);
+ return;
+ }
+ }
+ Assert(false); // didn't find old slot in the list
+ }
+#endif // 0
+}
+
+/*----------------------------------------------------------------------------------------------
+ Make sure all the values are cached that are needed to be copied to the output slots
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::EnsureCacheForOutput(GrTableManager * ptman)
+{
+ // Make sure the actual glyph ID is set.
+ gid16 gidActual = ActualGlyphForOutput(ptman);
+
+ // Make sure the glyph metrics are stored.
+ Font * pfont = ptman->State()->GetFont();
+ if (IsLineBreak(ptman->LBGlyphID()))
+ {
+ GetGlyphMetric(pfont, kgmetAscent, 0);
+ GetGlyphMetric(pfont, kgmetDescent, 0);
+ m_xysGlyphX = 0;
+ m_xysGlyphY = 0;
+ m_xysGlyphHeight = 0;
+ m_xysGlyphWidth = 0;
+ m_xysAdvX = 0;
+ m_xysAdvY = 0;
+ m_bIsSpace = true;
+ }
+ else
+ {
+ //IsSpace(ptman); // cache this flag--doing bb-top below will do it
+
+ GetGlyphMetric(pfont, kgmetAscent, gidActual);
+ GetGlyphMetric(pfont, kgmetDescent, gidActual);
+ GetGlyphMetric(pfont, kgmetBbTop, gidActual);
+ // call above will also cache all the values below
+ //GetGlyphMetric(pfont, kgmetBbBottom, gidActual);
+ //GetGlyphMetric(pfont, kgmetBbLeft, gidActual);
+ //GetGlyphMetric(pfont, kgmetBbRight, gidActual);
+ //GetGlyphMetric(pfont, kgmetAdvWidth, gidActual);
+ //GetGlyphMetric(pfont, kgmetAdvHeight, gidActual);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the associations for the slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::Associate(GrSlotState * pslot)
+{
+ m_vpslotAssoc.clear();
+ m_vpslotAssoc.push_back(pslot);
+}
+
+void GrSlotState::Associate(GrSlotState * pslotBefore, GrSlotState * pslotAfter)
+{
+ m_vpslotAssoc.clear();
+ m_vpslotAssoc.push_back(pslotBefore);
+ m_vpslotAssoc.push_back(pslotAfter);
+}
+
+void GrSlotState::Associate(std::vector<GrSlotState*> & vpslot)
+{
+ m_vpslotAssoc.clear();
+ ///vpslot.CopyTo(m_vpslotAssoc); -- bug in CopyTo, so we do it ourselves:
+ for (size_t islot = 0; islot < vpslot.size(); ++islot)
+ {
+ m_vpslotAssoc.push_back(vpslot[islot]);
+ }
+
+ // Set its character styles and features from the associated slot.
+ if (vpslot.size() > 0) // && !m_pslotPrevState
+ {
+ std::copy(m_vpslotAssoc[0]->PFeatureBuf(),
+ m_vpslotAssoc[0]->PFeatureBuf() + m_cnFeat, PFeatureBuf());
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Clear the associations for the slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::ClearAssocs()
+{
+ m_vpslotAssoc.clear();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a list of (ie, add into the vector) all the underlying associations, relative
+ to the official beginning of the segment.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::AllAssocs(std::vector<int> & vichw)
+{
+ if (PassModified() == 0)
+ {
+ Assert(m_ichwSegOffset != kInvalid);
+ vichw.push_back(m_ichwSegOffset);
+ }
+ else
+ {
+ for (size_t i = 0; i < m_vpslotAssoc.size(); ++i)
+ m_vpslotAssoc[i]->AllAssocs(vichw);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the underlying position of the before-association, relative to the official
+ beginning of the segment. May be -1, if this slot maps to a character in the previous
+ segment, or >= the length of the segment, if it maps to a character in the following
+ segment.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::BeforeAssoc()
+{
+ GrSlotState * pslot = this;
+ while (pslot->PassModified() > 0)
+ {
+ pslot = pslot->RawBeforeAssocSlot();
+ if (pslot == NULL)
+ {
+ return kPosInfinity;
+ }
+ }
+ Assert(pslot->m_ichwSegOffset != kInvalid);
+ return pslot->m_ichwSegOffset;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the underlying position of the after-association, relative to the official
+ beginning of the segment. May be -1, if this slot maps to a character in the previous
+ segment, or >= the length of the segment, if it maps to a character in the following
+ segment.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::AfterAssoc()
+{
+ GrSlotState * pslot = this;
+ while (pslot->PassModified() > 0)
+ {
+ pslot = pslot->RawAfterAssocSlot();
+ if (pslot == NULL)
+ {
+ return kNegInfinity;
+ }
+ }
+ Assert(pslot->m_ichwSegOffset != kInvalid);
+ return pslot->m_ichwSegOffset;
+}
+
+/*----------------------------------------------------------------------------------------------
+ It is possible to get into a state where we are associated with an invalid state.
+ For instance, slot C may be associated with slots B1 and B2, but slot B1 is not associated
+ with any earlier slot, in which case slot C should remove the association with B1 and just
+ be associated with B2.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::CleanUpAssocs()
+{
+ for (size_t i = 0; i < m_vpslotAssoc.size(); i++)
+ m_vpslotAssoc[i]->CleanUpAssocs();
+
+ GrSlotState * pslot;
+
+ pslot = RawBeforeAssocSlot();
+ while (pslot && BeforeAssoc() == kPosInfinity)
+ {
+ // The before association is bogus--delete it.
+ m_vpslotAssoc.erase(m_vpslotAssoc.begin());
+ pslot = RawBeforeAssocSlot();
+ }
+
+ pslot = RawAfterAssocSlot();
+ while (pslot && AfterAssoc() == kNegInfinity)
+ {
+ // The after association is bogus--delete it.
+ m_vpslotAssoc.pop_back();
+ pslot = RawAfterAssocSlot();
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the array of the given output slot with the underlying positions of the
+ ligature components, relative to the official beginning of the segment.
+ Positions may be < 0, if this slot maps to a character in the previous segment,
+ or >= the length of the segment, if it maps to a character in the following segment.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::SetComponentRefsFor(GrSlotOutput * pslout, int slatiArg)
+{
+ if (PassModified() > 0)
+ {
+ GrSlotState * pslot;
+ int slati;
+ if (HasComponents())
+ {
+ for (int iComponent = 0; iComponent < m_cnCompPerLig; iComponent++)
+ {
+ pslot = CompRefSlot(iComponent);
+ slati = Slati(iComponent);
+ if (pslot)
+ {
+ Assert(slati != -1);
+ Assert(PassModified() >= pslot->PassModified());
+ pslot->SetComponentRefsFor(pslout, slati);
+ }
+ }
+ }
+ else
+ {
+ // Follow the chain back through the passes.
+ for (int islot = 0; islot < AssocsSize(); islot++)
+ {
+ pslot = m_vpslotAssoc[islot];
+ if (pslot)
+ {
+ Assert(PassModified() >= pslot->PassModified());
+ // Passing slati here is definitely needed for our Arabic font: for instance when
+ // you type something like "mla", so the l is transformed into a temporary glyph
+ // before creating the ligature. However, this seems to have broken something,
+ // which I will probably find eventually. :-(
+ pslot->SetComponentRefsFor(pslout, slatiArg);
+ //pslot->SetComponentRefsFor(pslout, -1);
+ }
+ }
+ }
+ }
+ else
+ {
+ Assert(m_ichwSegOffset != kInvalid);
+ pslout->AddComponentReference(m_ichwSegOffset, slatiArg);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the vector with the underlying positions of the
+ ligature components, relative to the official beginning of the segment.
+ Positions may be < 0, if this slot maps to a character in the previous segment,
+ or >= the length of the segment, if it maps to a character in the following segment.
+ ENHANCE: merge with method above.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::AllComponentRefs(std::vector<int> & vichw, std::vector<int> & vicomp,
+ int iComponent)
+{
+ if (PassModified() > 0)
+ {
+ GrSlotState * pslot;
+ if (HasComponents())
+ {
+ for (int iComponent = 0; iComponent < m_cnCompPerLig; iComponent++)
+ {
+ pslot = CompRefSlot(iComponent);
+ if (pslot)
+ {
+ Assert(PassModified() >= pslot->PassModified());
+ pslot->AllComponentRefs(vichw, vicomp, iComponent);
+ }
+ }
+ }
+ else
+ {
+ for (int islot = 0; islot < AssocsSize(); islot++)
+ {
+ m_vpslotAssoc[islot]->AllComponentRefs(vichw, vicomp, iComponent);
+ }
+ }
+ }
+ else
+ {
+ Assert(m_ichwSegOffset != kInvalid);
+ vichw.push_back(m_ichwSegOffset);
+ vicomp.push_back(iComponent);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the value of the component.???.ref attribute for the slot.
+ Note that 'i' is the local index for the component as defined for this glyph.
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotState::CompRefSlot(int i)
+{
+ Assert(i < m_cnCompPerLig);
+ if (i < m_cnCompPerLig)
+ return CompRef(i);
+ else
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the value of the component.???.ref attribute for the slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::SetCompRefSlot(GrTableManager * ptman, int slati, GrSlotState * pslotComp)
+{
+ // Convert the global identifer for the component to the index for this glyph.
+ int icomp = ptman->ComponentIndexForGlyph(GlyphID(), slati);
+ Assert(icomp != -1);
+ if (icomp == -1)
+ // Component not defined for this glyph--ignore.
+ return;
+ Assert(icomp < m_cnCompPerLig);
+
+ if (m_fHasComponents == false)
+ {
+ // None have been set yet; initialize them.
+ for (int iLoop = 0; iLoop < m_cnCompPerLig; iLoop++)
+ {
+ SetCompRef(iLoop, NULL);
+ SetSlati(iLoop, -1);
+ }
+ }
+
+ m_fHasComponents = true;
+ int iLoop;
+ for (iLoop = 0; iLoop < m_cnCompPerLig; iLoop++)
+ {
+ if (Slati(iLoop) == slati)
+ break;
+ if (Slati(iLoop) == -1)
+ break;
+ }
+ //if (icomp < m_cnCompPerLig)
+ if (iLoop < m_cnCompPerLig)
+ {
+ //SetCompRef(icomp, pslotComp);
+ SetCompRef(iLoop, pslotComp);
+ SetSlati(iLoop, slati);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the underlying position for the slot, relative to the official beginning of the
+ segment.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::SegOffset()
+{
+ if (m_ichwSegOffset == kInvalid)
+ {
+ Assert(m_pslotPrevState);
+ Assert(m_ipassModified > 0);
+ return m_pslotPrevState->SegOffset();
+ }
+ else
+ {
+ Assert(m_pslotPrevState == NULL);
+ Assert(m_ipassModified == 0);
+ return m_ichwSegOffset;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the value of the glyph attribute (in design units, if this is a measurement).
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::GlyphAttrValueEmUnits(GrTableManager * ptman, int nAttrID)
+{
+ return ptman->GlyphAttrValue(m_chwGlyphID, nAttrID);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the value of the glyph metric, in design coordinates (ie, based on the font's
+ em-square).
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::GlyphMetricEmUnits(GrTableManager * ptman, int nMetricID)
+{
+ int mValue;
+ if (ptman->State()->GetFont())
+ {
+ // Get the actual metric, possibly adjusted for hinting, then convert back to
+ // design units.
+ float xysValue = GlyphMetricLogUnits(ptman, nMetricID);
+ mValue = ptman->LogToEmUnits(xysValue);
+ }
+ else
+ // Ask the font directly.
+ ////mValue = ???
+ mValue = 0;
+
+ return mValue;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the value of the glyph attribute, converted to source device coordinates.
+ The attribute is assumed to be one whose value is a measurement.
+----------------------------------------------------------------------------------------------*/
+float GrSlotState::GlyphAttrValueLogUnits(GrTableManager * ptman, int nAttrID)
+{
+ int mValue = GlyphAttrValueEmUnits(ptman, nAttrID);
+ float xysRet = ptman->EmToLogUnits(mValue);
+ return xysRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the value of the glyph metric, in the source device's logical units.
+----------------------------------------------------------------------------------------------*/
+float GrSlotState::GlyphMetricLogUnits(GrTableManager * ptman, int nMetricID)
+{
+#ifdef OLD_TEST_STUFF
+ if (ptman->GlyphTable() == NULL)
+ return 0;
+#endif // OLD_TEST_STUFF
+
+#ifdef _DEBUG
+ if (IsLineBreak(ptman->LBGlyphID()))
+ {
+ Warn("Getting metrics of line-break slot");
+ }
+#endif // _DEBUG
+ if (IsLineBreak(ptman->LBGlyphID()))
+ {
+ return 0;
+ }
+
+ return GetGlyphMetric(ptman->State()->GetFont(), nMetricID,
+ ActualGlyphForOutput(ptman));
+}
+
+
+float GrSlotOutput::GlyphMetricLogUnits(Font * pfont, int nMetricID)
+{
+ Assert(m_chwActual != kInvalidGlyph);
+ if (m_chwActual == kInvalidGlyph)
+ return 0;
+
+ return GetGlyphMetric(pfont, nMetricID, m_chwActual);
+}
+
+//float GrSlotOutput::GlyphMetricLogUnits(int gmet) -- obsolete: no longer caching these values
+//{
+// // When the font is not passed as an argument, the values better be cached!
+//
+// switch (gmet)
+// { // There may be off by one errors below, depending on what width and height mean
+// case kgmetLsb:
+// return m_xysGlyphX;
+// case kgmetRsb:
+// return (m_xysAdvX - m_xysGlyphX - m_xysGlyphWidth);
+// case kgmetBbTop:
+// return m_xysGlyphY;
+// case kgmetBbBottom:
+// return (m_xysGlyphY - m_xysGlyphHeight);
+// case kgmetBbLeft:
+// return m_xysGlyphX;
+// case kgmetBbRight:
+// return (m_xysGlyphX + m_xysGlyphWidth);
+// case kgmetBbHeight:
+// return m_xysGlyphHeight;
+// case kgmetBbWidth:
+// return m_xysGlyphWidth;
+// case kgmetAdvWidth:
+// return m_xysAdvX;
+// case kgmetAdvHeight:
+// return m_xysAdvY;
+// default:
+// Warn("GetGlyphMetric was asked for an illegal metric.");
+// };
+//
+// return 0;
+//}
+
+float GrSlotState::GetGlyphMetric(Font * pfont, int nMetricID, gid16 chwGlyphID)
+{
+ GlyphMetric gmet = GlyphMetric(nMetricID);
+ switch (gmet)
+ {
+ case kgmetAscent:
+ case kgmetDescent:
+ if (m_xysFontAscent == kNegInfFloat)
+ {
+ m_xysFontAscent = GrSlotAbstract::GetGlyphMetric(pfont, kgmetAscent, chwGlyphID);
+ m_xysFontDescent = GrSlotAbstract::GetGlyphMetric(pfont, kgmetDescent, chwGlyphID);
+ }
+ break;
+ default:
+ if (m_xysGlyphWidth == kNegInfFloat)
+ {
+ GetGlyphMetricAux(pfont, chwGlyphID, m_xysGlyphX, m_xysGlyphY, m_xysGlyphWidth,
+ m_xysGlyphHeight, m_xysAdvX, m_xysAdvY, m_bIsSpace);
+ }
+ break;
+ }
+
+ switch (gmet)
+ { // There may be off-by-one errors below, depending on what width and height mean
+ case kgmetAscent:
+ return m_xysFontAscent;
+ case kgmetDescent:
+ return m_xysFontDescent;
+ case kgmetLsb:
+ return m_xysGlyphX;
+ case kgmetRsb:
+ return (m_xysAdvX - m_xysGlyphX - m_xysGlyphWidth);
+ case kgmetBbTop:
+ return m_xysGlyphY;
+ case kgmetBbBottom:
+ return (m_xysGlyphY - m_xysGlyphHeight);
+ case kgmetBbLeft:
+ return m_xysGlyphX;
+ case kgmetBbRight:
+ return (m_xysGlyphX + m_xysGlyphWidth);
+ case kgmetBbHeight:
+ return m_xysGlyphHeight;
+ case kgmetBbWidth:
+ return m_xysGlyphWidth;
+ case kgmetAdvWidth:
+ return m_xysAdvX;
+ case kgmetAdvHeight:
+ return m_xysAdvY;
+ default:
+ Warn("GetGlyphMetric was asked for an illegal metric.");
+ };
+
+ return 0;
+}
+
+float GrSlotAbstract::GetGlyphMetric(Font * pfont, int nMetricID, gid16 chwGlyphID)
+{
+ GlyphMetric gmet = GlyphMetric(nMetricID);
+
+ float yAscent, yDescent;
+
+ if (kgmetAscent == gmet)
+ {
+ //if (m_xysFontAscent != -1)
+ // return m_xysFontAscent;
+ pfont->getFontMetrics(&yAscent);
+ //m_xysFontAscent = xysRet;
+ //if (pfont)
+ // m_xysFontAscent = yAscent;
+ return yAscent;
+ }
+
+ if (kgmetDescent == gmet)
+ {
+ //if (m_xysFontDescent != -1)
+ // return m_xysFontDescent;
+ pfont->getFontMetrics(NULL, &yDescent);
+ //m_xysFontDescent = xysRet;
+ //if (pfont)
+ // m_xysFontDescent = yDescent;
+ return yDescent;
+ }
+
+ float xysGlyphX, xysGlyphY, xysGlyphWidth, xysGlyphHeight, xysAdvX, xysAdvY;
+ GetGlyphMetricAux(pfont, chwGlyphID, xysGlyphX, xysGlyphY, xysGlyphWidth,
+ xysGlyphHeight, xysAdvX, xysAdvY, m_bIsSpace);
+
+ switch (gmet)
+ { // There may be off-by-one errors below, depending on what width and height mean
+ case kgmetLsb:
+ return xysGlyphX;
+ case kgmetRsb:
+ return (xysAdvX - xysGlyphX - xysGlyphWidth);
+ case kgmetBbTop:
+ return xysGlyphY;
+ case kgmetBbBottom:
+ return (xysGlyphY - xysGlyphHeight);
+ case kgmetBbLeft:
+ return xysGlyphX;
+ case kgmetBbRight:
+ return (xysGlyphX + xysGlyphWidth);
+ case kgmetBbHeight:
+ return xysGlyphHeight;
+ case kgmetBbWidth:
+ return xysGlyphWidth;
+ case kgmetAdvWidth:
+ return xysAdvX;
+ case kgmetAdvHeight:
+ return xysAdvY;
+ default:
+ Warn("GetGlyphMetric was asked for an illegal metric.");
+ };
+
+ return 0;
+}
+
+void GrSlotAbstract::GetGlyphMetricAux(Font * pfont, gid16 chwGlyphID,
+ float & xysGlyphX, float & xysGlyphY,
+ float & xysGlyphWidth, float & xysGlyphHeight, float & xysAdvX, float & xysAdvY, sdata8 & bIsSpace)
+{
+ gr::Point ptAdvances;
+ gr::Rect rectBb;
+ pfont->getGlyphMetrics(chwGlyphID, rectBb, ptAdvances);
+
+ xysGlyphX = rectBb.left;
+ xysGlyphY = rectBb.top;
+ xysGlyphWidth = (rectBb.right - rectBb.left);
+ xysGlyphHeight = (rectBb.top - rectBb.bottom);
+ xysAdvX = ptAdvances.x;
+ xysAdvY = ptAdvances.y;
+
+ bIsSpace = (0 == xysGlyphX && 0 == xysGlyphY); // should agree with test done in IsSpace() below
+
+ if (bIsSpace == 1)
+ {
+ // White space glyph - only case where nGlyphX == nGlyphY == 0
+ // nGlyphWidth & nGlyphHeight are always set to 16 for unknown reasons, so correct.
+ xysGlyphWidth = xysGlyphHeight = 0;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test the glyph id to see if it is a white space glyph.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::IsSpace(GrTableManager * ptman)
+{
+ gid16 gidActual = ActualGlyphForOutput(ptman);
+
+ ////if (m_xysGlyphWidth == -1)
+ ////{
+ //// res = ptman->State()->GraphicsObject()->GetGlyphMetrics(gidActual,
+ //// &m_xysGlyphWidth, &m_xysGlyphHeight,
+ //// &m_xysGlyphX, &m_xysGlyphY, &m_xysAdvX, &m_xysAdvY);
+ //// if (ResultFailed(res))
+ //// {
+ //// WARN(res);
+ //// return 2; // will test as true but can be distinguished by separate value
+ //// }
+
+ //// gr::Point ptAdvances;
+ //// gr::Rect rectBb;
+ //// ptman->State()->Font()->getGlyphMetrics(gidActual, rectBb, ptAdvances);
+ ////}
+
+ if (m_bIsSpace == -1)
+ GetGlyphMetric(ptman->State()->GetFont(), kgmetBbLeft, gidActual);
+ // One call is enough to cache the information.
+ //GetGlyphMetric(ptman->State()->Font(), kgmetBbBottom, gidActual);
+
+ // should agree with test done in GetGlyphMetric() above
+ //////m_bIsSpace = (0 == m_xysGlyphX && 0 == m_xysGlyphY);
+
+ Assert(m_bIsSpace == 0 || m_bIsSpace == 1);
+
+ return m_bIsSpace;
+}
+
+bool GrSlotOutput::IsSpace()
+{
+ Assert(m_bIsSpace == 0 || m_bIsSpace == 1);
+ return m_bIsSpace;
+}
+
+/*----------------------------------------------------------------------------------------------
+ If any of the attach attributes have been modified, fix things up. Set up the attachment
+ tree, and set any needed default positions. Zap the cached positions of any following
+ glyphs in the stream.
+
+ @param psstrm - the stream in which the modifications were made
+ @param islotThis - the index of the attached (leaf) slot in the stream;
+ -1 if we don't know
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::HandleModifiedPosition(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis)
+{
+ if (!m_fAttachMod && !m_fShiftMod)
+ return;
+
+ if (islotThis == -1)
+ {
+ for (int islot = 0; islot < psstrmOut->WritePos(); islot++)
+ {
+ if (psstrmOut->SlotAt(islot) == this)
+ {
+ islotThis = islot;
+ break;
+ }
+ }
+ Assert(islotThis > -1);
+ }
+
+ if (m_fAttachMod)
+ {
+ // Attachments.
+
+ // Note that it doesn't make sense to attach a slot to itself, so if the value of
+ // the attach.to attribute is 0, that means clear the attachment.
+ GrSlotState * pslotNewRoot = AttachRoot(psstrmOut);
+
+ AttachToRoot(ptman, psstrmOut, pslotNewRoot);
+
+ if (pslotNewRoot)
+ {
+ // If this is an attachment with no positions, attach the two glyphs side by side
+ // in the appropriate order.
+ bool fRtl = ((pslotNewRoot->PostBidiDirLevel(ptman) % 2) != 0);
+ if ((fRtl && m_srAttachTo < 0) || (!fRtl && m_srAttachTo > 0))
+ {
+ // The root is on the right, the leaf is on the left.
+ if (m_mAttachAtX == kNotYetSet && m_nAttachAtGpoint == kNotYetSet)
+ m_mAttachAtX = 0;
+ if (m_mAttachWithX == kNotYetSet && m_nAttachWithGpoint == kNotYetSet)
+ m_mAttachWithX = short(AdvanceX(ptman));
+ }
+ else
+ {
+ // The root is on the left, the leaf is on the right.
+ if (m_mAttachAtX == kNotYetSet && m_nAttachAtGpoint == kNotYetSet)
+ m_mAttachAtX = short(pslotNewRoot->AdvanceX(ptman));
+ if (m_mAttachWithX == kNotYetSet && m_nAttachWithGpoint == kNotYetSet)
+ m_mAttachWithX = 0;
+ }
+ }
+ }
+ else
+ {
+ // Shifting, or changing the advance width.
+ Assert(m_fShiftMod);
+ EnsureLocalAttachmentTree(ptman, psstrmIn, psstrmOut, islotThis);
+ ZapMetricsAndPositionDownToBase(psstrmOut);
+ ZapMetricsOfLeaves(psstrmOut);
+ }
+
+ if (psstrmOut->m_ipass == ptman->NumberOfPasses() - 1)
+ ptman->InitPosCache(); // cached position is most likely no longer valid
+
+ // Invalidate the positions of this and any following glyphs.
+ for (int islot = islotThis + 1; islot < psstrmOut->WritePos(); islot++)
+ psstrmOut->SlotAt(islot)->ZapPosition();
+
+ m_fAttachMod = false;
+ m_fShiftMod = false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ The shift attribute of a slot has been modified. Make sure any slots that are part of the
+ same attachment cluster are local to this stream. The reason for this is so that the
+ position calculations stay consistent within the stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::EnsureLocalAttachmentTree(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis)
+{
+ if (m_dislotRootFixed)
+ {
+ GrSlotState * pslotRoot = SlotAtOffset(psstrmOut, m_dislotRootFixed);
+ psstrmOut->EnsureLocalCopy(ptman, pslotRoot, psstrmIn);
+ pslotRoot = SlotAtOffset(psstrmOut, m_dislotRootFixed); // get the new one!
+ pslotRoot->EnsureLocalAttachmentTree(ptman, psstrmIn, psstrmOut, islotThis + m_dislotRootFixed);
+ }
+ for (size_t islot = 0; islot < m_vdislotAttLeaves.size(); islot++)
+ {
+ GrSlotState * pslotLeaf = SlotAtOffset(psstrmOut, m_vdislotAttLeaves[islot]);
+ psstrmOut->EnsureLocalCopy(ptman, pslotLeaf, psstrmIn);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ The recipient slot is being attached to the argument slot.
+ NOTE: the caller is responsible to zap the cached positions of following glyphs
+ in the stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::AttachToRoot(GrTableManager * ptman, GrSlotStream * psstrm,
+ GrSlotState * pslotNewRoot)
+{
+ GrSlotState * pslotOldRoot = (m_dislotRootFixed == 0) ?
+ NULL :
+ SlotAtOffset(psstrm, m_dislotRootFixed);
+
+ if (pslotOldRoot)
+ {
+ if (pslotOldRoot != pslotNewRoot)
+ pslotOldRoot->RemoveLeaf(m_dislotRootFixed);
+ pslotOldRoot->ZapMetricsAndPositionDownToBase(psstrm);
+ pslotOldRoot->ZapMetricsOfLeaves(psstrm);
+ }
+
+ ZapCompositeMetrics();
+
+ if (pslotNewRoot && pslotNewRoot != pslotOldRoot)
+ {
+ pslotNewRoot->AddLeaf(m_srAttachTo);
+ pslotNewRoot->ZapMetricsAndPositionDownToBase(psstrm);
+ pslotNewRoot->ZapMetricsOfLeaves(psstrm);
+ }
+
+ m_dislotRootFixed = m_srAttachTo;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the absolute position of the glyph, relative to the start of the segment,
+ in font design units.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::Position(GrTableManager * ptman,
+ GrSlotStream * psstrmOut, int * pmXPos, int * pmYPos)
+{
+ Assert(!m_fAttachMod); // the attachment tree should be set up
+ Assert(!m_fShiftMod);
+
+ float xsWidth, xsVisWidth;
+ if (m_xsPositionX == kNegInfFloat || m_ysPositionY == kNegInfFloat)
+ ptman->CalcPositionsUpTo(psstrmOut->m_ipass, this, &xsWidth, &xsVisWidth);
+
+ *pmXPos = ptman->LogToEmUnits(m_xsPositionX);
+ *pmYPos = ptman->LogToEmUnits(m_ysPositionY);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Recalculate the metrics for this slot, which has attachments on it (or possibly
+ did in the past).
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::AdjustRootMetrics(GrTableManager * ptman, GrSlotStream * psstrm)
+{
+ Assert(m_dislotRootFixed == m_srAttachTo);
+ GrSlotState * pslotRoot = AttachRoot(psstrm);
+ CalcRootMetrics(ptman, psstrm, kPosInfinity);
+ if (pslotRoot)
+ pslotRoot->AdjustRootMetrics(ptman, psstrm);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the composite metrics for this slot.
+
+ @param psstrm - stream for which we are calculating it
+ @param nLevel - attachment level we are asking for; kPosInifinity means all levels
+ @param fThorough - true: do a thorough recalculation; false: don't recalculate
+ metrics for leaves (are they assumed to be accurate???)
+ --currently not used
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::CalcCompositeMetrics(GrTableManager * ptman, GrSlotStream * psstrm,
+ int nLevel, bool fThorough)
+{
+ if (m_nCompositeLevel == nLevel)
+ return;
+
+ if (fThorough)
+ {
+ Assert(m_dislotRootFixed == m_srAttachTo);
+ GrSlotState * pslotRoot = AttachRoot(psstrm);
+
+ InitMetrics(ptman, pslotRoot);
+
+ for (size_t islot = 0; islot < m_vdislotAttLeaves.size(); islot++)
+ {
+ GrSlotState * pslotLeaf = SlotAtOffset(psstrm, m_vdislotAttLeaves[islot]);
+ if (pslotLeaf->AttachLevel() <= nLevel)
+ pslotLeaf->CalcCompositeMetrics(ptman, psstrm, nLevel, fThorough);
+ else
+ // this slot will be ignored in the composite metrics
+ pslotLeaf->ZapRootMetrics();
+ }
+ CalcRootMetrics(ptman, psstrm, nLevel);
+
+ m_nCompositeLevel = nLevel;
+ }
+ else
+ {
+ Assert(false); // for now
+
+ // Don't bother with the leaves.
+ InitRootMetrics(ptman);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the metrics for this node and all its leaf nodes.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::CalcRootMetrics(GrTableManager * ptman, GrSlotStream * psstrm, int nLevel)
+{
+ for (size_t idislot = 0; idislot < m_vdislotAttLeaves.size(); idislot++)
+ {
+ GrSlotState * pslot = SlotAtOffset(psstrm, m_vdislotAttLeaves[idislot]);
+ if (pslot->AttachLevel() > nLevel)
+ continue;
+
+ m_xsClusterXOffset = min(m_xsClusterXOffset, pslot->m_xsClusterXOffset);
+ if (!pslot->m_fIgnoreAdvance)
+ {
+ m_xsClusterAdv = max(
+ m_xsClusterAdv,
+ pslot->m_xsClusterAdv + m_xsRootShiftX);
+ }
+ m_xsClusterBbLeft = min(m_xsClusterBbLeft, pslot->m_xsClusterBbLeft);
+ m_xsClusterBbRight = max(m_xsClusterBbRight, pslot->m_xsClusterBbRight);
+ m_ysClusterBbTop = max(m_ysClusterBbTop, pslot->m_ysClusterBbTop);
+ m_ysClusterBbBottom = min(m_ysClusterBbBottom, pslot->m_ysClusterBbBottom);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reset the cluster metrics of this slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::InitMetrics(GrTableManager * ptman, GrSlotState * pslotRoot)
+{
+ InitLeafMetrics(ptman, pslotRoot);
+ InitRootMetrics(ptman);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the variables that store the offsets of just this node (ignoring any of its
+ leaves) relative to the cluster base.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::InitLeafMetrics(GrTableManager * ptman, GrSlotState * pslotRoot)
+{
+ float xsShiftX = ptman->EmToLogUnits(ShiftX());
+ float ysShiftY = ptman->EmToLogUnits(ShiftY());
+
+ if (ptman->RightToLeft())
+ xsShiftX *= -1;
+
+ if (IsBase())
+ {
+ // The x-value below has to be zero because the shift is incorporated into
+ // m_xsRootShiftX. (m_ysRootShiftY, on the other hand, isn't used anywhere.)
+ m_xsOffsetX = 0;
+ m_ysOffsetY = ysShiftY;
+
+ m_xsRootShiftX = xsShiftX;
+ m_ysRootShiftY = ysShiftY;
+ Assert(!IsLineBreak(ptman->LBGlyphID())
+ || (m_xsRootShiftX == 0 && m_ysRootShiftY == 0));
+ return;
+ }
+
+ Assert(!IsLineBreak(ptman->LBGlyphID()));
+
+ // Hint-adjusted logical coordinates equivalent to attach.at and attach.with attributes.
+ // If attach.at or attach.with attributes were unset, the defaults for a side-by-side
+ // attachment should have been supplied in HandleModifiedPosition().
+ float xsAttAtX, ysAttAtY, xsAttWithX, ysAttWithY;
+ AttachLogUnits(ptman, pslotRoot, &xsAttAtX, &ysAttAtY, &xsAttWithX, &ysAttWithY);
+
+ m_xsOffsetX = xsAttAtX - xsAttWithX;
+ m_xsOffsetX += pslotRoot->m_xsOffsetX;
+ m_xsOffsetX += xsShiftX;
+
+ m_ysOffsetY = ysAttAtY - ysAttWithY;
+ m_ysOffsetY += pslotRoot->m_ysOffsetY;
+ m_ysOffsetY += ysShiftY;
+
+ // Cumulative effect of shifts on this and all base nodes:
+ m_xsRootShiftX = pslotRoot->m_xsRootShiftX + xsShiftX;
+ m_ysRootShiftY = pslotRoot->m_ysRootShiftY + ysShiftY;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the variables that store the offsets of this node taking into account its
+ leaves; these are relative to the cluster base.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::InitRootMetrics(GrTableManager * ptman)
+{
+ if (IsLineBreak(ptman->LBGlyphID()))
+ {
+ m_fIgnoreAdvance = true;
+ m_xsClusterXOffset = 0;
+ m_xsClusterAdv = 0;
+ m_xsClusterBbLeft = 0;
+ m_xsClusterBbRight = 0;
+ m_ysClusterBbTop = 0;
+ m_ysClusterBbBottom = 0;
+ return;
+ }
+
+ float xsAdvanceX = ptman->EmToLogUnits(AdvanceX(ptman));
+
+ // If the glyph's advance width is zero, then we NEVER want it to have any affect,
+ // even if the glyph is attached way out to the right of its base's advance.
+ m_fIgnoreAdvance = (xsAdvanceX == 0);
+
+ float xsBbLeft = GlyphMetricLogUnits(ptman, kgmetBbLeft);
+ float xsBbRight = GlyphMetricLogUnits(ptman, kgmetBbRight);
+ float ysBbTop = GlyphMetricLogUnits(ptman, kgmetBbTop);
+ float ysBbBottom = GlyphMetricLogUnits(ptman, kgmetBbBottom);
+
+ // Any shifts should be ignored for the sake of calculating actual position or width,
+ // hence we subtract the cumulative effect of the shifts.
+ m_xsClusterXOffset = m_xsOffsetX - m_xsRootShiftX;
+ m_xsClusterAdv = m_xsOffsetX + xsAdvanceX - m_xsRootShiftX;
+
+ m_xsClusterBbLeft = m_xsOffsetX + xsBbLeft;
+ m_xsClusterBbRight = m_xsOffsetX + xsBbRight;
+ m_ysClusterBbTop = m_ysOffsetY + ysBbTop;
+ m_ysClusterBbBottom = m_ysOffsetY + ysBbBottom;
+}
+
+/*----------------------------------------------------------------------------------------------
+ X-offset of a single glyph relative to the previous advance position.
+----------------------------------------------------------------------------------------------*/
+float GrSlotState::GlyphXOffset(GrSlotStream * psstrm, float fakeItalicRatio)
+{
+ float xsRet = Base(psstrm)->ClusterRootOffset() + m_xsOffsetX;
+
+ // fake an italic slant
+ xsRet += m_ysOffsetY * fakeItalicRatio;
+
+ return xsRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Y-offsets of a single glyph relative to the previous advance position.
+----------------------------------------------------------------------------------------------*/
+float GrSlotState::GlyphYOffset(GrSlotStream * psstrm)
+{
+ return m_ysOffsetY;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the offset of the last leaf of the cluster, relative to this slot, which is
+ the base. Return kNegInfinity if there are not enough slots in the stream to tell.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::LastLeafOffset(GrSlotStream * psstrm)
+{
+ int islotRet = 0;
+ for (size_t idislot = 0; idislot < m_vdislotAttLeaves.size(); idislot++)
+ {
+ int dislot = m_vdislotAttLeaves[idislot];
+ Assert(dislot != 0);
+ if (!psstrm->HasSlotAtPosPassIndex(PosPassIndex() + dislot))
+ return kNegInfinity;
+ GrSlotState * pslotLeaf = SlotAtOffset(psstrm, dislot);
+ int islotTmp = pslotLeaf->LastLeafOffset(psstrm);
+ if (islotTmp == kNegInfinity)
+ return kNegInfinity;
+ islotRet = max(islotRet, (dislot + islotTmp));
+ }
+ return islotRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the attach positions in the device context's logical units,
+ adjusted for hinting if possible.
+
+ Note that m_nAttachAt/WithGpoint = 0 is always an invalid value (resulting from a
+ glyph attribute that was defined in terms of x/y coordinates that didn't map to an
+ actual on-curve point). Therefore the x/y coordinates should be used to do the
+ attachment. In the case where we actually want point #0 on the curve,
+ m_nAttachAt/WithGpoint will have the special value 'kGpointZero' (the glyph attribute
+ is defined this way).
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::AttachLogUnits(GrTableManager * ptman, GrSlotState * pslotRoot,
+ float * pxsAttAtX, float * pysAttAtY,
+ float * pxsAttWithX, float * pysAttWithY)
+{
+ if (m_nAttachAtGpoint == kNotYetSet || m_nAttachAtGpoint == 0)
+ {
+ // Use x- and y-coordinates; no adjustment for hinting is done.
+ int mX = m_mAttachAtX + m_mAttachAtXOffset;
+ int mY = m_mAttachAtY + m_mAttachAtYOffset;
+
+ *pxsAttAtX = ptman->EmToLogUnits(mX);
+ *pysAttAtY = ptman->EmToLogUnits(mY);
+ }
+ else
+ {
+ // Look up the actual on-curve point.
+ int nGpoint = m_nAttachAtGpoint;
+ if (nGpoint == kGpointZero)
+ nGpoint = 0;
+ bool fImpl = ptman->GPointToXY(pslotRoot->GlyphID(), nGpoint, pxsAttAtX, pysAttAtY);
+
+ // Debuggers:
+ //int mXTmpAt = m_mAttachAtX + m_mAttachAtXOffset;
+ //int mYTmpAt = m_mAttachAtY + m_mAttachAtYOffset;
+ //int xsAttAtXTmp = ptman->EmToLogUnits(mXTmpAt);
+ //int ysAttAtYTmp = ptman->EmToLogUnits(mYTmpAt);
+ //fImpl = false;
+
+ if (!fImpl)
+ {
+ // Fall back to using x- and y-coordinates; no adjustment for hinting.
+ int mX = m_mAttachAtX + m_mAttachAtXOffset;
+ int mY = m_mAttachAtY + m_mAttachAtYOffset;
+ *pxsAttAtX = ptman->EmToLogUnits(mX);
+ *pysAttAtY = ptman->EmToLogUnits(mY);
+ }
+ else
+ {
+ // Adjust by offsets.
+ *pxsAttAtX += ptman->EmToLogUnits(m_mAttachAtXOffset);
+ *pysAttAtY += ptman->EmToLogUnits(m_mAttachAtYOffset);
+ }
+ }
+
+ if (m_nAttachWithGpoint == kNotYetSet || m_nAttachWithGpoint == 0)
+ {
+ // Use x- and y-coordinates; no adjustment for hinting is done.
+ int mX = m_mAttachWithX + m_mAttachWithXOffset;
+ int mY = m_mAttachWithY + m_mAttachWithYOffset;
+
+ *pxsAttWithX = ptman->EmToLogUnits(mX);
+ *pysAttWithY = ptman->EmToLogUnits(mY);
+ }
+ else
+ {
+ // Look up the actual on-curve point.
+ int nGpoint = m_nAttachWithGpoint;
+ if (nGpoint == kGpointZero)
+ nGpoint = 0;
+ bool fImpl = ptman->GPointToXY(m_chwGlyphID, nGpoint, pxsAttWithX, pysAttWithY);
+
+ // Debuggers:
+ //int mXTmpWith = m_mAttachWithX + m_mAttachWithXOffset;
+ //int mYTmpWith = m_mAttachWithY + m_mAttachWithYOffset;
+ //int xsAttWithXTmp = ptman->EmToLogUnits(mXTmpWith);
+ //int ysAttWithYTmp = ptman->EmToLogUnits(mYTmpWith);
+ //fImpl = false;
+
+ if (!fImpl)
+ {
+ // Fall back to using x- and y-coordinates; no adjustment for hinting.
+ int mX = m_mAttachWithX + m_mAttachWithXOffset;
+ int mY = m_mAttachWithY + m_mAttachWithYOffset;
+ *pxsAttWithX = ptman->EmToLogUnits(mX);
+ *pysAttWithY = ptman->EmToLogUnits(mY);
+ }
+ else
+ {
+ // Adjust by offsets.
+ *pxsAttWithX += ptman->EmToLogUnits(m_mAttachWithXOffset);
+ *pysAttWithY += ptman->EmToLogUnits(m_mAttachWithYOffset);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the slot that is 'dislot' slots away from this slot in the given stream.
+ Only valid for streams that are the input to or output of positioning passes.
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotState::SlotAtOffset(GrSlotStream * psstrm, int dislot)
+{
+ Assert(psstrm->m_fUsedByPosPass);
+ return psstrm->SlotAtPosPassIndex(PosPassIndex() + dislot);
+}
+
+/*----------------------------------------------------------------------------------------------
+ If the direction level has not been calculated at this point, assume it is the
+ top direction. This should only happen if there was no bidi pass to set it.
+ This method should only be called by the positioning passes; it assumes any bidi
+ pass has been run.
+----------------------------------------------------------------------------------------------*/
+int GrSlotState::PostBidiDirLevel(GrTableManager * ptman)
+{
+ if (m_nDirLevel == -1)
+ {
+ Assert(!ptman->HasBidiPass());
+ return ptman->TopDirectionLevel();
+ }
+ return m_nDirLevel;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if this glyph represents a LRM code.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotState::IsLrm()
+{
+ if (PassModified() == 0)
+ return (m_nUnicode == knLRM);
+ return m_pslotPrevState->IsLrm();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if this glyph represents a RLM code.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotState::IsRlm()
+{
+ if (PassModified() == 0)
+ return (m_nUnicode == knRLM);
+ return m_pslotPrevState->IsRlm();
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Used by GlyphInfo
+----------------------------------------------------------------------------------------------*/
+//float GrSlotOutput::AdvanceX(Segment * pseg)
+//{
+// return pseg->EmToLogUnits(m_mAdvanceX);
+//}
+//float GrSlotOutput::AdvanceY(Segment * pseg)
+//{
+// return pseg->EmToLogUnits(m_mAdvanceY);
+//}
+float GrSlotOutput::MaxStretch(Segment * pseg, int level)
+{
+ Assert(level == 0);
+ return (level == 0) ? pseg->EmToLogUnits(m_mJStretch0) : 0;
+}
+float GrSlotOutput::MaxShrink(Segment * pseg, int level)
+{
+ Assert(level == 0);
+ return (level == 0) ? pseg->EmToLogUnits(m_mJShrink0) : 0;
+}
+float GrSlotOutput::StretchStep(Segment * pseg, int level)
+{
+ Assert(level == 0);
+ return (level == 0) ? pseg->EmToLogUnits(m_mJStep0) : 0;
+}
+int GrSlotOutput::JustWeight(int level)
+{
+ Assert(level == 0);
+ return (level == 0) ? m_nJWeight0 : 0;
+}
+float GrSlotOutput::JustWidth(Segment * pseg, int level)
+{
+ Assert(level == 0);
+ return (level == 0) ? pseg->EmToLogUnits(m_mJWidth0) : 0;
+}
+float GrSlotOutput::MeasureSolLogUnits(Segment * pseg)
+{
+ return pseg->EmToLogUnits(m_mMeasureSol);
+}
+float GrSlotOutput::MeasureEolLogUnits(Segment * pseg)
+{
+ return pseg->EmToLogUnits(m_mMeasureEol);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Make a copy of the GrSlotOutput. This is used in making an identical copy of the segment.
+ Warning: this function will break if GrSlotState and subclasses are given virtual
+ methods. In that case, we will need to copy from the address of the first variable in
+ GrSlotAbstract.
+----------------------------------------------------------------------------------------------*/
+void GrSlotOutput::ExactCopyFrom(GrSlotOutput * pslout, u_intslot * pnVarLenBuf, int cnExtraPerSlot)
+{
+ // The chunk of the object from GrSlotAbstract can be copied exactly,
+ // except for the variable-length buffer.
+ *this = *pslout;
+ m_prgnVarLenBuf = pnVarLenBuf;
+ std::copy(pslout->m_prgnVarLenBuf, pslout->m_prgnVarLenBuf + cnExtraPerSlot,
+ m_prgnVarLenBuf);
+
+ // Now copy the stuff specific to GrSlotOutput.
+ m_ichwBeforeAssoc = pslout->m_ichwBeforeAssoc;
+ m_ichwAfterAssoc = pslout->m_ichwAfterAssoc;
+ m_cComponents = pslout->m_cComponents;
+
+ m_isloutClusterBase = pslout->m_isloutClusterBase;
+ m_disloutCluster = pslout->m_disloutCluster;
+ m_xsClusterXOffset = pslout->m_xsClusterXOffset;
+ m_xsClusterAdvance = pslout->m_xsClusterAdvance;
+ m_igbb = pslout->m_igbb;
+ m_xsAdvanceX = pslout->m_xsAdvanceX;
+// m_ysAdvanceY = pslout->m_ysAdvanceY;
+// m_rectBB = pslout->m_rectBB;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Shift the glyph to the opposite end of the segment. This is needed for white-space-only
+ segments whose direction is being changed.
+----------------------------------------------------------------------------------------------*/
+void GrSlotOutput::ShiftForDirDepthChange(float dxsSegWidth)
+{
+ float dxsShift = dxsSegWidth - m_xsAdvanceX - (2 * m_xsPositionX);
+ int tmp; tmp = (int) dxsShift;
+ m_xsPositionX += dxsShift;
+// m_rectBB.left += dxsShift;
+// m_rectBB.right += dxsShift;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the indices of all the glyphs attached to this cluster, in logical order.
+ Return an empty vector if this glyph is not the base glyph or if there are no
+ attached glyphs.
+ This method return glyph indices, not slot indices.
+----------------------------------------------------------------------------------------------*/
+void GrSlotOutput::ClusterMembers(Segment * pseg, int isloutThis, std::vector<int> & visloutRet)
+{
+ if (m_isloutClusterBase == -1 || m_isloutClusterBase == isloutThis) // yes, a base
+ pseg->ClusterMembersForGlyph(isloutThis, m_disloutCluster, visloutRet);
+ else
+ {
+ Assert(visloutRet.size() == 0);
+ }
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.h
new file mode 100644
index 00000000000..83a21bedea4
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotState.h
@@ -0,0 +1,1315 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrSlotState.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Copyright (C) 1999 by SIL International. All rights reserved.
+
+Description:
+ Classes GrSlotAbstract, GrSlotState, and GrSlotOutput
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef SLOTSTATE_INCLUDED
+#define SLOTSTATE_INCLUDED
+
+namespace gr
+{
+
+class GrSlotAbstract;
+class GrSlotState;
+class GrSlotOutput;
+class GrSlotStream;
+class Font;
+
+//:End Ignore
+
+
+/*----------------------------------------------------------------------------------------------
+ Subsumes GrSlotState and GrSlotOutput, both of which represent a single glyph
+ and its slot attributes and features.
+
+ Hungarian: slab
+----------------------------------------------------------------------------------------------*/
+class GrSlotAbstract
+{
+ friend class GrSlotStream;
+ friend class GlyphInfo;
+
+public:
+ // Constructor:
+ GrSlotAbstract()
+ {
+ }
+
+ virtual ~GrSlotAbstract()
+ {
+ // the table manager is responsible for destroying the contents of m_prgnVarLenBuf
+ }
+
+ void BasicInitializeAbstract(int cnCompPerLig, u_intslot * pnBuf)
+ {
+ m_dirc = kNotYetSet8;
+ m_lb = kNotYetSet8;
+ m_fInsertBefore = true;
+ m_nDirLevel = -1;
+
+ m_bIsSpace = -1; // unknown
+
+ m_fInsertBefore = true;
+
+ m_mMeasureSol = 0;
+ m_mMeasureEol = 0;
+
+ m_mJStretch0 = 0;
+ m_mJShrink0 = 0;
+ m_mJStep0 = 0;
+ m_nJWeight0 = 0;
+ m_mJWidth0 = 0;
+
+ m_cnCompPerLig = byte(cnCompPerLig);
+ m_prgnVarLenBuf = pnBuf;
+ }
+
+ void CopyAbstractFrom(GrSlotState * pslot);
+
+ void SetBufferPtr(u_intslot * pn)
+ {
+ m_prgnVarLenBuf = pn;
+ }
+
+ gid16 GlyphID() { return m_chwGlyphID; }
+ gid16 RawActualGlyph() { return m_chwActual; }
+ virtual float GetGlyphMetric(Font * pfont, int nGlyphMetricID, gid16 chwGlyphID);
+
+protected:
+ void GetGlyphMetricAux(Font * pfont, gid16 chwGlyphID,
+ float & xysGlyphX, float & xysGlyphY,
+ float & xysGlyphWidth, float & xysGlyphHeight, float & xysAdvX, float & xysAdvY,
+ sdata8 & bIsSpace);
+
+public:
+
+ //GrSlotState * CompRefSlot(int i);
+
+ int BreakWeight()
+ {
+ return (int)m_lb;
+ }
+ DirCode Directionality()
+ {
+ return DirCode(int(m_dirc));
+ }
+ int InsertBefore()
+ {
+ return m_fInsertBefore;
+ }
+ int MeasureSol()
+ {
+ return m_mMeasureSol;
+ }
+ int MeasureEol()
+ {
+ return m_mMeasureEol;
+ }
+
+ int DirLevel()
+ {
+ return m_nDirLevel;
+ }
+
+ int SpecialSlotFlag()
+ {
+ return m_spsl;
+ }
+ void SetSpecialSlotFlag(int spsl)
+ {
+ m_spsl = sdata8(spsl);
+ }
+
+ enum {
+ kNotYetSet = 0x7FFF,
+ kNotYetSet8 = 0x7F,
+ kInvalidGlyph = 0xFFFF
+ };
+
+ gid16 ActualGlyphForOutput(GrTableManager * ptman);
+
+ // Needed for GlyphInfo:
+ float XPosition()
+ {
+ return m_xsPositionX;
+ }
+ float YPosition()
+ {
+ return m_ysPositionY; // relative to baseline (positive is up)
+ }
+
+protected:
+ gid16 m_chwGlyphID;
+ gid16 m_chwActual; // actual glyph to output (which is a different glyph for pseudos)
+
+ sdata8 m_spsl; // special slot flag: LB, bidi marker
+
+// bool m_fInitialLB; // for LB slots: true if this is the initial LB;
+ // false if it is the terminating LB
+ // TODO: remove
+
+ sdata8 m_dirc; // default = kNotYetSet8 (read from glyph attr)
+ sdata8 m_lb; // default = kNotYetSet8 (read from glyph attr)
+
+ sdata8 m_nDirLevel;
+
+ // Slot attributes that are used by GrSlotOutput:
+ short m_mMeasureSol;
+ short m_mMeasureEol;
+
+ unsigned short m_mJStretch0;
+ unsigned short m_mJShrink0;
+ unsigned short m_mJStep0;
+ int m_mJWidth0;
+ byte m_nJWeight0;
+
+ bool m_fInsertBefore; // default = true
+
+ sdata8 m_bIsSpace; // 0 = false, 1 = true, -1 = unknown
+
+ byte m_cnCompPerLig;
+ // There is a large block managed by either the GrTableManager (for GrSlotState)
+ // or the segment (for GrSlotOutput); this variable points at the sub-buffer for this
+ // particular slot:
+ u_intslot * m_prgnVarLenBuf;
+
+ float m_xsPositionX;
+ float m_ysPositionY;
+
+}; // end of class GrSlotAbstract
+
+
+/*----------------------------------------------------------------------------------------------
+ A GrSlotState represents one slot as modified by a pass in the table.
+ Each time a slot state is modified, a new instance is created, copying the relevant
+ information.
+
+ Hungarian: slot
+
+ Other hungarian:
+ m - integer indicating glyph design units ("em-units")
+ sr - integer indicating slot reference
+----------------------------------------------------------------------------------------------*/
+class GrSlotState : public GrSlotAbstract
+{
+
+ friend class GrSlotStream;
+ friend class FontMemoryUsage;
+
+public:
+ enum { kNeutral = 99 };
+
+ // Constructors:
+ GrSlotState()
+ : GrSlotAbstract(),
+ m_pslotPrevState(NULL)
+ {
+ m_vpslotAssoc.clear();
+ //m_fInitialLB = false; // TODO: remove
+ m_spsl = kspslNone;
+ m_fNeutralAssocs = false;
+ m_dircProc = kdircUnknown;
+ m_fDirProcessed = false;
+
+ m_vdislotAttLeaves.clear();
+ m_fAttachMod = false;
+ m_fShiftMod = false;
+ m_dislotRootFixed = 0;
+ ZapCompositeMetrics();
+ }
+
+ virtual ~GrSlotState()
+ {
+ }
+
+ void BasicInitialize(int cnUserDefn, int cnCompPerLig, int cnFeat, u_intslot * pnBuf)
+ {
+ BasicInitializeAbstract(cnCompPerLig, pnBuf);
+
+ m_mAdvanceX = kNotYetSet;
+ m_mAdvanceY = kNotYetSet;
+ m_mShiftX = 0;
+ m_mShiftY = 0;
+
+ m_fAdvXSet = false; // for transduction logging
+ m_fAdvYSet = false;
+
+ m_srAttachTo = 0;
+ m_nAttachLevel = 0;
+
+ m_mAttachAtX = kNotYetSet;
+ m_mAttachAtY = 0;
+ m_nAttachAtGpoint = kNotYetSet;
+ m_mAttachAtXOffset = 0;
+ m_mAttachAtYOffset = 0;
+ m_mAttachWithX = kNotYetSet;
+ m_mAttachWithY = 0;
+ m_nAttachWithGpoint = kNotYetSet;
+ m_mAttachWithXOffset = 0;
+ m_mAttachWithYOffset = 0;
+
+ m_islotPosPass = kNotYetSet;
+
+ m_cnUserDefn = byte(cnUserDefn);
+ m_cnFeat = byte(cnFeat);
+
+ m_fHasComponents = false;
+
+ m_xysFontAscent = kNegInfFloat;
+ m_xysFontDescent = kNegInfFloat;
+ m_xysGlyphWidth = kNegInfFloat;
+ m_xysGlyphHeight = kNegInfFloat;
+ m_xysGlyphX = kNegInfFloat;
+ m_xysGlyphY = kNegInfFloat;
+ m_xysAdvX = kNegInfFloat;
+ m_xysAdvY = kNegInfFloat;
+ }
+
+ void Initialize(gid16 chw, GrEngine *, GrFeatureValues fval,
+ int ipass, int ichwSegOffset, int nUnicode = -1);
+ void Initialize(gid16 chw, GrEngine *, GrSlotState * pslotFeat,
+ int ipass, int ichwSegOffset);
+ void Initialize(gid16 chw, GrEngine *, GrSlotState * pslotFeat,
+ int ipass);
+
+ void InitializeFrom(GrSlotState * pslot, int ipass);
+ void CopyFeaturesFrom(GrSlotState * pslotSrc);
+ void FixAttachmentTree(GrSlotState * pslotOld);
+
+ void CopyFrom(GrSlotState * pslot, bool fCopyEverything = true);
+
+ virtual float GetGlyphMetric(Font * pfont, int nGlyphMetricID, gid16 chwGlyphID);
+
+ // General:
+ int RawSegOffset() { return m_ichwSegOffset; }
+
+ void SetGlyphID(gid16 chw)
+ {
+ m_chwGlyphID = chw;
+ m_chwActual = kInvalidGlyph;
+ m_xysGlyphWidth = kNegInfFloat; // indicate glyph metrics are invalid
+ m_ipassFsmCol = -1;
+ m_colFsm = -1;
+ }
+ int PosPassIndex()
+ {
+ return m_islotPosPass;
+ }
+ void SetPosPassIndex(int islot, bool fInputToPosPass1)
+ {
+ // If we're resetting it, it should be to the same value as before:
+ Assert(fInputToPosPass1 || m_islotPosPass == kNotYetSet || m_islotPosPass == islot);
+ m_islotPosPass = islot;
+ }
+ void IncPosPassIndex()
+ {
+ m_islotPosPass++;
+ }
+ void ZapPosPassIndex()
+ {
+ m_islotPosPass = kNotYetSet;
+ }
+
+ int StyleIndex() { return m_bStyleIndex; }
+
+ int AttachTo() { return m_srAttachTo; }
+ int AttachLevel() { return m_nAttachLevel; }
+
+ int RawAttachAtX() { return m_mAttachAtX; }
+ int AttachAtY() { return m_mAttachAtY; }
+ int AttachAtGpoint() { return m_nAttachAtGpoint; }
+ int AttachAtXOffset() { return m_mAttachAtXOffset; }
+ int AttachAtYOffset() { return m_mAttachAtYOffset; }
+
+ int RawAttachWithX() { return m_mAttachWithX; }
+ int AttachWithY() { return m_mAttachWithY; }
+ int AttachWithGpoint() { return m_nAttachWithGpoint; }
+ int AttachWithXOffset() { return m_mAttachWithXOffset; }
+ int AttachWithYOffset() { return m_mAttachWithYOffset; }
+
+ void Associate(GrSlotState *);
+ void Associate(GrSlotState *, GrSlotState *);
+ void Associate(std::vector<GrSlotState*> &);
+ void ClearAssocs();
+
+ int AssocsSize() { return m_vpslotAssoc.size(); }
+ GrSlotState * RawBeforeAssocSlot()
+ {
+ if (m_vpslotAssoc.size() == 0)
+ return NULL;
+ return m_vpslotAssoc[0];
+ }
+ GrSlotState * RawAfterAssocSlot()
+ {
+ if (m_vpslotAssoc.size() == 0)
+ return NULL;
+ return m_vpslotAssoc.back();
+ }
+ GrSlotState * AssocSlot(int i) { return m_vpslotAssoc[i]; }
+
+ void AllAssocs(std::vector<int> & vichw);
+ int BeforeAssoc();
+ int AfterAssoc();
+
+ void CleanUpAssocs();
+
+ void SetComponentRefsFor(GrSlotOutput *, int iComp = -1);
+ void AllComponentRefs(std::vector<int> & vichw, std::vector<int> & vicomp, int iComponent = -1);
+
+ int PassModified() { return m_ipassModified; }
+ int SegOffset();
+ int UnderlyingPos();
+ GrSlotState * PrevState() { return m_pslotPrevState; }
+
+ void MarkDeleted() // for now, do nothing
+ {
+ }
+
+ int IsSpace(GrTableManager * ptman);
+
+ // TODO: remove argument from these methods; it is no longer needed.
+ bool IsLineBreak(gid16 chwLB)
+ {
+ return (IsInitialLineBreak(chwLB) || IsFinalLineBreak(chwLB));
+ //return (m_chwGlyphID == chwLB); // TODO: remove
+ }
+ bool IsInitialLineBreak(gid16 chwLB)
+ {
+ return (m_spsl == kspslLbInitial);
+ //return (IsLineBreak(chwLB) && m_fInitialLB == true); // TODO: remove
+ }
+ bool IsFinalLineBreak(gid16 chwLB)
+ {
+ return (m_spsl == kspslLbFinal);
+ //return (IsLineBreak(chwLB) && m_fInitialLB == false); // TODO: remove
+ }
+
+ bool IsBidiMarker()
+ {
+ switch (m_spsl)
+ {
+ case kspslLRM:
+ case kspslRLM:
+ case kspslLRO:
+ case kspslRLO:
+ case kspslLRE:
+ case kspslRLE:
+ case kspslPDF:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool HasComponents() { return m_fHasComponents; }
+
+ // Directionality as determined by the bidi algorithm
+ DirCode DirProcessed() // return the value
+ {
+ Assert(m_dirc != kNotYetSet8);
+ if (m_dircProc == kdircUnknown)
+ m_dircProc = DirCode(m_dirc);
+ return m_dircProc;
+ }
+ void SetDirProcessed(DirCode dirc) // set the directionality
+ {
+ m_dircProc = dirc;
+ }
+ bool DirHasBeenProcessed() // has this slot been fully processed?
+ {
+ return m_fDirProcessed;
+ }
+ void MarkDirProcessed() // this slot has been fully processed
+ {
+ m_fDirProcessed = true;
+ }
+
+ int RawAdvanceX() { return m_mAdvanceX; }
+ int RawAdvanceY() { return m_mAdvanceY; }
+ int ShiftX() { return m_mShiftX; }
+ int ShiftY() { return m_mShiftY; }
+
+ // Slot attributes that must be calculated:
+
+ int AdvanceX(GrTableManager * ptman)
+ {
+ if (m_mAdvanceX == kNotYetSet)
+ // Initialize it from the glyph metric (adjusted for hinting).
+ m_mAdvanceX = short(GlyphMetricEmUnits(ptman, kgmetAdvWidth));
+ return m_mAdvanceX;
+ }
+
+ int AdvanceY(GrTableManager * ptman)
+ {
+ if (m_mAdvanceY == kNotYetSet)
+ // Initialize it from the glyph metric (adjusted for hinting).
+ m_mAdvanceY = short(GlyphMetricEmUnits(ptman, kgmetAdvHeight));
+ return m_mAdvanceY;
+ }
+
+ int AttachAtX(GrTableManager * ptman, GrSlotStream * psstrm)
+ {
+ if (m_mAttachAtX == kNotYetSet)
+ {
+ Assert(false); // Should have already been set in HandleModifiedPosition,
+ // but just in case...
+ if (m_srAttachTo == 0)
+ return 0;
+ else
+ m_mAttachAtX = short(AttachRoot(psstrm)->AdvanceX(ptman)); // attach on the right
+ }
+ return m_mAttachAtX;
+ }
+
+ int AttachWithX(GrTableManager * ptman, GrSlotStream * psstrm)
+ {
+ if (m_mAttachAtX == kNotYetSet)
+ {
+ Assert(false); // Should have already been set in HandleModifiedPosition,
+ // but just in case.
+ if (!m_srAttachTo == 0)
+ return 0;
+ else
+ m_mAttachAtX = 0; // attach on the right
+ }
+ return m_mAttachAtX;
+ }
+
+ int JStretch()
+ {
+ return m_mJStretch0;
+ }
+ int JShrink()
+ {
+ return m_mJShrink0;
+ }
+ int JStep()
+ {
+ return m_mJStep0;
+ }
+ int JWeight()
+ {
+ return m_nJWeight0;
+ }
+ int JWidth()
+ {
+ return m_mJWidth0;
+ }
+
+ // Slot attribute setters:
+
+ void SetAdvanceX(int mVal)
+ {
+ Assert(mVal < 0xFFFF); m_mAdvanceX = short(mVal & 0xFFFF); m_fShiftMod = true;
+ m_fAdvXSet = true; // for transduction logging
+ }
+ void SetAdvanceY(int mVal)
+ {
+ Assert(mVal < 0xFFFF); m_mAdvanceY = short(mVal & 0xFFFF); m_fShiftMod = true;
+ m_fAdvYSet = true; // for transduction logging
+ }
+ void SetShiftX(int mVal)
+ {
+ Assert(mVal < 0xFFFF); m_mShiftX = short(mVal & 0xFFFF);
+ m_fShiftMod = true;
+ }
+ void SetShiftY(int mVal)
+ {
+ Assert(mVal < 0xFFFF); m_mShiftY = short(mVal & 0xFFFF);
+ m_fShiftMod = true;
+ }
+
+ void SetAttachTo(int srVal)
+ {
+ Assert(srVal < 0xFFFF);
+ m_srAttachTo = short(srVal & 0xFFFF);
+ m_fAttachMod = true;
+ }
+ void SetAttachLevel(int nVal) {
+ Assert(nVal < 0xFFFF); m_nAttachLevel = short(nVal & 0xFFFF); m_fAttachMod = true; }
+
+ void SetAttachAtX(int mVal)
+ {
+ Assert(mVal < 0xFFFF);
+ m_mAttachAtX = short(mVal) & 0xFFFF;
+ m_fAttachMod = true;
+ }
+ void SetAttachAtY(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachAtY = short(mVal & 0xFFFF); m_fAttachMod = true; }
+ void SetAttachAtGpoint(int nVal) {
+ m_nAttachAtGpoint = short(nVal); m_fAttachMod = true; }
+ void SetAttachAtXOffset(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachAtXOffset = short(mVal & 0xFFFF); m_fAttachMod = true; }
+ void SetAttachAtYOffset(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachAtYOffset = short(mVal & 0xFFFF); m_fAttachMod = true; }
+
+ void SetAttachWithX(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachWithX = short(mVal & 0xFFFF); m_fAttachMod = true; }
+ void SetAttachWithY(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachWithY = short(mVal & 0xFFFF); m_fAttachMod = true; }
+ void SetAttachWithGpoint(int nVal) {
+ m_nAttachWithGpoint = short(nVal); m_fAttachMod = true; }
+ void SetAttachWithXOffset(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachWithXOffset = short(mVal & 0xFFFF); m_fAttachMod = true; }
+ void SetAttachWithYOffset(int mVal) {
+ Assert(mVal < 0xFFFF); m_mAttachWithYOffset = short(mVal & 0xFFFF); m_fAttachMod = true; }
+
+ void SetCompRefSlot(GrTableManager * ptman, int i, GrSlotState * pslotComp);
+
+ void SetBreakWeight(int lb) { m_lb = sdata8(lb); }
+ void SetInsertBefore(bool f) { m_fInsertBefore = f; }
+
+ void SetDirectionality(DirCode dirc) { m_dirc = sdata8(dirc); }
+ void SetDirLevel(int n) { m_nDirLevel = sdata8(n); }
+
+ void SetMeasureSol(int mVal) { m_mMeasureSol = short(mVal); }
+ void SetMeasureEol(int mVal) { m_mMeasureEol = short(mVal); }
+
+ void SetJStretch(int mVal) { m_mJStretch0 = short(mVal); }
+ void SetJShrink(int mVal) { m_mJShrink0 = short(mVal); }
+ void SetJStep(int mVal) { m_mJStep0 = short(mVal); }
+ void SetJWeight(int nVal) { m_nJWeight0 = byte(nVal); }
+ void SetJWidth(int mVal) { m_mJWidth0 = mVal; }
+ void AddJWidthToAdvance(GrTableManager * ptman)
+ {
+ // Don't change m_fShiftMod.
+ m_mAdvanceX = short(m_mJWidth0 + AdvanceX(ptman)); // make sure it is calculated
+ m_mJWidth0 = 0;
+ m_fAdvXSet = true; // for transduction logging
+ }
+
+ int PostBidiDirLevel(GrTableManager * ptman);
+
+ bool BaseEarlierInStream();
+
+ void ZapDirLevel()
+ {
+ m_nDirLevel = -1;
+ m_dircProc = kdircUnknown;
+ m_fDirProcessed = false;
+ }
+
+ int GlyphAttrValueEmUnits(GrTableManager * ptman, int nAttrID);
+ int GlyphMetricEmUnits(GrTableManager * ptman, int nGlyphMetricID);
+
+ float GlyphAttrValueLogUnits(GrTableManager * ptman, int nAttrID);
+ float GlyphMetricLogUnits(GrTableManager * ptman, int nGlyphMetricID);
+
+// void HandleModifiedCluster(GrTableManager * ptman,
+// GrSlotStream * psstrm, int islotThis);
+ void HandleModifiedPosition(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis);
+
+ void CalcCompositeMetrics(GrTableManager * ptman, GrSlotStream * psstrm,
+ int nLevel, bool fThorough = false);
+
+ void Position(GrTableManager * ptman,
+ GrSlotStream * psstrmOut, int * pmXPos, int * pmYPos);
+
+ void ZapPosition()
+ {
+ m_xsPositionX = kNegInfFloat;
+ m_ysPositionY = kNegInfFloat;
+ }
+
+ void SetXPos(float xs)
+ {
+ m_xsPositionX = xs;
+ }
+ void SetYPos(float ys)
+ {
+ m_ysPositionY = ys; // relative to baseline (positive is up)
+ }
+
+ float ClusterRootOffset() { return -m_xsClusterXOffset; } // the offset of the root
+ // relative to the whole cluster
+
+ float ClusterAdvWidthFrom(float xs) { return xs + m_xsClusterAdv; }
+ float ClusterBbLeftFrom(float xs) { return xs + m_xsClusterBbLeft; }
+ float ClusterBbRightFrom(float xs) { return xs + m_xsClusterBbRight; }
+
+ float ClusterLsb(GrSlotStream * psstrm, float xs)
+ {
+ return ClusterBbLeft(psstrm) + xs;
+ }
+ float ClusterRsb(GrSlotStream * psstrm, float xs)
+ {
+ return ClusterAdvWidthFrom(xs) - ClusterBbRightFrom(xs);
+ }
+
+ float ClusterAdvWidth(GrSlotStream * psstrm)
+ {
+ return ClusterAdvWidthFrom(Base(psstrm)->ClusterRootOffset());
+ }
+// int ClusterAdvHeight(GrSlotStream * psstrm)
+// {
+// Assert(m_mAdvanceY != kNotYetSet);
+// return EmUnitsToTwips(m_mAdvanceY);
+// }
+ float ClusterBbLeft(GrSlotStream * psstrm)
+ {
+ return ClusterBbLeftFrom(Base(psstrm)->ClusterRootOffset());
+ }
+ float ClusterBbRight(GrSlotStream * psstrm)
+ {
+ return ClusterBbRightFrom(Base(psstrm)->ClusterRootOffset());
+ }
+ float ClusterBbTop(GrSlotStream * psstrm)
+ {
+ return m_ysClusterBbTop;
+ }
+ float ClusterBbBottom(GrSlotStream * psstrm)
+ {
+ return m_ysClusterBbBottom;
+ }
+ float ClusterBbWidth(GrSlotStream * psstrm)
+ {
+ return m_xsClusterBbRight - m_xsClusterBbLeft + 1;
+ }
+ float ClusterBbHeight(GrSlotStream * psstrm)
+ {
+ return m_ysClusterBbTop - m_ysClusterBbBottom + 1;
+ }
+ float ClusterLsb(GrSlotStream * psstrm)
+ {
+ return ClusterBbLeft(psstrm);
+ }
+ float ClusterRsb(GrSlotStream * psstrm)
+ {
+ return ClusterAdvWidth(psstrm) - ClusterBbRight(psstrm);
+ }
+
+ float GlyphXOffset(GrSlotStream * psstrm, float fakeItalicRatio = 0);
+ float GlyphYOffset(GrSlotStream * psstrm = NULL);
+
+ bool IsBase()
+ {
+ Assert(m_dislotRootFixed == m_srAttachTo);
+ return (m_dislotRootFixed == 0);
+ }
+
+ bool HasClusterMembers()
+ {
+ return (m_vdislotAttLeaves.size() > 0);
+ }
+
+ GrSlotState * AttachRoot(GrSlotStream * psstrm)
+ {
+ if (m_srAttachTo == 0)
+ return NULL;
+ else
+ return SlotAtOffset(psstrm, m_srAttachTo);
+ }
+
+ int AttachRootPosPassIndex()
+ {
+ return PosPassIndex() + m_srAttachTo;
+ }
+
+ GrSlotState * Base(GrSlotStream * psstrm)
+ {
+ GrSlotState * pslotRoot = AttachRoot(psstrm);
+ if (!pslotRoot)
+ return this;
+ else
+ return pslotRoot->Base(psstrm);
+ }
+
+ int LastLeafOffset(GrSlotStream * psstrm);
+
+ void AddLeaf(int dislot)
+ {
+ m_vdislotAttLeaves.push_back(dislot * -1);
+ }
+ void RemoveLeaf(int dislot)
+ {
+ for (size_t iislot = 0; iislot < m_vdislotAttLeaves.size(); iislot++)
+ {
+ if (m_vdislotAttLeaves[iislot] == dislot * -1)
+ {
+ m_vdislotAttLeaves.erase(m_vdislotAttLeaves.begin() + iislot);
+ return;
+ }
+ }
+ Assert(false);
+ }
+
+ bool HasAsRoot(GrSlotStream * psstrm, GrSlotState * pslot)
+ {
+ GrSlotState * pslotRoot = AttachRoot(psstrm);
+ if (pslotRoot == pslot)
+ return true;
+ else if (pslotRoot == NULL)
+ return false;
+ else
+ return pslotRoot->HasAsRoot(psstrm, pslot);
+ }
+
+ bool HasAsPreviousState(GrSlotState * pslot)
+ {
+ if (this == pslot)
+ return true;
+ else
+ return m_pslotPrevState->HasAsPreviousState(pslot);
+ }
+
+ void EnsureCacheForOutput(GrTableManager * ptman);
+
+ bool IsLrm();
+ bool IsRlm();
+
+ // Cache of FSM column information for the most recent pass:
+ int FsmColumn() { return m_colFsm; }
+ int PassNumberForColumn() { return m_ipassFsmCol; }
+ void CacheFsmColumn(int ipass, int col)
+ {
+ m_colFsm = col;
+ m_ipassFsmCol = ipass;
+ }
+
+ // Variable-length buffer--includes four sub-buffers:
+ // * user-defined variables
+ // * component.???.ref assignments
+ // * mapping from components used to global attribute IDs for components
+ // * feature values
+
+ // user-defined slot attributes
+ int UserDefn(int slati)
+ {
+ Assert(slati < m_cnUserDefn);
+ return m_prgnVarLenBuf[slati].nValue;
+ }
+ void SetUserDefn(int slati, int nVal)
+ {
+ Assert(slati < m_cnUserDefn);
+ m_prgnVarLenBuf[slati].nValue = nVal;
+ }
+ u_intslot * PUserDefnBuf()
+ {
+ return m_prgnVarLenBuf;
+ }
+
+ // pointer to the associated slot which is the value of the comp.ref attribute
+ GrSlotState * CompRef(int slati)
+ {
+ Assert(slati < m_cnCompPerLig);
+ return m_prgnVarLenBuf[m_cnUserDefn + slati].pslot;
+ }
+ void SetCompRef(int slati, GrSlotState * pvSlot)
+ {
+ Assert(slati < m_cnCompPerLig);
+ m_prgnVarLenBuf[m_cnUserDefn + slati].pslot = pvSlot;
+ }
+ u_intslot * PCompRefBuf()
+ {
+ return m_prgnVarLenBuf + m_cnUserDefn;
+ }
+
+ // global component identifier
+ int Slati(int i)
+ {
+ Assert(i < m_cnCompPerLig);
+ return m_prgnVarLenBuf[m_cnUserDefn + m_cnCompPerLig + i].nValue;
+ }
+ void SetSlati(int i, int n)
+ {
+ Assert(i < m_cnCompPerLig);
+ m_prgnVarLenBuf[m_cnUserDefn + m_cnCompPerLig + i].nValue = n;
+ }
+ u_intslot * PSlatiBuf()
+ {
+ return m_prgnVarLenBuf + m_cnUserDefn + m_cnCompPerLig;
+ }
+
+ // feature settings
+ int FeatureValue(int i)
+ {
+ Assert(i < m_cnFeat);
+ return m_prgnVarLenBuf[m_cnUserDefn + (m_cnCompPerLig * 2) + i].nValue;
+ }
+
+ u_intslot * PFeatureBuf()
+ {
+ return m_prgnVarLenBuf + m_cnUserDefn + (m_cnCompPerLig * 2);
+ }
+
+ int CExtraSpace()
+ {
+ return m_cnUserDefn + (m_cnCompPerLig * 2) + m_cnFeat;
+ }
+
+ GrSlotState * CompRefSlot(int i);
+
+ void GetFeatureValues(GrFeatureValues * pfval)
+ {
+ pfval->m_nStyleIndex = m_bStyleIndex;
+ std::fill(pfval->m_rgnFValues, pfval->m_rgnFValues + kMaxFeatures, 0);
+ for (size_t i = 0; i < m_cnFeat; i++)
+ pfval->m_rgnFValues[i] = PFeatureBuf()[i].nValue;
+ }
+
+// For transduction logging:
+#ifdef TRACING
+ void SlotAttrsModified(bool * rgfMods, bool fPreJust, int * pccomp, int * pcassoc);
+ void LogSlotAttribute(GrTableManager *, std::ostream &, int ipass, int slat, int icomp,
+ bool fPreJust, bool fPostJust);
+ void LogAssociation(GrTableManager * ptman,
+ std::ostream & strmOut, int ipass, int iassoc, bool fBoth, bool fAfter);
+ int m_islotTmpIn; // for use by transduction log; index of slot in input stream
+ int m_islotTmpOut; // ditto; index of slot in output stream
+#endif // TRACING
+
+protected:
+
+ // Instance variables:
+ int m_ipassModified; // pass in which this slot was modified
+
+ GrSlotState * m_pslotPrevState;
+
+ int m_ichwSegOffset; // for original (pass 0) slot states: position in
+ // underlying text relative to the official
+ // beginning of the segment;
+ // should == kInvalid for other slot states
+ int m_islotPosPass; // index of slot in positioning streams, relative to first official
+ // slot in the segment (possibly the LB slot)
+
+ int m_colFsm; // which FSM column this glyph corresponds to...
+ int m_ipassFsmCol; // ...for the most recent pass
+
+ std::vector<GrSlotState*> m_vpslotAssoc; // association mappings
+
+ bool m_fNeutralAssocs; // true if we've set the associations to some neutral
+ // default, rather than them being set explicitly
+ // within a rule
+
+ int m_nUnicode; // for debugging
+
+ DirCode m_dircProc; // directionality as processed in bidi algorithm
+ bool m_fDirProcessed;
+
+ // affects length of variable-length buffer
+ byte m_cnUserDefn;
+ byte m_cnFeat;
+
+ byte m_bStyleIndex;
+
+ // Slot attributes:
+ short m_mAdvanceX;
+ short m_mAdvanceY;
+ short m_mShiftX;
+ short m_mShiftY;
+
+ short m_srAttachTo;
+ short m_nAttachLevel;
+
+ short m_mAttachAtX;
+ short m_mAttachAtY;
+ short m_mAttachAtXOffset;
+ short m_mAttachAtYOffset;
+ short m_mAttachWithX;
+ short m_mAttachWithY;
+ short m_mAttachWithXOffset;
+ short m_mAttachWithYOffset;
+
+ short m_nAttachAtGpoint;
+ short m_nAttachWithGpoint;
+
+ // Raw glyph metrics (directly from font)
+ float m_xysFontAscent;
+ float m_xysFontDescent;
+ float m_xysGlyphWidth;
+ float m_xysGlyphHeight;
+ float m_xysGlyphX;
+ float m_xysGlyphY;
+ float m_xysAdvX;
+ float m_xysAdvY;
+
+ // Attachment and metrics
+
+ // This is a flag that is set whenever we change the value of any of the attach
+ // slot attributes. Then when we want to find out something about the attachments,
+ // if it is set, we have some work to do in updating the pointers and metrics.
+ bool m_fAttachMod;
+
+ // This is a flag that is set whenever we change the value of any of the shift or
+ // advance slot attributes. It forces us to zap the metrics.
+ bool m_fShiftMod;
+
+ // This glyph (and all its leaves, if any) have a zero advance width;
+ // never allow it to affect the advance width of a cluster it is part of.
+ bool m_fIgnoreAdvance;
+
+ int m_dislotRootFixed; // the offset of the slot (relative to this one) that considers
+ // this slot to be one of its leaves
+ std::vector<int> m_vdislotAttLeaves;
+
+ // The following are used by the CalcCompositeMetrics() method and depend on
+ // the cluster level that was passed as an argument.
+
+ int m_nCompositeLevel; // cluster level last used to calculate composite metrics;
+ // kNegInfinity if uncalculated
+
+ // offsets for this node only, relative to cluster base
+ float m_xsOffsetX;
+ float m_ysOffsetY; // relative to baseline (positive is up)
+
+ // offsets for this node and its leaves, relative to cluster base (y-coords are
+ // relative to baseline)
+ float m_xsClusterXOffset;
+ float m_xsClusterAdv;
+ float m_xsClusterBbLeft;
+ float m_xsClusterBbRight;
+ float m_ysClusterBbTop;
+ float m_ysClusterBbBottom;
+
+ // cumulative total of shifts for this node and roots; advance needs to ignore these
+ float m_xsRootShiftX;
+ float m_ysRootShiftY;
+
+ bool m_fHasComponents; // default = false
+
+ // Private methods:
+
+ void CopyAbstractFrom(GrSlotState * pslot);
+
+ void AdjustRootMetrics(GrTableManager * ptman, GrSlotStream *);
+ void InitMetrics(GrTableManager * ptman, GrSlotState * pslotRoot);
+ void InitLeafMetrics(GrTableManager * ptman, GrSlotState * pslotRoot);
+ void InitRootMetrics(GrTableManager * ptman);
+ void CalcRootMetrics(GrTableManager * ptman, GrSlotStream *, int nLevel);
+ void AttachToRoot(GrTableManager * ptman, GrSlotStream *, GrSlotState * pslotNewRoot);
+ void AttachLogUnits(GrTableManager * ptman,
+ GrSlotState * pslotRoot,
+ float * pxsAttAtX, float * pysAttAtY,
+ float * pxsAttWithX, float * pysAttWithY);
+
+ GrSlotState * SlotAtOffset(GrSlotStream * psstrm, int dislot); // ENHANCE SharonC: inline?
+
+ void EnsureLocalAttachmentTree(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis);
+
+ void ZapCompositeMetrics()
+ {
+ m_nCompositeLevel = kNegInfinity;
+ m_xsPositionX = kNegInfFloat;
+ m_ysPositionY = kNegInfFloat;
+ m_xsOffsetX = 0;
+ m_ysOffsetY = 0;
+ m_xsRootShiftX = 0;
+ m_ysRootShiftY = 0;
+ ZapRootMetrics();
+ }
+
+ void ZapRootMetrics()
+ {
+ m_xsClusterXOffset = 0;
+ m_xsClusterAdv = 0;
+ m_xsClusterBbLeft = 0;
+ m_xsClusterBbRight = 0;
+ m_ysClusterBbTop = 0;
+ m_ysClusterBbBottom = 0;
+ m_fIgnoreAdvance = false;
+ }
+
+ void ZapMetricsAndPositionDownToBase(GrSlotStream * psstrm)
+ {
+ ZapCompositeMetrics();
+ if (m_dislotRootFixed)
+ SlotAtOffset(psstrm, m_dislotRootFixed)->ZapMetricsAndPositionDownToBase(psstrm);
+ }
+
+ void ZapMetricsOfLeaves(GrSlotStream * psstrm, bool fThis = false)
+ {
+ if (fThis)
+ ZapCompositeMetrics();
+ for (size_t islot = 0; islot < m_vdislotAttLeaves.size(); islot++)
+ {
+ SlotAtOffset(psstrm, m_vdislotAttLeaves[islot])->ZapMetricsOfLeaves(psstrm, true);
+ }
+ }
+
+public: // for transduction logging
+ bool m_fAdvXSet;
+ bool m_fAdvYSet;
+
+}; // end of class GrSlotState
+
+
+/*----------------------------------------------------------------------------------------------
+ A GrSlotOutput represents one slot as the final output of the final pass. These
+ are recorded in the segment.
+
+ Hungarian: slout
+----------------------------------------------------------------------------------------------*/
+class GrSlotOutput : public GrSlotAbstract
+{
+ friend class GlyphInfo;
+ friend class Segment;
+ friend class SegmentMemoryUsage;
+
+public:
+ GrSlotOutput()
+ {
+ m_cComponents = 0;
+ m_isloutClusterBase = -1; // not part of any cluster
+ m_disloutCluster = 0;
+ m_igbb = -1;
+ }
+
+ void ExactCopyFrom(GrSlotOutput * pslout, u_intslot * pnVarLenBuf, int cnExtraPerSlot);
+
+ void InitializeOutputFrom(GrSlotState * pslot);
+
+ int BeforeAssoc()
+ {
+ return m_ichwBeforeAssoc; // relative to the official beginning of the segment
+ }
+ int AfterAssoc()
+ {
+ return m_ichwAfterAssoc; // relative to the official beginning of the segment
+ }
+
+ void SetBeforeAssoc(int ichw)
+ {
+ m_ichwBeforeAssoc = ichw;
+ }
+ void SetAfterAssoc(int ichw)
+ {
+ m_ichwAfterAssoc = ichw;
+ }
+
+ //u_intslot * PCompRefBufSlout()
+ //{
+ // return m_prgnVarLenBuf;
+ //}
+ int CExtraSpaceSlout()
+ {
+ return (m_cnCompPerLig * 2);
+ }
+
+ int IbufUnderlyingCompOffset()
+ {
+ return 0;
+ }
+ int IbufCompIdOffset()
+ {
+ return m_cnCompPerLig;
+ }
+
+ void AddComponentReference(int ichw, int slati)
+ {
+ short ichw16 = short(ichw);
+ if (m_cComponents >= m_cnCompPerLig)
+ {
+ Assert(false); // too many--ignore the requested component ref
+ }
+ else
+ {
+ int iComp;
+ for (iComp = 0; iComp < m_cComponents; iComp++)
+ {
+ if (ComponentId(iComp) == slati)
+ {
+ // We already have at least one character for this component. Add another.
+ if (m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[0] > ichw16)
+ m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[0] = ichw16; // min
+ if (m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[1] < ichw16)
+ m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[1] = ichw16; // max
+ return;
+ }
+ }
+
+ iComp = m_cComponents;
+
+ m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[0] = ichw16; // min
+ m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[1] = ichw16; // max
+
+ // OBSOLETE comment:
+ // Maps the used components to the defined components. Normally this will be
+ // one-to-one and the buffer will hold [0,1,2...]. But possibly we may
+ // have defined components a, b, and c, but only mapped a and c to actual
+ // characters. This buffer will then hold [0,2].
+
+ m_prgnVarLenBuf[IbufCompIdOffset() + iComp].nValue = slati;
+
+// Assert(iComp >= m_cComponents); // because we process them in order they are defined
+ // in, but we could have skipped some that are
+ // defined
+ m_cComponents++;
+ }
+ }
+ int NumberOfComponents() // the number used by the rules
+ {
+ return m_cComponents;
+ }
+ // Index of ligature components, relative to the beginning of the segment.
+ // iComp is index of components USED in this glyph.
+ int FirstUnderlyingComponent(int iComp)
+ {
+ Assert(iComp < m_cnCompPerLig);
+ int ichw = m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[0];
+ return ichw;
+ }
+ int LastUnderlyingComponent(int iComp)
+ {
+ Assert(iComp < m_cnCompPerLig);
+ int ichw = m_prgnVarLenBuf[IbufUnderlyingCompOffset() + iComp].smallint[1];
+ return ichw;
+ }
+ int ComponentId(int iComp)
+ {
+ return m_prgnVarLenBuf[IbufCompIdOffset() + iComp].nValue;
+ }
+
+ void SetClusterBase(int islout)
+ {
+ m_isloutClusterBase = islout;
+ }
+
+ int ClusterBase()
+ {
+ return m_isloutClusterBase;
+ }
+
+ bool IsPartOfCluster()
+ {
+ return (m_isloutClusterBase > -1);
+ }
+
+ //int NumClusterMembers()
+ //{
+ // return m_visloutClusterMembers.size();
+ //}
+ //int ClusterMember(int iislout)
+ //{
+ // return m_visloutClusterMembers[iislout];
+ //}
+
+ void AddClusterMember(int isloutThis, int isloutAttached)
+ {
+ m_disloutCluster = sdata8(max(int(m_disloutCluster), abs(isloutThis - isloutAttached)));
+ }
+
+ void ClusterMembers(Segment * pseg, int islout, std::vector<int> & visloutRet);
+
+ int ClusterRange()
+ {
+ return m_disloutCluster;
+ }
+
+ float ClusterXOffset() { return m_xsClusterXOffset; }
+ float ClusterAdvance() { return m_xsClusterAdvance; }
+ void SetClusterXOffset(float xs) { m_xsClusterXOffset = xs; }
+ void SetClusterAdvance(float xs) { m_xsClusterAdvance = xs; }
+
+ float GlyphMetricLogUnits(Font * pfont, int nGlyphMetric);
+ //float GlyphMetricLogUnits(int nMetricID);
+
+ int GlyphBbIndex() { return m_igbb; }
+ void SetGlyphBbIndex (int i) { m_igbb = i; }
+
+ Rect BoundingBox(Font & font)
+ {
+ Rect rectBB;
+ rectBB.left = m_xsPositionX + GlyphMetricLogUnits(&font, kgmetBbLeft);
+ if (IsSpace())
+ rectBB.right = m_xsPositionX + GlyphMetricLogUnits(&font, kgmetAdvWidth);
+ else
+ rectBB.right = m_xsPositionX + GlyphMetricLogUnits(&font, kgmetBbRight);
+ rectBB.top = m_ysPositionY + GlyphMetricLogUnits(&font, kgmetBbTop);
+ rectBB.bottom = m_ysPositionY + GlyphMetricLogUnits(&font, kgmetBbBottom);
+ return rectBB;
+ }
+
+ bool IsLineBreak()
+ {
+ return (IsInitialLineBreak() || IsFinalLineBreak());
+ }
+ bool IsInitialLineBreak()
+ {
+ return (m_spsl == kspslLbInitial);
+ }
+ bool IsFinalLineBreak()
+ {
+ return (m_spsl == kspslLbFinal);
+ }
+
+ //float AdvanceXMetric()
+ //{
+ // return m_xysAdvX;
+ //}
+
+ bool IsSpace();
+
+ void AdjustPosXBy(float dxs)
+ {
+ m_xsPositionX += dxs;
+ //m_rectBB.left += dxs;
+ //m_rectBB.right += dxs;
+ }
+
+ void ShiftForDirDepthChange(float dxsSegWidth);
+
+ // Used by GlyphInfo
+ int IndexAttachedTo();
+ //inline float AdvanceX(Segment * pseg);
+ //inline float AdvanceY(Segment * pseg);
+ float MaxStretch(Segment * pseg, int level);
+ float MaxShrink(Segment * pseg, int level);
+ float StretchStep(Segment * pseg, int level);
+ int JustWeight(int level);
+ float JustWidth(Segment * pseg, int level);
+ float MeasureSolLogUnits(Segment * pseg);
+ float MeasureEolLogUnits(Segment * pseg);
+ Rect ComponentRect(Segment * pseg, int icomp);
+
+protected:
+ // Instance variables:
+
+ sdata8 m_cComponents;
+
+ data8 m_disloutCluster; // how far to search on either side of this glyph to find
+ // other members of the cluster;
+ // 0 means there are no cluster members or this glyph is
+ // attached to some other base
+
+ int m_isloutClusterBase; // the index of the slot that serves as the base for the
+ // cluster this slot is a part of; -1 if not part of cluster
+
+ int m_ichwBeforeAssoc; // index of associated character(s) in the string
+ int m_ichwAfterAssoc; // (relative to the official beginning of the segment)
+ // char might possibly not be officially in this segment,
+ // in which case value is infinity
+
+ // Measurements for highlighting an entire cluster, relative to origin of this slot,
+ // which is the cluster base.
+ float m_xsClusterXOffset;
+ float m_xsClusterAdvance; // for single non-cluster glyphs, advance width of positioned glyph
+
+ // Index into m_prggbb in Segment; -1 indicates a line break slot that is not rendered:
+ int m_igbb;
+
+ float m_xsAdvanceX;
+// float m_ysAdvanceY; -- not used
+// Rect m_rectBB;
+
+}; // end of class GrSlotOutput
+
+} // namespace gr
+
+
+#endif // !SLOTSTATE_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.cpp
new file mode 100644
index 00000000000..df1a73e5e3e
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.cpp
@@ -0,0 +1,2381 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrSlotStream.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ GrSlotStream class implementation.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#include "GrConstants.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Answer true if there is nothing valid available to read from the stream.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::AtEnd()
+{
+ Assert(AssertValid());
+
+ if (m_islotReprocPos > -1 && m_islotReprocPos < signed(m_vpslotReproc.size()))
+ return false;
+
+ if (m_islotSegLim > -1 && m_islotReadPos >= m_islotSegLim)
+ // We've determined the segment limit, and we're at or past it.
+ return true;
+
+ return (m_islotReadPos == m_islotWritePos);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Answer true if there is nothing at all available to read from the stream.
+ For substitution passes, we need to consider slots that may be beyond what we know
+ will be the official end of the segment.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::AtEndOfContext()
+{
+ if (m_fUsedByPosPass)
+ return AtEnd();
+
+ if (m_islotReprocPos > -1 && m_islotReprocPos < signed(m_vpslotReproc.size()))
+ return false;
+
+ return (m_islotReadPos == m_islotWritePos);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Append a slot to the end of the stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::NextPut(GrSlotState * pslot)
+{
+ Assert(AssertValid());
+
+ if (m_islotWritePos < signed(m_vpslot.size()))
+ {
+ m_vpslot[m_islotWritePos] = pslot;
+ }
+ else
+ {
+ m_vpslot.push_back(pslot);
+ m_vislotPrevChunkMap.push_back(-1);
+ m_vislotNextChunkMap.push_back(-1);
+ }
+
+ if (m_fUsedByPosPass && GotIndexOffset())
+ pslot->SetPosPassIndex(m_islotWritePos - m_cslotPreSeg, m_fInputToPosPass1);
+
+ m_islotWritePos++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the next slot from the stream.
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotStream::NextGet()
+{
+ Assert(AssertValid());
+ Assert(!AtEndOfContext());
+
+ GrSlotState * pslotRet;
+
+ if (m_islotReprocPos > -1)
+ {
+ if (m_islotReprocPos >= signed(m_vpslotReproc.size()))
+ {
+ // Finished reprocessing.
+ Assert((unsigned)m_islotReprocPos == m_vpslotReproc.size());
+ m_islotReprocPos = -1;
+ // But leave the m_vpslotReproc array in place so that earlier slots can
+ // be accessed by the rules.
+ pslotRet = m_vpslot[m_islotReadPos];
+ m_islotReadPos++;
+ }
+ else
+ {
+ // Read from the reprocess buffer.
+ pslotRet = m_vpslotReproc[m_islotReprocPos];
+ m_islotReprocPos++;
+ }
+ }
+ else
+ {
+ // Read normally.
+ pslotRet = m_vpslot[m_islotReadPos];
+ m_islotReadPos++;
+ }
+
+ Assert(!m_fUsedByPosPass || pslotRet->PosPassIndex() != GrSlotAbstract::kNotYetSet);
+
+ return pslotRet;
+}
+
+/*---------------------------------------------------------------------------------------------
+ Peek at the next slot from the stream (dislot = 0 means the very next slot).
+ Only used for peeking forward. RuleInputSlot is used for accessing any possible
+ slot in the rule's context.
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotStream::Peek(int dislot)
+{
+ Assert(AssertValid());
+ Assert(!AtEndOfContext());
+ Assert(dislot >= 0);
+
+ GrSlotState * pslotRet;
+
+ if (m_islotReprocPos > -1)
+ {
+ int cslotReproc = m_vpslotReproc.size() - m_islotReprocPos; // num left in reproc buffer
+ if (dislot >= cslotReproc)
+ {
+ // Not quite enough slots in the reprocess buffer.
+ pslotRet = m_vpslot[m_islotReadPos + dislot - cslotReproc];
+ }
+ else if (m_islotReprocPos + dislot < 0)
+ {
+ // Reading prior to the reprocess buffer
+ pslotRet = m_vpslot[m_islotReadPos + dislot - cslotReproc];
+ }
+ else
+ {
+ // Read from the reprocess buffer.
+ pslotRet = m_vpslotReproc[m_islotReprocPos + dislot];
+ }
+ }
+ else
+ {
+ // Read normally.
+ Assert(m_islotWritePos - m_islotReadPos > dislot);
+ pslotRet = m_vpslot[m_islotReadPos + dislot];
+ }
+
+ return pslotRet;
+}
+
+/*---------------------------------------------------------------------------------------------
+ Treat the stream, which is really the output stream, as an input stream,
+ retrieving a recently output slot. This happens when we are reading before the
+ current stream position when the rule is being matched, or before the original
+ stream position when the rule is being run.
+
+ @param dislot - how far back to peek before the write position
+ when the rule started; a negative number
+ (NOTE: the current write position is irrelevant)
+ @param fNullOkay - true if it's okay to return NULL in the situation where we're asking
+ for something before the beginning of the stream
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotStream::PeekBack(int dislot, bool fNullOkay)
+{
+ Assert(dislot < 0);
+ if (dislot < m_islotRuleStartWrite * -1)
+ {
+ Assert(fNullOkay);
+ return NULL;
+ }
+ GrSlotState * pslotRet;
+ if (m_islotReprocPos > -1)
+ {
+ if (dislot < m_islotReprocLim - m_islotRuleStartWrite &&
+ dislot >= m_islotReprocLim - m_islotRuleStartWrite - signed(m_vpslotReproc.size()))
+ {
+ // Read from the reprocess buffer.
+ // Review: this is weird; can it ever happen?
+ pslotRet = m_vpslotReproc[m_vpslotReproc.size()
+ - (m_islotReprocLim - m_islotRuleStartWrite) + dislot];
+ }
+ else
+ pslotRet = m_vpslot[m_islotRuleStartWrite + dislot];
+ }
+ else
+ pslotRet = m_vpslot[m_islotRuleStartWrite + dislot];
+
+ return pslotRet;
+}
+
+/*---------------------------------------------------------------------------------------------
+ Skip the given number of slots in the stream.
+ ENHANCE: implement more efficiently
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::Skip(int dislot)
+{
+ for (int islot = 0; islot < dislot; ++islot)
+ NextGet();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform assertions to ensure that the stream is in a valid state.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::AssertValid()
+{
+ Assert(m_islotWritePos <= signed(m_vpslot.size()));
+ Assert(m_islotReadPos <= m_islotWritePos);
+ // Streams used by the positioning passes (input or output) should not be working
+ // with slots beyond the segment lim
+ Assert(m_islotSegLim == -1 || !m_fUsedByPosPass || m_islotReadPos <= m_islotSegLim);
+ Assert(m_vpslot.size() == m_vislotPrevChunkMap.size());
+ Assert(m_vpslot.size() == m_vislotNextChunkMap.size());
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of slots that have been completely output by the previous pass but not
+ yet processed by the following pass. ("Completely" output means that they do not need
+ to be reprocessed by the same pass, only then are they available as valid input.)
+ Include any slots that are present by virtue of needing to be reprocessed by the
+ corresponding output stream.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::SlotsPending()
+{
+ Assert(AssertValid());
+ if (m_islotSegLim > -1)
+ return (m_islotSegLim - m_islotReadPos + SlotsToReprocess());
+ else
+ return (m_islotWritePos - m_islotReadPos + SlotsToReprocess());
+}
+
+int GrSlotStream::SlotsPendingInContext()
+{
+ Assert(AssertValid());
+ if (m_fUsedByPosPass)
+ return SlotsPending();
+ else
+ return (m_islotWritePos - m_islotReadPos + SlotsToReprocess());
+}
+
+int GrSlotStream::TotalSlotsPending()
+{
+ int cslot = SlotsPendingInContext();
+ if (m_fUsedByPosPass && m_islotSegLim > -1)
+ {
+ int ctmp = m_islotWritePos - m_islotReadPos + SlotsToReprocess();
+ if (ctmp > cslot)
+ {
+ int x; x = 3;
+ }
+ cslot = max(cslot, ctmp);
+ }
+ return cslot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if this pass is input or output to a positioning pass and we're past the end
+ of the segment. So this stream is virtually finished.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::PastEndOfPositioning(bool fOutput)
+{
+ if (m_fUsedByPosPass && m_islotSegLim > -1)
+ {
+ if (fOutput) // this stream is functioning as an output stream
+ return (m_islotWritePos >= m_islotSegLim);
+ else // this stream is functioning as an input stream
+ return (m_islotReadPos >= m_islotSegLim);
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Mark the stream as fully written, so that the output pass doesn't keep trying to ask
+ for more input.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::MarkFullyWritten()
+{
+ m_fFullyWritten = true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the position of the first glyph at or following the given position
+ that is in the top direction, or -1 if we do not have a complete range.
+
+ @param ptman
+ @param islotStart
+ @nTopDirLevel - top direction: 0 = left-to-right, 1 = right-to-left
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::OldDirLevelRange(EngineState * pengst, int islotStart, int nTopDirLevel)
+{
+ Assert(m_islotReadPos <= islotStart);
+ Assert(islotStart < m_islotWritePos);
+
+ int islot = islotStart;
+ int nSlotDirLevel = GetSlotDirLevel(pengst, islot, nTopDirLevel, nTopDirLevel,
+ kdircUnknown, kdircNeutral);
+ if (nSlotDirLevel == -1)
+ return -1;
+ while (nSlotDirLevel > nTopDirLevel)
+ {
+ islot++;
+ if (islot >= m_islotWritePos)
+ {
+ if (m_fFullyWritten)
+ return islot;
+ else
+ return -1;
+ }
+ else if (m_islotSegLim > -1 && islot >= m_islotSegLim)
+ {
+ return islot;
+ }
+
+ nSlotDirLevel = GetSlotDirLevel(pengst, islot, nTopDirLevel, nTopDirLevel,
+ kdircUnknown, kdircNeutral);
+ if (nSlotDirLevel == -1)
+ return -1;
+ }
+ return islot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the position of the first glyph at or following the given position
+ that is in the top direction, or -1 if we do not have a complete range.
+
+ @param ptman
+ @param islotStart
+ @nTopDirLevel - top direction: 0 = left-to-right, 1 = right-to-left
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::DirLevelRange(EngineState * pengst, int islotStart, int nTopDirLevel,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops)
+{
+ Assert(m_islotReadPos <= islotStart);
+ Assert(islotStart < m_islotWritePos);
+
+ std::vector<int> vislotStartStack; // indices of starts of ranges to reverse
+
+ // Stack corresponding to embedding and override markers:
+ std::vector<DirCode> vdircMarkerStack;
+ std::vector<DirCode> vdircOverrideStack;
+ std::vector<int> vnLevelStack;
+
+ vislotStarts.clear();
+ vislotStops.clear();
+
+ //vislotStartStack.Push(islot);
+
+ int islotSegLim = (FullyWritten() || m_islotSegLim > -1) ?
+ FinalSegLim() :
+ WritePos() + 100; // arbitrarily large number
+
+ if (islotStart > islotSegLim)
+ {
+ // Don't do anything fancy with stuff beyond the end of the segment.
+ return 0;
+ }
+
+ DirCode dircMarker = kdircNeutral; // none so far
+ int nCurrLevel = nTopDirLevel;
+ int nMarkerLevel = nTopDirLevel;
+ //bool fHitMark = false;
+ DirCode dircOverride = kdircNeutral;
+ int islot = islotStart;
+ Assert(islot <= m_islotWritePos);
+
+ while (true)
+ {
+ GrSlotState * pslot = m_vpslot[islot];
+ DirCode dirc = pslot->DirProcessed();
+ bool fIncludeLast = false;
+ int nSlotDirLevel;
+ if (dirc == kdircLRO || dirc == kdircLRE) // steps X1, X3 in the Unicode bidi algorithm
+ {
+ vdircMarkerStack.push_back(dircMarker);
+ vdircOverrideStack.push_back(dircOverride);
+ vnLevelStack.push_back(nCurrLevel);
+ dircMarker = dirc;
+ dircOverride = (dirc == kdircLRO) ? kdircL : kdircNeutral;
+ nSlotDirLevel = (nCurrLevel % 2) ?
+ nCurrLevel + 1 : nCurrLevel + 2; // next highest LTR level
+ nMarkerLevel = nSlotDirLevel;
+
+ pslot->SetDirProcessed(dircMarker);
+ pslot->SetDirLevel(nMarkerLevel);
+ pslot->MarkDirProcessed();
+ }
+ else if (dirc == kdircRLO || dirc == kdircRLE) // steps X2, X4
+ {
+ vdircMarkerStack.push_back(dircMarker);
+ vdircOverrideStack.push_back(dircOverride);
+ vnLevelStack.push_back(nCurrLevel);
+ dircMarker = dirc;
+ dircOverride = (dirc == kdircRLO) ? kdircR : kdircNeutral;
+ nSlotDirLevel = (nCurrLevel % 2) ?
+ nCurrLevel + 2 : nCurrLevel + 1; // next highest RTL level
+ nMarkerLevel = nSlotDirLevel;
+
+ pslot->SetDirProcessed(dircMarker);
+ pslot->SetDirLevel(nMarkerLevel);
+ pslot->MarkDirProcessed();
+ }
+ else if (dirc == kdircPDF)
+ {
+ if (dircMarker == kdircNeutral)
+ pslot->SetDirProcessed((nCurrLevel % 2) ? kdircR : kdircL);
+ else
+ pslot->SetDirProcessed(RightToLeftDir(dircMarker) ? kdircPdfR : kdircPdfL);
+ pslot->SetDirLevel(nMarkerLevel);
+ pslot->MarkDirProcessed();
+
+ if (vnLevelStack.size())
+ {
+ dircMarker = vdircMarkerStack.back();
+ vdircMarkerStack.pop_back();
+ dircOverride = vdircOverrideStack.back();
+ vdircOverrideStack.pop_back();
+ nMarkerLevel = vnLevelStack.back();
+ vnLevelStack.pop_back();
+ nSlotDirLevel = nMarkerLevel;
+ fIncludeLast = true;
+ }
+ else // ignore
+ nSlotDirLevel = nCurrLevel;
+ }
+ else
+ {
+ nSlotDirLevel = GetSlotDirLevel(pengst, islot, nTopDirLevel, nMarkerLevel,
+ dircMarker, dircOverride);
+ if (nSlotDirLevel == -1)
+ return -1; // not enough slots
+ }
+
+ Assert(pengst->WhiteSpaceOnly() || nCurrLevel >= nTopDirLevel);
+ while (nSlotDirLevel > nCurrLevel)
+ {
+ vislotStartStack.push_back(islot);
+ nCurrLevel++;
+ }
+ // otherwise...
+ while (nTopDirLevel <= nCurrLevel && nSlotDirLevel < nCurrLevel)
+ {
+ if (vislotStartStack.size())
+ {
+ int islotStartTmp = vislotStartStack.back();
+ vislotStartStack.pop_back();
+ vislotStarts.push_back(islotStartTmp);
+ vislotStops.push_back(islot - 1); // previous character was the end of the range
+ }
+ else
+ Assert(pengst->WhiteSpaceOnly()); // the space is higher than the segment itself
+ nCurrLevel--;
+ }
+ // In the case of white-space-only segments, the space may be bumped up to a level
+ // higher than the segment itself.
+ Assert(pengst->WhiteSpaceOnly() || vislotStartStack.size() + nTopDirLevel == (unsigned)nCurrLevel);
+ Assert(pengst->WhiteSpaceOnly() || vnLevelStack.size() == vdircMarkerStack.size());
+ Assert(pengst->WhiteSpaceOnly() || vdircOverrideStack.size() == vdircMarkerStack.size());
+
+ if (nCurrLevel <= nTopDirLevel)
+ {
+ if (fIncludeLast)
+ {
+ // Include in the range to reverse the PDF or the char after the LRM/RLM.
+ // (Note: don't use a size_t below: we are decrementing below zero.)
+ for (int i = signed(vislotStops.size()) - 1; i >= 0 && vislotStops[i] == islot-1; i--)
+ {
+ vislotStops[i] = islot;
+ }
+ islot++;
+ }
+ break; // reached end of reversible range
+ }
+
+ islot++;
+ if (islot >= m_islotWritePos)
+ {
+ if (m_fFullyWritten)
+ break; // end of input
+ else
+ return -1; // not enough slots
+ }
+ else if (islot >= islotSegLim)
+ {
+ break; // end of input
+ }
+ }
+
+ // Reached the end of a reversable range.
+ while (vislotStartStack.size() > 0)
+ {
+ int islotStartTmp = vislotStartStack.back();
+ vislotStartStack.pop_back();
+ vislotStarts.push_back(islotStartTmp);
+ //vislotStops.push_back(min(islot, ReadPos() - 1));
+ //vislotStops.push_back(min(islot, max(ReadPos() - 1, islotStartTmp)));
+ vislotStops.push_back(min(islot - 1, islotSegLim - 1));
+ nCurrLevel--;
+ }
+ Assert(pengst->WhiteSpaceOnly() || nCurrLevel == nTopDirLevel);
+ Assert(vislotStarts.size() == vislotStops.size());
+
+ // The start- and stop-lists were generated in the order that we hit the stops, in other
+ // words, from inner to outer. Which is the order in which we need to do the reversals, too.
+
+ return islot;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Return the direction level of the glyph at the given position, according to the
+ Unicode bidi algorithm. Return -1 if there aren't enough slots in the stream to
+ figure it out.
+
+ ???? How should this handle the reprocessing sub-stream????
+
+ @param ptman
+ @param islot - slot for which information is requested
+ @param nOuterLevel - 0 = left-to-right, 1 = right-to-left
+ @param nCurrLevel
+ @param dircMarker - most recent override or embedding marker, if any
+ (for interpreting PDF codes)
+ @param dircOverride - override imposed by LRO or RLO
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::GetSlotDirLevel(EngineState * pengst, int islot,
+ int nOuterLevel, int nCurrLevel, DirCode dircMarker, DirCode dircOverride)
+{
+// Assert(m_psstrmReprocess == NULL);
+
+ GrSlotState * pslot = m_vpslot[islot];
+
+ int nDirLevel = pslot->DirLevel();
+ if (nDirLevel > -1)
+ // already figured out
+ return nDirLevel;
+
+ if (pengst->WhiteSpaceOnly())
+ {
+ // White-space-only segments should not have any reordering.
+ nDirLevel = pengst->ParaRightToLeft();
+ pslot->SetDirLevel(nDirLevel);
+ pslot->MarkDirProcessed();
+ return nDirLevel;
+ }
+
+ DirCode dirc = pslot->DirProcessed();
+
+ if (!pslot->DirHasBeenProcessed() && (WeakDir(dirc) || NeutralDir(dirc)) )
+ {
+ // Resolve weak and neutral types; process an entire run of weak types at once,
+ // in several passes.
+
+ int islotWeakRunLim = islot + 1;
+ while (true)
+ {
+ if (islotWeakRunLim >= m_islotWritePos)
+ {
+ if (!m_fFullyWritten)
+ return -1; // get more slots
+ else
+ break;
+ }
+ else if (m_islotSegLim > -1 && islotWeakRunLim >= SegLimIfKnown())
+ {
+ break;
+ }
+ if (StrongDir(m_vpslot[islotWeakRunLim]->DirProcessed()))
+ // ignore the line-break; we need the next strong dir after that
+ //// && !m_vpslot[islotWeakRunLim]->IsFinalLineBreak(ptman->LBGlyphID()))
+ {
+ break;
+ }
+ if (m_vpslot[islotWeakRunLim]->DirProcessed() == kdircPDF &&
+ dircMarker != kdircUnknown)
+ {
+ // A valid PDF is a strong code. TODO: replace kdircPDF with kdircPdfL/R
+ break;
+ }
+
+ islotWeakRunLim++;
+ }
+
+ int islotLp;
+
+ // X6. Handle directional overrides: LRO, RLO.
+ if (dircOverride != kdircNeutral)
+ {
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ m_vpslot[islotLp]->SetDirProcessed(dircOverride);
+ m_vpslot[islotLp]->MarkDirProcessed();
+ }
+ goto LSetDir;
+ }
+
+ DirCode dircLp;
+ //DirCode dircTmp;
+
+ // W1. Non-spacing marks get the type of the previous slot.
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ Assert(!m_vpslot[islotLp]->DirHasBeenProcessed());
+
+ if (m_vpslot[islotLp]->DirProcessed() == kdircNSM)
+ {
+#ifdef _DEBUG
+ if (islotLp <= 0)
+ {
+ Warn("Pathological case in bidi algorithm");
+ }
+#endif // _DEBUG
+ dircLp = AdjacentNonBndNeutralCode(pengst, islotLp - 1, -1, dircMarker);
+
+ m_vpslot[islotLp]->SetDirProcessed(dircLp);
+ }
+ }
+
+ // W2. European numbers are changed to Arabic numbers if the previous strong type
+ // was an Arabic letter.
+ DirCode dircPrevStrong = AdjacentStrongCode(pengst, islot - 1, -1, dircMarker);
+ if (dircPrevStrong == kdircRArab)
+ {
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ dircLp = m_vpslot[islotLp]->DirProcessed();
+ if (dircLp == kdircEuroNum)
+ m_vpslot[islotLp]->SetDirProcessed(kdircArabNum);
+ }
+ }
+
+ // W4. A single European separator between two Latin numbers changes to a Latin number.
+ // A single common separator between two numbers of the same type changes to that
+ // type.
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ dircLp = m_vpslot[islotLp]->DirProcessed();
+ if ((dircLp == kdircEuroSep || dircLp == kdircComSep) &&
+ islotLp + 1 < m_islotWritePos) // don't test last slot in stream
+ {
+ DirCode dircPrev = AdjacentNonBndNeutralCode(pengst, islotLp - 1, -1, dircMarker);
+ DirCode dircNext = AdjacentNonBndNeutralCode(pengst, islotLp + 1, 1, dircMarker);
+ if (dircPrev == dircNext)
+ {
+ if (dircLp == kdircEuroSep && dircPrev == kdircEuroNum)
+ {
+ m_vpslot[islotLp]->SetDirProcessed(kdircEuroNum);
+ }
+ else if (dircLp == kdircComSep &&
+ (dircPrev == kdircEuroNum || dircPrev == kdircArabNum))
+ {
+ m_vpslot[islotLp]->SetDirProcessed(dircPrev);
+ }
+ }
+ }
+ }
+
+ // W5, W6. A sequence of European number terminators adjacent to Latin numbers changes
+ // to Latin numbers.
+ // This appears to be an ambiguity in the official algorithm: do we search backward
+ // first, or forward? For our purposes, it is easier to search backward first.
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ dircLp = m_vpslot[islotLp]->DirProcessed();
+ if (dircLp == kdircEuroTerm || dircLp == kdircBndNeutral)
+ {
+ if (TerminatorSequence(pengst, islotLp - 1, -1, dircMarker) == kdircEuroNum)
+ dircLp = kdircEuroNum;
+ else
+ {
+ if (TerminatorSequence(pengst, islotLp + 1, 1, dircMarker) == kdircEuroNum)
+ dircLp = kdircEuroNum;
+ // else could possibly be unknown if we are at the end of the stream
+ }
+ }
+
+ // W6. Separators and terminators change to neutral. (Don't change
+ // boundary neutrals at this point, because that would confuse step Pre-L1.)
+ if (dircLp == kdircEuroSep || dircLp == kdircEuroTerm || dircLp == kdircComSep)
+ {
+ dircLp = kdircNeutral;
+ }
+ m_vpslot[islotLp]->SetDirProcessed(dircLp);
+ }
+
+ // W7. European numbers are changed to plain left-to-right if the previous strong type
+ // was left-to-right.
+ dircPrevStrong = AdjacentStrongCode(pengst, islot - 1, -1, dircMarker);
+ if (dircPrevStrong == kdircL)
+ {
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ dircLp = (m_vpslot[islotLp]->DirProcessed());
+ if (dircLp == kdircEuroNum)
+ m_vpslot[islotLp]->SetDirProcessed(kdircL);
+ }
+ }
+
+ // Pre-L1. Make a list of all the trailing whitespace characters that need to take
+ // on the direction of the final line break (ie, the top direction). We can't actually
+ // change them yet, because that would confuse the loop below. But we have to
+ // record them now because they might get changed in the loop below.
+ std::vector<int> vislotTrailingWS;
+ int islotFinalLB = -1;
+ for (islotLp = islotWeakRunLim; islotLp-- > islot; )
+ {
+ if (m_vpslot[islotLp]->IsFinalLineBreak(pengst->TableManager()->LBGlyphID()))
+ {
+ islotFinalLB = islotLp;
+ for (int islotLp2 = islotLp; islotLp2-- > islot; )
+ {
+ dircLp = m_vpslot[islotLp2]->DirProcessed();
+ if (dircLp == kdircWhiteSpace || dircLp == kdircBndNeutral)
+ vislotTrailingWS.push_back(islotLp2);
+ else
+ break; // hit something other than whitespace or neutral
+ }
+ break;
+ }
+ }
+
+ // N1. A sequence of neutrals takes the direction of the strong surrounding text if
+ // the text on both sides has the same direction. Latin and Arabic numbers are treated
+ // as if they are right-to-left.
+ // (If they are not the same, leave the type as neutral.)
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ {
+ dircLp = m_vpslot[islotLp]->DirProcessed();
+
+ // Change Boundary Neutrals to plain neutrals (must happen after Pre-L1).
+ if (dircLp == kdircBndNeutral)
+ {
+ m_vpslot[islotLp]->SetDirProcessed(kdircNeutral);
+ dircLp = kdircNeutral;
+ }
+
+ if (NeutralDir(dircLp))
+ {
+ // First, look for either a strong code or a number. If we get at least
+ // one strong code and a number with the same direction, use that strong
+ // code.
+ DirCode dircPrev = AdjacentStrongCode(pengst, islotLp - 1, -1, dircMarker, true);
+ DirCode dircNext = AdjacentStrongCode(pengst, islotLp + 1, 1, dircMarker, true);
+
+ if (dircNext == kdircUnknown)
+ return -1;
+
+ if (dircPrev == kdircUnknown)
+ dircPrev = dircNext;
+
+ DirCode dircResult = kdircUnknown;
+ if (dircNext == kdircNeutral)
+ {}
+ else if (RightToLeftDir(dircPrev) == RightToLeftDir(dircNext) &&
+ (StrongDir(dircNext) || StrongDir(dircPrev)))
+ {
+ // Got a strong matching direction.
+ dircResult = (StrongDir(dircPrev)) ? dircPrev : dircNext;
+ }
+ else if (dircNext == kdircPdfL || dircNext == kdircPdfR)
+ {
+ // A following PDF flag wins, because it represents the edge of a run.
+ dircResult = dircNext;
+ }
+ else if (StrongDir(dircNext) && StrongDir(dircPrev))
+ { // We must have text in different directions.
+ }
+ else
+ {
+ // Try again, insisting on strong codes, no numbers.
+ if (!StrongDir(dircPrev))
+ dircPrev = AdjacentStrongCode(pengst, islotLp - 1, -1, dircMarker, false);
+ if (!StrongDir(dircNext))
+ dircNext = AdjacentStrongCode(pengst, islotLp + 1, 1, dircMarker, false);
+ if (dircPrev == kdircUnknown)
+ dircPrev = dircNext;
+
+ if (RightToLeftDir(dircPrev) == RightToLeftDir(dircNext) &&
+ (StrongDir(dircNext) || StrongDir(dircPrev)))
+ {
+ // Got a strong matching direction.
+ dircResult = (StrongDir(dircPrev)) ? dircPrev : dircNext;
+ }
+ }
+
+ if (dircResult != kdircUnknown)
+ {
+ dircResult = (RightToLeftDir(dircResult)) ? kdircR : kdircL;
+ m_vpslot[islotLp]->SetDirProcessed(dircResult);
+ }
+ // else leave as neutral
+ }
+ }
+
+ // L1. Now change trailing neutrals recorded above to the directionality of
+ // the immediately following line-break, if any.
+ if (islotFinalLB != -1)
+ {
+ DirCode dircLB = m_vpslot[islotFinalLB]->DirProcessed();
+ dircLB = (dircLB == kdircLlb) ? kdircL : kdircR;
+ for (int iislot = 0; iislot < signed(vislotTrailingWS.size()); iislot++)
+ {
+ int islotTmp = vislotTrailingWS[iislot];
+ m_vpslot[islotTmp]->SetDirProcessed(dircLB);
+ }
+ }
+
+ // Mark all the slots processed.
+ for (islotLp = islot; islotLp < islotWeakRunLim; islotLp++)
+ m_vpslot[islotLp]->MarkDirProcessed();
+ }
+ else
+ m_vpslot[islot]->MarkDirProcessed();
+
+LSetDir:
+
+ // Final resolution.
+
+ dirc = pslot->DirProcessed();
+
+ if (dirc != kdircLlb && dirc != kdircRlb && dircOverride != kdircNeutral)
+ {
+ // Enforce whatever is imposed by the override.
+ m_vpslot[islot]->SetDirProcessed(dircOverride);
+ nDirLevel = nCurrLevel;
+ }
+ else if ((nCurrLevel % 2) == 0) // current level is even (left-to-right)
+ {
+ switch (dirc)
+ {
+ case kdircNeutral:
+ case kdircWhiteSpace:
+ nDirLevel = nCurrLevel;
+ break;
+
+ case kdircL:
+ nDirLevel = nCurrLevel;
+ break;
+
+ case kdircLlb:
+ case kdircRlb: // all line-breaks have the direction of the paragraph
+ nDirLevel = nOuterLevel;
+ break;
+
+ case kdircR:
+ case kdircRArab:
+ nDirLevel = nCurrLevel + 1;
+ break;
+
+ case kdircEuroNum:
+ case kdircArabNum:
+ nDirLevel = nCurrLevel + 2;
+ break;
+
+ default:
+ Assert(false);
+ nDirLevel = nCurrLevel;
+ }
+ }
+ else // current level is odd (right-to-left)
+ {
+ switch (dirc)
+ {
+ case kdircNeutral:
+ case kdircWhiteSpace:
+ nDirLevel = nCurrLevel;
+ break;
+
+ case kdircR:
+ //case kdircRlb:
+ case kdircRArab:
+ nDirLevel = nCurrLevel;
+ break;
+
+ case kdircL:
+ //case kdircLlb:
+ case kdircEuroNum:
+ case kdircArabNum:
+ nDirLevel = nCurrLevel + 1;
+ break;
+
+ case kdircLlb:
+ case kdircRlb: // all line-breaks have the direction of the paragraph
+ nDirLevel = nOuterLevel;
+ break;
+
+ default:
+ Assert(false);
+ nDirLevel = nCurrLevel;
+ }
+ }
+ pslot->SetDirLevel(nDirLevel);
+
+ return nDirLevel;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the next or previous strong code, kdircNeutral if we don't find one,
+ or kdircUnknown if we need more slots to process.
+
+ @param islot - index of slot of interest
+ @param nInc - +1 to search forward, -1 to search backward
+ @param fNumbersAreStrong - true if we want to treat numbers as having strong
+ directionality
+ @param dircPDF - how to interpret PDF codes (from corresponding RLO, etc)
+----------------------------------------------------------------------------------------------*/
+DirCode GrSlotStream::AdjacentStrongCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF, bool fNumbersAreStrong)
+{
+ if (islot < 0)
+ return pengst->InitialStrongDir();
+
+ else if (islot >= m_islotWritePos)
+ {
+ if (m_fFullyWritten || (m_islotSegLim > -1 && islot >= SegLimIfKnown()))
+ return kdircNeutral;
+ else
+ return kdircUnknown;
+ }
+
+ DirCode dirc = m_vpslot[islot]->DirProcessed();
+
+ if (dirc == kdircPDF && StrongDir(dircPDF))
+ return (RightToLeftDir(dircPDF)) ? kdircPdfR : kdircPdfL;
+ if (StrongDir(dirc))
+ return dirc;
+ if (fNumbersAreStrong && (dirc == kdircEuroNum || dirc == kdircArabNum))
+ return dirc;
+
+ return AdjacentStrongCode(pengst, islot + nInc, nInc, dircPDF, fNumbersAreStrong);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return kdircEuroNum if there is a terminator sequence starting or ending with a
+ European number. Return kdircUnknown if we need more slots to process.
+ Return kdircNeutral otherwise.
+
+ @param islot - index of slot of interest
+ @param nInc - +1 to search forward, -1 to search backward
+ @param dircPDF - how to interpret PDF codes (from corresponding RLO, etc)
+----------------------------------------------------------------------------------------------*/
+DirCode GrSlotStream::TerminatorSequence(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF)
+{
+ if (islot < 0)
+ return pengst->InitialTermDir();
+
+ else if (islot >= m_islotWritePos)
+ {
+ if (m_fFullyWritten)
+ return kdircNeutral;
+ else
+ return kdircUnknown;
+ }
+
+ DirCode dirc = m_vpslot[islot]->DirProcessed();
+
+ if (dirc == kdircPDF)
+ return (RightToLeftDir(dircPDF)) ? kdircPdfR : kdircPdfL;
+ else if (dirc == kdircEuroNum)
+ // number found at end of terminator sequence
+ return kdircEuroNum;
+ else if (dirc == kdircEuroTerm)
+ // yes, this slot is a terminator; are there more?
+ return TerminatorSequence(pengst, islot + nInc, nInc, dircPDF);
+ else if (dirc == kdircLlb || dirc == kdircRlb)
+ // line-break slot--ignore and keep going
+ return TerminatorSequence(pengst, islot + nInc, nInc, dircPDF);
+ else if (dirc == kdircBndNeutral)
+ // boundary neutral--ignore and keep going
+ return TerminatorSequence(pengst, islot + nInc, nInc, dircPDF);
+ else
+ // no number found
+ return kdircNeutral;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the previous code that is not a Boundary Neutral. Return Other Neutral if there
+ is no such.
+
+ @param islot - index of slot of interest
+ @param nInc - +1 to search forward, -1 to search backward
+ @param dircPDF - how to interpret PDF codes (from corresponding RLO, etc)
+----------------------------------------------------------------------------------------------*/
+DirCode GrSlotStream::AdjacentNonBndNeutralCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF)
+{
+ Assert(islot < m_islotWritePos);
+ if (islot < 0)
+ return kdircNeutral; // or should we use: ptman->InitialStrongDir() ??
+
+ else if (islot >= m_islotWritePos)
+ {
+ if (m_fFullyWritten)
+ return kdircNeutral;
+ else
+ return kdircUnknown;
+ }
+
+ DirCode dirc = m_vpslot[islot]->DirProcessed();
+
+ if (dirc == kdircBndNeutral)
+ return AdjacentNonBndNeutralCode(pengst, islot + nInc, nInc, dircPDF);
+ else if (dirc == kdircPDF)
+ return (RightToLeftDir(dircPDF)) ? kdircPdfR : kdircPdfL;
+ else
+ return dirc;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Directionality type functions.
+----------------------------------------------------------------------------------------------*/
+bool StrongDir(DirCode dirc)
+{
+ return (dirc == kdircL || dirc == kdircR || dirc == kdircRArab ||
+ dirc == kdircLRO || dirc == kdircRLO || dirc == kdircLRE || dirc == kdircRLE ||
+ dirc == kdircPdfL || dirc == kdircPdfR);
+}
+
+bool WeakDir(DirCode dirc)
+{
+ return (dirc == kdircEuroNum || dirc == kdircEuroSep ||
+ dirc == kdircEuroTerm || dirc == kdircArabNum ||
+ dirc == kdircComSep || dirc == kdircBndNeutral || dirc == kdircNSM);
+}
+
+bool NeutralDir(DirCode dirc)
+{
+ return (dirc == kdircWhiteSpace || dirc == kdircNeutral);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Special values used by the bidi algorithm.
+----------------------------------------------------------------------------------------------*/
+bool BidiCode(int nUnicode)
+{
+ switch (nUnicode)
+ {
+ case knLRM:
+ case knRLM:
+ case knLRO:
+ case knRLO:
+ case knLRE:
+ case knRLE:
+ case knPDF:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the directionality should be treated as right-to-left.
+ Used for the step of resolving neutrals (N1).
+----------------------------------------------------------------------------------------------*/
+bool RightToLeftDir(DirCode dirc)
+{
+ switch (dirc)
+ {
+ case kdircL:
+ case kdircLRO:
+ case kdircLRE:
+ case kdircPdfL:
+ case kdircLlb:
+ return false;
+
+ case kdircR:
+ case kdircRArab:
+ case kdircArabNum:
+ case kdircEuroNum:
+ case kdircRLO:
+ case kdircRLE:
+ case kdircPdfR:
+ return true;
+
+ case kdircNeutral:
+ case kdircWhiteSpace:
+ case kdircComSep:
+ case kdircEuroSep:
+ case kdircEuroTerm:
+ case kdircBndNeutral:
+ case kdircNSM:
+ case kdircPDF:
+ return false;
+
+ default:
+ Assert(false);
+ return false;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy a slot from prevStream, incrementing the positions.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::CopyOneSlotFrom(GrSlotStream * psstrmPrev)
+{
+#ifdef _DEBUG
+ gid16 chw; chw = psstrmPrev->Peek()->GlyphID();
+#endif
+
+ // If we are exactly at the segment boundary, pass the information on to this stream.
+ if (psstrmPrev->AtSegMin())
+ SetSegMinToWritePos();
+ if (psstrmPrev->AtSegLim())
+ SetSegLimToWritePos();
+
+ NextPut(psstrmPrev->NextGet());
+
+ AssertValid();
+ psstrmPrev->AssertValid();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy one slot from the input stream to the recipient, which is the output stream.
+ Used when reversing ranges of glyphs; caller is responsible for adjusting the read-
+ and write-positions of the streams.
+
+ REVIEW: How should this handle the reprocessing sub-stream? Currently this is not a problem
+ because this function is only used by the bidi pass, which never has intra-pass
+ reprocessing.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::SimpleCopyFrom(GrSlotStream * psstrmI, int islotInput, int islotOutput)
+{
+ if (signed(m_vpslot.size()) < islotOutput + 1)
+ {
+ m_vpslot.resize(islotOutput + 1);
+ m_vislotPrevChunkMap.resize(islotOutput + 1);
+ m_vislotNextChunkMap.resize(islotOutput + 1);
+ }
+
+ m_vpslot[islotOutput] = psstrmI->m_vpslot[islotInput];
+ m_vislotPrevChunkMap[islotOutput] = -1;
+ m_vislotNextChunkMap[islotOutput] = -1;
+
+ Assert(m_fUsedByPosPass);
+ if (m_fUsedByPosPass && GotIndexOffset())
+ m_vpslot[islotOutput]->SetPosPassIndex(islotOutput - m_cslotPreSeg, m_fInputToPosPass1);
+
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if there is physical space to add more glyphs, false if the positioning
+ has caused them to use all the alotted space. Recipient is assumed to be output
+ stream from the final pass.
+
+ @param ptman - table manager, for handling the positioning
+ @param pgg - graphics device
+ @param xsSpaceAllotted - how much space is available
+ @param fWidthIsCharCount - kludge for test procedures
+ @param fIgnoreTrailingWS - true if we are ignoring trailing white-space (currently
+ always true)
+ @param twsh - how the segment is handling trailing white-space
+ @param pxsWidth - return width of stuff so far
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::MoreSpace(GrTableManager * ptman,
+ float xsSpaceAllotted, bool fWidthIsCharCount,
+ bool fIgnoreTrailingWS, TrWsHandling twsh,
+ float * pxsWidth)
+{
+ Assert(ptman->NumberOfPasses() - 1 == m_ipass);
+
+ if (fWidthIsCharCount)
+ {
+ // Used in test procedures
+ *pxsWidth = (float)m_islotWritePos;
+ return (m_islotWritePos < xsSpaceAllotted);
+ }
+ else
+ {
+ *pxsWidth = -1;
+ if (!GotIndexOffset())
+ return true;
+ if (WritePos() <= IndexOffset())
+ return true;
+ int dislot = MaxClusterSlot(WritePos());
+ if (dislot == kNegInfinity || dislot > 0)
+ // We're in the middle of processing a cluster--we have to keep processing,
+ // so for now assume there is more space.
+ return true;
+
+ float xsWidth, xsVisWidth;
+ ptman->CalcPositionsUpTo(m_ipass, NULL, &xsWidth, &xsVisWidth);
+
+ *pxsWidth = (fIgnoreTrailingWS || twsh == ktwshOnlyWs) ? xsVisWidth : xsWidth;
+ return (*pxsWidth < xsSpaceAllotted);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Work backwards from the prevLineBreak position (or if none, the readPos) to find the
+ previous line-break of the given weight or less. Return the position of the inserted
+ line-break slot, or -1 if no appropriate break point was found. Recipient should be
+ the output of the final line break pass, or if none, the output of the
+ glyph-generation pass.
+
+ @param ptman - table manager, for supplying new slots
+ @param islotPrevBreak - position of previous inserted line break
+ @param fInsertedLB - did we actually insert a line-break glyph before?
+ @param islotStartTry - where to start looking, or -1 for the end of the stream
+ @param lb - (max) break weight to allow
+ @param twsh - how we are handling trailing white-space
+ @param islotMin - first slot that is officially part of the segment (after initial LB)
+ @param plbNextToTry - the best we found
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::InsertLineBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin,
+ LineBrk * plbNextToTry)
+{
+ EngineState * pengst = ptman->State();
+
+ Assert(!fInsertedLB || islotPrevBreak > -1);
+
+ int ichwSegOffset;
+ int islot;
+ LineBrk lbFound;
+ if (!FindSegmentEnd(ptman, islotStartTry, lb, twsh, islotMin,
+ &islot, &ichwSegOffset, &lbFound, plbNextToTry))
+ {
+ return -1; // didn't find a legal break
+ }
+
+ GrSlotState * pslotCopyFeat = pengst->AnAdjacentSlot(m_ipass, islot + 1);
+ Assert(pslotCopyFeat);
+
+ if (islotPrevBreak > -1 && fInsertedLB)
+ {
+ //GrSlotState * pslotOld = m_vpslot[islotPrevBreak];
+
+ m_vpslot.erase(m_vpslot.begin() + islotPrevBreak);
+ m_vislotPrevChunkMap.erase(m_vislotPrevChunkMap.begin() + islotPrevBreak);
+ m_vislotNextChunkMap.erase(m_vislotNextChunkMap.begin() + islotPrevBreak);
+ AdjustPrevStreamNextChunkMap(ptman, islotPrevBreak + 1, -1);
+ }
+ else
+ {
+ m_islotReadPos++;
+ m_islotWritePos++;
+ }
+
+ GrSlotState * pslotNew;
+ pengst->NewSlot(ptman->LBGlyphID(), pslotCopyFeat, 0, ichwSegOffset, &pslotNew);
+
+ pslotNew->SetSpecialSlotFlag(kspslLbFinal);
+ pslotNew->SetBreakWeight(lbFound);
+ pslotNew->SetDirectionality(ptman->RightToLeft() ? kdircRlb : kdircLlb);
+
+ int islotLB = islot + 1;
+ m_vpslot.insert(m_vpslot.begin() + islotLB, pslotNew);
+ // Inserting -1 makes it part of a chunk with the previous char/glyph
+ m_vislotPrevChunkMap.insert(m_vislotPrevChunkMap.begin() + islotLB, -1);
+ m_vislotNextChunkMap.insert(m_vislotNextChunkMap.begin() + islotLB, -1);
+ AdjustPrevStreamNextChunkMap(ptman, islotLB, 1);
+ // We don't need to adjust the following stream because we are going to unwind it anyway.
+
+ if (m_fUsedByPosPass && GotIndexOffset())
+ {
+ pslotNew->SetPosPassIndex(islot - m_cslotPreSeg, m_fInputToPosPass1);
+ // Increment the stream index for the following slots.
+ for (int islotTmp = islotLB;
+ islotTmp < ((islotPrevBreak == -1) ? m_islotWritePos : islotPrevBreak + 1);
+ islotTmp++)
+ {
+ SlotAt(islotTmp)->IncPosPassIndex();
+ }
+ }
+
+ m_islotSegLim = islotLB + 1; // after the line-break glyph
+
+ return islotLB;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Make a segment break that does not correspond to a line break; ie, don't insert
+ a line-break glyph.
+
+ Work backwards from the prevLineBreak position (or if none, the readPos) to find the
+ previous line-break of the given weight or less. Return the position of the final slot
+ in the segment, or -1 if no appropriate break point was found. Recipient should be
+ the output of the final line break pass, if any, or the glyph-generation pass.
+
+ @param ptman - table manager, for supplying new slots
+ @param islotPrevBreak - position of previous inserted line break
+ @param fInsertedLB - did we actually insert a line-break glyph previously; currently
+ ignored
+ @param islotStartTry - where to start looking, or -1 for the end of the stream
+ @param lb - (max) break weight to allow
+ @param twsh - how we are handling trailing white-space
+ @param islotMin - first slot that is officially part of the segment (after initial LB)
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::MakeSegmentBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin,
+ LineBrk * plbNextToTry)
+{
+ int ichwSegOffset;
+ int islot;
+ LineBrk lbFound;
+ if (!FindSegmentEnd(ptman, islotStartTry, lb, twsh, islotMin,
+ &islot, &ichwSegOffset, &lbFound, plbNextToTry))
+ {
+ return -1; // didn't find a legal break
+ }
+
+ // Review: do we need to delete any previously-inserted line-break glyph from the stream?
+ // Doesn't seem like this has been a problem so far.
+
+ m_islotSegLim = islot + 1; // after the final glyph of this segment
+
+ return islot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Work backwards from the prev line break position (or if none, the readPos) to find an
+ earlier line-break of the given weight or less.
+ Recipient should be the output of the final line break pass, if any, or the output
+ of the glyph-generation pass.
+
+ @param ptman - table manager, for supplying new slots
+ @param islotStartTry - where to start looking, or -1 for the end of the stream
+ @param lb - (max) break weight to allow
+ @param twsh - how we are handling trailing white-space
+ @param islotMin - first slot that is officially part of the segment (after initial LB)
+ @param pislot - slot AFTER which the break will go (not the lim of the segment)
+ @param pichwSegOffset - offset relative to the segment
+ @param plbFound - weight of break to be created
+ @param plbNextToTry - best found, in case we didn't find one at the requested level
+
+ @return Whether or not an appropriate break was found.
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::FindSegmentEnd(GrTableManager * ptman,
+ int islotStartTry, LineBrk lb, TrWsHandling twsh, int islotMin,
+ int * pislot, int * pichwSegOffset, LineBrk * plbFound,
+ LineBrk * plbNextToTry)
+{
+ Assert(AssertValid());
+ Assert(m_ipass == ptman->NumberOfLbPasses());
+
+ if (islotStartTry < 0)
+ return false;
+
+ *pislot = islotStartTry;
+ GrSlotState * pslot = m_vpslot[*pislot];
+ *plbNextToTry = klbClipBreak; // worst break
+
+ ptman->State()->SetRemovedTrWhiteSpace(false);
+
+ while (twsh != ktwshOnlyWs) // in white-space only case, ignore lb values
+ {
+ if (*pislot < islotMin)
+ {
+ return false;
+ }
+ *plbFound = LineBrk(pslot->m_lb);
+ // Sanity check
+ if (abs(*plbFound) > klbClipBreak)
+ {
+// Assert(false);
+ Warn("Unusually large breakweight");
+ *plbFound = (LineBrk)((*plbFound < 0) ? -klbClipBreak : klbClipBreak);
+ }
+ *plbNextToTry = (LineBrk)(min(static_cast<int>(*plbNextToTry), abs(*plbFound)));
+ *pichwSegOffset = pslot->SegOffset();
+
+ if (int(*plbFound) >= 0 && *plbFound <= lb)
+ break;
+
+ --(*pislot);
+ if (*pislot < 0)
+ {
+ return false;
+ }
+ pslot = m_vpslot[*pislot];
+
+ if (int(*plbFound) <= 0 && ((int)*plbFound * -1) <= lb)
+ {
+ *plbFound = LineBrk(int(*plbFound) * -1);
+ break;
+ }
+ }
+
+ // Found a good break.
+
+ if (twsh == ktwshOnlyWs)
+ {
+ // white-space-only segment
+ while (pslot->Directionality() != kdircWhiteSpace)
+ {
+ --(*pislot);
+ if (*pislot < 0)
+ return false;
+ pslot = m_vpslot[*pislot];
+ *pichwSegOffset = pslot->SegOffset();
+ }
+ }
+ else if (twsh == ktwshNoWs)
+ {
+ // no trailing white-space: remove it
+ while (pslot->Directionality() == kdircWhiteSpace)
+ {
+ --(*pislot);
+ if (*pislot < 0)
+ return false;
+ pslot = m_vpslot[*pislot];
+ *pichwSegOffset = pslot->SegOffset();
+ ptman->State()->SetRemovedTrWhiteSpace(true);
+ }
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the stream (which should be the output of the last linebreak pass) has
+ a better break at some earlier point than the one we found.
+
+ @param islotBreak - position of inserted or final break point in stream, or index
+ of last valid slot
+----------------------------------------------------------------------------------------------*/
+bool GrSlotStream::HasEarlierBetterBreak(int islotBreak, LineBrk lbFound, gid16 chwLB)
+{
+ Assert(AssertValid());
+
+ int islot = islotBreak;
+ if (SlotAt(islot)->IsFinalLineBreak(chwLB))
+ islot--;
+
+ if (lbFound == klbNoBreak)
+ lbFound = (LineBrk)SlotAt(islot)->BreakWeight();
+
+ while (islot >= 0)
+ {
+ if (SlotAt(islot)->IsInitialLineBreak(chwLB))
+ return false;
+ if (SlotAt(islot)->BreakWeight() < lbFound)
+ return true;
+ islot--;
+ }
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Make sure the stream contains a local instance of the given slot, not a copy used by
+ a previous pass.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::EnsureLocalCopy(GrTableManager * ptman, GrSlotState * pslot,
+ GrSlotStream * psstrmIn)
+{
+ //Assert(m_vpslot[islot + m_cslotPreSeg] == pslot);
+ Assert(pslot->PassModified() <= m_ipass);
+
+ if (pslot->PassModified() < m_ipass)
+ {
+ int islot = pslot->PosPassIndex();
+ Assert(SlotAtPosPassIndex(islot) == pslot);
+ GrSlotState * pslotNew;
+ ptman->State()->NewSlotCopy(pslot, m_ipass, &pslotNew);
+ m_vpslot[islot + m_cslotPreSeg] = pslotNew;
+
+ psstrmIn->ReplaceSlotInReprocessBuffer(pslot, pslotNew);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ A slot has been replace within the coorsponding output stream. Make sure the reprocess
+ buffer of this stream constains the same slot.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::ReplaceSlotInReprocessBuffer(GrSlotState * pslotOld, GrSlotState * pslotNew)
+{
+ if (m_islotReprocPos > -1)
+ {
+ for (size_t islot = 0; islot < m_vpslotReproc.size(); islot++)
+ {
+ if (m_vpslotReproc[islot] == pslotOld)
+ m_vpslotReproc[islot] = pslotNew;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Inserting a line break can potentially alter the directionality of preceeding glyphs.
+ Zap the information that has been calculated.
+
+ @param islotLB - index of the inserted final line-break glyph
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::ZapCalculatedDirLevels(int islotLB)
+{
+ int islot;
+ for (islot = m_islotWritePos; islot-- > islotLB; )
+ m_vpslot[islot]->ZapDirLevel();
+
+ for (islot = islotLB; islot-- > 0; )
+ {
+ if (StrongDir(m_vpslot[islot]->Directionality()))
+ // We've found a strong direction code; don't need to zap beyond this point.
+ return;
+
+ m_vpslot[islot]->ZapDirLevel();
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the slot index of the last slot in the cluster for the just-processed chunk,
+ relative to the last slot in the chunk.
+
+ Return kNegInfinity if there are not enough slots in the stream to tell. This can
+ happen while we are in the middle of processing a cluster.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::MaxClusterSlot(int islotChunkMin, int islotChunkLim)
+{
+ Assert(islotChunkLim > islotChunkMin);
+
+ if (!m_fUsedByPosPass)
+ return 0; // no clusters yet
+
+ int islotRet = SlotAt(islotChunkLim - 1)->PosPassIndex();
+
+ for (int islot = islotChunkMin; islot < islotChunkLim; islot++)
+ {
+ GrSlotState * pslot = SlotAt(islot);
+
+ if (m_cslotPreSeg == -1)
+ return kNegInfinity;
+ if (!HasSlotAtPosPassIndex(pslot->AttachRootPosPassIndex()))
+ return kNegInfinity;
+
+ GrSlotState * pslotBase = pslot->Base(this);
+
+ int dislotOffset = pslotBase->LastLeafOffset(this);
+ if (dislotOffset == kNegInfinity)
+ return kNegInfinity;
+ islotRet = max(islotRet, pslotBase->PosPassIndex() + dislotOffset);
+ }
+
+ // Make it relative to the last slot in the chunk.
+ islotRet -= SlotAt(islotChunkLim - 1)->PosPassIndex();
+
+ return islotRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the break weight of the given slot, which should be a line-break.
+ OBSOLETE??
+----------------------------------------------------------------------------------------------*/
+LineBrk GrSlotStream::BreakWeightAt(gid16 chwLB, int islot)
+{
+ GrSlotState * pslot = GetSlotAt(islot);
+ Assert(pslot->IsLineBreak(chwLB));
+ return LineBrk(pslot->m_lb);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Append an initial or final line break of the given weight to the stream.
+
+ @param ptman - table manager, for generating new slot
+ @param lb - break weight for the line-break glyph
+ @param dirc - directionality code for the line-break glyph
+ @param islotLB - where to insert, or -1 if at the end
+ @param fInitial - is this an initial line-break, or a final break?
+ @param ichwSegOffset - offset relative to the beginning of the segment
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AppendLineBreak(GrTableManager * ptman, GrCharStream * pchstrm,
+ LineBrk lb, DirCode dirc, int islotLB, bool fInitial, int ichwSegOffset)
+{
+ EngineState * pengst = ptman->State();
+
+ Assert(AssertValid());
+/// Assert(m_islotReprocPos == -1);
+
+ Assert(islotLB == -1 || fInitial);
+ if (islotLB == -1)
+ islotLB = m_islotWritePos;
+
+// int islot = m_islotWritePos;
+
+ GrSlotState * pslotCopyFeat = pengst->AnAdjacentSlot(m_ipass, islotLB);
+ GrSlotState * pslotNew;
+ if (pslotCopyFeat)
+ pengst->NewSlot(ptman->LBGlyphID(), pslotCopyFeat, 0, ichwSegOffset, &pslotNew);
+ else
+ {
+ GrFeatureValues fval;
+ pchstrm->CurrentFeatures(ptman, &fval);
+ pengst->NewSlot(ptman->LBGlyphID(), fval, 0, ichwSegOffset, -1, &pslotNew);
+ }
+
+ pslotNew->m_lb = sdata8(lb);
+ pslotNew->SetSpecialSlotFlag(fInitial ? kspslLbInitial : kspslLbFinal);
+ //pslotNew->m_fInitialLB = fInitial; // TODO: remove
+ pslotNew->SetDirectionality(dirc);
+
+ m_vpslot.insert(m_vpslot.begin() + islotLB, pslotNew);
+ // Make it part of a chunk with previous char/glyph
+ m_vislotPrevChunkMap.insert(m_vislotPrevChunkMap.begin() + islotLB, -1);
+ m_vislotNextChunkMap.insert(m_vislotNextChunkMap.begin() + islotLB, -1);
+ if (m_ipass > 0)
+ AdjustPrevStreamNextChunkMap(ptman, islotLB, 1);
+
+ m_islotWritePos++;
+
+ if (m_fUsedByPosPass && GotIndexOffset())
+ {
+ pslotNew->SetPosPassIndex(islotLB - m_cslotPreSeg, m_fInputToPosPass1);
+ // Increment the stream index for the following slots.
+ for (int islotTmp = islotLB + 1; islotTmp < m_islotWritePos; islotTmp++)
+ {
+ SlotAt(islotTmp)->IncPosPassIndex();
+ }
+ }
+
+ if (fInitial)
+ m_islotSegMin = islotLB; // just before the LB
+ else
+ m_islotSegLim = islotLB + 1; // just after the LB
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the index of the line break glyph within the specified range, or -1 if none.
+ Recipient is functioning as the output stream.
+
+ @param chwLB - glyph ID being used for line-break glyphs
+ @param islotMin/Lim - range to search
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::FindFinalLineBreak(gid16 chwLB, int islotMin, int islotLim)
+{
+ for (int islot = islotMin; islot < islotLim; ++islot)
+ {
+ if (m_vpslot[islot]->IsFinalLineBreak(chwLB))
+ return islot;
+ }
+ return -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ A slot has been inserted (nInc == 1) or deleted (nInc == -1). Adjust the next-chunk map
+ of the previous stream to match.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AdjustPrevStreamNextChunkMap(GrTableManager * ptman, int islotMod, int nInc)
+{
+ if (m_ipass == 0)
+ return; // no previous stream to adjust
+
+ int islotTmp = max(islotMod - 5, 0);
+ while (islotTmp > 0 && m_vislotPrevChunkMap[islotTmp] == -1)
+ islotTmp--;
+
+ ptman->InputStream(m_ipass)->AdjustNextChunkMap(
+ ((islotTmp <= 0) ? 0 : m_vislotPrevChunkMap[islotTmp]),
+ islotMod, nInc);
+}
+
+/*----------------------------------------------------------------------------------------------
+ An insertion or deletion has occurred at the given location in the following stream
+ (specifically of an line-break glyph). Adjust the next-chunk-map accordingly so
+ the indices still match.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AdjustNextChunkMap(int islotMin, int islotInsOrDel, int nInc)
+{
+ for (int islot = islotMin; islot < m_islotWritePos; islot++)
+ {
+ if (m_vislotNextChunkMap[islot] != -1 && m_vislotNextChunkMap[islot] >= islotInsOrDel)
+ m_vislotNextChunkMap[islot] += nInc;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Unwind the read position of the stream, so that the following pass will begin
+ reading from the new position. The recipient is functioning as the input stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::UnwindInput(int islotNewPos, bool fPreBidiPass)
+{
+ Assert(m_islotReprocPos == -1);
+ Assert(islotNewPos <= m_islotReadPos);
+
+ int islot;
+ for (islot = islotNewPos; islot < m_islotReadPos; ++islot)
+ m_vislotNextChunkMap[islot] = -1;
+
+ m_islotReadPos = islotNewPos;
+ m_islotReadPosMax = m_islotReadPos;
+
+ Assert(m_islotReadPos <= m_islotWritePos);
+ if (fPreBidiPass)
+ {
+ for (islot = m_islotReadPos; islot < m_islotWritePos; ++islot)
+ SlotAt(islot)->ZapDirLevel();
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Unwind the write position of the stream, so that the pass will begin writing
+ at the new position. The recipient is functioning as the output stream
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::UnwindOutput(int islotNewPos, bool fOutputOfPosPass)
+{
+ Assert(islotNewPos <= m_islotWritePos);
+
+ int islot;
+ for (islot = islotNewPos; islot < m_islotWritePos; ++islot)
+ {
+ m_vislotPrevChunkMap[islot] = -1;
+
+ if (!fOutputOfPosPass && m_fUsedByPosPass)
+ // This stream is the input to the first positioning pass, ie, the output
+ // of the last sub pass or the bidi pass. Zap the stream indices,
+ // since unwinding this pass could cause them to be invalid due to a later
+ // reordering.
+ SlotAt(islot)->ZapPosPassIndex();
+ }
+
+ m_islotWritePos = islotNewPos;
+
+ m_fFullyWritten = false;
+
+ if (m_islotSegMin > m_islotWritePos)
+ m_islotSegMin = -1;
+ if (m_islotSegLim > m_islotWritePos)
+ m_islotSegLim = -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ We've just created a new chunk, with the recipient as the output stream. The beginning
+ of the chunk is passed as 'islotOutput' and the end of the chunk is assumed to be the
+ write-position of the recipient. Store the mappings into the corresponding
+ input position.
+
+ @param islotInputMin - beginning of chunk in input stream
+ @param islotOutputMin - beginning of chunk in output stream (recipient)
+ @param islotInputLim - end of chunk in input stream (currently not used)
+ @param fSkipChunkStart - if true, either we have reprocessed part of a
+ previously created chunk,
+ or there was no input consumed;
+ in either case, don't record the beginning of the chunk,
+ just make this chunk be part of the previous
+ @param fBackingUp - this chunk results in the stream position moving backwards,
+ so clear anything we're backing over
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::MapInputChunk(int islotInputMin, int islotOutputMin, int islotInputLim,
+ bool fSkipChunkStart, bool fBackingUp)
+{
+ Assert(AssertValid());
+ Assert(islotOutputMin >= -1);
+
+ if (!fSkipChunkStart)
+ {
+ Assert(islotOutputMin >= 0);
+ if (islotOutputMin >= 0) // just in case an invalid value was passed
+ m_vislotPrevChunkMap[islotOutputMin] = islotInputMin;
+ }
+
+ int islot;
+ for (islot = max(0, islotOutputMin + 1); islot < m_islotWritePos; ++islot)
+ m_vislotPrevChunkMap[islot] = -1; // not a chunk boundary
+
+// if (fBackingUp && m_islotWritePos < m_vislotPrevChunkMap.Size())
+// m_vislotPrevChunkMap[m_islotWritePos] = -1;
+
+ if (fBackingUp)
+ for (islot = m_islotWritePos; islot < signed(m_vislotPrevChunkMap.size()); islot++)
+ m_vislotPrevChunkMap[islot] = -1;
+
+// m_vislotPrevChunkMap[m_islotWritePos] = islotInputLim;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the length of the final chunk, where the recipient is the input stream.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::LastNextChunkLength()
+{
+ int cslotRet = 1;
+ for (int islot = m_islotReadPos; islot-- > 0; )
+ {
+ if (m_vislotNextChunkMap[islot] != -1)
+ return cslotRet;
+ cslotRet++;
+ }
+ return cslotRet + 1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ We've just created a new chunk, with the recipient as the input stream. The beginning of
+ the chunk is passed as 'islotInputMin' and the end of the chunk is assumed to be the
+ read-position of the recipient. Store the mappings into the corresponding
+ output position.
+
+ @param islotOutputMin - beginning of chunk in output stream
+ @param islotInputMin - beginning of chunk in input stream (recipient)
+ @param islotOutputLim - end of chunk in output stream (currently not used)
+ @param fSkipChunkStart - if true, either we have reprocessed part of a
+ previously created chunk,
+ or there was no output generated;
+ in either case, don't record the beginning of the chunk,
+ just make this chunk be part of the previous
+ @param fBackingUp - this chunk results in the stream position moving backwards,
+ so clear anything we're backing over
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::MapOutputChunk(int islotOutputMin, int islotInputMin, int islotOutputLim,
+ bool fSkipChunkStart, int cslotReprocess, bool fBackingUp)
+{
+ Assert(AssertValid());
+
+ // Note: islotInputMin can be less than -1 if there is a large reprocess buffer near the
+ // beginning of the input stream. In which case, fSkipChunk start should be true and
+ // cslotReprocess large enough to keep any of the stuff below from having any problems.
+ //Assert(islotInputMin >= -1);
+
+ if (!fSkipChunkStart)
+ {
+ Assert(islotInputMin >= 0);
+ if (islotInputMin >= 0) // just in case an invalid value was passed
+ m_vislotNextChunkMap[islotInputMin] = islotOutputMin;
+ }
+
+ int islot;
+ for (islot = max(0, islotInputMin + 1 + cslotReprocess); islot < m_islotReadPos; ++islot)
+ m_vislotNextChunkMap[islot] = -1; // not a chunk boundary
+
+// if (fBackingUp && m_islotReadPos < m_vislotNextChunkMap.Size())
+// m_vislotNextChunkMap[m_islotReadPos] = -1;
+
+ if (fBackingUp)
+ for (islot = m_islotReadPos; islot < signed(m_vislotNextChunkMap.size()); islot++)
+ m_vislotNextChunkMap[islot] = -1;
+
+// m_vislotNextChunkMap[m_islotReadPos] = islotOutputLim;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Ensure that the chunk maps for a pair of streams match properly. The recipient is
+ the input stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AssertChunkMapsValid(GrSlotStream * psstrmOut)
+{
+#ifdef _DEBUG
+ GrSlotStream * psstrmIn = this;
+
+ Assert(m_ipass == 0 || (m_ipass + 1 == psstrmOut->m_ipass));
+
+ int islotMapNext;
+ int islotMapPrev;
+ int islot;
+ for (islot = 0; islot < m_islotReadPos; ++islot)
+ {
+ islotMapNext = psstrmIn->ChunkInNext(islot);
+ Assert(islotMapNext != -2);
+ if (islotMapNext != -1)
+ {
+ islotMapPrev = psstrmOut->ChunkInPrev(islotMapNext);
+ if (islotMapPrev == -2)
+ {
+ Assert(islot == psstrmOut->WritePos());
+ }
+ else
+ {
+ Assert(islot == islotMapPrev);
+ }
+ }
+ }
+
+ for (islot = 0; islot < psstrmOut->m_islotWritePos; ++islot)
+ {
+ islotMapPrev = psstrmOut->ChunkInPrev(islot);
+ Assert(islotMapPrev != -2);
+ if (islotMapPrev != -1)
+ {
+ islotMapNext = psstrmIn->ChunkInNext(islotMapPrev);
+ if (islotMapNext == -2)
+ {
+ Assert(islot == psstrmIn->ReadPos());
+ }
+ else
+ {
+ Assert(islot == islotMapNext);
+ }
+ }
+ }
+#endif // _DEBUG
+}
+
+/*----------------------------------------------------------------------------------------------
+ Ensure that corresponding items in the streams of a positioning pass have matching
+ stream indices. The recipient is the output stream.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AssertStreamIndicesValid(GrSlotStream * psstrmIn)
+{
+#ifdef _DEBUG
+ if (!GotIndexOffset())
+ return;
+
+ Assert(m_fUsedByPosPass);
+
+ for (int islot = 0; islot < WritePos(); islot++)
+ {
+ GrSlotState * pslotOut = SlotAt(islot);
+ GrSlotState * pslotIn =
+ psstrmIn->SlotAt(islot + psstrmIn->IndexOffset() - IndexOffset());
+ Assert(pslotOut->PosPassIndex() == pslotIn->PosPassIndex());
+ Assert(pslotOut->HasAsPreviousState(pslotIn));
+ }
+#endif // _DEBUG
+}
+
+/*----------------------------------------------------------------------------------------------
+ Ensure that the roots of all attachments made in this chunk are present
+ in the output stream. (Currently the compiler ensures this by making it an error
+ to write rules that don't do this.)
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::AssertAttachmentsInOutput(int islotMin, int islotLim)
+{
+#ifdef _DEBUG
+ for (int islot = islotMin; islot < islotLim; islot++)
+ {
+ GrSlotState * pslotOut = SlotAt(islot);
+ int dislot = pslotOut->AttachTo();
+ Assert(islotMin <= islot + dislot);
+ Assert(islot + dislot < islotLim);
+ }
+#endif // _DEBUG
+}
+
+/*----------------------------------------------------------------------------------------------
+ Answer the slot index corresponding to the start of the chunk (as mapped to the following
+ stream).
+ ENHANCE: make more robust.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::ChunkInNextMin(int islot)
+{
+ int islotRet = islot;
+ while (m_vislotNextChunkMap[islotRet] == -1 && islotRet > 0)
+ --islotRet;
+ return islotRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Answer the slot index corresponding to the end of the chunk (as mapped to the following
+ stream).
+ ENHANCE: make more robust.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::ChunkInNextLim(int islot)
+{
+ int islotRet = islot + 1;
+ if (islotRet == m_islotReadPos)
+ return islot;
+ while (m_vislotNextChunkMap[islotRet] == -1 && islotRet < m_islotReadPos)
+ {
+ ++islotRet;
+ //Assert(islotRet < signed(m_vislotNextChunkMap.size()));
+ if (islotRet >= signed(m_vislotNextChunkMap.size()))
+ {
+ islotRet = m_vislotNextChunkMap.size() - 1;
+ break;
+ }
+ }
+ return islotRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Skip over the given number slots. This is used to resync the streams when we
+ are restarting a new segment. Specifically the output stream informs the
+ input stream of the number of slots to skip to get the boundary for a chunk that
+ the output finds interesting.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::ResyncSkip(int cslot)
+{
+ Assert(AssertValid());
+ m_islotReadPos += cslot;
+ m_cslotSkippedForResync = cslot;
+ // Should never skip past the beginning of the line.
+ Assert(m_islotSegMin == -1 || m_islotReadPos <= m_islotSegMin);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record the number of slots in the stream that are previous to the official start of the
+ segment.
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::CalcIndexOffset(GrTableManager * ptman)
+{
+ if (GotIndexOffset())
+ return; // already figured it
+
+ if (m_islotSegMin > -1)
+ {
+ m_cslotPreSeg = m_islotSegMin;
+ if (m_fUsedByPosPass)
+ {
+ for (int islotPre = 0; islotPre < WritePos(); islotPre++)
+ {
+ SlotAt(islotPre)->SetPosPassIndex(islotPre - m_cslotPreSeg,
+ m_fInputToPosPass1);
+ }
+ }
+ }
+ // else can't figure it out yet
+
+ // Old code:
+#if 0
+ gid16 chwLB = ptman->LBGlyphID();
+
+ for (int islot = 0; islot < WritePos(); islot++)
+ {
+ if (SlotAt(islot)->IsLineBreak(chwLB))
+ {
+ if (SlotAt(islot)->IsInitialLineBreak(chwLB))
+ {
+ m_cslotPreSeg = islot;
+ }
+ else
+ {
+ // Otherwise, we hit the final line break, which is kind of strange, because
+ // in this case there is no initial line break, and we should have set
+ // m_cslotPreSeg to 0 immediately when it was initialized.
+ Assert(false);
+ m_cslotPreSeg = 0;
+ }
+
+ if (m_fUsedByPosPass)
+ {
+ for (int islotPre = 0; islotPre < WritePos(); islotPre++)
+ {
+ SlotAt(islotPre)->SetPosPassIndex(islotPre - m_cslotPreSeg,
+ m_fInputToPosPass1);
+ }
+ }
+ return;
+ }
+
+ }
+ // No line breaks yet, so no way to tell.
+#endif
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the positions in the streams for the next rule. The recipient is the output stream.
+ If we are moving backwards, copy part of the output stream back to (a temporary buffer
+ in) the input stream, so that we can reprocess it.
+
+ @param cslotArg - how far to skip forward or back; most commonly zero
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::SetPosForNextRule(int cslotArg, GrSlotStream * psstrmIn,
+ bool fOutputOfPosPass)
+{
+ Assert(AssertValid());
+
+ int cslot = cslotArg;
+ // Can't reprocess what has already been read by the next pass. MaxBackup should allow
+ // the flexibility needed, but if not, we fix it here.
+ if (m_islotWritePos + cslot < m_islotReadPos)
+ cslot = m_islotReadPos - m_islotWritePos;
+
+ Assert(psstrmIn->m_ipass == m_ipass-1);
+
+ if (cslot >= 0)
+ {
+ // Skipping forward.
+ Assert(cslot <= psstrmIn->SlotsPendingInContext());
+ for (int islot = 0; islot < cslot; islot++)
+ CopyOneSlotFrom(psstrmIn);
+ }
+ else
+ {
+ // Reprocessing.
+
+ // Save corresponding positions before doing the back-up.
+ int islotReadPosInSave = psstrmIn->ReadPosForNextGet();
+ int islotWritePosOutSave = this->WritePos();
+
+ std::vector<GrSlotState*> vpslotTmp;
+ int islot;
+ if (psstrmIn->SlotsToReprocess() > 0)
+ {
+ // Stick any slots still to reprocess in a temporary buffer.
+ for (islot = psstrmIn->m_islotReprocPos;
+ islot < signed(psstrmIn->m_vpslotReproc.size());
+ islot++)
+ {
+ vpslotTmp.push_back(psstrmIn->m_vpslotReproc[islot]);
+ }
+ }
+
+ psstrmIn->ClearReprocBuffer();
+ psstrmIn->m_islotReprocLim = psstrmIn->m_islotReadPos;
+
+ for (islot = cslot; islot < 0; islot++)
+ psstrmIn->m_vpslotReproc.push_back(m_vpslot[m_islotWritePos+islot]);
+ for (islot = 0; islot < signed(vpslotTmp.size()); islot++)
+ psstrmIn->m_vpslotReproc.push_back(vpslotTmp[islot]);
+ psstrmIn->m_islotReprocPos = 0;
+
+ if (!fOutputOfPosPass && m_fUsedByPosPass)
+ {
+ // Last substitution pass; zap the stream indices, since they may
+ // now be invalid.
+ for (islot = 0; islot < signed(psstrmIn->m_vpslotReproc.size()); islot++)
+ psstrmIn->m_vpslotReproc[islot]->ZapPosPassIndex();
+ }
+
+ // If either the min or lim is in the middle of the reprocess buffer,
+ // adjust as necessary to match where it is in the output stream.
+ int islotSegMinIn = psstrmIn->SegMin();
+ if (islotSegMinIn > -1 &&
+ psstrmIn->ReadPosForNextGet() <= islotSegMinIn &&
+ islotSegMinIn < islotReadPosInSave)
+ {
+ Assert(this->SegMin() > -1);
+ int dislotIn = islotReadPosInSave - islotSegMinIn;
+ int dislotOut = islotWritePosOutSave - SegMin();
+ psstrmIn->SetSegMin(islotSegMinIn + dislotIn - dislotOut, true);
+ if (psstrmIn->m_cslotPreSeg > psstrmIn->SegMin())
+ psstrmIn->m_cslotPreSeg = -1;
+ }
+ int islotSegLimIn = psstrmIn->SegLimIfKnown();
+ if (islotSegLimIn > -1 &&
+ psstrmIn->ReadPosForNextGet() <= islotSegLimIn &&
+ islotSegLimIn < islotReadPosInSave)
+ {
+ int islotSegLimOut = this->SegLimIfKnown();
+ Assert(islotSegLimOut > -1);
+ int dislotIn = islotReadPosInSave - islotSegLimIn;
+ int dislotOut = islotWritePosOutSave - islotSegLimOut;
+ psstrmIn->SetSegLim(islotSegLimIn + dislotIn - dislotOut);
+ }
+
+ m_islotWritePos += cslot;
+
+ if (m_islotSegMin >= m_islotWritePos)
+ m_islotSegMin = -1;
+ if (m_islotSegLim >= m_islotWritePos)
+ m_islotSegLim = -1;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ If a rule was run over a LB glyph, set the appropriate flag in the table manager.
+ CURRENTLY NOT USED
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::SetLBContextFlag(GrTableManager * ptman, int islotStart)
+{
+ gid16 chwLB = ptman->LBGlyphID();
+ for (int islot = islotStart; islot < WritePos(); islot++)
+ {
+ GrSlotState * pslot = SlotAt(islot);
+ if (pslot->IsInitialLineBreak(chwLB))
+ ptman->State()->SetStartLineContext(true);
+ if (pslot->IsFinalLineBreak(chwLB))
+ ptman->State()->SetEndLineContext(true);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the number of slots that have been output by the current pass but must be
+ reprocessed by this same pass. The recipient is serving as the input stream.
+----------------------------------------------------------------------------------------------*/
+int GrSlotStream::SlotsToReprocess()
+{
+ Assert(AssertValid());
+
+ if (m_islotReprocPos == -1)
+ return 0;
+ return (m_vpslotReproc.size() - m_islotReprocPos);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the input at the given slot, that is, the original input, ignoring the issue of
+ reprocessing.
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotStream::GetSlotAt(int islot)
+{
+ return m_vpslot[islot];
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the "current" input item from the rule's perspective, ie, the last slot read.
+ So dislotOffset = 0 means not the slot at the read position but one slot earlier.
+
+ If dislotOffset is less the the original read position that was in effect at the
+ beginning of the rule, we need to read from the output stream, which has the
+ up-to-date values. See the class comment for more details.
+
+ @param dislotOffset - offset from current stream position
+ @param fNullOkay - true if it's okay to return NULL in the situation where we're asking
+ for something before the beginning of the stream
+----------------------------------------------------------------------------------------------*/
+
+GrSlotState * GrSlotStream::RuleInputSlot(int dislotOffset, GrSlotStream * psstrmOutput,
+ bool fNullOkay)
+{
+ Assert(m_islotRuleStartRead <= m_islotReadPos);
+
+ if (dislotOffset > 0)
+ return Peek(dislotOffset - 1);
+
+ int cslotOffsetBack = dislotOffset * -1;
+
+ if (m_islotReprocLim > -1)
+ {
+ // There is a reprocess buffer.
+
+ // Position when starting the rule should never be earlier than the
+ // beginning of the reprocess buffer.
+ Assert(m_islotRuleStartRead >= m_islotReprocLim - signed(m_vpslotReproc.size()));
+
+ // number of items following the reprocess buffer:
+ int cslotPostReproc = m_islotReadPos - m_islotReprocLim;
+
+ if (cslotOffsetBack >= cslotPostReproc)
+ {
+ // number of items in the reprocess buffer that were valid when the rule
+ // was started:
+ int cslotValidReproc = m_islotReprocLim - m_islotRuleStartRead;
+
+ if (cslotOffsetBack >= cslotPostReproc + cslotValidReproc)
+ {
+ // Read from the output stream.
+ int dislotTmp = dislotOffset - 1 + cslotPostReproc + cslotValidReproc;
+ Assert(dislotTmp < 0);
+ return psstrmOutput->PeekBack(dislotTmp);
+ }
+ else
+ {
+ if (m_islotReprocPos > -1)
+ {
+ // Current read pos is inside reprocess buffer.
+ Assert(cslotPostReproc == 0);
+ int islotStartReadReprocBuf = m_vpslotReproc.size() - cslotValidReproc;
+ Assert(islotStartReadReprocBuf >= 0);
+ int islotInReprocBuf = m_islotReprocPos - cslotOffsetBack - 1;
+ if (islotInReprocBuf < islotStartReadReprocBuf)
+ {
+ // Return a slot from before the reprocess buffer, from the
+ // output stream (which is serving as our input stream for precontext
+ // items).
+ return psstrmOutput->PeekBack(islotInReprocBuf - islotStartReadReprocBuf);
+ }
+ else if (islotInReprocBuf < 0)
+ {
+ Assert(false);
+ //int islotReprocMin = m_islotReprocLim - m_vpslotReproc.Size();
+ //return m_vpslot[islotReprocMin + islotInReprocBuf];
+ }
+ else
+ // Read from the reprocess buffer.
+ return m_vpslotReproc[islotInReprocBuf];
+ }
+ else
+ // Looking backwards into the reprocess buffer.
+ return m_vpslotReproc[
+ m_vpslotReproc.size() - cslotOffsetBack + cslotPostReproc - 1];
+ }
+ }
+ }
+
+ // There is no reprocess buffer, or it is not a factor.
+
+ if (m_islotReadPos + dislotOffset - 1 < m_islotRuleStartRead)
+ {
+ // Read from the output stream.
+ return psstrmOutput->PeekBack(m_islotReadPos + dislotOffset - 1 - m_islotRuleStartRead,
+ fNullOkay);
+ }
+ else
+ {
+ // Read normally from the input stream.
+ return m_vpslot[m_islotReadPos - cslotOffsetBack - 1];
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the "current" output item from the rule's perspective, ie, the last slot written.
+ So dislotOffset = 0 means not the slot at the write position but one slot earlier.
+----------------------------------------------------------------------------------------------*/
+
+GrSlotState * GrSlotStream::RuleOutputSlot(int dislotOffset)
+{
+ return m_vpslot[m_islotWritePos - 1 + dislotOffset];
+}
+
+/*----------------------------------------------------------------------------------------------
+ For any slot in the final output that has no associations, set the "before" pointer to
+ the following slot and the "after" pointer to the preceding slot. The idea of this is
+ that it will make it impossible to select a the glyph separately.
+
+ Note that if the slot is the first on the line, it will not be associated with
+ a slot in the previous segment.
+
+ @param chwLB - the glyph IB for the line-break glyphs
+----------------------------------------------------------------------------------------------*/
+void GrSlotStream::SetNeutralAssociations(gid16 chwLB)
+{
+ for (int islot = 0; islot < m_islotWritePos; ++islot)
+ {
+ GrSlotState * pslot = SlotAt(islot);
+ if (pslot->PassModified() > 0 &&
+ (pslot->BeforeAssoc() == kPosInfinity || pslot->AfterAssoc() == kNegInfinity))
+ {
+ pslot->CleanUpAssocs();
+ if (pslot->BeforeAssoc() != kPosInfinity && pslot->AfterAssoc() != kNegInfinity)
+ continue;
+
+ Assert(pslot->BeforeAssoc() == kPosInfinity && pslot->AfterAssoc() == kNegInfinity);
+
+ GrSlotState * pslotBefore = FindAssociatedSlot(islot, 1, chwLB);
+ GrSlotState * pslotAfter = FindAssociatedSlot(islot, -1, chwLB);
+
+ if (pslotBefore && pslotAfter)
+ pslot->Associate(pslotBefore, pslotAfter);
+ else if (pslotBefore)
+ pslot->Associate(pslotBefore);
+ else if (pslotAfter)
+ pslot->Associate(pslotAfter);
+ else
+ // Weird, but can happen with an empty segment.
+ Warn("No assocations");
+
+// Assert(pslot->m_vpslotAssoc.Size() > 0);
+ pslot->m_fNeutralAssocs = true;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find the next or previous slot in the final output that has explicit associations, or
+ return NULL if none.
+
+ @param islot - starting slot
+ @param nInc - +1 if we want to find the next slot, -1 if we want the previous slot
+ @param chwLB - the glyph IB for the line-break glyphs
+----------------------------------------------------------------------------------------------*/
+GrSlotState * GrSlotStream::FindAssociatedSlot(int islot, int nInc, gid16 chwLB)
+{
+ int islotNext = islot + nInc;
+
+ while (islotNext >= 0 && islotNext < m_islotWritePos)
+ {
+ GrSlotState * pslotRet = SlotAt(islotNext);
+ if (pslotRet->IsLineBreak(chwLB))
+ { }
+ else if (pslotRet->PassModified() == 0 ||
+ (pslotRet->m_vpslotAssoc.size() > 0 && pslotRet->m_fNeutralAssocs == false))
+ {
+ return pslotRet;
+ }
+ islotNext += nInc;
+ }
+ return NULL;
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.h
new file mode 100644
index 00000000000..006191252dc
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrSlotStream.h
@@ -0,0 +1,577 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrSlotStream.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Classes GrSlotStream and GrSlotState.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef SLOTSTREAM_INCLUDED
+#define SLOTSTREAM_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+class EngineState;
+class Font;
+
+/*----------------------------------------------------------------------------------------------
+ Each GrSlotStream represents the output of one pass, which also serves as the input
+ of the following pass. Hence it has two positions, a write position for when it is
+ serving as an output stream, and a read position for when it is serving as an input
+ stream. The TableManager holds a list of the streams.
+
+ The reading of slot streams is complicated by two factors. First, it may be necessary
+ to access the "pre-context" items of a rule, which are the slots before the current
+ stream position at the point when the rule is matched. These items will not be modified
+ by the rule, but may have been modified by a previous rule in the same pass, Therefore
+ we need to read these slots from the output stream, rather than the input stream,
+ because the output stream has the current slot attribute values that we want to work with.
+ In order make this happen, we keep track of the read and write positions of
+ the streams at the time the current rule was matched (m_islotRuleStartRead and
+ m_islotRuleStartWrite) and whenever we try to read a slot before m_islotRuleStartRead,
+ we read the corresponding slot from the output stream instead.
+
+ Second, a rule may explicitly set the advance position so that some items are
+ actually reprocessed (and potentially modified) by the same pass. When this happens,
+ we actually copy the slots to reprocess from the output stream back
+ into a temporary buffer (m_vpslotReproc) in the input stream, and set up the stream so
+ that the next read operations will read from the buffer.
+
+ It gets tricky because these two mechanisms can overlap with each other, so care
+ must be taken to read from the right place: the input stream in the normal way,
+ the reprocess buffer, or the output stream. See the RuleInputSlot method.
+
+ Another messy bit of code has to do with maintaining chunks. These are used for
+ backtracking and unwinding after inserting a line-break. Adjacent streams have maps
+ showing how many slots were processed by a single rule; the maps must be consisent
+ between adjacent rules. The following is an example of a pair of valid chunk maps:
+
+ Input stream Output stream
+ Pos next-map prev-map
+ 0 0 0
+ 1 -1 -1
+ 2 2 2
+ 3 4 -1
+ 4 -1 3
+ 5 -1 -1
+ 6 7 -1
+ 7 -1 6
+ 8 -1 -1
+
+ A -1 means that slot is not at the beginning of a chunk. Otherwise, there must be a
+ corresponding value in the parallel map of the adjacent stream--eg, the input stream's
+ next-map(3) == 4 and the output stream's prev-map(4) == 3. Assertions are run
+ regularly to ensure that the chunk maps stay valid.
+
+ So above, the first chunk corresponds to slots 0-1 in the input and 0-1 in the output;
+ two slots were processed by the rule. The second chunk corresponds to slot 2
+ in the input and slots 2-3 in the output (a slot was inserted).
+ The third corresponds to slots 3-5 in the input and 4-6 in the output (three slots
+ processed). The fourth chunk covers slots 6-8 in the input and 7-8 in the output
+ (one slot was deleted).
+
+ ENHANCE SharonC: explain the effect of skipped slots on the chunk maps.
+
+ Hungarian: sstrm
+----------------------------------------------------------------------------------------------*/
+class GrSlotStream {
+
+ friend class GrSlotState;
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor:
+ GrSlotStream(int ipass)
+ {
+ m_ipass = ipass;
+ m_vpslot.clear();
+ m_vislotPrevChunkMap.clear();
+ m_vislotNextChunkMap.clear();
+ m_vpslotReproc.clear();
+ }
+
+ // Destructor:
+ ~GrSlotStream()
+ {
+ ReleaseSlots(0, m_vpslot.size());
+ }
+
+ void ReleaseSlots(int islotMin, int islotLim)
+ {
+ // A slot stream is responsible for deleting the slot states that it created,
+ // that is, the ones whose modified tag equals this stream's pass index.
+ // NO LONGER TRUE - there is a master list of them managed by the GrTableManager.
+// for (int islot = islotMin; islot < islotLim; ++islot)
+// {
+// if (m_vpslot[islot]->m_ipassModified == m_ipass)
+// delete m_vpslot[islot];
+// }
+ }
+
+ // Getters:
+ int WritePos() { return m_islotWritePos; }
+ int ReadPos() { return m_islotReadPos; }
+ bool FullyWritten() { return m_fFullyWritten; }
+
+ int SlotsPresent() { return m_vpslot.size(); }
+
+ // Setters:
+ void SetWritePos(int islot)
+ {
+ m_islotWritePos = islot;
+ }
+ void SetReadPos(int islot)
+ {
+ m_islotReadPos = islot;
+ }
+
+ void Initialize(int ipassPos1, bool fAnythingPrevious)
+ {
+ m_islotWritePos = 0;
+ m_islotReadPos = 0;
+ m_islotReprocPos = -1;
+ m_islotReprocLim = -1;
+ m_islotRuleStartRead = 0;
+ m_islotRuleStartWrite = 0;
+ m_islotReadPosMax = 0;
+ m_cslotSkippedForResync = 0;
+ m_cslotPreSeg = (fAnythingPrevious) ? -1 : 0;
+ m_fFullyWritten = false;
+ m_islotSegMin = -1;
+ m_islotSegLim = -1;
+ m_fUsedByPosPass = (m_ipass + 1 >= ipassPos1);
+ m_fInputToPosPass1 = (m_ipass + 1 == ipassPos1);
+ m_vpslot.clear(); // not responsible for destroying the slots
+ m_vislotPrevChunkMap.clear();
+ m_vislotNextChunkMap.clear();
+ }
+
+public:
+ bool AtEnd();
+ bool AtEndOfContext();
+ void NextPut(GrSlotState* pslot);
+ GrSlotState * NextGet();
+ GrSlotState * Peek(int dislot = 0);
+ GrSlotState * PeekBack(int dislot, bool fNullOkay = false);
+ void Skip(int = 1);
+ GrSlotState * SlotAt(int islot)
+ {
+ return m_vpslot[islot];
+ }
+
+ int OutputOfPass()
+ {
+ return m_ipass;
+ }
+
+ // This function is intended to be used within positioning passes where there is a
+ // one-to-one correspondence beween the slots in consecutive streams.
+ GrSlotState * OutputSlotAt(int islot)
+ {
+ return Peek(islot - ReadPosForNextGet());
+ }
+
+ int ReadPosForNextGet()
+ {
+ return ReadPos() - SlotsToReprocess();
+ }
+
+ // Only valid for streams that are the input or output to a positioning pass.
+ GrSlotState * SlotAtPosPassIndex(int islot)
+ {
+ Assert(GotIndexOffset());
+ Assert(m_fUsedByPosPass);
+ return m_vpslot[islot + m_cslotPreSeg];
+ }
+
+ // Only valid for streams that are the input or output to a positioning pass.
+ bool HasSlotAtPosPassIndex(int islot)
+ {
+ Assert(GotIndexOffset());
+ Assert(m_fUsedByPosPass);
+ return (signed(m_vpslot.size()) > (islot + m_cslotPreSeg));
+ }
+
+ bool AssertValid();
+ void AssertChunkMapsValid(GrSlotStream * psstrmOut);
+ void AssertStreamIndicesValid(GrSlotStream * psstrmIn);
+ void AssertAttachmentsInOutput(int islotMin, int islotLim);
+ bool NoReproc()
+ {
+ return (m_islotReprocPos == -1 || (m_islotReprocPos >= signed(m_vpslotReproc.size())));
+ }
+
+ int SlotsPending();
+ int SlotsPendingInContext();
+ int TotalSlotsPending();
+ bool PastEndOfPositioning(bool fOutput);
+
+ void ClearReprocBuffer()
+ {
+ m_islotReprocPos = -1;
+ m_islotReprocLim = -1;
+ m_vpslotReproc.clear();
+ }
+
+ int ReprocLim()
+ {
+ return m_islotReprocLim;
+ }
+
+ int ReprocMin()
+ {
+ Assert(m_islotReprocPos > -1);
+ return m_islotReprocLim - m_vpslot.size();
+ }
+
+ int RuleStartReadPos()
+ {
+ return m_islotRuleStartRead;
+ }
+
+ void SetRuleStartReadPos()
+ {
+ if (m_islotReprocPos > -1)
+ m_islotRuleStartRead = m_islotReprocLim - SlotsToReprocess();
+ else
+ m_islotRuleStartRead = m_islotReadPos;
+ }
+
+ int RuleStartWritePos()
+ {
+ return m_islotRuleStartWrite;
+ }
+
+ void SetRuleStartWritePos()
+ {
+ m_islotRuleStartWrite = m_islotWritePos;
+ }
+
+ void MarkFullyWritten();
+
+ void SetSegMin(int islot, bool fAdjusting = false)
+ {
+ Assert(fAdjusting || m_islotSegMin == -1 || m_islotSegMin == islot);
+ m_islotSegMin = islot;
+ }
+ void SetSegMinToWritePos(bool fMod = true)
+ {
+ if (m_islotSegMin == -1)
+ m_islotSegMin = m_islotWritePos;
+ else
+ Assert(m_islotSegMin <= m_islotWritePos); // eg, already set to before the initial LB
+ }
+ int SegMin()
+ {
+ return m_islotSegMin;
+ }
+ void SetSegLim(int islot)
+ {
+ m_islotSegLim = islot;
+ }
+ void SetSegLimToWritePos(bool fMod = true)
+ {
+ if (m_islotSegLim > -1 && !fMod)
+ {
+ Assert(m_islotSegLim <= m_islotWritePos);
+ return;
+ }
+ m_islotSegLim = m_islotWritePos;
+ }
+ int SegLimIfKnown()
+ {
+ return m_islotSegLim;
+ }
+ int FinalSegLim()
+ {
+ if (m_islotSegLim > -1)
+ return m_islotSegLim;
+ else
+ return m_islotWritePos;
+ }
+
+ // Return true if we are exactly at the segment min.
+ bool AtSegMin()
+ {
+ if (m_islotSegMin == -1)
+ return false;
+ return (m_islotSegMin == ReadPosForNextGet());
+ }
+
+ // Return true if we are exactly at the segment lim.
+ bool AtSegLim()
+ {
+ if (m_islotSegLim == -1)
+ return false;
+ return (m_islotSegLim == ReadPosForNextGet());
+ }
+
+ int ReadPosMax()
+ {
+ return m_islotReadPosMax;
+ }
+ void SetReadPosMax(int islot)
+ {
+ m_islotReadPosMax = std::max(m_islotReadPosMax, islot);
+ }
+
+ int OldDirLevelRange(EngineState * pengst, int islotStart, int nTopDirection);
+ int DirLevelRange(EngineState * pengst, int islotStart, int nTopDirection,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops);
+ int GetSlotDirLevel(EngineState * pengst, int islot,
+ int nOuterLevel, int nCurrLevel, DirCode dircMarker, DirCode dircOverride);
+ DirCode AdjacentStrongCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF, bool fNumbersAreStrong = false);
+ DirCode TerminatorSequence(EngineState * pengst, int islot, int nInc, DirCode dircPDF);
+ DirCode AdjacentNonBndNeutralCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF);
+
+ void CopyOneSlotFrom(GrSlotStream * psstrmPrev);
+ void SimpleCopyFrom(GrSlotStream * psstrmI, int islotInput, int islotOutput);
+
+ bool MoreSpace(GrTableManager * ptman,
+ float xsSpaceAllotted, bool fWidthIsCharCount,
+ bool fIgnoreTrailingWS, TrWsHandling twsh,
+ float * pxsWidth);
+
+ int InsertLineBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin, LineBrk * plbNextToTry);
+ int MakeSegmentBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin, LineBrk * plbNextToTry);
+ bool FindSegmentEnd(GrTableManager * ptman,
+ int islotStartTry, LineBrk lb, TrWsHandling twsh, int islotMin,
+ int * pislot, int * pichwSegOffset,
+ LineBrk * plbFound, LineBrk * plbNextToTry);
+ bool HasEarlierBetterBreak(int islotBreak, LineBrk lbFound, gid16 chwLB);
+ LineBrk BreakWeightAt(gid16 chwLB, int islot);
+ void AppendLineBreak(GrTableManager *, GrCharStream * pchstrm,
+ LineBrk, DirCode dirc, int islot, bool fInitial, int ichwSegOffset);
+ int FindFinalLineBreak(gid16 chwLB, int islotMin, int islotLim);
+ void AdjustPrevStreamNextChunkMap(GrTableManager * ptman, int islotMod, int nInc);
+ void AdjustNextChunkMap(int islotMin, int islotMod, int nInc);
+
+ void EnsureLocalCopy(GrTableManager * ptman, GrSlotState * pslot, GrSlotStream * psstrmIn);
+ void ReplaceSlotInReprocessBuffer(GrSlotState * pslotOld, GrSlotState * pslotNew);
+
+ void ZapCalculatedDirLevels(int islotLB);
+
+ int MaxClusterSlot(int islotChunkLim)
+ {
+ return MaxClusterSlot(islotChunkLim - 1, islotChunkLim);
+ }
+ int MaxClusterSlot(int islotChunkMin, int islotChunkLim);
+
+ void UnwindInput( int islot, bool fPreBidiPass);
+ void UnwindOutput(int islot, bool fOutputOfPosPass);
+
+ void MapInputChunk( int islotIn, int islotOut, int islotInLim,
+ bool fReprocessing, bool fBackingUp);
+ void MapOutputChunk(int islotOut, int islotIn, int islotOutLim,
+ bool fReprocessing, int cslotReprocess, bool fBackingUp);
+
+ int LastNextChunkLength();
+
+ int ChunkInPrev(int i)
+ {
+ Assert(i >= 0);
+ Assert(i < signed(m_vislotPrevChunkMap.size()));
+ Assert(i < m_islotWritePos);
+ return m_vislotPrevChunkMap[i];
+ }
+ int ChunkInNext(int i)
+ {
+ Assert(i >= 0);
+ Assert(i < signed(m_vislotNextChunkMap.size()));
+ Assert(i < m_islotReadPos);
+ return m_vislotNextChunkMap[i];
+ }
+
+ int ChunkInNextMin(int islot);
+ int ChunkInNextLim(int islot);
+
+ void ResyncSkip(int nslot);
+ int SlotsSkippedToResync()
+ {
+ return m_cslotSkippedForResync;
+ }
+ void ClearSlotsSkippedToResync()
+ {
+ m_cslotSkippedForResync = 0;
+ }
+
+ int IndexOffset()
+ {
+ Assert(GotIndexOffset()); // should have been calculated
+ return m_cslotPreSeg;
+ }
+ void SetIndexOffset(int c)
+ {
+ m_cslotPreSeg = c;
+ }
+ bool GotIndexOffset()
+ {
+ return (m_cslotPreSeg >= 0);
+ }
+ void CalcIndexOffset(GrTableManager * ptman);
+
+ void SetPosForNextRule(int nslot, GrSlotStream * psstrmInput, bool fOutputOfPosPass);
+ void SetLBContextFlag(GrTableManager * ptman, int islotStart);
+ int SlotsToReprocess();
+
+ void SetNeutralAssociations(gid16 chwLB);
+protected:
+ GrSlotState * FindAssociatedSlot(int islot, int nInc, gid16 chwLB);
+
+ GrSlotState * GetSlotAt(int islot);
+
+public:
+ // Used by the action code:
+ void BackupReadPos(int cslot = 1)
+ {
+ for (int islot = 0; islot < cslot; islot++)
+ {
+ if (m_islotReprocLim > -1 && m_islotReprocLim == m_islotReadPos)
+ {
+ if (m_islotReprocPos == -1)
+ m_islotReprocPos = m_vpslotReproc.size() - 1;
+ else
+ --m_islotReprocPos;
+ Assert(m_islotReprocPos >= 0);
+ }
+ else
+ --m_islotReadPos;
+ }
+ }
+
+ GrSlotState * RuleInputSlot(int dislot = 0, GrSlotStream * psstrmOut = NULL,
+ bool fNullOkay = false);
+ GrSlotState * RuleOutputSlot(int dislot = 0);
+
+ void PutSlotAt(GrSlotState * pslot, int islot)
+ {
+ // Currently only used for the final pass, when applying justify.width to
+ // the advance width.
+ Assert(signed(m_vpslot.size()) > islot);
+ Assert(WritePos() > islot);
+ Assert(ReadPos() <= islot);
+ Assert(SlotsToReprocess() == 0);
+ m_vpslot[islot] = pslot;
+ }
+
+protected:
+ // Instance variables:
+ int m_ipass; // which pass this stream is serving as OUTPUT of
+
+ std::vector<GrSlotState*> m_vpslot; // the slots being processed
+
+ // Chunking information:
+ std::vector<int> m_vislotPrevChunkMap; // chunk mapping into previous stream;
+ // -1 if not at a chunk boundary
+ // (this information is needed for
+ // reinitialization after inserting a line break)
+
+ std::vector<int> m_vislotNextChunkMap; // chunk mapping into next stream, or -1
+ // (this information is needed for backtracking)
+
+ // Since most streams serve as both input and output, there are two positions.
+ // Note that readPos <= writePos always.
+ int m_islotWritePos; // where previous pass should put next output
+ int m_islotReadPos; // where following pass should start processing from
+
+ // When we are reprocessing some of the output from the next stream:
+ std::vector<GrSlotState*> m_vpslotReproc; // temporary buffer
+ int m_islotReprocLim; // the read position corresponding to the end of the reprocess
+ // buffer; -1 if buffer is invalid
+ int m_islotReprocPos; // index into m_vpslotReproc from where we should read next;
+ // -1 if we are not reprocessing
+
+ int m_islotRuleStartRead; // read position when the rule was started; any requests before
+ // this point should access the output stream, because it has
+ // the most up-to-date values.
+ int m_islotRuleStartWrite; // write position when the rule started
+
+ bool m_fFullyWritten; // set to true when we can't get any more from the
+ // previous pass; initially false.
+
+ int m_islotSegMin; // the official min of the segment; -1 if not yet set
+ int m_islotSegLim; // the official lim of the segment; -1 if not yet set
+ // (only set for the output of the final line-break pass
+ // and those beyond)
+
+ int m_cslotSkippedForResync; // number of slots skipped to resync;
+ // specifically, the number of slots' worth of the
+ // next-chunk-map that are invalid, not mapped
+ // to any slots in the following stream
+
+ int m_cslotPreSeg; // number of slots previous to the official beginning of the segment;
+ // -1 if we haven't figured it out yet. Used for keeping streams
+ // in the positioning pass in sync; not particularly useful for
+ // substitution passes, and will possibly be left uncalculated.
+
+ bool m_fUsedByPosPass; // true if this is input to or output from a positioning pass
+ bool m_fInputToPosPass1; // true if this is the input to the first positioning pass
+
+ // Max value of m_islotReadPos; used for recognizing infinite loops and forcibly
+ // advancing (see GrPass::CheckInputProgress).
+ int m_islotReadPosMax;
+
+public:
+ // For transduction logging:
+#ifdef TRACING
+// void LogSlotGlyphs(std::ofstream & strmOut, gid16 chwLB);
+#endif // TRACING
+
+ // For test procedures:
+ int NumberOfSlots() { return m_vpslot.size(); }
+ GrSlotState * LastSlotWritten()
+ {
+ if (m_islotWritePos == 0)
+ return NULL;
+ else
+ return m_vpslot[m_islotWritePos-1];
+ }
+ GrSlotState * LastSlotRead()
+ {
+ if (m_islotReadPos == 0)
+ return NULL;
+ else
+ return m_vpslot[m_islotReadPos-1];
+ }
+
+ gid16 GlyphIDAt(int islot)
+ {
+ return m_vpslot[islot]->m_chwGlyphID;
+ }
+
+ int PreChunk() // answer the number of prepended items that are not in any chunk;
+ // should be obsolete now
+ {
+ int islot;
+ for (islot = 0; islot < m_islotReadPos; ++islot)
+ {
+ if (m_vislotNextChunkMap[islot] != -1)
+ return islot;
+ }
+ Assert(false);
+ return islot;
+ }
+
+}; // end of class GrSlotStream
+
+} // namespace gr
+
+
+#endif // !SLOTSTREAM_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.cpp
new file mode 100644
index 00000000000..ff675adb0ad
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.cpp
@@ -0,0 +1,2694 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrTableManager.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ GrTableManager, which handles the interactions between passes, including the demand-pull
+ algorithm.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+#ifndef _WIN32
+#include <stdlib.h>
+#include <math.h>
+#endif
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Constructors and initializers
+----------------------------------------------------------------------------------------------*/
+EngineState::EngineState()
+ : m_ipassJustCalled(-1),
+ m_fStartLineContext(false),
+ m_fEndLineContext(false),
+ ////m_pgg(NULL),
+ m_cslotPreSeg(0),
+ m_islotblkCurr(-1),
+ m_islotNext(kSlotBlockSize),
+ m_fInitialLB(false),
+ m_fFinalLB(false),
+ m_fInsertedLB(false),
+ m_fExceededSpace(false),
+ m_fHitHardBreak(false),
+ m_fRemovedWhtsp(false),
+ m_dxsShrinkPossible(GrSlotState::kNotYetSet),
+ m_islotPosNext(-1),
+ m_xsPosXNext(0),
+ m_ysPosYNext(0),
+ m_dxsTotWidthSoFar(0),
+ m_dxsVisWidthSoFar(0),
+ m_prgzpst(NULL),
+ m_prgpsstrm(NULL)
+{
+ m_vslotblk.clear();
+ m_vprgnSlotVarLenBufs.clear();
+}
+
+void EngineState::Initialize(GrEngine * pgreng, GrTableManager * ptman)
+{
+ m_ptman = ptman;
+ m_cpass = ptman->NumberOfPasses(); // duplicate for convenience
+
+ m_cUserDefn = pgreng->NumUserDefn();
+ m_cFeat = pgreng->NumFeat();
+ m_cCompPerLig = pgreng->NumCompPerLig();
+
+ if (m_prgzpst)
+ delete[] m_prgzpst;
+ m_prgzpst = new PassState[m_cpass];
+ ptman->StorePassStates(m_prgzpst);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructors
+----------------------------------------------------------------------------------------------*/
+GrTableManager::~GrTableManager()
+{
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ delete Pass(ipass);
+
+ delete[] m_prgppass;
+}
+
+EngineState::~EngineState()
+{
+ DestroySlotBlocks();
+
+ delete[] m_prgzpst;
+
+ if (m_prgpsstrm)
+ {
+ for (int isstrm = 0; isstrm < m_cpass; ++isstrm)
+ delete OutputStream(isstrm);
+
+ delete[] m_prgpsstrm;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Delete all the slots.
+----------------------------------------------------------------------------------------------*/
+void EngineState::DestroySlotBlocks()
+{
+ Assert(m_vslotblk.size() == m_vprgnSlotVarLenBufs.size());
+ for (size_t islotblk = 0; islotblk < m_vslotblk.size(); ++islotblk)
+ {
+ delete[] m_vslotblk[islotblk];
+ delete[] m_vprgnSlotVarLenBufs[islotblk];
+ }
+ m_vslotblk.clear();
+ m_vprgnSlotVarLenBufs.clear();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create the passes, and them fill them in by reading from the file stream.
+----------------------------------------------------------------------------------------------*/
+bool GrTableManager::CreateAndReadPasses(GrIStream & grstrm,
+ int fxdSilfVersion, int fxdRuleVersion,
+ int cpassFont, long lSubTableStart, int * rgnPassOffsets,
+ int ipassSub1Font, int ipassPos1Font, int ipassJust1Font, byte ipassPostBidiFont)
+{
+ Assert(ipassSub1Font <= ipassJust1Font);
+ Assert(ipassJust1Font <= ipassPos1Font);
+ Assert(ipassPos1Font <= cpassFont);
+ if (ipassSub1Font > ipassJust1Font || ipassJust1Font > ipassPos1Font
+ || ipassPos1Font > cpassFont)
+ {
+ return false; // bad table
+ }
+
+ // Adjusted indices based on the fact that we have a glyph generation pass that is
+ // pass 0, and possibly a bidi pass:
+ m_cpass = cpassFont + 1;
+ int ipassLB1, ipassSub1, ipassBidi, ipassPos1, ipassJust1;
+ ipassLB1 = 1;
+ ipassSub1 = ipassSub1Font + 1;
+ if (ipassPostBidiFont == 0xFF)
+ {
+ // No bidi pass.
+ m_fBidi = false;
+ // Add 1 below to account for the glyph-generation pass.
+ ipassPos1 = ipassPos1Font + 1;
+ ipassJust1 = ipassJust1Font + 1;
+ ipassBidi = ipassJust1;
+ }
+ else
+ {
+ m_fBidi = true;
+ m_cpass++;
+ Assert(ipassPostBidiFont == ipassJust1Font);
+ ipassJust1 = ipassJust1Font + 2;
+ ipassPos1 = ipassPos1Font + 2;
+ ipassBidi = ipassJust1 - 1;
+ }
+
+ // Always make at least one positioning pass, even if there are no rules.
+ if (ipassPos1 == m_cpass)
+ {
+ m_cpass++;
+ }
+
+ m_prgppass = new GrPass*[m_cpass + 1];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+
+ int ipass = 1;
+ int ipassFont = 0;
+ m_cpassLB = 0;
+ m_ipassJust1 = 1;
+ m_ipassPos1 = 1;
+ for ( ; ipass < m_cpass; ipass++, ipassFont++)
+ {
+ if (ipass < ipassSub1)
+ {
+ m_prgppass[ipass] = new GrLineBreakPass(ipass);
+ m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
+ lSubTableStart + rgnPassOffsets[ipassFont]);
+ m_cpassLB++;
+ m_ipassJust1++;
+ m_ipassPos1++;
+ }
+ else if (ipassSub1 <= ipass && ipass < ipassBidi)
+ {
+ m_prgppass[ipass] = new GrSubPass(ipass);
+ m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
+ lSubTableStart + rgnPassOffsets[ipassFont]);
+ m_ipassJust1++;
+ m_ipassPos1++;
+ }
+ else if (ipassBidi == ipass && ipass < ipassJust1)
+ {
+ m_prgppass[ipass] = new GrBidiPass(ipass);
+ m_prgppass[ipass]->SetTopDirLevel(TopDirectionLevel());
+ ipassFont--; // no corresponding pass in font
+ m_ipassJust1++;
+ m_ipassPos1++;
+ }
+ else if (ipassJust1 <= ipass && ipass < ipassPos1)
+ {
+ // A justification pass is, in essence, a substitution pass.
+ m_prgppass[ipass] = new GrSubPass(ipass);
+ m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
+ lSubTableStart + rgnPassOffsets[ipassFont]);
+ m_ipassPos1++;
+ }
+ else if (ipassPos1 <= ipass)
+ {
+ m_prgppass[ipass] = new GrPosPass(ipass);
+ if (ipassFont < cpassFont)
+ {
+ m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
+ lSubTableStart + rgnPassOffsets[ipassFont]);
+ }
+ else
+ {
+ // No positioning pass in font: create a bogus one.
+ m_prgppass[ipass]->InitializeWithNoRules();
+ }
+ }
+ else
+ {
+ Assert(false);
+ return false; // bad table
+ }
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create passes corresponding to an invalid font.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::CreateEmpty()
+{
+ m_cpass = 2;
+
+ m_prgppass = new GrPass*[2];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+
+ m_prgppass[1] = new GrPosPass(1);
+ m_prgppass[1]->InitializeWithNoRules();
+
+ m_ipassPos1 = 1;
+ m_cpassLB = 0;
+ m_fBidi = false;
+
+ m_engst.CreateEmpty();
+}
+
+void EngineState::CreateEmpty()
+{
+ m_fStartLineContext = false;
+ m_fEndLineContext = false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create the slot streams corresponding to the passes.
+----------------------------------------------------------------------------------------------*/
+void EngineState::CreateSlotStreams()
+{
+ if (m_prgpsstrm)
+ return;
+
+ m_prgpsstrm = new GrSlotStream * [m_cpass];
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ {
+ m_prgpsstrm[ipass] = new GrSlotStream(ipass);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Store information about the pass-states in the pass objects.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::StorePassStates(PassState * rgzpst)
+{
+ for (int ipass = 0; ipass < m_cpass; ipass++)
+ Pass(ipass)->SetPassState(rgzpst + ipass);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Demand-driven loop: with goal of filling up final slot stream, loop backward and forward
+ filling up slot streams until final stream has reached physical capacity.
+
+ @param pgjus - justification agent; NULL if justification is of no interest
+ @param jmodi - (internal) justification mode
+ @param fStartLine, fEndLine
+ @param ichSegLim - known end of segment; -1 when using backtracking
+ @param dxWidthRequested - available width; when justifying, exact width desired
+ @param dxUnjustifiedWidth - when justifying, what the width would be normally
+ @param fNeedFinalBreak - true if the end of the segment needs to be a valid break point
+ @param fMoreText - true if char stream doesn't go up to text-stream lim
+ @param ichFontLim - end of the range that could be rendered by this font
+ @param fInfiniteWidth - used for "measured" segments
+ @param fWidthIsCharCount - kludge for test procedures: the width is a character count,
+ not a pixel count
+ @param lbPref - try for longest segment ending with this breakweight
+ - when justifying, lb to assume
+ @param lbMax - max (last resort) breakweight if no preferred break possible
+ @param ichwCallerBtLim - caller's backtrack lim; -1 if caller is not backtracking
+ @param twsh - how to handle trailing white-space
+ @param fParaRtl - overall paragraph direction
+ @param nDirDepth - direction depth of this segment
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::Run(Segment * psegNew, Font * pfont,
+ GrCharStream * pchstrm, IGrJustifier * pgjus, int jmodi,
+ LayoutEnvironment & layout,
+ int ichSegLim,
+ float dxWidthRequested, float dxUnjustifiedWidth,
+ bool fNeedFinalBreak, bool fMoreText, int ichFontLim,
+ bool fInfiniteWidth, bool fWidthIsCharCount,
+ int ichwCallerBtLim,
+ int nDirDepth, SegEnd estJ)
+{
+ bool fStartLine = layout.startOfLine();
+ bool fEndLine = layout.endOfLine();
+ LineBrk lbPref = layout.bestBreak();
+ LineBrk lbMax = layout.worstBreak();
+ TrWsHandling twsh = layout.trailingWs();
+ bool fParaRtl = layout.rightToLeft();
+ Segment * psegPrev = layout.prevSegment();
+ Segment * psegInit = layout.segmentForInit();
+ std::ostream * pstrmLog = layout.loggingStream();
+
+ m_engst.Initialize(Engine(), this); // do this after the tables have been fully read
+ m_engst.m_jmodi = jmodi;
+ m_engst.m_ipassJustCalled = -1;
+ m_engst.m_twsh = twsh;
+ m_engst.m_fParaRtl = fParaRtl;
+ m_engst.m_dxsShrinkPossible = GrSlotState::kNotYetSet;
+ m_fLogging = (pstrmLog != NULL);
+
+ int cbPrev;
+ byte * pbPrevSegDat = NULL;
+ if (psegPrev)
+ cbPrev = psegPrev->NextSegInitBuffer(&pbPrevSegDat);
+ else if (psegInit)
+ cbPrev = psegInit->ThisSegInitBuffer(&pbPrevSegDat);
+ else
+ cbPrev = 0;
+
+ if (pchstrm->IsEmpty())
+ {
+ m_engst.m_lbPrevEnd = klbNoBreak;
+ InitSegmentAsEmpty(psegNew, pfont, pchstrm, fStartLine, fEndLine);
+ psegNew->SetWidths(0, 0);
+ psegNew->SetUpOutputArrays(pfont, this, NULL, 0, 0, 0, twsh,
+ fParaRtl, nDirDepth, true);
+ psegNew->SetLayout(layout);
+ return;
+ }
+
+ int islotUnderBreak = -1; // position of inserted or final break point in underlying
+ // data; none so far (if an actual LB has been inserted,
+ // this is the index of that slot; otherwise it is the
+ // index of the last valid slot)
+ int islotSurfaceBreak = -1; // position of line break in surface stream; none so far
+ LineBrk lbBestToTry = lbPref;
+ LineBrk lbFound = klbNoBreak;
+
+ float dxMaxWidth = dxWidthRequested;
+
+ if (m_engst.m_jmodi == kjmodiJustify)
+ {
+ Assert(fInfiniteWidth);
+ lbBestToTry = klbClipBreak;
+ lbFound = lbPref;
+ }
+
+ float dxWidth;
+
+ std::vector<int> vnslotNeeded;
+ vnslotNeeded.resize(m_cpass);
+
+ m_engst.InitializeStreams(this, pchstrm, cbPrev, pbPrevSegDat, fNeedFinalBreak, &islotUnderBreak);
+
+ int ipassCurr;
+ int nNeedInput; // kNextPass: go on to the next pass
+ // kBacktrack: need to insert a line break
+ // > 0: need more input from previous pass
+
+ int cchwPostXlbContext = m_pgreng->PostXlbContext();
+ if (ichSegLim > -1)
+ {
+ // When we know exactly where the end of the segment will be, get as much as
+ // we need from the character stream, and then fill up the remaining streams.
+ // (3 below is an arbitrary number; we just want to get slightly more than
+ // we really need.)
+ vnslotNeeded[0] = ichSegLim - pchstrm->Min() + cchwPostXlbContext + 3;
+ for (int ipass = 1; ipass < m_cpass; ipass++)
+ vnslotNeeded[ipass] = 10000;
+ // Start at pass 0.
+ ipassCurr = 0;
+ }
+ else
+ {
+ // When we're doing line-breaking to find the end of the segment, use the
+ // demand-driven approach that tries to fill up the available space.
+ vnslotNeeded[m_cpass - 1] = 1;
+
+ // Start at the last pass. (It might be more efficient to start at the first pass and
+ // generate a small arbitrary number of glyphs.)
+ ipassCurr = m_cpass - 1;
+ }
+
+ while (ipassCurr < m_cpass)
+ {
+ if (ipassCurr == 0)
+ {
+ int nNeedNow = vnslotNeeded[0];
+ // Zeroth pass: generate glyph IDs from the underlying input.
+ nNeedInput = Pass(0)->ExtendGlyphIDOutput(this,
+ pchstrm, OutputStream(0), ichSegLim, cchwPostXlbContext, lbPref,
+ nNeedNow, fNeedFinalBreak, m_engst.m_twsh, &islotUnderBreak);
+ Assert(nNeedInput == kNextPass || nNeedInput == kBacktrack);
+ vnslotNeeded[0] -= nNeedNow;
+ }
+ else if (ipassCurr < m_cpass - 1)
+ {
+ // Middle pass.
+ int cslotNeedNow = vnslotNeeded[ipassCurr];
+ cslotNeedNow = max(1, cslotNeedNow);
+ int cslotGot;
+ Pass(ipassCurr)->ExtendOutput(this,
+ InputStream(ipassCurr), OutputStream(ipassCurr), cslotNeedNow, twsh,
+ &nNeedInput, &cslotGot, &islotUnderBreak);
+ vnslotNeeded[ipassCurr] -= cslotGot;
+ //if (nNeedInput != kNextPass && nNeedInput != kBacktrack)
+ // nNeedInput = max(nNeedInput, cslotNeedNow - cslotGot);
+ }
+ else // (ipassCurr == m_cpass - 1)
+ {
+ // Final pass: position and test allotted space.
+ float dxWidthWShrink = dxMaxWidth;
+ if (m_engst.m_dxsShrinkPossible != GrSlotState::kNotYetSet)
+ dxWidthWShrink += (int)m_engst.m_dxsShrinkPossible;
+ nNeedInput = Pass(ipassCurr)->ExtendFinalOutput(this,
+ InputStream(ipassCurr), OutputStream(ipassCurr),
+ dxWidthWShrink, fWidthIsCharCount, fInfiniteWidth,
+ (islotUnderBreak > -1), (fNeedFinalBreak && lbFound == klbNoBreak),
+ lbMax, twsh,
+ &islotSurfaceBreak, &dxWidth);
+ }
+
+ if (m_engst.m_jmodi == kjmodiJustify)
+ {
+ if (ipassCurr < m_ipassJust1 && !OutputStream(ipassCurr)->FullyWritten())
+ {
+ // When justifying, fill up all the streams up to the point where we need
+ // to interact with the justification routine.
+ // I think this code is obsolete.
+ int nStillNeed = 1000;
+ if ((ipassCurr == 1 && nNeedInput != kNextPass) || ipassCurr == 0)
+ nStillNeed = ichSegLim - (pchstrm->Pos() - pchstrm->Min())
+ + cchwPostXlbContext + 3;
+ if (nStillNeed > 0)
+ {
+ if (nNeedInput == kNextPass)
+ ipassCurr++; // repeat this pass
+ nNeedInput = nStillNeed;
+ }
+ }
+ else if (nNeedInput == kNextPass && ipassCurr + 1 == m_ipassJust1)
+ {
+ CallJustifier(pgjus, ipassCurr, dxUnjustifiedWidth, dxWidthRequested, fEndLine);
+ }
+ }
+ DetermineShrink(pgjus, ipassCurr);
+
+ if (nNeedInput == kBacktrack)
+ {
+ // Final output has overflowed its space--find (or adjust) the break point.
+
+ bool fFoundBreak = Backtrack(&islotUnderBreak,
+ &lbBestToTry, lbMax, twsh, fMoreText, ichwCallerBtLim, fEndLine, &lbFound);
+ if (!fFoundBreak)
+ {
+ // Nothing will fit. Initialize the new segment just enough so that
+ // we can delete it.
+ InitSegmentToDelete(psegNew, pfont, pchstrm);
+ return;
+ }
+ }
+ else if (nNeedInput == kNextPass)
+ {
+ // This pass is sufficiently full--return to following pass.
+ ipassCurr++;
+ }
+ else
+ {
+ // Get more input from previous pass.
+ ipassCurr--;
+ vnslotNeeded[ipassCurr] = nNeedInput;
+ }
+ }
+
+ // At this point we have fully transduced all the text for this segment.
+
+ // Figure out why we broke the segment and what the caller is supposed to do about it.
+ SegEnd est;
+ if (m_engst.m_jmodi == kjmodiJustify)
+ {
+ // Don't change what was passed in.
+ est = estJ;
+ }
+ else if (m_engst.m_fRemovedWhtsp) // (islotUnderBreak > -1 && twsh == ktwshNoWs)
+ {
+ Assert(!m_engst.m_fInsertedLB);
+ est = kestMoreWhtsp;
+ }
+
+ else if (m_engst.m_fHitHardBreak)
+ {
+ est = kestHardBreak;
+ }
+
+ else if (!m_engst.m_fExceededSpace && !fMoreText)
+ // Rendered to the end of the original requested range.
+ est = kestNoMore;
+
+// else if (!m_fExceededSpace && !fNextIsSameWs && fMoreText)
+// // Writing system break; may be more room on the line. But see tweak below.
+// *pest = kestWsBreak;
+
+ else if (m_engst.m_fExceededSpace)
+ {
+ // Exceeded available space, found a legal break.
+ if (twsh == ktwshNoWs && m_engst.m_fRemovedWhtsp)
+ est = kestMoreWhtsp;
+ else
+ est = kestMoreLines;
+ }
+
+ else if (twsh == ktwshOnlyWs)
+ {
+ est = kestOkayBreak; // but see tweak below
+ }
+
+ else
+ {
+ // Broke because of something like a font change. Determine whether this is a legal
+ // break or not.
+ // TODO SharonC: handle the situation where it is legal to break BEFORE the first
+ // character of the following segment.
+ Assert(fMoreText);
+ //Assert(fNextIsSameWs);
+ if (ichwCallerBtLim > -1)
+ {
+ Assert(m_engst.m_fInsertedLB);
+ }
+ else if (ichSegLim > -1)
+ {
+ // We stopped where caller said to.
+ Assert(fInfiniteWidth);
+ }
+ else
+ {
+ Assert(!m_engst.m_fInsertedLB);
+ Assert(islotUnderBreak == -1 || m_engst.m_fFinalLB);
+ }
+ int islotTmp = OutputStream(m_cpass - 1)->WritePos();
+ GrSlotState * pslotTmp;
+ if (m_engst.m_fFinalLB || m_engst.m_fInsertedLB)
+ pslotTmp = OutputStream(m_cpass-1)->SlotAt(islotTmp - 2);
+ else
+ pslotTmp = OutputStream(m_cpass-1)->SlotAt(islotTmp - 1);
+
+ if (abs(pslotTmp->BreakWeight()) <= lbPref)
+ est = kestOkayBreak;
+
+ else if (abs(pslotTmp->BreakWeight()) > lbMax)
+ est = kestBadBreak;
+
+ else if (OutputStream(m_cpassLB)->HasEarlierBetterBreak(islotUnderBreak, lbFound,
+ this->LBGlyphID()))
+ {
+ est = kestBadBreak;
+ }
+ else
+ est = kestOkayBreak;
+
+ // We no longer have the ability to know whether or not the next segment will use
+ // the same writing system.
+ //if (est == kestBadBreak && m_engst.m_fExceededSpace && !fNextIsSameWs && fMoreText)
+ // est = kestWsBreak;
+ }
+
+ // Make a segment out of it and return it.
+ int dichSegLen;
+ InitNewSegment(psegNew, pfont, pchstrm, pgjus,
+ islotUnderBreak, islotSurfaceBreak, fStartLine, fEndLine, ichFontLim, lbFound, est,
+ &dichSegLen);
+ if (psegNew->segmentTermination() == kestNothingFit)
+ {
+ return;
+ }
+ else if (psegNew->segmentTermination() == kestHardBreak &&
+ psegNew->startCharacter() == psegNew->stopCharacter())
+ {
+ // Empty segment caused by a hard-break.
+ m_engst.m_lbPrevEnd = klbNoBreak;
+ psegNew->SetWidths(0, 0);
+ psegNew->SetUpOutputArrays(pfont, this, NULL, 0, 0, 0, twsh,
+ fParaRtl, nDirDepth, true);
+ psegNew->SetLayout(layout);
+ return;
+ }
+
+ psegNew->RecordInitializationForThisSeg(cbPrev, pbPrevSegDat);
+
+ if ((est == kestNoMore || est == kestWsBreak) && twsh == ktwshOnlyWs &&
+ dichSegLen < pchstrm->Lim() - pchstrm->Min())
+ {
+ // If we are asking for white-space only, and we didn't use up everything in the font
+ // range, we could possibly have gotten an initial white-space only segment
+ // (as opposed to a writing system break).
+ est = kestOkayBreak;
+ psegNew->FixTermination(est);
+ }
+
+ // Do this before fixing up the associations below.
+ //if (m_pgreng->LoggingTransduction())
+ // WriteTransductionLog(pchstrm, *ppsegRet,
+ // cbPrev, pbPrevSegDat, pbNextSegDat, pcbNextSegDat);
+ WriteTransductionLog(pstrmLog, pchstrm, psegNew, cbPrev, pbPrevSegDat);
+
+ RecordAssocsAndOutput(pfont, psegNew, fWidthIsCharCount, twsh, fParaRtl, nDirDepth);
+
+ // Do this after fixing up the associations.
+ //if (m_pgreng->LoggingTransduction())
+ // WriteAssociationLog(pchstrm, *ppsegRet);
+ WriteAssociationLog(pstrmLog, pchstrm, psegNew);
+
+ psegNew->SetLayout(layout);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create a new segment to return.
+
+ @param pchstrm - input stream
+ @param pgjus - justification agent, in case this segment needs to be
+ stretched or shrunk
+ @param islotLBStreamBreak - position of inserted line break slot (which should be equal
+ to the position in the glyph generation stream);
+ -1 if no line-break was inserted (we rendered to the
+ end of the range)
+ @param islotSurfaceBreak - position of line break slot in final (surface) stream
+ @param fStartLine - does this segment start a line?
+ @param fEndLine - does this segment end a line?
+ @param ichFontLim - end of range that could be rendered by this font
+ @param lbEndFound - line break found; possibly adjusted here
+ @param est - why did the segment terminate
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::InitNewSegment(Segment * psegNew,
+ Font * pfont, GrCharStream * pchstrm, IGrJustifier * pgjus,
+ int islotLBStreamBreak, int islotSurfaceBreak, bool fStartLine, bool fEndLine, int ichFontLim,
+ LineBrk lbEndFound, SegEnd est, int * pdichSegLen)
+{
+ LineBrk lbStart = m_engst.m_lbPrevEnd;
+ LineBrk lbEnd = lbEndFound;
+ if (est == kestBadBreak)
+ lbEnd = klbLetterBreak;
+
+ int ichwMin = pchstrm->Min();
+ int ichwLim;
+
+// int cslotPreSegStream0 = m_cslotPreSeg;
+// if (m_fInitialLB && m_cpassLB > 0)
+// {
+// // Initial LB is included in m_cslotPreSeg, but is not in stream 0.
+// // --Not really needed, because both islotLBStreamBreak and m_cslotPreSeg take
+// // the initial LB into account if it is there.
+// cslotPreSegStream0--;
+// }
+
+ // No longer have to subtract this, because the chunk map takes it into
+ // consideration.
+ //int cslotPreInitialLB = m_cslotPreSeg - (m_fInitialLB ? 1 : 0);
+
+ //int ichwOldTmp;
+
+ if (m_engst.m_fInsertedLB)
+ {
+ Assert(islotLBStreamBreak > -1);
+ int ichwSegLim = m_engst.LbSlotToSegLim(islotLBStreamBreak, pchstrm, m_cpassLB);
+ ichwLim = ichwSegLim + pchstrm->Min(); // - cslotPreInitialLB;
+
+ // Old result, for debugging:
+ //ichwOldTmp = islotLBStreamBreak + pchstrm->Min() - m_cslotPreSeg;
+ }
+ else if (m_engst.m_fFinalLB || islotLBStreamBreak == -1)
+ ichwLim = pchstrm->Lim();
+ else
+ {
+ int ichwSegLim = m_engst.LbSlotToSegLim(islotLBStreamBreak, pchstrm, m_cpassLB);
+ ichwLim = ichwSegLim + pchstrm->Min(); // - cslotPreInitialLB;
+
+ // Old result, for debugging:
+ // islotLBStreamBreak is the last slot in the segment, not the LB glyph; hence +1.
+ //ichwOldTmp = islotLBStreamBreak + pchstrm->Min() - m_cslotPreSeg + 1;
+ }
+
+ *pdichSegLen = ichwLim - ichwMin;
+
+ if (ichwMin >= ichwLim)
+ {
+ if (est == kestHardBreak)
+ {
+ // Empty segment cause by a hard-break.
+ InitSegmentAsEmpty(psegNew, pfont, pchstrm, fStartLine, fEndLine);
+ psegNew->FixTermination(est);
+ }
+ else
+ {
+ // Invalid empty segment.
+ Assert(ichwMin == ichwLim);
+ InitSegmentToDelete(psegNew, pfont, pchstrm);
+ }
+ return;
+ }
+
+ Assert(psegNew);
+
+ psegNew->Initialize(pchstrm->TextSrc(),
+ ichwMin, ichwLim,
+ lbStart, lbEnd, est, fStartLine, fEndLine, m_pgreng->RightToLeft());
+
+ psegNew->SetEngine(m_pgreng);
+ psegNew->SetFont(pfont);
+ psegNew->SetJustifier(pgjus);
+ psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
+
+ bool fNextSegNeedsContext =
+ !(est == kestNoMore || est == kestWsBreak
+ || ichwLim >= pchstrm->Lim() || ichwLim >= ichFontLim);
+
+ InitializeForNextSeg(psegNew, islotLBStreamBreak, islotSurfaceBreak, lbEnd,
+ fNextSegNeedsContext, pchstrm);
+
+ psegNew->SetPreContext(0 - m_pgreng->PreXlbContext());
+}
+
+/*----------------------------------------------------------------------------------------------
+ The newly created segment is invalid, for instance, because we were backtracking and
+ couldn't find a valid break point. Initialize it just enough so that it can be
+ deleted by the client.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::InitSegmentToDelete(Segment * psegNew, Font * pfont,
+ GrCharStream * pchstrm)
+{
+ psegNew->Initialize(pchstrm->TextSrc(), 0, 0,
+ klbClipBreak, klbClipBreak, kestNothingFit, false, false,
+ m_pgreng->RightToLeft());
+
+ psegNew->SetEngine(m_pgreng);
+ psegNew->SetFont(pfont);
+ psegNew->SetJustifier(NULL); // can't justify an empty segment
+ psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
+ psegNew->SetPreContext(0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Map from the given slot (which is generally the final LB slot) to the end of the segment,
+ taking into account the fact that a single slot may represent two 16-bit surrogates.
+
+ There are several approaches that seem reasonable but do NOT work. (I tried them!)
+ You can't calculate it directly from the length of the streams, because that doesn't take
+ into account the possible presence of surrogate pairs in the character stream. You can't
+ use the chunk map at the point of the LB, because if a rule spanned a LB the chunk won't
+ have ended there and so there won't be any valid information.
+
+ What seems to work is to figure out the slot(s) in the zeroth stream using the associations
+ and then use the segment offset for this slot. This should be reliable because there is
+ always a one-to-one correspondence between glyphs in the line-break passes (ie, no
+ insertions or deletions), so the associations should be dependable and straightforward.
+----------------------------------------------------------------------------------------------*/
+int EngineState::LbSlotToSegLim(int islotLB, GrCharStream * pchstrm, int cpassLB)
+{
+ Assert(islotLB < OutputStream(cpassLB)->WritePos());
+
+ // Figure out the corresponding characters in the zeroth stream. These should be straight-
+ // forward to figure out because no substitutions are permitted in the LB passes.
+ // I do the slots before and after the LB, if possible, as a sanity check.
+ GrSlotStream * psstrmLB = OutputStream(cpassLB);
+ GrSlotState * pslotPreLB = (m_fFinalLB || m_fInsertedLB) ?
+ psstrmLB->SlotAt(islotLB - 1) :
+ psstrmLB->SlotAt(islotLB);
+ GrSlotState * pslotPostLB = (psstrmLB->WritePos() > islotLB + 1) ?
+ psstrmLB->SlotAt(islotLB + 1) :
+ NULL;
+
+ int ichwPreLB = pslotPreLB->AfterAssoc();
+
+ int ichwSegLim;
+ if (pslotPostLB)
+ {
+ ichwSegLim = pslotPostLB->BeforeAssoc();
+ Assert(ichwPreLB + 1 == ichwSegLim
+ || ichwPreLB + 2 == ichwSegLim); // in case of a surrogate
+ }
+ else
+ {
+ ichwSegLim = ichwPreLB + 1;
+ while (!pchstrm->AtUnicodeCharBoundary(ichwSegLim))
+ ichwSegLim++;
+ Assert(pchstrm->AtUnicodeCharBoundary(ichwSegLim));
+ }
+
+ // Old buggy routine that doesn't handle the case where a rule (and hence the chunk map) did
+ // not end at the LB character:
+ // Map backwards through the LB pass streams, if any.
+ //int islotAdjusted = islotLB + 1; // after the LB
+ //for (int ipass = m_cpassLB; ipass > 0; ipass--)
+ //{
+ // islotAdjusted = ChunkInPrev(ipass, islotAdjusted, pchstrm);
+ //}
+ //
+ //int ichwSegLim = ChunkInPrev(0, islotAdjusted, pchstrm);
+
+ // Mapping from 32-bit to 16-bit should only increase the index. Except that there
+ // may be a LB in the slot stream that is not in the character stream, so it could be
+ // one less.
+ Assert(ichwSegLim + m_cslotPreSeg >= islotLB - 1);
+
+ return ichwSegLim;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the chunk mapping into the previous stream, taking into account the fact that it
+ is not recorded for the write-position.
+----------------------------------------------------------------------------------------------*/
+int GrTableManager::ChunkInPrev(int ipass, int islot, GrCharStream * pchstrm)
+{
+ GrSlotStream * psstrmOut = OutputStream(ipass);
+ GrSlotStream * psstrmIn = (ipass == 0) ? NULL : InputStream(ipass);
+
+ int islotTmp = islot;
+ int islotAdjusted;
+ do {
+ if (islot >= psstrmOut->WritePos())
+ {
+ Assert(islot == psstrmOut->WritePos());
+ islotAdjusted = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
+ Assert(islotAdjusted > -1);
+ }
+ else
+ islotAdjusted = psstrmOut->ChunkInPrev(islotTmp);
+ islotTmp--;
+ } while (islotAdjusted == -1);
+
+ return islotAdjusted;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create a new segment corresponding to an empty string.
+
+ @param pchstrm - input stream
+ @param fStartLine - does this segment start a line?
+ @param fEndLine - does this segment end a line?
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::InitSegmentAsEmpty(Segment * psegNew, Font * pfont,
+ GrCharStream * pchstrm, bool fStartLine, bool fEndLine)
+{
+ LineBrk lbStart = m_engst.m_lbPrevEnd;
+ LineBrk lbEnd = klbNoBreak;
+
+ int ichwMin = 0;
+ int ichwLim = 0;
+
+ Assert(psegNew);
+
+ psegNew->Initialize(pchstrm->TextSrc(), ichwMin, ichwLim,
+ lbStart, lbEnd, kestNoMore, fStartLine, fEndLine, m_pgreng->RightToLeft());
+
+ psegNew->SetEngine(m_pgreng);
+ psegNew->SetFont(pfont);
+ psegNew->SetJustifier(NULL); // can't justify an empty segment
+ psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
+
+ byte pbNextSegDat[256];
+ int cbNextSegDat;
+ int * pcbNextSegDat = &cbNextSegDat;
+
+ // Initialization for (theoretical) next segment.
+ byte * pb = pbNextSegDat;
+ *pb++ = byte(lbEnd);
+ *pb++ = kdircNeutral;
+ *pb++ = kdircNeutral;
+ *pb++ = 0;
+ for (int ipass = 0; ipass < m_cpass; ipass++)
+ *pb++ = 0;
+ *pcbNextSegDat = 0;
+ psegNew->RecordInitializationForNextSeg(*pcbNextSegDat, pbNextSegDat);
+
+ psegNew->SetPreContext(0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find a line-break and unwind the passes. Return true if we were able to
+ backtrack successfully (which may have meant using a less-than-optimal line-break).
+ Return false if no line-break could be found (because maxBreakWeight did not allow
+ letter breaks or clipping--generally because there was already something on this
+ line).
+
+ @param pislotPrevBreak - position of previously-created break, -1 if none;
+ this is the index of the line-break glyph if any,
+ or the index of the last slot in the segment;
+ adjusted to contain the position of the newly
+ found break
+ @param plbMin - minimum (best) line break weight to try
+ @param lbMax - maximum (worst possible) line break weight
+ @param twsh - how to handle trailing white-space
+ @param fMoreText - true if char stream doesn't go up to original lim
+ @param ichwCallerBtLim - caller's backtrack lim; -1 if caller is not backtracking
+ @param plbFound - kind of line-break created
+----------------------------------------------------------------------------------------------*/
+bool GrTableManager::Backtrack(int * pislotPrevBreak,
+ LineBrk * plbMin, LineBrk lbMax, TrWsHandling twsh, bool fMoreText,
+ int ichwCallerBtLim, bool fEndLine,
+ LineBrk * plbFound)
+{
+ int islotStartTry;
+ //if (*pislotPrevBreak == ichwCallerBtLim - 1)
+ //{
+ // islotStartTry = *pislotPrevBreak;
+ //}
+ //else
+ if (*pislotPrevBreak == -1)
+ {
+ // If no line break has been found so far, figure out where to start trying based
+ // on where the final stream choked.
+ GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
+ if ((islotStartTry
+ = m_engst.TraceStreamZeroPos(psstrmFinal->WritePos()-1, TopDirectionLevel()))
+ == -1)
+ {
+ // Just start looking at the end of what's been generated.
+ islotStartTry = OutputStream(m_cpassLB)->ReadPos() - 1;
+ }
+ }
+ else
+ {
+ // Start just before previous line break.
+ if (m_engst.m_fInsertedLB || m_engst.m_fFinalLB)
+ islotStartTry = *pislotPrevBreak - 2; // skip inserted LB and previous slot
+ else
+ islotStartTry = *pislotPrevBreak - 1; // skip previous slot
+ }
+ if (ichwCallerBtLim > -1 && islotStartTry > ichwCallerBtLim - 1)
+ {
+ islotStartTry = ichwCallerBtLim - 1;
+ }
+
+ // Determine if we want to insert an actual line-break "glyph". Don't do that if
+ // we are omitting trailing white space or we are at a writing-system or font break.
+ bool fInsertLB;
+ if (twsh == ktwshNoWs)
+ // omitting trailing white-space
+ fInsertLB = false;
+
+ // These rules seem more complicated than what is necessary... :-/
+ //else if (twsh == ktwshOnlyWs)
+ // // trailing white-space segment
+ // fInsertLB = true;
+ //else if (ichwCallerBtLim > -1)
+ // // backtracking
+ // fInsertLB = true;
+ //else if (*pislotPrevBreak > -1)
+ // // no longer at the edge of the writing system or font
+ // fInsertLB = true;
+ //else if (!fMoreText)
+ // // at final edge of total range to render
+ // fInsertLB = true;
+ //else
+ // fInsertLB = false;
+
+ else if (!fEndLine)
+ fInsertLB = false;
+ else
+ fInsertLB = true;
+
+ // Try to insert a line-break in the output of the (final) line-break pass (if any, or
+ // the output of the glyph-generation pass). First try the preferred (strictest)
+ // break weight and gradually relax.
+ LineBrk lb = *plbMin;
+ Assert(*plbMin <= lbMax);
+ GrSlotStream * psstrmLB = OutputStream(m_cpassLB);
+ islotStartTry = min(islotStartTry, psstrmLB->WritePos() - 1);
+ int islotNewBreak = -1;
+ while (lb <= lbMax)
+ {
+ LineBrk lbNextToTry;
+ if (fInsertLB)
+ {
+ islotNewBreak = psstrmLB->InsertLineBreak(this,
+ *pislotPrevBreak, m_engst.m_fInsertedLB, islotStartTry,
+ lb, twsh, m_engst.m_cslotPreSeg, &lbNextToTry);
+ }
+ else
+ {
+ islotNewBreak = psstrmLB->MakeSegmentBreak(this,
+ *pislotPrevBreak, m_engst.m_fInsertedLB, islotStartTry,
+ lb, twsh, m_engst.m_cslotPreSeg, &lbNextToTry);
+ }
+ if (islotNewBreak > -1)
+ break;
+ if (lb >= lbMax)
+ break;
+ lb = IncLineBreak(lb); // relax the break weight
+ }
+
+ if (islotNewBreak == -1)
+ {
+ return false;
+ }
+
+ // We've successfully inserted a line break.
+
+ if (fInsertLB)
+ m_engst.m_fInsertedLB = true;
+
+ m_engst.m_fFinalLB = false;
+
+ UnwindAndReinit(islotNewBreak);
+
+ *pislotPrevBreak = islotNewBreak;
+ *plbMin = lb; // return the best break we were able to find, so we don't keep trying
+ // for a better one when we know now that we can't find it
+ *plbFound = lb;
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method is called after backtracking or removing trailing white-space.
+ Unwind the following slot streams as necessary depending on where the change was made.
+
+ @param islotNewBreak - in output of (final) line-break pass
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::UnwindAndReinit(int islotNewBreak)
+{
+ OutputStream(m_cpassLB)->ZapCalculatedDirLevels(islotNewBreak);
+
+ // Mark the passes before the line-break pass as fully written, so that if there
+ // isn't a line-break glyph to intercept, we don't keep trying to get more input
+ // from them.
+ int ipass;
+ for (ipass = 1; ipass < m_cpassLB + 1; ++ipass)
+ {
+ InputStream(ipass)->MarkFullyWritten();
+ }
+
+ // Unwind the passes to the changed positions.
+ // Note that we don't need to unwind pass 0, since all it does is generate glyph IDs.
+ // Also we don't need to unwind the line-break passes, because conceptually they happen
+ // before the break is inserted.
+
+ int islotChgPos = islotNewBreak;
+ bool fFirst = true;
+ for (ipass = m_cpassLB + 1 ; ipass < m_cpass ; ++ipass)
+ {
+ islotChgPos =
+ Pass(ipass)->Unwind(this, islotChgPos, InputStream(ipass), OutputStream(ipass),
+ fFirst);
+ fFirst = false;
+ }
+ // For anything that may have been skipped in the final output:
+ OutputStream(m_cpass - 1)->SetReadPos(0);
+ OutputStream(m_cpass - 1)->SetReadPosMax(0);
+ Pass(m_cpass - 1)->UndoResyncSkip();
+ OutputStream(m_cpass - 1)->ClearSlotsSkippedToResync();
+
+ m_engst.InitPosCache();
+
+ m_engst.m_dxsShrinkPossible = GrSlotState::kNotYetSet; // recalculate it
+}
+
+/*----------------------------------------------------------------------------------------------
+ Store information in the newly created segment that will allow us to reinitalize
+ the streams in order to process the next segment, appropriately handling any
+ cross-line-boundary contextuals.
+
+ The information required is the number of glyphs in the first stream that must
+ be reprocessed, and a skip-offset between each stream indicating the beginning
+ of chunk boundaries.
+
+ In most cases, where there are no cross-line-boundary contextuals, all these numbers
+ will be zero.
+
+ The buffer generated is of the following format (all are 1 byte, unsigned):
+ end breakweight
+ previous strong directionality code
+ previous terminator dir code
+ restart backup
+ skip offsets for each pass
+ This format must match what is generated by InitializeStreams.
+
+ @param pseg - newly created segment
+ @param islotUnderBreak - position of line break inserted in underlying stream (output
+ of glyph-generation pass--stream 0); -1 if we rendered to
+ the end of the range
+ @param islotSurfaceBreak - position of line break in surface stream;
+ -1 if we rendered to the end of the range
+ @param lbEnd - kind of line-break at the end of this segment
+ @param fNextSegNeedsContext - true if we need to remember the context for the next seg
+ @param pchstrm - character stream input for this segment
+ @param cbNextMax - amount of space available in the buffer
+ @param pbNextSegDat - buffer for initializing next segment
+ @param pcbNextSegDat - amount of space used in buffer
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::InitializeForNextSeg(Segment * pseg,
+ int islotUnderBreak, int islotSurfaceBreak, LineBrk lbEnd,
+ bool fNextSegNeedsContext, GrCharStream * pchstrm)
+{
+ byte pbNextSegDat[256];
+ int cbNextSegDat;
+ int * pcbNextSegDat = &cbNextSegDat;
+
+ std::vector<int> vcslotSkipOffsets;
+ vcslotSkipOffsets.resize(m_cpass);
+
+ byte * pb = pbNextSegDat;
+
+ if (!fNextSegNeedsContext)
+ {
+ // No contextualization between this segment and the next, whatever kind of renderer
+ // it might use.
+ *pcbNextSegDat = 0;
+ return;
+ }
+
+ gid16 chwLB = LBGlyphID();
+
+ int islotUnderLim = islotUnderBreak;
+ if (!m_engst.m_fInsertedLB && !m_engst.m_fFinalLB)
+ // Then islotUnderBreak is the position of the last slot in the segment; increment
+ // to get the lim in stream zero.
+ islotUnderLim++;
+
+ int islotSurfaceLim = islotSurfaceBreak;
+ if (islotSurfaceLim == -1)
+ islotSurfaceLim = OutputStream(m_cpass - 1)->FinalSegLim();
+
+ *pb++ = byte(lbEnd);
+
+ // Find previous strong and terminator directionality codes.
+
+ GrSlotStream * psstrm = OutputStream(m_cpass - 1);
+ DirCode dircStrong = kdircNeutral;
+ DirCode dircTerm = kdircNeutral;
+ int islot;
+ for (islot = islotSurfaceLim; islot-- > 0; )
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ DirCode dirc = pslot->Directionality();
+ if (dircTerm == kdircNeutral && dirc == kdircEuroTerm)
+ dircTerm = dirc;
+ if (StrongDir(dirc))
+ {
+ dircStrong = dirc;
+ break;
+ }
+ }
+ *pb++ = byte(dircStrong);
+ *pb++ = byte(dircTerm);
+
+ // Record how much of each pass to redo in the next segment.
+ // The basic algorithm is described in the "WR Data Transform Engine" document.
+ // But here we are doing a variation on what is described there. We are calculating
+ // the backup locations for BOTH the rule start locations and the necessary pre-contexts.
+ // It is the precontext values that are recorded for use by the following segment. But we
+ // also calculate the positions for the rule-start locations to make sure there is enough
+ // pre-context at each pass.
+
+ int islotRS = islotSurfaceLim; // rule-start positions
+ int islotPC = islotRS; // to handle pre-context positions
+
+ // If line-breaks are irrelevant to this font, we don't need to bother.
+ bool fGiveUp = !m_pgreng->LineBreakFlag();
+
+ int ipass;
+ for (ipass = m_cpass - 1; ipass >= 0 && !fGiveUp; --ipass)
+ {
+ GrSlotStream * psstrmIn = (ipass == 0) ? NULL : InputStream(ipass);
+ GrSlotStream * psstrmOut = OutputStream(ipass);
+ int islotBackupMin = (ipass == 0) ? 0 : psstrmOut->SegMin();
+ if (ipass >= m_cpassLB && m_engst.m_fInitialLB)
+ islotBackupMin++; // how far we can back up--not before the start of this segment
+
+ int islotPrevRS = 0; // corresponding slot in the previous stream for rule-start position
+ int islotPrevPC = 0; // same for pre-context position
+
+ // Initially we have to include at least this many prior slots:
+ int cslotSkipOffset = 0;
+
+ if (islotRS == psstrmOut->WritePos())
+ {
+ islotPrevRS = (ipass == 0) ? pchstrm->Pos() : psstrmIn->ReadPos();
+ }
+ else
+ {
+ // Ignore the final line-break, because it is explicitly inserted during
+ // the (final) line-break pass.
+// if (ipass == m_cpassLB && psstrm->SlotAt(islotRS)->IsFinalLineBreak(chwLB))
+// {
+// Assert(islotRS > 0);
+// islotRS--;
+// }
+ // Ignore the chunk in the pass that generated the line break that corresponds
+ // to the inserted line break being chunked with the previous glyph--we don't
+ // want to treat that as a cross-line-boundary contextual!
+ if (ipass == m_cpassLB && psstrmOut->SlotAt(islotRS)->IsFinalLineBreak(chwLB))
+ {
+// Assert(psstrm->ChunkInPrev(islotRS) == -1);
+ if (islotRS + 1 == psstrmOut->WritePos())
+ islotPrevRS = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
+ else
+ islotPrevRS = psstrmOut->ChunkInPrev(islotRS + 1);
+ }
+ else
+ {
+ // Back up to the beginning of a chunk.
+ while (islotRS >= islotBackupMin &&
+ (islotPrevRS = psstrmOut->ChunkInPrev(islotRS)) == -1)
+ {
+ --islotRS;
+ //++cslotSkipOffset;
+ }
+ }
+ }
+ if (islotPrevRS == -1 || islotRS < islotBackupMin) // hit the start of the segment
+ {
+ // In order to get enough context to be sure to run the same rules again,
+ // we'd have to back up into the previous segment. Too complicated, so give up.
+ fGiveUp = true;
+ break;
+ }
+
+ int cslotPreContext = Pass(ipass)->MaxRulePreContext();
+LBackupPC:
+ if (islotPC == psstrmOut->WritePos())
+ {
+ islotPrevPC = (ipass == 0) ? pchstrm->Pos() : psstrmIn->ReadPos();
+ }
+ else
+ {
+ if (ipass == m_cpassLB && psstrmOut->SlotAt(islotPC)->IsFinalLineBreak(chwLB))
+ {
+ if (islotPC+1 == psstrmOut->WritePos())
+ islotPrevPC = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
+ else
+ islotPrevPC = psstrmOut->ChunkInPrev(islotPC+1);
+ }
+ else
+ {
+ // Back up to the beginning of a chunk; also make sure there are enough slots
+ // to handle the required pre-context for this pass.
+ while (islotPC >= islotBackupMin &&
+ ((islotPrevPC = psstrmOut->ChunkInPrev(islotPC)) == -1 ||
+ islotPrevRS - islotPrevPC < cslotPreContext))
+ {
+ --islotPC;
+ ++cslotSkipOffset;
+ }
+ }
+ }
+ if (islotPC >= islotBackupMin && islotPrevRS - islotPrevPC < cslotPreContext)
+ {
+ --islotPC;
+ ++cslotSkipOffset;
+ goto LBackupPC;
+ }
+ if (islotPrevPC == -1 || islotPC < islotBackupMin) // hit the start of the segment
+ {
+ fGiveUp = true;
+ break;
+ }
+
+ vcslotSkipOffsets[ipass] = cslotSkipOffset;
+
+ islotRS = islotPrevRS;
+ islotPC = islotPrevPC;
+
+ if (ipass == 0)
+ {
+ // Convert from underlying chars to stream-zero slots.
+ islotRS += m_engst.m_cslotPreSeg;
+ islotPC += m_engst.m_cslotPreSeg;
+ }
+ }
+
+ // The following should be the case unless they tried to position contextually across
+ // the line break boundary, which is a very strange thing to do! - no longer true,
+ // because the pre-context is now included in this count, and it normal to have
+ // a pre-context in the final positioning pass.
+ //Assert(vcslotSkipOffsets[m_cpass-1] == 0);
+
+ // Also no adjustments are made by the glyph-generation pass, so this should always
+ // be true:
+ Assert(vcslotSkipOffsets[0] == 0);
+
+ // The number of slots in the underlying input previous to the line-break
+ // that must be reprocessed:
+ int cslotPreLB = islotUnderLim - islotPC;
+
+ if (fGiveUp)
+ {
+ // We can't reasonably provide enough context, so don't try to do it at all.
+ cslotPreLB = 0;
+ for (ipass = 0; ipass < m_cpass; ipass++)
+ vcslotSkipOffsets[ipass] = 0;
+ }
+
+ Assert(cslotPreLB >= 0);
+ Assert(cslotPreLB < 0xFF);
+
+ *pb++ = byte(cslotPreLB);
+ for (ipass = 0; ipass < m_cpass; ipass++)
+ *pb++ = byte(vcslotSkipOffsets[ipass]);
+
+ *pcbNextSegDat = 4 + m_cpass;
+
+ pseg->RecordInitializationForNextSeg(*pcbNextSegDat, pbNextSegDat);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the associations, and record the output slots in the segment.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::RecordAssocsAndOutput(Font * pfont,
+ Segment * pseg, bool fWidthIsCharCount,
+ TrWsHandling twsh, bool fParaRtl, int nDirDepth)
+{
+ int cchwUnderlying = pseg->stopCharacter() - pseg->startCharacter();
+
+ GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
+ int csloutSurface = psstrmFinal->WritePos() - psstrmFinal->IndexOffset(); // # of output slots
+
+ psstrmFinal->SetNeutralAssociations(LBGlyphID());
+
+ float xsTotalWidth, xsVisWidth;
+
+#ifdef OLD_TEST_STUFF
+ if (fWidthIsCharCount)
+ xsTotalWidth = xsVisWidth = 0;
+ else
+#endif // OLD_TEST_STUFF
+
+ // Make sure the final positions are set for every glyph.
+ CalcPositionsUpTo(m_cpass-1, reinterpret_cast<GrSlotState *>(NULL),
+ &xsTotalWidth, &xsVisWidth);
+ pseg->SetWidths(xsVisWidth, xsTotalWidth);
+
+ pseg->SetUpOutputArrays(pfont, this, psstrmFinal, cchwUnderlying, csloutSurface, LBGlyphID(),
+ twsh, fParaRtl, nDirDepth);
+
+ // Set underlying-to-surface assocations in the segment.
+ CalculateAssociations(pseg, csloutSurface);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the underlying-to-surface associations and ligature mappings.
+ Assumes the arrays have been properly initialized.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::CalculateAssociations(Segment * pseg, int csloutSurface)
+{
+ GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
+
+ std::vector<int> vichwAssocs;
+ std::vector<int> vichwComponents;
+ std::vector<int> vicomp;
+
+ for (int islot = psstrmFinal->IndexOffset(); islot < psstrmFinal->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+ int islout = islot - psstrmFinal->IndexOffset();
+ if (!pslot->IsLineBreak(LBGlyphID()))
+ {
+ vichwAssocs.clear();
+ pslot->AllAssocs(vichwAssocs);
+
+ size_t iichw;
+ for (iichw = 0; iichw < vichwAssocs.size(); ++iichw)
+ {
+ pseg->RecordSurfaceAssoc(vichwAssocs[iichw], islout, 0);
+ }
+
+ vichwComponents.clear();
+ vicomp.clear();
+ if (pslot->HasComponents())
+ pslot->AllComponentRefs(vichwComponents, vicomp);
+
+ for (iichw = 0; iichw < vichwComponents.size(); iichw++)
+ {
+ pseg->RecordLigature(vichwComponents[iichw], islout, vicomp[iichw]);
+ }
+ }
+ }
+
+ AdjustAssocsForOverlaps(pseg);
+ pseg->CleanUpAssocsVectors();
+
+// pseg->AdjustForOverlapsWithPrevSeg(); // for any characters officially in the
+ // previous segment but rendered in this one,
+ // or vice versa
+
+ // TODO SharonC: for all characters that are right-to-left in the underlying stream,
+ // reverse the before and after flags in the segment.
+}
+
+/*----------------------------------------------------------------------------------------------
+ For any slots associated with characters in the new segment but not rendered in the
+ segment, adjust the underlying-to-surface mappings accordingly. Ie, set the before
+ mapping to kNegInfinity for slots at the beginning of the streams, and set the
+ after mapping to kPosInfinity for slots at the end of the streams.
+
+ TODO SharonC: Rework this method more carefully to handle each slot exactly once. The current
+ approach could possibly, for instance, process a slot that is inserted in one pass
+ and deleted in the next.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::AdjustAssocsForOverlaps(Segment * pseg)
+{
+ if (!m_engst.m_fInitialLB && !m_engst.m_fFinalLB && !m_engst.m_fInsertedLB)
+ // no cross-line contextualization possible
+ return;
+
+ gid16 chwLB = LBGlyphID();
+ std::vector<int> vichwAssocs;
+
+ // Process any slots output by any substitution pass (or later) on either side of the
+ // line-breaks. These are the relevant slots that are rendered in the previous and
+ // following segments.
+ for (int ipass = m_cpass; ipass-- > m_cpassLB + 1; )
+ {
+ GrSlotStream * psstrm = OutputStream(ipass);
+ int islotMin = (ipass == m_cpass - 1) ? psstrm->IndexOffset() : 0;
+
+ if (m_engst.m_fInitialLB)
+ {
+ for (int islot = islotMin; ; islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsInitialLineBreak(chwLB))
+ break;
+ Assert(!pslot->IsFinalLineBreak(chwLB));
+ if (pslot->PassModified() != ipass)
+ continue;
+
+ vichwAssocs.clear();
+ pslot->AllAssocs(vichwAssocs);
+ for (size_t iichw = 0; iichw < vichwAssocs.size(); ++iichw)
+ pseg->MarkSlotInPrevSeg(vichwAssocs[iichw], islot);
+ }
+ }
+
+ if ((m_engst.m_fFinalLB || m_engst.m_fInsertedLB) && ipass > m_cpassLB)
+ {
+ for (int islot = psstrm->WritePos(); islot-- > islotMin ; )
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsFinalLineBreak(chwLB))
+ break;
+ Assert(!pslot->IsInitialLineBreak(chwLB));
+ if (pslot->PassModified() != ipass)
+ continue;
+
+ vichwAssocs.clear();
+ pslot->AllAssocs(vichwAssocs);
+ for (size_t iichw = 0; iichw < vichwAssocs.size(); ++iichw)
+ pseg->MarkSlotInNextSeg(vichwAssocs[iichw], islot);
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize all the streams. In particular, process the information about the
+ skip-offsets to handle segments other than the first.
+
+ @param cbPrev - number of bytes in the pbPrevSegDat buffer
+ @param pbPrevSegDat - buffer in the following format (all are 1 byte, unsigned):
+ prev seg's end breakweight
+ prev seg's previous strong directionality code
+ prev seg's previous terminator dir code
+ restart backup
+ skip offsets for each pass
+ This format must match what is generated by InitializeForNextSeg.
+----------------------------------------------------------------------------------------------*/
+void EngineState::InitializeStreams(GrTableManager * ptman,
+ GrCharStream * pchstrm,
+ int cbPrev, byte * pbPrevSegDat, bool fNeedFinalBreak, int * pislotFinalBreak)
+{
+ int cpassLB = ptman->NumberOfLbPasses();
+ int ipassPos1 = ptman->FirstPosPass();
+
+ CreateSlotStreams();
+
+ int cslotBackup = 0;
+
+ InitForNewSegment(ptman);
+
+ if (cbPrev == 0)
+ {
+ m_lbPrevEnd = klbNoBreak;
+ m_dircInitialStrongDir = kdircNeutral;
+ m_dircInitialTermDir = kdircNeutral;
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ {
+ OutputStream(ipass)->Initialize(ipassPos1, false);
+ m_prgzpst[ipass].SetResyncSkip(0);
+
+ if (ptman->LoggingTransduction())
+ m_prgzpst[ipass].InitializeLogInfo();
+ }
+ }
+ else
+ {
+ Assert(cbPrev >= 4);
+ byte * pb = pbPrevSegDat;
+
+ m_lbPrevEnd = LineBrk(*pb++);
+
+ // Directionality codes from the previous segment.
+ m_dircInitialStrongDir = DirCode((int)*pb++);
+ m_dircInitialTermDir = DirCode((int)*pb++);
+
+ cslotBackup = (int)*pb++;
+ Assert((cbPrev == 4 || cslotBackup == 0) || cbPrev == m_cpass + 4);
+
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ {
+ OutputStream(ipass)->Initialize(ipassPos1, true);
+ if (cbPrev == 4)
+ m_prgzpst[ipass].SetResyncSkip(0); // different writing system
+ else
+ m_prgzpst[ipass].SetResyncSkip(*pb++);
+
+ if (ptman->LoggingTransduction())
+ m_prgzpst[ipass].InitializeLogInfo();
+ }
+
+ pchstrm->Backup(cslotBackup);
+ }
+
+ if (cbPrev > 0 || pchstrm->StartLine())
+ {
+ // Go ahead and run the initial line-break passes (if any), and then insert
+ // a line-break at the appropriate place where the new segment will begin.
+ int cslotToGet = cslotBackup;
+LGetMore:
+ ptman->Pass(0)->ExtendGlyphIDOutput(ptman, pchstrm, OutputStream(0),
+ -1, 0, klbWordBreak,
+ cslotToGet, fNeedFinalBreak, m_twsh, pislotFinalBreak);
+ OutputStream(0)->SetSegMin(cslotBackup);
+ for (int ipass = 1; ipass <= cpassLB; ipass++)
+ {
+ if (cslotToGet > 0)
+ {
+ int nRet = kNextPass;
+ int cslotGot;
+ ptman->Pass(ipass)->ExtendOutput(ptman,
+ InputStream(ipass), OutputStream(ipass),
+ cslotToGet, m_twsh, &nRet, &cslotGot, pislotFinalBreak);
+ if (nRet != kNextPass)
+ {
+ cslotToGet = 1;
+ goto LGetMore;
+ }
+ }
+ OutputStream(ipass)->SetSegMin(cslotBackup);
+ }
+ Assert(OutputStream(cpassLB)->WritePos() >= cslotBackup);
+ m_cslotPreSeg = cslotBackup;
+ if (pchstrm->StartLine())
+ {
+ OutputStream(cpassLB)->AppendLineBreak(ptman, pchstrm, m_lbPrevEnd,
+ (ptman->RightToLeft() ? kdircRlb : kdircLlb), cslotBackup, true, -1);
+ SetInitialLB();
+ m_cslotPreSeg++;
+ if (cpassLB > 0 && *pislotFinalBreak > -1)
+ // See corresponding kludge in GrPass::ExtendGlyphIDOutput.
+ *pislotFinalBreak += 1;
+ }
+ else
+ {
+ OutputStream(cpassLB)->SetSegMin(cslotBackup);
+ }
+ OutputStream(cpassLB)->CalcIndexOffset(ptman);
+ }
+
+ else
+ {
+ Assert(cslotBackup == 0);
+ OutputStream(0)->SetSegMin(0);
+ m_cslotPreSeg = 0;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reinitialize as we start to generate a new segment.
+----------------------------------------------------------------------------------------------*/
+void EngineState::InitForNewSegment(GrTableManager * ptman)
+{
+ // Set up a fresh batch of slots.
+ DestroySlotBlocks();
+ m_islotblkCurr = -1;
+ m_islotNext = kSlotBlockSize;
+
+ m_fInitialLB = false;
+ m_fFinalLB = false;
+ m_fInsertedLB = false;
+ m_fExceededSpace = false;
+ m_fHitHardBreak = false;
+ m_fRemovedWhtsp = false;
+ InitPosCache();
+ //////m_pgg = pgg;
+
+ for (int ipass = 0; ipass < m_cpass; ipass++)
+ m_prgzpst[ipass].InitForNewSegment(ipass, ptman->Pass(ipass)->MaxRuleContext());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the position in stream zero of the given slot in the final stream,
+ based on the associations. (This will be the same as the position at the end of the
+ line-break passes, which is really what we want.)
+
+ @param islotFinal - index of the final slot in the final stream
+----------------------------------------------------------------------------------------------*/
+int EngineState::TraceStreamZeroPos(int islotFinal, int nTopDir)
+{
+ GrSlotStream * psstrmFinal = OutputStream(m_cpass - 1);
+ if (psstrmFinal->WritePos() == 0)
+ return -1;
+
+ GrSlotState * pslot = psstrmFinal->SlotAt(islotFinal);
+
+ // If we're in the middle of reordered bidi stuff, just use the end of the stream.
+ if (pslot->DirLevel() > nTopDir)
+ return -1;
+
+ int islot = pslot->BeforeAssoc();
+ if (islot == kPosInfinity || islot < 0)
+ return -1;
+ return islot + m_cslotPreSeg;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the next higher (more relaxed, less desirable) line break weight.
+----------------------------------------------------------------------------------------------*/
+LineBrk GrTableManager::IncLineBreak(LineBrk lb)
+{
+ Assert(lb != klbClipBreak);
+ return (LineBrk)((int)lb + 1);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return a pointer to a slot that is near the current position in the given stream.
+ Return NULL if no slots have been output at all.
+ This is used for initializing features of line-break slots.
+ @param ipassArg - pass at which to start looking
+ @param islot - slot to look for; -1 if considering the current position
+----------------------------------------------------------------------------------------------*/
+GrSlotState * EngineState::AnAdjacentSlot(int ipassArg, int islot)
+{
+ int ipass = ipassArg;
+ while (ipass >= 0)
+ {
+ GrSlotStream * psstrm = OutputStream(ipass);
+ if (psstrm->NumberOfSlots() > 0)
+ {
+ if (islot == -1)
+ {
+ if (psstrm->AtEnd())
+ return psstrm->SlotAt(psstrm->WritePos() - 1);
+ else
+ return psstrm->Peek();
+ }
+ else
+ {
+ if (psstrm->WritePos() <= islot)
+ return psstrm->SlotAt(psstrm->WritePos() - 1);
+ else
+ return psstrm->SlotAt(islot);
+ }
+ }
+ ipass--;
+ }
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Simple access methods.
+----------------------------------------------------------------------------------------------*/
+GrEngine * GrTableManager::Engine()
+{
+ return m_pgreng;
+}
+
+EngineState * GrTableManager::State()
+{
+ return &m_engst;
+}
+
+GrEngine * EngineState::Engine()
+{
+ return m_ptman->Engine();
+}
+
+GrTableManager * EngineState::TableManager()
+{
+ return m_ptman;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Memory management for slots
+----------------------------------------------------------------------------------------------*/
+
+// standard for pass 0 slots
+void EngineState::NewSlot(
+ gid16 gID, GrFeatureValues fval, int ipass, int ichwSegOffset, int nUnicode,
+ GrSlotState ** ppslotRet)
+{
+ NextSlot(ppslotRet);
+ (*ppslotRet)->Initialize(gID, Engine(), fval, ipass, ichwSegOffset, nUnicode);
+}
+
+// line-break slots
+void EngineState::NewSlot(
+ gid16 gID, GrSlotState * pslotFeat, int ipass, int ichwSegOffset,
+ GrSlotState ** ppslotRet)
+{
+ NextSlot(ppslotRet);
+ (*ppslotRet)->Initialize(gID, Engine(), pslotFeat, ipass, ichwSegOffset);
+}
+
+// for inserting new slots after pass 0 (under-pos and unicode are irrelevant)
+void EngineState::NewSlot(
+ gid16 gID, GrSlotState * pslotFeat, int ipass,
+ GrSlotState ** ppslotRet)
+{
+ NextSlot(ppslotRet);
+ (*ppslotRet)->Initialize(gID, Engine(), pslotFeat, ipass);
+}
+
+// for making a new version of the slot initialized from the old
+void EngineState::NewSlotCopy(GrSlotState * pslotCopyFrom, int ipass,
+ GrSlotState ** ppslotRet)
+{
+ NextSlot(ppslotRet);
+ (*ppslotRet)->InitializeFrom(pslotCopyFrom, ipass);
+}
+
+void EngineState::NextSlot(GrSlotState ** ppslotRet)
+{
+ int cnExtraPerSlot = m_cUserDefn + (m_cCompPerLig * 2) + m_cFeat;
+ if (m_islotNext >= kSlotBlockSize)
+ {
+ // Allocate a new block of slots
+ GrSlotState * slotblkNew = new GrSlotState[kSlotBlockSize];
+ u_intslot * prgnSlotBuf = new u_intslot[kSlotBlockSize * cnExtraPerSlot];
+
+ m_vslotblk.push_back(slotblkNew);
+ m_vprgnSlotVarLenBufs.push_back(prgnSlotBuf);
+ m_islotblkCurr++;
+ m_islotNext = 0;
+ Assert((unsigned)m_islotblkCurr == m_vslotblk.size()-1);
+ }
+
+ *ppslotRet = m_vslotblk[m_islotblkCurr] + m_islotNext;
+ (*ppslotRet)->BasicInitialize(m_cUserDefn, m_cCompPerLig, m_cFeat,
+ (m_vprgnSlotVarLenBufs[m_islotblkCurr] + (m_islotNext * cnExtraPerSlot)));
+ m_islotNext++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert the number of font design units into source device logical units.
+----------------------------------------------------------------------------------------------*/
+float GrTableManager::EmToLogUnits(int m)
+{
+ return m_engst.EmToLogUnits(m);
+}
+
+float EngineState::EmToLogUnits(int m)
+{
+ if (m == 0)
+ return 0;
+
+ float xysFontEmSquare;
+ m_pfont->getFontMetrics(NULL, NULL, &xysFontEmSquare);
+
+ // mEmUnits should be equal to the design units in the font's em square
+ int mEmUnits = Engine()->GetFontEmUnits();
+ if (mEmUnits <= 0)
+ {
+ Warn("Failed to obtain font em-units");
+ return (float)m;
+ }
+
+ return GrEngine::GrIFIMulDiv(m, xysFontEmSquare, mEmUnits);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert the source device coordinates to font design units.
+----------------------------------------------------------------------------------------------*/
+int GrTableManager::LogToEmUnits(float xys)
+{
+ return m_engst.LogToEmUnits(xys);
+}
+
+int EngineState::LogToEmUnits(float xys)
+{
+ if (xys == 0)
+ return 0;
+
+ float xysFontEmSquare;
+ m_pfont->getFontMetrics(NULL, NULL, &xysFontEmSquare);
+
+ // mEmUnits should be equal to the design units in the font's em square
+ int mEmUnits = Engine()->GetFontEmUnits();
+ if (mEmUnits < 0)
+ {
+ Warn("Failed to obtain font em-units");
+ return (int)xys;
+ }
+
+ return GrEngine::GrFIFMulDiv(xys, mEmUnits, xysFontEmSquare);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find the coordinates for a given glyph point.
+ Return true on success, false otherwise.
+----------------------------------------------------------------------------------------------*/
+bool GrTableManager::GPointToXY(gid16 chwGlyphID, int nGPoint, float * pxs, float * pys)
+{
+ return m_engst.GPointToXY(chwGlyphID, nGPoint, pxs, pys);
+}
+
+bool EngineState::GPointToXY(gid16 chwGlyphID, int nGPoint, float * pxs, float * pys)
+{
+ *pxs = INT_MIN;
+ *pys = INT_MIN;
+ Point pointRet;
+ m_pfont->getGlyphPoint(chwGlyphID, nGPoint, pointRet);
+ *pxs = pointRet.x;
+ *pys = pointRet.y;
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Call the justification routines.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::CallJustifier(IGrJustifier * pgjus, int ipassCurr,
+ float dxUnjustified, float dxJustified, bool fEndLine)
+{
+ // Indicates the stream the justification routines will read and modify:
+ m_engst.m_ipassJustCalled = ipassCurr;
+
+ int iGlyphMin = OutputStream(ipassCurr)->SegMin();
+ int iGlyphLim = OutputStream(ipassCurr)->SegLimIfKnown();
+ if (iGlyphLim == -1)
+ iGlyphLim = OutputStream(ipassCurr)->WritePos();
+
+ GrSlotStream * psstrm = OutputStream(ipassCurr);
+ if (m_pgreng->BasicJustification() && fEndLine)
+ UnstretchTrailingWs(psstrm, iGlyphLim);
+
+ pgjus->adjustGlyphWidths(m_pgreng, iGlyphMin, iGlyphLim, dxUnjustified, dxJustified);
+
+ // After returning, reading and modifying slot attributes is not permitted:
+ m_engst.m_ipassJustCalled = -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For the basic justification approach, remove stretch from the trailing whitespace.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::UnstretchTrailingWs(GrSlotStream * psstrm, int iGlyphLim)
+{
+ int islot = iGlyphLim - 1;
+ while (islot >= 0)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsLineBreak(LBGlyphID()))
+ { } // keep looking for the trailing space
+ else if (pslot->IsSpace(this))
+ pslot->SetJStretch(0); // TODO: do this at level 0
+ else
+ // something other than space--quit
+ return;
+ islot--;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Determine how much shrink is permissible.
+
+ This method is really used only for testing the shrink mechanism, since at this time
+ we don't allow low-end justification to do any shrinking.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::DetermineShrink(IGrJustifier * pgjus, int ipassCurr)
+{
+ if (m_engst.m_dxsShrinkPossible != GrSlotState::kNotYetSet)
+ return;
+
+ if (m_engst.m_jmodi != kjmodiCanShrink || pgjus == NULL)
+ {
+ m_engst.m_dxsShrinkPossible = 0;
+ return;
+ }
+
+ if (ipassCurr != m_ipassJust1 - 1)
+ return;
+
+ GrSlotStream * psstrm = OutputStream(ipassCurr);
+ if (!psstrm->FullyWritten())
+ return;
+
+ // Normally just answer 0. To test shrinking, turn on the code below.
+ m_engst.m_dxsShrinkPossible = 0;
+
+#if TEST_SHRINK
+ int mTotal = 0;
+ int mShrink = 0;
+ int islotLim = psstrm->SegLimIfKnown();
+ if (islotLim == -1)
+ islotLim = psstrm->WritePos();
+ for ( ; islotLim >= 0; islotLim--)
+ {
+ // Trailing white space is not shrinkable.
+ GrSlotState * pslot = psstrm->SlotAt(islotLim - 1);
+ if (pslot->IsLineBreak(LBGlyphID()))
+ continue;
+ if (!pslot->IsSpace(this))
+ break;
+ }
+ int islot;
+ for (islot = psstrm->SegMin(); islot < islotLim; islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsLineBreak(LBGlyphID()))
+ continue;
+ mTotal += pslot->AdvanceX(this);
+ mShrink += pslot->JShrink();
+ }
+
+ // Say that we are allowed to shrink up to 10% of the width of the segment.
+ mShrink = min(mShrink, mTotal/10);
+ m_engst.m_dxsShrinkPossible = EmToLogUnits(mShrink);
+#endif // TEST_SHRINK
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the attribute of the given slot, back to the justification routine. Return
+ logical units.
+----------------------------------------------------------------------------------------------*/
+GrResult EngineState::GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
+ float * pValueRet)
+{
+ GrResult res;
+ int valueRetInt = 0;
+ switch(jgat)
+ {
+ case kjgatWeight:
+ case kjgatStretchInSteps:
+ case kjgatBreak:
+ res = GetGlyphAttrForJustification(iGlyph, jgat, nLevel, &valueRetInt);
+ *pValueRet = (float)valueRetInt;
+ return res;
+ default:
+ break;
+ }
+
+ if (m_ipassJustCalled == -1)
+ return kresUnexpected;
+
+ if (nLevel != 1)
+ return kresInvalidArg;
+
+ GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
+
+ if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
+ return kresInvalidArg;
+
+ GrSlotState * pslot = psstrm->SlotAt(iGlyph);
+
+ // bool fConvertUnits = true;
+
+ switch(jgat)
+ {
+ case kjgatStretch:
+ *pValueRet = EmToLogUnits(pslot->JStretch());
+ break;
+ case kjgatShrink:
+ *pValueRet = EmToLogUnits(pslot->JShrink());
+ break;
+ case kjgatStep:
+ *pValueRet = EmToLogUnits(pslot->JStep());
+ break;
+ default:
+ return kresNotImpl;
+ }
+ return kresOk;
+}
+
+GrResult EngineState::GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
+ int * pValueRet)
+{
+ GrResult res;
+ float valueRetFloat;
+ switch(jgat)
+ {
+ case kjgatStretch:
+ case kjgatShrink:
+ case kjgatStep:
+ res = GetGlyphAttrForJustification(iGlyph, jgat, nLevel, &valueRetFloat);
+ *pValueRet = GrEngine::RoundFloat(valueRetFloat);
+ return res;
+ default:
+ break;
+ }
+
+ if (m_ipassJustCalled == -1)
+ return kresUnexpected;
+
+ if (nLevel != 1)
+ return kresInvalidArg;
+
+ GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
+
+ if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
+ return kresInvalidArg;
+
+ GrSlotState * pslot = psstrm->SlotAt(iGlyph);
+
+ int mStretch, mStep;
+ //float xsStretch, xsStep;
+
+ switch(jgat)
+ {
+ case kjgatWeight:
+ *pValueRet = pslot->JWeight();
+ break;
+ case kjgatStretchInSteps:
+ // ???? should this be calculated in terms of logical units??
+ // Probably doesn't matter, since the logical units are floating point, so the
+ // level of precision is about the same.
+ mStretch = pslot->JStretch();
+ mStep = pslot->JStep();
+ if (mStep == 0)
+ return kresUnexpected;
+ *pValueRet = int(mStretch / mStep); // round down
+ break;
+ //case kjgatStretchInSteps:
+ // xsStretch = EmToLogUnits(pslot->JStretch());
+ // xsStep = EmToLogUnits(pslot->JStep());
+ // if (xsStep == 0)
+ // return kresUnexpected;
+ // *pValueRet = int(xsStretch / xsStep); // round down
+ // break;
+ case kjgatBreak:
+ *pValueRet = pslot->BreakWeight();
+ break;
+ default:
+ return kresNotImpl;
+ }
+ return kresOk;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the attribute of the given slot, for the justification routine.
+----------------------------------------------------------------------------------------------*/
+GrResult EngineState::SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
+ float value)
+{
+ GrResult res;
+ int valueInt;
+ switch(jgat)
+ {
+ case kjgatWeight:
+ case kjgatStretchInSteps:
+ case kjgatBreak:
+ valueInt = (int)value;
+ res = SetGlyphAttrForJustification(iGlyph, jgat, nLevel, valueInt);
+ return res;
+ default:
+ break;
+ }
+
+ if (m_ipassJustCalled == -1)
+ return kresUnexpected;
+
+ if (nLevel != 1)
+ return kresInvalidArg;
+
+ GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
+
+ if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
+ return kresInvalidArg;
+
+ GrSlotState * pslot = psstrm->SlotAt(iGlyph);
+
+ int mValue = LogToEmUnits(value);
+ mValue = min(mValue, 0xFFFF); // truncate to an unsigned short
+
+ // Review: do we really want to allow them to set stretch/shrink/step/weight? The normal
+ // thing for them to do is set width.
+ switch(jgat)
+ {
+ case kjgatStretch:
+ pslot->SetJStretch(mValue);
+ break;
+ case kjgatShrink:
+ pslot->SetJShrink(mValue);
+ break;
+ case kjgatStep:
+ pslot->SetJStep(mValue);
+ break;
+ case kjgatWidth:
+ pslot->SetJWidth(mValue);
+ break;
+ default:
+ return kresNotImpl;
+ }
+ return kresOk;
+}
+
+GrResult EngineState::SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
+ int value)
+{
+ GrResult res;
+ float valueFloat;
+ switch(jgat)
+ {
+ case kjgatStretch:
+ case kjgatShrink:
+ case kjgatStep:
+ case kjgatWidth:
+ valueFloat = (float)value;
+ res = SetGlyphAttrForJustification(iGlyph, jgat, nLevel, valueFloat);
+ return res;
+ default:
+ break;
+ }
+
+ if (m_ipassJustCalled == -1)
+ return kresUnexpected;
+
+ if (nLevel != 1)
+ return kresInvalidArg;
+
+ GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
+
+ if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
+ return kresInvalidArg;
+
+ GrSlotState * pslot = psstrm->SlotAt(iGlyph);
+
+ int mValue, cSteps;
+ switch(jgat)
+ {
+ case kjgatWeight:
+ pslot->SetJWeight(value);
+ break;
+ case kjgatWidthInSteps:
+ cSteps = value;
+ mValue = pslot->JStep();
+ if (mValue == 0)
+ return kresUnexpected;
+ pslot->SetJWidth(mValue * cSteps);
+ break;
+ default:
+ return kresNotImpl;
+ }
+ return kresOk;
+}
+
+//:>--------------------------------------------------------------------------------------------
+//:> Functions to forward to the engine.
+//:>------------------------------------------------------------------------------------------*/
+gid16 GrTableManager::GetGlyphIDFromUnicode(int nUnicode)
+{
+ return m_pgreng->GetGlyphIDFromUnicode(nUnicode);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+gid16 GrTableManager::ActualGlyphForOutput(utf16 chw)
+{
+ return m_pgreng->ActualGlyphForOutput(chw);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+GrGlyphTable * GrTableManager::GlyphTable()
+{
+ return m_pgreng->GlyphTable();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+gid16 GrTableManager::LBGlyphID()
+{
+ return m_pgreng->LBGlyphID();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+gid16 GrTableManager::GetClassGlyphIDAt(int nClass, int nIndex)
+{
+ return m_pgreng->GetClassGlyphIDAt(nClass, nIndex);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::GetIndexInGlyphClass(int nClass, gid16 chwGlyphID)
+{
+ return m_pgreng->GetIndexInGlyphClass(nClass, chwGlyphID);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+size_t GrTableManager::NumberOfGlyphsInClass(int nClass)
+{
+ return m_pgreng->NumberOfGlyphsInClass(nClass);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+void GrTableManager::SetSlotAttrsFromGlyphAttrs(GrSlotState * pslot)
+{
+ m_pgreng->SetSlotAttrsFromGlyphAttrs(pslot);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::NumFeat()
+{
+ return m_pgreng->NumFeat();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::DefaultForFeatureAt(int ifeat)
+{
+ return m_pgreng->DefaultForFeatureAt(ifeat);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+void GrTableManager::DefaultsForLanguage(isocode lgcode,
+ std::vector<featid> & vnFeats, std::vector<int> & vnValues)
+{
+ return m_pgreng->DefaultsForLanguage(lgcode, vnFeats, vnValues);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+GrFeature * GrTableManager::FeatureWithID(featid nID, int * pifeat)
+{
+ return m_pgreng->FeatureWithID(nID, pifeat);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+GrFeature * GrTableManager::Feature(int ifeat)
+{
+ return m_pgreng->Feature(ifeat);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+bool GrTableManager::RightToLeft()
+{
+ if (m_engst.WhiteSpaceOnly())
+ return m_engst.m_fParaRtl;
+ else
+ return m_pgreng->RightToLeft();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::TopDirectionLevel()
+{
+ return m_pgreng->TopDirectionLevel();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+float GrTableManager::VerticalOffset()
+{
+ return m_pgreng->VerticalOffset();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::NumUserDefn()
+{
+ return m_pgreng->NumUserDefn();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::NumCompPerLig()
+{
+ return m_pgreng->NumCompPerLig();
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID)
+{
+ return m_pgreng->ComponentIndexForGlyph(chwGlyphID, nCompID);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int GrTableManager::GlyphAttrValue(gid16 chwGlyphID, int nAttrID)
+{
+ return m_pgreng->GlyphAttrValue(chwGlyphID, nAttrID);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+bool GrTableManager::LoggingTransduction()
+{
+ return m_fLogging;
+ //return m_pgreng->LoggingTransduction();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Calculate the positions of the glyphs up to the given slot, within the output of the given
+ pass. If the slot is NULL, go all the way to the end of what has been generated.
+
+ @param ipass - index of pass needing positioning; normally this will be the
+ final pass, but it could be another if positions are
+ requested by the rules themselves
+ @param pslotLast - last slot that needs to be positioned, or NULL
+ @param pxsWidth - return the total width used so far
+ @param psxVisibleWidth - return the visible width so far
+
+ MOVE to EngineState
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::CalcPositionsUpTo(int ipass, GrSlotState * pslotLast,
+ float * pxsWidth, float * pxsVisibleWidth)
+{
+ Assert(ipass >= m_ipassPos1 - 1);
+
+ int isstrm = ipass;
+ GrSlotStream * psstrm = OutputStream(isstrm);
+ Assert(psstrm->GotIndexOffset());
+ if (psstrm->WritePos() <= psstrm->IndexOffset())
+ {
+ Assert(psstrm->WritePos() == 0);
+ *pxsWidth = 0;
+ *pxsVisibleWidth = 0;
+ return;
+ }
+ if (!pslotLast)
+ {
+ pslotLast = psstrm->SlotAt(psstrm->WritePos() - 1);
+ }
+ Assert(pslotLast);
+
+ // First set positions of all base slots.
+
+ int islot = psstrm->IndexOffset();
+ GrSlotState * pslot;
+ float xs = 0;
+ float ys = VerticalOffset();
+ *pxsWidth = 0;
+ *pxsVisibleWidth = 0;
+
+ bool fLast = false;
+ bool fLastBase = false;
+
+ bool fFakeItalic = m_pgreng->FakeItalic();
+ float fakeItalicRatio = 0;
+ if (fFakeItalic)
+ fakeItalicRatio = State()->GetFont()->fakeItalicRatio();
+ bool fBasicJust = m_pgreng->BasicJustification();
+
+ // Figure out how to know when to stop.
+ // We need to calculate up to the base of the last leaf slot, if it happens
+ // to be later in the stream than the last actual slot passed in.
+ if (!psstrm->HasSlotAtPosPassIndex(pslotLast->AttachRootPosPassIndex()))
+ return;
+ GrSlotState * pslotLastBase = pslotLast->Base(psstrm);
+
+ if (ipass == m_cpass - 1 && m_engst.m_islotPosNext > -1)
+ {
+ // For final pass, initialize from cache of previous calculations.
+ islot = m_engst.m_islotPosNext;
+ xs = m_engst.m_xsPosXNext;
+ ys = m_engst.m_ysPosYNext;
+ *pxsWidth = m_engst.m_dxsTotWidthSoFar;
+ *pxsVisibleWidth = m_engst.m_dxsVisWidthSoFar;
+
+ if (psstrm->SlotsPresent() <= islot)
+ return;
+
+ if (pslotLastBase->PosPassIndex() == GrSlotAbstract::kNotYetSet)
+ {
+ Assert(false); // I think this case is handled above
+ return; // can't position this slot yet; its base has not been processed
+ }
+
+ if (pslotLastBase->PosPassIndex() + psstrm->IndexOffset() < islot)
+ {
+ fLastBase = true;
+ if (pslotLast == pslotLastBase)
+ fLast = true;
+ }
+ }
+
+ std::vector<GrSlotState *> vpslotAttached;
+
+ bool fRtl = RightToLeft();
+
+ while (!fLast || !fLastBase)
+ {
+ Assert(islot < psstrm->SlotsPresent());
+
+ pslot = (isstrm == ipass) ? psstrm->SlotAt(islot) : psstrm->OutputSlotAt(islot);
+
+ if (!pslot->IsBase())
+ {
+ // This slot is attached to another; it will be positioned strictly
+ // relative to that one. This happens in the loop below.
+ vpslotAttached.push_back(pslot);
+ }
+ else
+ {
+ // Base character.
+
+ bool fLB = pslot->IsLineBreak(LBGlyphID());
+ if (InternalJustificationMode() == kjmodiJustify && fBasicJust
+ && ipass == m_cpass - 1 && !fLB)
+ {
+ m_engst.AddJWidthToAdvance(psstrm, &pslot, islot, &pslotLast, &pslotLastBase);
+ }
+
+ // Make sure the metrics are the complete ones.
+ pslot->CalcCompositeMetrics(this, psstrm, kPosInfinity, true);
+
+ float xsInc = pslot->GlyphXOffset(psstrm, fakeItalicRatio);
+ float ysInc = pslot->GlyphYOffset(psstrm);
+ float xsAdvX = pslot->ClusterAdvWidth(psstrm);
+ float ysAdvY = (fLB) ?
+ 0 :
+ EmToLogUnits(pslot->AdvanceY(this));
+
+ if (fRtl)
+ {
+ xs -= xsAdvX;
+ ys -= ysAdvY;
+ pslot->SetXPos(xs + xsInc);
+ pslot->SetYPos(ys + ysInc);
+ }
+ else
+ {
+ pslot->SetXPos(xs + xsInc);
+ pslot->SetYPos(ys + ysInc);
+ xs += xsAdvX;
+ ys += ysAdvY;
+ }
+
+ *pxsWidth = max(*pxsWidth, fabsf(xs));
+ if (!IsWhiteSpace(pslot))
+ *pxsVisibleWidth = *pxsWidth;
+
+ if (isstrm == m_cpass - 1)
+ {
+ // For the final output pass, cache the results of the calculation so far.
+ // Only do this for slots that have actually been processed by the final
+ // pass, because others may have intermediate values that may be changed
+ // later.
+ m_engst.m_islotPosNext = pslot->PosPassIndex() + psstrm->IndexOffset() + 1;
+ m_engst.m_xsPosXNext = xs;
+ m_engst.m_ysPosYNext = ys;
+ m_engst.m_dxsTotWidthSoFar = *pxsWidth;
+ m_engst.m_dxsVisWidthSoFar = *pxsVisibleWidth;
+ }
+ }
+
+ // Need to have calculated both the last leaf and the last base (if they happen to
+ // be different); if so, we're done.
+ if (pslot == pslotLast)
+ fLast = true;
+ if (pslot == pslotLastBase)
+ fLastBase = true;
+
+ islot++;
+ }
+
+ Assert(fLast);
+ Assert(fLastBase);
+
+ // Now set positions of non-base slots, relative to their bases.
+
+ for (size_t ipslot = 0; ipslot < vpslotAttached.size(); ipslot++)
+ {
+ GrSlotState * pslot = vpslotAttached[ipslot];
+ GrSlotState * pslotBase = pslot->Base(psstrm);
+ if (pslotBase->XPosition() == kNegInfinity || pslotBase->YPosition() == kNegInfinity)
+ {
+ Assert(false);
+ continue;
+ }
+ float xsCluster = pslotBase->XPosition() - pslotBase->GlyphXOffset(psstrm, fakeItalicRatio);
+ float ysCluster = pslotBase->YPosition() - pslotBase->GlyphYOffset(psstrm);
+ float xsInc = pslot->GlyphXOffset(psstrm, fakeItalicRatio);
+ float ysInc = pslot->GlyphYOffset(psstrm);
+ pslot->SetXPos(xsCluster + xsInc);
+ pslot->SetYPos(ysCluster + ysInc);
+
+ // My theory is that we don't need to adjust *pxsWidth here, because the width of
+ // any non-base slots should be factored into the advance width of their cluster
+ // base, which was handled above.
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the given slot is white space.
+----------------------------------------------------------------------------------------------*/
+bool GrTableManager::IsWhiteSpace(GrSlotState * pslot)
+{
+ if (pslot->IsLineBreak(LBGlyphID()))
+ return true;
+ return pslot->IsSpace(this);
+}
+
+/*----------------------------------------------------------------------------------------------
+ When doing basic justification, apply the value of justify.width to the advance width.
+ This happens during the final positioning routine.
+----------------------------------------------------------------------------------------------*/
+void EngineState::AddJWidthToAdvance(GrSlotStream * psstrm, GrSlotState ** ppslot, int islot,
+ GrSlotState ** ppslotLast, GrSlotState ** ppslotLastBase)
+{
+ Assert(psstrm->OutputOfPass() == m_cpass - 1); // only used for final stream
+ if ((*ppslot)->JWidth() > 0)
+ {
+ if ((*ppslot)->PassModified() != m_cpass - 1)
+ {
+ // Replace the slot with a new slot, so it gets marked properly with the
+ // pass in which it was modified. (Otherwise the debug log gets screwed up.)
+ GrSlotState * pslotNew;
+ NewSlotCopy((*ppslot), m_cpass - 1, &pslotNew);
+ psstrm->PutSlotAt(pslotNew, islot);
+ if (*ppslot == *ppslotLast)
+ *ppslotLast = pslotNew;
+ if (*ppslot == *ppslotLastBase)
+ *ppslotLastBase = pslotNew;
+ *ppslot = pslotNew;
+ }
+ (*ppslot)->AddJWidthToAdvance(TableManager());
+ }
+}
+
+
+//:>********************************************************************************************
+//:> Debuggers and utilities
+//:>********************************************************************************************
+
+//:Ignore
+#if 0
+void GrTableManager::TempDebug()
+{
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ {
+ int wpos = OutputStream(ipass)->WritePos();
+ int rpos = OutputStream(ipass)->ReadPos();
+ GrSlotState * wslot = OutputStream(ipass)->LastSlotWritten();
+ GrSlotState * rslot = OutputStream(ipass)->LastSlotRead();
+
+ }
+}
+#endif
+/*----------------------------------------------------------------------------------------------
+ Given a character index in the original string, locate the corresponding line-break slot
+ in the final surface stream. The character index must be one before which there is a
+ line-break (seg lim), or the beginning or the end of the string.
+ TODO SharonC: fix the bugs
+----------------------------------------------------------------------------------------------*/
+int GrTableManager::SurfaceLineBreakSlot(int ichw, GrCharStream * pchstrm, bool fInitial)
+{
+ if (ichw == 0)
+ {
+ Assert(fInitial);
+ return -1; // no initial line break
+ }
+ if (ichw == pchstrm->Lim())
+ {
+ Assert(!fInitial);
+ return -1; // no terminating line break
+ }
+
+ int islotIn = pchstrm->SegOffset(ichw);
+ Assert(islotIn >= 0);
+ islotIn += (fInitial? m_engst.m_cslotPreSeg - 1: m_engst.m_cslotPreSeg);
+
+ gid16 chwLBGlyphID = LBGlyphID();
+
+ // Now islotIn is the position in stream 0;
+
+ for (int ipass = 1; ipass < m_cpass; ++ipass)
+ {
+ int islotChunkMin;
+ int islotChunkLim;
+ GrSlotStream * psstrmOut = OutputStream(ipass);
+
+ GrSlotStream * psstrmIn = InputStream(ipass);
+ if (fInitial)
+ islotIn = max(islotIn, psstrmIn->PreChunk());
+ int islotT = psstrmIn->ChunkInNextMin(islotIn);
+ islotChunkMin = psstrmIn->ChunkInNext(islotT);
+ islotChunkMin = (islotChunkMin == -1)? 0: islotChunkMin;
+
+ islotT = psstrmIn->ChunkInNextLim(islotIn);
+ Assert(islotT <= psstrmIn->ReadPos());
+ if (islotT == psstrmIn->ReadPos())
+ islotChunkLim = psstrmOut->WritePos();
+ else
+ islotChunkLim = psstrmIn->ChunkInNext(islotT);
+
+ int islotOut;
+ for (islotOut = islotChunkMin; islotOut < islotChunkLim; ++islotOut)
+ {
+ gid16 chw = psstrmOut->GlyphIDAt(islotOut);
+ if (chw == chwLBGlyphID)
+ break;
+ }
+ Assert(psstrmOut->GlyphIDAt(islotOut) == chwLBGlyphID);
+
+ islotIn = islotOut;
+ }
+ return islotIn;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Generate a debugger string showing the chunk boundaries for the given stream.
+----------------------------------------------------------------------------------------------*/
+std::wstring GrTableManager::ChunkDebugString(int ipass)
+{
+ GrSlotStream * psstrm = OutputStream(ipass);
+ std::wstring stuRet;
+ //utf16 chwN = '\\';
+ //utf16 chwR = '^';
+
+ gid16 chwLBGlyphID = LBGlyphID();
+
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ if (psstrm->ChunkInPrev(islot) != -1)
+ {
+ if (psstrm->ChunkInNext(islot) != -1)
+ stuRet.append(L">");
+ else
+ stuRet.append(L"\\");
+ }
+ else if (psstrm->ChunkInNext(islot) != -1)
+ stuRet.append(L"/");
+ else
+ stuRet.append(L" ");
+
+// if (islot == psstrm->ReadPos())
+// stuRet.Append(&chwR, 1);
+
+ wchar_t chw = psstrm->SlotAt(islot)->GlyphID();
+ if (chw == chwLBGlyphID)
+ stuRet.append(L"#");
+ else
+ stuRet.append(&chw, 1);
+ }
+ return stuRet;
+}
+
+} // namespace gr
+
+//:End Ignore
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.h
new file mode 100644
index 00000000000..b75034479e4
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/GrTableManager.h
@@ -0,0 +1,557 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrTableManager.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ The GrTableManager class.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GR_TABLEMAN_INCLUDED
+#define GR_TABLEMAN_INCLUDED
+
+#include <cassert>
+//:End Ignore
+
+namespace gr
+{
+
+class Font;
+
+/*----------------------------------------------------------------------------------------------
+ There is a single instance of Engine State that keeps track of the state of the processing
+ for a single segment generation.
+
+ Hungarian: engst
+----------------------------------------------------------------------------------------------*/
+class EngineState
+{
+ friend class GrTableManager;
+ friend class FontMemoryUsage;
+
+public:
+ EngineState();
+ void Initialize(GrEngine *, GrTableManager *);
+
+ ~EngineState();
+ void DestroySlotBlocks();
+
+ void InitForNewSegment(GrTableManager * ptman);
+
+ void CreateEmpty();
+
+ GrEngine * Engine();
+ GrTableManager * TableManager();
+
+ void CreateSlotStreams();
+
+ GrSlotStream * InputStream(int ipass)
+ {
+ Assert(ipass > 0); // the char stream serves as input to the zeroth pass
+ return m_prgpsstrm[ipass - 1];
+ }
+
+ // Return the stream that serves as output to the given pass.
+ GrSlotStream * OutputStream(int ipass)
+ {
+ Assert(ipass < m_cpass);
+ return m_prgpsstrm[ipass];
+ }
+
+ GrSlotState * AnAdjacentSlot(int ipassArg, int islotArg);
+
+ GrResult GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel, float * pxysValueRet);
+ GrResult GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel, int * pxysValueRet);
+ GrResult SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel, float xysValue);
+ GrResult SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel, int xysValue);
+
+ enum { kSlotBlockSize = 50 }; // number of slots to allocate in a block
+
+ void InitPosCache()
+ {
+ m_islotPosNext = -1;
+ m_xsPosXNext = 0;
+ m_ysPosYNext = 0;
+ m_dxsTotWidthSoFar = 0;
+ m_dxsVisWidthSoFar = 0;
+ }
+
+ void SetFont(Font * pfont)
+ {
+ m_pfont = pfont;
+ }
+ Font * GetFont()
+ {
+ return m_pfont;
+ }
+
+ bool StartLineContext()
+ {
+ return m_fStartLineContext;
+ }
+ bool EndLineContext()
+ {
+ return m_fEndLineContext;
+ }
+ void SetStartLineContext(bool f)
+ {
+ m_fStartLineContext = f;
+ }
+ void SetEndLineContext(bool f)
+ {
+ m_fEndLineContext = f;
+ }
+
+ void SetInitialLB(bool f = true)
+ {
+ m_fInitialLB = f;
+ }
+
+ void SetFinalLB(bool f = true)
+ {
+ m_fFinalLB = f;
+ }
+
+ void SetInsertedLB(bool f = true)
+ {
+ m_fInsertedLB = f;
+ }
+
+ bool HasInitialLB()
+ {
+ return m_fInitialLB;
+ }
+ bool HasInsertedLB()
+ {
+ return m_fInsertedLB;
+ }
+ bool HasFinalLB()
+ {
+ return m_fFinalLB;
+ }
+
+ void SetExceededSpace(bool f = true)
+ {
+ m_fExceededSpace = f;
+ }
+
+ bool ExceededSpace()
+ {
+ return m_fExceededSpace;
+ }
+
+ void SetHitHardBreak(bool f = true)
+ {
+ m_fHitHardBreak = f;
+ }
+
+ bool HitHardBreak()
+ {
+ return m_fHitHardBreak;
+ }
+
+ void SetRemovedTrWhiteSpace(bool f = true)
+ {
+ m_fRemovedWhtsp = f;
+ }
+
+ bool RemovedTrWhiteSpace()
+ {
+ return m_fRemovedWhtsp;
+ }
+
+ bool WhiteSpaceOnly()
+ {
+ return (m_twsh == ktwshOnlyWs);
+ }
+
+ bool ParaRightToLeft()
+ {
+ return m_fParaRtl;
+ }
+
+ //int PrevPassMaxBackup(int ipass)
+ //{
+ // if (ipass == 0)
+ // return 0;
+ // return Pass(ipass - 1)->MaxBackup();
+ //}
+
+ DirCode InitialStrongDir()
+ {
+ return m_dircInitialStrongDir;
+ }
+ DirCode InitialTermDir()
+ {
+ return m_dircInitialTermDir;
+ }
+
+ void InitializeStreams(GrTableManager * ptman, GrCharStream * pchstrm,
+ int cbPrev, byte * pbPrevSegDat, bool fNeedFinalBreak, int * pislotFinalBreak);
+ int LbSlotToSegLim(int islot, GrCharStream * pchstrm, int cpassLB);
+ int TraceStreamZeroPos(int islotFinal, int nTopDir);
+
+ float EmToLogUnits(int m);
+ int LogToEmUnits(float xys);
+ bool GPointToXY(gid16 chwGlyphID, int nGPoint, float * xs, float * ys);
+
+ void AddJWidthToAdvance(GrSlotStream * psstrm, GrSlotState ** ppslot, int islot,
+ GrSlotState ** ppslotLast, GrSlotState ** ppslotLastBase);
+
+ // Memory management for slots:
+ void NewSlot(gid16 gID, GrFeatureValues fval, int ipass, int ichwSegOffset, int nUnicode,
+ GrSlotState **);
+ void NewSlot(gid16 gID, GrSlotState * pslotFeat, int ipass, int ichwSegOffset,
+ GrSlotState **);
+ void NewSlot(gid16 gID, GrSlotState * pslotFeat, int ipass, GrSlotState **);
+ void NewSlotCopy(GrSlotState * pslotCopyFrom, int ipass,
+ GrSlotState ** pslotRet);
+protected:
+ void NextSlot(GrSlotState ** ppslot);
+
+protected:
+ GrTableManager * m_ptman;
+
+ int m_cFeat;
+ int m_cCompPerLig;
+ int m_cUserDefn;
+
+ int m_jmodi; // justification mode
+ int m_ipassJustCalled; // pass after which justification routine was called;
+ // -1 if we are not in the midst of interacting with the
+ // GrJustifier
+
+ // Pointer to font
+ Font * m_pfont;
+
+ bool m_fStartLineContext; // true if there was a rule that ran over the initial LB
+ bool m_fEndLineContext; // true if there was a rule that ran over the final LB
+
+ // the number of slots inserted in the first stream before the official beginning
+ // of the segment, including any initial line break
+ int m_cslotPreSeg;
+
+ // List of allocated GrSlotStates; hungarian slotblk = prgslot
+ std::vector<GrSlotState *> m_vslotblk;
+ std::vector<u_intslot *> m_vprgnSlotVarLenBufs; // corresponding var-length blocks
+ int m_islotblkCurr;
+ int m_islotNext;
+
+ // Directionality codes from previous segment; these are used by the bidi algorithm
+ // at the initial line-break character.
+ DirCode m_dircInitialStrongDir;
+ DirCode m_dircInitialTermDir;
+
+ LineBrk m_lbPrevEnd;
+
+ // All of the following 3 are true only when there is an actual LB glyph in the stream
+ bool m_fInitialLB; // is there is an initial LB (an actual LB glyph--in all streams)
+ bool m_fFinalLB; // is there is a final LB (in all streams--true when we've hit
+ // the end of the input and end-of-line is true)
+ bool m_fInsertedLB; // is there is a final LB inserted in the output of LB pass
+ // (true when we've backtracked)
+
+ bool m_fExceededSpace; // true if we backtracked due to exceeding space; false if we
+ // haven't backtracked, or we did so for some other reason
+ // (eg, omitting trailing whitespace)
+
+ bool m_fHitHardBreak; // true if we encountered a hard-break in the input stream
+ // (before the natural end of the segment)
+
+ bool m_fRemovedWhtsp; // true if we've hit trailing whitespace characters that we've
+ // removed
+
+ TrWsHandling m_twsh; // white-space handling
+ bool m_fParaRtl; // paragraph direction
+
+ float m_dxsShrinkPossible;
+
+ // The final positioning pass is where we are going to do most of the positioning.
+ // Cache the intermediate results so we don't have to calculate from the beginning of
+ // the segment every time.
+ int m_islotPosNext; // where to continue calculating positions in final output stream
+ // (one past the last base that was calculated)
+ float m_xsPosXNext;
+ float m_ysPosYNext;
+ float m_dxsTotWidthSoFar;
+ float m_dxsVisWidthSoFar;
+
+ int m_cpass; // number of passes
+
+ // array of pass-state objects
+ PassState * m_prgzpst;
+
+ // array of slot streams which are output of passes (input of zeroth
+ // pass is the character stream, not a slot stream):
+ GrSlotStream ** m_prgpsstrm;
+ // For instance, a simple set of passes might look like this:
+ // CharStream
+ // GlyphGenPass pass 0
+ // SlotStream stream 0
+ // SubPass pass 1
+ // SlotStream stream 1
+ // PosPass pass 2
+ // SlotStream stream 2
+ //
+ // m_cpass = 3
+
+}; // end of class EngineState
+
+/*----------------------------------------------------------------------------------------------
+ There is a single instance of GrTableManager that handle the interactions between
+ passes, including the demand-pull mechanism.
+
+ Hungarian: tman
+----------------------------------------------------------------------------------------------*/
+
+class GrTableManager {
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor & destructor:
+ GrTableManager(GrEngine * pgreng)
+ : m_cpass(0),
+ m_fBidi(false),
+ m_prgppass(NULL),
+ m_pgreng(pgreng)
+ {
+ Assert(pgreng);
+ }
+
+ ~GrTableManager();
+
+ bool CreateAndReadPasses(GrIStream & grstrm, int fxdSilfVersion, int fxdRuleVersion,
+ int cpassFont, long lSubTableStart, int * rgnPassOffsets,
+ int ipassSub1Font, int ipassPos1Font, int ipassJust1Font, byte ipassPostBidiFont);
+
+ void CreateEmpty();
+
+ GrEngine * Engine();
+ EngineState * State();
+
+ void Run(Segment * psegNew, Font * pfont, GrCharStream * pchstrm,
+ IGrJustifier * pgjus, int jmodi,
+ LayoutEnvironment & layout,
+ int ichStop, float dxWidth, float dxUnjustified,
+ bool fNeedFinalBreak, bool fMoreText, int ichFontLim,
+ bool fInfiniteWidth, bool fWidthIsCharCount,
+ int ichwCallerBtLim,
+ int nDirDepth, SegEnd estJ);
+
+ GrPass* Pass(int ipass)
+ {
+ Assert(ipass >= 0);
+ return m_prgppass[ipass];
+ }
+
+ int NumberOfPasses()
+ {
+ return m_cpass;
+ }
+
+ int NumberOfLbPasses()
+ {
+ return m_cpassLB;
+ }
+
+ bool HasBidiPass()
+ {
+ return m_fBidi;
+ }
+
+ int FirstPosPass()
+ {
+ return m_ipassPos1;
+ }
+
+ void StorePassStates(PassState * rgzpst);
+
+ // Return the stream that serves as input to the given pass.
+ GrSlotStream * InputStream(int ipass)
+ {
+ return m_engst.InputStream(ipass);
+ }
+ GrSlotStream * OutputStream(int ipass)
+ {
+ return m_engst.OutputStream(ipass);
+ }
+
+ void UnwindAndReinit(int islotNewBreak);
+
+public:
+ int InternalJustificationMode()
+ {
+ return m_engst.m_jmodi;
+ }
+
+ bool ShouldLogJustification()
+ {
+ return (m_engst.m_jmodi != kjmodiNormal);
+ }
+
+ int PrevPassMaxBackup(int ipass)
+ {
+ if (ipass == 0)
+ return 0;
+ return Pass(ipass - 1)->MaxBackup();
+ }
+
+ // Forward to the engine itself
+ gid16 GetGlyphIDFromUnicode(int nUnicode);
+ gid16 ActualGlyphForOutput(utf16 chwGlyphID);
+ GrGlyphTable * GlyphTable();
+
+ gid16 LBGlyphID();
+
+ gid16 GetClassGlyphIDAt(int nClass, int nIndex);
+ int GetIndexInGlyphClass(int nClass, gid16 chwGlyphID);
+ size_t NumberOfGlyphsInClass(int nClass);
+
+ void SetSlotAttrsFromGlyphAttrs(GrSlotState * pslot);
+
+ int NumFeat();
+ int DefaultForFeatureAt(int ifeat);
+ GrFeature * FeatureWithID(featid nID, int * pifeat);
+ GrFeature * Feature(int ifeat);
+ void DefaultsForLanguage(isocode lgcode,
+ std::vector<featid> & vnFeats, std::vector<int> & vnValues);
+
+ bool RightToLeft();
+ int TopDirectionLevel();
+
+ float VerticalOffset();
+
+ int NumUserDefn();
+ int NumCompPerLig();
+
+ int ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID);
+ int GlyphAttrValue(gid16 chwGlyphID, int nAttrID);
+
+ // ---
+
+ bool LoggingTransduction();
+
+ float EmToLogUnits(int m);
+ int LogToEmUnits(float xys);
+ bool GPointToXY(gid16 chwGlyphID, int nGPoint, float * xs, float * ys);
+
+ void CalcPositionsUpTo(int ipass, GrSlotState * pslotLast,
+ float * pxsWidth, float * pxsVisibleWidth);
+
+ void InitPosCache()
+ {
+ m_engst.InitPosCache();
+ }
+
+ bool IsWhiteSpace(GrSlotState * pslot);
+
+ // For transduction logging:
+ //bool WriteTransductionLog(GrCharStream * pchstrm, Segment * psegRet,
+ // int cbPrev, byte * pbPrevSegDat, byte * pbNextSegDat, int * pcbNextSegDat);
+ //bool WriteAssociationLog(GrCharStream * pchstrm, Segment * psegRet);
+ bool WriteTransductionLog(std::ostream * pstrmLog,
+ GrCharStream * pchstrm, Segment * psegRet, int cbPrevSetDat, byte * pbPrevSegDat);
+ bool WriteAssociationLog(std::ostream * pstrmLog,
+ GrCharStream * pchstrm, Segment * psegRet);
+#ifdef TRACING
+ void WriteXductnLog(std::ostream & strmOut, GrCharStream * pchstrm, Segment * psegRet,
+ int cbPrevSegDat, byte * pbPrevSegDat);
+ //bool LogFileName(std::string & staFile);
+ void LogUnderlying(std::ostream & strmOut, GrCharStream * pchstrm, int cchwBackup);
+ void LogPass1Input(std::ostream & strmOut);
+ void LogPassOutput(std::ostream & strmOut, int ipass, int cslotSkipped);
+ void LogAttributes(std::ostream & strmOut, int ipass, bool fJustWidths = false);
+ void LogFinalPositions(std::ostream & strmOut);
+ void LogUnderlyingHeader(std::ostream & strmOut, int ichwMin,
+ int ichwLim, int cchwBackup, int * prgichw16bit);
+ void LogSlotHeader(std::ostream & strmOut, int cslot,
+ int cspPerSlot, int cspLeading, int islotMin = 0);
+ void LogSlotGlyphs(std::ostream & strmOut, GrSlotStream * psstrm);
+ void SlotAttrsModified(int ipass, bool * rgfMods, bool fPreJust, int * pccomp, int *pcassoc);
+ void LogInTable(std::ostream & strmOut, int n);
+ void LogInTable(std::ostream & strmOut, float n);
+ void LogHexInTable(std::ostream & strmOut, gid16 chw, bool fPlus = false);
+ void LogDirCodeInTable(std::ostream & strmOut, int dirc);
+ void LogBreakWeightInTable(std::ostream & strmOut, int lb);
+#endif // TRACING
+
+protected:
+ void InitNewSegment(Segment * psegNew, Font * pfont, GrCharStream * pchstrm, IGrJustifier * pgjus,
+ int islotStream0Break, int islotSurfaceBreak, bool fStartLine, bool fEndLine, int ichFontLim,
+ LineBrk lbEnd, SegEnd est, int * dichSegLen);
+
+ void InitSegmentAsEmpty(Segment * psegNew, Font * pfont, GrCharStream * pchstrm,
+ bool fStartLine, bool fEndLine);
+
+ void InitSegmentToDelete(Segment * psegNew, Font * pfont, GrCharStream * pchstrm);
+
+ int ChunkInPrev(int ipass, int islot, GrCharStream * pchstrm);
+
+ bool Backtrack(int * islotPrevLB,
+ LineBrk * plbPref, LineBrk lbMax, TrWsHandling, bool fMoreText,
+ int ichwCallerBtLim, bool fEndLine, LineBrk * plbFound);
+
+ LineBrk IncLineBreak(LineBrk lb);
+
+ void InitializeForNextSeg(Segment* pseg,
+ int islotStream0Break, int islotSurfaceBreak, LineBrk lbEnd,
+ bool fNextSegNeedsContext, GrCharStream * pchstrm);
+
+ void RecordAssocsAndOutput(Font * pfont,
+ Segment * pseg, bool fWidthIsCharCount,
+ TrWsHandling twsh, bool fParaRtl, int nDirDepth);
+
+ void CalculateAssociations(Segment * pseg, int csloutSurface);
+ void AdjustAssocsForOverlaps(Segment * pseg);
+
+ void UnstretchTrailingWs(GrSlotStream * psstrm, int iGlyphLim);
+ void CallJustifier(IGrJustifier * pgjus, int ipassCurr, float dxUnjustified, float dxJustified,
+ bool fEndLine);
+
+ void DetermineShrink(IGrJustifier * pgjus, int ipass);
+
+protected:
+ // Instance variables:
+
+ int m_cpass; // number of passes; zero-th pass is Unicode character -> glyph ID mapping;
+ // Note thatwe always have one positioning pass to measure things even
+ // if there are no tables to run.
+
+ int m_cpassLB; // number of line-break passes
+ int m_ipassPos1; // first positioning pass
+ int m_ipassJust1; // first justification pass (== m_ipassPos1 if none)
+
+ bool m_fBidi; // is there a bidi pass?
+
+ // array of passes:
+ GrPass ** m_prgppass;
+
+ // Pointer back to Graphite engine, to give access to global constants and tables.
+ GrEngine * m_pgreng;
+
+ // State of processing.
+ EngineState m_engst;
+
+ bool m_fLogging;
+
+public:
+ // For test procedures:
+ void SetUpTest(std::wstring);
+
+protected:
+ void TempDebug();
+ int SurfaceLineBreakSlot(int ichw, GrCharStream * pchstrm, bool fInitial);
+ std::wstring ChunkDebugString(int ipass);
+}; // end of class GrTableManager
+
+} // namespace gr
+
+
+#endif // !GR_TABLEMAN_INCLUDED
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/Main.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/Main.h
new file mode 100644
index 00000000000..e3f971bfdbb
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/Main.h
@@ -0,0 +1,182 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: Main.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Main.header file for the Graphite engine.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef GRAPHITE_H
+#define GRAPHITE_H 1
+
+//:End Ignore
+
+#define NO_EXCEPTIONS 1
+
+// It's okay to use functions that were declared deprecated by VS 2005:
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#pragma warning(disable: 4996) // warning: function was declared deprecated
+#pragma warning(disable: 4702) // unreachable code
+#endif
+
+#include "GrCommon.h"
+
+//:>********************************************************************************************
+//:> Interfaces.
+//:>********************************************************************************************
+#include "GrData.h"
+
+//:>********************************************************************************************
+//:> Implementations.
+//:>********************************************************************************************
+
+#ifndef _WIN32
+#include "GrMstypes.h"
+#ifndef HAVE_FABSF
+float fabsf(float x);
+#endif
+#endif
+#include "GrDebug.h"
+
+// For reading the font (FieldWorks's approach) and transduction logging:
+#include <fstream>
+#include <iostream>
+
+#include <vector>
+////#include <algorithm>
+#include <string>
+#include <cstring>
+
+// gAssert should be used for any kind of assertions that can be caused by a corrupted font,
+// particularly those that won't be caught when loading the tables.
+#define gAssert(x) Assert(x)
+// When testing the error mechanism (because the process of bringing up the assertion dialog
+// interferes with FW repainting the invalid window:
+////#define gAssert(x) if (!(x)) Warn("corrupted font?")
+
+// Internal headers.
+#include "FileInput.h"
+
+// Public headers.
+#include "GrResult.h"
+//////#include "IGrGraphics.h"
+#include "ITextSource.h"
+#include "IGrJustifier.h"
+#include "IGrEngine.h"
+#include "GrConstants.h"
+#include "GrFeature.h"
+
+// External helper classes.
+#include "GrExt.h"
+
+
+// Forward declarations.
+namespace gr
+{
+ class GrTableManager;
+ class Segment;
+ class GrEngine;
+}
+
+// Define after GrExt.h to avoid conflict with FW Rect class.
+namespace gr
+{
+/*
+struct Point
+{
+ float x;
+ float y;
+
+ Point()
+ {
+ x = y = 0;
+ }
+
+ Point(POINT & p)
+ {
+ x = (float)p.x;
+ y = (float)p.y;
+ }
+};
+
+
+struct Rect
+{
+ float top;
+ float bottom;
+ float left;
+ float right;
+
+ Rect()
+ {
+ top = bottom = left = right = 0;
+ };
+
+ Rect(RECT & r)
+ {
+ top = (float)r.top;
+ bottom = (float)r.bottom;
+ left = (float)r.left;
+ right = (float)r.right;
+ };
+};
+*/
+}; // namespace gr
+
+#include "GrFeatureValues.h"
+#include "GrSlotState.h"
+
+#include "SegmentAux.h"
+
+// Internal headers
+#include "GrCharStream.h"
+#include "GrGlyphTable.h"
+#include "GrClassTable.h"
+#include "GrPseudoMap.h"
+#include "GrSlotStream.h"
+#include "GrFSM.h"
+#include "GrPass.h"
+#include "GrTableManager.h"
+#include "FontCache.h"
+
+
+// Public headers
+#include "Font.h"
+#include "GraphiteProcess.h"
+#include "GrEngine.h"
+#include "FontFace.h"
+#include "Segment.h"
+#include "SegmentPainter.h"
+
+//#ifdef _WIN32
+//#include <hash_map>
+//#include "WinFont.h"
+//#include "WinSegmentPainter.h"
+//#endif
+
+// Internal headers
+#include "TtfUtil.h"
+//#include "GrUtil.h"
+
+#include "GrWrappers.h"
+
+//#include "IGrDebug.h"
+//#include "GrSegmentDebug.h"
+//#include "GrEngineDebug.h"
+
+/////<<<<<<< .mine
+// clashes with non gr stuff
+// using namespace gr;
+///////>>>>>>> .r98
+
+#endif // GRAPHITE_H
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/Makefile.am b/Build/source/libs/graphite/engine-2.3.1/src/segment/Makefile.am
new file mode 100644
index 00000000000..59113aa924b
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/Makefile.am
@@ -0,0 +1,26 @@
+segmentdir = $(top_srcdir)/src/segment
+
+libgraphite_la_SOURCES += $(segmentdir)/FileInput.cpp
+libgraphite_la_SOURCES += $(segmentdir)/FontCache.cpp
+libgraphite_la_SOURCES += $(segmentdir)/FontFace.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrCharStream.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrClassTable.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrEngine.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrFeature.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrFSM.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrGlyphTable.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrPassActionCode.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrPass.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrSlotState.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrSlotStream.cpp
+libgraphite_la_SOURCES += $(segmentdir)/GrTableManager.cpp
+libgraphite_la_SOURCES += $(segmentdir)/MemoryUsage.cpp
+libgraphite_la_SOURCES += $(segmentdir)/Platform.cpp
+libgraphite_la_SOURCES += $(segmentdir)/SegmentAux.cpp
+libgraphite_la_SOURCES += $(segmentdir)/Segment.cpp
+libgraphite_la_SOURCES += $(segmentdir)/TestFSM.cpp
+libgraphite_la_SOURCES += $(segmentdir)/TestPasses.cpp
+libgraphite_la_SOURCES += $(segmentdir)/TransductionLog.cpp
+
+EXTRA_DIST += $(segmentdir)/*.h
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/MemoryUsage.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/MemoryUsage.cpp
new file mode 100644
index 00000000000..1fb3fc25282
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/MemoryUsage.cpp
@@ -0,0 +1,781 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: MemoryUsage.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Calculates memory usage for the engine and segments.
+----------------------------------------------------------------------------------------------*/
+
+#pragma warning(disable: 4244) // conversion from wchar_t to char
+#pragma warning(disable: 4702) // unreachable code
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+
+#include "GrCommon.h"
+#include "GrData.h"
+#ifndef _WIN32
+#include "GrMstypes.h"
+#endif
+#include "GrDebug.h"
+//#include <fstream>
+#include <iostream>
+#include <cstring>
+//#include <string>
+// Forward declarations.
+
+#include "Main.h"
+
+//namespace gr
+//{
+// class GrTableManager;
+// class Segment;
+// class GrEngine;
+//}
+//
+//#include "GrTableManager.h"
+//#include "GrFeatureValues.h"
+//#include "GrSlotState.h"
+//#include "SegmentAux.h"
+//#include "Segment.h"
+#include "MemoryUsage.h"
+
+//#ifndef _MSC_VER
+//#include "config.h"
+//#endif
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+const int stringOverhead = (3 * sizeof(int)) + (sizeof(void *)) + (8 * sizeof(short));
+const int vectorOverhead = 3 * sizeof(void *);
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Font/engine
+//:>********************************************************************************************
+
+void FontMemoryUsage::initialize()
+{
+ font = 0;
+ fontCache = 0;
+ fontFace = 0;
+
+ eng_count = 0;
+ eng_overhead = 0;
+ eng_scalars = 0;
+ eng_strings = 0;
+ eng_pointers = 0;
+ eng_cmap = 0;
+ eng_nameTable = 0;
+
+ pseudoMap = 0;
+
+ clstbl_counters = 0;
+ clstbl_offsets = 0;
+ clstbl_glyphList = 0;
+
+ glftbl_general = 0;
+ glftbl_compDefns = 0;
+ glftbl_attrTable = 0;
+ glftbl_attrOffsets = 0;
+
+ lngtbl_general = 0;
+ lngtbl_entries = 0;
+ lngtbl_featureSets = 0;
+
+ tman_general = 0;
+
+ pass_count = 0;
+ pass_general = 0;
+ pass_fsm = 0;
+ pass_ruleExtras = 0;
+ pass_constraintOffsets = 0;
+ pass_constraintCode = 0;
+ pass_actionOffsets = 0;
+ pass_actionCode = 0;
+
+ engst_general = 0;
+ engst_passState = 0;
+
+ sstrm_count = 0;
+ sstrm_general = 0;
+ sstrm_chunkMapsUsed = 0;
+ sstrm_chunkMapsAlloc = 0;
+ sstrm_reprocBuf = 0;
+
+ slot_count = 0;
+ slot_general = 0;
+ slot_abstract = 0;
+ slot_varLenBuf = 0;
+ slot_assocsUsed = 0;
+ slot_assocsAlloc = 0;
+ slot_attachUsed = 0;
+ slot_attachAlloc = 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the total byte count.
+----------------------------------------------------------------------------------------------*/
+int FontMemoryUsage::total()
+{
+ int grandTotal = 0;
+ grandTotal += font + fontCache + fontFace;
+ grandTotal += eng_overhead + eng_scalars + eng_strings + eng_pointers + eng_cmap + eng_nameTable;
+ grandTotal += pseudoMap;
+ grandTotal += clstbl_counters + clstbl_offsets + clstbl_glyphList;
+ grandTotal += glftbl_general + glftbl_compDefns + glftbl_attrTable + glftbl_attrOffsets;
+ grandTotal += lngtbl_general + lngtbl_entries + lngtbl_featureSets;
+ grandTotal += tman_general;
+ grandTotal += pass_general + pass_fsm + pass_ruleExtras
+ + pass_constraintOffsets + pass_constraintCode + pass_actionOffsets + pass_actionCode;
+ grandTotal += engst_general + engst_passState;
+ grandTotal += sstrm_general + sstrm_chunkMapsAlloc + sstrm_reprocBuf;
+ grandTotal += slot_general + slot_abstract + slot_varLenBuf + slot_assocsAlloc + slot_attachAlloc;
+
+ return grandTotal;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add the results of two runs together.
+----------------------------------------------------------------------------------------------*/
+void FontMemoryUsage::add(FontMemoryUsage & fmu)
+{
+ font += fmu.font;
+ fontCache += fmu.fontCache;
+ fontFace += fmu.fontFace;
+
+ eng_count += fmu.eng_count;
+ eng_overhead += fmu.eng_overhead;
+ eng_scalars += fmu.eng_scalars;
+ eng_strings += fmu.eng_strings;
+ eng_pointers += fmu.eng_pointers;
+ eng_cmap += fmu.eng_cmap;
+ eng_nameTable += fmu.eng_nameTable;
+
+ pseudoMap += fmu.pseudoMap;
+
+ clstbl_counters += fmu.clstbl_counters;
+ clstbl_offsets += fmu.clstbl_offsets;
+ clstbl_glyphList += fmu.clstbl_glyphList;
+
+ glftbl_general += fmu.glftbl_general;
+ glftbl_compDefns += fmu.glftbl_compDefns;
+ glftbl_attrTable += fmu.glftbl_attrTable;
+ glftbl_attrOffsets += fmu.glftbl_attrOffsets;
+
+ lngtbl_general += fmu.lngtbl_general;
+ lngtbl_entries += fmu.lngtbl_entries;
+ lngtbl_featureSets += fmu.lngtbl_featureSets;
+
+ tman_general += fmu.tman_general;
+
+ pass_count += fmu.pass_count;
+ pass_general += fmu.pass_general;
+ pass_fsm += fmu.pass_fsm;
+ pass_ruleExtras += fmu.pass_ruleExtras;
+ pass_constraintOffsets += fmu.pass_constraintOffsets;
+ pass_constraintCode += fmu.pass_constraintCode;
+ pass_actionOffsets += fmu.pass_actionOffsets;
+ pass_actionCode += fmu.pass_actionCode;
+
+ engst_general += fmu.engst_general;
+ engst_passState += fmu.engst_passState;
+
+ sstrm_count += fmu.sstrm_count;
+ sstrm_general += fmu.sstrm_general;
+ sstrm_chunkMapsUsed += fmu.sstrm_chunkMapsUsed;
+ sstrm_chunkMapsAlloc += fmu.sstrm_chunkMapsAlloc;
+ sstrm_reprocBuf += fmu.sstrm_reprocBuf;
+
+ slot_count += fmu.slot_count;
+ slot_general += fmu.slot_general;
+ slot_abstract += fmu.slot_abstract;
+ slot_varLenBuf += fmu.slot_varLenBuf;
+ slot_assocsUsed += fmu.slot_assocsUsed;
+ slot_assocsAlloc += fmu.slot_assocsAlloc;
+ slot_attachUsed += fmu.slot_attachUsed;
+ slot_attachAlloc += fmu.slot_attachAlloc;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add up the memory used by all the engines in the cache.
+----------------------------------------------------------------------------------------------*/
+FontMemoryUsage Font::calculateMemoryUsage()
+{
+ FontMemoryUsage fmu;
+ FontFace::calculateAllMemoryUsage(fmu);
+ return fmu;
+}
+
+void FontFace::calculateAllMemoryUsage(FontMemoryUsage & fmu)
+{
+ s_pFontCache->calculateMemoryUsage(fmu);
+}
+
+void FontCache::calculateMemoryUsage(FontMemoryUsage & fmuTotal)
+{
+ fmuTotal.fontCache += sizeof(int) * 4; // m_cfci, m_cfciMax, m_cfface, m_flush
+ fmuTotal.fontCache += sizeof(void*); // m_prgfci;
+
+ // Iterate through all the font faces in the cache.
+ for (int ifci = 0; ifci < m_cfci; ifci++)
+ {
+ CacheItem * pfci = m_prgfci + ifci;
+ char rgchFontName[32];
+ memset(rgchFontName, 0, 32 * sizeof(char));
+ std::copy(pfci->szFaceName, pfci->szFaceName + 32, rgchFontName);
+ std::string strFontName(rgchFontName);
+ fmuTotal.vstrFontNames.push_back(strFontName);
+ int cface = 0;
+ if (pfci->pffaceRegular)
+ {
+ FontMemoryUsage fmu;
+ pfci->pffaceRegular->calculateMemoryUsage(fmu);
+ fmuTotal.add(fmu);
+ fmuTotal.vFontTotalsReg.push_back(fmu.total());
+ cface++;
+ }
+ else
+ fmuTotal.vFontTotalsReg.push_back(0);
+
+ if (pfci->pffaceBold)
+ {
+ FontMemoryUsage fmu;
+ pfci->pffaceBold->calculateMemoryUsage(fmu);
+ fmuTotal.add(fmu);
+ fmuTotal.vFontTotalsBold.push_back(fmu.total());
+ cface++;
+ }
+ else
+ fmuTotal.vFontTotalsBold.push_back(0);
+
+ if (pfci->pffaceItalic)
+ {
+ FontMemoryUsage fmu;
+ pfci->pffaceItalic->calculateMemoryUsage(fmu);
+ fmuTotal.add(fmu);
+ fmuTotal.vFontTotalsItalic.push_back(fmu.total());
+ cface++;
+ }
+ else
+ fmuTotal.vFontTotalsItalic.push_back(0);
+
+ if (pfci->pffaceBI)
+ {
+ FontMemoryUsage fmu;
+ pfci->pffaceBI->calculateMemoryUsage(fmu);
+ fmuTotal.add(fmu);
+ fmuTotal.vFontTotalsBI.push_back(fmu.total());
+ cface++;
+ }
+ else
+ fmuTotal.vFontTotalsBI.push_back(0);
+
+ fmuTotal.vFaceCount.push_back(cface);
+ }
+}
+
+void FontFace::calculateMemoryUsage(FontMemoryUsage & fmu)
+{
+ fmu.fontFace += sizeof(int); // m_cfonts
+ fmu.fontFace += sizeof(void *) * 2; // s_pFontCache, m_pgreng
+
+ fmu.font += m_cfonts * sizeof(void*); // m_pfface
+
+ fmu.addEngine(m_pgreng);
+}
+
+void FontMemoryUsage::addEngine(GrEngine * pgreng)
+{
+ eng_count++;
+
+ eng_overhead += sizeof(long); // m_cref
+ eng_scalars += sizeof(bool) * 6; // m_fBold, m_fItalic, m_fSmart...
+ eng_scalars += sizeof(bool) * 2; // m_fFakeItalicCache, m_fFakeBICache;
+ eng_strings += stringOverhead * 4; // m_strCtrlFileReg/Bold/Italic/BI
+ eng_strings += sizeof(wchar_t) * pgreng->m_strCtrlFileReg.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_strCtrlFileBold.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_strCtrlFileItalic.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_strCtrlFileBI.length();
+ eng_scalars += sizeof(bool);
+ eng_strings += stringOverhead * 6; // m_stuCtrlFile etc.
+ eng_strings += sizeof(wchar_t) * pgreng->m_stuCtrlFile.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_stuInitError.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_stuFaceName.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_stuFeatures.length();
+ eng_strings += sizeof(wchar_t) * pgreng->m_stuBaseFaceName.length();
+ eng_scalars += sizeof(bool); // m_fUseSepBase
+ eng_scalars += sizeof(GrResult) * 2; // m_resFontRead, m_resFontValid
+ eng_scalars += sizeof(FontErrorCode);
+ eng_scalars += sizeof(int) * 3; // m_fxdBadVersion, m_nFontCheckSum, m_nScriptTag, m_grfsdc
+ eng_scalars += sizeof(bool); // m_fRightToLeft
+ eng_scalars += sizeof(int) * 2; // m_mXAscent, m_mXDescent
+ eng_scalars += sizeof(float); // m_dysOffset
+ eng_scalars += sizeof(bool); // m_fBasicJust
+ eng_scalars += sizeof(int); // m_cJLevels
+ eng_pointers += sizeof(void*) * 4; // m_ptman, m_pctbl, m_pgtbl, m_pfface
+ eng_scalars += sizeof(GrFeature) * kMaxFeatures;
+ eng_scalars += sizeof(int); // m_cfeat
+ eng_scalars += sizeof(size_t); // m_clcidFeatLabelLangs
+ eng_scalars += sizeof(short) * pgreng->m_clcidFeatLabelLangs;
+ // m_langtbl
+ eng_scalars += sizeof(bool); // m_fLineBreak
+ eng_scalars += sizeof(int) * 2; // m_cchwPreXlbContext, m_cchwPostXlbContext
+ eng_scalars += sizeof(data16) * 7; // m_chwPseudoAttr, etc.
+ eng_scalars += sizeof(gid16); // m_chwLBGlyphID
+ eng_scalars += sizeof(int) * 4; // m_cComponents, m_cnUserDefn, m_cnCompPerLig, m_mFontEmUnits
+
+ pseudoMap += sizeof(int) * 3;
+ pseudoMap += sizeof(GrPseudoMap) * pgreng->m_cpsd;
+
+ eng_cmap += sizeof(void*) * 2;
+ eng_cmap += sizeof(byte*);
+ eng_cmap += sizeof(bool);
+ if (pgreng->m_fCmapTblCopy)
+ eng_cmap += pgreng->m_cbCmapTbl;
+
+ eng_nameTable += sizeof(byte *);
+ eng_nameTable += sizeof(bool);
+ if (pgreng->m_fNameTblCopy)
+ eng_nameTable += pgreng->m_cbNameTbl;
+
+ eng_scalars += sizeof(bool) * 2; // m_fLogXductn, m_fInErrorState
+
+ clstbl_counters += sizeof(int) * 2; // m_ccls, m_cclsLinear
+ clstbl_offsets += sizeof(data16) * (pgreng->m_pctbl->m_ccls + 1);
+ clstbl_glyphList += sizeof(data16) * (pgreng->m_pctbl->m_prgichwOffsets[pgreng->m_pctbl->m_ccls]);
+
+ glftbl_general += sizeof(int) * 3; // m_cglf, m_cComponents, m_cgstbl
+ glftbl_general += vectorOverhead; // m_vpgstbl
+ GrGlyphSubTable * pgstbl = pgreng->m_pgtbl->m_vpgstbl[0];
+ glftbl_general += sizeof(int) * 4; // m_fxdSilfVersion, m_nAttrIDLim, m_cComponents, m_cnCompPerLig
+ glftbl_general += sizeof(bool) * 2; // m_fHasDebugStrings, m_fGlocShort
+ glftbl_general += sizeof(data16) * 3; // m_chw...Attr
+ glftbl_compDefns += sizeof(int) * (pgstbl->m_cnCompPerLig + 1) * pgreng->m_pgtbl->m_cglf;
+ glftbl_attrTable += sizeof(int) * 2; // m_fxdSilfVersion, m_cbEntryBufLen
+ glftbl_attrTable += sizeof(byte) * pgstbl->m_pgatbl->m_cbEntryBufLen;
+ glftbl_attrOffsets +=
+ (pgreng->m_pgtbl->m_cglf + 1) * ((pgstbl->m_fGlocShort) ? sizeof(data16) : sizeof(data32));
+
+ lngtbl_general += sizeof(size_t); // m_clang
+ lngtbl_general += sizeof(data16) * 3; // m_dilangInit, m_cLoop, m_ilangStart
+ lngtbl_general += sizeof(void*) * 2; // m_prglang, m_prgfset
+ lngtbl_general += sizeof(int); // m_cbOffset0
+ lngtbl_entries += sizeof(GrLangTable::LangEntry) * pgreng->m_langtbl.m_clang;
+ lngtbl_featureSets += sizeof(GrLangTable::FeatSet) * pgreng->m_langtbl.m_cfset;
+
+ GrTableManager * ptman = pgreng->m_ptman;
+ tman_general += sizeof(int) * 4; // m_cpass, m_cpassLB, m_ipassPos1, m_ipassJust1
+ tman_general += sizeof(bool); // m_fBidi
+ tman_general += sizeof(void*) * 2; // m_prgppass, m_pgreng
+ tman_general += sizeof(void*) * ptman->m_cpass; // m_prgppass
+ tman_general += sizeof(bool); // m_fLogging
+
+ pass_count += ptman->m_cpass;
+ for (int ipass = 0; ipass < ptman->m_cpass; ipass++)
+ {
+ GrPass * ppass = ptman->m_prgppass[ipass];
+ pass_general = sizeof(GrPass);
+
+ GrFSM * pfsm = ppass->m_pfsm;
+ if (pfsm)
+ {
+ pass_fsm += sizeof(int) * 5; // m_crow, m_crowFinal, m_rowFinalMin, m_crowNonAcpt, m_ccol
+ pass_fsm += sizeof(void*) * 3; // m_prgirulnMin, m_prgrulnMatched, m_prgrowTransitions
+ int crowSuccess = pfsm->m_crow - pfsm->m_crowNonAcpt;
+ pass_fsm += sizeof(data16) * (crowSuccess + 1); // m_prgirulnMin
+ pass_fsm += sizeof(data16) * (pfsm->m_crulnMatched); // m_prgrulnMatched
+ pass_fsm += sizeof(short) * ((pfsm->m_crow - pfsm->m_crowFinal) * pfsm->m_ccol);
+ pass_fsm += sizeof(data16); // m_dimcrInit, m_cLoop, m_imcrStart
+ pass_fsm += sizeof(int); // m_cmcr
+ pass_fsm += sizeof(void*); // m_prgmcr
+ pass_fsm += sizeof(GrFSMClassRange) * pfsm->m_cmcr;
+ pass_fsm += sizeof(int) * 2; // m_critMinRulePreContext, m_critMaxRulePreContext
+ pass_fsm += sizeof(void*); // m_prgrowStartStates
+ pass_fsm += sizeof(short) * (pfsm->m_critMaxRulePreContext - pfsm->m_critMinRulePreContext + 1);
+ }
+
+ pass_ruleExtras = sizeof(data16) * ppass->m_crul; // m_prgchwRuleSortKeys
+ pass_ruleExtras = sizeof(byte*) * ppass->m_crul; // m_prgcritRulePreModContext
+
+ pass_constraintOffsets += sizeof(data16) * (ppass->m_crul + 1);
+ pass_actionOffsets =+ sizeof(data16) * (ppass->m_crul + 1);
+
+ pass_constraintCode += sizeof(byte) * ppass->m_cbConstraints;
+ pass_actionCode += sizeof(byte) * ppass->m_cbActions;
+
+ pass_general += sizeof(bool) * ppass->m_crul; // m_prgfRuleOkay
+ pass_general += vectorOverhead; // m_vnStack
+ pass_general += sizeof(int) * ppass->m_vnStack.capacity();
+ }
+
+ engst_general += sizeof(EngineState);
+ engst_general += sizeof(void *) * ptman->m_engst.m_vslotblk.capacity();
+ engst_general += sizeof(void *) * ptman->m_engst.m_vprgnSlotVarLenBufs.capacity();
+ engst_general += sizeof(void *) * ptman->m_engst.m_cpass; // m_prgpsstrm
+
+ engst_passState += sizeof(PassState) * ptman->m_engst.m_cpass;
+
+ for (int isstrm = 0; isstrm < ptman->m_engst.m_cpass; isstrm++)
+ {
+ sstrm_count++;
+ GrSlotStream * psstrm = ptman->m_engst.m_prgpsstrm[isstrm];
+ sstrm_general += sizeof(GrSlotStream);
+ sstrm_chunkMapsUsed += psstrm->m_vislotPrevChunkMap.size();
+ sstrm_chunkMapsUsed += psstrm->m_vislotPrevChunkMap.size();
+ sstrm_chunkMapsAlloc += psstrm->m_vislotPrevChunkMap.capacity();
+ sstrm_chunkMapsAlloc += psstrm->m_vislotNextChunkMap.capacity();
+ sstrm_reprocBuf += psstrm->m_vpslotReproc.capacity();
+ sstrm_reprocBuf += sizeof(int) * 2;
+ sstrm_general -= sizeof(int) * 2;
+ }
+
+ slot_general += ptman->m_engst.m_vslotblk.size() * EngineState::kSlotBlockSize
+ * (sizeof(GrSlotState) - sizeof(GrSlotAbstract));
+ slot_abstract += ptman->m_engst.m_vslotblk.size() * EngineState::kSlotBlockSize
+ * sizeof(GrSlotAbstract);
+ int cnExtraPerSlot = ptman->m_engst.m_cUserDefn + (ptman->m_engst.m_cCompPerLig * 2)
+ + ptman->m_engst.m_cFeat;
+ slot_varLenBuf += EngineState::kSlotBlockSize * cnExtraPerSlot * sizeof(u_intslot);
+ for (size_t islotblk = 0; islotblk < ptman->m_engst.m_vslotblk.size(); islotblk++)
+ {
+ for (int islot = 0; islot < EngineState::kSlotBlockSize; islot++)
+ {
+ slot_count++;
+ GrSlotState * pslot = ptman->m_engst.m_vslotblk[islotblk] + islot;
+ slot_assocsUsed += pslot->m_vpslotAssoc.size();
+ slot_assocsAlloc += pslot->m_vpslotAssoc.capacity();
+ slot_attachUsed += pslot->m_vdislotAttLeaves.size();
+ slot_attachAlloc += pslot->m_vdislotAttLeaves.capacity();
+ }
+ }
+
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the memory usage onto a stream.
+----------------------------------------------------------------------------------------------*/
+void FontMemoryUsage::prettyPrint(std::ostream & strm)
+{
+ int totalBytes = total();
+
+ strm << "Number of engines: " << eng_count << "\n";
+ strm << "Number of passes: " << pass_count << "\n\n";
+
+ strm << "Number of slot streams: " << sstrm_count << "\n";
+ strm << "Number of slots: " << slot_count << "\n\n";
+
+ int classTableTotal = clstbl_counters + clstbl_offsets + clstbl_glyphList;
+ int glyphTableTotal = glftbl_general + glftbl_compDefns + glftbl_attrTable + glftbl_attrOffsets;
+ int langTableTotal = lngtbl_general + lngtbl_entries + lngtbl_featureSets;
+ int passTotal = pass_general + pass_fsm + pass_ruleExtras + pass_constraintOffsets + pass_constraintCode
+ + pass_actionOffsets + pass_actionCode;
+ int engineTotal = eng_overhead + eng_scalars + eng_strings + eng_pointers + eng_cmap + eng_nameTable
+ + pseudoMap + classTableTotal + glyphTableTotal + langTableTotal + tman_general
+ + passTotal;
+
+ strm << "BYTE COUNT TOTALS\n";
+ strm << "Font: " << font << "\n";
+ strm << "Font cache: " << fontCache << "\n";
+ strm << "Font face: " << fontFace << "\n";
+ strm << "Engine " << engineTotal << "\n";
+ strm << " Overhead: " << eng_overhead << "\n";
+ strm << " Scalars: " << eng_scalars << "\n";
+ strm << " Strings: " << eng_strings << "\n";
+ strm << " Pointers: " << eng_pointers << "\n";
+ strm << " Cmap table: " << eng_cmap << "\n";
+ strm << " Name table: " << eng_nameTable << "\n";
+ strm << " Pseudo map: " << pseudoMap << "\n";
+ strm << " Class table: " << classTableTotal << "\n";
+ strm << " Counters: " << clstbl_counters << "\n";
+ strm << " Offsets: " << clstbl_offsets << "\n";
+ strm << " Glyph list: " << clstbl_glyphList << "\n";
+ strm << " Glyph table: " << glyphTableTotal << "\n";
+ strm << " General: " << glftbl_general << "\n";
+ strm << " Component defns: " << glftbl_compDefns << "\n";
+ strm << " Attr table: " << glftbl_attrTable << "\n";
+ strm << " Attr offsets: " << glftbl_attrOffsets << "\n";
+ strm << " Language table: " << langTableTotal << "\n";
+ strm << " General: " << lngtbl_general << "\n";
+ strm << " Entries: " << lngtbl_entries << "\n";
+ strm << " Feature sets: " << lngtbl_featureSets << "\n";
+ strm << " Table manager: " << tman_general << "\n";
+ strm << " Passes: " << passTotal << "\n";
+ strm << " General: " << pass_general << "\n";
+ strm << " FSM: " << pass_fsm << "\n";
+ strm << " Rule extras: " << pass_ruleExtras << "\n";
+ strm << " Constraint offsets: " << pass_constraintOffsets << "\n\n";
+ strm << " Constraint code: " << pass_constraintCode << "\n";
+ strm << " Action offsets: " << pass_actionOffsets << "\n";
+ strm << " Action code: " << pass_actionCode << "\n\n";
+
+ int slotTotal = slot_general + slot_abstract + slot_varLenBuf + slot_assocsAlloc + slot_attachAlloc;
+ int streamTotal = sstrm_general + sstrm_chunkMapsAlloc + sstrm_reprocBuf + slotTotal;
+ int engineStateTotal = engst_general + engst_passState + streamTotal;
+
+ strm << " Engine State: " << engineStateTotal << "\n";
+ strm << " General: " << engst_general << "\n";
+ strm << " Pass states: " << engst_passState << "\n";
+ strm << " Slot streams: " << streamTotal << "\n";
+ strm << " General: " << sstrm_general << "\n";
+ strm << " Chunk maps: " << sstrm_chunkMapsAlloc << " (" << sstrm_chunkMapsUsed << " used)\n";
+ strm << " Reprocess buffer: " << sstrm_reprocBuf << "\n";
+ strm << " Slots: " << slotTotal << "\n";
+ strm << " General: " << slot_general << "\n";
+ strm << " Abstract: " << slot_abstract << "\n";
+ strm << " Var-length buf: " << slot_varLenBuf << "\n";
+ strm << " Associations: " << slot_assocsAlloc << " (" << slot_assocsUsed << " used)\n";
+ strm << " Attachments: " << slot_attachAlloc << " (" << slot_attachUsed << " used)\n\n";
+
+ strm << "Total bytes used: " << totalBytes << "\n\n";
+
+ strm << "TOTALS PER FONT\n";
+ for (size_t ifont = 0; ifont < vstrFontNames.size(); ifont++)
+ {
+ strm << vstrFontNames[ifont].c_str() << "\n";
+ strm << " Regular: " << vFontTotalsReg[ifont] << "\n";
+ strm << " Bold: " << vFontTotalsBold[ifont] << "\n";
+ strm << " Italic: " << vFontTotalsItalic[ifont] << "\n";
+ strm << " Bold-italic: " << vFontTotalsBI[ifont] << "\n\n";
+ }
+}
+
+
+//:>********************************************************************************************
+//:> Segment
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the data structure.
+----------------------------------------------------------------------------------------------*/
+void SegmentMemoryUsage::initialize()
+{
+ seg_count = 0;
+ overhead = 0;
+ pointers = 0;
+ scalars = 0;
+ strings = 0;
+ metrics = 0;
+ associations = 0;
+ init = 0;
+ obsolete = 0;
+
+ slot_count = 0;
+ slot_abstract = 0;
+ slot_varLenBuf = 0;
+ slot_scalars = 0;
+ slot_clusterMembers = 0;
+
+ glyphInfo_count = 0;
+ glyphInfo = 0;
+
+ wastedVector = 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Add the memory for the segemtn to the SegmentMemoryUsage data structure.
+----------------------------------------------------------------------------------------------*/
+void Segment::calculateMemoryUsage(SegmentMemoryUsage & smu)
+{
+ smu.addSegment(*this);
+}
+
+
+void SegmentMemoryUsage::addSegment(Segment & seg)
+{
+ seg_count++;
+
+ overhead += sizeof(long); // m_cref
+ pointers += sizeof(void*); // m_pgts
+ scalars += sizeof(int); // m_dichwLim
+ scalars += sizeof(int); // m_ichwMin
+ pointers += sizeof(void*); // m_pfont
+ pointers += sizeof(void*); // m_preneng
+ scalars += sizeof(bool); // m_fErroneous
+ pointers += sizeof(void*); // m_pgjus
+ scalars += sizeof(LayoutEnvironment);
+ scalars += sizeof(bool); // m_fWsRtl
+ scalars += sizeof(bool); // m_fParaRtl
+ scalars += sizeof(TrWsHandling);
+ scalars += sizeof(int); // m_nDirDepth
+ init += sizeof(byte*); // m_prgbNextSegDat
+ init += sizeof(int); // m_cbNextSegDat
+ init += sizeof(byte) * seg.m_cbNextSegDat;
+ init += sizeof(byte*); // m_prgInitDat
+ init += sizeof(int); // m_cbInitDat
+ init += sizeof(byte) * seg.m_cbInitDat;
+ init += sizeof(int); // m_dichPreContext
+// obsolete += sizeof(void *); // m_psegPrev
+// obsolete += sizeof(void *); // m_psegNext
+// strings += stringOverhead * 2;
+// strings += sizeof(wchar_t) * seg.m_stuFaceName.length();
+// strings += sizeof(wchar_t) * seg.m_stuBaseFaceName.length();
+// scalars += sizeof(bool); // m_fUseSepBase;
+// scalars += sizeof(float); // m_pixHeight
+// scalars += sizeof(bool); // m_fBold
+// scalars += sizeof(bool); // m_fItalic
+ scalars += sizeof(LineBrk); // m_lbStart
+ scalars += sizeof(LineBrk); // m_lbEnd
+ scalars += sizeof(bool); // m_fStartLine
+ scalars += sizeof(bool); // m_fEndLine
+ scalars += sizeof(SegEnd); // m_est
+ metrics += sizeof(int); // m_mFontEmUnits
+ metrics += sizeof(float) * 17; // was 19, removed m_x/ysDPI
+ associations += sizeof(int); // m_ichwAssocsMin
+ associations += sizeof(int); // m_ichwAssocsLim
+ int dichw = seg.m_ichwAssocsLim - seg.m_ichwAssocsMin;
+ associations += sizeof(int*); // m_prgisloutBefore
+ associations += sizeof(int) * dichw;
+ associations += sizeof(int*); // m_prgisloutAfter
+ associations += sizeof(int) * dichw;
+ associations += sizeof(void*); // m_prgpvisloutAssocs
+ associations += sizeof(void*) * dichw;
+ for (int idichw = 0; idichw < dichw; idichw++)
+ {
+ std::vector<int> * pvisloutAssocs = seg.m_prgpvisloutAssocs[idichw];
+ if (pvisloutAssocs)
+ {
+ associations += vectorOverhead;
+ associations += sizeof(int) * pvisloutAssocs->capacity();
+ wastedVector += sizeof(int) * (pvisloutAssocs->capacity() - pvisloutAssocs->size());
+ }
+ }
+ associations += sizeof(int*); // m_prgisloutLigature
+ associations += sizeof(int) * dichw;
+ associations += sizeof(sdata8*); // m_prgiComponent
+ associations += sizeof(sdata8) * dichw;
+// obsolete += sizeof(void*); // m_psstrm
+ scalars += sizeof(int); // m_cslout
+ slot_count += seg.m_cslout;
+ for (int islout = 0; islout < seg.m_cslout; islout++)
+ {
+ GrSlotOutput * pslout = seg.m_prgslout + islout;
+ slot_abstract += sizeof(gid16) * 2; // m_chwGlyphID, m_chwActual
+ slot_abstract += sizeof(sdata8) * 4; // m_spsl, m_dirc, m_lb, m_nDirLevel
+// slot_abstract += sizeof(float) * 8; // font/glyph metrics
+ slot_abstract += sizeof(short) * 5; // slot attributes - was 21
+ slot_abstract += sizeof(int); // m_mJWidth0;
+ slot_abstract += sizeof(byte); // m_nJWeight0;
+ slot_abstract += sizeof(bool); // m_fInsertBefore
+ slot_abstract += sizeof(sdata8); // m_bIsSpace
+ slot_abstract += sizeof(byte); // m_cnCompPerLig
+ slot_abstract += sizeof(void*); // m_prgnVarLenBuf
+ slot_varLenBuf += pslout->CExtraSpaceSlout() * sizeof(u_intslot);
+ slot_abstract += sizeof(float); // m_xsPositionX, m_ysPositionY
+// slot_abstract += sizeof(bool); // m_fAdvXSet, m_fAdvYSet
+ slot_scalars += sizeof(int) * 2; // m_ichwBefore/AfterAssoc
+ slot_scalars += sizeof(sdata8); // m_cComponents
+ slot_scalars += sizeof(int); // m_isloutClusterBase
+ slot_scalars += sizeof(sdata8); // m_disloutCluster
+ slot_scalars += sizeof(float) * 3; // m_xsClusterXOffset, m_xsClusterAdvance, m_xsAdvanceX
+ slot_scalars += sizeof(int); // m_igbb
+// slot_scalars += sizeof(Rect); // m_rectBB
+ }
+ scalars += sizeof(int); // m_cnUserDefn
+ scalars += sizeof(int); // m_cnCompPerLig
+ scalars += sizeof(int); // m_cnFeat
+ glyphInfo_count += seg.m_cginf;
+ scalars += sizeof(int); // m_cginf;
+ scalars += sizeof(int); // m_isloutGinf0
+ for (int iginf = 0; iginf < seg.m_cginf; iginf++)
+ {
+ ///GlyphInfo * pginf = seg.m_prgginf + iginf;
+ glyphInfo += sizeof(void *); // m_pseg
+ glyphInfo += sizeof(void *); // m_pslout
+ glyphInfo += sizeof(int); // m_islout
+ }
+ init += sizeof(int); // m_cslotRestartBackup
+ init += vectorOverhead;
+ init += sizeof(sdata8) * seg.m_vnSkipOffsets.capacity();
+ wastedVector += sizeof(sdata8) * (seg.m_vnSkipOffsets.capacity() - seg.m_vnSkipOffsets.size());
+ init += sizeof(DirCode); // m_dircPrevStrong
+ init += sizeof(DirCode); // m_dircPrevTerm
+
+ //int grandTotal;
+ //grandTotal = overhead + pointers + scalars + strings + metrics + associations
+ // + init + obsolete + slot_count + slot_abstract + slot_varLenBuf + slot_scalars
+ // + slot_clusterMembers + glyphInfo_count + glyphInfo;
+
+ //int totalPerSeg = grandTotal / seg_count;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the memory usage onto a stream.
+----------------------------------------------------------------------------------------------*/
+void SegmentMemoryUsage::prettyPrint(std::ostream & strm)
+{
+ int totalBytes = overhead + pointers + scalars + strings + metrics + associations
+ + init + obsolete + slot_count + slot_abstract + slot_varLenBuf + slot_scalars
+ + slot_clusterMembers + glyphInfo_count + glyphInfo;
+
+ int slotTotal = slot_abstract + slot_varLenBuf + slot_scalars + slot_clusterMembers;
+
+ strm << "Number of segments: " << seg_count << "\n\n";
+
+ strm << "TOTALS\n";
+ strm << "Overhead: " << overhead << "\n";
+ strm << "Pointers: " << pointers << "\n";
+ strm << "Scalars: " << scalars << "\n";
+ strm << "Strings: " << strings << "\n";
+ strm << "Metrics: " << metrics << "\n";
+ strm << "Associations: " << associations << "\n";
+ strm << "Obsolete: " << obsolete << "\n";
+ strm << "Slot data: " << slotTotal << "\n";
+ strm << " Abstract: " << slot_abstract << "\n";
+ strm << " Var-length buffer: " << slot_varLenBuf << "\n";
+ strm << " Scalars: " << slot_scalars << "\n";
+ strm << " Cluster members: " << slot_clusterMembers << "\n";
+ strm << "Glyph info: " << glyphInfo << "\n\n";
+
+ strm << "Wasted in vectors: " << wastedVector << "\n\n";
+
+ strm << "Total bytes used: " << totalBytes << "\n\n";
+
+ if (seg_count > 0)
+ {
+ strm << "AVERAGES\n";
+ strm << "Overhead: " << overhead/seg_count << "\n";
+ strm << "Pointers: " << pointers/seg_count << "\n";
+ strm << "Scalars: " << scalars/seg_count << "\n";
+ strm << "Strings: " << strings/seg_count << "\n";
+ strm << "Metrics: " << metrics/seg_count << "\n";
+ strm << "Associations: " << associations/seg_count << "\n";
+ strm << "Obsolete: " << obsolete/seg_count << "\n";
+ strm << "Slot data: " << slotTotal/seg_count << "\n";
+ strm << " Abstract: " << slot_abstract/seg_count << "\n";
+ strm << " Var-length buffer: " << slot_varLenBuf/seg_count << "\n";
+ strm << " Scalars: " << slot_scalars/seg_count << "\n";
+ strm << " Cluster members: " << slot_clusterMembers/seg_count << "\n";
+ strm << "Glyph info: " << glyphInfo/seg_count << "\n\n";
+
+ strm << "Avg. bytes per segment: " << totalBytes / seg_count << "\n\n";
+
+ strm << "Avg. # of slots per segment: " << slot_count / seg_count << "\n\n";
+ }
+}
+
+} //namespace gr
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/Platform.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/Platform.cpp
new file mode 100644
index 00000000000..30ec3f4bf1f
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/Platform.cpp
@@ -0,0 +1,113 @@
+#include "GrPlatform.h"
+
+#ifdef _WIN32
+#include "windows.h"
+
+namespace gr
+{
+
+size_t Platform_UnicodeToANSI(const utf16 * prgchwSrc, size_t cchwSrc, char * prgchsDst, size_t cchsDst)
+{
+ return ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)prgchwSrc, cchwSrc, prgchsDst, cchsDst, NULL, NULL);
+}
+
+size_t Platform_AnsiToUnicode(const char * prgchsSrc, size_t cchsSrc, utf16 * prgchwDst, size_t cchwDst)
+{
+ return ::MultiByteToWideChar(CP_ACP, 0, prgchsSrc, cchsSrc, (LPWSTR)prgchwDst, cchwDst);
+}
+
+size_t Platform_8bitToUnicode(int nCodePage, const char * prgchsSrc, int cchsSrc,
+ utf16 * prgchwDst, int cchwDst)
+{
+ return ::MultiByteToWideChar(nCodePage, 0, prgchsSrc, cchsSrc, (LPWSTR)prgchwDst, cchwDst);
+}
+
+size_t utf8len(const char *s)
+{
+ return mbstowcs(NULL,s,0);
+}
+
+utf16 *utf16cpy(utf16 *dest, const utf16 *src)
+{
+ return (utf16*)wcscpy((wchar_t*)dest, (const wchar_t*)src);
+}
+
+utf16 *utf16ncpy(utf16 *dest, const utf16 *src, size_t n)
+{
+ return (utf16*)wcsncpy((wchar_t*)dest, (const wchar_t*)src, n);
+}
+
+utf16 *utf16ncpy(utf16 *dest, const char *src, size_t n)
+{
+ #ifdef UTF16DEBUG
+ std::cerr << "utf16ncpy8: " << src << std::endl;
+ #endif
+ Platform_AnsiToUnicode(src, strlen(src), dest, n);
+ return dest;
+}
+
+
+size_t utf16len(const utf16 *s)
+{
+ return wcslen((const wchar_t*)s);
+}
+
+int utf16cmp(const utf16 *s1, const utf16 *s2)
+{
+return wcscmp((const wchar_t*)s1, (const wchar_t*)s2);
+}
+
+int utf16ncmp(const utf16 *s1, const utf16 *s2, size_t n)
+{
+ return wcsncmp((const wchar_t*)s1, (const wchar_t*)s2, n);
+}
+
+int utf16cmp(const utf16 *s1, const char *s2)
+{
+ while (*s1 && s2)
+ {
+ if (*s1 < *s2)
+ {
+ return -1;
+ }
+ if (*s1 > *s2)
+ {
+ return 1;
+ }
+ *s1++;
+ *s2++;
+ }
+ if (*s1) return -1;
+ else if (*s2) return 1;
+ return 0;
+}
+
+}
+#else // not _WIN32
+
+#include <iostream>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef HAVE_FABSF
+float fabsf(float x)
+{
+ return (x < 0.0f) ? -x : x;
+}
+#endif
+
+namespace gr
+{
+
+size_t utf16len(const utf16 *s)
+{
+ // assumes NULL terminated strings
+ const utf16 *start = s;
+ for (; *s; ++s);
+
+ return s - start;
+}
+
+} // namespace gr
+#endif // _WIN32
+
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/Segment.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/Segment.cpp
new file mode 100644
index 00000000000..669864780a6
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/Segment.cpp
@@ -0,0 +1,3558 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: Segment.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements a Graphite segment--a range of rendered text in one writing system, that can be
+ rendered with a single font, and that fits on a single line.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+#include <math.h>
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+#if 0 // TODO remove
+namespace
+{
+
+static bool g_fDrawing;
+
+} // namespace
+#endif
+
+
+static int g_csegTotal = 0;
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Segment methods
+//:>********************************************************************************************
+
+
+int Segment::GetSegmentCount() /// TEMP
+{
+ return g_csegTotal;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Constructor: basic initialization.
+----------------------------------------------------------------------------------------------*/
+Segment::Segment() :
+ m_pgts(NULL),
+ m_pfont(NULL),
+ m_preneng(NULL),
+ m_fErroneous(false),
+ m_pgjus(NULL),
+ m_prgbNextSegDat(NULL),
+ m_cbNextSegDat(0),
+ m_prgInitDat(NULL),
+ m_cbInitDat(0),
+// m_fUseSepBase(0),
+ //m_psegAltEndLine(NULL),
+ m_prgisloutBefore(NULL),
+ m_prgisloutAfter(NULL),
+ m_prgpvisloutAssocs(NULL),
+ m_prgisloutLigature(NULL),
+ m_prgiComponent(NULL),
+// m_psstrm(NULL),
+ m_cslout(0),
+ m_prgslout(NULL),
+ m_prgnSlotVarLenBuf(NULL),
+// m_cnUserDefn(0),
+ m_cnCompPerLig(0),
+// m_cnFeat(0),
+ m_cginf(0),
+ m_prgginf(NULL)
+{
+ m_cref = 1;
+
+ g_csegTotal++;
+
+// m_stuFaceName.erase();
+// m_stuBaseFaceName.erase();
+ m_vnSkipOffsets.clear();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reference counting.
+----------------------------------------------------------------------------------------------*/
+
+long Segment::IncRefCount(void)
+{
+ AssertPtr(this);
+ return InterlockedIncrement(&m_cref);
+}
+
+long Segment::DecRefCount(void)
+{
+ AssertPtr(this);
+ long cref = InterlockedDecrement(&m_cref);
+ if (cref == 0) {
+ m_cref = 1;
+ delete this;
+ }
+ return cref;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Constructor to fit as much of the text on the line as possible,
+ finding a reasonable break point if necessary.
+----------------------------------------------------------------------------------------------*/
+LineFillSegment::LineFillSegment(
+ Font * pfont,
+ ITextSource * pts,
+ LayoutEnvironment * playoutArg,
+ toffset ichStart,
+ toffset ichStop,
+ float xsMaxWidth,
+ bool fBacktracking)
+ : Segment()
+{
+ if (!pfont)
+ throw;
+ if (!pts)
+ throw;
+
+ LayoutEnvironment layoutDefault;
+ LayoutEnvironment * playout = (!playoutArg) ? &layoutDefault : playoutArg;
+
+ pfont->RenderLineFillSegment(this, pts, *playout, ichStart, ichStop, xsMaxWidth,
+ fBacktracking);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Constructor to create a segment representing the given range of characters.
+----------------------------------------------------------------------------------------------*/
+RangeSegment::RangeSegment(
+ Font * pfont,
+ ITextSource * pts,
+ LayoutEnvironment * playoutArg,
+ toffset ichStart,
+ toffset ichStop,
+ Segment * psegInitLike)
+ : Segment()
+{
+ if (!pfont)
+ throw;
+ if (!pts)
+ throw;
+
+ LayoutEnvironment layoutDefault;
+ LayoutEnvironment * playout = (!playoutArg) ? &layoutDefault : playoutArg;
+ playout->setSegmentForInit(psegInitLike);
+
+ pfont->RenderRangeSegment(this, pts, *playout, ichStart, ichStop);
+
+ playout->setSegmentForInit(NULL);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Constructor to create a justified segment. Private.
+----------------------------------------------------------------------------------------------*/
+JustSegmentAux::JustSegmentAux(
+ Font * pfont,
+ ITextSource * pts,
+ LayoutEnvironment * playoutArg,
+ toffset ichStart,
+ toffset ichStop,
+ float xsNaturalWidth,
+ float xsJustifiedWidth,
+ Segment * psegInitLike)
+ : Segment()
+{
+ if (!pfont)
+ throw;
+ if (!pts)
+ throw;
+
+ LayoutEnvironment layoutDefault;
+ LayoutEnvironment * playout = (!playoutArg) ? &layoutDefault : playoutArg;
+ playout->setSegmentForInit(psegInitLike);
+
+ pfont->RenderJustifiedSegment(this, pts, *playout, ichStart, ichStop,
+ xsNaturalWidth, xsJustifiedWidth);
+
+ playout->setSegmentForInit(NULL);
+}
+
+//Segment::Segment(ITextSource * pgts, int ichwMin, int ichwLim,
+// LineBrk lbStart, LineBrk lbEnd,
+// bool fStartLine, bool fEndLine, bool fWsRtl)
+//{
+// m_cref = 1;
+// Initialize(pgts, ichwMin, ichwLim, lbStart, lbEnd, fStartLine, fEndLine, fWsRtl);
+//}
+
+void Segment::Initialize(ITextSource * pgts, int ichwMin, int ichwLim,
+ LineBrk lbStart, LineBrk lbEnd, SegEnd est,
+ bool fStartLine, bool fEndLine, bool fWsRtl)
+{
+ AssertPtrN(pgts);
+ Assert(ichwMin >= 0);
+ Assert(ichwLim >= 0);
+ Assert(ichwMin <= ichwLim);
+
+ //pgts->TextSrcObject(&m_pgts); // create a permanent wrapper, if necessary
+ // m_pgts->AddRef(); no, smart pointer
+ m_pgts = pgts;
+
+ m_ichwMin = ichwMin;
+ m_dichwLim = ichwLim - ichwMin;
+ m_lbStart = lbStart;
+ m_lbEnd = lbEnd;
+ m_est = est;
+ m_dxsStretch = 0;
+ m_dxsWidth = -1;
+ m_dysAscent = -1; // to properly init, ComputeDimensions must be called
+ m_dysHeight = -1;
+ m_dysXAscent = -1;
+ m_dysXDescent = -1;
+ m_dysAscentOverhang = -1;
+ m_dysDescentOverhang = -1;
+ m_dxsLeftOverhang = -1;
+ m_dxsRightOverhang = -1;
+ m_dysOffset = 0;
+ m_fStartLine = fStartLine;
+ m_fEndLine = fEndLine;
+ m_fWsRtl = fWsRtl;
+
+ m_dxsVisibleWidth = -1;
+ m_dxsTotalWidth = -1;
+
+// m_psstrm = NULL;
+ m_prgslout = NULL;
+ m_prgnSlotVarLenBuf = NULL;
+ m_prgisloutBefore = NULL;
+ m_prgisloutAfter = NULL;
+ m_prgpvisloutAssocs = NULL;
+ m_prgisloutLigature = NULL;
+ m_prgiComponent = NULL;
+
+ m_prgbNextSegDat = NULL;
+ m_cbNextSegDat = 0;
+
+ //m_psegAltEndLine = NULL;
+
+// m_stuFaceName.erase();
+// m_stuBaseFaceName.erase();
+// m_fUseSepBase = false;
+
+// m_psegPrev = NULL; // obsolete
+// m_psegNext = NULL;
+
+ //InitializePlatform();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructor.
+----------------------------------------------------------------------------------------------*/
+Segment::~Segment()
+{
+ g_csegTotal--;
+
+ DestroyContents();
+}
+
+void Segment::DestroyContents()
+{
+ delete m_pfont;
+ m_pfont = NULL;
+
+ //if (m_pgts)
+ // // A specially-created wrapper object has to be deleted.
+ // m_pgts->DeleteTextSrcPtr();
+ m_pgts = NULL;
+
+ //if (m_pgjus)
+ // // A specially-created wrapper object has to be deleted.
+ // m_pgjus->DeleteJustifierPtr();
+ m_pgjus = NULL;
+
+ //if (m_psegAltEndLine)
+ //{
+ // if (m_psegAltEndLine->m_psegAltEndLine == this)
+ // m_psegAltEndLine->m_psegAltEndLine = NULL;
+ // delete m_psegAltEndLine;
+ //}
+
+ //for (int iginf = 0; iginf < m_cginf; iginf++) // DELETE
+ // delete m_prgginf[iginf].components;
+
+ Assert((m_prgslout && m_prgnSlotVarLenBuf) || (!m_prgslout && !m_prgnSlotVarLenBuf));
+ delete[] m_prgslout;
+ delete[] m_prgnSlotVarLenBuf;
+ delete[] m_prgisloutBefore;
+ delete[] m_prgisloutAfter;
+ for (int ichw = 0; ichw < m_ichwAssocsLim - m_ichwAssocsMin; ichw++)
+ {
+ if (m_prgpvisloutAssocs && m_prgpvisloutAssocs[ichw])
+ delete m_prgpvisloutAssocs[ichw];
+ }
+ delete[] m_prgpvisloutAssocs;
+ delete[] m_prgisloutLigature;
+ delete[] m_prgiComponent;
+ delete[] m_prgbNextSegDat;
+ delete[] m_prgInitDat;
+ delete[] m_prgginf;
+ m_cginf = 0;
+
+ //DestroyContentsPlatform();
+
+ // ReleaseObj(m_pgts); automatic because smart pointer
+}
+
+/*----------------------------------------------------------------------------------------------
+ Factory method to create a new version of an existing segment with different
+ line-boundary flags.
+----------------------------------------------------------------------------------------------*/
+Segment * Segment::LineContextSegment(Segment & seg, bool fStartLine, bool fEndLine)
+{
+ if (!seg.hasLineBoundaryContext())
+ {
+ // Make an identical segment and just change the flags.
+ Segment * psegNew = new Segment(seg);
+ psegNew->InitLineContextSegment(fStartLine, fEndLine);
+ return psegNew;
+ }
+ else
+ {
+ // Rerun the processing.
+ LayoutEnvironment layout = seg.Layout();
+ layout.setStartOfLine(fStartLine);
+ layout.setEndOfLine(fEndLine);
+ ITextSource & gts = seg.getText();
+ Font & font = seg.getFont();
+ return new RangeSegment(&font, &gts, &layout,
+ seg.startCharacter(), seg.stopCharacter(), &seg);
+ }
+}
+
+void Segment::InitLineContextSegment(bool fStartLine, bool fEndLine)
+{
+ // For RTL end-of-line segments, trailing white space hangs off the left of
+ // the origin of the segment. So when changing that flag
+ // shift appropriately.
+ bool fShift = ((m_nDirDepth % 2) && (m_fEndLine != fEndLine));
+
+ m_fStartLine = fStartLine;
+ m_fEndLine = fEndLine;
+
+ m_layout.setStartOfLine(fStartLine);
+ m_layout.setEndOfLine(fEndLine);
+
+ if (fShift)
+ {
+ (m_fEndLine) ?
+ ShiftGlyphs(m_dxsVisibleWidth - m_dxsTotalWidth) : // shift left
+ ShiftGlyphs(m_dxsTotalWidth - m_dxsVisibleWidth); // shift right
+ }
+
+ m_dxsWidth = -1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ A factory method to create a justified version of an existing segment.
+----------------------------------------------------------------------------------------------*/
+Segment * Segment::JustifiedSegment(Segment & seg, float xsNewWidth)
+{
+ LayoutEnvironment layout(seg.Layout());
+ ITextSource & gts = seg.getText();
+
+ // Why do we have to do this?
+ layout.setJustifier(seg.Justifier());
+ Font & font = seg.getFont();
+ return new JustSegmentAux(&font, &gts, &layout,
+ seg.startCharacter(), seg.stopCharacter(),
+ seg.advanceWidth(), xsNewWidth, &seg);
+}
+
+/*----------------------------------------------------------------------------------------------
+ A factory method to create a new version of an existing trailing white-space segment
+ with a different direction.
+----------------------------------------------------------------------------------------------*/
+Segment * Segment::WhiteSpaceSegment(Segment & seg, int nNewDepth)
+{
+ Segment * psegNew = new Segment(seg);
+ psegNew->InitWhiteSpaceSegment(nNewDepth);
+ return psegNew;
+}
+
+void Segment::InitWhiteSpaceSegment(int nNewDepth)
+{
+ if (nNewDepth == m_nDirDepth)
+ {
+ return;
+ }
+ else if ((nNewDepth % 2) == (m_nDirDepth % 2))
+ {
+ // Same direction, not much to change.
+ m_nDirDepth = nNewDepth;
+ return;
+ }
+ else if (m_twsh != ktwshOnlyWs)
+ return; // couldn't change it, oh, well
+
+ // Otherwise, do the hard stuff: reverse the positions of the glyphs.
+ for (int islout = 0; islout < m_cslout; islout++)
+ {
+ OutputSlot(islout)->ShiftForDirDepthChange(m_dxsTotalWidth);
+ }
+ m_nDirDepth = nNewDepth;
+
+ //SetDirectionDepthPlatform(nNewDepth);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Basic copy method.
+----------------------------------------------------------------------------------------------*/
+Segment::Segment(Segment & seg)
+{
+ int islout;
+
+ m_pgts = seg.m_pgts;
+ m_dichwLim = seg.m_dichwLim;
+ m_ichwMin = seg.m_ichwMin;
+ m_pfont = seg.m_pfont->copyThis();
+ m_preneng = seg.m_preneng;
+ m_fErroneous = seg.m_fErroneous;
+ m_pgjus = seg.m_pgjus;
+ m_fWsRtl = seg.m_fWsRtl;
+ m_fParaRtl = seg.m_fParaRtl;
+ m_twsh = seg.m_twsh;
+ m_nDirDepth = seg.m_nDirDepth;
+ m_cbNextSegDat = seg.m_cbNextSegDat;
+ m_prgbNextSegDat = new byte[m_cbNextSegDat];
+ std::copy(seg.m_prgbNextSegDat, seg.m_prgbNextSegDat + m_cbNextSegDat, m_prgbNextSegDat);
+// m_psegPrev = seg.m_psegPrev;
+// m_psegNext = seg.m_psegNext;
+// m_stuFaceName = seg.m_stuFaceName;
+// m_stuBaseFaceName = seg.m_stuBaseFaceName;
+// m_fUseSepBase = seg.m_fUseSepBase;
+// m_pixHeight = seg.m_pixHeight;
+// m_fBold = seg.m_fBold;
+// m_fItalic = seg.m_fItalic;
+ m_lbStart = seg.m_lbStart;
+ m_lbEnd = seg.m_lbEnd;
+ m_fStartLine = seg.m_fStartLine;
+ m_fEndLine = seg.m_fEndLine;
+ m_est = seg.m_est;
+ m_mFontEmUnits = seg.m_mFontEmUnits;
+ m_dysFontAscent = seg.m_dysFontAscent;
+ m_dysFontDescent = seg.m_dysFontDescent;
+ m_xysEmSquare = seg.m_xysEmSquare;
+// m_xsDPI = seg.m_xsDPI;
+// m_ysDPI = seg.m_ysDPI;
+ m_dxsStretch = seg.m_dxsStretch;
+ m_dxsWidth = seg.m_dxsWidth;
+ m_dysHeight = seg.m_dysHeight;
+ m_dysAscent = seg.m_dysAscent;
+ m_dysXAscent = seg.m_dysXAscent;
+ m_dysXDescent = seg.m_dysXDescent;
+ m_dysAscentOverhang = seg.m_dysAscentOverhang;
+ m_dysDescentOverhang = seg.m_dysDescentOverhang;
+ m_dxsLeftOverhang = seg.m_dxsLeftOverhang;
+ m_dxsRightOverhang = seg.m_dxsRightOverhang;
+ m_dxsVisibleWidth = seg.m_dxsVisibleWidth;
+ m_dxsTotalWidth = seg.m_dxsTotalWidth;
+ m_isloutVisLim = seg.m_isloutVisLim;
+ m_dysOffset = seg.m_dysOffset;
+
+ m_ichwAssocsMin = seg.m_ichwAssocsMin;
+ m_ichwAssocsLim = seg.m_ichwAssocsLim;
+
+ int dichw = m_ichwAssocsLim - m_ichwAssocsMin;
+ m_prgisloutBefore = new int[dichw];
+ std::copy(seg.m_prgisloutBefore, seg.m_prgisloutBefore + dichw, m_prgisloutBefore);
+ m_prgisloutAfter = new int[dichw];
+ std::copy(seg.m_prgisloutAfter, seg.m_prgisloutAfter + dichw, m_prgisloutAfter);
+ m_prgpvisloutAssocs = new std::vector<int> * [dichw];
+ for (int ivislout = 0; ivislout < dichw; ivislout++)
+ {
+ std::vector<int> * pvislout = seg.m_prgpvisloutAssocs[ivislout];
+ if (pvislout)
+ {
+ std::vector<int> * pvisloutNew = new std::vector<int>;
+ m_prgpvisloutAssocs[ivislout] = pvisloutNew;
+ *pvisloutNew = *pvislout; // copy the vector
+ }
+ }
+ m_prgisloutLigature = new int[dichw];
+ std::copy(seg.m_prgisloutLigature, seg.m_prgisloutLigature + dichw, m_prgisloutLigature);
+ m_prgiComponent = new sdata8[dichw];
+ std::copy(seg.m_prgiComponent, seg.m_prgiComponent + dichw, m_prgiComponent);
+
+ m_cslout = seg.m_cslout;
+ int cnExtraPerSlot = (m_cslout > 0) ? seg.m_prgslout[0].CExtraSpaceSlout() : 0;
+ m_prgnSlotVarLenBuf = new u_intslot[m_cslout * cnExtraPerSlot];
+ m_prgslout = new GrSlotOutput[m_cslout];
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutOrig = seg.m_prgslout + islout;
+ GrSlotOutput * psloutThis = m_prgslout + islout;
+ psloutThis->ExactCopyFrom(psloutOrig,
+ m_prgnSlotVarLenBuf + (islout * cnExtraPerSlot), // var-length buffer location
+ cnExtraPerSlot);
+ }
+
+// m_cnUserDefn = seg.m_cnUserDefn;
+ m_cnCompPerLig = seg.m_cnCompPerLig;
+// m_cnFeat = seg.m_cnFeat;
+ m_cslotRestartBackup = seg.m_cslotRestartBackup;
+ std::copy(seg.m_prgnSlotVarLenBuf, seg.m_prgnSlotVarLenBuf +
+ (m_cslout * cnExtraPerSlot), m_prgnSlotVarLenBuf);
+
+ m_cginf = seg.m_cginf;
+ m_isloutGinf0 = seg.m_isloutGinf0;
+ m_prgginf = new GlyphInfo[m_cginf];
+ std::copy(seg.m_prgginf, seg.m_prgginf + m_cginf, m_prgginf);
+ for (int iginf = 0; iginf < m_cginf; iginf++)
+ {
+ m_prgginf[iginf].m_pseg = this;
+ m_prgginf[iginf].m_pslout = m_prgslout + m_prgginf[iginf].m_islout;
+ }
+
+ // Platform-specific; remove eventually:
+ //m_cgstrm = seg.m_cgstrm;
+ //m_prggstrm = new GlyphStrm[m_cgstrm];
+ //for (int igstrm = 0; igstrm < m_cgstrm; igstrm++)
+ //{
+ // m_prggstrm[igstrm].gsk.ys = seg.m_prggstrm[igstrm].gsk.ys;
+ // m_prggstrm[igstrm].gsk.clrFore = seg.m_prggstrm[igstrm].gsk.clrFore;
+ // m_prggstrm[igstrm].gsk.clrBack = seg.m_prggstrm[igstrm].gsk.clrBack;
+ // m_prggstrm[igstrm].vchwGlyphId = seg.m_prggstrm[igstrm].vchwGlyphId;
+ // m_prggstrm[igstrm].vdxs = seg.m_prggstrm[igstrm].vdxs;
+ // m_prggstrm[igstrm].vigbb = seg.m_prggstrm[igstrm].vigbb;
+ // m_prggstrm[igstrm].xsStart = seg.m_prggstrm[igstrm].xsStart;
+ // m_prggstrm[igstrm].xsStartInt = seg.m_prggstrm[igstrm].xsStartInt;
+ //}
+ //m_cgbb = seg.m_cgbb;
+ //m_prggbb = new GlyphBb[m_cgbb];
+ //memcpy(m_prggbb, seg.m_prggbb, m_cgbb * sizeof(GlyphBb));
+ //-------------------------------------
+
+ m_vnSkipOffsets = seg.m_vnSkipOffsets;
+ m_dircPrevStrong = seg.m_dircPrevStrong;
+ m_dircPrevTerm = seg.m_dircPrevTerm;
+ m_cbInitDat = seg.m_cbInitDat;
+ m_prgInitDat = new byte[m_cbInitDat];
+ std::copy(seg.m_prgInitDat, seg.m_prgInitDat + m_cbInitDat, m_prgInitDat);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Swap the guts of the two segments.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void Segment::SwapWith(Segment * pgrseg)
+{
+ int crefThis = m_cref;
+ int crefOther = pgrseg->m_cref;
+
+ std::swap(*this, *pgrseg);
+
+ m_cref = crefThis;
+ pgrseg->m_cref = crefOther;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Delete the pointer to the alternate-end-of-line segment.
+----------------------------------------------------------------------------------------------*/
+void Segment::ClearAltEndLineSeg()
+{
+ //if (m_psegAltEndLine)
+ //{
+ // if (m_psegAltEndLine->m_psegAltEndLine == this)
+ // m_psegAltEndLine->m_psegAltEndLine = NULL; // so we don't get into a loop
+ // delete m_psegAltEndLine;
+ // m_psegAltEndLine = NULL;
+ //}
+}
+
+
+//:>********************************************************************************************
+//:> Interface methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Return the font that was used to create this segment.
+ Note that in some implementations, the font may be invalid; eg, on Windows the font
+ may not contain a valid device context.
+----------------------------------------------------------------------------------------------*/
+Font & Segment::getFont()
+{
+ return *m_pfont;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the text-source that the segment is representing.
+----------------------------------------------------------------------------------------------*/
+ITextSource & Segment::getText()
+{
+ return *m_pgts;
+}
+
+/*----------------------------------------------------------------------------------------------
+ The distance the drawing point should advance after drawing this segment.
+ Always positive, even for RtoL segments.
+----------------------------------------------------------------------------------------------*/
+float Segment::advanceWidth()
+{
+ if (m_dxsWidth < 0)
+ {
+ ////SetUpGraphics(ichwBase, pgg, true);
+ ComputeDimensions();
+ }
+ return m_dxsWidth;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Compute the rectangle in destination coords which contains all the pixels drawn by
+ this segment. This should be a sufficient rectangle to invalidate if the segment is
+ about to be discarded.
+----------------------------------------------------------------------------------------------*/
+Rect Segment::boundingRect()
+{
+ if (m_dxsWidth < 0)
+ {
+ ////SetUpGraphics(ichwBase, pgg, true);
+ ComputeDimensions();
+ }
+
+ Rect rectRet;
+ rectRet.top = m_dysAscent + m_dysAscentOverhang;
+ rectRet.bottom = (m_dysAscent - m_dysHeight) - m_dysDescentOverhang;
+ rectRet.left = m_dxsLeftOverhang;
+ rectRet.right = m_dxsVisibleWidth + m_dxsRightOverhang;
+
+ return rectRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Answer whether the primary direction of the segment is right-to-left. This is based
+ on the direction of the writing system, except for white-space-only segments, in
+ which case it is based on the main paragraph direction.
+----------------------------------------------------------------------------------------------*/
+bool Segment::rightToLeft()
+{
+ if (m_twsh == ktwshOnlyWs)
+ {
+ // White-space-only segment: use main paragraph direction.
+ return (m_nDirDepth % 2);
+ }
+
+ GrEngine * pgreng = EngineImpl();
+ if (pgreng)
+ {
+ return pgreng->RightToLeft();
+ }
+ return (m_pgts->getRightToLeft(m_ichwMin));
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the depth of direction embedding used by this segment. It is presumably the same
+ for all runs of the segment, otherwise, some of them would use a different writing
+ system and therefore be part of a different segment. So just use the first.
+----------------------------------------------------------------------------------------------*/
+int Segment::directionDepth(bool * pfWeak)
+{
+ if (pfWeak)
+ *pfWeak = (m_twsh == ktwshOnlyWs);
+
+// *pnDepth = m_pgts->getDirectionDepth(m_ichwLim);
+// Assert(*pnDepth == m_nDirDepth);
+
+ return m_nDirDepth;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Change the direction of the segment. This is needed specifically for white-space-only
+ segments, which are initially created to be in the direction of the paragraph, but then
+ later are discovered to not be line-end after all, and need to be changed to use the
+ directionality of the writing system.
+
+ @return kresFail for segments that do not have weak directionality and therefore
+ cannot be changed.
+----------------------------------------------------------------------------------------------*/
+bool Segment::setDirectionDepth(int nNewDepth)
+{
+ Assert(false);
+
+ if (nNewDepth == m_nDirDepth)
+ {
+ return true;
+ }
+ else if ((nNewDepth % 2) == (m_nDirDepth % 2))
+ {
+ // Same direction, not much to change.
+ m_nDirDepth = nNewDepth;
+ return true;
+ }
+ else if (m_twsh != ktwshOnlyWs)
+ return false;
+
+ // Otherwise, do the hard stuff: reverse the positions of the glyphs.
+ for (int islout = 0; islout < m_cslout; islout++)
+ {
+ OutputSlot(islout)->ShiftForDirDepthChange(m_dxsTotalWidth);
+ }
+
+ //SetDirectionDepthPlatform(nNewDepth);
+
+ return true;
+
+}
+
+/*----------------------------------------------------------------------------------------------
+ The logical range of characters covered by the segment, relative to the beginning of
+ the segment. The stop character is the index of the first character beyond the end
+ of the segment.
+
+ These values should be exact at a writing system or string boundary,
+ but may be somewhat fuzzy at a line-break, since characters may be re-ordered
+ across such boundaries. The renderer is free to apply any definition it likes of
+ where a line-break occurs. This should always be the same value obtained from the
+ renderer as pdichLimSeg.
+----------------------------------------------------------------------------------------------*/
+int Segment::startCharacter()
+{
+ return m_ichwMin;
+}
+
+int Segment::stopCharacter()
+{
+ return m_ichwMin + m_dichwLim;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns an indication of why the segment ended.
+----------------------------------------------------------------------------------------------*/
+bool Segment::startOfLine()
+{
+ return m_fStartLine;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns an indication of why the segment ended.
+----------------------------------------------------------------------------------------------*/
+bool Segment::endOfLine()
+{
+ return m_fEndLine;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns true if this segment has something special happening at line boundaries.
+----------------------------------------------------------------------------------------------*/
+bool Segment::hasLineBoundaryContext()
+{
+ return (EngineImpl()->LineBreakFlag());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Returns an indication of why the segment ended.
+----------------------------------------------------------------------------------------------*/
+SegEnd Segment::segmentTermination()
+{
+ return m_est;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Indicates the last character of interest to the segment, relative to the beginning
+ of the segment. The meaning of this is that no behavior of this segment will be
+ affected if characters beyond that change. This does not necessarily mean that
+ a different line break could not have been obtained by the renderer if characters
+ beyond that change, just that a segment with the boundaries of this one would
+ not behave differently.
+----------------------------------------------------------------------------------------------*/
+//GrResult Segment::get_LimInterest(int ichwBase, int * pdichw)
+//{
+// ChkGrOutPtr(pdichw);
+//
+// GrEngine * pgreng = EngineImpl();
+// Assert(pgreng);
+// *pdichw = m_dichwLim + pgreng->PostXlbContext();
+// ReturnResult(kresOk);
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Changes the end-of-line status of the segment. This is used after making the last segment
+ of a string if we want to attempt to put some more text after it (e.g., in another
+ writing system), or if we have reordered due to bidirectionality.
+
+ ENHANCE: the current version handles switching back and forth when we are trying to
+ decide whether we can put more stuff on a line. So it assumes we are at the end of
+ the contextual run (ie, the next batch of stuff will be in a different ows).
+ This will not correctly handle the way this function could or possibly
+ should be used for bidirectional reordering.
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult Segment::changeLineEnds(bool fNewStart, bool fNewEnd)
+{
+ if (m_fStartLine != fNewStart || m_fEndLine != fNewEnd)
+ {
+ if (EngineImpl()->LineBreakFlag())
+ {
+ if (!m_psegAltEndLine)
+ {
+ int dichwLimSeg, dichwContext;
+ float dxWidth;
+ SegEnd est;
+ int cbNextSegDat;
+ byte rgbNextSegDat[256];
+ OLECHAR rgchErrMsg[256];
+ Segment * pseg;
+
+ EngineImpl()->FindBreakPointAux(m_pfont, m_pgts, m_pgjus,
+ m_ichwMin, m_ichwMin + m_dichwLim, m_ichwMin + m_dichwLim,
+ false, fNewStart, fNewEnd, kPosInfFloat, false,
+ klbNoBreak, klbNoBreak, m_twsh, m_fParaRtl,
+ &pseg,
+ &dichwLimSeg, &dxWidth, &est,
+ m_cbInitDat, m_prgInitDat, 256, rgbNextSegDat, &cbNextSegDat,
+ &dichwContext,
+ NULL,
+ rgchErrMsg, 256);
+ // TODO: do something with the error message. This shouldn't really happen,
+ // since to get here we already created a segment with this font.
+ if (!pseg)
+ {
+ // Because we provide INT_MAX as the amount of space, there should
+ // always be enough room to generate the alternate segment.
+ Assert(false);
+ THROW(kresUnexpected);
+ }
+ Assert(cbNextSegDat == 0);
+ m_psegAltEndLine = pseg;
+ }
+ Assert(m_psegAltEndLine->m_fEndLine == fNewEnd);
+ Segment * pseg = m_psegAltEndLine; // save the value
+ SwapWith(m_psegAltEndLine);
+ m_psegAltEndLine = pseg; // reset it after swap
+ pseg->m_psegAltEndLine = this;
+ }
+ else
+ {
+ bool fShift = ((m_nDirDepth % 2) && (m_fEndLine != fNewEnd));
+ m_fStartLine = fNewStart;
+ m_fEndLine = fNewEnd;
+ if (fShift)
+ {
+ (m_fEndLine) ?
+ ShiftGlyphs(m_dxsVisibleWidth - m_dxsTotalWidth) : // shift left
+ ShiftGlyphs(m_dxsTotalWidth - m_dxsVisibleWidth); // shift right
+ }
+ m_dxsWidth = -1;
+ }
+ }
+
+ ReturnResult(kresOk);
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ Get the type of break that occurs at the logical start of the segment.
+----------------------------------------------------------------------------------------------*/
+LineBrk Segment::startBreakWeight()
+{
+ return m_lbStart;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Get the type of break that occurs at the logical end of the segment.
+----------------------------------------------------------------------------------------------*/
+LineBrk Segment::endBreakWeight()
+{
+ return m_lbEnd;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the amount of stretch, that is, the difference between the actual and natural width.
+ If the segment has been shrunk, returns a negative number.
+ TODO: implement properly.
+----------------------------------------------------------------------------------------------*/
+float Segment::stretch()
+{
+ return (float)m_dxsStretch;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the maximum stretch possible.
+ TODO: implement properly.
+----------------------------------------------------------------------------------------------*/
+float Segment::maxStretch()
+{
+ return 1000;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the maximum shrink possible.
+ TODO: implement properly.
+----------------------------------------------------------------------------------------------*/
+float Segment::maxShrink()
+{
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return iterators representing the complete range of glyphs in the segment.
+----------------------------------------------------------------------------------------------*/
+std::pair<GlyphIterator, GlyphIterator> Segment::glyphs()
+{
+ return std::make_pair(GlyphIterator(*this, 0), GlyphIterator(*this, m_cginf));
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return iterators representing the set of glyphs for the given character.
+----------------------------------------------------------------------------------------------*/
+std::pair<GlyphSetIterator, GlyphSetIterator> Segment::charToGlyphs(toffset ich)
+{
+ std::vector<int> vislout = UnderlyingToLogicalAssocs(ich);
+
+ if (vislout.size() == 0)
+ return std::make_pair(GlyphSetIterator(), GlyphSetIterator());
+ else
+ {
+ // Note that BOTH instances of GlyphSetIterator must use the same underlying vector,
+ // so that comparisons make sense.
+ RcVector * qvislout = new RcVector(vislout);
+ return std::make_pair(
+ GlyphSetIterator(*this, 0, qvislout),
+ GlyphSetIterator(*this, vislout.size(), qvislout));
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the rendered glyphs and their x- and y-coordinates, in the order generated by
+ the final positioning pass, relative to the top-left of the segment. They are always
+ returned in (roughly) left-to-right order. Note: any of the arrays may be null.
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult Segment::GetGlyphsAndPositions(
+ Rect rs, Rect rd, int cchMax, int * pcchRet,
+ utf16 * prgchGlyphs, float * prgxd, float * prgyd, float * prgdxdAdv)
+{
+ ChkGrOutPtr(pcchRet);
+ if (prgchGlyphs)
+ ChkGrArrayArg(prgchGlyphs, cchMax);
+ if (prgxd)
+ ChkGrArrayArg(prgxd, cchMax);
+ if (prgyd)
+ ChkGrArrayArg(prgyd, cchMax);
+ if (prgdxdAdv)
+ ChkGrArrayArg(prgdxdAdv, cchMax);
+
+ GrResult res;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ *pcchRet = m_cginf;
+ if (cchMax < m_cginf)
+ {
+ res = (cchMax == 0) ? kresFalse : kresInvalidArg;
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ if (m_dxsWidth < 0)
+ ComputeDimensions();
+
+ float dysFontAscent = m_dysFontAscent;
+ //////res = GetFontAscentSourceUnits(pgg, &dysFontAscent);
+ //////if (ResultFailed(res))
+ //////{
+ ////// RestoreFont(pgg);
+ ////// ReturnResult(res);
+ //////}
+
+ float xs = 0;
+ // Top of text that sits on the baseline, relative to top of segment:
+ float ys = m_dysAscent - dysFontAscent;
+
+ float * prgxdLocal;
+ if (prgxd == NULL)
+ prgxdLocal = new float[cchMax];
+ else
+ prgxdLocal = prgxd;
+
+ res = GetGlyphsAndPositionsPlatform(xs, ys, rs, rd,
+ prgchGlyphs, prgxdLocal, prgyd, prgdxdAdv);
+
+ if (!prgxd)
+ delete[] prgxdLocal;
+
+ //RestoreFont(pgg);
+
+ ReturnResult(res);
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ For debugging. Return the characters in this segment.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+GrResult Segment::GetCharData(int cchMax, utf16 * prgch, int * pcchRet)
+{
+ ChkGrArgPtr(prgch);
+ ChkGrOutPtr(pcchRet);
+
+ int ichLimTmp = m_ichwMin + min(m_dichwLim, cchMax);
+ m_pgts->fetch(m_ichwMin, ichLimTmp - m_ichwMin, prgch);
+ *pcchRet = ichLimTmp - m_ichwMin;
+ ReturnResult(kresOk);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return either the first or last character that the the glyph corresponds to. The
+ index of the glyph matches what was returned by GetGlyphsAndPositions.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+GrResult Segment::GlyphToChar(int iginf, bool fFirst, int * pich)
+{
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ *pich = PhysicalSurfaceToUnderlying(iginf, fFirst);
+ ReturnResult(kresOk);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return all the characters that the glyph corresponds to. Most commonly this will
+ be only one char, but ligatures, for instance, will have several. The index of the
+ glyph matches what was returned by GetGlyphsAndPositions.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+GrResult Segment::GlyphToAllChars(int iginf,
+ int cichMax, int * prgich, int * pcichRet)
+{
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ std::vector<int> vich;
+ int ichFirst = PhysicalSurfaceToUnderlying(iginf, true);
+ int ichLast = PhysicalSurfaceToUnderlying(iginf, false);
+ Assert(ichFirst <= ichLast);
+
+ if (ichFirst < ichLast)
+ {
+ // Loop over the range of characters that might be associated with this glyph
+ // and add any that actually are.
+ // TODO: we should probably use a method that gets us all the physical associations,
+ // but this should get us 99.5% of the way there for now.
+ for (int ich = ichFirst; ich <= ichLast; ich++)
+ {
+ int iginfFirst = UnderlyingToPhysicalSurface(ich, true);
+ int iginfLast = UnderlyingToPhysicalSurface(ich, false);
+ if (iginfFirst == iginf || iginfLast == iginf)
+ vich.push_back(ich);
+ }
+ }
+ else
+ vich.push_back(ichFirst);
+
+ *pcichRet = vich.size();
+ if (cichMax < signed(vich.size()))
+ {
+ GrResult res = (cichMax == 0 ? kresFalse : kresInvalidArg);
+ ReturnResult(res);
+ }
+ int * pi = prgich;
+ for (size_t i = 0; i < vich.size(); i++)
+ *pi++ = vich[i];
+
+ ReturnResult(kresOk);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return either the first or last glyph that corresponds to the character. The
+ index of the glyph matches what was returned by GetGlyphsAndPositions.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+GrResult Segment::CharToGlyph(int ich, bool fFirst, int * pigbb)
+{
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ *pigbb = UnderlyingToPhysicalSurface(ich, fFirst);
+ ReturnResult(kresOk);
+}
+
+
+//:>********************************************************************************************
+//:> Non-FieldWorks interface methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Return the breakweight for the given character. Returns the best value if the character is
+ mapped to glyphs with different values.
+----------------------------------------------------------------------------------------------*/
+LineBrk Segment::getBreakWeight(int ich, bool fBreakBefore)
+{
+ LineBrk lbFirst, lbLast;
+
+ int isloutFirst = UnderlyingToLogicalSurface(ich, true);
+ if (isloutFirst == kPosInfinity || isloutFirst == kNegInfinity)
+ return klbClipBreak;
+ GrSlotOutput * psloutFirst = m_prgslout + isloutFirst;
+ bool fNotFirst = false;
+ if ((psloutFirst->NumberOfComponents() > 0)
+ && psloutFirst->FirstUnderlyingComponent(0) != ich)
+ {
+ // Not the first component of a ligature.
+ lbFirst = (LineBrk) ((int)klbClipBreak * -1);
+ fNotFirst = true;
+ }
+ else
+ {
+ lbFirst = (LineBrk) psloutFirst->BreakWeight();
+ }
+
+ int isloutLast = UnderlyingToLogicalSurface(ich, false);
+ if (isloutLast == kPosInfinity || isloutLast == kNegInfinity)
+ return klbClipBreak;
+ GrSlotOutput * psloutLast = m_prgslout + isloutLast;
+ bool fNotLast = false;
+ int icompLast = psloutLast->NumberOfComponents() - 1;
+ if ((psloutLast->NumberOfComponents() > 0)
+ && psloutLast->LastUnderlyingComponent(icompLast) != ich)
+ {
+ // Not the last component of a ligature.
+ lbLast = klbClipBreak;
+ fNotLast = true;
+ }
+ else
+ {
+ lbLast = (LineBrk) psloutLast->BreakWeight();
+ }
+
+ LineBrk lbRet;
+ if (fNotLast && fNotFirst)
+ // middle of a ligature
+ lbRet = klbClipBreak;
+ else if (fNotLast)
+ lbRet = (fBreakBefore) ? lbFirst : klbClipBreak;
+ else if (fNotFirst)
+ lbRet = (fBreakBefore) ? klbClipBreak : lbLast;
+ else
+ lbRet = (fBreakBefore) ? lbFirst : lbLast;
+
+ return lbRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the width of the range of characters. Line-boundary contextualization is handled
+ by the measure attributes on the glyphs. The width returned is equivalent to the sum of
+ the widths of any line-segments that would be needed to underline all the characters.
+
+ Since this method is intended to be used on "measured" segments that include the entire
+ paragraph, it is not very smart about handling cross-line-boundary contextualization.
+ It basically ignores any glyphs that are rendered by this segment but not officially
+ part of the segment.
+----------------------------------------------------------------------------------------------*/
+float Segment::getRangeWidth(int ichMin, int ichLim,
+ bool fStartLine, bool fEndLine, bool fSkipSpace)
+{
+ if (m_dxsWidth < 0)
+ {
+ ////SetUpGraphics(ichwBase, pgg, true);
+ ComputeDimensions();
+ }
+
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ //float xsSegRight = m_dxsTotalWidth;
+
+ int ichMinRange = min(ichMin, ichLim);
+ int ichLimRange = max(ichMin, ichLim);
+
+ //int ichMinSeg = max(ichMinRange, m_ichwMin + m_ichwAssocsMin);
+ //int ichLimSeg = min(ichLimRange, m_ichwMin + m_ichwAssocsLim);
+ int ichMinSeg = max(ichMinRange, m_ichwMin);
+ int ichLimSeg = min(ichLimRange, m_ichwMin + m_dichwLim);
+
+ if (ichLimSeg < m_ichwMin) // not + m_ichwAssocsMin
+ return 0;
+ if (ichMinSeg >= m_ichwMin + m_dichwLim) // not m_ichwAssocsLim
+ return 0;
+
+ if (fSkipSpace)
+ {
+ int islout = UnderlyingToLogicalSurface(ichLimSeg - 1, true);
+ GrSlotOutput * pslout = (islout == kNegInfinity || islout == kPosInfinity) ?
+ NULL :
+ OutputSlot(islout);
+ while (pslout && pslout->IsSpace())
+ {
+ ichLimSeg--;
+ islout = UnderlyingToLogicalSurface(ichLimSeg - 1, true);
+// pslout = OutputSlot(islout);
+ pslout = (islout == kNegInfinity || islout == kPosInfinity) ?
+ NULL : OutputSlot(islout);
+ }
+ }
+
+ float xsWidth = 0;
+ SegmentNonPainter segp(this); // doesn't really need to paint
+ float rgxdLefts[100];
+ float rgxdRights[100];
+ size_t cxd = 0;
+ if (ichMinRange < ichLimRange)
+ cxd = segp.getUnderlinePlacement(ichMinSeg, ichLimSeg, fSkipSpace,
+ 100, rgxdLefts, rgxdRights, NULL);
+ for (size_t i = 0; i < cxd; i++)
+ xsWidth += rgxdRights[i] - rgxdLefts[i];
+
+ // Add in the line-boundary contextualization.
+ int isloutFirst = UnderlyingToLogicalSurface(ichMin, true);
+ int isloutLast = UnderlyingToLogicalSurface(ichLim - 1, false);
+ int mSol = 0;
+ int mEol = 0;
+ if (0 <= isloutFirst && isloutFirst < m_cslout)
+ mSol = m_prgslout[isloutFirst].MeasureSol();
+ if (0 <= isloutLast && isloutLast < m_cslout)
+ mEol = m_prgslout[isloutLast].MeasureEol();
+ float dxsSol = GrEngine::GrIFIMulDiv(mSol, m_xysEmSquare, m_mFontEmUnits);
+ float dxsEol = GrEngine::GrIFIMulDiv(mEol, m_xysEmSquare, m_mFontEmUnits);
+ xsWidth += dxsSol;
+ xsWidth += dxsEol;
+
+ //RestoreFont(pgg);
+
+ return xsWidth;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the next reasonable breakpoint after ichStart resulting in range that fits in
+ the specified width.
+----------------------------------------------------------------------------------------------*/
+int Segment::findNextBreakPoint(int ichStart,
+ LineBrk lbPref, LineBrk lbWorst, float dxMaxWidth,
+ float * pdxBreakWidth, bool fStartLine, bool fEndLine)
+{
+ ChkGrOutPtr(pdxBreakWidth);
+
+ int ichBreak;
+
+ // First make a rough estimation of how much will fit, using a binary chop approach.
+ int iginfStart = UnderlyingToPhysicalSurface(ichStart, !m_fWsRtl);
+ int iginfEnd = UnderlyingToPhysicalSurface(m_ichwMin + m_dichwLim - 1, m_fWsRtl);
+ int iginfLeft = min(iginfStart, iginfEnd);
+ int iginfRight= max(iginfStart, iginfEnd);
+
+ int iginfMin = iginfLeft;
+ int iginfLim = iginfRight;
+ int ichFit;
+ if (m_fWsRtl) // right-to-left
+ {
+ float xRight = GlyphLeftEdge(iginfRight + 1);
+ float xLeftMost = xRight - dxMaxWidth;
+ while (GlyphLeftEdge(iginfLim) < xLeftMost)
+ {
+ if (iginfLim - iginfMin <= 1)
+ break;
+ int iginfMid = (iginfLim + iginfMin) >> 1; // divide by 2
+ if (GlyphLeftEdge(iginfMid) < xLeftMost)
+ iginfLim = iginfMid;
+ else
+ iginfMin = iginfMid;
+ }
+ ichFit = PhysicalSurfaceToUnderlying(iginfLim, false);
+ }
+ else // left-to-right
+ {
+ float xLeft = GlyphLeftEdge(iginfLeft);
+ float xRightMost = dxMaxWidth - xLeft; // QUESTION: shouldn't this be +, not -?
+ iginfLim++;
+ while (GlyphLeftEdge(iginfLim) > xRightMost)
+ {
+ if (iginfLim - iginfMin <= 1)
+ break;
+ int iginfMid = (iginfLim + iginfMin) >> 1; // divide by 2
+ if (GlyphLeftEdge(iginfMid) > xRightMost)
+ iginfLim = iginfMid;
+ else
+ iginfMin = iginfMid;
+ }
+ Assert(iginfLim <= m_cginf);
+ if (iginfLim >= m_cginf) iginfLim = m_cginf - 1;
+ ichFit = PhysicalSurfaceToUnderlying(iginfLim, false);
+ }
+
+ // Breaking after ichFit should pretty much fit in the space. But make sure.
+ float dxWidthFit;
+ while (ichFit > ichStart)
+ {
+ dxWidthFit = getRangeWidth(ichStart, ichFit, fStartLine, fEndLine);
+ if (dxWidthFit <= dxMaxWidth)
+ break;
+ ichFit--;
+ }
+
+ if (ichFit <= ichStart)
+ {
+ // Nothing will fit.
+ return ichStart - 1;
+ }
+
+ // Now look for a good break. First look forward until the range doesn't fit anymore.
+ int ichTry = ichFit;
+ int nExtra = 2;
+ LineBrk lbBest = klbClipBreak;
+ int ichBestBreak = -1;
+ while (nExtra > 0 && ichTry < m_ichwMin + m_dichwLim)
+ {
+ float dxWTmp;
+ dxWTmp = getRangeWidth(ichStart, ichTry, fStartLine, fEndLine);
+ if (dxWTmp <= dxMaxWidth)
+ {
+ LineBrk lbTmp;
+ lbTmp = getBreakWeight(ichTry - 1, false);
+ if (lbTmp > 0 && lbTmp < lbWorst && max(lbTmp, lbPref) <= lbBest)
+ {
+ ichBestBreak = ichTry;
+ lbBest = max(lbTmp, lbPref); // any value better than lbPref is insignificant
+ }
+ else
+ {
+ lbTmp = getBreakWeight(ichTry - 1, true);
+ if (lbTmp < 0)
+ {
+ lbTmp = LineBrk(max(lbTmp * -1L, long(lbPref)));
+ if (lbTmp < lbWorst && lbTmp <= lbBest)
+ {
+ ichBestBreak = ichTry - 1;
+ lbBest = lbTmp;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Didn't fit. But it is theoretically possible that actually adding another
+ // character will! Try a few more.
+ nExtra--;
+ }
+ ichTry++;
+ }
+
+ if (ichBestBreak > -1)
+ {
+ if (ichTry >= m_ichwMin + m_dichwLim)
+ {
+ // Break at the end of the segment.
+ ichBreak = m_ichwMin + m_dichwLim;
+ *pdxBreakWidth = getRangeWidth(ichStart, m_dichwLim, fStartLine, fEndLine);
+ return ichBreak;
+ }
+
+ if (lbBest <= lbPref)
+ {
+ // Found a reasonable break by looking forward; return it.
+ ichBreak = ichBestBreak;// + m_ichwMin;
+ *pdxBreakWidth = getRangeWidth(ichStart, ichBestBreak, fStartLine, fEndLine);
+ return ichBreak;
+ }
+ }
+
+ // Didn't find a really good break point looking forward from our rough guess.
+ // Now look backward.
+
+ ichTry = ichFit;
+ while (ichTry > ichStart)
+ {
+ LineBrk lbTmp;
+ lbTmp = getBreakWeight(ichTry - 1, false);
+ if (lbTmp > 0 && lbTmp < lbWorst && max(lbTmp, lbPref) < lbBest)
+ {
+ ichBestBreak = ichTry;
+ lbBest = max(lbTmp, lbPref); // any value better than lbPref is insignificant
+ }
+ else
+ {
+ lbTmp = getBreakWeight(ichTry - 1, true);
+ if (lbTmp < 0)
+ {
+ lbTmp = LineBrk(max(lbTmp * -1L, long(lbPref)));
+ if (lbTmp < lbWorst && lbTmp < lbBest)
+ {
+ ichBestBreak = ichTry - 1;
+ lbBest = lbTmp;
+ }
+ }
+ }
+ if (lbBest <= lbPref)
+ break;
+
+ ichTry--;
+ }
+
+ if (ichBestBreak > -1 && ichBestBreak > ichStart)
+ {
+ // Found a reasonable break by looking backward; return it.
+ ichBreak = ichBestBreak;// + m_ichwMin;
+ *pdxBreakWidth = getRangeWidth(ichStart, ichBestBreak, fStartLine, fEndLine);
+ return ichBreak;
+ }
+
+ // No reasonable break.
+ return ichStart - 1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Private; used by findNextBreakPoint().
+----------------------------------------------------------------------------------------------*/
+float Segment::GlyphLeftEdge(int iginf)
+{
+ if (iginf >= m_cginf)
+ return m_prgginf[m_cginf - 1].origin() + m_prgginf[m_cginf - 1].advanceWidth();
+// return m_prgginf[m_cginf].origin() + m_prgginf[m_cginf].advanceWidth();
+ else
+ return m_prgginf[iginf].origin();
+}
+
+
+//:>********************************************************************************************
+//:> Other methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ Get the embedded string. For temporary use; AddRef is not automatically called.
+ Do not release unless you AddRef.
+----------------------------------------------------------------------------------------------*/
+ITextSource * Segment::GetString()
+{
+ return m_pgts;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Compute the ascent, height, width, and overhangs of the segment.
+ The ascent is the ascent of the font (distance from the baseline to the top)
+ plus any extra ascent height specified by the font.
+ The descent is distance from the baseline to the bottom of font, plus any extra descent
+ specified by the font (ExtraDescent).
+ The ascent overhang is the distance from the top of the font to the top of the highest
+ glyph, or zero if all the glyphs fit within the ascent.
+ The descent overhang is the distance from the bottom of the font to the bottom of the lowest
+ glyph, or zero if all the glyphs fit within the descent.
+ The height is the sum of the ascent and descent.
+----------------------------------------------------------------------------------------------*/
+void Segment::ComputeDimensions()
+{
+ if (m_fEndLine)
+ m_dxsWidth = m_dxsVisibleWidth; // don't include trailing white space.
+ else
+ m_dxsWidth = m_dxsTotalWidth;
+
+ if (m_dxsWidth == -1)
+ {
+ for (int iginf = 0; iginf < m_cginf; iginf++)
+ {
+ GlyphInfo * pginf = m_prgginf + iginf;
+ if (pginf->isSpace())
+ continue;
+ m_dxsWidth = max(m_dxsWidth, (pginf->origin() + pginf->advanceWidth()));
+ }
+ }
+
+ int dysNegFontDescent = (int)m_dysFontDescent * -1;
+
+ // if there were no glyphs in the segment then there is sometimes no EngineImpl
+ if (!EngineImpl())
+ {
+ Assert(m_cslout == 0);
+ Assert(m_cginf == 0);
+ m_dxsWidth = 0;
+ m_dysAscent = 0; // max(0.0, m_dysFontAscent);
+ m_dysHeight = 0; // max(0.0, m_dysAscent - dysNegFontDescent);
+ m_dysAscentOverhang = 0;
+ m_dysDescentOverhang = 0;
+ m_dxsLeftOverhang = 0;
+ m_dxsRightOverhang = 0;
+ return;
+ }
+
+ // Calculate the extra ascent and descent.
+ int mXAscent = EngineImpl()->ExtraAscent();
+ int mXDescent = EngineImpl()->ExtraDescent();
+
+ m_dysXAscent = GrEngine::GrIFIMulDiv(mXAscent, m_xysEmSquare, m_mFontEmUnits);
+ m_dysXDescent = GrEngine::GrIFIMulDiv(mXDescent, m_xysEmSquare, m_mFontEmUnits);
+
+ m_dysAscent = m_dysFontAscent + m_dysXAscent;
+ float dysNegDescent = dysNegFontDescent - m_dysXDescent; // dysNegDescent < 0
+ m_dysHeight = m_dysAscent - dysNegDescent;
+
+ // Calculate the overhangs.
+ float dysVisAscent = m_dysAscent;
+ float dysNegVisDescent = dysNegDescent;
+ float dxsVisLeft = 0;
+ float dxsVisRight = m_dxsTotalWidth;
+ ComputeOverhangs(&dysVisAscent, &dysNegVisDescent, &dxsVisLeft, &dxsVisRight);
+ m_dysAscentOverhang = max(float(0), (dysVisAscent - m_dysAscent));
+ m_dysDescentOverhang = max(float(0), (dysNegDescent - dysNegVisDescent));
+ m_dxsLeftOverhang = min(float(0), dxsVisLeft);
+ m_dxsRightOverhang = max(float(0), dxsVisRight - m_dxsTotalWidth);
+
+ m_dysOffset = EngineImpl()->VerticalOffset();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Compute the visible ascent and descent, based on how much the bounding box of any
+ glyph may extend beyond the ascent or descent of the font.
+ Also compute the left- and right-overhangs.
+----------------------------------------------------------------------------------------------*/
+void Segment::ComputeOverhangs(float * pdysVisAscent, float * pdysNegVisDescent,
+ float * pdxsVisLeft, float * pdxsVisRight)
+{
+ for (int iginf = 0; iginf < m_cginf; iginf++)
+ {
+ *pdysVisAscent = max(*pdysVisAscent, m_prgginf[iginf].bb().top);
+ *pdysNegVisDescent = min(*pdysNegVisDescent, m_prgginf[iginf].bb().bottom);
+
+ *pdxsVisLeft = min(*pdxsVisLeft, m_prgginf[iginf].bb().left);
+ *pdxsVisRight = max(*pdxsVisRight, m_prgginf[iginf].bb().right);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Create the arrays to store the final output and association information.
+----------------------------------------------------------------------------------------------*/
+void Segment::SetUpOutputArrays(Font * pfont, GrTableManager * ptman,
+ GrSlotStream * psstrmFinal,
+ int cchwInThisSeg, int csloutSurface, gid16 chwLB,
+ TrWsHandling twsh, bool fParaRtl, int nDirDepth, bool fEmpty)
+{
+ m_mFontEmUnits = EngineImpl()->GetFontEmUnits();
+
+ pfont->getFontMetrics(&m_dysFontAscent, &m_dysFontDescent, &m_xysEmSquare);
+// m_xsDPI = (float)pfont->getDPIx();
+// m_ysDPI = (float)pfont->getDPIy();
+
+ // Note that storing both of these values is redundant; they should be the same.
+// Assert(m_xysEmSquare == m_pixHeight);
+
+ m_twsh = twsh;
+ m_fParaRtl = fParaRtl;
+ if (m_twsh == ktwshOnlyWs)
+ m_nDirDepth = (int)fParaRtl;
+ else if (fParaRtl && nDirDepth == 0)
+ m_nDirDepth = 2;
+ else
+ m_nDirDepth = nDirDepth;
+
+ // Create association mappings and set up final versions of slots.
+
+ Assert((psstrmFinal == NULL) == fEmpty);
+
+ m_ichwAssocsMin = 0;
+ m_ichwAssocsLim = cchwInThisSeg;
+
+ m_prgisloutBefore = new int[cchwInThisSeg];
+
+ m_prgisloutAfter = new int[cchwInThisSeg];
+
+ m_prgpvisloutAssocs = new std::vector<int> * [cchwInThisSeg];
+
+ m_prgisloutLigature = new int[cchwInThisSeg];
+
+ m_prgiComponent = new sdata8[cchwInThisSeg];
+
+ int cslot = 0;
+ //m_psstrm = psstrmFinal; // TODO: make a local variable
+ if (psstrmFinal)
+ cslot = psstrmFinal->FinalSegLim();
+ else
+ Assert(fEmpty);
+
+ float xsMin = 0;
+ int islot;
+ int islotMin = (psstrmFinal) ? psstrmFinal->IndexOffset() : 0;
+ for (islot = islotMin; islot < cslot; islot++)
+ xsMin = min(xsMin, psstrmFinal->SlotAt(islot)->XPosition());
+
+ // For right-to-left segments, the draw origin is at the left side of the visible
+ // portion of the text. So if necessary, scoot everything left so that the invisible
+ // trailing white-space is to the left of the draw position.
+ Assert(m_dxsTotalWidth > -1);
+ Assert(m_dxsVisibleWidth > -1);
+ float dxsInvisible = (m_fEndLine) ? m_dxsTotalWidth - m_dxsVisibleWidth : 0;
+ for (islot = islotMin; ((m_nDirDepth % 2) && (islot < cslot)); islot++)
+ {
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+ // int islout = islot - islotMin;
+ if (pslot->GlyphID() == chwLB)
+ continue; // skip over linebreak markers
+ if (m_nDirDepth % 2) // redundant test
+ {
+ // RTL will have descending neg values, adjust to be positive. Also make sure
+ // invisible trailing white space is to the left of the draw origin.
+ // Review: will changing this value have side affects?
+ pslot->SetXPos(pslot->XPosition() - xsMin - dxsInvisible);
+ }
+ }
+
+ Assert(kPosInfinity > 0);
+ Assert(kNegInfinity < 0);
+ for (int ichw = 0; ichw < cchwInThisSeg; ++ichw)
+ {
+ m_prgisloutBefore[ichw] = kPosInfinity;
+ m_prgisloutAfter[ichw] = kNegInfinity;
+ m_prgpvisloutAssocs[ichw] = new std::vector<int>;
+ m_prgisloutLigature[ichw] = kNegInfinity;
+ m_prgiComponent[ichw] = 0;
+ }
+
+ m_cslout = csloutSurface;
+ if (ptman->NumUserDefn() > 0 && ptman->NumCompPerLig() > 0)
+ {
+ int x; x = 3;
+ }
+
+// m_cnUserDefn = ptman->NumUserDefn();
+ m_cnCompPerLig = ptman->NumCompPerLig();
+// m_cnFeat = ptman->NumFeat();
+ // Normal buffers, plus:
+ // - underlying indices of ligature components
+ // - map from used components to defined components
+// int cnExtraPerSlot = m_cnUserDefn + (m_cnCompPerLig * 2) + m_cnFeat + (m_cnCompPerLig * 2);
+
+ // We don't need to store the user-defined slot attributes or the features in the segment itself.
+ // What we need is: (1) component.ref attr settings, (2) slot-attribute indices,
+ // (3) underlying indices of ligature components, and (4) map from used components
+ // to defined components
+ // 18Jul08 - it looks like all we need are underlying chars for ligature components and
+ // map from components to defined components.
+ int cnExtraPerSlot = m_cnCompPerLig * 2;
+ m_prgslout = new GrSlotOutput[m_cslout];
+ m_prgnSlotVarLenBuf = new u_intslot[m_cslout * cnExtraPerSlot];
+
+ m_isloutVisLim = 0;
+ if (psstrmFinal)
+ {
+ for (islot = islotMin; islot < psstrmFinal->FinalSegLim(); ++islot)
+ {
+ int isloutRel = islot - islotMin;
+
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+ pslot->SetPosPassIndex(isloutRel, false);
+ pslot->EnsureCacheForOutput(ptman);
+ GrSlotOutput * pslout = OutputSlot(isloutRel);
+ pslout->SetBufferPtr(m_prgnSlotVarLenBuf + (isloutRel * cnExtraPerSlot));
+ pslout->InitializeOutputFrom(pslot);
+ pslout->SetBeforeAssoc(pslot->BeforeAssoc());
+ pslout->SetAfterAssoc(pslot->AfterAssoc());
+ if (pslot->HasComponents())
+ pslot->SetComponentRefsFor(pslout);
+ Assert(pslot->HasComponents() == (pslout->NumberOfComponents() > 0));
+ //if (pslot->HasClusterMembers())
+ //{
+ //Assert(pslot->HasClusterMembers() || pslot->ClusterRootOffset() == 0);
+ pslout->SetClusterXOffset(pslot->ClusterRootOffset() * -1);
+ pslout->SetClusterAdvance(pslot->ClusterAdvWidthFrom(0));
+
+ //}
+
+ if (!ptman->IsWhiteSpace(pslot))
+ m_isloutVisLim = islot + 1;
+ }
+ }
+
+ // Set up the clusters.
+ for (islot = islotMin; islot < m_cslout; islot++)
+ {
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+ int isloutAdj = islot - islotMin;
+ int isloutBaseIndex = pslot->Base(psstrmFinal)->PosPassIndex();
+ if (!pslot->IsBase())
+ {
+ OutputSlot(isloutBaseIndex)->AddClusterMember(isloutBaseIndex, pslot->PosPassIndex());
+ OutputSlot(isloutAdj)->SetClusterBase(isloutBaseIndex);
+ }
+ else if (pslot->HasClusterMembers() && pslot->IsBase())
+ {
+ Assert(isloutBaseIndex == islot - islotMin);
+ OutputSlot(isloutAdj)->SetClusterBase(isloutBaseIndex);
+ }
+ }
+
+ ///AssertValidClusters(psstrmFinal);
+
+#ifdef OLD_TEST_STUFF
+ if (ptman->GlyphTable() == NULL)
+ return; // test procedures
+#endif // OLD_TEST_STUFF
+
+ // CalcPositionsUpTo() called on final pass already from Table Mgr
+
+ // Final output for draw routines.
+
+ SetUpGlyphInfo(ptman, psstrmFinal, chwLB, nDirDepth, islotMin, cslot);
+
+ //SetUpOutputArraysPlatform(ptman, chwLB, nDirDepth, islotMin, cslot);
+
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set up the data structures that represent the actual rendered glyphs for the new segment.
+----------------------------------------------------------------------------------------------*/
+void Segment::SetUpGlyphInfo(GrTableManager * ptman, GrSlotStream * psstrmFinal,
+ gid16 chwLB, int nDirDepth, int islotMin, int cslot)
+{
+ //int paraDirLevel = (ptman->State()->ParaRightToLeft()) ? 1 : 0;
+
+ m_cginf = 0;
+
+ int islot;
+ for (islot = islotMin; islot < cslot; islot++)
+ {
+ if (psstrmFinal->SlotAt(islot)->GlyphID() != chwLB)
+ {
+ m_cginf++;
+ }
+ }
+
+ // For right-to-left segments, the draw origin will be at the left side of the visible
+ // portion of the text. So if necessary, scoot everything left so that the invisible
+ // trailing white-space is to the left of the draw position.
+ Assert(m_dxsTotalWidth > -1);
+ Assert(m_dxsVisibleWidth > -1);
+ //float dxsInvisible = (m_fEndLine) ? m_dxsTotalWidth - m_dxsVisibleWidth : 0;
+
+ m_prgginf = new GlyphInfo [m_cginf];
+
+ m_isloutGinf0 = -1;
+ int iginf = 0;
+ for (int islot = islotMin; islot < cslot; islot++)
+ {
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+
+ if (pslot->GlyphID() == chwLB)
+ {
+ continue; // skip over linebreak markers
+ }
+
+ int islout = islot - islotMin;
+ GrSlotOutput * pslout = OutputSlot(islout);
+
+ if (m_isloutGinf0 == -1)
+ m_isloutGinf0 = islout;
+
+ m_prgginf[iginf].m_pslout = pslout;
+ m_prgginf[iginf].m_islout = islout;
+ m_prgginf[iginf].m_pseg = this;
+
+ // Fill in stuff in the output slot that is needed by the GlyphInfo object.
+ ////pslout->m_xsAdvanceX = pslot->GlyphMetricLogUnits(ptman, kgmetAdvWidth); // wrong
+ pslout->m_xsAdvanceX = ptman->EmToLogUnits(pslot->AdvanceX(ptman));
+ //pslout->m_ysAdvanceY = ptman->EmToLogUnits(pslot->AdvanceY(ptman));
+ //pslout->m_rectBB.top
+ // = pslot->YPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbTop);
+ //pslout->m_rectBB.bottom
+ // = pslot->YPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbBottom);
+ //pslout->m_rectBB.left
+ // = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbLeft);
+ //if (pslot->IsSpace(ptman))
+ // pslout->m_rectBB.right
+ // = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetAdvWidth);
+ //else
+ // pslout->m_rectBB.right
+ // = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbRight);
+
+ iginf++;
+ }
+
+ if (cslot - islotMin == 0)
+ m_isloutGinf0 = 0;
+ if (m_isloutGinf0 == -1)
+ {
+ Assert(m_cginf == 0);
+ m_isloutGinf0 = ((OutputSlot(0)->IsInitialLineBreak()) ? 1 : 0);
+ }
+
+ Assert(m_isloutGinf0 == 0 || m_isloutGinf0 == 1);
+}
+
+/*
+// OLD VERSION
+void Segment::SetUpGlyphInfo(GrTableManager * ptman, GrSlotStream * psstrmFinal, gid16 chwLB, int nDirDepth,
+ int islotMin, int cslot)
+{
+ int paraDirLevel = (ptman->State()->ParaRightToLeft()) ? 1 : 0;
+
+ m_cginf = 0;
+ int islot;
+ for (islot = islotMin; islot < cslot; islot++)
+ {
+ if (psstrmFinal->SlotAt(islot)->GlyphID() != chwLB)
+ m_cginf++;
+ }
+
+ // For right-to-left segments, the draw origin will be at the left side of the visible
+ // portion of the text. So if necessary, scoot everything left so that the invisible
+ // trailing white-space is to the left of the draw position.
+ Assert(m_dxsTotalWidth > -1);
+ Assert(m_dxsVisibleWidth > -1);
+ float dxsInvisible = (m_fEndLine) ? m_dxsTotalWidth - m_dxsVisibleWidth : 0;
+
+ m_prgginf = new GlyphInfo [m_cginf];
+
+ // Fill in glyph information structures.
+ m_isloutGinf0 = -1;
+ for (islot = islotMin; islot < cslot; islot++)
+ {
+ GrSlotState * pslot = psstrmFinal->SlotAt(islot);
+
+ int islout = islot - islotMin;
+ if (pslot->GlyphID() == chwLB)
+ {
+ continue; // skip over linebreak markers
+ }
+ if (m_isloutGinf0 == -1)
+ m_isloutGinf0 = islout;
+
+ GrSlotOutput * pslout = OutputSlot(islout);
+
+ int iginf = islout - m_isloutGinf0;
+ GlyphInfo & ginf = m_prgginf[iginf];
+
+ ginf.glyphID = pslot->ActualGlyphForOutput(ptman);
+ ginf.pseudoGlyphID = pslot->GlyphID();
+ if (ginf.glyphID == ginf.pseudoGlyphID)
+ ginf.pseudoGlyphID = 0;
+
+ ginf.isSpace = pslot->IsSpace(ptman);
+
+ ginf.origin = pslot->XPosition();
+ ginf.yOffset = pslot->YPosition();
+
+ ginf.bbLeft = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbLeft);
+ ginf.bbTop = pslot->YPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbTop);
+ if (ginf.isSpace)
+ {
+ ginf.bbRight = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetAdvWidth);
+ }
+ else
+ {
+ ginf.bbRight = pslot->XPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbRight);
+ }
+ ginf.bbBottom = pslot->YPosition() + pslot->GlyphMetricLogUnits(ptman, kgmetBbBottom);
+
+ ginf.advanceWidth = pslot->GlyphMetricLogUnits(ptman, kgmetAdvWidth);
+ ginf.advanceHeight = 0;
+
+ if (pslot->AttachTo() == 0) // not attached
+ ginf.attachedTo = -1;
+ else
+ ginf.attachedTo = pslot->AttachTo() + islot;
+
+ ginf.directionality = byte(pslot->Directionality());
+ if (pslot->DirLevel() == -1)
+ ginf.directionLevel = paraDirLevel;
+ else
+ ginf.directionLevel = byte(pslot->DirLevel());
+
+ //ginf.firstChar = LogicalSurfaceToUnderlying(islout, true);
+ //ginf.lastChar = LogicalSurfaceToUnderlying(islout, false);
+
+ if (pslot->HasComponents())
+ {
+ SetUpLigInfo(ptman, ginf, pslout);
+ }
+ else
+ {
+ ginf.numberOfComponents = 0;
+ ginf.components = NULL;
+ }
+
+ ginf.insertBefore = pslot->InsertBefore();
+
+ ginf.maxStretch[0] = ptman->EmToLogUnits(pslot->JStretch());
+ ginf.maxShrink[0] = ptman->EmToLogUnits(pslot->JShrink());
+ ginf.stretchStep[0]= ptman->EmToLogUnits(pslot->JStep());
+ ginf.justWidth[0] = ptman->EmToLogUnits(pslot->JWidth());
+ ginf.justWeight[0] = pslot->JWeight();
+
+ ginf.measureStartOfLine = pslout->MeasureSolLogUnits();
+ ginf.measureEndOfLine = pslout->MeasureEolLogUnits();
+ }
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ Set up the data structures that represent the components of a ligature glyph.
+----------------------------------------------------------------------------------------------*/
+/*
+void Segment::SetUpLigInfo(GrTableManager * ptman, GlyphInfo & ginf, GrSlotOutput * pslout)
+{
+ GrGlyphTable * pgtbl = ptman->GlyphTable();
+
+ int ccomp = pslout->NumberOfComponents();
+ ginf.numberOfComponents = ccomp;
+ ginf.components = new ComponentBox[ccomp];
+ for (int icomp = 0; icomp < ccomp; icomp++)
+ {
+ ComponentBox & cb = ginf.components[icomp];
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ float xsLeft, xsRight, ysTop, ysBottom;
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ pgtbl->ComponentBoxLogUnits(m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_mFontEmUnits, m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom, false);
+
+ cb.firstChar = pslout->UnderlyingComponent(icomp);
+ cb.lastChar = cb.firstChar; // TODO: is this supported?
+ cb.left = xsLeft;
+ cb.right = xsRight;
+ cb.top = ysTop;
+ cb.bottom = ysBottom;
+ }
+}
+*/
+
+
+// --------- OBSOLETE - replaced by GrTableManager::AdjustAssocsForOverlaps() ---------------
+#if 0
+
+/*----------------------------------------------------------------------------------------------
+ Now that this segment is finished and has its associations set, handle any overlaps in
+ the associations between the previous segment and this one.
+
+ Review: Think about whether we need to distinguish between before==kPosInfinity meaning
+ that the glyph is in the next segment vs. there is no association at all.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void Segment::AdjustForOverlapsWithPrevSeg()
+{
+ if (m_psegPrev)
+ {
+ AdjustBeforeArrayFromPrevSeg();
+ m_psegPrev->AdjustAfterArrayFromNextSeg();
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ For any characters that are officially in this segment but are rendered in
+ the previous segment, initialize this segment's before array appropriately. Specifically,
+ set this segment's before value to something invalid--negative infinity, which will
+ never be overwritten.
+ OBSOLETE - replaced by AdjustAfterArrayFromNextSeg
+----------------------------------------------------------------------------------------------*/
+void Segment::InitBeforeArrayFromPrevSeg()
+{
+ Assert(m_psegPrev);
+
+ int ichwPrevMin = m_psegPrev->m_ichwMin;
+ int ichwPrevLim = m_psegPrev->m_ichwLim;
+// int ichwPrevContextLim =
+// m_psegPrev->m_ichwAssocsLim - m_psegPrev->m_ichwAssocsMin + m_psegPrev->m_ichwMin;
+ int cchwPrevAssocsMin = m_psegPrev->m_ichwAssocsMin;
+ int cchwPrevAssocsLim = m_psegPrev->m_ichwAssocsLim;
+
+ // Loop over associations appended to the end of the previous segment;
+ // ichwPrev and ichwThis are relative to the start of their respective segments.
+ for (int ichwPrev = ichwPrevLim - ichwPrevMin; ichwPrev < cchwPrevAssocsLim; ++ichwPrev)
+ {
+ int ichwThis = ichwPrev - (ichwPrevLim - ichwPrevMin); // relative to start of this seg
+ if (m_psegPrev->m_prgisloutBefore[ichwPrev - cchwPrevAssocsMin] < kPosInfinity)
+ // The "before" value is in the previous segment, so make this segment's
+ // before value invalid.
+ m_prgisloutBefore[ichwThis - m_ichwAssocsMin] = kNegInfinity;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ For any associations that overlap between the previous segment and this, adjust
+ this segment's before array appropriately. Specifically, for any characters that
+ are rendered in both, set this segment's before value to something invalid.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void Segment::AdjustBeforeArrayFromPrevSeg()
+{
+ Assert(m_psegPrev);
+
+ int ichwPrevMin = m_psegPrev->m_ichwMin;
+ int ichwPrevLim = m_psegPrev->m_ichwLim;
+ int ichwPrevAssocsMin = m_psegPrev->m_ichwAssocsMin;
+ int ichwPrevAssocsLim = m_psegPrev->m_ichwAssocsLim;
+
+ // Loop over associations appended to the end of the previous segment
+ // (ie, rendered in the previous segment but officially in this one);
+ // ichwPrev and ichwThis are relative to the start of their respective segments.
+ for (int ichwPrev = ichwPrevLim - ichwPrevMin; ichwPrev < ichwPrevAssocsLim; ++ichwPrev)
+ {
+ int ichwThis = ichwPrev - (ichwPrevLim - ichwPrevMin); // relative to start of this seg
+ if (m_psegPrev->m_prgisloutBefore[ichwPrev - ichwPrevAssocsMin] < kPosInfinity)
+ // The "before" value is in the previous segment, so make this segment's
+ // before value invalid.
+ m_prgisloutBefore[ichwThis - m_ichwAssocsMin] = kNegInfinity;
+ }
+ // Loop over associations prepended to the start of this segment
+ // (ie, rendered in this segment but officially in the previous one);
+ // ichwPrev and ichwThis are relative to the start of their respective segments.
+ for (int ichwThis = m_ichwAssocsMin; ichwThis < 0; ++ichwThis)
+ {
+ int ichwPrev = ichwThis + (ichwPrevLim - ichwPrevMin);
+ if (m_psegPrev->m_prgisloutBefore[ichwPrev - ichwPrevAssocsMin] < kPosInfinity)
+ // The "before" value is in the previous segment, so make this segment's
+ // before value invalid.
+ m_prgisloutBefore[ichwThis - m_ichwAssocsMin] = kNegInfinity;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ For any associations that overlap between this segment and the next, adjust
+ this segment's after array appropriately. Specifically, for any characters that
+ are rendered in both, set this segment's after value to something invalid.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void Segment::AdjustAfterArrayFromNextSeg()
+{
+ Assert(m_psegNext);
+
+ int ichwNextMin = m_psegNext->m_ichwMin;
+ int ichwNextContextMin = ichwNextMin + m_psegNext->m_ichwAssocsMin;
+ int ichwNextAssocsMin = m_psegNext->m_ichwAssocsMin;
+
+ // Loop over associations prepended to the beginning of the following segment
+ // (ie, rendered in the next segment but officially in this one);
+ // ichwThis and ichwNext are relative to the start of their respective segments.
+ for (int ichwNext = cchwNextAssocsMin; ichwNext < 0; ++ichwNext)
+ {
+ int ichwThis = ichwNext + (m_ichwLim - m_ichwMin);
+ if (m_psegNext->m_prgisloutAfter[ichwNext - ichwNextAssocsMin] > kNegInfinity)
+ // The "after" value is in the next segment, so make this segment's
+ // after value invalid.
+ m_prgisloutAfter[ichwThis - m_ichwAssocsMin] = kPosInfinity;
+ }
+
+ // Loop over associations appended to the end of this segment
+ // (ie, rendered in this segment but officially in the next one);
+ // ichwThis and ichwNext are relative to the start of their respective segments.
+ for (int ichwThis = m_ichwLim - m_ichwMin; ichwThis < m_cchwAssocsLim; ++ichwThis)
+ {
+ int ichwNext = ichwThis - (m_ichwLim - m_ichwMin);
+ if (m_psegNext->m_prgisloutAfter[ichwNext - ichwNextAssocsMin] > kNegInfinity)
+ // The "after" value is in the next segment, so make this segment's
+ // after value invalid.
+ m_prgisloutAfter[ichwThis - m_ichwAssocsMin] = kPosInfinity;
+ }
+}
+
+#endif // -------------------------- END OF OBSOLETE CODE ----------------------------------
+
+
+/*----------------------------------------------------------------------------------------------
+ Generate a list of all the glyphs that are attached to the base with the given index.
+ Note that we want to generate glyph indices, not slot indices.
+
+ @param disloutCluster - indicates how far on either side of the base to look.
+----------------------------------------------------------------------------------------------*/
+void Segment::ClusterMembersForGlyph(int isloutBase, int disloutCluster,
+ std::vector<int> & visloutRet)
+{
+ for (int islout = max(0, isloutBase - disloutCluster);
+ islout < min(m_cslout, isloutBase + disloutCluster + 1);
+ islout++)
+ {
+ if (islout == isloutBase)
+ continue; // don't include the base itself
+ GrSlotOutput * pslout = m_prgslout + islout;
+ if (pslout->ClusterBase() == isloutBase)
+ {
+ visloutRet.push_back(islout);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record an underlying-to-surface association mapping, based on the fact that there is
+ a corresponding surface-to-underlying association in the streams.
+
+ @param ichwUnder - character index relative to the official beginning of the segment
+ @param islotSurface - surface glyph it maps to
+----------------------------------------------------------------------------------------------*/
+void Segment::RecordSurfaceAssoc(int ichwUnder, int islotSurface, int nDir)
+{
+ // If we are recording an association across the line boundary, make sure there
+ // is space for it.
+ EnsureSpaceAtLineBoundaries(ichwUnder);
+
+ // For left-to-right chars, the before-value is the minimum of the previous
+ // and new values, and the after-value is the maximum.
+ if (nDir % 2 == 0)
+ {
+ // left-to-right
+ m_prgisloutBefore[ichwUnder - m_ichwAssocsMin] =
+ min(m_prgisloutBefore[ichwUnder - m_ichwAssocsMin], islotSurface);
+ m_prgisloutAfter[ ichwUnder - m_ichwAssocsMin] =
+ max(m_prgisloutAfter[ ichwUnder - m_ichwAssocsMin], islotSurface);
+ }
+ else
+ {
+ // right-to-left: the before-value is the max and the after-value is the min
+ m_prgisloutBefore[ichwUnder - m_ichwAssocsMin] =
+ max(m_prgisloutBefore[ichwUnder - m_ichwAssocsMin], islotSurface);
+ m_prgisloutAfter[ ichwUnder - m_ichwAssocsMin] =
+ min(m_prgisloutAfter[ ichwUnder - m_ichwAssocsMin], islotSurface);
+ }
+
+ m_prgpvisloutAssocs[ichwUnder - m_ichwAssocsMin]->push_back(islotSurface);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record an underlying-to-surface ligature mapping, based on the fact that there is
+ a component.ref attribute in the surface stream. Note that if there was a previous
+ ligature value there, it will be overwritten.
+
+ @param ichwUnder - character index relative to the official beginning of the segment
+ @param islotSurface - surface glyph it maps to
+ @param iComponent - which component this glyph represents
+----------------------------------------------------------------------------------------------*/
+void Segment::RecordLigature(int ichwUnder, int islotSurface, int iComponent)
+{
+ // If we are recording a mapping across the line boundary, make sure there
+ // is space for it.
+ EnsureSpaceAtLineBoundaries(ichwUnder);
+
+ Assert(m_prgisloutLigature[ichwUnder - m_ichwAssocsMin] == kNegInfinity);
+
+ m_prgisloutLigature[ichwUnder - m_ichwAssocsMin] = islotSurface;
+ Assert(iComponent < kMaxComponentsPerGlyph);
+ m_prgiComponent[ ichwUnder - m_ichwAssocsMin] = sdata8(iComponent);
+}
+
+/*----------------------------------------------------------------------------------------------
+ The given slot is one that is rendered in the previous segment.
+ If it is associated with a character officially in this segment, mark the
+ before-association kNegInfinity.
+
+ @param ichwUnder - character index relative to the official beginning of the segment
+ @param islot - processed glyph it maps to
+----------------------------------------------------------------------------------------------*/
+void Segment::MarkSlotInPrevSeg(int ichwUnder, int islot)
+{
+ if (ichwUnder >= m_ichwAssocsMin)
+ m_prgisloutBefore[ichwUnder - m_ichwAssocsMin] = kNegInfinity;
+}
+
+/*----------------------------------------------------------------------------------------------
+ The given slot is one that is rendered in the following segment.
+ If it is associated with a character officially in this segment, mark the
+ after-association kPosInfinity.
+
+ @param ichwUnder - character index relative to the official beginning of the segment
+ @param islot - processed glyph it maps to
+----------------------------------------------------------------------------------------------*/
+void Segment::MarkSlotInNextSeg(int ichwUnder, int islot)
+{
+ if (ichwUnder < m_ichwAssocsLim)
+ m_prgisloutAfter[ichwUnder - m_ichwAssocsMin] = kPosInfinity;
+}
+
+/*----------------------------------------------------------------------------------------------
+ If we are recording an association across the line boundary (in either direction),
+ make sure there is space for it. This involves adding space to the beginning or
+ the end of the association arrays, and adjusting the min and lim indicators.
+----------------------------------------------------------------------------------------------*/
+void Segment::EnsureSpaceAtLineBoundaries(int ichwUnder)
+{
+ int cchwNewMin = min(ichwUnder, m_ichwAssocsMin);
+ int cchwNewLim = max(ichwUnder+1, m_ichwAssocsLim);
+ if (cchwNewMin < m_ichwAssocsMin || cchwNewLim > m_ichwAssocsLim)
+ {
+ // Make space either at the beginning or the end of the arrays.
+ int cchwPreAdd = m_ichwAssocsMin - cchwNewMin;
+ int cchwPostAdd = cchwNewLim - m_ichwAssocsLim;
+
+ int * prgisloutTmp = m_prgisloutBefore;
+ m_prgisloutBefore = new int[cchwNewLim - cchwNewMin];
+ std::copy(prgisloutTmp, prgisloutTmp + (m_ichwAssocsLim - m_ichwAssocsMin),
+ m_prgisloutBefore + cchwPreAdd);
+ delete[] prgisloutTmp;
+
+ prgisloutTmp = m_prgisloutAfter;
+ m_prgisloutAfter = new int[cchwNewLim - cchwNewMin];
+ std::copy(prgisloutTmp, prgisloutTmp + (m_ichwAssocsLim - m_ichwAssocsMin),
+ m_prgisloutAfter + cchwPreAdd);
+ delete[] prgisloutTmp;
+
+ std::vector<int> ** ppvisloutTmp = m_prgpvisloutAssocs;
+ m_prgpvisloutAssocs = new std::vector<int> * [cchwNewLim - cchwNewMin];
+ std::swap_ranges(m_prgpvisloutAssocs + cchwPreAdd,
+ m_prgpvisloutAssocs + cchwPreAdd +
+ (m_ichwAssocsLim - m_ichwAssocsMin), ppvisloutTmp);
+ delete[] ppvisloutTmp;
+
+ prgisloutTmp = m_prgisloutLigature;
+ m_prgisloutLigature = new int[cchwNewLim - cchwNewMin];
+ std::copy(prgisloutTmp, prgisloutTmp + (m_ichwAssocsLim - m_ichwAssocsMin),
+ m_prgisloutLigature + cchwPreAdd);
+ delete[] prgisloutTmp;
+
+ sdata8 * prgiCompTmp = m_prgiComponent;
+ m_prgiComponent = new sdata8[cchwNewLim - cchwNewMin];
+ std::copy(prgiCompTmp, prgiCompTmp + (m_ichwAssocsLim - m_ichwAssocsMin),
+ m_prgiComponent + cchwPreAdd);
+ delete[] prgiCompTmp;
+
+ // Initialize new slots.
+ int i;
+ for (i = 0; i < cchwPreAdd; ++i)
+ {
+ m_prgisloutBefore[i] = kPosInfinity;
+ m_prgisloutAfter[i] = kNegInfinity;
+ m_prgpvisloutAssocs[i] = new std::vector<int>;
+ m_prgisloutLigature[i] = kNegInfinity;
+ m_prgiComponent[i] = 0;
+ }
+ for (i = m_ichwAssocsLim - m_ichwAssocsMin + cchwPreAdd;
+ i < m_ichwAssocsLim - m_ichwAssocsMin + cchwPreAdd + cchwPostAdd;
+ ++i)
+ {
+ m_prgisloutBefore[i] = kPosInfinity;
+ m_prgisloutAfter[i] = kNegInfinity;
+ m_prgpvisloutAssocs[i] = new std::vector<int>;
+ m_prgisloutLigature[i] = kNegInfinity;
+ m_prgiComponent[i] = 0;
+ }
+ m_ichwAssocsMin = cchwNewMin;
+ m_ichwAssocsLim = cchwNewLim;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the given output slot.
+----------------------------------------------------------------------------------------------*/
+GrSlotOutput * Segment::OutputSlot(int islout)
+{
+ return m_prgslout + islout;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the rendering engine to the current one.
+----------------------------------------------------------------------------------------------*/
+void Segment::SetEngine(GrEngine * pgreng)
+{
+ //if (m_preneng)
+ // m_preneng->DecRefCount();
+ m_preneng = pgreng;
+ //if (m_preneng)
+ // m_preneng->IncRefCount();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the font.
+----------------------------------------------------------------------------------------------*/
+void Segment::SetFont(Font * pfont)
+{
+ m_pfont = pfont->copyThis();
+
+// m_fBold = pfont->bold();
+// m_fItalic = pfont->italic();
+ // Note that we store the character height (which does not include the internal leading),
+ // not the actual font height, ie, ascent + descent. This is what is used in the LOGFONT.
+ pfont->getFontMetrics(NULL, NULL, &m_xysEmSquare); // m_xysEmSquare = m_pixHeight
+}
+
+/*----------------------------------------------------------------------------------------------
+ Switch the font out.
+ ??? Do we need to change the member variables too?
+----------------------------------------------------------------------------------------------*/
+void Segment::SwitchFont(Font * pfont)
+{
+ m_pfont = pfont;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the engine implementation if it is a proper GrEngine, or NULL otherwise.
+----------------------------------------------------------------------------------------------*/
+GrEngine * Segment::EngineImpl()
+{
+ return m_preneng;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the justification agent, in case this segment will ever need to be stretched
+ or shrunk.
+----------------------------------------------------------------------------------------------*/
+void Segment::SetJustifier(IGrJustifier * pgjus)
+{
+ m_pgjus = pgjus;
+ //if (pgjus)
+ // pgjus->JustifierObject(&m_pgjus);
+ //else
+ // m_pgjus = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the graphics object to use the base font.
+----------------------------------------------------------------------------------------------*/
+//void Segment::SetToBaseFont(IGrGraphics * pgg)
+//{
+// if (m_fUseSepBase)
+// EngineImpl()->SwitchGraphicsFont(pgg, true);
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Restore the graphics object to use the font that it originally had when passed in to
+ the interface method.
+----------------------------------------------------------------------------------------------*/
+//void Segment::RestoreFont(IGrGraphics * pgg)
+//{
+// if (m_fUseSepBase)
+// EngineImpl()->SwitchGraphicsFont(pgg, false);
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Given a logical surface location, return the underlying position (relative to the
+ beginning of the string). NOTE that we are returning the index of the closest charater
+ (plus an indication of which side the click was on), not a position between characters.
+
+ @param islout - output slot
+ @param xsOffset - x coordinate of physical click, relative to left of glyph;
+ kPosInfinity means all the way to the right;
+ kNegInfinity means all the way to the left
+ @param ysOffset - y coordinate of physical click, relative to TOP of segment (NOT
+ upwards from baseline); kPosInfinity means all the way at
+ the top; kNegInfinity means all the way at the bottom
+ @param dxsGlyphWidth - width of glyph clicked on, or 0 if irrelevant
+ @param dysGlyphHeight - actually line height -- CURRENTLY NOT USED
+ @param pfAfter - return true if they clicked on trailing side; possibly NULL
+----------------------------------------------------------------------------------------------*/
+int Segment::LogicalSurfaceToUnderlying(int islout, float xsOffset, float ysClick,
+ float dxsGlyphWidth, float dysGlyphHeight, bool * pfAfter)
+{
+ Assert(islout >= 0);
+ Assert(islout < m_cslout);
+
+ GrSlotOutput * pslout = OutputSlot(islout);
+ bool fGlyphRtl = SlotIsRightToLeft(pslout);
+
+ int dichw;
+ bool fAfter, fRight;
+
+ float ysForGlyph = pslout->YPosition();
+
+ float dysFontAscent = m_dysFontAscent;
+ ////GrResult res = GetFontAscentSourceUnits(pgg, &dysFontAscent);
+ ////if (ResultFailed(res))
+ //// THROW(WARN(res));
+ dysFontAscent += m_dysXAscent;
+
+ float dysOffset = ysClick - (m_dysAscent - dysFontAscent); // relative to top of 0-baseline text
+
+ // If the slot has components, see if the offset falls within one of them.
+
+ if (pslout->NumberOfComponents() > 0)
+ {
+ GrEngine * pgreng = EngineImpl();
+ if (!pgreng)
+ goto LNotLigature;
+
+ GrGlyphTable * pgtbl = pgreng->GlyphTable();
+
+ for (int icomp = 0; icomp < pslout->NumberOfComponents(); icomp++)
+ {
+ float xsLeft, xsRight, ysTop, ysBottom;
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ if (!pgtbl->ComponentBoxLogUnits(m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_mFontEmUnits, m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom))
+ {
+ continue; // component not defined
+ }
+ Assert(xsLeft <= xsRight);
+ Assert(ysTop <= ysBottom);
+ if (xsOffset < xsLeft || xsOffset > xsRight)
+ continue;
+ if ((dysOffset - ysForGlyph) < ysTop || (dysOffset - ysForGlyph) > ysBottom)
+ continue;
+
+ // Click was within the component's box.
+
+ fRight = (xsOffset - xsLeft > xsRight - xsOffset);
+ fAfter = (fGlyphRtl) ? !fRight : fRight;
+ if (pfAfter)
+ *pfAfter = fAfter;
+
+ if (fAfter)
+ dichw = pslout->LastUnderlyingComponent(icomp);
+ else
+ dichw = pslout->FirstUnderlyingComponent(icomp);
+ Assert(m_ichwMin + dichw >= 0);
+ Assert(dichw < m_dichwLim);
+
+ Assert(GrCharStream::AtUnicodeCharBoundary(m_pgts, m_ichwMin + dichw));
+
+ return m_ichwMin + dichw;
+ }
+ }
+
+LNotLigature:
+
+ // No relevant ligature component.
+ // If the x-offset is less than half way across,
+ // answer the before-association; otherwise answer the after-association.
+
+ if (xsOffset == kPosInfinity)
+ fRight = true;
+ else if (xsOffset == kNegInfinity)
+ fRight = false;
+ else
+ fRight = (xsOffset > (dxsGlyphWidth / 2));
+
+ fAfter = (fGlyphRtl) ? !fRight : fRight;
+
+ int diCharAdj = 0;
+ if (fAfter)
+ {
+ dichw = pslout->AfterAssoc();
+ if (pfAfter)
+ *pfAfter = true;
+ // The following should not be necessary because of the way associations are set up:
+ //while (!GrCharStream::AtUnicodeCharBoundary(m_pgts, ichwBase + dichw + diCharAdj))
+ // diCharAdj++;
+ }
+ else
+ {
+ dichw = pslout->BeforeAssoc();
+ if (pfAfter)
+ *pfAfter = false;
+ // The following should not be necessary because of the way associations are set up:
+ //while (!GrCharStream::AtUnicodeCharBoundary(m_pgts, ichwBase + dichw + diCharAdj))
+ // diCharAdj--;
+ }
+
+ if (dichw == kNegInfinity || dichw == kPosInfinity)
+ return dichw;
+
+ // This should be true because of the way the associations are set up:
+ Assert(GrCharStream::AtUnicodeCharBoundary(m_pgts, m_ichwMin + dichw)); // + diCharAdj));
+
+ return m_ichwMin + dichw + diCharAdj;
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int Segment::LogicalSurfaceToUnderlying(int islout, bool fBefore)
+{
+ if (fBefore)
+ return LogicalSurfaceToUnderlying(islout, kNegInfFloat, kNegInfFloat);
+ else
+ return LogicalSurfaceToUnderlying(islout, kPosInfFloat, kPosInfFloat);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given a physical surface location (an index into the glyph boxes),
+ return the underlying position, relative to the beginning of the string.
+
+ @param igbb - index of glyph
+ @param xsOffset - relative to left side of glyph
+ @param ysOffset - downwards from top of segment (not upwards from baseline)
+----------------------------------------------------------------------------------------------*/
+int Segment::PhysicalSurfaceToUnderlying(
+ int iginf, float xsOffset, float ysOffset,
+ float dxsGlyphWidth, float dysGlyphHeight, bool * pfAfter)
+{
+ int islout = iginf + m_isloutGinf0;
+ return LogicalSurfaceToUnderlying(islout, xsOffset, ysOffset,
+ dxsGlyphWidth, dysGlyphHeight, pfAfter);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+int Segment::PhysicalSurfaceToUnderlying(int iginf, bool fBefore)
+{
+ int islout = iginf + m_isloutGinf0;
+ bool fGlyphRtl = SlotIsRightToLeft(OutputSlot(islout));
+ if (fBefore == fGlyphRtl)
+ return PhysicalSurfaceToUnderlying(iginf, kPosInfFloat, kPosInfFloat);
+ else
+ return PhysicalSurfaceToUnderlying(iginf, kNegInfFloat, kNegInfFloat);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given an underlying position (relative to the beginning of the string),
+ return the logical surface location (ignoring right-to-left).
+ NOTE that ichw indicates a CHARACTER, not a location between characters. So ichw = 3,
+ fBefore = false indicates a selection between characters 3 and 4.
+ For surrogates, it indicates the FIRST of the pair of 16-bit chars.
+----------------------------------------------------------------------------------------------*/
+int Segment::UnderlyingToLogicalSurface(int ichw, bool fBefore)
+{
+ int ichwSegOffset = ichw - m_ichwMin;
+
+ if (ichwSegOffset < m_ichwAssocsMin)
+ return kNegInfinity; // probably rendered in previous segment
+
+
+ // if the buffers aren't even allocated, then it probably means there
+ // wasn't room for any glyphs, so the following segment is most likely
+// else if (ichwSegOffset >= m_ichwAssocsLim)
+ else if (ichwSegOffset >= m_ichwAssocsLim || !m_prgisloutBefore || !m_prgisloutAfter)
+ return kPosInfinity; // probably rendered in following segment
+
+ else if (fBefore)
+ {
+ int isloutRet;
+ int ichw = ichwSegOffset;
+ // If no association has been made, loop forward to the next slot
+ // we are before. As a last resort, answer kPosInfinity, meaning we
+ // aren't before anything.
+ do
+ {
+ isloutRet = m_prgisloutBefore[ichw - m_ichwAssocsMin];
+ do { ++ichw; }
+ while (!GrCharStream::AtUnicodeCharBoundary(m_pgts, ichw));
+ } while (isloutRet == kPosInfinity && ichw < m_ichwAssocsLim);
+ return isloutRet;
+ }
+ else
+ {
+ int isloutRet;
+ int ichw = ichwSegOffset;
+ // If no association has been made, loop backward to the previous slot
+ // we are after. As a last resort, answer kNegInfinity, meaning we
+ // aren't after anything.
+ do
+ {
+ isloutRet = m_prgisloutAfter[ichw - m_ichwAssocsMin];
+ do { --ichw; }
+ while (!GrCharStream::AtUnicodeCharBoundary(m_pgts, ichw));
+ } while (isloutRet == kNegInfinity && ichw >= 0);
+ return isloutRet;
+ }
+ Assert(false); // should never reach here
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given an underlying position (relative to the beginning of the string),
+ return the physical surface location, the index into m_prgginf.
+----------------------------------------------------------------------------------------------*/
+int Segment::UnderlyingToPhysicalSurface(int ichw, bool fBefore)
+{
+ int islout = UnderlyingToLogicalSurface(ichw, fBefore);
+ return LogicalToPhysicalSurface(islout);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given a logical position (index into output slots), return the physical position,
+ the index into the list of glyphs (m_prgginf).
+----------------------------------------------------------------------------------------------*/
+int Segment::LogicalToPhysicalSurface(int islout)
+{
+ if (islout == kNegInfinity || islout == kPosInfinity)
+ return islout;
+
+ Assert(m_prgginf[islout - m_isloutGinf0].logicalIndex() == (unsigned)(islout - m_isloutGinf0));
+
+ return islout - m_isloutGinf0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given an underlying position (relative to the beginning of the string),
+ return the physical surface locations of all the associated surface glyphs.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+#if 0
+void Segment::UnderlyingToPhysicalAssocs(int ichw, std::vector<int> & viginf)
+{
+ int ichwSegOffset = ichw - m_ichwMin;
+
+ if (ichwSegOffset < m_ichwAssocsMin)
+ return; // possibly rendered in previous segment
+
+ else if (ichwSegOffset >= m_ichwAssocsLim)
+ return; // possibly rendered in following segment
+
+ else
+ {
+ std::vector<int> * pvisloutTmp = &(m_prgvisloutAssocs[ichwSegOffset - m_ichwAssocsMin]);
+
+ for (size_t i = 0; i < pvisloutTmp->size(); i++)
+ {
+ int islout = (*pvisloutTmp)[i];
+ Assert(islout != kNegInfinity);
+ Assert(islout != kPosInfinity);
+ viginf.push_back(LogicalToPhysicalSurface(islout));
+ }
+ }
+}
+#endif
+
+/*----------------------------------------------------------------------------------------------
+ Given an underlying character position (relative to the beginning of the string),
+ return a pointer to the vector containing the logical surface locations of
+ all the associated surface glyphs.
+
+ Returns an empty vector (not something containing infinities) if the character is
+ "invisible."
+----------------------------------------------------------------------------------------------*/
+std::vector<int> Segment::UnderlyingToLogicalAssocs(int ichw)
+{
+ std::vector<int> vnEmpty;
+ vnEmpty.clear();
+ Assert(vnEmpty.size() == 0);
+
+ int ichwSegOffset = ichw - m_ichwMin;
+
+ if (ichwSegOffset < m_ichwAssocsMin)
+ return vnEmpty; // probably rendered in previous segment
+
+ else if (ichwSegOffset >= m_ichwAssocsLim)
+ return vnEmpty; // probably rendered in following segment
+
+ else if (m_prgpvisloutAssocs[ichwSegOffset - m_ichwAssocsMin] == NULL)
+ {
+ // Create a vector using the before and after values.
+ std::vector<int> visloutRet;
+ int isloutBefore = m_prgisloutBefore[ichwSegOffset - m_ichwAssocsMin];
+ int isloutAfter = m_prgisloutAfter[ichwSegOffset - m_ichwAssocsMin];
+ if (isloutBefore != kPosInfinity && isloutBefore != kNegInfinity)
+ visloutRet.push_back(isloutBefore);
+ if (isloutAfter != kPosInfinity && isloutAfter != kNegInfinity && isloutBefore != isloutAfter)
+ {
+ visloutRet.push_back(isloutAfter);
+ }
+ return visloutRet;
+ }
+ else
+ {
+ std::vector<int> * pvisloutRet = m_prgpvisloutAssocs[ichwSegOffset - m_ichwAssocsMin];
+ return *pvisloutRet;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Given an underlying character position (relative to the beginning of the string),
+ return an index of a slot in this segment that can used to test things like
+ InsertBefore. Don't return kNegInfinity or kPosInfinity except as a last resort.
+----------------------------------------------------------------------------------------------*/
+int Segment::UnderlyingToLogicalInThisSeg(int ichw)
+{
+ int isloutTest = kNegInfinity;
+ std::vector<int> vislout = UnderlyingToLogicalAssocs(ichw);
+ for (size_t iislout = 0; iislout < vislout.size(); iislout++)
+ {
+ isloutTest = vislout[iislout];
+ if (isloutTest != kNegInfinity && isloutTest != kPosInfinity)
+ return isloutTest;
+ }
+ return isloutTest;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return true if the two characters map to exactly the same set of glyphs.
+----------------------------------------------------------------------------------------------*/
+bool Segment::SameSurfaceGlyphs(int ichw1, int ichw2)
+{
+ std::vector<int> vislout1 = UnderlyingToLogicalAssocs(ichw1);
+ std::vector<int> vislout2 = UnderlyingToLogicalAssocs(ichw2);
+
+ bool fRet = true;
+ if (vislout1.size() == 0 || vislout2.size() == 0)
+ fRet = false;
+ else if (vislout1.size() != vislout2.size())
+ fRet = false;
+ else
+ {
+ for (size_t islout = 0; islout < vislout1.size(); islout++)
+ {
+ if (vislout1[islout] != vislout2[islout])
+ {
+ fRet = false;
+ break;
+ }
+ }
+ }
+ return fRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the direction level of the given character.
+----------------------------------------------------------------------------------------------*/
+int Segment::DirLevelOfChar(int ichw, bool fBefore)
+{
+ if (m_twsh == ktwshOnlyWs)
+ return m_nDirDepth;
+ int islot = UnderlyingToLogicalSurface(ichw, fBefore);
+ if (islot == kNegInfinity || islot == kPosInfinity)
+ return 0;
+ int nDir = OutputSlot(islot)->DirLevel();
+ if (nDir == -1)
+ // Not calculated: assume to be the top direction level.
+ nDir = TopDirLevel();
+
+ return nDir;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return whether the given character is right-to-left.
+----------------------------------------------------------------------------------------------*/
+int Segment::CharIsRightToLeft(int ichw, bool fBefore)
+{
+ int nDir = DirLevelOfChar(ichw, fBefore);
+ return ((nDir % 2) != 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return whether the given slot is right-to-left.
+----------------------------------------------------------------------------------------------*/
+int Segment::SlotIsRightToLeft(GrSlotOutput * pslout)
+{
+ if (m_twsh == ktwshOnlyWs)
+ return (m_nDirDepth % 2);
+ int nDir = pslout->DirLevel();
+ if (nDir == -1)
+ nDir = TopDirLevel();
+ return (nDir % 2);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check to make sure that the attachments are valid. Specifically, for every glyph that
+ is part of a cluster, all glyphs between that glyph and its root must (ultimately) have
+ that root glyph as one of its roots.
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+void Segment::AssertValidClusters(GrSlotStream * psstrm)
+{
+#ifdef _DEBUG
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslotThis = psstrm->SlotAt(islot);
+ GrSlotState * pslotRoot = pslotThis->AttachRoot(psstrm);
+ if (!pslotRoot)
+ continue;
+ Assert(pslotRoot != pslotThis);
+
+ int inc = (pslotThis->PosPassIndex() > pslotRoot->PosPassIndex()) ? -1 : 1;
+
+ for (int islot2 = pslotThis->PosPassIndex() + inc;
+ islot2 != pslotRoot->PosPassIndex();
+ islot2 += inc)
+ {
+ GrSlotState * pslotMid = psstrm->SlotAt(islot2);
+ Assert(pslotMid->HasAsRoot(psstrm, pslotRoot));
+ }
+ }
+#endif // _DEBUG
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return information about (editing) clusters as appropriate for Uniscribe, ie, consistent
+ with the ScriptShape funciton.
+ A cluster includes all attachments, all clumps of characters created by insert = false,
+ and clumps of reordered glyphs.
+
+ prgiginfFirstOfCluster returns the first glyph of the cluster for each CHARACTER
+ (glyph indices returned are zero-based and refer to physical order--left-to-right, etc.).
+ pfClusterStart returns a flag for each GLYPH indicating whether it is the first (left-most)
+ of a cluster.
+ Both arrays are optional.
+ CORRECTION: for now we use strictly logical order. It's not clear whether physical
+ order is needed for right-to-left text or not. See note below.
+
+ TODO: convert from GlyphInfo objects which are RTL.
+----------------------------------------------------------------------------------------------*/
+GrResult Segment::getUniscribeClusters(
+ int * prgiginfFirstOfCluster, int cchMax, int * pcch,
+ bool * pfClusterStart, int cfMax, int * pcf)
+{
+ ChkGrOutPtr(pcch);
+ if (prgiginfFirstOfCluster)
+ ChkGrArrayArg(prgiginfFirstOfCluster, cchMax);
+ ChkGrOutPtr(pcf);
+ if (pfClusterStart)
+ ChkGrArrayArg(pfClusterStart, cfMax);
+
+ GrResult res = kresOk;
+
+ //SetUpGraphics(ichwBase, pgg, true);
+
+ if (m_dxsWidth == -1)
+ ComputeDimensions();
+
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ if (pcch)
+ *pcch = m_dichwLim;
+ if (pcf)
+ *pcf = m_cginf;
+ if (cchMax < m_dichwLim)
+ {
+ if (cchMax == 0 && cfMax == 0)
+ res = kresFalse; // just asking for size information
+ else if (prgiginfFirstOfCluster || cchMax > 0)
+ res = kresInvalidArg; // not enough space
+ }
+ if (cfMax < m_cginf)
+ {
+ if (cchMax == 0 && cfMax == 0)
+ res = kresFalse;
+ else if (pfClusterStart || cfMax > 0)
+ res = kresInvalidArg;
+ }
+ if (res != kresOk)
+ {
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ // Generate a pair of arrays, indicating the first and last (logical) slots
+ // of the cluster for each character. Initially clusters are based just on
+ // character-to-glyph associations, but they expand as we process
+ // insert=false settings, attachments, and reordering.
+
+ std::vector<int> visloutBefore;
+ std::vector<int> visloutAfter;
+ visloutBefore.resize(m_dichwLim);
+ visloutAfter.resize(m_dichwLim);
+
+ int ich;
+ for (ich = 0; ich < m_dichwLim; ich++)
+ {
+ visloutBefore[ich] = m_prgisloutBefore[ich - m_ichwAssocsMin];
+ visloutAfter[ich] = m_prgisloutAfter[ich - m_ichwAssocsMin];
+ }
+
+ if (m_dichwLim == 1)
+ {
+ // Only one character, therefore only one cluster.
+ visloutBefore[0] = m_isloutGinf0;
+ visloutAfter[0] = max(m_cginf - 1, 0) + m_isloutGinf0;
+ }
+ else
+ {
+ // Make all glyphs attached to each other part of a cluster, or glyphs where
+ // insertion is not allowed.
+ for (ich = 0; ich < m_dichwLim; ich++)
+ {
+ std::vector<int> vislout = UnderlyingToLogicalAssocs(ich + m_ichwMin);
+
+ if (vislout.size() == 0)
+ {
+ // No glyphs represent this character. Merge it with the previous
+ // character.
+ visloutBefore[ich] = (ich == 0) ? visloutBefore[ich + 1] : visloutBefore[ich - 1];
+ visloutAfter[ich] = (ich == 0) ? visloutAfter[ich + 1] : visloutAfter[ich - 1];
+ continue;
+ }
+
+ size_t iislout;
+ for (iislout = 0; iislout < vislout.size(); iislout++)
+ {
+ int islout = vislout[iislout];
+ if (!m_prgslout[islout].InsertBefore())
+ {
+ // This glyph does not allow insertion before it; make its character part
+ // of the same cluster as the previous character.
+ MergeUniscribeCluster(visloutBefore, visloutAfter, ich - 1, ich);
+/*
++ // Keith Stribley's fix:
++ // NOTE: this is NOT always the same as the previous character, so
++ // check whether the next character actually has a glyph before this
++ // one
++ if ((ich == m_dichwLim - 1) ||
++ (std::min(visloutBefore[ich + 1], visloutAfter[ich + 1]) >
++ std::max(visloutBefore[ich], visloutAfter[ich])))
++ {
++ MergeUniscribeCluster(visloutBefore, visloutAfter, ich - 1, ich);
++ }
++ else
++ MergeUniscribeCluster(visloutBefore, visloutAfter, ich, ich + 1);
+*/
+ }
+ else if (m_prgslout[islout].ClusterBase() != -1
+ && m_prgslout[islout].ClusterBase() != islout)
+ {
+ // This glyph is attached to something; make them part of the same cluster.
+ int isloutBase = m_prgslout[islout].ClusterBase();
+ int ichBase = LogicalSurfaceToUnderlying(isloutBase, false) - m_ichwMin;
+ MergeUniscribeCluster(visloutBefore, visloutAfter,
+ ich, ichBase);
+ int ichBase1 = LogicalSurfaceToUnderlying(isloutBase, false) - m_ichwMin;
+ if (ichBase1 != ichBase)
+ MergeUniscribeCluster(visloutBefore, visloutAfter,
+ ich, ichBase1);
+ }
+ }
+ }
+
+ // Handle reordering. Whenever the islout values get out of order, we need to
+ // merge into a single cluster.
+ for (ich = 0; ich < m_dichwLim - 1; ich++)
+ {
+ Assert(visloutBefore[ich] <= visloutAfter[ich]);
+ Assert(visloutBefore[ich] != kPosInfinity);
+ Assert(visloutBefore[ich] != kNegInfinity);
+ Assert(visloutAfter[ich] != kPosInfinity);
+ Assert(visloutAfter[ich] != kNegInfinity);
+ const int b1 = visloutBefore[ich];
+ const int a1 = visloutAfter[ich];
+ const int b2 = visloutBefore[ich + 1];
+ const int a2 = visloutAfter[ich + 1];
+ if (b1 == b2 && a1 == a2)
+ continue; // already a cluster
+
+ if (std::min(b2, a2) <= std::max(b1, a1))
+ {
+ MergeUniscribeCluster(visloutBefore, visloutAfter, ich, ich + 1);
+ }
+ }
+ }
+
+ if (pfClusterStart)
+ {
+ // Initialize.
+ int iginf;
+ for (iginf = 0; iginf < m_cginf; iginf++)
+ pfClusterStart[iginf] = false;
+ }
+
+ // To skip line-break slots; remember that the number of output slots equals the
+ // number of gbbs plus initial and/or final line-break slots if any.
+ // In this case the beginning of the first cluster indicates the first real glyph.
+ int isloutFirstReal = (m_dichwLim) ? ((m_fWsRtl)? visloutAfter[0] : visloutBefore[0]) : 0;
+
+ // Kludge to make assertions below easier:
+ if (m_dichwLim > 0)
+ {
+ visloutBefore.push_back(visloutAfter.back() + 1);
+ visloutAfter.push_back(visloutAfter.back() + 1);
+ }
+
+ // Convert (logical) slots to actual glyphs.
+ for (ich = 0; ich < m_dichwLim; ich++)
+ {
+ // NOTE: to treat the first of the cluster as the left-most, use visloutAfter for
+ // right-to-left situations.
+
+ if (prgiginfFirstOfCluster)
+ prgiginfFirstOfCluster[ich]
+ = LogicalToPhysicalSurface((m_fWsRtl) ? visloutAfter[ich] : visloutBefore[ich]);
+ int clusterStartPos = ((m_fWsRtl) ? visloutAfter[ich] : visloutBefore[ich]) - isloutFirstReal;
+ if (pfClusterStart)
+ pfClusterStart[clusterStartPos] = true;
+
+ Assert((visloutBefore[ich] == visloutBefore[ich + 1] &&
+ visloutAfter[ich] == visloutAfter[ich + 1])
+ || (visloutBefore[ich] <= visloutAfter[ich] &&
+ visloutAfter[ich] < visloutBefore[ich + 1]));
+ }
+
+ //RestoreFont(pgg);
+
+ return kresOk;
+}
+
+
+// suppress GCC 4.3 warning for optimized min()/max() when called with (ich, ich+1) or similar
+#pragma GCC diagnostic ignored "-Wstrict-overflow"
+
+/*----------------------------------------------------------------------------------------------
+ Merge the given characters into the same Uniscribe cluster. This means merging any
+ intervening characters as well.
+----------------------------------------------------------------------------------------------*/
+void Segment::MergeUniscribeCluster(
+ std::vector<int> & visloutBefore, std::vector<int> & visloutAfter,
+ int ich1, int ich2)
+{
+ int ichStartOrig = min(ich1, ich2);
+ int ichStopOrig = max(ich1, ich2);
+
+ int isloutMin = visloutBefore[ichStopOrig];
+ int isloutMax = visloutAfter[ichStartOrig];
+
+ int ichStart = ichStopOrig;
+ int ichStop = ichStartOrig;
+ // Find the beginning of the cluster.
+ while (ichStart > 0 &&
+ (ichStart > ichStartOrig
+ || visloutBefore[ichStart - 1] >= visloutBefore[ichStopOrig]
+ || visloutBefore[ichStart - 1] == visloutBefore[ichStart]))
+ {
+ ichStart--;
+ isloutMin = std::min(isloutMin, visloutBefore[ichStart]);
+ isloutMax = std::max(isloutMax, visloutAfter[ichStart]);
+ }
+ // Find end of cluster.
+ while (ichStop < m_dichwLim - 1 &&
+ (ichStop < ichStopOrig
+ || visloutAfter[ichStop + 1] <= visloutAfter[ichStartOrig]
+ || visloutAfter[ichStop + 1] == visloutAfter[ichStop]))
+ {
+ ichStop++;
+ isloutMin = std::min(isloutMin, visloutBefore[ichStop]);
+ isloutMax = std::max(isloutMax, visloutAfter[ichStop]);
+ }
+
+ int ich;
+ for (ich = ichStart; ich <= ichStop; ich++)
+ {
+ visloutBefore[ich] = isloutMin;
+ visloutAfter[ich] = isloutMax;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return information about the positioning of glyphs as appropriate for Uniscribe.
+ The advance widths returned are the natural ones (what would be applied if no smart
+ rendering were happening), and the x-offsets are the difference between the
+ natural location of the glyph and what is produced by Graphite. The y-offset
+ is the same as GetGlyphsAndPositions.
+
+ This is an experimental method. Its behavior may change signficantly in the future.
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult Segment::GetUniscribePositions(
+ Rect rs, Rect rd, int cgidMax, int *pcgidRet,
+ float * prgxd, float * prgyd, float * prgdxdAdv)
+{
+ ChkGrOutPtr(pcgidRet);
+ ChkGrArrayArg(prgxd, cgidMax);
+ ChkGrArrayArg(prgyd, cgidMax);
+ ChkGrArrayArg(prgdxdAdv, cgidMax);
+
+ GrResult res;
+
+ //SetUpGraphics(ichBase, pgg, true);
+
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ *pcgidRet = m_cginf;
+ if (cgidMax < m_cginf)
+ {
+ res = (cgidMax == 0) ? kresFalse : kresInvalidArg;
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ if (m_dxsWidth < 0)
+ ComputeDimensions();
+
+ float * rgxdTmp = new float[cgidMax];
+ float * rgdxdAdvTmp = new float[cgidMax];
+ res = GetGlyphsAndPositions(rs, rd, cgidMax, pcgidRet,
+ NULL, rgxdTmp, prgyd, rgdxdAdvTmp);
+ if (ResultFailed(res))
+ {
+ delete[] rgxdTmp;
+ delete[] rgdxdAdvTmp;
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ float xdLeft = SegmentPainter::ScaleX(0, rs, rd);
+ float xdXPosNatural = xdLeft;
+ for (int iginf = 0; iginf < *pcgidRet; iginf++)
+ {
+ int islout = iginf + m_isloutGinf0;
+ GrSlotOutput * pslout = OutputSlot(islout);
+ float dxsAdvNatural = pslout->AdvanceXMetric();
+ float dxdAdvNatural = SegmentPainter::ScaleX(dxsAdvNatural, rs, rd) - xdLeft;
+ prgdxdAdv[iginf] = dxdAdvNatural;
+ prgxd[iginf] = rgxdTmp[iginf] - xdXPosNatural;
+
+ xdXPosNatural += dxdAdvNatural;
+ }
+
+ delete[] rgxdTmp;
+ delete[] rgdxdAdvTmp;
+
+ //RestoreFont(pgg);
+
+ ReturnResult(res);
+
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ Return information about the positioning of glyphs as appropriate for Uniscribe.
+ The advance widths returned are the natural ones (what would be applied if no smart
+ rendering were happening), and the x-offsets are the difference between the
+ natural location of the glyph and what is produced by Graphite. The y-offset
+ is the same as GetGlyphsAndPositions.
+
+ This is an experimental method. Its behavior may change signficantly in the future.
+----------------------------------------------------------------------------------------------*/
+/*
+GrResult Segment::GetUniscribeGlyphsAndPositions(
+ Rect rs, Rect rd, int cgidMax, int *pcgidRet, utf16 * prgchGlyphs,
+ float * prgxd, float * prgyd, float * prgdxdAdv)
+{
+ ChkGrOutPtr(pcgidRet);
+ ChkGrArrayArg(prgxd, cgidMax);
+ ChkGrArrayArg(prgyd, cgidMax);
+ ChkGrArrayArg(prgdxdAdv, cgidMax);
+
+ GrResult res;
+
+ //SetUpGraphics(ichBase, pgg, true);
+
+ Assert(m_dxsWidth >= 0);
+ Assert(m_dysAscent >= 0);
+
+ *pcgidRet = m_cginf;
+ if (cgidMax < m_cginf)
+ {
+ res = (cgidMax == 0) ? kresFalse : kresInvalidArg;
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ if (m_dxsWidth < 0)
+ ComputeDimensions();
+
+ float * rgxdTmp = new float[cgidMax];
+ float * rgdxdAdvTmp = new float[cgidMax];
+ res = GetGlyphsAndPositions(rs, rd, cgidMax, pcgidRet,
+ prgchGlyphs, rgxdTmp, prgyd, rgdxdAdvTmp);
+ if (ResultFailed(res))
+ {
+ delete[] rgxdTmp;
+ delete[] rgdxdAdvTmp;
+ //RestoreFont(pgg);
+ ReturnResult(res);
+ }
+
+ float xdLeft = SegmentPainter::ScaleX(0, rs, rd);
+ float xdXPosNatural = xdLeft;
+ for (int iginf = 0; iginf < *pcgidRet; iginf++)
+ {
+ int islout = iginf + m_isloutGinf0;
+ GrSlotOutput * pslout = OutputSlot(islout);
+ float dxsAdvNatural = pslout->AdvanceXMetric();
+ float dxdAdvNatural = SegmentPainter::ScaleX(dxsAdvNatural, rs, rd) - xdLeft;
+ prgdxdAdv[iginf] = dxdAdvNatural;
+ prgxd[iginf] = rgxdTmp[iginf] - xdXPosNatural;
+
+ xdXPosNatural += dxdAdvNatural;
+ }
+
+ delete[] rgxdTmp;
+ delete[] rgdxdAdvTmp;
+
+ //RestoreFont(pgg);
+
+ ReturnResult(res);
+}
+*/
+
+/*----------------------------------------------------------------------------------------------
+ Return the visual box for the given ligature component. Return (0,0,0,0) if the component
+ is not defined.
+----------------------------------------------------------------------------------------------*/
+Rect Segment::ComponentRect(GrSlotOutput * pslout, int icomp)
+{
+ Rect rectRet;
+ rectRet.top = rectRet.bottom = rectRet.left = rectRet.right = 0;
+ if (icomp < 0 || icomp > pslout->NumberOfComponents())
+ return rectRet;
+
+ GrEngine * pgreng = EngineImpl();
+ if (!pgreng)
+ return rectRet;
+ GrGlyphTable * pgtbl = pgreng->GlyphTable();
+ if (!pgtbl)
+ return rectRet;
+
+ float xsLeft, xsRight, ysTop, ysBottom;
+
+ // TODO: Rework ComponentIndexForGlyph to take slati rather than iForGlyph.
+ int slati = pslout->ComponentId(icomp);
+ int iForGlyph = pgtbl->ComponentIndexForGlyph(pslout->GlyphID(), slati);
+ if (!pgtbl->ComponentBoxLogUnits(m_xysEmSquare, pslout->GlyphID(), iForGlyph,
+ m_mFontEmUnits, m_dysAscent,
+ &xsLeft, &ysTop, &xsRight, &ysBottom,
+ false)) // origin is baseline
+ {
+ return rectRet;
+ }
+ rectRet.top = ysTop;
+ rectRet.bottom = ysBottom;
+ rectRet.left = xsLeft;
+ rectRet.right = xsRight;
+
+ return rectRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Shift the glyphs physically by the given amount. This happens when a right-to-left
+ segment is changed from being end-of-line to not, so we have to account for the fact
+ that the trailing white-space was previous invisible but is now visible.
+----------------------------------------------------------------------------------------------*/
+void Segment::ShiftGlyphs(float dxsShift)
+{
+ for (int islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * pslout = OutputSlot(islout);
+ pslout->AdjustPosXBy(dxsShift);
+ }
+
+ //ShiftGlyphsPlatform(dxsShift);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Find the glyph that best matches the given click location.
+
+ @param xsClick - relative to start of segment
+ @param ysClick - relative to segment baseline
+----------------------------------------------------------------------------------------------*/
+int Segment::GlyphHit(float xsClick, float ysClick)
+{
+ float xsLeft = kPosInfFloat;
+ float xsRight = kNegInfFloat;
+
+ int iginf;
+ for (iginf = 0; iginf < m_cginf; iginf++)
+ {
+ GlyphInfo * pginf = m_prgginf + iginf;
+ xsLeft = min(xsLeft, pginf->origin());
+ xsRight = max(xsRight, pginf->origin() + pginf->advanceWidth());
+ }
+
+ if (xsClick < xsLeft)
+ return m_fWsRtl ? m_cginf - 1 : 0;
+ else if (xsClick > xsRight)
+ return m_fWsRtl ? 0 : m_cginf - 1;
+
+ int iginfHit;
+ std::vector<int> viginfNear;
+ std::vector<int> viginfHit;
+ std::vector<int> viginfInside;
+
+ // Find glyph which might contain click point.
+
+ for (iginfHit = m_cginf; iginfHit-- > 0; )
+ {
+ if (m_fWsRtl)
+ {
+ if (m_prgginf[iginfHit].bb().right >= xsClick)
+ break;
+ }
+ else
+ {
+ if (m_prgginf[iginfHit].bb().left <= xsClick)
+ break;
+ }
+ }
+ if (iginfHit < 0) // click within lsb of first glyph
+ {
+ return 0;
+ }
+
+ // Find all BB that OVERLAP the click point (bb.left < XClick < bb.right).
+ for (iginf = iginfHit; iginf >= 0; iginf--)
+ {
+ Rect rectBB = m_prgginf[iginf].bb();
+ if (rectBB.left <= xsClick && xsClick <= rectBB.right)
+ {
+ viginfNear.push_back(iginf);
+ }
+ }
+
+ // Find all BB that CONTAIN the click point (considering the click's Y coor too).
+ int iiginf;
+ for (iiginf = 0; iiginf < (int)viginfNear.size(); iiginf++)
+ {
+ Rect rectBB = m_prgginf[viginfNear[iiginf]].bb();
+ if (rectBB.bottom <= ysClick && ysClick <= rectBB.top)
+ {
+ viginfHit.push_back(viginfNear[iiginf]);
+ }
+ }
+
+ if (viginfNear.size() > 2 && viginfHit.size() == 0)
+ {
+ // No hit along y-axis; find the closest thing.
+ float dy = float(10000000.0);
+ for (int iiginf2 = 0; iiginf2 < (int)viginfNear.size(); iiginf2++)
+ {
+ Rect rectBB = m_prgginf[viginfNear[iiginf2]].bb();
+ if (fabsf(rectBB.top - ysClick) < dy)
+ {
+ dy = fabsf(rectBB.top - ysClick);
+ viginfHit.clear();
+ viginfHit.push_back(viginfNear[iiginf2]);
+ }
+ if (fabsf(rectBB.bottom - ysClick) < dy)
+ {
+ dy = fabsf(rectBB.bottom - ysClick);
+ viginfHit.clear();
+ viginfHit.push_back(viginfNear[iiginf2]);
+ }
+ }
+ }
+
+ // Find all BB for which the click is within their advance width, if any.
+ for (iiginf = 0; iiginf < (int)viginfHit.size(); iiginf++)
+ {
+ //Rect rectBB = m_prgginf[viginfHit[iiginf]].bb(); -- ?? this tests the bounding box again :-/
+ //if (rectBB.left <= xsClick && xsClick <= rectBB.right)
+ gr::GlyphInfo * pginf = m_prgginf + viginfHit[iiginf];
+ if (pginf->advanceWidth() == 0 // advance width is irrelevant
+ || (pginf->origin() < xsClick && xsClick <= pginf->origin() + pginf->advanceWidth()))
+ {
+ viginfInside.push_back(viginfHit[iiginf]);
+ }
+ }
+
+ // If no BB coincides in any way with the click point, take the BB whose leading edge
+ // is closest to the click point.
+ // There could be more than one BB with the same leading x coor.
+ if (viginfHit.size() == 0 && viginfNear.size() == 0 && viginfInside.size() == 0)
+ {
+ float xsLeading;
+ if (iginfHit + 1 == m_cginf)
+ {
+ viginfNear.push_back(iginfHit);
+ }
+ else if (!m_fWsRtl)
+ {
+ // Left-to-right:
+ xsLeading = m_prgginf[iginfHit + 1].bb().left;
+ for (iginf = iginfHit + 1; iginf < m_cginf; iginf++)
+ {
+ if (m_prgginf[iginf].bb().left == xsLeading)
+ viginfNear.push_back(iginf);
+ }
+ }
+ else
+ {
+ // Right-to-left:
+ xsLeading = m_prgginf[iginfHit].bb().right;
+ for (iginf = iginfHit; iginf < m_cginf; iginf++)
+ {
+ if (m_prgginf[iginf].bb().right == xsLeading)
+ viginfNear.push_back(iginf);
+ }
+ }
+ }
+
+ Assert(viginfNear.size());
+
+ int iginfLoc;
+
+ // Select the BB based on its leading edge, offset from baseline, position in final pass.
+ if (viginfInside.size())
+ iginfLoc = SelectBb(viginfInside, m_fWsRtl);
+ else if (viginfHit.size())
+ iginfLoc = SelectBb(viginfHit, m_fWsRtl);
+ else
+ iginfLoc = SelectBb(viginfNear, m_fWsRtl);
+
+ return iginfLoc;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Select the bounding box we will use for a mouse hit.
+ First select any glyph with a significantly smaller bounding box.
+ Then, select the BB with the left-most (LTR) or right-most (RTL) edge.
+ If more than one BB has same edge of interest, select the one that is closest to the
+ the baseline.
+ If that is a tie, select the one with the lowest islout.
+
+ @param vigbb - list of indexes into m_prggbb
+ @param fRTL - writing system direction
+----------------------------------------------------------------------------------------------*/
+int Segment::SelectBb(std::vector<int> & viginf, bool fRTL)
+{
+ if (!viginf.size())
+ {
+ Assert(false);
+ return -1;
+ }
+
+ if (viginf.size() == 1)
+ return viginf[0];
+
+ // Find a glyph that has a signficantly smaller bounding box.
+ // The idea is that it is going to be harder to hit than the bigger glyph.
+ float smallestArea = float(1000000000.0);
+ float largestArea = 0.0;
+ size_t iiginfSmallest = 0;
+ size_t iiginf;
+ for (iiginf = 0; iiginf < viginf.size(); iiginf++)
+ {
+ gr::GlyphInfo * pginf = m_prgginf + viginf[iiginf];
+ Rect rectBB = pginf->bb();
+ float thisArea = (rectBB.right - rectBB.left) * (rectBB.top - rectBB.bottom);
+ if (smallestArea > thisArea)
+ {
+ smallestArea = thisArea;
+ iiginfSmallest = iiginf;
+ }
+ largestArea = max(largestArea, thisArea);
+ }
+ if (smallestArea * 2.0 < largestArea)
+ return viginf[iiginfSmallest];
+
+ // Find appropriate x coor of leading edge.
+ float xsLeading;
+ if (!fRTL)
+ xsLeading = m_prgginf[viginf[0]].bb().left;
+ else
+ xsLeading = m_prgginf[viginf[0]].bb().right;
+
+ for (iiginf = 1; iiginf < viginf.size(); iiginf++)
+ {
+ Rect rectBB = m_prgginf[viginf[iiginf]].bb();
+ if (!fRTL)
+ xsLeading = min(xsLeading, rectBB.left);
+ else
+ xsLeading = max(xsLeading, rectBB.right);
+ }
+
+ // Find BBs with the leading edge.
+ std::vector<int> viginfSameEdge;
+ for (iiginf = 0; iiginf < viginf.size(); iiginf++)
+ {
+ Rect rectBB = m_prgginf[viginf[iiginf]].bb();
+ if (!fRTL)
+ {
+ if (rectBB.left == xsLeading)
+ viginfSameEdge.push_back(viginf[iiginf]);
+ }
+ else
+ {
+ if (rectBB.right == xsLeading)
+ viginfSameEdge.push_back(viginf[iiginf]);
+ }
+ }
+
+ if (viginfSameEdge.size() == 1)
+ return viginfSameEdge[0];
+
+ // Find minimum distance from baseline.
+ float ysMin = fabsf(m_prgginf[viginfSameEdge[0]].yOffset());
+ for (iiginf = 1; iiginf < viginfSameEdge.size(); iiginf++)
+ {
+ float ysThis = fabsf(m_prgginf[viginfSameEdge[iiginf]].yOffset());
+ ysMin = min(ysMin, ysThis);
+ }
+
+ // Find BBs with minimum distance from baseline.
+ std::vector<int> viginfSameY;
+ for (iiginf = 0; iiginf < viginfSameEdge.size(); iiginf++)
+ {
+ if (fabsf(m_prgginf[viginfSameEdge[iiginf]].yOffset()) == ysMin)
+ viginfSameY.push_back(viginfSameEdge[iiginf]);
+ }
+
+ if (viginfSameY.size() == 1)
+ return viginfSameY[0];
+
+ // Find minimum index of current candidates.
+ int islout = m_prgginf[viginfSameY[0]].logicalIndex();
+ for (iiginf = 1; iiginf < viginfSameY.size(); iiginf++)
+ {
+ int isloutThis = m_prgginf[viginfSameY[iiginf]].logicalIndex();
+ islout = min(islout, isloutThis);
+ }
+
+ // Find BB with minimum islout - islout should be unique for all glyphs.
+ for (iiginf = 0; iiginf < viginfSameY.size(); iiginf++)
+ {
+ if (m_prgginf[viginfSameY[iiginf]].logicalIndex() == (unsigned)islout)
+ return viginfSameY[iiginf];
+ }
+
+ Assert(false);
+ return -1; // needed to stop compiler warning
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the right-most glyph on the physical surface. If there are ties, it will
+ prefer the one that is logically closest to the edge.
+----------------------------------------------------------------------------------------------*/
+int Segment::RightMostGlyph()
+{
+ float xsRight = kNegInfFloat;
+ int iginfRet = -1;
+ for (int iginf = 0; iginf < m_cginf; iginf++)
+ {
+ float xsThis = m_prgginf[iginf].bb().right;
+ // For RTL, we prefer the glyph that is logically first; for LTR we prefer logically last.
+ if (xsThis > xsRight || (!m_fWsRtl && xsRight == xsThis))
+ {
+ xsRight = xsThis;
+ iginfRet = iginf;
+ }
+ }
+ return iginfRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the left-most glyph on the physical surface. If there are ties, it will
+ prefer the one that is logically closest to the edge.
+----------------------------------------------------------------------------------------------*/
+int Segment::LeftMostGlyph()
+{
+ float xsLeft = kPosInfFloat;
+ int iginfRet = -1;
+ for (int iginf = 0; iginf < m_cginf; iginf++)
+ {
+ float xsThis = m_prgginf[iginf].bb().left;
+ // For RTL, we prefer the glyph that is logically last; for LTR we prefer logically first.
+ if (xsThis < xsLeft || (m_fWsRtl && xsLeft == xsThis))
+ {
+ xsLeft = xsThis;
+ iginfRet = iginf;
+ }
+ }
+ return iginfRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Convert from em-units to logical units.
+----------------------------------------------------------------------------------------------*/
+float Segment::EmToLogUnits(int m)
+{
+ return GrEngine::GrIFIMulDiv(m, m_xysEmSquare, m_mFontEmUnits);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return the line-break pseudo glyph ID.
+----------------------------------------------------------------------------------------------*/
+gid16 Segment::LBGlyphID()
+{
+ return m_preneng->LBGlyphID();
+}
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/SegmentAux.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/SegmentAux.cpp
new file mode 100644
index 00000000000..2d475f9114f
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/SegmentAux.cpp
@@ -0,0 +1,256 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2005 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: SegmentAux.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements auxiliary class that work with Segment:
+ - GlyphInfo
+ - GlyphIterator
+ - LayoutEnvironment
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+// any other headers (not precompiled)
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> GlyphInfo methods
+//:>********************************************************************************************
+
+gid16 GlyphInfo::glyphID()
+{
+ return m_pslout->m_chwActual;
+}
+
+gid16 GlyphInfo::pseudoGlyphID()
+{
+ if (m_pslout->m_chwActual == m_pslout->m_chwGlyphID)
+ return 0; // not a pseudo-glyph
+ return m_pslout->m_chwGlyphID;
+}
+
+bool GlyphInfo::isAttached() const throw()
+{
+ return m_pslout->IsPartOfCluster();
+}
+
+gr::GlyphIterator GlyphInfo::attachedClusterBase() const throw()
+{
+ const int islout = m_pslout->ClusterBase();
+
+ // Since we are not passing an array, the constructor expects a ginf index, not a slout index.
+ return GlyphIterator(*m_pseg, ((islout >= 0) ? islout : m_islout) - m_pseg->m_isloutGinf0);
+}
+
+float GlyphInfo::attachedClusterAdvance() const throw()
+{
+ return m_pslout->ClusterAdvance();
+}
+
+std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> GlyphInfo::attachedClusterGlyphs() const
+{
+ std::vector<int> visloutClusterMembers;
+ m_pslout->ClusterMembers(m_pseg, m_islout, visloutClusterMembers);
+ RcVector * qvislout = new RcVector(visloutClusterMembers);
+ return std::make_pair(
+ GlyphSetIterator(*m_pseg, 0, qvislout),
+ GlyphSetIterator(*m_pseg, visloutClusterMembers.size(), qvislout));
+}
+
+size_t GlyphInfo::logicalIndex()
+{
+ if (m_pseg->OutputSlot(0)->IsLineBreak())
+ return m_islout - 1;
+ else
+ return m_islout;
+}
+
+float GlyphInfo::origin()
+{
+ return m_pslout->XPosition();
+}
+
+float GlyphInfo::advanceWidth() // logical units
+{
+ return m_pslout->m_xsAdvanceX;
+}
+
+float GlyphInfo::advanceHeight() // logical units; zero for horizontal fonts
+{
+ Font & font = m_pseg->getFont();
+ return m_pslout->GlyphMetricLogUnits(&font, kgmetAdvHeight);
+}
+
+float GlyphInfo::yOffset()
+{
+ return m_pslout->YPosition();
+}
+
+Rect GlyphInfo::bb() // logical units
+{
+ return m_pslout->BoundingBox(m_pseg->getFont());
+}
+
+bool GlyphInfo::isSpace()
+{
+ return m_pslout->IsSpace();
+}
+
+// first char associated with this glyph, relative to start of the text-source
+toffset GlyphInfo::firstChar()
+{
+ return m_pseg->LogicalSurfaceToUnderlying(m_islout, true);
+}
+
+// last char associated with this glyph, relative to start of the text-source
+toffset GlyphInfo::lastChar()
+{
+ return m_pseg->LogicalSurfaceToUnderlying(m_islout, false);
+}
+
+unsigned int GlyphInfo::directionality()
+{
+ return m_pslout->Directionality();
+}
+
+// Embedding depth
+unsigned int GlyphInfo::directionLevel()
+{
+ return m_pslout->DirLevel();
+}
+
+bool GlyphInfo::insertBefore()
+{
+ return m_pslout->InsertBefore();
+}
+
+int GlyphInfo::breakweight()
+{
+ return m_pslout->BreakWeight();
+}
+
+float GlyphInfo::maxStretch(size_t level)
+{
+ return m_pslout->MaxStretch(m_pseg, (int)level);
+}
+
+float GlyphInfo::maxShrink(size_t level)
+{
+ return m_pslout->MaxShrink(m_pseg, (int)level);
+}
+
+float GlyphInfo::stretchStep(size_t level)
+{
+ return m_pslout->StretchStep(m_pseg, (int)level);
+}
+
+byte GlyphInfo::justWeight(size_t level)
+{
+ return byte(m_pslout->JustWeight((int)level));
+}
+
+float GlyphInfo::justWidth(size_t level)
+{
+ return m_pslout->JustWidth(m_pseg, (int)level);
+}
+
+float GlyphInfo::measureStartOfLine()
+{
+ return m_pslout->MeasureSolLogUnits(m_pseg);
+}
+
+float GlyphInfo::measureEndOfLine()
+{
+ return m_pslout->MeasureEolLogUnits(m_pseg);
+}
+
+size_t GlyphInfo::numberOfComponents()
+{
+ return m_pslout->NumberOfComponents();
+}
+
+Rect GlyphInfo::componentBox(size_t icomp)
+{
+ return m_pseg->ComponentRect(m_pslout, icomp);
+}
+
+toffset GlyphInfo::componentFirstChar(size_t icomp)
+{
+ Assert((int)icomp < m_pslout->NumberOfComponents());
+ return m_pslout->FirstUnderlyingComponent(icomp) + m_pseg->startCharacter();
+}
+toffset GlyphInfo::componentLastChar(size_t icomp)
+{
+ Assert((int)icomp < m_pslout->NumberOfComponents());
+ return m_pslout->LastUnderlyingComponent(icomp) + m_pseg->startCharacter();
+}
+
+bool GlyphInfo::erroneous()
+{
+ return m_pseg->Erroneous();
+}
+
+
+//:>********************************************************************************************
+//:> GlyphIterator methods
+//:>********************************************************************************************
+
+// Constructor
+GlyphIterator::GlyphIterator(Segment & seg, size_t iginf)
+: m_pginf(seg.m_prgginf + iginf)
+{}
+
+// Copy constructor.
+// Check if the incoming iterator is null, as we cannot dereference
+// it to get the segment, and create a null GlyphIterator.
+// Technically this might better be an assert as converting a null
+// GlyphSetIterator into a null GlyphIterator is pointless and suggests
+// some kind of error.
+GlyphIterator::GlyphIterator(const GlyphSetIterator & sit)
+: m_pginf((sit == GlyphSetIterator())
+ ? 0
+ : sit->segment().m_prgginf + sit->logicalIndex())
+{}
+
+/*----------------------------------------------------------------------------------------------
+ Dereference the iterator, returning a GlyphInfo object.
+----------------------------------------------------------------------------------------------*/
+
+GlyphSetIterator::reference GlyphSetIterator::operator*() const
+{
+ assert(m_pseg != 0);
+ assert(m_vit != std::vector<int>::const_iterator());
+ // in the case of a non-contiguous list
+ return m_pseg->m_prgginf[(*m_vit) - m_pseg->m_isloutGinf0];
+}
+
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/TestFSM.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/TestFSM.cpp
new file mode 100644
index 00000000000..6dad1dc9dc8
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/TestFSM.cpp
@@ -0,0 +1,3416 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TestFSM.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Hard-coded FSMs for test procedures.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:Ignore
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+#ifdef OLD_TEST_STUFF
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+#ifndef _DEBUG
+
+bool GrLineBreakPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+bool GrSubPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+bool GrPosPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+#endif // !_DEBUG
+
+
+#ifdef _DEBUG
+
+/*----------------------------------------------------------------------------------------------
+ Call the appropriate test function.
+----------------------------------------------------------------------------------------------*/
+
+bool GrLineBreakPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+bool GrSubPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ if (m_staBehavior == "SimpleFSM")
+ return RunSimpleFSMTest(ptman, ruln, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "RuleAction")
+ return false;
+ else if (m_staBehavior == "RuleAction2")
+ return false;
+ else if (m_staBehavior == "Assoc")
+ return false;
+ else
+ return false;
+}
+
+bool GrPosPass::RunTestRules(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ A simple FSM.
+
+ Rules:
+ r1. clsCons clsVowel clsDiacrAcute
+ r2. clsCons clsVowelAE clsDiacr
+ r3. clsCons clsVowelI
+ r4. clsCons clsVowelI clsDiacrGrave
+ r5. clsCons clsVowelI clsDiacr
+
+ Machine classes:
+ mcCons: b,c,d / f,g,h / j,k,l,m,n / p,q,r,s,t / v,w,x,y,z
+ mcVae: a 97/ e 101
+ mcVi: i 105
+ mcVou: o 111 / u 117
+ mcDa: acute '/' 47
+ mcDg: grave '\' 92
+ mcDct: other diacritics-circumflex '^' 94 / tilde '~' 126
+
+
+ FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcCons mcVae mcVi mcVou mcDa mcDg mcDct
+ ---------------------------------------------------------------------------
+ T NA s0 | s1
+ | - - - - - - -
+ T NA s1 | s2 s4 s3
+ | - - - - - - -
+ T NA s2 | s5 s6 s6
+ | - - - - - - -
+ T NA s3 | s10
+ | - - - - - - -
+ T A s4 | s7 s8 s9
+ | - - - - - - -
+ F A s5 |
+ | - - - - - - -
+ F A s6 |
+ | - - - - - - -
+ F A s7 |
+ | - - - - - - -
+ F A s8 |
+ | - - - - - - -
+ F A s9 |
+ | - - - - - - -
+ F A s10 |
+ | - - - - - - -
+
+ Rules Matched:
+ s4: r3
+ s5: r1, r2
+ s6: r2
+ s7: r1, r5
+ s8: r4, r5
+ s9: r5
+ s10: r1
+
+----------------------------------------------------------------------------------------------*/
+
+void GrSubPass::SetUpSimpleFSMTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "SimpleFSM";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpSimpleFSMTest();
+}
+
+void GrFSM::SetUpSimpleFSMTest()
+{
+ // Create machine class ranges.
+ m_cmcr = 14;
+ m_prgmcr = new GrFSMClassRange[14];
+ m_prgmcr[0].m_chwFirst = 47; // forward slash (acute): mcDa
+ m_prgmcr[0].m_chwLast = 47;
+ m_prgmcr[0].m_col = 4;
+
+ m_prgmcr[1].m_chwFirst = 92; // backslash: mcDg
+ m_prgmcr[1].m_chwLast = 92;
+ m_prgmcr[1].m_col = 5;
+
+ m_prgmcr[2].m_chwFirst = 94; // caret: mcDct
+ m_prgmcr[2].m_chwLast = 94;
+ m_prgmcr[2].m_col = 6;
+
+ m_prgmcr[3].m_chwFirst = 97; // a: mcVae
+ m_prgmcr[3].m_chwLast = 97;
+ m_prgmcr[3].m_col = 1;
+
+ m_prgmcr[4].m_chwFirst = 98; // b - d: mcCons
+ m_prgmcr[4].m_chwLast = 100;
+ m_prgmcr[4].m_col = 0;
+
+ m_prgmcr[5].m_chwFirst = 101; // e: mcVae
+ m_prgmcr[5].m_chwLast = 101;
+ m_prgmcr[5].m_col = 1;
+
+ m_prgmcr[6].m_chwFirst = 102; // f - h: mcCons
+ m_prgmcr[6].m_chwLast = 104;
+ m_prgmcr[6].m_col = 0;
+
+ m_prgmcr[7].m_chwFirst = 105; // i: mcVi
+ m_prgmcr[7].m_chwLast = 105;
+ m_prgmcr[7].m_col = 2;
+
+ m_prgmcr[8].m_chwFirst = 106; // j - n: mcCons
+ m_prgmcr[8].m_chwLast = 110;
+ m_prgmcr[8].m_col = 0;
+
+ m_prgmcr[9].m_chwFirst = 111; // o: mcVou
+ m_prgmcr[9].m_chwLast = 111;
+ m_prgmcr[9].m_col = 3;
+
+ m_prgmcr[10].m_chwFirst = 112; // p - t: mcCons
+ m_prgmcr[10].m_chwLast = 116;
+ m_prgmcr[10].m_col = 0;
+
+ m_prgmcr[11].m_chwFirst = 117; // u: mcVou
+ m_prgmcr[11].m_chwLast = 117;
+ m_prgmcr[11].m_col = 3;
+
+ m_prgmcr[12].m_chwFirst = 118; // v - z: mcCons
+ m_prgmcr[12].m_chwLast = 122;
+ m_prgmcr[12].m_col = 0;
+
+ m_prgmcr[13].m_chwFirst = 126; // tilde: mcDct
+ m_prgmcr[13].m_chwLast = 126;
+ m_prgmcr[13].m_col = 6;
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 11;
+ m_crowNonAcpt = 4;
+ m_crowFinal = 6;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 7;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[35]; // 35 = (m_crow-m_crowFinal) * m_ccol
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 2; *psn++ = 4; *psn++ = 3; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 5; *psn++ = 6; *psn++ = 6;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =10; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 7; *psn++ = 8; *psn++ = 9;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[10]; // 10 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[7+1]; // 7 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s4: r3
+ m_prgrulnMatched[0] = 3;
+
+ m_prgirulnMin[1] = 1; // s5: r1, r2
+ m_prgrulnMatched[1] = 1;
+ m_prgrulnMatched[2] = 2;
+
+ m_prgirulnMin[2] = 3; // s6: r2
+ m_prgrulnMatched[3] = 2;
+
+ m_prgirulnMin[3] = 4; // s7: r1, r5
+ m_prgrulnMatched[4] = 1;
+ m_prgrulnMatched[5] = 5;
+
+ m_prgirulnMin[4] = 6; // s8: r4, r5
+ m_prgrulnMatched[6] = 4;
+ m_prgrulnMatched[7] = 5;
+
+ m_prgirulnMin[5] = 8; // s9: r5
+ m_prgrulnMatched[8] = 5;
+
+ m_prgirulnMin[6] = 9; // s10: r1
+ m_prgrulnMatched[9] = 1;
+
+ m_prgirulnMin[7] = 10;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ The "rule" does something silly: just inserts *'s--the number equals the number of the
+ rule.
+----------------------------------------------------------------------------------------------*/
+bool GrSubPass::RunSimpleFSMTest(GrTableManager * ptman, int ruln, GrSlotStream * psstrmInput,
+ GrSlotStream * psstrmOutput)
+{
+ int cslotMatched = (ruln == 3)? 2: 3;
+
+ GrSlotState * pslot0 = psstrmInput->Peek(0);
+
+ for (int islot = 0; islot < cslotMatched; islot++)
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ for (islot = 0; islot < ruln; islot++)
+ {
+ GrSlotState * pslot;
+ ptman->NewSlot('*', pslot0, NULL, m_ipass, &pslot);
+ pslot->Associate(pslot0);
+ psstrmOutput->NextPut(pslot);
+ }
+
+ return true;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ A simple set of rules with actions.
+
+ Rules:
+ r0. clsDigit gSlash clsDigit _ > @3 _ @1 gTilde; // tilde = 126
+ r1. _ clsDigit gBackSlash clsDigit > gDollar @4 _ @2; // dollar sign = 36
+
+ Machine classes:
+ mcDigit: '0' - '9' 48 - 57
+ mcSlash: '/' 47
+ mcBSlash: '\' 92
+
+
+ FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | clsDig mcSlash mcBSlash
+ ------------------------------------------------------
+ T NA s0 | s1
+ | - - -
+ T NA s1 | s2 s3
+ | - - -
+ T NA s2 | s4
+ | - - -
+ T NA s3 | s5
+ | - - -
+ F A s4 |
+ | - - -
+ F A s5 |
+ | - - -
+
+ Rules Matched:
+ s4: r0
+ s5: r1
+
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpRuleActionTest()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpRuleActionTest();
+}
+
+void GrClassTable::SetUpRuleActionTest()
+{
+ m_ccls = 2; // number of classes
+ m_cclsLinear = 2; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new data16[100];
+
+ m_prgichwOffsets = new data16[2+1];
+
+ gid16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: tilde
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(126)); // '~'
+
+ // Output class 1: dollar
+ m_prgichwOffsets[1] = 1;
+ *pchw++ = msbf(data16(36)); // '$'
+
+ m_prgichwOffsets[2] = 2;
+}
+
+void GrSubPass::SetUpRuleActionTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "RuleAction";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpRuleActionTest();
+
+ m_crul = 2;
+
+ // Set up constraint code--succeed trivially.
+ m_prgbConstraintBlock = new byte[3];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopPushByte; *pb++ = 1; // Push true
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[30];
+ pb = m_prgbActionBlock;
+
+ // Rule 1: clsDigit gSlash clsDigit _ > @3 _ @1 gTilde;
+
+ *pb++ = kopPutCopy; *pb++ = 2; // PutCopy 2
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutCopy; *pb++ = -2; // PutCopy -2
+ *pb++ = kopNext; // Next
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 0; // PutGlyph 0 ('~' = 126)
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopPopRet; // PopAndRet
+
+ // Rule 2: _ clsDigit gBackSlash clsDigit > gDollar @4 _ @2;
+
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 1; // PutGlyph 1 ('$' = 36)
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutCopy; *pb++ = 2; // PutCopy 2
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutCopy; *pb++ = -2; // PutCopy -2
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 15;
+}
+
+void GrFSM::SetUpRuleActionTest()
+{
+ // Create machine class ranges.
+ m_cmcr = 3;
+ m_prgmcr = new GrFSMClassRange[3];
+ m_prgmcr[0].m_chwFirst = 47; // forward slash: mcSlash
+ m_prgmcr[0].m_chwLast = 47;
+ m_prgmcr[0].m_col = 1;
+
+ m_prgmcr[1].m_chwFirst = 48; // 0 - 9: mcDigit
+ m_prgmcr[1].m_chwLast = 57;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 92; // backslash
+ m_prgmcr[2].m_chwLast = 92;
+ m_prgmcr[2].m_col = 2;
+
+
+ m_dimcrInit = 2; // (max power of 2 <= m_cmcr);
+ m_cLoop = 1; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 6;
+ m_crowNonAcpt = 4;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 3;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[12]; // 12 = (m_crow-m_crowFinal) * m_ccol
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 2; *psn++ = 3;
+ *psn++ = 4; *psn++ = 0; *psn++ = 0;
+ *psn++ = 5; *psn++ = 0; *psn++ = 0;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[2]; // 2 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[2+1]; // 2 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s4: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s5: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2;
+}
+
+/*----------------------------------------------------------------------------------------------
+ A more complicated set of rules with actions.
+
+ PASS 1:
+ r0. clsDigit > @1 {dir = DIR_RIGHT} / ^ _ {dir == DIR_LEFT};
+ r1. clsSpecial > @2 {dir = DIR_ARABNUMBER} / clsDigit {dir != DIR_LEFT} ^ _;
+ r2. clsSpecial > @2 {dir = @1.dir} / clsSpecial ^ _;
+
+ Pass 1 machine classes:
+ mcDigit: '0' - '9' 48 - 57
+ mcSpecial: '-', '_', '=', '~' 45, 95, 61, 126
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcDigit mcSpecial
+ ------------------------------------------
+ T NA s0 | s2 s1
+ | - _
+ T NA s1 | s4
+ | - -
+ T A s2 | s3
+ | - -
+ F A s3 |
+ | - -
+ F A s4 |
+ | - -
+
+ Rules Matched:
+ s2: r0
+ s3: r1
+ s4: r2
+
+ PASS 2:
+ r0. clsVowel gCaret > clsCirumVowel _;
+ r1. clsVowel gSlash > _ clsAcuteVowel$1;
+
+ Pass 2 machine classes:
+ mcVowel
+ mcCaret: '^' 94
+ mcSlash: '/' 47
+
+
+ Pass 2 FSM:
+ | mcVowel mcCaret mcSlash
+ -----------------------------------------------------
+ T NA s0 | s1
+ | - _
+ T NA s1 | s2 s3
+ | - -
+ F A s2 |
+ | - -
+ F A s3 |
+ | - -
+
+ Rules matched:
+ s2: r0
+ s3: r1
+
+
+ PASS 3:
+ r0. clsLeft > clsRight {dir = @1.dir} / _ clsDir {dir==DIR_RIGHT};
+ r1. clsRight > clsLeft {dir = @1.dir} / clsDir {dir==DIR_RIGHT} _;
+
+ Pass 3 machine classes:
+ mcDir: (clsDigit, clsSpecial)
+ mcLeft: '(', '[', '{' 40, 91, 123
+ mcRight: ')', ']', '}' 41, 93, 125
+
+ Pass 3 FSM:
+ | mcDir mcLeft mcRight
+ -----------------------------------------------------
+ T NA s0 | s2 s1
+ | - _
+ T NA s1 | s3
+ | - -
+ T NA s2 | s4
+ | - -
+ F A s3 |
+ | - -
+ F A s4 |
+ | - -
+
+ Rules matched:
+ s3: r0
+ s4: r1
+
+
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpRuleAction2Test()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpRuleAction2Test();
+}
+
+void GrClassTable::SetUpRuleAction2Test()
+{
+ m_ccls = 7; // number of classes
+ m_cclsLinear = 4; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new data16[70];
+
+ m_prgichwOffsets = new data16[7+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: clsCirumVowel
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(226)); // a
+ *pchw++ = msbf(data16(234)); // e
+ *pchw++ = msbf(data16(238)); // i
+ *pchw++ = msbf(data16(244)); // o
+ *pchw++ = msbf(data16(251)); // u
+ *pchw++ = msbf(data16(194)); // A
+ *pchw++ = msbf(data16(202)); // E
+ *pchw++ = msbf(data16(206)); // I
+ *pchw++ = msbf(data16(212)); // O
+ *pchw++ = msbf(data16(219)); // U
+
+ // Output class 1: clsAcuteVowel
+ m_prgichwOffsets[1] = 10;
+ *pchw++ = msbf(data16(225)); // a
+ *pchw++ = msbf(data16(233)); // e
+ *pchw++ = msbf(data16(237)); // i
+ *pchw++ = msbf(data16(243)); // o
+ *pchw++ = msbf(data16(250)); // u
+ *pchw++ = msbf(data16(193)); // A
+ *pchw++ = msbf(data16(201)); // E
+ *pchw++ = msbf(data16(205)); // I
+ *pchw++ = msbf(data16(211)); // O
+ *pchw++ = msbf(data16(218)); // U
+
+ // Output class 2: clsLeft
+ m_prgichwOffsets[2] = 10 + 10;
+ *pchw++ = msbf(data16(40)); // (
+ *pchw++ = msbf(data16(91)); // [
+ *pchw++ = msbf(data16(123)); // {
+
+ // Output class 3: clsRight
+ m_prgichwOffsets[3] = 20 + 3;
+ *pchw++ = msbf(data16(41)); // )
+ *pchw++ = msbf(data16(93)); // ]
+ *pchw++ = msbf(data16(125)); // }
+
+ // Input class 4: clsVowel
+ m_prgichwOffsets[4] = 23 + 3; // 26
+ *pchw++ = msbf(data16(10));
+ *pchw++ = msbf(data16(8)); *pchw++ = msbf(data16(3)); *pchw++ = msbf(data16(10-8));
+ *pchw++ = msbf(data16(65)); *pchw++ = msbf(data16(5)); // A
+ *pchw++ = msbf(data16(69)); *pchw++ = msbf(data16(6)); // E
+ *pchw++ = msbf(data16(73)); *pchw++ = msbf(data16(7)); // I
+ *pchw++ = msbf(data16(79)); *pchw++ = msbf(data16(8)); // O
+ *pchw++ = msbf(data16(85)); *pchw++ = msbf(data16(9)); // U
+ *pchw++ = msbf(data16(97)); *pchw++ = msbf(data16(0)); // a
+ *pchw++ = msbf(data16(101)); *pchw++ = msbf(data16(1)); // e
+ *pchw++ = msbf(data16(105)); *pchw++ = msbf(data16(2)); // i
+ *pchw++ = msbf(data16(111)); *pchw++ = msbf(data16(3)); // o
+ *pchw++ = msbf(data16(117)); *pchw++ = msbf(data16(4)); // u
+
+ // Input class 5: clsLeft
+ m_prgichwOffsets[5] = 26 + 4 + 10*2; // 50
+ *pchw++ = msbf(data16(3));
+ *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(3-2));
+ *pchw++ = msbf(data16(40)); *pchw++ = msbf(data16(0)); // (
+ *pchw++ = msbf(data16(91)); *pchw++ = msbf(data16(1)); // [
+ *pchw++ = msbf(data16(123)); *pchw++ = msbf(data16(2)); // {
+
+ // Input class 6: clsRight
+ m_prgichwOffsets[6] = 50 + 4 + 3*2; // 60
+ *pchw++ = msbf(data16(3));
+ *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(3-2));
+ *pchw++ = msbf(data16(41)); *pchw++ = msbf(data16(0)); // )
+ *pchw++ = msbf(data16(93)); *pchw++ = msbf(data16(1)); // ]
+ *pchw++ = msbf(data16(125)); *pchw++ = msbf(data16(2)); // }
+
+ m_prgichwOffsets[7] = 60 + 4 + 3*2; // 70
+}
+
+void GrSubPass::SetUpRuleAction2Test()
+{
+ if (m_ipass == 1)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "RuleAction2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpRuleAction2Test(m_ipass);
+
+ m_crul = 3;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 10 + 10];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ *pb++ = kopCntxtItem; *pb++ = 0; // ContextItem 0
+ *pb++ = kopPushSlotAttr; *pb++= kslatDir; // PushSlotAttr dir 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = kdircL; // Push DIR_LEFT
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ *pb++ = kopCntxtItem; *pb++ = 0; // ContextItem 0
+ *pb++ = kopPushSlotAttr; *pb++= kslatDir; // PushSlotAttr dir 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = kdircL; // Push DIR_LEFT
+ *pb++ = kopNotEq; // NotEqual
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 1;
+ m_prgibConstraintStart[1] = 11;
+ m_prgibConstraintStart[2] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[10 + 11 + 12];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsDigit > @1 {dir = DIR_RIGHT} / ^ _ {dir == DIR_LEFT};
+
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopPushByte; *pb++ = kdircR; // PushByte DIR_RIGHT
+ *pb++ = kopAttrSet; *pb++ = kslatDir; // AttrSet dir
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = -1; // Push -1
+ *pb++ = kopPopRet; // PopAndRet
+
+ // Rule 1: clsSpecial > @2 {dir = DIR_ARABNUMBER} / clsDigit {dir != DIR_LEFT} ^ _;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopPushByte; *pb++ = kdircArabNum; // Push DIR_ARABNUMBER
+ *pb++ = kopAttrSet; *pb++ = kslatDir; // AttrSet dir
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = -1; // Push -1
+ *pb++ = kopPopRet; // PopAndRet
+
+ // Rule 2: clsSpecial > @2 {dir = @1.dir} / clsSpecial ^ _;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopPushSlotAttr;*pb++ = kslatDir; // PushSlotAttr dir -1
+ *pb++ = -1;
+ *pb++ = kopAttrSet; *pb++ = kslatDir; // AttrSet dir
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = -1; // Push -1
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 10;
+ m_prgibActionStart[2] = 10 + 11;
+ }
+ else if (m_ipass == 2)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 3;
+ m_staBehavior = "RuleAction2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpRuleAction2Test(m_ipass);
+
+ m_crul = 2;
+
+ // Set up constraint code--succeed trivially.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[16];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsVowel gCaret > clsCirumVowel _;
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 clsVowel clsCircumVowel
+ *pb++ = 4; *pb++ = 0;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: clsVowel gSlash > _ clsAcuteVowel$1;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutSubs8bitObs; *pb++ = -1; // PutSubs -1 clsVowel clsAcuteVowel
+ *pb++ = 4; *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 8;
+ }
+ else if (m_ipass == 3)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 3;
+ m_staBehavior = "RuleAction2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpRuleAction2Test(m_ipass);
+
+ m_crul = 2;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 10 + 10];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ *pb++ = kopCntxtItem; *pb++ = 1; // ContextItem 1
+ *pb++ = kopPushSlotAttr;*pb++ = kslatDir; // PushSlotAttr dir 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = kdircR; // Push DIR_RIGHT
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ *pb++ = kopCntxtItem; *pb++ = 0; // ContextItem 0
+ *pb++ = kopPushSlotAttr;*pb++ = kslatDir; // PushSlotAttr dir 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = kdircR; // Push DIR_RIGHT
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 1;
+ m_prgibConstraintStart[1] = 1 + 10;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[23];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsLeft > clsRight {dir = @1.dir} / _ clsDir {dir == DIR_RIGHT};
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 clsLeft clsRight
+ *pb++ = 5; *pb++ = 3;
+ *pb++ = kopPushSlotAttr;*pb++ = kslatDir; // PushSlotAttr dir 1
+ *pb++ = 1;
+ *pb++ = kopAttrSet; *pb++ = kslatDir; // AttrSet dir
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: clsRight > clsLeft {dir = @1.dir} / clsDir {dir == DIR_RIGHT} _;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 clsRight clsLeft
+ *pb++ = 6; *pb++ = 2;
+ *pb++ = kopPushSlotAttr;*pb++ = kslatDir; // PushSlotAttr dir -1
+ *pb++ = -1;
+ *pb++ = kopAttrSet; *pb++ = kslatDir; // AttrSet dir
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 11;
+ }
+}
+
+
+void GrFSM::SetUpRuleAction2Test(int ipass)
+{
+ if (ipass == 1)
+ {
+ // Create machine class ranges.
+ m_cmcr = 5;
+ m_prgmcr = new GrFSMClassRange[5];
+ m_prgmcr[0].m_chwFirst = 45; // hyphen
+ m_prgmcr[0].m_chwLast = 45;
+ m_prgmcr[0].m_col = 1;
+
+ m_prgmcr[1].m_chwFirst = 48; // 0 - 9: mcDigit
+ m_prgmcr[1].m_chwLast = 57;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 61; // equals sign
+ m_prgmcr[2].m_chwLast = 61;
+ m_prgmcr[2].m_col = 1;
+
+ m_prgmcr[3].m_chwFirst = 95; // underscore
+ m_prgmcr[3].m_chwLast = 95;
+ m_prgmcr[3].m_col = 1;
+
+ m_prgmcr[4].m_chwFirst = 126; // tilde
+ m_prgmcr[4].m_chwLast = 126;
+ m_prgmcr[4].m_col = 1;
+
+ m_dimcrInit = 4; // (max power of 2 <= m_cmcr);
+ m_cLoop = 2; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 5;
+ m_crowNonAcpt = 2;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 2;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[6]; // 6 = (m_crow-m_crowFinal) * m_ccol
+ short * psn = m_prgrowTransitions;
+ *psn++ = 2; *psn++ = 1;
+ *psn++ = 0; *psn++ = 4;
+ *psn++ = 0; *psn++ = 3;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[3]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[3+1]; // 3 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s2: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s3: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2; // s3: r2
+ m_prgrulnMatched[2] = 2;
+
+ m_prgirulnMin[3] = 3;
+ }
+ else if (ipass == 2)
+ {
+ // Create machine class ranges.
+ m_cmcr = 12;
+ m_prgmcr = new GrFSMClassRange[12];
+ m_prgmcr[0].m_chwFirst = 47; // slash
+ m_prgmcr[0].m_chwLast = 47;
+ m_prgmcr[0].m_col = 2;
+
+ m_prgmcr[1].m_chwFirst = 65; // A
+ m_prgmcr[1].m_chwLast = 65;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 69; // E
+ m_prgmcr[2].m_chwLast = 69;
+ m_prgmcr[2].m_col = 0;
+
+ m_prgmcr[3].m_chwFirst = 73; // I
+ m_prgmcr[3].m_chwLast = 73;
+ m_prgmcr[3].m_col = 0;
+
+ m_prgmcr[4].m_chwFirst = 79; // O
+ m_prgmcr[4].m_chwLast = 79;
+ m_prgmcr[4].m_col = 0;
+
+ m_prgmcr[5].m_chwFirst = 85; // U
+ m_prgmcr[5].m_chwLast = 85;
+ m_prgmcr[5].m_col = 0;
+
+ m_prgmcr[6].m_chwFirst = 94; // caret
+ m_prgmcr[6].m_chwLast = 94;
+ m_prgmcr[6].m_col = 1;
+
+ m_prgmcr[7].m_chwFirst = 97; // a
+ m_prgmcr[7].m_chwLast = 97;
+ m_prgmcr[7].m_col = 0;
+
+ m_prgmcr[8].m_chwFirst = 101; // e
+ m_prgmcr[8].m_chwLast = 101;
+ m_prgmcr[8].m_col = 0;
+
+ m_prgmcr[9].m_chwFirst = 105; // i
+ m_prgmcr[9].m_chwLast = 105;
+ m_prgmcr[9].m_col = 0;
+
+ m_prgmcr[10].m_chwFirst = 111; // o
+ m_prgmcr[10].m_chwLast = 111;
+ m_prgmcr[10].m_col = 0;
+
+ m_prgmcr[11].m_chwFirst = 117; // u
+ m_prgmcr[11].m_chwLast = 117;
+ m_prgmcr[11].m_col = 0;
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 4;
+ m_crowNonAcpt = 2;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 3;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[6]; // 6 = (m_crow-m_crowFinal) * m_ccol
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 2; *psn++ = 3;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[2]; // 2 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[2+1]; // 2 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s1: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s2: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2;
+ }
+ else if (ipass == 3)
+ {
+ // Create machine class ranges.
+ m_cmcr = 11;
+ m_prgmcr = new GrFSMClassRange[11];
+ m_prgmcr[0].m_chwFirst = 40; // (
+ m_prgmcr[0].m_chwLast = 40;
+ m_prgmcr[0].m_col = 1;
+
+ m_prgmcr[1].m_chwFirst = 41; // )
+ m_prgmcr[1].m_chwLast = 41;
+ m_prgmcr[1].m_col = 2;
+
+ m_prgmcr[2].m_chwFirst = 45; // hyphen
+ m_prgmcr[2].m_chwLast = 45;
+ m_prgmcr[2].m_col = 0;
+
+ m_prgmcr[3].m_chwFirst = 48; // 0 - 9: mcDigit
+ m_prgmcr[3].m_chwLast = 57;
+ m_prgmcr[3].m_col = 0;
+
+ m_prgmcr[4].m_chwFirst = 61; // =
+ m_prgmcr[4].m_chwLast = 61;
+ m_prgmcr[4].m_col = 0;
+
+ m_prgmcr[5].m_chwFirst = 91; // [
+ m_prgmcr[5].m_chwLast = 91;
+ m_prgmcr[5].m_col = 1;
+
+ m_prgmcr[6].m_chwFirst = 93; // ]
+ m_prgmcr[6].m_chwLast = 93;
+ m_prgmcr[6].m_col = 2;
+
+ m_prgmcr[7].m_chwFirst = 95; // underscore
+ m_prgmcr[7].m_chwLast = 95;
+ m_prgmcr[7].m_col = 0;
+
+ m_prgmcr[8].m_chwFirst = 123; // {
+ m_prgmcr[8].m_chwLast = 123;
+ m_prgmcr[8].m_col = 1;
+
+ m_prgmcr[9].m_chwFirst = 125; // }
+ m_prgmcr[9].m_chwLast = 125;
+ m_prgmcr[9].m_col = 2;
+
+ m_prgmcr[10].m_chwFirst = 126; // tilde
+ m_prgmcr[10].m_chwLast = 126;
+ m_prgmcr[10].m_col = 0;
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 5;
+ m_crowNonAcpt = 3;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 3;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[9]; // 9 = (m_crow-m_crowFinal) * m_ccol
+ short * psn = m_prgrowTransitions;
+ *psn++ = 2; *psn++ = 1; *psn++ = 0;
+ *psn++ = 3; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 4;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[2]; // 2 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[2+1]; // 2 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s3: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s4: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2;
+ }
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Tests of various kinds of assocations.
+
+ PASS 1 (line-break):
+ r0. gX / # _ ^ ; // do nothing
+ r1. gX {break = -2};
+
+ Pass 1 machine classes:
+ mcX: 'x' 120
+ mcLB: 35
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | gX gLB
+ --------------------------------
+ T NA s0 | s2 s1
+ |
+ T NA s1 | s3
+ |
+ F A s2 |
+ |
+ F A s3 |
+
+
+ Rules Matched:
+ s2: r1
+ s3: r0
+
+
+
+ PASS 2:
+ r0. clsOA clsE > clsELig:(1 2) _;
+ r1. clsLC _ _ gX > @1 @5 @1 @5 / _ _ # {break==2} _ _ ;
+ r2. _ clsFraction _ > clsNumerator:2 gSlash:2 clsDenom:2;
+
+ Pass 2 machine classes:
+ mcOA: O A 79 65
+ mcOAlc: o a 111 97
+ mcE E e 69 101
+ mcFraction: 188 189 190
+ mcX: x 120
+ mcLCother
+ mcLB: 35
+
+
+ Pass 2 FSM: mcLC
+ | mcOA mcOAlc mcE mcElc other mcX mcFractn mcLB
+ -----------------------------------------------------------------------------------------
+ T NA s0 | s1 s2 s4 s3 s3 s6
+ | - - - - - - -
+ T NA s1 | s7
+ | - - - - - - -
+ T NA s2 | s7 s5
+ | - - - - - - -
+ T NA s3 | s5
+ | - - - - - - -
+ T NA s4 | s5
+ | - - - - - - -
+ T NA s5 | s8
+ | - - - - - - -
+ F A s6 |
+ | - - - - - -
+ F A s7 |
+ | - - - - - -
+ F A s8 |
+ | - - - - - -
+
+ Rules matched:
+ s6: r2
+ s7: r0
+ s8: r1
+
+
+ PASS 3:
+ r0. _ > gHyphen / _ # {break == 2} ^;
+
+ Pass 3 machine classes:
+ mcLB: 35
+
+ Pass 3 FSM:
+
+ | gLB
+ --------------------------------
+ T NA s0 | s1
+ |
+ F A s1 |
+ |
+
+ Rules Matched:
+ s1: r0
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpAssocTest()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpAssocTest();
+
+ m_fLineBreak = true;
+ m_cchwPreXlbContext = 1;
+ m_cchwPostXlbContext = 1;
+}
+
+void GrClassTable::SetUpAssocTest()
+{
+ m_ccls = 11; // number of classes
+ m_cclsLinear = 5; // number of classes in linear format (output classes)
+
+ m_prgchwBIGGlyphList = new data16[143];
+
+ m_prgichwOffsets = new data16[m_ccls+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: clsELig
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(140)); // OE
+ *pchw++ = msbf(data16(198)); // AE
+ *pchw++ = msbf(data16(156)); // oe
+ *pchw++ = msbf(data16(230)); // ae
+
+ // Output class 1: clsNumerator
+ m_prgichwOffsets[1] = 4;
+ *pchw++ = msbf(data16(49)); // 1
+ *pchw++ = msbf(data16(49)); // 1
+ *pchw++ = msbf(data16(51)); // 3
+
+ // Output class 2: clsDenom
+ m_prgichwOffsets[2] = 4 + 3;
+ *pchw++ = msbf(data16(52)); // 4
+ *pchw++ = msbf(data16(50)); // 2
+ *pchw++ = msbf(data16(52)); // 4
+
+ // Output class 3: gSlash
+ m_prgichwOffsets[3] = 7 + 3;
+ *pchw++ = msbf(data16(47)); // '/'
+
+ // Output class 4: gHyphen
+ m_prgichwOffsets[4] = 10 + 1;
+ *pchw++ = msbf(data16(45)); // '-'
+
+ // Input class 5: clsOA
+ m_prgichwOffsets[5] = 11 + 1;
+ *pchw++ = msbf(data16(4));
+ *pchw++ = msbf(data16(4)); *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(0));
+ *pchw++ = msbf(data16(65)); *pchw++ = msbf(data16(1)); // A
+ *pchw++ = msbf(data16(79)); *pchw++ = msbf(data16(0)); // O
+ *pchw++ = msbf(data16(97)); *pchw++ = msbf(data16(3)); // a
+ *pchw++ = msbf(data16(111)); *pchw++ = msbf(data16(2)); // o
+
+ // Input class 6: clsE
+ m_prgichwOffsets[6] = 12 + 4 + 4*2; // 24
+ *pchw++ = msbf(data16(3));
+ *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(3-2));
+ *pchw++ = msbf(data16(40)); *pchw++ = msbf(data16(0)); // E
+ *pchw++ = msbf(data16(91)); *pchw++ = msbf(data16(1)); // e
+
+ // Input class 7: clsLC
+ m_prgichwOffsets[7] = 24 + 4 + 2*2; // 32
+ *pchw++ = msbf(data16(26));
+ *pchw++ = msbf(data16(16)); *pchw++ = msbf(data16(4)); *pchw++ = msbf(data16(26-16));
+ for (int i = 0; i < 26; ++i)
+ {
+ *pchw++ = msbf(data16(97+i)); *pchw++ = msbf(data16(i));
+ }
+
+ // Input class 8: gX
+ m_prgichwOffsets[8] = 32 + 4 + 26*2; // 88
+ *pchw++ = msbf(data16(1));
+ *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(0)); *pchw++ = msbf(data16(0));
+ *pchw++ = msbf(data16(120)); *pchw++ = msbf(data16(0));
+
+ // Input class 9: clsFraction
+ m_prgichwOffsets[9] = 88 + 4 + 1*2; // 127
+ *pchw++ = msbf(data16(3));
+ *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(3-2));
+ *pchw++ = msbf(data16(188)); *pchw++ = msbf(data16(0)); // 1/4
+ *pchw++ = msbf(data16(189)); *pchw++ = msbf(data16(1)); // 1/2
+ *pchw++ = msbf(data16(190)); *pchw++ = msbf(data16(2)); // 3/4
+
+ // Input class 10: #
+ m_prgichwOffsets[10] = 127 + 4 + 3*2; // 137
+ *pchw++ = msbf(data16(1));
+ *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(0)); *pchw++ = msbf(data16(0));
+ *pchw++ = msbf(data16(35)); *pchw++ = msbf(data16(0)); // 1/4
+
+ m_prgichwOffsets[11] = 137 + 4 + 1*2; // 143
+}
+
+void GrLineBreakPass::SetUpAssocTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Assoc";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpAssocTest(m_ipass);
+
+ m_crul = 2;
+
+ // Set up constraint code--succeed trivially.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[7 + 8];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: gX / # _ ^ ; // do nothing
+
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: gX {break = -2};
+
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopPushByte; *pb++ = -2; // PushByte -2
+ *pb++ = kopAttrSet; *pb++ = kslatBreak; // AttrSet breakweight
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 7;
+}
+
+void GrSubPass::SetUpAssocTest()
+{
+ if (m_ipass == 2)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Assoc";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpAssocTest(m_ipass);
+
+ m_crul = 3;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 10];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ *pb++ = kopCntxtItem; *pb++ = 1; // ContextItem 1
+ *pb++ = kopPushSlotAttr;*pb++ = kslatBreak; // PushSlotAttr break 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = 2; // Push 2
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 1;
+ m_prgibConstraintStart[2] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[12 + 12 + 22];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsOA clsE > clsELig:(1 2) _ ;
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 clsOA clsELig
+ *pb++ = 5; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 2; // Assoc 2 0 1
+ *pb++ = 0; *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: clsLC _ _ gX > @1 @5 @1 @5 / _ _ # {break==2} _ _ ;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = 2; // PutCopy 2
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext - line break
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = -1; // PutCopy -1
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 2: _ clsFraction _ > clsNumerator:2 gSlash:2 clsDenom:2;
+
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = 1; // PutSubs 1 clsFraction clsNumerator
+ *pb++ = 9; *pb++ = 1;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 1
+ *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 3; // PutGlyph gSlash
+ *pb++ = kopNext; // Next
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 clsFraction clsDenom
+ *pb++ = 9; *pb++ = 2;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 0
+ *pb++ = 0;
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 12;
+ m_prgibActionStart[2] = 12 + 12;
+ }
+ else if (m_ipass == 3)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 3;
+ m_staBehavior = "Assoc";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpAssocTest(m_ipass);
+
+ m_crul = 1;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 10];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ *pb++ = kopCntxtItem; *pb++ = 0; // ContextItem 0
+ *pb++ = kopPushSlotAttr;*pb++ = kslatBreak; // PushSlotAttr break 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = 2; // Push 2
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 1;
+
+ m_prgbActionBlock = new byte[7];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: _ > gHyphen / _ # {break == 2} ^;
+
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 4; // PutGlyph 4 ('-' = 45)
+ *pb++ = kopNext; // Next
+ *pb++ = kopPushByte; *pb++ = 1; // Push 1
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ }
+ else
+ Assert(false);
+}
+
+
+void GrFSM::SetUpAssocTest(int ipass)
+{
+ if (ipass == 1)
+ {
+ // Create machine class ranges.
+ m_cmcr = 2;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 35; // #
+ m_prgmcr[0].m_chwLast = 35;
+ m_prgmcr[0].m_col = 1;
+
+ m_prgmcr[1].m_chwFirst = 120; // x
+ m_prgmcr[1].m_chwLast = 120;
+ m_prgmcr[1].m_col = 0;
+
+ m_dimcrInit = 2; // (max power of 2 <= m_cmcr);
+ m_cLoop = 1; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 4;
+ m_crowNonAcpt = 2;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 2;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 4
+ short * psn = m_prgrowTransitions;
+ *psn++ = 2; *psn++ = 1;
+ *psn++ = 3; *psn++ = 0;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[2]; // 2 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s2: r1
+ m_prgrulnMatched[0] = 1;
+
+ m_prgirulnMin[1] = 1; // s3: r0
+ m_prgrulnMatched[1] = 0;
+
+ m_prgirulnMin[2] = 2;
+ }
+ else if (ipass == 2)
+ {
+ // Create machine class ranges.
+ m_cmcr = 13;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 35; // #
+ m_prgmcr[0].m_chwLast = 35;
+ m_prgmcr[0].m_col = 7;
+
+ m_prgmcr[1].m_chwFirst = 65; // A
+ m_prgmcr[1].m_chwLast = 65;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 69; // E
+ m_prgmcr[2].m_chwLast = 69;
+ m_prgmcr[2].m_col = 2;
+
+ m_prgmcr[3].m_chwFirst = 79; // O
+ m_prgmcr[3].m_chwLast = 79;
+ m_prgmcr[3].m_col = 0;
+
+ m_prgmcr[4].m_chwFirst = 97; // a
+ m_prgmcr[4].m_chwLast = 97;
+ m_prgmcr[4].m_col = 1;
+
+ m_prgmcr[5].m_chwFirst = 98; // b - d
+ m_prgmcr[5].m_chwLast = 100;
+ m_prgmcr[5].m_col = 4;
+
+ m_prgmcr[6].m_chwFirst = 101; // e
+ m_prgmcr[6].m_chwLast = 101;
+ m_prgmcr[6].m_col = 3;
+
+ m_prgmcr[7].m_chwFirst = 102; // f - n
+ m_prgmcr[7].m_chwLast = 110;
+ m_prgmcr[7].m_col = 4;
+
+ m_prgmcr[8].m_chwFirst = 111; // o
+ m_prgmcr[8].m_chwLast = 111;
+ m_prgmcr[8].m_col = 1;
+
+ m_prgmcr[9].m_chwFirst = 112; // p - w
+ m_prgmcr[9].m_chwLast = 119;
+ m_prgmcr[9].m_col = 4;
+
+ m_prgmcr[10].m_chwFirst = 120; // x
+ m_prgmcr[10].m_chwLast = 120;
+ m_prgmcr[10].m_col = 5;
+
+ m_prgmcr[11].m_chwFirst = 121; // y - z
+ m_prgmcr[11].m_chwLast = 122;
+ m_prgmcr[11].m_col = 4;
+
+ m_prgmcr[12].m_chwFirst = 188; // 1/4, 1/2, 3/4
+ m_prgmcr[12].m_chwLast = 190;
+ m_prgmcr[12].m_col = 6;
+
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 9;
+ m_crowNonAcpt = 6;
+ m_crowFinal = 3;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 8;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 48
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 2; *psn++ = 0; *psn++ = 4; *psn++ = 3; *psn++ = 3; *psn++ = 6; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 7; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 7; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 5;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 5;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 5;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 8; *psn++ = 0; *psn++ = 0;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[3]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[3+1]; // 3 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s6: r2
+ m_prgrulnMatched[0] = 2;
+
+ m_prgirulnMin[1] = 1; // s7: r0
+ m_prgrulnMatched[1] = 0;
+
+ m_prgirulnMin[2] = 2; // s8: r1
+ m_prgrulnMatched[2] = 1;
+
+ m_prgirulnMin[3] = 3;
+ }
+ else if (ipass == 3)
+ {
+ // Create machine class ranges.
+ m_cmcr = 1;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 35; // #
+ m_prgmcr[0].m_chwLast = 35;
+ m_prgmcr[0].m_col = 0;
+
+ m_dimcrInit = 1; // (max power of 2 <= m_cmcr);
+ m_cLoop = 0; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 2;
+ m_crowNonAcpt = 1;
+ m_crowFinal = 1;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 1;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 1
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[1]; // 1 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s1: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1;
+ }
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Second batch of association tests.
+
+ PASS 1:
+ r0. clsSymbol _ > _ @1 / _ gNumber gHyphen # gNumber _;
+ r1. clsSymbol _ > _ @1 / _ gHyphen # _;
+ r2. _ clsSymbol > @6 _ / _ gNumber gHyphen # gNumber _;
+ r3. _ clsSymbol > @4 _ / _ gHyphen # _;
+ r4. clsLeft _ > @1 clsRight$1:1 / _ clsLetter gHyphen # _ gSpace;
+ r5. clsLeft _ > @1 clsRight$1:1 / _ clsLetter gHyphen # clsLetter _ gSpace;
+ r6. clsLeft _ > @1 clsRight$1:1 / _ clsLetter _ gSpace;
+ r7. clsLeft _ > @1 clsRight$1:1 / _ clsLetter clsLetter _ gSpace;
+
+ Pass 1 machine classes:
+ mcSym: @, $, %, & 64, 36, 37, 38
+ mcNum: 48-57
+ mcHyphen: 45
+ mcSpace: 32
+ mcLet: 97-122
+ mcLeft: ( [ { 40, 91, 123
+ mcRight: ) ] } 41, 93, 125
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcSym mcNum mcHyph mcSpace mcLet mcLeft mcLB
+ ----------------------------------------------------------------------------------
+ T NA s0 | s1 s2 s3 s4
+ |
+ T NA s1 | s5 s6
+ |
+ T NA s2 | s7
+ |
+ T NA s3 | s8
+ |
+ T NA s4 | s9
+ |
+ T NA s5 | s10
+ |
+ T NA s6 | s18
+ |
+ T NA s7 | s11
+ |
+ T NA s8 | s19
+ |
+ T NA s9 | s12 s20 s13
+ |
+ T NA s10 | s14
+ |
+ T NA s11 | s15
+ |
+ T NA s12 | s16
+ |
+ T NA s13 | s21
+ |
+ T NA s14 | s22
+ |
+ T NA s15 | s23
+ |
+ T NA s16 | s24 s17
+ |
+ T NA s17 | s25
+ |
+ F A s18 |
+ |
+ F A s19 |
+ |
+ F A s20 |
+ |
+ F A s21 |
+ |
+ F A s22 |
+ |
+ F A s23 |
+ |
+ F A s24 |
+ |
+ F A s25 |
+
+
+ Rules Matched:
+ s18: r1
+ s19: r3
+ s20: r6
+ s21: r7
+ s22: r0
+ s23: r2
+ s24: r4
+ s25: r5
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpAssoc2Test()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpAssoc2Test();
+
+ m_fLineBreak = true;
+ m_cchwPreXlbContext = 3;
+ m_cchwPostXlbContext = 2;
+}
+
+void GrClassTable::SetUpAssoc2Test()
+{
+ m_ccls = 2; // number of classes
+ m_cclsLinear = 1; // number of classes in linear format (output classes)
+
+ m_prgchwBIGGlyphList = new data16[13];
+
+ m_prgichwOffsets = new data16[m_ccls+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: clsRight
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(41)); // )
+ *pchw++ = msbf(data16(93)); // ]
+ *pchw++ = msbf(data16(125)); // }
+
+ // Input class 1: clsLeft
+ m_prgichwOffsets[1] = 3;
+ *pchw++ = msbf(data16(3));
+ *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(1)); *pchw++ = msbf(data16(3-2));
+ *pchw++ = msbf(data16(40)); *pchw++ = msbf(data16(0)); // (
+ *pchw++ = msbf(data16(91)); *pchw++ = msbf(data16(1)); // [
+ *pchw++ = msbf(data16(123)); *pchw++ = msbf(data16(2)); // {
+
+ m_prgichwOffsets[2] = 3 + 4 + 3*2; // 13
+}
+
+void GrSubPass::SetUpAssoc2Test()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 6;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Assoc2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpAssoc2Test(m_ipass);
+
+ m_crul = 8;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+ m_prgibConstraintStart[2] = 0;
+ m_prgibConstraintStart[3] = 0;
+ m_prgibConstraintStart[4] = 0;
+ m_prgibConstraintStart[5] = 0;
+ m_prgibConstraintStart[6] = 0;
+ m_prgibConstraintStart[7] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[11 + 9 + 11 + 9 + 14 + 15 + 12 + 13];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsSymbol _ > _ @1 / _ gNumber gHyphen # gNumber _;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = -4; // PutCopy -4
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: clsSymbol _ > _ @1 / _ gHyphen # _;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = -2; // PutCopy -2
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 2: _ clsSymbol > @6 _ / _ gNumber gHyphen # gNumber _;
+
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = 5; // PutCopy 5
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 3: _ clsSymbol > @4 _ / _ gHyphen # _;
+
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutCopy; *pb++ = 3; // PutCopy 3
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 4: clsLeft _ > @1 clsRight$1 / _ clsLetter gHyphen # _ gSpace;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = -3; // PutSubs -3 1 0
+ *pb++ = 1; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 -3
+ *pb++ = -3;
+ *pb++ = kopNext; // Next;
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 5: clsLeft _ > @1 clsRight$1 / _ clsLetter gHyphen # clsLetter _ gSpace;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = -4; // PutSubs -4 1 0
+ *pb++ = 1; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 -4
+ *pb++ = -4;
+ *pb++ = kopNext; // Next;
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 6: clsLeft _ > @1 clsRight$1 / _ clsLetter _ gSpace;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = -1; // PutSubs -1 1 0
+ *pb++ = 1; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 -1
+ *pb++ = -1;
+ *pb++ = kopNext; // Next;
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 7: clsLeft _ > @1 clsRight$1 / _ clsLetter clsLetter _ gSpace;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutSubs8bitObs; *pb++ = -2; // PutSubs -2 1 0
+ *pb++ = 1; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 1; // Assoc 1 -2
+ *pb++ = -2;
+ *pb++ = kopNext; // Next;
+ *pb++ = kopRetZero; // RetZero
+
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 11;
+ m_prgibActionStart[2] = 11 + 9;
+ m_prgibActionStart[3] = 20 + 11;
+ m_prgibActionStart[4] = 31 + 9;
+ m_prgibActionStart[5] = 40 + 14;
+ m_prgibActionStart[6] = 54 + 15;
+ m_prgibActionStart[7] = 69 + 12;
+}
+
+
+void GrFSM::SetUpAssoc2Test(int ipass)
+{
+ // Create machine class ranges.
+ m_cmcr = 10;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 32; // space
+ m_prgmcr[0].m_chwLast = 32;
+ m_prgmcr[0].m_col = 3;
+
+ m_prgmcr[1].m_chwFirst = 35; // #
+ m_prgmcr[1].m_chwLast = 35;
+ m_prgmcr[1].m_col = 6;
+
+ m_prgmcr[2].m_chwFirst = 36; // $, %, &
+ m_prgmcr[2].m_chwLast = 38;
+ m_prgmcr[2].m_col = 0;
+
+ m_prgmcr[3].m_chwFirst = 40; // (
+ m_prgmcr[3].m_chwLast = 40;
+ m_prgmcr[3].m_col = 5;
+
+ m_prgmcr[4].m_chwFirst = 45; // -
+ m_prgmcr[4].m_chwLast = 45;
+ m_prgmcr[4].m_col = 2;
+
+ m_prgmcr[5].m_chwFirst = 48; // 0 - 9
+ m_prgmcr[5].m_chwLast = 57;
+ m_prgmcr[5].m_col = 1;
+
+ m_prgmcr[6].m_chwFirst = 64; // @
+ m_prgmcr[6].m_chwLast = 64;
+ m_prgmcr[6].m_col = 0;
+
+ m_prgmcr[7].m_chwFirst = 91; // [
+ m_prgmcr[7].m_chwLast = 91;
+ m_prgmcr[7].m_col = 5;
+
+ m_prgmcr[8].m_chwFirst = 97; // a - z
+ m_prgmcr[8].m_chwLast = 122;
+ m_prgmcr[8].m_col = 4;
+
+ m_prgmcr[9].m_chwFirst = 123; // {
+ m_prgmcr[9].m_chwLast = 123;
+ m_prgmcr[9].m_col = 5;
+
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 26;
+ m_crowNonAcpt = 18;
+ m_crowFinal = 8;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 7;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 126
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 2; *psn++ = 3; *psn++ = 0; *psn++ = 0; *psn++ = 4; *psn++ = 0;
+ *psn++ = 0; *psn++ = 5; *psn++ = 6; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 7; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 8;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 9; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ =10; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =18;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =11;
+ *psn++ =19; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ =12; *psn++ =20; *psn++ =13; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =14;
+ *psn++ = 0; *psn++ =15; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =16;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =21; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ =22; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ =23; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =24; *psn++ =17; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ =25; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[8]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s18: r1
+ m_prgrulnMatched[0] = 1;
+
+ m_prgirulnMin[1] = 1; // s19: r3
+ m_prgrulnMatched[1] = 3;
+
+ m_prgirulnMin[2] = 2; // s20: r6
+ m_prgrulnMatched[2] = 6;
+
+ m_prgirulnMin[3] = 3; // s21: r7
+ m_prgrulnMatched[3] = 7;
+
+ m_prgirulnMin[4] = 4; // s22: r0
+ m_prgrulnMatched[4] = 0;
+
+ m_prgirulnMin[5] = 5; // s23: r2
+ m_prgrulnMatched[5] = 2;
+
+ m_prgirulnMin[6] = 6; // s24: r4
+ m_prgrulnMatched[6] = 4;
+
+ m_prgirulnMin[7] = 7; // s25: r5
+ m_prgrulnMatched[7] = 5;
+
+ m_prgirulnMin[8] = 8;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test of default associations
+
+ PASS 1:
+ r0. gDollar _ > @1 gEquals;
+ r1. gAtSign > _ ;
+
+ Pass 1 machine classes:
+ mcDollar: $ 36
+ mcAt: @ 64
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcDollar mcAt
+ --------------------------------------
+ T NA s0 | s1 s2
+ |
+ F A s1 |
+ |
+ F A s2 |
+
+
+ Rules Matched:
+ s1: r0
+ s2: r1
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpDefaultAssocTest()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpDefaultAssocTest();
+}
+
+void GrClassTable::SetUpDefaultAssocTest()
+{
+ m_ccls = 1; // number of classes
+ m_cclsLinear = 1; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new data16[1];
+
+ m_prgichwOffsets = new data16[m_ccls+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: gEquals
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(61));
+
+ m_prgichwOffsets[1] = 1;
+}
+
+void GrSubPass::SetUpDefaultAssocTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "DefaultAssoc";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpDefaultAssocTest();
+
+ m_crul = 2;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue;
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[6 + 3];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: gDollar _ > @1 gEquals;
+
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopInsert; // Insert
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 0; // PutGlyph 0
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: gAtSign > _ ;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 6;
+}
+
+
+void GrFSM::SetUpDefaultAssocTest()
+{
+ // Create machine class ranges.
+ m_cmcr = 2;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 36; // $
+ m_prgmcr[0].m_chwLast = 36;
+ m_prgmcr[0].m_col = 0;
+
+ m_prgmcr[1].m_chwFirst = 64; // @
+ m_prgmcr[1].m_chwLast = 64;
+ m_prgmcr[1].m_col = 1;
+
+
+ m_dimcrInit = 2; // (max power of 2 <= m_cmcr);
+ m_cLoop = 1; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 3;
+ m_crowNonAcpt = 1;
+ m_crowFinal = 2;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 2;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 2
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 2;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[2]; // 2 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s1: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s2: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Test of features. The ID of "theFeature" == 234, its index is 0. The default value is 1.
+
+ PASS 1:
+ if (theFeature == 0) // * -> $
+ r0. gAsterisk > gDollar ;
+ else if (theFeature == 1) // * -> %
+ r1. gAsterisk > gPercent ;
+ else // * -> @
+ r2. gAsterisk > gAt ;
+
+ Pass 1 machine classes:
+ mcAsterisk: * 42
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcAsterisk
+ --------------------------------
+ T NA s0 | s1
+ |
+ F A s1 |
+
+
+ Rules Matched:
+ s1: r0, r1, r2
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpFeatureTest()
+{
+ AddFeature(234, 0, 1, 1);
+
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpFeatureTest();
+}
+
+void GrClassTable::SetUpFeatureTest()
+{
+ m_ccls = 4; // number of classes
+ m_cclsLinear = 4; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new data16[4];
+
+ m_prgichwOffsets = new data16[m_ccls + 1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(36)); // $
+
+ m_prgichwOffsets[1] = 1;
+ *pchw++ = msbf(data16(37)); // %
+
+ m_prgichwOffsets[2] = 2;
+ *pchw++ = msbf(data16(64)); // @
+
+ m_prgichwOffsets[3] = 3;
+ *pchw++ = msbf(data16(42)); // *
+
+ m_prgichwOffsets[4] = 4;
+}
+
+void GrSubPass::SetUpFeatureTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Feature";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpFeatureTest();
+
+ m_crul = 3;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 6 + 12 + 12];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue;
+
+ // (theFeature == 0)
+ *pb++ = kopPushFeat; *pb++ = 0; // PushFeat 0
+ *pb++ = kopPushByte; *pb++ = 0; // PushByte 0
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopPopRet; // PopAndRet
+
+ // (theFeature != 0 && theFeature == 1)
+ *pb++ = kopPushFeat; *pb++ = 0; // PushFeat 0
+ *pb++ = kopPushByte; *pb++ = 0; // PushByte 0
+ *pb++ = kopNotEq; // NotEq
+ *pb++ = kopPushFeat; *pb++ = 0; // PushFeat 0
+ *pb++ = kopPushByte; *pb++ = 1; // PushByte 1
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopAnd; // And
+ *pb++ = kopPopRet; // PopAndRet
+
+ // (theFeature != 0 && theFeature != 1)
+ *pb++ = kopPushFeat; *pb++ = 0; // PushFeat 0
+ *pb++ = kopPushByte; *pb++ = 0; // PushByte 0
+ *pb++ = kopNotEq; // NotEq
+ *pb++ = kopPushFeat; *pb++ = 0; // PushFeat 0
+ *pb++ = kopPushByte; *pb++ = 1; // PushByte 1
+ *pb++ = kopNotEq; // NotEq
+ *pb++ = kopAnd; // And
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 1;
+ m_prgibConstraintStart[1] = 1 + 6;
+ m_prgibConstraintStart[2] = 1 + 6 + 12;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[4 + 4 + 4];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: gAsterisk > gDollar ;
+
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 0; // PutGlyph 0
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: gAsterisk > gPercent ;
+
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 1; // PutGlyph 1
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 2: gAsterisk > gAt ;
+
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 2; // PutGlyph 2
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 4;
+ m_prgibActionStart[2] = 4 + 4;
+}
+
+
+void GrFSM::SetUpFeatureTest()
+{
+ // Create machine class ranges.
+ m_cmcr = 1;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 42; // *
+ m_prgmcr[0].m_chwLast = 42;
+ m_prgmcr[0].m_col = 0;
+
+
+ m_dimcrInit = 1; // (max power of 2 <= m_cmcr);
+ m_cLoop = 0; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 2;
+ m_crowNonAcpt = 1;
+ m_crowFinal = 1;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 1;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 1
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[3]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s1: r0, r1, r2
+ m_prgrulnMatched[0] = 0;
+ m_prgrulnMatched[1] = 1;
+ m_prgrulnMatched[2] = 2;
+
+ m_prgirulnMin[1] = 3;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Tests of ligatures and components.
+
+ PASS 1 (line-break):
+ r0. clsLetter { break = 2 }
+
+ Pass 1 machine classes:
+ mcLetter: a - z 97 - 122
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | clsLetter
+ --------------------------------
+ T NA s0 | s1
+ |
+ F A s1 |
+
+
+ Rules Matched:
+ s1: r0
+
+
+ PASS 2 (substitution):
+ r0. gX gY gZ > gCapX:(1 2 4) { comp {X.ref=@1; Y.ref=@2; Z.ref=@4 }} _ _
+ / _ _ # {break==2} _;
+ r1. gX gY gZ > _ _ gCapZ:(1 3 4) { comp {X.ref=@1; Y.ref=@3; Z.ref=@4 }}
+ / _ # {break==2} _ _;
+ r2. gX gY gZ > _ gCapY:(1 2 3) { comp {X.ref=@1; Y.ref=@2; Z.ref=@3 }} gPlus;
+
+ Pass 2 machine classes:
+ mcX: x 120
+ mcY: y 121
+ mcZ: z 122
+ mcLB: 35
+
+
+ Pass 2 FSM:
+ | mcX mcY mcZ mcLB
+ ----------------------------------------------------
+ T NA s0 | s1
+ | - - -
+ T NA s1 | s2 s3
+ | - - -
+ T NA s2 | s6 s4
+ | - - -
+ T NA s3 | s5
+ | - - -
+ T NA s4 | s7
+ | - - -
+ T NA s5 | s8
+ | - - -
+ F A s6 |
+ | - - -
+ F A s7 |
+ | - - -
+ F A s8 |
+ | - - -
+
+ Rules matched:
+ s6: r2
+ s7: r0
+ s8: r1
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpLigatureTest()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpLigatureTest();
+
+ m_pgtbl = new GrGlyphTable();
+ m_pgtbl->SetUpLigatureTest();
+
+ m_fLineBreak = true;
+ m_cchwPreXlbContext = 2;
+ m_cchwPostXlbContext = 2;
+}
+
+void GrClassTable::SetUpLigatureTest()
+{
+ m_ccls = 7; // number of classes
+ m_cclsLinear = 7; // number of classes in linear format (all classes are single-item)
+
+ m_prgchwBIGGlyphList = new data16[7];
+
+ m_prgichwOffsets = new data16[m_ccls+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Class 0: gCapX
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(88)); // X
+
+ // Class 1: gCapY
+ m_prgichwOffsets[1] = 1;
+ *pchw++ = msbf(data16(89)); // Y
+
+ // Class 2: gCapZ
+ m_prgichwOffsets[2] = 2;
+ *pchw++ = msbf(data16(90)); // Z
+
+ // Class 3: gPlus
+ m_prgichwOffsets[3] = 3;
+ *pchw++ = msbf(data16(43)); // +
+
+ // Class 4: gX
+ m_prgichwOffsets[4] = 4;
+ *pchw++ = msbf(data16(120)); // x
+
+ // Class 5: gY
+ m_prgichwOffsets[5] = 5;
+ *pchw++ = msbf(data16(121)); // y
+
+ // Class 6: gZ
+ m_prgichwOffsets[6] = 6;
+ *pchw++ = msbf(data16(122)); // z
+
+ m_prgichwOffsets[7] = 7;
+}
+
+void GrGlyphTable::SetUpLigatureTest()
+{
+ SetNumberOfGlyphs(128);
+ SetNumberOfStyles(1);
+
+ GrGlyphSubTable * pgstbl = new GrGlyphSubTable();
+ Assert(pgstbl);
+
+ pgstbl->Initialize(1, 0, 128, 10, 4);
+ SetSubTable(0, pgstbl);
+
+ SetNumberOfComponents(4); // comp.w, comp.x, comp.y, comp.z
+
+ pgstbl->SetUpLigatureTest();
+}
+
+/***********************************************************************************************
+ TODO: This method is BROKEN because m_prgibBIGAttrValues has been changed. It is no
+ longer a data16 *. The Gloc table can contain 16-bit or 32-bit entries and must be
+ accessed accordingly.
+***********************************************************************************************/
+void GrGlyphSubTable::SetUpLigatureTest()
+{
+ m_nAttrIDLim = 20;
+
+ m_pgatbl = new GrGlyphAttrTable();
+ m_pgatbl->Initialize(0, 102);
+
+ for (int i = 0; i < 88; i++)
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(0));
+
+ m_prgibBIGAttrValues[88] = (byte)msbf(data16(0));
+ m_prgibBIGAttrValues[89] = (byte)msbf(data16(34));
+ m_prgibBIGAttrValues[90] = (byte)msbf(data16(68));
+
+ for (i = 91; i < 128; i++)
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(102));
+
+ m_pgatbl->SetUpLigatureTest();
+}
+
+void GrGlyphAttrTable::SetUpLigatureTest()
+{
+ // Glyph 88 'X' (2 runs; offset = 0):
+ // 0 = 0 comp.w undefined
+ // 1 = 8 comp.x: (0,0, 25,100)
+ // 2 = 12 comp.y: (25,0, 75,100)
+ // 3 = 16 comp.z: (75,0, 100,100)
+ // 4-7 = 0 comp.w box corners
+ // 8 = 100 comp.x. top
+ // 9 = 0 bottom
+ // 10= 0 left
+ // 11= 25 right
+ // 12= 100 comp.y. top
+ // 13= 0 bottom
+ // 14= 25 left
+ // 15= 75 right
+ // 16= 100 comp.z. top
+ // 17= 0 bottom
+ // 18= 75 left
+ // 19= 100 right
+ //
+ // Glyph 89 (2 runs; offset = 34):
+ // 0 = 0 comp.w undefined
+ // 1 = 8 comp.x: (0,0, 33,100)
+ // 2 = 12 comp.y: (33,0, 67,100)
+ // 3 = 16 comp.z: (67,0, 100,100)
+ // 4-7 = 0 comp.w box corners
+ // 8 = 100 comp.x. top
+ // 9 = 0 bottom
+ // 10= 0 left
+ // 11= 33 right
+ // 12= 100 comp.y. top
+ // 13= 0 bottom
+ // 14= 33 left
+ // 15= 67 right
+ // 16= 100 comp.z. top
+ // 17= 0 bottom
+ // 18= 67 left
+ // 19= 100 right
+ //
+ // Glyph 90 (2 runs; offset = 68):
+ // 0 = 0 comp.w undefined
+ // 1 = 8 comp.x: (0,0, 10,100)
+ // 2 = 12 comp.y: (10,0, 90,100)
+ // 3 = 16 comp.z: (90,0, 100,100)
+ // 4-7 = 0 comp.w box corners
+ // 8 = 100 comp.x. top
+ // 9 = 0 bottom
+ // 10= 0 left
+ // 11= 10 right
+ // 12= 100 comp.y. top
+ // 13= 0 bottom
+ // 14= 10 left
+ // 15= 90 right
+ // 16= 100 comp.z. top
+ // 17= 0 bottom
+ // 18= 90 left
+ // 19= 100 right
+
+ byte * pbBIG = m_prgbBIGEntries;
+
+ GrGlyphAttrRun gatrun;
+
+ // Glyph 88 'X'
+ gatrun.m_bMinAttrID = 1;
+ gatrun.m_cAttrs = 3;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(8));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(12));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(16));
+ memcpy(pbBIG, &gatrun, 8); // 8 = 3*2 + 2
+ pbBIG += 8;
+ gatrun.m_bMinAttrID = 8; // comp.x.top
+ gatrun.m_cAttrs = 12;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[3] = msbf(data16(25));
+ gatrun.m_rgchwBIGValues[4] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[5] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[6] = msbf(data16(25));
+ gatrun.m_rgchwBIGValues[7] = msbf(data16(75));
+ gatrun.m_rgchwBIGValues[8] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[9] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[10] = msbf(data16(75));
+ gatrun.m_rgchwBIGValues[11] = msbf(data16(100));
+ memcpy(pbBIG, &gatrun, 26); // 26 = 12*2 + 2
+ pbBIG += 26;
+
+ // Glyph 89 'Y'
+ gatrun.m_bMinAttrID = 1;
+ gatrun.m_cAttrs = 3;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(8));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(12));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(16));
+ memcpy(pbBIG, &gatrun, 8); // 8 = 3*2 + 2
+ pbBIG += 8;
+ gatrun.m_bMinAttrID = 8; // comp.x.top
+ gatrun.m_cAttrs = 12;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[3] = msbf(data16(33));
+ gatrun.m_rgchwBIGValues[4] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[5] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[6] = msbf(data16(33));
+ gatrun.m_rgchwBIGValues[7] = msbf(data16(67));
+ gatrun.m_rgchwBIGValues[8] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[9] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[10] = msbf(data16(67));
+ gatrun.m_rgchwBIGValues[11] = msbf(data16(100));
+ memcpy(pbBIG, &gatrun, 26); // 26 = 12*2 + 2
+ pbBIG += 26;
+
+ // Glyph 90 'Z'
+ gatrun.m_bMinAttrID = 1;
+ gatrun.m_cAttrs = 3;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(8));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(12));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(16));
+ memcpy(pbBIG, &gatrun, 8); // 8 = 3*2 + 2
+ pbBIG += 8;
+ gatrun.m_bMinAttrID = 8; // comp.x.top
+ gatrun.m_cAttrs = 12;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[3] = msbf(data16(10));
+ gatrun.m_rgchwBIGValues[4] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[5] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[6] = msbf(data16(10));
+ gatrun.m_rgchwBIGValues[7] = msbf(data16(90));
+ gatrun.m_rgchwBIGValues[8] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[9] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[10] = msbf(data16(90));
+ gatrun.m_rgchwBIGValues[11] = msbf(data16(100));
+ memcpy(pbBIG, &gatrun, 26); // 26 = 12*2 + 2
+ pbBIG += 26;
+
+ Assert(pbBIG == m_prgbBIGEntries + 102);
+}
+
+void GrLineBreakPass::SetUpLigatureTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Ligatures";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpLigatureTest(m_ipass);
+
+ m_crul = 1;
+
+ // Set up constraint code--succeed trivially.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[8];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsLetter { break = 2 }
+
+ *pb++ = kopPutCopy; *pb++ = 0; // PutCopy 0
+ *pb++ = kopPushByte; *pb++ = 2; // PushByte 2
+ *pb++ = kopAttrSet; *pb++ = kslatBreak; // AttrSet breakweight
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+}
+
+void GrSubPass::SetUpLigatureTest()
+{
+ if (m_ipass == 2)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 4;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Ligatures";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpLigatureTest(m_ipass);
+
+ m_crul = 3;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1 + 10 + 10];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ *pb++ = kopCntxtItem; *pb++ = 2; // ContextItem 2
+ *pb++ = kopPushSlotAttr;*pb++ = kslatBreak; // PushSlotAttr break 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = 2; // Push 2
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ *pb++ = kopCntxtItem; *pb++ = 1; // ContextItem 1
+ *pb++ = kopPushSlotAttr;*pb++ = kslatBreak; // PushSlotAttr break 0
+ *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = 2; // Push 2
+ *pb++ = kopEqual; // Equal
+ *pb++ = kopOr; // Or
+ *pb++ = kopPopRet; // PopAndRet
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 1;
+ m_prgibConstraintStart[1] = 11;
+ m_prgibConstraintStart[2] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[29 + 29 + 29];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: gX gY gZ > gCapX:(1 2 4) { comp {X.ref=@1; Y.ref=@2; Z.ref=@4 }} _ _
+ // / _ _ # {break==2} _;
+
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 0; // PutGlyph 0 (gCapX)
+ *pb++ = kopAssoc; *pb++ = 3; // Assoc 3 0 1 3
+ *pb++ = 0; *pb++ = 1; *pb++ = 3;
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref x
+ *pb++ = kslatCompRef; *pb++ = 1;
+ *pb++ = kopPushByte; *pb++ = 1; // Push 1
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref y
+ *pb++ = kslatCompRef; *pb++ = 2;
+ *pb++ = kopPushByte; *pb++ = 3; // Push 3
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref z
+ *pb++ = kslatCompRef; *pb++ = 3;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: gX gY gZ > _ _ gCapZ:(1 3 4) { comp {X.ref=@1; Y.ref=@3; Z.ref=@4 }}
+ // / _ # {break==2} _ _;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopCopyNext; // CopyNext
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 2; // PutGlyph 2 (gCapZ)
+ *pb++ = kopAssoc; *pb++ = 3; // Assoc 3 -3 -1 0
+ *pb++ = -3; *pb++ = -1; *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = -3; // Push -3
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref x
+ *pb++ = kslatCompRef; *pb++ = 1;
+ *pb++ = kopPushByte; *pb++ = -1; // Push -1
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref y
+ *pb++ = kslatCompRef; *pb++ = 2;
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref z
+ *pb++ = kslatCompRef; *pb++ = 3;
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 2: gX gY gZ > _ gCapY:(1 2 3) { comp {X.ref=@1; Y.ref=@2; Z.ref=@3 }} gPlus;
+
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 1; // PutGlyph 1 (gCapY)
+ *pb++ = kopAssoc; *pb++ = 3; // Assoc 3 -1 0 1
+ *pb++ = -1; *pb++ = 0; *pb++ = 1;
+ *pb++ = kopPushByte; *pb++ = -1; // Push -1
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref x
+ *pb++ = kslatCompRef; *pb++ = 1;
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref y
+ *pb++ = kslatCompRef; *pb++ = 2;
+ *pb++ = kopPushByte; *pb++ = 1; // Push 1
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot comp_ref z
+ *pb++ = kslatCompRef; *pb++ = 3;
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutGlyph8bitObs; *pb++ = 3; // PutGlyph 3 (gPlus)
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 29;
+ m_prgibActionStart[2] = 29 + 29;
+ }
+ else
+ Assert(false);
+}
+
+
+void GrFSM::SetUpLigatureTest(int ipass)
+{
+ if (ipass == 1)
+ {
+ // Create machine class ranges.
+ m_cmcr = 1;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 97; // a - z
+ m_prgmcr[0].m_chwLast = 122;
+ m_prgmcr[0].m_col = 0;
+
+ m_dimcrInit = 1; // (max power of 2 <= m_cmcr);
+ m_cLoop = 0; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 2;
+ m_crowNonAcpt = 1;
+ m_crowFinal = 1;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 1;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 1
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[1]; // 1 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[m_crow - m_crowNonAcpt + 1];
+
+ m_prgirulnMin[0] = 0; // s1: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1;
+ }
+ else if (ipass == 2)
+ {
+ // Create machine class ranges.
+ m_cmcr = 4;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 35; // #
+ m_prgmcr[0].m_chwLast = 35;
+ m_prgmcr[0].m_col = 3;
+
+ m_prgmcr[1].m_chwFirst = 120; // x
+ m_prgmcr[1].m_chwLast = 120;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 121; // y
+ m_prgmcr[2].m_chwLast = 121;
+ m_prgmcr[2].m_col = 1;
+
+ m_prgmcr[3].m_chwFirst = 122; // z
+ m_prgmcr[3].m_chwLast = 123;
+ m_prgmcr[3].m_col = 2;
+
+
+ m_dimcrInit = 4; // (max power of 2 <= m_cmcr);
+ m_cLoop = 2; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 9;
+ m_crowNonAcpt = 6;
+ m_crowFinal = 3;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 4;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 24
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 0; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 2; *psn++ = 0; *psn++ = 3;
+ *psn++ = 0; *psn++ = 0; *psn++ = 6; *psn++ = 4;
+ *psn++ = 0; *psn++ = 5; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 7; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 8; *psn++ = 0;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[3]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[3+1]; // 3 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s6: r2
+ m_prgrulnMatched[0] = 2;
+
+ m_prgirulnMin[1] = 1; // s7: r0
+ m_prgrulnMatched[1] = 0;
+
+ m_prgirulnMin[2] = 2; // s8: r1
+ m_prgrulnMatched[2] = 1;
+
+ m_prgirulnMin[3] = 3;
+ }
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Tests of ligatures and components where the components are modified glyphs.
+
+ PASS 1:
+ r0. gX gI > @2 @1;
+ r1. clsPlainVowel gAcute > clsVowelAcute:(1 2) _;
+ r2. clsPlainVowel gGrave > clsVowelGrave:(1 2) _;
+
+ Pass 1 machine classes:
+ mcX: x 120
+ mcI: i 105
+ mcPV: a e o u 97 101 111 117
+ mcAcute: / 47
+ mcGrave: \ 92
+
+ Pass 1 FSM: (T=transition, F=final, A=accepting, NA=non-accepting)
+
+ | mcX mcPV mcI mcAcute mcGrave
+ ---------------------------------------------------------------
+ T NA s0 | s1 s2 s2
+ | - - - -
+ T NA s1 | s3
+ | - - - -
+ T NA s2 | s4 s5
+ | - - - -
+ F A s3 |
+ | - - - -
+ F A s4 |
+ | - - - -
+ F A s5 |
+ | - - - -
+
+
+ Rules Matched:
+ s3: r0
+ s4: r1
+ s5: r2
+
+
+ PASS 2:
+ r0. clsVowel gI > clsCapVowel:(1 2) { comp {v.ref = @1; i.ref = @2}} _;
+
+ Pass 2 machine classes:
+ mcV: 97 101 111 117
+ 224 225 232 233 236 237 242 243 249 250
+ mcI: i 105
+
+
+ Pass 2 FSM:
+ | mcV mcI
+ ----------------------------------------------------
+ T NA s0 | s1 s1
+ | -
+ T NA s1 | s2
+ | -
+ F A s2 |
+ | -
+
+ Rules matched:
+ s2: r0
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpLigature2Test()
+{
+ if (m_pctbl)
+ delete m_pctbl;
+
+ m_pctbl = new GrClassTable();
+ m_pctbl->SetUpLigature2Test();
+
+ m_pgtbl = new GrGlyphTable();
+ m_pgtbl->SetUpLigature2Test();
+}
+
+void GrClassTable::SetUpLigature2Test()
+{
+ m_ccls = 5; // number of classes
+ m_cclsLinear = 3; // number of classes in linear format
+
+ m_prgchwBIGGlyphList = new data16[73];
+
+ m_prgichwOffsets = new data16[m_ccls+1];
+
+ data16 * pchw = m_prgchwBIGGlyphList;
+
+ // Output class 0: clsVowelAcute
+ m_prgichwOffsets[0] = 0;
+ *pchw++ = msbf(data16(225)); // a-acute
+ *pchw++ = msbf(data16(233)); // e-acute
+ *pchw++ = msbf(data16(237)); // i-acute
+ *pchw++ = msbf(data16(243)); // o-acute
+ *pchw++ = msbf(data16(250)); // u-acute
+
+ // Output class 1: clsVowelGrave
+ m_prgichwOffsets[1] = 5;
+ *pchw++ = msbf(data16(224)); // a-grave
+ *pchw++ = msbf(data16(232)); // e-grave
+ *pchw++ = msbf(data16(236)); // i-grave
+ *pchw++ = msbf(data16(242)); // o-grave
+ *pchw++ = msbf(data16(249)); // u-grave
+
+ // Output class 2: clsCapVowel
+ m_prgichwOffsets[2] = 5 + 5; // 10
+ *pchw++ = msbf(data16(65)); // A
+ *pchw++ = msbf(data16(69)); // E
+ *pchw++ = msbf(data16(73)); // I
+ *pchw++ = msbf(data16(79)); // O
+ *pchw++ = msbf(data16(85)); // U
+ *pchw++ = msbf(data16(193)); // A-acute
+ *pchw++ = msbf(data16(201)); // E-acute
+ *pchw++ = msbf(data16(205)); // I-acute
+ *pchw++ = msbf(data16(211)); // O-acute
+ *pchw++ = msbf(data16(218)); // U-acute
+ *pchw++ = msbf(data16(192)); // A-grave
+ *pchw++ = msbf(data16(200)); // E-grave
+ *pchw++ = msbf(data16(204)); // I-grave
+ *pchw++ = msbf(data16(210)); // O-grave
+ *pchw++ = msbf(data16(217)); // U-grave
+
+ // Input class 3: clsPlainVowel
+ m_prgichwOffsets[3] = 10 + 15; // 25
+ *pchw++ = msbf(data16(5));
+ *pchw++ = msbf(data16(4)); *pchw++ = msbf(data16(2)); *pchw++ = msbf(data16(5-4));
+ *pchw++ = msbf(data16(97)); *pchw++ = msbf(data16(0)); // a
+ *pchw++ = msbf(data16(101)); *pchw++ = msbf(data16(1)); // e
+ *pchw++ = msbf(data16(105)); *pchw++ = msbf(data16(2)); // i
+ *pchw++ = msbf(data16(111)); *pchw++ = msbf(data16(3)); // o
+ *pchw++ = msbf(data16(117)); *pchw++ = msbf(data16(4)); // u
+
+ // Input class 4: clsVowel
+ m_prgichwOffsets[4] = 25 + 4+(5*2); // 39
+ *pchw++ = msbf(data16(15));
+ *pchw++ = msbf(data16(8)); *pchw++ = msbf(data16(3)); *pchw++ = msbf(data16(15-8));
+ *pchw++ = msbf(data16(97)); *pchw++ = msbf(data16(0)); // a
+ *pchw++ = msbf(data16(101)); *pchw++ = msbf(data16(1)); // e
+ *pchw++ = msbf(data16(105)); *pchw++ = msbf(data16(2)); // i
+ *pchw++ = msbf(data16(111)); *pchw++ = msbf(data16(3)); // o
+ *pchw++ = msbf(data16(117)); *pchw++ = msbf(data16(4)); // u
+ *pchw++ = msbf(data16(224)); *pchw++ = msbf(data16(10)); // a-grave
+ *pchw++ = msbf(data16(225)); *pchw++ = msbf(data16(5)); // a-acute
+ *pchw++ = msbf(data16(232)); *pchw++ = msbf(data16(11)); // e-grave
+ *pchw++ = msbf(data16(233)); *pchw++ = msbf(data16(6)); // e-acute
+ *pchw++ = msbf(data16(236)); *pchw++ = msbf(data16(12)); // i-grave
+ *pchw++ = msbf(data16(237)); *pchw++ = msbf(data16(7)); // i-acute
+ *pchw++ = msbf(data16(242)); *pchw++ = msbf(data16(13)); // o-grave
+ *pchw++ = msbf(data16(243)); *pchw++ = msbf(data16(8)); // o-acute
+ *pchw++ = msbf(data16(249)); *pchw++ = msbf(data16(14)); // u-grave
+ *pchw++ = msbf(data16(250)); *pchw++ = msbf(data16(9)); // u-acute
+
+ m_prgichwOffsets[5] = 39 + 4+(15*2); // 73
+}
+
+void GrGlyphTable::SetUpLigature2Test()
+{
+ SetNumberOfGlyphs(256);
+ SetNumberOfStyles(1);
+
+ GrGlyphSubTable * pgstbl = new GrGlyphSubTable();
+ Assert(pgstbl);
+
+ pgstbl->Initialize(1, 0, 256, 10, 4);
+ SetSubTable(0, pgstbl);
+
+ SetNumberOfComponents(2); // comp.base, comp.i
+
+ pgstbl->SetUpLigature2Test();
+}
+
+/***********************************************************************************************
+ TODO: This method is BROKEN because m_prgibBIGAttrValues has been changed. It is no
+ longer a data16 *. The Gloc table can contain 16-bit or 32-bit entries and must be
+ accessed accordingly.
+***********************************************************************************************/
+void GrGlyphSubTable::SetUpLigature2Test()
+{
+ m_nAttrIDLim = 10;
+
+ m_pgatbl = new GrGlyphAttrTable();
+ m_pgatbl->Initialize(0, 330);
+
+ for (int i = 0; i <= 65; i++) // A
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(0));
+
+ for (i = 66; i <= 69; i++) // E
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(22));
+
+ for (i = 70; i <= 73; i++) // I
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(44));
+
+ for (i = 74; i <= 79; i++) // O
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(66));
+
+ for (i = 80; i <= 85; i++) // U
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(88));
+
+ for (i = 86; i <= 192; i++) // A-grave
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(110));
+
+ m_prgibBIGAttrValues[193] = (byte)msbf(data16(132)); // A-acute
+
+ for (i = 194; i <= 200; i++) // E-grave
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(154));
+
+ m_prgibBIGAttrValues[201] = (byte)msbf(data16(176)); // E-acute
+
+ for (i = 202; i <= 204; i++) // I-grave
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(198));
+
+ m_prgibBIGAttrValues[205] = (byte)msbf(data16(220)); // I-acute
+
+ for (i = 206; i <= 210; i++) // O-grave
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(242));
+
+ m_prgibBIGAttrValues[211] = (byte)msbf(data16(264)); // O-acute
+
+ for (i = 212; i <= 217; i++) // U-grave
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(286));
+
+ m_prgibBIGAttrValues[218] = (byte)msbf(data16(308)); // O-acute
+
+ for (i = 219; i < 256; i++)
+ m_prgibBIGAttrValues[i] = (byte)msbf(data16(330));
+
+ m_pgatbl->SetUpLigature2Test();
+}
+
+void GrGlyphAttrTable::SetUpLigature2Test()
+{
+ // All ligatures have the following defined:
+ //
+ // 0 = 2 comp.base (0,30, 100,100)
+ // 1 = 6 comp.i (0,0, 100,30)
+ // 2= 100 comp.base.top
+ // 3= 30 bottom
+ // 4= 0 left
+ // 5= 100 right
+ // 6 = 30 comp.i.top
+ // 7 = 0 bottom
+ // 8= 0 left
+ // 9= 100 right
+
+ byte * pbBIG = m_prgbBIGEntries;
+
+ GrGlyphAttrRun gatrun;
+
+ for (int i = 0; i < 15; i++)
+ {
+ gatrun.m_bMinAttrID = 0;
+ gatrun.m_cAttrs = 10;
+ gatrun.m_rgchwBIGValues[0] = msbf(data16(2));
+ gatrun.m_rgchwBIGValues[1] = msbf(data16(6));
+ gatrun.m_rgchwBIGValues[2] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[3] = msbf(data16(30));
+ gatrun.m_rgchwBIGValues[4] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[5] = msbf(data16(100));
+ gatrun.m_rgchwBIGValues[6] = msbf(data16(30));
+ gatrun.m_rgchwBIGValues[7] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[8] = msbf(data16(0));
+ gatrun.m_rgchwBIGValues[9] = msbf(data16(100));
+ memcpy(pbBIG, &gatrun, 22); // 22 = 10*2 + 2
+ pbBIG += 22;
+ }
+
+ Assert(pbBIG == m_prgbBIGEntries + (22 * 15));
+}
+
+void GrSubPass::SetUpLigature2Test()
+{
+ if (m_ipass == 1)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Ligatures2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpLigature2Test(m_ipass);
+
+ m_crul = 3;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+ m_prgibConstraintStart[1] = 0;
+ m_prgibConstraintStart[2] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[7 + 12 + 12];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: gX gI > @2 @1;
+
+ *pb++ = kopPutCopy; *pb++ = 1; // PutCopy 1
+ *pb++ = kopNext; // Next
+ *pb++ = kopPutCopy; *pb++ = -1; // PutCopy -1
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 1: clsPlainVowel gAcute > clsVowelAcute:(1 2) _;
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 3 0
+ *pb++ = 3; *pb++ = 0;
+ *pb++ = kopAssoc; *pb++ = 2; // Assoc 2 0 1
+ *pb++ = 0; *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ // Rule 2: clsPlainVowel gGrave > clsVowelGrave:(1 2) _;
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 3 1
+ *pb++ = 3; *pb++ = 1;
+ *pb++ = kopAssoc; *pb++ = 2; // Assoc 2 0 1
+ *pb++ = 0; *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ m_prgibActionStart[1] = 7;
+ m_prgibActionStart[2] = 7 + 12;
+ }
+ else if (m_ipass == 2)
+ {
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 5;
+ m_staBehavior = "Ligatures2";
+
+ m_pfsm = new GrFSM();
+ Assert(m_pfsm);
+ m_pfsm->SetUpLigature2Test(m_ipass);
+
+ m_crul = 1;
+
+ // Set up constraint code.
+ m_prgbConstraintBlock = new byte[1];
+ byte * pb = m_prgbConstraintBlock;
+ *pb++ = kopRetTrue; // RetTrue
+
+ m_prgibConstraintStart = new data16[m_crul];
+ m_prgibConstraintStart[0] = 0;
+
+ // Set up rule action code.
+ m_prgbActionBlock = new byte[7 + 12 + 12];
+ pb = m_prgbActionBlock;
+
+ // Rule 0: clsVowel gI > clsCapVowel:(1 2) { comp {v.ref = @1; i.ref = @2}} _;
+
+ *pb++ = kopPutSubs8bitObs; *pb++ = 0; // PutSubs 0 4 2
+ *pb++ = 4; *pb++ = 2;
+ *pb++ = kopAssoc; *pb++ = 2; // Assoc 2 0 1
+ *pb++ = 0; *pb++ = 1;
+ *pb++ = kopPushByte; *pb++ = 0; // Push 0
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot compRef v
+ *pb++ = kslatCompRef; *pb++ = 0;
+ *pb++ = kopPushByte; *pb++ = 1; // Push 1
+ *pb++ = kopIAttrSetSlot; // IAttrSetSlot compRef i
+ *pb++ = kslatCompRef; *pb++ = 1;
+ *pb++ = kopNext; // Next
+ *pb++ = kopDelete; // Delete
+ *pb++ = kopNext; // Next
+ *pb++ = kopRetZero; // RetZero
+
+ m_prgibActionStart = new data16[m_crul];
+ m_prgibActionStart[0] = 0;
+ }
+ else
+ Assert(false);
+}
+
+
+void GrFSM::SetUpLigature2Test(int ipass)
+{
+ if (ipass == 1)
+ {
+ // Create machine class ranges.
+ m_cmcr = 8;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 47; // acute
+ m_prgmcr[0].m_chwLast = 47;
+ m_prgmcr[0].m_col = 3;
+
+ m_prgmcr[1].m_chwFirst = 92; // grave
+ m_prgmcr[1].m_chwLast = 92;
+ m_prgmcr[1].m_col = 4;
+
+ m_prgmcr[2].m_chwFirst = 97; // a
+ m_prgmcr[2].m_chwLast = 97;
+ m_prgmcr[2].m_col = 1;
+
+ m_prgmcr[3].m_chwFirst = 101; // e
+ m_prgmcr[3].m_chwLast = 101;
+ m_prgmcr[3].m_col = 1;
+
+ m_prgmcr[4].m_chwFirst = 105; // i
+ m_prgmcr[4].m_chwLast = 105;
+ m_prgmcr[4].m_col = 2;
+
+ m_prgmcr[5].m_chwFirst = 111; // o
+ m_prgmcr[5].m_chwLast = 111;
+ m_prgmcr[5].m_col = 1;
+
+ m_prgmcr[6].m_chwFirst = 117; // u
+ m_prgmcr[6].m_chwLast = 117;
+ m_prgmcr[6].m_col = 1;
+
+ m_prgmcr[7].m_chwFirst = 120; // x
+ m_prgmcr[7].m_chwLast = 120;
+ m_prgmcr[7].m_col = 0;
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 6;
+ m_crowNonAcpt = 3;
+ m_crowFinal = 3;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 5;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 15
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 2; *psn++ = 2; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 3; *psn++ = 0; *psn++ = 0;
+ *psn++ = 0; *psn++ = 0; *psn++ = 0; *psn++ = 4; *psn++ = 5;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[3]; // 3 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[3+1]; // 3 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s3: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1; // s4: r1
+ m_prgrulnMatched[1] = 1;
+
+ m_prgirulnMin[2] = 2; // s5: r2
+ m_prgrulnMatched[2] = 2;
+
+ m_prgirulnMin[3] = 3;
+ }
+ else if (ipass == 2)
+ {
+ // Create machine class ranges.
+ m_cmcr = 10;
+ m_prgmcr = new GrFSMClassRange[m_cmcr];
+ m_prgmcr[0].m_chwFirst = 97; // a
+ m_prgmcr[0].m_chwLast = 97;
+ m_prgmcr[0].m_col = 0;
+
+ m_prgmcr[1].m_chwFirst = 101; // e
+ m_prgmcr[1].m_chwLast = 101;
+ m_prgmcr[1].m_col = 0;
+
+ m_prgmcr[2].m_chwFirst = 105; // i
+ m_prgmcr[2].m_chwLast = 105;
+ m_prgmcr[2].m_col = 1;
+
+ m_prgmcr[3].m_chwFirst = 111; // o
+ m_prgmcr[3].m_chwLast = 111;
+ m_prgmcr[3].m_col = 0;
+
+ m_prgmcr[4].m_chwFirst = 117; // u
+ m_prgmcr[4].m_chwLast = 117;
+ m_prgmcr[4].m_col = 0;
+
+ m_prgmcr[5].m_chwFirst = 224; // a-grave, a-acute
+ m_prgmcr[5].m_chwLast = 225;
+ m_prgmcr[5].m_col = 0;
+
+ m_prgmcr[6].m_chwFirst = 232; // e-grave, e-acute
+ m_prgmcr[6].m_chwLast = 233;
+ m_prgmcr[6].m_col = 0;
+
+ m_prgmcr[7].m_chwFirst = 236; // i-grave, i-acute
+ m_prgmcr[7].m_chwLast = 237;
+ m_prgmcr[7].m_col = 0;
+
+ m_prgmcr[8].m_chwFirst = 242; // o-grave, o-acute
+ m_prgmcr[8].m_chwLast = 243;
+ m_prgmcr[8].m_col = 0;
+
+ m_prgmcr[9].m_chwFirst = 249; // u-grave, u-acute
+ m_prgmcr[9].m_chwLast = 250;
+ m_prgmcr[9].m_col = 0;
+
+
+ m_dimcrInit = 8; // (max power of 2 <= m_cmcr);
+ m_cLoop = 3; // log2(max power of 2 <= m_cmcr);
+ m_imcrStart = m_cmcr - m_dimcrInit;
+
+
+ m_crow = 3;
+ m_crowNonAcpt = 2;
+ m_crowFinal = 1;
+ m_rowFinalMin = m_crow - m_crowFinal;
+ m_ccol = 2;
+
+ // Set up transition table.
+ m_prgrowTransitions = new short[(m_crow-m_crowFinal) * m_ccol]; // 4
+ short * psn = m_prgrowTransitions;
+ *psn++ = 1; *psn++ = 1;
+ *psn++ = 0; *psn++ = 2;
+
+ // Set up matched-rules tables.
+ m_prgrulnMatched = new data16[1]; // 1 = sum of rules matched for each accepting state
+ m_prgirulnMin = new data16[1+1]; // 1 = m_crow - m_crowNonAcpt
+
+ m_prgirulnMin[0] = 0; // s2: r0
+ m_prgrulnMatched[0] = 0;
+
+ m_prgirulnMin[1] = 1;
+ }
+}
+
+#endif // _DEBUG
+
+} // namespace gr
+
+#endif // OLD_TEST_STUFF
+
+//:End Ignore
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/TestPasses.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/TestPasses.cpp
new file mode 100644
index 00000000000..a85e6c56207
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/TestPasses.cpp
@@ -0,0 +1,1005 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TestPasses.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Hard-coded passes for test procedures.
+-------------------------------------------------------------------------------*//*:End Ignore*/
+
+//:Ignore
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+#ifdef OLD_TEST_STUFF
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ For release version.
+----------------------------------------------------------------------------------------------*/
+#ifndef _DEBUG
+
+bool GrLineBreakPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+bool GrSubPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+bool GrPosPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+#endif // !_DEBUG
+
+
+#ifdef _DEBUG
+
+/*----------------------------------------------------------------------------------------------
+ Set up a table manager for testing.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::SetUpTest(std::wstring stuRendBehavior)
+{
+ if (stuRendBehavior == L"NoRules")
+ {
+ m_cpass = 2;
+ m_cpassLB = 0;
+ m_ipassPos1 = 1;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrPosPass(1);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"JustReorder" || stuRendBehavior == "RightToLeftLayout")
+ {
+ m_cpass = 4;
+ m_cpassLB = 0;
+ m_ipassPos1 = 3;
+ m_fBidi = true;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrBidiPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpReverseNumbersTest();
+ m_prgppass[2]->SetUpTestData();
+ m_prgppass[3]->SetUpTestData();
+
+ m_prgppass[2]->SetTopDirLevel(TopDirectionLevel());
+ }
+ else if (stuRendBehavior == L"CrossLineContext")
+ {
+ m_cpass = 4;
+ m_cpassLB = 1;
+ m_ipassPos1 = 3;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrLineBreakPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpCrossLineContextTest();
+ m_prgppass[2]->SetUpCrossLineContextTest();
+ m_prgppass[3]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"Reprocess")
+ {
+ m_cpass = 6;
+ m_cpassLB = 1;
+ m_ipassPos1 = 5;
+ m_fBidi = true;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrLineBreakPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrSubPass(3);
+ m_prgppass[4] = new GrBidiPass(4);
+ m_prgppass[5] = new GrPosPass(5);
+
+ m_prgppass[0]->SetUpTestData(); // glyph-gen pass
+ m_prgppass[1]->SetUpReprocessTest(); // line-break pass
+ m_prgppass[2]->SetUpReverseNumbersTest(); // sub pass 1
+ m_prgppass[3]->SetUpReprocessTest(); // sub pass 2
+ m_prgppass[4]->SetUpTestData(); // bidi pass
+ m_prgppass[5]->SetUpTestData(); // pos pass
+
+ m_prgppass[4]->SetTopDirLevel(TopDirectionLevel());
+ }
+ else if (stuRendBehavior == L"LineEdgeContext")
+ {
+ m_cpass = 4;
+ m_cpassLB = 0;
+ m_ipassPos1 = 3;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpLineEdgeContextTest(1);
+ m_prgppass[2]->SetUpLineEdgeContextTest(2);
+ m_prgppass[3]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"BidiAlgorithm")
+ {
+ m_cpass = 4;
+ m_cpassLB = 0;
+ m_ipassPos1 = 3;
+ m_fBidi = true;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrBidiPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpBidiAlgorithmTest();
+ m_prgppass[2]->SetUpBidiAlgorithmTest();
+ m_prgppass[3]->SetUpTestData();
+
+ m_prgppass[2]->SetTopDirLevel(TopDirectionLevel());
+ }
+ else if (stuRendBehavior == L"PseudoGlyphs")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpPseudoGlyphsTest();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"SimpleFSM")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpSimpleFSMTest();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"RuleAction")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpRuleActionTest();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"RuleAction2")
+ {
+ m_cpass = 6;
+ m_cpassLB = 0;
+ m_ipassPos1 = 5;
+ m_fBidi = true;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrSubPass(3);
+ m_prgppass[4] = new GrBidiPass(4);
+ m_prgppass[5] = new GrPosPass(5);
+
+ m_prgppass[0]->SetUpTestData(); // glyph-gen pass
+ m_prgppass[1]->SetUpRuleAction2Test(); // sub pass 1
+ m_prgppass[2]->SetUpRuleAction2Test(); // sub pass 2
+ m_prgppass[3]->SetUpRuleAction2Test(); // sub pass 3
+ m_prgppass[4]->SetUpTestData(); // bidi pass
+ m_prgppass[5]->SetUpTestData(); // pos pass
+
+ m_prgppass[4]->SetTopDirLevel(TopDirectionLevel());
+ }
+ else if (stuRendBehavior == L"Assoc")
+ {
+ m_cpass = 5;
+ m_cpassLB = 1;
+ m_ipassPos1 = 4;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrLineBreakPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrSubPass(3);
+ m_prgppass[4] = new GrPosPass(4);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpAssocTest();
+ m_prgppass[2]->SetUpAssocTest();
+ m_prgppass[3]->SetUpAssocTest();
+ m_prgppass[4]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"Assoc2")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpAssoc2Test();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"DefaultAssoc")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpDefaultAssocTest();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"BidiNumbers")
+ {
+ m_cpass = 4;
+ m_cpassLB = 0;
+ m_ipassPos1 = 3;
+ m_fBidi = true;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrBidiPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpBidiNumbersTest();
+ m_prgppass[2]->SetUpBidiNumbersTest();
+ m_prgppass[3]->SetUpTestData();
+
+ m_prgppass[2]->SetTopDirLevel(TopDirectionLevel());
+ }
+ else if (stuRendBehavior == L"Feature")
+ {
+ m_cpass = 3;
+ m_cpassLB = 0;
+ m_ipassPos1 = 2;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrPosPass(2);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpFeatureTest();
+ m_prgppass[2]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"Ligatures")
+ {
+ m_cpass = 4;
+ m_cpassLB = 1;
+ m_ipassPos1 = 3;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrLineBreakPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpLigatureTest();
+ m_prgppass[2]->SetUpLigatureTest();
+ m_prgppass[3]->SetUpTestData();
+ }
+ else if (stuRendBehavior == L"Ligatures2")
+ {
+ m_cpass = 4;
+ m_cpassLB = 1;
+ m_ipassPos1 = 3;
+ m_fBidi = false;
+
+ m_prgppass = new GrPass*[m_cpass];
+ m_prgppass[0] = new GrGlyphGenPass(0);
+ m_prgppass[1] = new GrSubPass(1);
+ m_prgppass[2] = new GrSubPass(2);
+ m_prgppass[3] = new GrPosPass(3);
+
+ m_prgppass[0]->SetUpTestData();
+ m_prgppass[1]->SetUpLigature2Test();
+ m_prgppass[2]->SetUpLigature2Test();
+ m_prgppass[3]->SetUpTestData();
+ }
+ else
+ Assert(false);
+
+ m_engst.m_prgpsstrm = new GrSlotStream*[m_cpass];
+ for (int ipass = 0; ipass < m_cpass; ++ipass)
+ m_engst.m_prgpsstrm[ipass] = new GrSlotStream(ipass);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Set the pass variables that normally will be read from the ECF.
+----------------------------------------------------------------------------------------------*/
+
+void GrPass::SetUpTestData()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 2;
+}
+
+//void GrBidiPass::SetUpTestData()
+//{
+// m_nMaxRuleContext = m_nMaxChunk = 1;
+// m_nMaxRuleLoop = 2;
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Call the appropriate test function.
+----------------------------------------------------------------------------------------------*/
+
+bool GrLineBreakPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ if (m_staBehavior == "Reprocess")
+ return RunReprocessTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "CrossLineContext")
+ return RunCrossLineContextTest(ptman, psstrmInput, psstrmOutput);
+ else
+ return false;
+}
+
+bool GrSubPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ if (m_staBehavior == "ReverseNumbers")
+ return RunReverseNumbersTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "CrossLineContext")
+ return RunCrossLineContextTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "Reprocess")
+ return RunReprocessTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "LineEdgeContext")
+ return RunLineEdgeContextTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "BidiAlgorithm")
+ return RunBidiAlgorithmTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "PseudoGlyphs")
+ return RunPseudoGlyphsTest(ptman, psstrmInput, psstrmOutput);
+ else if (m_staBehavior == "BidiNumbers")
+ return RunBidiNumbersTest(ptman, psstrmInput, psstrmOutput);
+ else
+ return false;
+}
+
+bool GrPosPass::RunTestRules(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ A substitution pass that causes numbers to be reversed. Used by both the JustReorder test
+ and the Reprocess test.
+----------------------------------------------------------------------------------------------*/
+
+void GrSubPass::SetUpReverseNumbersTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "ReverseNumbers";
+}
+
+bool GrSubPass::RunReverseNumbersTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ data16 chw0;
+
+ // clsDigit { dir = DIR_RIGHT };
+ if (psstrmInput->SlotsPending() >= 1)
+ {
+ bool fRtl = ptman->RightToLeft();
+ chw0 = psstrmInput->Peek(0)->GlyphID();
+ if ((chw0 >= '0') && (chw0 <= '9'))
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval0;
+// pslot0->GetFeatureValues(&fval0);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlotCopy(pslot0, m_ipass, &pslotNew);
+ pslotNew->SetDirectionality(fRtl ? kdircArabNum : kdircR);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ return true;
+ }
+ else
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval0;
+// pslot0->GetFeatureValues(&fval0);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlotCopy(pslot0, m_ipass, &pslotNew);
+ if (chw0 == 32)
+ pslotNew->SetDirectionality(kdircWhiteSpace);
+ else if (chw0 == '.')
+ pslotNew->SetDirectionality(kdircComSep);
+ else
+ pslotNew->SetDirectionality(fRtl ? kdircR : kdircL);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ return true;
+ }
+ }
+ else
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ A substitution pass that will do some hard-coded actions resulting in cross-line-boundary
+ contextuals.
+----------------------------------------------------------------------------------------------*/
+void GrEngine::SetUpCrossLineContextTest()
+{
+ m_fLineBreak = true;
+ m_cchwPreXlbContext = 2;
+ m_cchwPostXlbContext = 0;
+}
+
+void GrLineBreakPass::SetUpCrossLineContextTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "CrossLineContext";
+}
+
+void GrSubPass::SetUpCrossLineContextTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "CrossLineContext";
+}
+
+bool GrLineBreakPass::RunCrossLineContextTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ // '=' { break = intra };
+ if ((psstrmInput->SlotsPending() >= 1) &&
+ (psstrmInput->Peek(0)->GlyphID() == 61))
+ {
+ GrSlotState * pslotNew0;
+ ptman->NewSlotCopy(psstrmInput->NextGet(), m_ipass, &pslotNew0);
+ pslotNew0->SetBreakWeight(int(klbHyphenBreak));
+ psstrmOutput->NextPut(pslotNew0);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool GrSubPass::RunCrossLineContextTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ // any '=' _ _ > any '=' '=':2 any:1 / _ _ # _ _
+ if ((psstrmInput->SlotsPending() >= 3) &&
+ (psstrmInput->Peek(1)->GlyphID() == 61) &&
+ (psstrmInput->Peek(2)->GlyphID() == ptman->LBGlyphID()))
+ {
+ GrSlotState * pslot0 = psstrmInput->Peek(0);
+ GrSlotState * pslot1 = psstrmInput->Peek(1);
+ gid16 chw0 = pslot0->GlyphID();
+// GrFeatureValues fval0;
+// pslot0->GetFeatureValues(&fval0);
+// GrFeatureValues fval1;
+// pslot1->GetFeatureValues(&fval1);
+
+ // copy the first 3 slots
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ // insert 2 more
+ GrSlotState * pslot3;
+ ptman->NewSlot(61, pslot1, NULL, m_ipass, &pslot3);
+ pslot3->Associate(pslot1);
+ psstrmOutput->NextPut(pslot3);
+
+ GrSlotState * pslot4;
+ ptman->NewSlot(chw0, pslot0, NULL, m_ipass, &pslot4);
+ pslot4->Associate(pslot0);
+ psstrmOutput->NextPut(pslot4);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Line break and substitution passes that cause intra-pass reprocessing (ie, the ^ mechanism).
+----------------------------------------------------------------------------------------------*/
+
+void GrLineBreakPass::SetUpReprocessTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 2;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "Reprocess";
+}
+
+bool GrLineBreakPass::RunReprocessTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chw;
+
+ // '^' {lb=2} / _ lc
+ if ((psstrmInput->SlotsPending() >=2) &&
+ (psstrmInput->Peek(0)->GlyphID() == '^') &&
+ (((chw = psstrmInput->Peek(1)->GlyphID()) >= 'a') &&
+ (chw <= 'z')))
+ {
+ GrSlotState * pslotNew0;
+ ptman->NewSlotCopy(psstrmInput->NextGet(), m_ipass, &pslotNew0);
+ pslotNew0->SetBreakWeight(int(klbHyphenBreak));
+ psstrmOutput->NextPut(pslotNew0);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+
+void GrSubPass::SetUpReprocessTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "Reprocess";
+}
+
+bool GrSubPass::RunReprocessTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chw;
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // symbol > @2 {dir = DIR_ARABNUMBER} / any {dir != DIR_LEFT} ^ _
+ if ((psstrmInput->SlotsPending() >= 2) &&
+ (psstrmInput->Peek(0)->Directionality() != kdircL) &&
+ (((chw = psstrmInput->Peek(1)->GlyphID()) == '@') ||
+ (chw == '@') || (chw == '$') || (chw == '%') ||
+ (chw == '^') || (chw == '&') || (chw == '*')))
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ GrSlotState * pslotNew1;
+ ptman->NewSlotCopy(psstrmInput->NextGet(), m_ipass, &pslotNew1);
+ pslotNew1->SetDirectionality(kdircArabNum);
+ psstrmOutput->NextPut(pslotNew1);
+
+ psstrmOutput->SetPosForNextRule(-1, psstrmInput, false);
+
+ return true;
+ }
+
+ // '^' lc > @1 uc
+ else if ((psstrmInput->SlotsPending() >= 2) &&
+ (psstrmInput->Peek(0)->GlyphID() == '^') &&
+ (((chw = psstrmInput->Peek(1)->GlyphID()) >= 'a') &&
+ (chw <= 'z')))
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ gid16 chwNew = chw - 'a' + 'A';
+ GrSlotState * pslotNew1;
+ ptman->NewSlotCopy(psstrmInput->NextGet(), m_ipass, &pslotNew1);
+ pslotNew1->SetGlyphID(chwNew);
+ psstrmOutput->NextPut(pslotNew1);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+
+ // '^' lc > @1 uc / _ # _
+ else if ((psstrmInput->SlotsPending() >= 3) &&
+ (psstrmInput->Peek(0)->GlyphID() == '^') &&
+ (psstrmInput->Peek(1)->IsLineBreak(chwLB)) &&
+ (((chw = psstrmInput->Peek(2)->GlyphID()) >= 'a') &&
+ (chw <= 'z')))
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ gid16 chwNew = chw - 'a' + 'A';
+ GrSlotState * pslotNew1;
+ ptman->NewSlotCopy(psstrmInput->NextGet(), m_ipass, &pslotNew1);
+ pslotNew1->SetGlyphID(chwNew);
+ psstrmOutput->NextPut(pslotNew1);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+
+ else
+ return false;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Substitution passes that create contextual forms at the line breaks; also a cross-line-
+ boundary contextual.
+----------------------------------------------------------------------------------------------*/
+
+void GrSubPass::SetUpLineEdgeContextTest(int ipass)
+{
+ m_nMaxRuleContext = (ipass == 2)? 5: 2;
+ m_nMaxChunk = m_nMaxRuleContext;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "LineEdgeContext";
+}
+
+bool GrSubPass::RunLineEdgeContextTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // any _ _ > @1 '-' '-' / _ _ _ #
+ if ((m_ipass == 1) &&
+ (psstrmInput->SlotsPending() >= 2) &&
+ (psstrmInput->Peek(1)->IsLineBreak(chwLB)))
+ {
+ GrSlotState * pslot0 = psstrmInput->Peek(0);
+// GrFeatureValues fval;
+// pslot0->GetFeatureValues(&fval);
+
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ GrSlotState * pslotNew1;
+ ptman->NewSlot('-', pslot0, NULL, m_ipass, &pslotNew1);
+ pslotNew1->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew1);
+
+ GrSlotState * pslotNew2;
+ ptman->NewSlot('-', pslot0, NULL, m_ipass, &pslotNew2);
+ pslotNew2->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew2);
+
+ return true;
+ }
+
+ // _ _ any > '+' '+' @4 / # _ _ _
+ else if ((m_ipass == 1) &&
+ (psstrmInput->SlotsPending() >= 2) &&
+ (psstrmInput->Peek(0)->IsLineBreak(chwLB)))
+ {
+ GrSlotState * pslot2 = psstrmInput->Peek(1);
+// GrFeatureValues fval;
+// pslot2->GetFeatureValues(&fval);
+
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ GrSlotState * pslotNew0;
+ ptman->NewSlot('+', pslot2, NULL, m_ipass, &pslotNew0);
+ pslotNew0->Associate(pslot2);
+ psstrmOutput->NextPut(pslotNew0);
+
+ GrSlotState * pslotNew1;
+ ptman->NewSlot('+', pslot2, NULL, m_ipass, &pslotNew1);
+ pslotNew1->Associate(pslot2);
+ psstrmOutput->NextPut(pslotNew1);
+
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ return true;
+ }
+
+ // '-' '-' '+' '+' > @1 _ _ @4 / _ _ # _ _
+ else if ((m_ipass == 2) &&
+ (psstrmInput->SlotsPending() >= 5) &&
+ (psstrmInput->Peek(0)->GlyphID() == '-') &&
+ (psstrmInput->Peek(1)->GlyphID() == '-') &&
+ (psstrmInput->Peek(2)->IsLineBreak(chwLB)) &&
+ (psstrmInput->Peek(3)->GlyphID() == '+') &&
+ (psstrmInput->Peek(4)->GlyphID() == '+'))
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmInput->Skip(1);
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmInput->Skip(1);
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ return true;
+ }
+
+ else
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Substitution passes that do something special with pseudo glyphs.
+----------------------------------------------------------------------------------------------*/
+
+void GrSubPass::SetUpPseudoGlyphsTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 3;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "PseudoGlyphs";
+}
+
+bool GrSubPass::RunPseudoGlyphsTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // pseudo > uppercase / _ ' '
+ if ((psstrmInput->SlotsPending() >= 2) &&
+ (psstrmInput->Peek(0)->GlyphID() > 1000) && // pseudo
+ (psstrmInput->Peek(1)->GlyphID() == 32))
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval;
+// pslot0->GetFeatureValues(&fval);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlotCopy(pslot0, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(pslot0->GlyphID() - 1000);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+
+ // pseudo > uppercase / _ |
+ // pseudo > uppercase / _ #
+ else if ((psstrmInput->SlotsPending() <= 2) &&
+ (psstrmInput->Peek(0)->GlyphID() > 1000) && // pseudo
+ (psstrmInput->SlotsPending() < 2 || psstrmInput->Peek(1)->GlyphID() == 35))
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval;
+// pslot0->GetFeatureValues(&fval);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlotCopy(pslot0, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(pslot0->GlyphID() - 1000);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, false);
+
+ return true;
+ }
+
+ // pseudo any _ > lowercase:1 @2 @1 / _ _ ^ _;
+ else if ((psstrmInput->SlotsPending() >= 3) &&
+ (psstrmInput->Peek(0)->GlyphID() > 1000)) // pseudo
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval;
+// pslot0->GetFeatureValues(&fval);
+
+ GrSlotState * pslotNew0;
+ ptman->NewSlot(pslot0->GlyphID()-1000-65+97, pslot0, NULL, m_ipass, &pslotNew0);
+ pslotNew0->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew0);
+
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+
+ GrSlotState * pslotNew2;
+ ptman->NewSlot(pslot0->GlyphID(), pslot0, NULL, m_ipass, &pslotNew2);
+ pslotNew2->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew2);
+
+ psstrmOutput->SetPosForNextRule(-1, psstrmInput, false);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Substitution pass that tests reversing numbers.
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::SetUpBidiNumbersTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "BidiNumbers";
+}
+
+bool GrSubPass::RunBidiNumbersTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chw0;
+
+ // clsDigit > clsDigit { dir = DIR_ARABNUMBER };
+ if ((psstrmInput->SlotsPending() >= 1) &&
+ (((chw0 = psstrmInput->Peek(0)->GlyphID()) >= '0' && chw0 <= '9') ||
+ (chw0 >= 'A' && chw0 <= 'Z') || (chw0 >= 'a' && chw0 <= 'z')))
+ {
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval0;
+// pslot0->GetFeatureValues(&fval0);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlot(chw0, pslot0, NULL, m_ipass, &pslotNew);
+ if (chw0 >= '0' && chw0 <= '9')
+ pslotNew->SetDirectionality(kdircArabNum);
+ else // a-z and A-Z
+ pslotNew->SetDirectionality(kdircR);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+void GrBidiPass::SetUpBidiNumbersTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_nTopDirection = 1;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Substitution pass that tests the bidi algorithm thoroughly.
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::SetUpBidiAlgorithmTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_staBehavior = "BidiAlgorithm";
+}
+
+bool GrSubPass::RunBidiAlgorithmTest(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput)
+{
+ gid16 chw0;
+
+ if (psstrmInput->SlotsPending() >= 1)
+ {
+ chw0 = psstrmInput->Peek(0)->GlyphID();
+
+ DirCode dircNew;
+
+ if (chw0 >= '0' && chw0 <= '9')
+ dircNew = kdircEuroNum;
+ else if (chw0 >= 'a' && chw0 <= 'z')
+ dircNew = kdircL;
+ else if (chw0 >= 'A' && chw0 <= 'M')
+ dircNew = kdircR;
+ else if (chw0 >= 'N' && chw0 <= 'T')
+ dircNew = kdircRArab;
+ else if (chw0 >= 'U' && chw0 <= 'Z')
+ dircNew = kdircArabNum;
+ else if (chw0 == '$' || chw0 == '%')
+ dircNew = kdircEuroTerm;
+ else if (chw0 == '.' || chw0 == '*' || chw0 == '+')
+ dircNew = kdircEuroSep;
+ else if (chw0 == '@')
+ dircNew = kdircComSep;
+ else if (chw0 == '_' || chw0 == '=')
+ dircNew = kdircNeutral;
+ else if (chw0 == ':')
+ dircNew = kdircNSM;
+ else
+ return false;
+
+ GrSlotState * pslot0 = psstrmInput->NextGet();
+// GrFeatureValues fval0;
+// pslot0->GetFeatureValues(&fval0);
+
+ GrSlotState * pslotNew;
+ ptman->NewSlot(chw0, pslot0, NULL, m_ipass, &pslotNew);
+ pslotNew->SetDirectionality(dircNew);
+ pslotNew->Associate(pslot0);
+ psstrmOutput->NextPut(pslotNew);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+void GrBidiPass::SetUpBidiAlgorithmTest()
+{
+ m_nMaxRuleContext = m_nMaxChunk = 1;
+ m_nMaxRuleLoop = 2;
+ m_nTopDirection = 0;
+}
+
+
+#endif // _DEBUG
+
+} // namespace gr
+
+#endif // OLD_TEST_STUFF
+
+//:End Ignore
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/TransductionLog.cpp b/Build/source/libs/graphite/engine-2.3.1/src/segment/TransductionLog.cpp
new file mode 100644
index 00000000000..9071e3fd462
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/TransductionLog.cpp
@@ -0,0 +1,2129 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 2000, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: TransductionLog.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Contains the functions for writing a log of the transduction process.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#include <cstring>
+#include <math.h>
+
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+#define SP_PER_SLOT 7
+#define LEADING_SP 15
+#define MAX_SLOTS 128
+
+/*----------------------------------------------------------------------------------------------
+ Output a file showing a log of the transduction process and the resulting segment.
+----------------------------------------------------------------------------------------------*/
+//bool GrTableManager::WriteTransductionLog(GrCharStream * pchstrm, Segment * psegRet,
+// int cbPrevSegDat, byte * pbPrevSegDat, byte * pbNextSegDat, int * pcbNextSegDat)
+//{
+//#ifdef TRACING
+// std::string staFile;
+// if (!LogFileName(staFile))
+// return false;
+//
+// std::ofstream strmOut;
+// if (cbPrevSegDat > 0)
+// strmOut.open(staFile.c_str(), std::ios::app); // append
+// else
+// strmOut.open(staFile.c_str());
+// if (strmOut.fail())
+// return false;
+//
+// WriteXductnLog(strmOut, pchstrm, psegRet, cbPrevSegDat, pbPrevSegDat);
+//
+// strmOut.close();
+// return true;
+//#else
+// return false;
+//#endif // TRACING
+//}
+
+bool GrTableManager::WriteTransductionLog(std::ostream * pstrmLog,
+ GrCharStream * pchstrm, Segment * psegRet, int cbPrevSegDat, byte * pbPrevSegDat)
+{
+#ifdef TRACING
+ if (!pstrmLog)
+ return false;
+ std::ostream & strmOut = *pstrmLog;
+ WriteXductnLog(strmOut, pchstrm, psegRet, cbPrevSegDat, pbPrevSegDat);
+ return true;
+#else
+ return false;
+#endif // TRACING
+}
+
+/*----------------------------------------------------------------------------------------------
+ Append to the file, showing the surface/underlying mappings. This must be done after
+ figuring out all the associations.
+
+ Also write the final glyph positions, since they are now determined.
+----------------------------------------------------------------------------------------------*/
+//bool GrTableManager::WriteAssociationLog(GrCharStream * pchstrm, Segment * psegRet)
+//{
+//#ifdef TRACING
+// std::string staFile;
+// if (!LogFileName(staFile))
+// return false;
+//
+// std::ofstream strmOut;
+// strmOut.open(staFile.c_str(), std::ios::app); // append
+// if (strmOut.fail())
+// return false;
+//
+// LogFinalPositions(strmOut);
+//
+// strmOut << "\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n";
+//
+// psegRet->LogUnderlyingToSurface(this, strmOut, pchstrm);
+// psegRet->LogSurfaceToUnderlying(this, strmOut);
+//
+// strmOut << "\n\n=======================================================================\n\n";
+//
+// strmOut.close();
+// return true;
+//#else
+// return false;
+//#endif // TRACING
+//}
+
+
+bool GrTableManager::WriteAssociationLog(std::ostream * pstrmLog,
+ GrCharStream * pchstrm, Segment * psegRet)
+{
+#ifdef TRACING
+ if (!pstrmLog)
+ return false;
+
+ std::ostream & strmOut = *pstrmLog;
+ LogFinalPositions(strmOut);
+
+ strmOut << "\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n";
+
+ psegRet->LogUnderlyingToSurface(this, strmOut, pchstrm);
+ psegRet->LogSurfaceToUnderlying(this, strmOut);
+
+ strmOut << "\n\n=======================================================================\n\n";
+
+ return true;
+#else
+ return false;
+#endif // TRACING
+}
+
+#ifdef TRACING
+
+/*----------------------------------------------------------------------------------------------
+ Generate the name of the file where the log will be written. It goes in the directory
+ defined by either the TEMP or TMP environment variable.
+
+ TODO: remove
+----------------------------------------------------------------------------------------------*/
+//bool GrTableManager::LogFileName(std::string & staFile)
+//{
+// char * pchTmpEnv = getenv("TEMP");
+// if (pchTmpEnv == 0)
+// pchTmpEnv = getenv("TMP");
+// if (pchTmpEnv == 0)
+// return false;
+//
+// staFile.assign(pchTmpEnv);
+// if (staFile[staFile.size() - 1] != '\\')
+// staFile.append("\\");
+// staFile.append("gr_xductn.log");
+//
+// return true;
+//}
+
+/*----------------------------------------------------------------------------------------------
+ Output a file showing a log of the transduction process and the resulting segment.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::WriteXductnLog(std::ostream & strmOut,
+ GrCharStream * pchstrm, Segment * psegRet,
+ int cbPrevSegDat, byte * pbPrevSegDat)
+{
+ if (cbPrevSegDat == 0)
+ LogUnderlying(strmOut, pchstrm, 0);
+ else
+ {
+ Assert(*(pbPrevSegDat + 4) == 0); // skip offset for first pass
+ LogUnderlying(strmOut, pchstrm, *(pbPrevSegDat + 3));
+ }
+
+ LogPass1Input(strmOut);
+
+ for (int ipass = 1; ipass < m_cpass; ipass++)
+ {
+ if (cbPrevSegDat == 0)
+ LogPassOutput(strmOut, ipass, 0);
+ else
+ LogPassOutput(strmOut, ipass, *(pbPrevSegDat + 4 + ipass));
+ }
+
+ // Do this later, after outputting final positions:
+ //strmOut << "\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out a log of the underlying input.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogUnderlying(std::ostream & strmOut, GrCharStream * pchstrm,
+ int cchwBackup)
+{
+ strmOut << "UNDERLYING INPUT\n\n";
+
+ int rgnChars[MAX_SLOTS];
+ bool rgfNewRun[MAX_SLOTS];
+ std::fill_n(rgfNewRun, MAX_SLOTS, false);
+ GrFeatureValues rgfval[MAX_SLOTS];
+ int cchwMaxRawChars;
+
+ int cnUtf32 = pchstrm->GetLogData(this, rgnChars, rgfNewRun, rgfval,
+ cchwBackup, &cchwMaxRawChars);
+ cnUtf32 = min(cnUtf32, MAX_SLOTS);
+
+ int ichw;
+
+ // For UTF-8 and surrogate representation:
+ utf16 rgchwChars2[MAX_SLOTS];
+ utf16 rgchwChars3[MAX_SLOTS];
+ utf16 rgchwChars4[MAX_SLOTS];
+ utf16 rgchwChars5[MAX_SLOTS];
+ utf16 rgchwChars6[MAX_SLOTS];
+ int rgcchwRaw[MAX_SLOTS];
+
+ if (cchwMaxRawChars > 1)
+ {
+ cchwMaxRawChars = min(cchwMaxRawChars, 6); // max of 6 raw (UTF-8 or UTF-16) chars per slot
+ pchstrm->GetLogDataRaw(this, cnUtf32, cchwBackup, cchwMaxRawChars,
+ rgnChars, rgchwChars2, rgchwChars3, rgchwChars4, rgchwChars5, rgchwChars6,
+ rgcchwRaw);
+ }
+ else
+ {
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ {
+ rgcchwRaw[ichw] = 1;
+ rgchwChars2[ichw] = 0;
+ rgchwChars3[ichw] = 0;
+ rgchwChars4[ichw] = 0;
+ rgchwChars5[ichw] = 0;
+ rgchwChars6[ichw] = 0;
+ }
+ }
+
+ LogUnderlyingHeader(strmOut, pchstrm->Min(), (pchstrm->Min() + cnUtf32 - cchwBackup),
+ cchwBackup, rgcchwRaw);
+
+ // Text
+ strmOut << "Text: "; // 15 spaces
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ {
+ if (rgnChars[ichw] < 0x0100 && rgchwChars2[ichw] == 0) // ANSI
+ strmOut << (char)rgnChars[ichw] << " "; // 6 spaces
+ else if (rgnChars[ichw] == knLRM)
+ strmOut << "<LRM> ";
+ else if (rgnChars[ichw] == knRLM)
+ strmOut << "<RLM> ";
+ else if (rgnChars[ichw] == knLRO)
+ strmOut << "<LRO> ";
+ else if (rgnChars[ichw] == knRLO)
+ strmOut << "<RLO> ";
+ else if (rgnChars[ichw] == knLRE)
+ strmOut << "<LRE> ";
+ else if (rgnChars[ichw] == knRLE)
+ strmOut << "<RLE> ";
+ else if (rgnChars[ichw] == knPDF)
+ strmOut << "<PDF> ";
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+
+ // Unicode
+ strmOut << "Unicode: ";
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ LogHexInTable(strmOut, utf16(rgnChars[ichw]));
+ strmOut << "\n";
+ for (int icchRaw = 2; icchRaw <= cchwMaxRawChars; icchRaw++)
+ {
+ strmOut << " ";
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ {
+ utf16 chw;
+ switch (icchRaw)
+ {
+ case 2: chw = rgchwChars2[ichw]; break;
+ case 3: chw = rgchwChars3[ichw]; break;
+ case 4: chw = rgchwChars4[ichw]; break;
+ case 5: chw = rgchwChars5[ichw]; break;
+ case 6: chw = rgchwChars6[ichw]; break;
+ default: chw = 0;
+ }
+ if (chw == 0)
+ strmOut << " ";
+ else
+ LogHexInTable(strmOut, chw);
+ }
+ strmOut << "\n";
+ }
+
+ // Runs
+ strmOut << "Runs: ";
+ int crun = 0;
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ {
+ if (rgfNewRun[ichw])
+ {
+ crun++;
+ strmOut << "|" << crun << ((crun < 10) ? " " : " ");
+ }
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+
+ // Features
+ strmOut << "Features and character properties:\n";
+ crun = 0;
+ for (ichw = 0; ichw < cnUtf32; ichw++)
+ {
+ if (rgfNewRun[ichw])
+ {
+ crun++;
+ strmOut << " Run " << crun << ": ";
+ rgfval[ichw].WriteXductnLog(this, strmOut);
+
+ }
+ }
+}
+
+
+void GrFeatureValues::WriteXductnLog(GrTableManager * ptman, std::ostream & strmOut)
+{
+ bool fFirst = true;
+ for (int i = 0; i < kMaxFeatures; i++)
+ {
+ if (m_rgnFValues[i] != 0)
+ {
+ GrFeature * pfeat = ptman->Feature(i);
+ if (!fFirst)
+ strmOut << ",";
+ strmOut << pfeat->ID() << "=" << m_rgnFValues[i];
+ fFirst = false;
+ }
+ }
+ if (fFirst)
+ strmOut << "all features=0";
+
+ strmOut << "\n\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Loop through the input stream of underlying characters, storing information in the
+ arrays for the log.
+ ENHANCE SharonC: do we need to show the underline properties?
+----------------------------------------------------------------------------------------------*/
+int GrCharStream::GetLogData(GrTableManager * ptman, int * rgchl, bool * rgfNewRun,
+ GrFeatureValues * rgfval, int cchrBackup, int * pcchrMax)
+{
+ Assert(cchrBackup <= m_cchrBackedUp);
+
+ int ichrPosToStop = m_ichrPos;
+ int ichrStart = m_ichrMin - max(cchrBackup, m_cchrBackedUp);
+
+ *pcchrMax = 0;
+
+ // Restart the stream.
+ m_ichrPos = ichrStart;
+ m_ichrRunMin = 0;
+ m_ichrRunLim = 0;
+ m_ichrRunOffset = kPosInfinity;
+ m_vislotNextChunkMap.clear();
+
+ int cchrSkipBackup = m_cchrBackedUp - cchrBackup;
+
+ int c = 0;
+ int cchr = 0;
+
+ while (m_ichrPos < ichrPosToStop)
+ {
+ if ((c < MAX_SLOTS) && (m_ichrPos >= m_ichrRunLim))
+ {
+ rgfNewRun[c] = true;
+ }
+
+ GrFeatureValues fval;
+ int ichrOffset, cchrThis;
+ int chl = NextGet(ptman, &fval, &ichrOffset, &cchrThis);
+ cchr += cchrThis;
+ if (cchr <= cchrSkipBackup)
+ {} // ignore - this is before the pre-segment stuff that we want to skip
+ else if (c < MAX_SLOTS)
+ {
+ rgchl[c] = chl;
+ *pcchrMax = max(*pcchrMax, cchrThis);
+ if (rgfNewRun[c])
+ {
+ rgfval[c] = fval;
+ }
+ c++;
+ }
+ }
+
+ ////return (m_ichwPos - (m_ichwMin - cchwBackup));
+ return c;
+}
+
+/*----------------------------------------------------------------------------------------------
+ If any of the characters are comprised of surrogates or UTF-8, fill in the arrays with
+ the raw (UTF-16 or UTF-8) chars for display. To do this we get the raw characters
+ directly from the text source.
+----------------------------------------------------------------------------------------------*/
+void GrCharStream::GetLogDataRaw(GrTableManager * ptman, int cchl, int cchrBackup,
+ int cchrMaxRaw, int * prgchl,
+ utf16 * prgchw2, utf16 * prgchw3, utf16 * prgchw4, utf16 * prgchw5, utf16 * prgchw6,
+ int * prgcchr)
+{
+ for (int i = 0; i < cchl; i++)
+ {
+ prgchw2[i] = 0;
+ }
+
+ int ichrLim = m_ichrPos;
+ int ichrMin = m_ichrMin - cchrBackup;
+
+ int cchrRange = ichrLim - ichrMin;
+ int ichr;
+ utf16 * prgchwRunText = new utf16[cchrRange];
+ utf8 * prgchsRunText8 = NULL;
+
+ UtfType utf = m_pgts->utfEncodingForm();
+
+ switch (utf)
+ {
+ case kutf8:
+ prgchsRunText8 = new utf8[cchrRange];
+ m_pgts->fetch(ichrMin, cchrRange, prgchsRunText8);
+ for (int ichr = 0; ichr < cchrRange; ichr++)
+ prgchwRunText[ichr] = (utf16)prgchsRunText8[ichr]; // zero-extend into UTF-16 buffer
+ break;
+ case kutf16:
+ m_pgts->fetch(ichrMin, cchrRange, prgchwRunText);
+ break;
+ default:
+ case kutf32: // this method should never have been called
+ Assert(false);
+ for (int ichrLp = 0; ichrLp < cchrRange; ichrLp++)
+ {
+ prgcchr[ichrLp] = 1;
+ prgchw2[ichrLp] = 0;
+ prgchw3[ichrLp] = 0;
+ prgchw4[ichrLp] = 0;
+ prgchw5[ichrLp] = 0;
+ prgchw6[ichrLp] = 0;
+ }
+ return;
+ }
+
+ ichr = ichrMin;
+ int ichl = 0;
+ while (ichr < ichrLim)
+ {
+ int cchrThis = 1;
+ // Replace 32-bit char with (first) 16-bit or 8-bit char.
+ prgchl[ichl] = (int)prgchwRunText[ichr - ichrMin];
+ prgcchr[ichr] = cchrThis;
+ ichr++;
+
+ while (!AtUnicodeCharBoundary(prgchwRunText, cchrRange, ichr - ichrMin, utf))
+ {
+ cchrThis++;
+ switch (cchrThis)
+ {
+ case 2: prgchw2[ichl] = prgchwRunText[ichr - ichrMin]; break;
+ case 3: prgchw3[ichl] = prgchwRunText[ichr - ichrMin]; break;
+ case 4: prgchw4[ichl] = prgchwRunText[ichr - ichrMin]; break;
+ case 5: prgchw5[ichl] = prgchwRunText[ichr - ichrMin]; break;
+ case 6: prgchw6[ichl] = prgchwRunText[ichr - ichrMin]; break;
+ default:
+ break;
+ }
+ prgcchr[ichr] = cchrThis;
+ ichr++;
+ }
+ switch (cchrThis)
+ {
+ case 1:
+ prgchw2[ichl] = 0;
+ // fall through
+ case 2:
+ prgchw3[ichl] = 0;
+ // fall through
+ case 3:
+ prgchw4[ichl] = 0;
+ // fall through
+ case 4:
+ prgchw5[ichl] = 0;
+ // fall through
+ case 5:
+ prgchw6[ichl] = 0;
+ }
+ ichl++;
+ }
+
+ delete[] prgchwRunText;
+ delete[] prgchsRunText8;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Output the glyph IDs generated by the glyph generation pass (pass 0).
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogPass1Input(std::ostream & strmOut)
+{
+ strmOut << "INPUT TO PASS 1\n\n";
+
+ GrSlotStream * psstrm = OutputStream(0);
+
+ LogSlotHeader(strmOut, psstrm->WritePos(), SP_PER_SLOT, LEADING_SP);
+
+ LogSlotGlyphs(strmOut, psstrm);
+
+ strmOut << "\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Output the the results of pass.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogPassOutput(std::ostream & strmOut, int ipass, int cslotSkipped)
+{
+ strmOut << "\n";
+
+ GrPass * ppass = Pass(ipass);
+ GrSlotStream * psstrmIn = InputStream(ipass);
+ GrSlotStream * psstrmOut = OutputStream(ipass);
+
+ int islot;
+ // Mark each slot with its index in the input and output streams.
+ for (islot = 0; islot < psstrmIn->ReadPos(); islot++)
+ psstrmIn->SlotAt(islot)->m_islotTmpIn = islot;
+
+ for (islot = 0; islot < psstrmOut->WritePos(); islot++)
+ psstrmOut->SlotAt(islot)->m_islotTmpOut = islot;
+
+ if (!dynamic_cast<GrBidiPass *>(ppass))
+ ppass->LogRulesFiredAndFailed(strmOut, psstrmIn);
+
+ strmOut << "\nOUTPUT OF PASS " << ipass;
+ if (dynamic_cast<GrBidiPass *>(ppass))
+ strmOut << " (bidi)";
+ else if (dynamic_cast<GrSubPass *>(ppass))
+ {
+ if (ipass >= m_ipassJust1)
+ strmOut << " (justification)";
+ else
+ strmOut << " (substitution)";
+ }
+ else if (dynamic_cast<GrPosPass *>(ppass))
+ strmOut << " (positioning)";
+ else if (dynamic_cast<GrLineBreakPass *>(ppass))
+ strmOut << " (linebreak)";
+ strmOut << "\n";
+
+ ppass->LogInsertionsAndDeletions(strmOut, psstrmOut);
+
+ LogSlotHeader(strmOut, psstrmOut->WritePos(), SP_PER_SLOT, LEADING_SP);
+
+ LogSlotGlyphs(strmOut, psstrmOut);
+
+ bool fAnyPseudos = false;
+ if (dynamic_cast<GrPosPass *>(ppass))
+ {
+ for (islot = 0; islot < psstrmOut->WritePos(); islot++)
+ {
+ GrSlotState * pslotTmp = psstrmOut->SlotAt(islot);
+ if (pslotTmp->GlyphID() != pslotTmp->ActualGlyphForOutput(this))
+ {
+ fAnyPseudos = true;
+ break;
+ }
+ }
+ }
+ if (fAnyPseudos)
+ {
+ strmOut << "Actual glyphs: ";
+ for (islot = 0; islot < psstrmOut->WritePos(); islot++)
+ {
+ GrSlotState * pslotTmp = psstrmOut->SlotAt(islot);
+ if (pslotTmp->GlyphID() != pslotTmp->ActualGlyphForOutput(this))
+ LogHexInTable(strmOut, pslotTmp->ActualGlyphForOutput(this));
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+
+ LogAttributes(strmOut, ipass);
+
+ // Do this later, after we're sure the positions have been set:
+ //if (ipass == m_cpass - 1)
+ // LogFinalPositions(strmOut);
+
+ if (cslotSkipped > 0)
+ {
+ strmOut << "\n ";
+ for (islot = 0; islot < cslotSkipped; islot++)
+ strmOut << "SKIP ";
+ strmOut << "\n";
+ }
+
+ // If this was the pass just before the justification routines get run, output a
+ // special line that just shows the results, ie, the values of justify.width.
+ // TODO: adjust this when measure mode get functioning.
+ if (ipass == m_ipassJust1 - 1 && ShouldLogJustification()
+ && m_engst.m_jmodi == kjmodiJustify)
+ {
+ strmOut << "\nJUSTIFICATION\n\n";
+ LogSlotHeader(strmOut, psstrmOut->WritePos(), SP_PER_SLOT, LEADING_SP);
+ LogSlotGlyphs(strmOut, psstrmOut);
+ LogAttributes(strmOut, ipass, true);
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write the list of rules fired and failed for a given pass.
+----------------------------------------------------------------------------------------------*/
+void GrPass::LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn)
+{
+ m_pzpst->LogRulesFiredAndFailed(strmOut, psstrmIn);
+}
+
+void PassState::LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn)
+{
+
+ strmOut << "PASS " << m_ipass << "\n\n" << "Rules matched: ";
+ if (m_crulrec == 0)
+ strmOut << "none";
+ strmOut << "\n";
+
+ for (int irulrec = 0; irulrec < m_crulrec; irulrec++)
+ {
+ if (m_rgrulrec[irulrec].m_fFired)
+ strmOut << " * ";
+ else
+ strmOut << " ";
+
+ strmOut << m_rgrulrec[irulrec].m_islot << ". ";
+
+ if (m_rgrulrec[irulrec].m_irul == PassState::kHitMaxRuleLoop)
+ strmOut << "hit MaxRuleLoop\n";
+ else if (m_rgrulrec[irulrec].m_irul == PassState::kHitMaxBackup)
+ strmOut << "hit MaxBackup\n";
+ else
+ {
+ strmOut << "rule " << m_ipass << "." << m_rgrulrec[irulrec].m_irul;
+
+ if (m_rgrulrec[irulrec].m_fFired)
+ strmOut << " FIRED\n";
+ else
+ strmOut << " failed\n";
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the marks on top of the slot table indicating insertions and deletions.
+----------------------------------------------------------------------------------------------*/
+void GrPass::LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut)
+{
+ m_pzpst->LogInsertionsAndDeletions(strmOut, psstrmOut);
+}
+
+void PassState::LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut)
+{
+ int cslotDel = m_rgcslotDeletions[0];
+ bool fIns;
+ if (cslotDel > 1)
+ strmOut << "\n DEL-" << cslotDel;
+ else if (cslotDel == 1)
+ strmOut << "\n DEL ";
+ else
+ strmOut << "\n ";
+
+ for (int islot = 0; islot < psstrmOut->WritePos(); islot++)
+ {
+ cslotDel = (islot + 1 >= MAX_SLOTS) ? 0 : m_rgcslotDeletions[islot + 1];
+ fIns = (islot >= MAX_SLOTS) ? 0 : m_rgfInsertion[islot];
+
+ if (fIns)
+ {
+ strmOut << "INS";
+ if (cslotDel > 0)
+ {
+ if (cslotDel > 1)
+ strmOut << "/D-" << cslotDel;
+ else
+ strmOut << "/DEL";
+ }
+ else
+ strmOut << " ";
+
+ }
+ else if (cslotDel > 0)
+ {
+ if (cslotDel >= 10)
+ strmOut << "DEL-" << cslotDel << " ";
+ else if (cslotDel > 1)
+ strmOut << " DEL-" << cslotDel << " ";
+ else
+ strmOut << " DEL ";
+ }
+ else
+ strmOut << " ";
+ }
+
+ strmOut << "\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out a line for each slot attribute that changed during the pass.
+
+ @param fJustWidths - a special pass that writes out just the effects of the justification
+ routines, ie, the values of justify.width
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogAttributes(std::ostream & strmOut, int ipass,
+ bool fJustWidths)
+{
+ // Figure out which slot attributes were modified for some slot during the pass.
+ bool * prgfMods = new bool[kslatMax + NumUserDefn() - 1];
+
+ bool fPreJust = (!fJustWidths && ipass == m_ipassJust1 - 1 && ShouldLogJustification());
+ bool fPostJust = ((fJustWidths || ipass == m_ipassJust1) && ShouldLogJustification());
+
+ int ccomp; // max number of components per slot
+ int cassoc; // max number of associations per slot
+ SlotAttrsModified(ipass, prgfMods, fPreJust, &ccomp, &cassoc);
+
+ if (fPreJust)
+ {
+ // prgfMods[kslatJStretch] = true;
+ // prgfMods[kslatJShrink] = true;
+ // prgfMods[kslatJStep] = true;
+ // prgfMods[kslatWeight] = true;
+ prgfMods[kslatJWidth] = false; // output j.width in its own line (we call this
+ // method with fJustWidths == true)
+ }
+ else if (fPostJust)
+ prgfMods[kslatJWidth] = true;
+
+ GrPass * ppass = Pass(ipass);
+ GrPass * ppassNext = (ipass < m_cpass - 1) ? Pass(ipass + 1) : NULL;
+ GrSlotStream * psstrm = OutputStream(ipass);
+
+ if (fJustWidths)
+ {}
+ else if (dynamic_cast<GrBidiPass *>(ppass))
+ {
+ // Special stuff for Bidi pass:
+ // Log value of directionality attribute.
+ strmOut << "directionality ";
+ int islot;
+ for (islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ LogDirCodeInTable(strmOut, pslot->DirProcessed());
+ }
+ strmOut << "\n";
+
+ // Log final direction level for bidi pass.
+ strmOut << "dir level ";
+ for (islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ LogInTable(strmOut, pslot->DirLevel());
+ }
+ strmOut << "\n";
+ }
+ else if (ppassNext && dynamic_cast<GrBidiPass *>(ppassNext))
+ {
+ // Next pass is Bidi: log input values of directionality attribute that are input for it.
+ strmOut << "directionality ";
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ LogDirCodeInTable(strmOut, pslot->Directionality());
+ }
+ strmOut << "\n";
+ }
+
+ for (int slat = 0; slat < kslatMax + NumUserDefn() - 1; slat++)
+ {
+ int cIndexLim = 1;
+ if (slat == kslatCompRef)
+ cIndexLim = ccomp;
+ else if (slat == kslatUserDefn)
+ cIndexLim = 1; // kMaxUserDefinedSlotAttributes;
+
+ if (fJustWidths && slat != kslatJWidth)
+ continue;
+
+ bool fValidAttr = true;
+ for (int iIndex = 0; iIndex < cIndexLim; iIndex++)
+ {
+ if (prgfMods[slat])
+ {
+ switch(slat)
+ {
+ case kslatAdvX: strmOut << "advance.x "; break;
+ case kslatAdvY: strmOut << "advance.y "; break;
+ case kslatAttTo: strmOut << "att.to "; break;
+ case kslatAttAtX: strmOut << "att.at.x "; break;
+ case kslatAttAtY: strmOut << "att.at.y "; break;
+ case kslatAttAtGpt: strmOut << "att.at.gpt "; break;
+ case kslatAttAtXoff: strmOut << "att.at.xoff "; break;
+ case kslatAttAtYoff: strmOut << "att.at.yoff "; break;
+ case kslatAttWithX: strmOut << "att.with.x "; break;
+ case kslatAttWithY: strmOut << "att.with.y "; break;
+ case kslatAttWithGpt: strmOut << "att.with.gpt "; break;
+ case kslatAttWithXoff: strmOut << "att.with.xoff "; break;
+ case kslatAttWithYoff: strmOut << "att.with.yoff "; break;
+ case kslatAttLevel: strmOut << "att.level "; break;
+ case kslatBreak: strmOut << "breakweight "; break;
+ case kslatCompRef: strmOut << "component " << iIndex + 1 // 1-based
+ << " "; break;
+ case kslatDir: strmOut << "dir "; break;
+ case kslatInsert: strmOut << "insert "; break;
+ case kslatMeasureSol: strmOut << "measure.sol "; break;
+ case kslatMeasureEol: strmOut << "measure.eol "; break;
+ case kslatJStretch: strmOut << "j.stretch "; break;
+ case kslatJShrink: strmOut << "j.shrink "; break;
+ case kslatJStep: strmOut << "j.step "; break;
+ case kslatJWeight: strmOut << "j.weight "; break;
+ case kslatJWidth: strmOut << "j.width "; break;
+ case kslatPosX:
+ case kslatPosY:
+ Assert(false);
+ break;
+ case kslatShiftX: strmOut << "shift.x "; break;
+ case kslatShiftY: strmOut << "shift.y "; break;
+ default:
+ if (kslatUserDefn <= slat &&
+ slat < kslatUserDefn + NumUserDefn())
+ {
+ strmOut << "user" << (slat - kslatUserDefn + 1) // 1-based
+ << ((iIndex >= 9) ? " " : " ");
+ }
+ else
+ {
+ // Invalid attribute:
+ Warn("bad slot attribute");
+ fValidAttr = false;
+ break;
+ }
+ }
+
+ if (!fValidAttr)
+ break; // out of iIndex loop
+
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ pslot->LogSlotAttribute(this, strmOut, ipass, slat, iIndex,
+ fPreJust, fPostJust);
+ }
+
+ strmOut << "\n";
+ }
+ }
+ }
+
+ if (fJustWidths)
+ goto LDone;
+
+ for (int iassoc = 0; iassoc < cassoc; iassoc++)
+ {
+ // Log associations. Put them on one line it that will work; otherwise use several.
+ bool fBoth = (cassoc <= 2);
+ bool fAfter = (iassoc == (cassoc - 1));
+ if (fBoth)
+ strmOut << "assocs ";
+ else if (iassoc == 0)
+ strmOut << "assocs-before ";
+ else if (fAfter)
+ strmOut << " -after ";
+ else
+ strmOut << " -other ";
+
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ pslot->LogAssociation(this, strmOut, ipass, iassoc, fBoth, fAfter);
+ }
+
+ strmOut << "\n";
+
+ if (fBoth)
+ break;
+ }
+
+ if (cassoc == 0 && dynamic_cast<GrBidiPass *>(ppass))
+ {
+ strmOut << "assocs ";
+
+ // Log associations for all slots moved during the Bidi pass.
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->m_islotTmpIn != pslot->m_islotTmpOut)
+ LogInTable(strmOut, pslot->m_islotTmpIn);
+ else
+ strmOut << " ";
+ }
+
+ strmOut << "\n";
+ }
+
+LDone:
+
+ delete[] prgfMods;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the final positions.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogFinalPositions(std::ostream & strmOut)
+{
+ GrSlotStream * psstrm = OutputStream(m_cpass - 1);
+
+ strmOut << "x position ";
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsLineBreak(LBGlyphID()))
+ {
+ strmOut << " ";
+ continue;
+ }
+ LogInTable(strmOut, pslot->XPosition());
+ }
+ strmOut << "\n";
+
+ strmOut << "y position ";
+ for (int islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrm->SlotAt(islot);
+ if (pslot->IsLineBreak(LBGlyphID()))
+ {
+ strmOut << " ";
+ continue;
+ }
+ LogInTable(strmOut, pslot->YPosition());
+ }
+ strmOut << "\n";
+}
+#endif // TRACING
+
+/*----------------------------------------------------------------------------------------------
+ Write out the final underlying-to-surface associations.
+----------------------------------------------------------------------------------------------*/
+void Segment::LogUnderlyingToSurface(GrTableManager * ptman, std::ostream & strmOut,
+ GrCharStream * pchstrm)
+{
+#ifdef TRACING
+ strmOut << "\n\nUNDERLYING TO SURFACE MAPPINGS\n\n";
+
+ size_t cassocs = 0;
+ int fLigs = false;
+ int ichw;
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ if (m_prgpvisloutAssocs[ichw])
+ cassocs = max(cassocs, m_prgpvisloutAssocs[ichw]->size());
+ if (m_prgisloutLigature[ichw] != kNegInfinity)
+ fLigs = true;
+ }
+
+// ptman->LogSlotHeader(strmOut, m_ichwAssocsLim, SP_PER_SLOT, LEADING_SP, m_ichwAssocsMin);
+ ptman->LogUnderlyingHeader(strmOut, pchstrm->Min(), (pchstrm->Min() + m_ichwAssocsLim),
+ -m_ichwAssocsMin, NULL);
+
+ int rgnChars[MAX_SLOTS];
+ bool rgfNewRun[MAX_SLOTS];
+ std::fill_n(rgfNewRun, MAX_SLOTS, false);
+ GrFeatureValues rgfval[MAX_SLOTS];
+ int cchwMaxRawChars;
+
+ int cchw = pchstrm->GetLogData(ptman, rgnChars, rgfNewRun, rgfval,
+ -m_ichwAssocsMin, &cchwMaxRawChars);
+ cchw = min(cchw, MAX_SLOTS);
+
+ utf16 rgchwChars2[MAX_SLOTS];
+ utf16 rgchwChars3[MAX_SLOTS];
+ utf16 rgchwChars4[MAX_SLOTS];
+ utf16 rgchwChars5[MAX_SLOTS];
+ utf16 rgchwChars6[MAX_SLOTS];
+ int rgcchwRaw[MAX_SLOTS];
+ if (cchwMaxRawChars > 1)
+ {
+ cchwMaxRawChars = min(cchwMaxRawChars, 6);
+ pchstrm->GetLogDataRaw(ptman, cchw, -m_ichwAssocsMin, cchwMaxRawChars,
+ rgnChars, rgchwChars2, rgchwChars3, rgchwChars4, rgchwChars5, rgchwChars6,
+ rgcchwRaw);
+ }
+ else
+ {
+ for (ichw = 0 ; ichw <(m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ rgcchwRaw[ichw] = 1;
+ rgchwChars2[ichw] = 0;
+ rgchwChars3[ichw] = 0;
+ rgchwChars4[ichw] = 0;
+ rgchwChars5[ichw] = 0;
+ rgchwChars6[ichw] = 0;
+ }
+ }
+
+ // Text
+ strmOut << "Text: "; // 15 spaces
+ int inUtf32 = 0;
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ utf16 chw, chwNext;
+ switch (rgcchwRaw[ichw])
+ {
+ default:
+ case 1: chw = utf16(rgnChars[inUtf32]); chwNext = rgchwChars2[inUtf32]; break;
+ case 2: chw = rgchwChars2[inUtf32]; chwNext = rgchwChars3[inUtf32]; break;
+ case 3: chw = rgchwChars3[inUtf32]; chwNext = rgchwChars4[inUtf32]; break;
+ case 4: chw = rgchwChars4[inUtf32]; chwNext = rgchwChars5[inUtf32]; break;
+ case 5: chw = rgchwChars5[inUtf32]; chwNext = rgchwChars6[inUtf32]; break;
+ case 6: chw = rgchwChars6[inUtf32]; chwNext = 0; break;
+ }
+ if (rgcchwRaw[ichw] == 1 && chwNext == 0 && chw < 0x0100) // ANSI
+ strmOut << (char)chw << " "; // 6 spaces
+ else
+ strmOut << " "; // 7 spaces
+ if (chwNext == 0)
+ inUtf32++;
+ }
+ strmOut << "\n";
+
+ // Unicode
+ strmOut << "Unicode: ";
+ inUtf32 = 0;
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ utf16 chw, chwNext;
+ switch (rgcchwRaw[ichw])
+ {
+ default:
+ case 1: chw = utf16(rgnChars[inUtf32]); chwNext = rgchwChars2[inUtf32]; break;
+ case 2: chw = rgchwChars2[inUtf32]; chwNext = rgchwChars3[inUtf32]; break;
+ case 3: chw = rgchwChars3[inUtf32]; chwNext = rgchwChars4[inUtf32]; break;
+ case 4: chw = rgchwChars4[inUtf32]; chwNext = rgchwChars5[inUtf32]; break;
+ case 5: chw = rgchwChars5[inUtf32]; chwNext = rgchwChars6[inUtf32]; break;
+ case 6: chw = rgchwChars6[inUtf32]; chwNext = 0; break;
+ }
+ ptman->LogHexInTable(strmOut, chw, chwNext != 0);
+ if (chwNext == 0)
+ inUtf32++;
+ }
+ strmOut << "\n";
+
+ strmOut << "before ";
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ if (rgcchwRaw[ichw] > 1)
+ // continuation of Unicode codepoint
+ strmOut << " ";
+ else if (m_prgisloutBefore[ichw] == kNegInfinity)
+ strmOut << "<-- ";
+ else if (m_prgisloutBefore[ichw] == kPosInfinity)
+ strmOut << "--> ";
+ else
+ ptman->LogInTable(strmOut, m_prgisloutBefore[ichw]);
+ }
+ strmOut <<"\n";
+
+ for (int ix = 1; ix < signed(cassocs) - 1; ix++) //(cassocs > 2)
+ {
+ if (ix == 1)
+ strmOut << "other ";
+ else
+ strmOut << " ";
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ std::vector<int> * pvislout = m_prgpvisloutAssocs[ichw];
+ if (pvislout == NULL)
+ strmOut << " ";
+ else if (signed(pvislout->size()) <= ix)
+ strmOut << " ";
+ else if ((*pvislout)[ix] != m_prgisloutAfter[ichw])
+ ptman->LogInTable(strmOut, (*pvislout)[ix]);
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+
+ strmOut << "after ";
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ if (rgcchwRaw[ichw] > 1)
+ // continuation of Unicode codepoint
+ strmOut << " ";
+ else if (m_prgisloutAfter[ichw] == kNegInfinity)
+ strmOut << "<-- ";
+ else if (m_prgisloutAfter[ichw] == kPosInfinity)
+ strmOut << "--> ";
+ else
+ ptman->LogInTable(strmOut, m_prgisloutAfter[ichw]);
+ }
+ strmOut <<"\n";
+
+ if (fLigs)
+ {
+ strmOut << "ligature ";
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ if (rgcchwRaw[ichw] > 1)
+ // continuation of Unicode codepoint
+ strmOut << " ";
+ else if (m_prgisloutLigature[ichw] != kNegInfinity)
+ ptman->LogInTable(strmOut, m_prgisloutLigature[ichw]);
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+
+ strmOut << "component ";
+ for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++)
+ {
+ if (rgcchwRaw[ichw] > 1)
+ // continuation of Unicode codepoint
+ strmOut << " ";
+ else if (m_prgisloutLigature[ichw] != kNegInfinity)
+ ptman->LogInTable(strmOut, m_prgiComponent[ichw] + 1); // 1-based
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+
+ strmOut << "\n";
+#endif
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the final surface-to-underlying associations.
+----------------------------------------------------------------------------------------------*/
+void Segment::LogSurfaceToUnderlying(GrTableManager * ptman, std::ostream & strmOut)
+{
+#ifdef TRACING
+ strmOut << "\nSURFACE TO UNDERLYING MAPPINGS\n\n";
+
+ ptman->LogSlotHeader(strmOut, m_cslout, SP_PER_SLOT, LEADING_SP);
+
+ int ccomp = 0;
+
+ strmOut << "Glyph IDs: ";
+ int islout;
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->SpecialSlotFlag() == kspslLbInitial ||
+ psloutTmp->SpecialSlotFlag() == kspslLbFinal)
+ {
+ strmOut << "# ";
+ }
+ else
+ {
+ ptman->LogHexInTable(strmOut, psloutTmp->GlyphID());
+ ccomp = max(ccomp, psloutTmp->NumberOfComponents());
+ }
+ }
+ strmOut << "\n";
+
+ bool fAnyPseudos = false;
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->GlyphID() != psloutTmp->ActualGlyphForOutput(ptman))
+ {
+ fAnyPseudos = true;
+ break;
+ }
+ }
+ if (fAnyPseudos)
+ {
+ strmOut << "Actual glyphs: ";
+ for (int islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->GlyphID() != psloutTmp->ActualGlyphForOutput(ptman))
+ ptman->LogHexInTable(strmOut, psloutTmp->ActualGlyphForOutput(ptman));
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+
+ strmOut << "before ";
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->SpecialSlotFlag() == kspslLbInitial ||
+ psloutTmp->SpecialSlotFlag() == kspslLbFinal)
+ {
+ strmOut << " ";
+ }
+ else
+ ptman->LogInTable(strmOut, psloutTmp->BeforeAssoc());
+ }
+ strmOut << "\n";
+
+ strmOut << "after ";
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->SpecialSlotFlag() == kspslLbInitial ||
+ psloutTmp->SpecialSlotFlag() == kspslLbFinal)
+ {
+ strmOut << " ";
+ }
+ else
+ ptman->LogInTable(strmOut, psloutTmp->AfterAssoc());
+ }
+ strmOut << "\n";
+
+ for (int icomp = 0; icomp < ccomp; icomp++)
+ {
+ strmOut << "component " << icomp + 1 // 1=based
+ << " ";
+ for (islout = 0; islout < m_cslout; islout++)
+ {
+ GrSlotOutput * psloutTmp = m_prgslout + islout;
+ if (psloutTmp->SpecialSlotFlag() == kspslLbInitial ||
+ psloutTmp->SpecialSlotFlag() == kspslLbFinal)
+ {
+ strmOut << " ";
+ }
+ else if (icomp < psloutTmp->NumberOfComponents())
+ {
+ if (psloutTmp->FirstUnderlyingComponent(icomp)
+ != psloutTmp->LastUnderlyingComponent(icomp)) // $$$$$
+ {
+ // Multiple characters represented by this component.
+ char rgch[10];
+ std::string strTmp;
+ sprintf(rgch, "%d", psloutTmp->FirstUnderlyingComponent(icomp));
+ strTmp += rgch;
+ memset(rgch, 0, 10);
+ sprintf(rgch, "%d", psloutTmp->LastUnderlyingComponent(icomp));
+ strTmp += "/";
+ strTmp += rgch;
+ if (strlen(strTmp.c_str()) > SP_PER_SLOT-1)
+ strmOut << "****** ";
+ else
+ {
+ while (strlen(strTmp.c_str()) < SP_PER_SLOT) // pad with spaces
+ strTmp += " ";
+ strmOut << strTmp;
+ }
+ }
+ else
+ ptman->LogInTable(strmOut, psloutTmp->FirstUnderlyingComponent(icomp)); // $$$$$
+ }
+ else
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+#endif
+}
+
+#ifdef TRACING
+/*----------------------------------------------------------------------------------------------
+ Write out the header lines for the underlying data.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogUnderlyingHeader(std::ostream & strmOut, int iMin,
+ int iLim, int cBackup, int * prgichr)
+{
+ strmOut << "string ";
+ int i, iLabel;
+ int * pichr = prgichr;
+ for (i = iMin - cBackup, iLabel = i; i < iLim; i++, iLabel++, pichr++)
+ {
+ while (prgichr && *pichr > 1)
+ {
+ // continuation of upper-plane char
+ iLabel++;
+ pichr++;
+ }
+ LogInTable(strmOut, iLabel);
+ }
+ strmOut << "\n";
+
+ strmOut << "segment ";
+ pichr = prgichr;
+ for (i = 0 - cBackup, iLabel = i; i < (iLim - iMin); i++, iLabel++, pichr++)
+ {
+ while (prgichr && *pichr > 1)
+ {
+ // continuation of upper-plane char
+ iLabel++;
+ pichr++;
+ }
+ LogInTable(strmOut, iLabel);
+ }
+ strmOut << "\n\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the header lines for the slot contents.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogSlotHeader(std::ostream & strmOut, int islotLim,
+ int cspPerSlot, int cspLeading, int islotMin)
+{
+ islotLim = min(islotLim, MAX_SLOTS);
+
+ int isp, islot;
+
+ for (isp = 0; isp < cspLeading; isp++)
+ strmOut << " ";
+
+ for (islot = islotMin; islot < islotLim; islot++)
+ LogInTable(strmOut, islot);
+ strmOut << "\n\n";
+
+/****
+ if (cslot >= 100)
+ {
+ for (isp = 0; isp < cspLeading; isp++)
+ strmOut << " ";
+
+ for (islot = 0; islot < 100; islot++)
+ {
+ for (isp = 0; isp < cspPerSlot; isp++)
+ strmOut << " ";
+ }
+
+ for (islot = 100; islot < cslot; islot++)
+ {
+ strmOut << "1";
+ for (isp = 1; isp < cspPerSlot; isp++)
+ strmOut << " ";
+ }
+ }
+
+ if (cslot > 10)
+ {
+ for (isp = 0; isp < cspLeading; isp++)
+ strmOut << " ";
+
+ for (islot = 0; islot < 10; islot++)
+ {
+ for (isp = 0; isp < cspPerSlot; isp++)
+ strmOut << " ";
+ }
+
+ for (islot = 10; islot < cslot; islot++)
+ {
+ if (true) // (islot % 10 == 0)
+ {
+ if (islot >= 100)
+ strmOut << ((islot - 100) / 10);
+ else
+ strmOut << (islot / 10);
+ }
+ else
+ strmOut << " ";
+
+ for (isp = 1; isp < cspPerSlot; isp++)
+ strmOut << " ";
+ }
+ strmOut << "\n";
+ }
+
+ for (isp = 0; isp < cspLeading; isp++)
+ strmOut << " ";
+
+ for (islot = 0; islot < cslot; islot++)
+ {
+ strmOut << (islot % 10);
+ for (isp = 1; isp < cspPerSlot; isp++)
+ strmOut << " ";
+
+ }
+ strmOut << "\n";
+****/
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write out the glyph numbers for the given stream.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogSlotGlyphs(std::ostream & strmOut, GrSlotStream * psstrm)
+{
+ strmOut << "Glyph IDs: ";
+ int islot;
+ for (islot = 0; islot < psstrm->WritePos(); islot++)
+ {
+ GrSlotState * pslotTmp = psstrm->SlotAt(islot);
+ if (pslotTmp->IsLineBreak(LBGlyphID()))
+ strmOut << "# ";
+ else
+ LogHexInTable(strmOut, pslotTmp->GlyphID());
+ }
+ strmOut << "\n";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Return flags indicating which attributes were modified for some slot during the pass
+ and therefore need a line in the log file.
+
+ The 'pfMods' array has one flag per slot attribute; the final group are the user-
+ definable attributes. 'pccomp' returns the maximum number of ligature components
+ in this pass. Associations are assumed to have changed if anything else for the slot did.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::SlotAttrsModified(int ipass, bool * rgfMods, bool fPreJust,
+ int * pccomp, int * pcassoc)
+{
+ // Zero the flags
+ std::fill_n(rgfMods, kslatMax + NumUserDefn() - 1, false);
+ *pccomp = 0;
+ *pcassoc = 0;
+
+ //GrSlotStream * psstrmIn = InputStream(ipass);
+ GrSlotStream * psstrmOut = OutputStream(ipass);
+
+ for (int islot = 0; islot < psstrmOut->WritePos(); islot++)
+ {
+ GrSlotState * pslot = psstrmOut->SlotAt(islot);
+ Assert(pslot->PassModified() <= ipass);
+ if (pslot->PassModified() < ipass && !fPreJust)
+ continue; // not modified during this pass
+
+ pslot->SlotAttrsModified(rgfMods, fPreJust, pccomp, pcassoc);
+ }
+}
+
+void GrSlotState::SlotAttrsModified(bool * rgfMods, bool fPreJust, int * pccomp, int * pcassoc)
+{
+ // To handle reprocessing, in which case there may be a chain of slots modified
+ // in the same pass:
+ GrSlotState * pslotPrev = m_pslotPrevState;
+ while (pslotPrev && pslotPrev->PassModified() == PassModified())
+ pslotPrev = pslotPrev->m_pslotPrevState;
+
+ if (!pslotPrev)
+ {
+ // Inserted slot?
+ if (m_fAdvXSet)
+ rgfMods[kslatAdvX] = true;
+ if (m_fAdvYSet)
+ rgfMods[kslatAdvY] = true;
+
+ if (m_srAttachTo != 0)
+ rgfMods[kslatAttTo] = true;
+
+ if (m_mAttachAtX != kNotYetSet || m_mAttachAtY != 0)
+ { // always do these in pairs
+ rgfMods[kslatAttAtX] = true;
+ rgfMods[kslatAttAtY] = true;
+ }
+ if (m_nAttachAtGpoint != kNotYetSet)
+ rgfMods[kslatAttAtGpt] = true;
+ if (m_mAttachAtXOffset != 0 || m_mAttachAtYOffset != 0)
+ { // always do these in pairs
+ rgfMods[kslatAttAtXoff] = true;
+ rgfMods[kslatAttAtYoff] = true;
+ }
+
+ if (m_mAttachWithX != kNotYetSet || m_mAttachWithY != 0)
+ { // always do these in pairs
+ rgfMods[kslatAttWithX] = true;
+ rgfMods[kslatAttWithY] = true;
+ }
+ if (m_nAttachWithGpoint != kNotYetSet)
+ rgfMods[kslatAttWithGpt] = true;
+ if (m_mAttachWithXOffset != 0 || m_mAttachWithYOffset != 0)
+ { // always do these in pairs
+ rgfMods[kslatAttWithXoff] = true;
+ rgfMods[kslatAttWithYoff] = true;
+ }
+
+ if (m_nAttachLevel != 0)
+ rgfMods[kslatAttLevel] = true;
+
+ if (m_lb != kNotYetSet8)
+ rgfMods[kslatBreak] = true;
+ if (m_dirc != kNotYetSet8)
+ rgfMods[kslatDir] = true;
+ if (m_fInsertBefore != true)
+ rgfMods[kslatInsert] = true;
+
+ if (m_mMeasureSol != kNotYetSet && m_mMeasureSol != 0)
+ rgfMods[kslatMeasureSol] = true;
+ if (m_mMeasureEol != kNotYetSet && m_mMeasureEol != 0)
+ rgfMods[kslatMeasureEol] = true;
+
+ if (m_mJStretch0 != kNotYetSet && m_mJStretch0 != 0)
+ rgfMods[kslatJStretch] = true;
+ if (m_mJShrink0 != kNotYetSet && m_mJShrink0 != 0)
+ rgfMods[kslatJShrink] = true;
+ if (m_mJStep0 != kNotYetSet && m_mJStep0 != 0)
+ rgfMods[kslatJStep] = true;
+ if (m_nJWeight0 != byte(kNotYetSet) &&
+ m_nJWeight0 != 0 && m_nJWeight0 != 1)
+ rgfMods[kslatJWeight] = true;
+ if (m_mJWidth0 != kNotYetSet && m_mJWidth0 != 0)
+ rgfMods[kslatJWidth] = true;
+
+ if (m_mShiftX != 0)
+ rgfMods[kslatShiftX] = true;
+ if (m_mShiftY != 0)
+ rgfMods[kslatShiftY] = true;
+
+ int i;
+ for (i = 0; i < m_cnCompPerLig; i++)
+ {
+ if (CompRef(i) != NULL)
+ rgfMods[kslatCompRef] = true;
+ if (CompRef(i))
+ *pccomp = max(*pccomp, i + 1); // max number of ligatures in this pass
+ }
+
+ for (i = 0; i < m_cnUserDefn; i++)
+ {
+ if (UserDefn(i) != 0)
+ rgfMods[kslatUserDefn + i] = true;
+ }
+ }
+ else
+ {
+ if (m_fAdvXSet && m_mAdvanceX != pslotPrev->m_mAdvanceX)
+ rgfMods[kslatAdvX] = true;
+ if (m_fAdvYSet && m_mAdvanceY != pslotPrev->m_mAdvanceY)
+ rgfMods[kslatAdvY] = true;
+
+ if (m_srAttachTo != pslotPrev->m_srAttachTo)
+ rgfMods[kslatAttTo] = true;
+
+ if (m_mAttachAtX != pslotPrev->m_mAttachAtX || m_mAttachAtY != pslotPrev->m_mAttachAtY)
+ {
+ rgfMods[kslatAttAtX] = true;
+ rgfMods[kslatAttAtY] = true;
+ }
+ if (m_nAttachAtGpoint != pslotPrev->m_nAttachAtGpoint)
+ rgfMods[kslatAttAtGpt] = true;
+ if (m_mAttachAtXOffset != pslotPrev->m_mAttachAtXOffset ||
+ m_mAttachAtYOffset != pslotPrev->m_mAttachAtYOffset)
+ {
+ rgfMods[kslatAttAtXoff] = true;
+ rgfMods[kslatAttAtYoff] = true;
+ }
+
+ if (m_mAttachWithX != pslotPrev->m_mAttachWithX ||
+ m_mAttachWithY != pslotPrev->m_mAttachWithY)
+ {
+ rgfMods[kslatAttWithX] = true;
+ rgfMods[kslatAttWithY] = true;
+ }
+ if (m_nAttachWithGpoint != pslotPrev->m_nAttachWithGpoint)
+ rgfMods[kslatAttWithGpt] = true;
+ if (m_mAttachWithXOffset != pslotPrev->m_mAttachWithXOffset ||
+ m_mAttachWithYOffset != pslotPrev->m_mAttachWithYOffset)
+ {
+ rgfMods[kslatAttWithXoff] = true;
+ rgfMods[kslatAttWithYoff] = true;
+ }
+
+ if (m_nAttachLevel != pslotPrev->m_nAttachLevel)
+ rgfMods[kslatAttLevel] = true;
+
+ if (m_lb != pslotPrev->m_lb)
+ rgfMods[kslatBreak] = true;
+ if (m_dirc != pslotPrev->m_dirc)
+ rgfMods[kslatDir] = true;
+ if (m_fInsertBefore != pslotPrev->m_fInsertBefore)
+ rgfMods[kslatInsert] = true;
+
+ if (m_mMeasureSol != pslotPrev->m_mMeasureSol)
+ rgfMods[kslatMeasureSol] = true;
+ if (m_mMeasureEol != pslotPrev->m_mMeasureEol)
+ rgfMods[kslatMeasureEol] = true;
+
+ if (m_mJStretch0 != pslotPrev->m_mJStretch0 || (fPreJust && m_mJStretch0 != 0))
+ rgfMods[kslatJStretch] = true;
+ if (m_mJShrink0 != pslotPrev->m_mJShrink0 || (fPreJust && m_mJShrink0 != 0))
+ rgfMods[kslatJShrink] = true;
+ if (m_mJStep0 != pslotPrev->m_mJStep0 || (fPreJust && m_mJStep0 != 0))
+ rgfMods[kslatJStep] = true;
+ if (m_nJWeight0 != pslotPrev->m_nJWeight0 || (fPreJust && m_nJWeight0 != 0))
+ rgfMods[kslatJWeight] = true;
+ if (m_mJWidth0 != pslotPrev->m_mJWidth0)
+ rgfMods[kslatJWidth] = true;
+
+ if (m_mShiftX != pslotPrev->m_mShiftX)
+ rgfMods[kslatShiftX] = true;
+ if (m_mShiftY != pslotPrev->m_mShiftY)
+ rgfMods[kslatShiftY] = true;
+
+ int i;
+ for (i = 0; i < m_cnCompPerLig; i++)
+ {
+ if (CompRef(i) != pslotPrev->CompRef(i))
+ rgfMods[kslatCompRef] = true;
+ if (CompRef(i))
+ *pccomp = max(*pccomp, i + 1); // max number of ligatures in this pass
+ }
+
+ for (i = 0; i < m_cnUserDefn; i++)
+ {
+ if (UserDefn(i) != pslotPrev->UserDefn(i))
+ rgfMods[kslatUserDefn + i] = true;
+ }
+ }
+
+ *pcassoc = max(*pcassoc, AssocsSize());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Log the value of the slot attribute for the given slot, if it changed.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::LogSlotAttribute(GrTableManager * ptman,
+ std::ostream & strmOut, int ipass, int slat, int iIndex,
+ bool fPreJust, bool fPostJust)
+{
+ if (m_ipassModified != ipass && !fPreJust && !fPostJust)
+ {
+ strmOut << " ";
+ return;
+ }
+
+ // To handle reprocessing, in which case there may be a chain of slots modified
+ // in the same pass:
+ GrSlotState * pslotPrev = m_pslotPrevState;
+ while (pslotPrev && pslotPrev->PassModified() == PassModified())
+ pslotPrev = pslotPrev->m_pslotPrevState;
+
+ // General-purpose variables for em-unit attributes:
+ int mThis = 0;
+ int mPrev = 0;
+ switch (slat)
+ {
+ case kslatShiftX:
+ mThis = m_mShiftX;
+ mPrev = (pslotPrev) ? pslotPrev->m_mShiftX : 0;
+ break;
+ case kslatShiftY:
+ mThis = m_mShiftY;
+ mPrev = (pslotPrev) ? pslotPrev->m_mShiftY : 0;
+ break;
+ case kslatMeasureSol:
+ mThis = m_mMeasureSol;
+ mPrev = (pslotPrev) ? pslotPrev->m_mMeasureSol : 0;
+ break;
+ case kslatMeasureEol:
+ mThis = m_mMeasureEol;
+ mPrev = (pslotPrev) ? pslotPrev->m_mMeasureEol : 0;
+ break;
+ case kslatJStretch:
+ mThis = m_mJStretch0;
+ mPrev = (pslotPrev) ? pslotPrev->m_mJStretch0 : 0;
+ mPrev = (fPreJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change
+ break;
+ case kslatJShrink:
+ mThis = m_mJShrink0;
+ mPrev = (pslotPrev) ? pslotPrev->m_mJShrink0 : 0;
+ mPrev = (fPreJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change
+ break;
+ case kslatJStep:
+ mThis = m_mJStep0;
+ mPrev = (pslotPrev) ? pslotPrev->m_mJStep0 : 0;
+ mPrev = (fPreJust && mThis > 1) ? -1 : mPrev; // log it even if it didn't change
+ break;
+ case kslatJWeight:
+ mThis = m_nJWeight0;
+ mPrev = (pslotPrev) ? pslotPrev->m_nJWeight0 : 0;
+ mPrev = (fPreJust && mThis > 1) ? -1 : mPrev; // log it even if it didn't change
+ break;
+ case kslatJWidth:
+ mThis = m_mJWidth0;
+ mPrev = (pslotPrev) ? pslotPrev->m_mJWidth0 : 0;
+ mPrev = (fPostJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change
+ break;
+ default:
+ // don't use these variables
+ break;
+ }
+
+ switch (slat)
+ {
+ case kslatAdvX:
+ if (m_fAdvXSet && (!pslotPrev || m_mAdvanceX != pslotPrev->m_mAdvanceX))
+ {
+ ptman->LogInTable(strmOut, m_mAdvanceX);
+ return;
+ }
+ break;
+ case kslatAdvY:
+ if (m_fAdvYSet && (!pslotPrev || m_mAdvanceY != pslotPrev->m_mAdvanceY))
+ {
+ ptman->LogInTable(strmOut, m_mAdvanceY);
+ return;
+ }
+ break;
+
+ case kslatAttTo:
+ if (m_srAttachTo != (pslotPrev ? pslotPrev->m_srAttachTo : 0))
+ {
+ ptman->LogInTable(strmOut, m_srAttachTo);
+ return;
+ }
+ break;
+
+ case kslatAttAtX: // always do these in pairs
+ case kslatAttAtY:
+ if (m_mAttachAtX != (pslotPrev ? pslotPrev->m_mAttachAtX : kNotYetSet) ||
+ m_mAttachAtY != (pslotPrev ? pslotPrev->m_mAttachAtY : 0))
+ {
+ ptman->LogInTable(strmOut,
+ ((slat == kslatAttAtX) ? m_mAttachAtX : m_mAttachAtY));
+ return;
+ }
+ break;
+ case kslatAttAtGpt:
+ if (m_nAttachAtGpoint != (pslotPrev ? pslotPrev->m_nAttachAtGpoint : kNotYetSet))
+ {
+ ptman->LogInTable(strmOut,
+ ((m_nAttachAtGpoint == kGpointZero) ? 0 : m_nAttachAtGpoint));
+ return;
+ }
+ break;
+ case kslatAttAtXoff: // always do these in pairs
+ case kslatAttAtYoff:
+ if (m_mAttachAtXOffset != (pslotPrev ? pslotPrev->m_mAttachAtXOffset : 0) ||
+ m_mAttachAtYOffset != (pslotPrev ? pslotPrev->m_mAttachAtYOffset : 0))
+ {
+ ptman->LogInTable(strmOut,
+ ((slat == kslatAttAtXoff) ? m_mAttachAtXOffset : m_mAttachAtYOffset));
+ return;
+ }
+ break;
+
+ case kslatAttWithX: // always do these in pairs
+ case kslatAttWithY:
+ if (m_mAttachWithX != (pslotPrev ? pslotPrev->m_mAttachWithX : kNotYetSet) ||
+ m_mAttachWithY != (pslotPrev ? pslotPrev->m_mAttachWithY : 0))
+ {
+ ptman->LogInTable(strmOut,
+ ((slat == kslatAttWithX) ? m_mAttachWithX : m_mAttachWithY));
+ return;
+ }
+ break;
+ case kslatAttWithGpt:
+ if (m_nAttachWithGpoint != (pslotPrev ? pslotPrev->m_nAttachWithGpoint : kNotYetSet))
+ {
+ ptman->LogInTable(strmOut,
+ ((m_nAttachWithGpoint == kGpointZero) ? 0 : m_nAttachWithGpoint));
+ return;
+ }
+ break;
+ case kslatAttWithXoff: // always do these in pairs
+ case kslatAttWithYoff:
+ if (m_mAttachWithXOffset != (pslotPrev ? pslotPrev->m_mAttachWithXOffset : 0) ||
+ m_mAttachWithYOffset != (pslotPrev ? pslotPrev->m_mAttachWithYOffset : 0))
+ {
+ ptman->LogInTable(strmOut,
+ ((slat == kslatAttWithXoff) ? m_mAttachWithXOffset : m_mAttachWithYOffset));
+ return;
+ }
+ break;
+
+ case kslatAttLevel:
+ if (m_nAttachLevel != (pslotPrev ? pslotPrev->m_nAttachLevel : 0))
+ {
+ ptman->LogInTable(strmOut, m_nAttachLevel);
+ return;
+ }
+ break;
+
+ case kslatBreak:
+ if (m_lb != (pslotPrev ? pslotPrev->m_lb : kNotYetSet8))
+ {
+ ptman->LogBreakWeightInTable(strmOut, m_lb);
+ return;
+ }
+ break;
+ case kslatDir:
+ if (m_dirc != (pslotPrev ? pslotPrev->m_dirc : kNotYetSet8))
+ {
+ ptman->LogDirCodeInTable(strmOut, m_dirc);
+ return;
+ }
+ break;
+ case kslatInsert:
+ if (m_fInsertBefore != (pslotPrev ? pslotPrev->m_fInsertBefore : true))
+ {
+ if (m_fInsertBefore)
+ strmOut << "true ";
+ else
+ strmOut << "false ";
+ return;
+ }
+ break;
+
+ case kslatJWeight:
+ if (m_mJStretch0 == 0 && m_mJShrink0 == 0)
+ mPrev = mThis; // don't log; weight is irrelevant
+ // fall through
+ case kslatShiftX:
+ case kslatShiftY:
+ case kslatMeasureSol:
+ case kslatMeasureEol:
+ case kslatJStretch:
+ case kslatJShrink:
+ case kslatJStep:
+ case kslatJWidth:
+ if (mThis != mPrev)
+ {
+ ptman->LogInTable(strmOut, mThis);
+ return;
+ }
+ break;
+
+ case kslatCompRef:
+ if (CompRef(iIndex) != (pslotPrev ? pslotPrev->CompRef(iIndex) : 0))
+ {
+ GrSlotState * pslotComp = reinterpret_cast<GrSlotState *>(CompRef(iIndex));
+ ptman->LogInTable(strmOut, pslotComp->m_islotTmpIn);
+ return;
+ }
+ break;
+
+ default:
+ if (kslatUserDefn <= slat && slat <= kslatUserDefn + m_cnUserDefn)
+ {
+ int iTmp = slat - kslatUserDefn;
+ if (UserDefn(iTmp) != (pslotPrev ? pslotPrev->UserDefn(iTmp) : 0))
+ {
+ ptman->LogInTable(strmOut, UserDefn(iTmp));
+ return;
+ }
+ }
+ else
+ gAssert(false);
+ }
+
+ strmOut << " ";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Log the value of the association, if the slot changed.
+----------------------------------------------------------------------------------------------*/
+void GrSlotState::LogAssociation(GrTableManager * ptman,
+ std::ostream & strmOut, int ipass, int iassoc, bool fBoth, bool fAfter)
+{
+ if (m_ipassModified != ipass)
+ {
+ strmOut << " ";
+ return;
+ }
+
+ if (fBoth)
+ {
+ GrSlotState * pslotBefore = (m_vpslotAssoc.size()) ? m_vpslotAssoc[0] : NULL;
+ GrSlotState * pslotAfter = (m_vpslotAssoc.size()) ? m_vpslotAssoc.back() : NULL;
+ // handle possible reprocessing
+ while (pslotBefore && pslotBefore->PassModified() == m_ipassModified)
+ pslotBefore = pslotBefore->m_pslotPrevState;
+ while (pslotAfter && pslotAfter->PassModified() == m_ipassModified)
+ pslotAfter = pslotAfter->m_pslotPrevState;
+
+ int nBefore, nAfter;
+
+
+ int csp = 4;
+ if (pslotBefore)
+ {
+ nBefore = pslotBefore->m_islotTmpIn;
+ strmOut << nBefore;
+ if (nBefore > 99) csp--;
+ if (nBefore > 9) csp--;
+ }
+ else
+ {
+ strmOut << "??";
+ csp--;
+ }
+ if (pslotAfter)
+ {
+ nAfter = pslotAfter->m_islotTmpIn;
+ strmOut << "/" << nAfter;
+ if (nAfter > 99) csp--;
+ if (nAfter > 9) csp--;
+ }
+ else
+ {
+ if (pslotBefore)
+ {
+ strmOut << "/" << "??";
+ csp--;
+ }
+ else
+ csp = 5;
+ }
+
+ for (int isp = 0; isp < csp; isp++)
+ strmOut << " ";
+ }
+
+ else if (fAfter)
+ {
+ Assert(m_vpslotAssoc.size());
+ GrSlotState * pslotAfter = m_vpslotAssoc.back();
+ // handle possible reprocessing
+ while (pslotAfter && pslotAfter->PassModified() == m_ipassModified)
+ pslotAfter = pslotAfter->m_pslotPrevState;
+
+ if (pslotAfter)
+ {
+ int nAfter = pslotAfter->m_islotTmpIn;
+ ptman->LogInTable(strmOut, nAfter);
+ }
+ else
+ strmOut << "?? ";
+ }
+ else if (iassoc < signed(m_vpslotAssoc.size()))
+ {
+ GrSlotState * pslot = m_vpslotAssoc[iassoc];
+ // handle possible reprocessing
+ while (pslot && pslot->PassModified() == m_ipassModified)
+ pslot = pslot->m_pslotPrevState;
+
+ if (pslot)
+ {
+ int n = pslot->m_islotTmpIn;
+ ptman->LogInTable(strmOut, n);
+ }
+ else
+ strmOut << "?? ";
+ }
+ else
+ strmOut << " ";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write a hex value (a glyphID or Unicode codepoint) into the table.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogInTable(std::ostream & strmOut, int n)
+{
+ if (n == kNegInfinity)
+ {
+ strmOut << "-inf ";
+ return;
+ }
+ if (n == kPosInfinity)
+ {
+ strmOut << "+inf ";
+ return;
+ }
+ if (n > 999999)
+ {
+ strmOut << "****** ";
+ return;
+ }
+ if (n < -99999)
+ {
+ strmOut << "-***** ";
+ return;
+ }
+
+ strmOut << n;
+ int csp = SP_PER_SLOT - 1;
+
+ if (abs(n) > 99999) csp--;
+ if (abs(n) > 9999) csp--;
+ if (abs(n) > 999) csp--;
+ if (abs(n) > 99) csp--;
+ if (abs(n) > 9) csp--;
+
+ if (n < 0) csp--;
+
+ for (int isp = 0; isp < csp; isp++)
+ strmOut << " ";
+}
+
+void GrTableManager::LogInTable(std::ostream & strmOut, float n)
+{
+ if (n == kNegInfFloat)
+ {
+ strmOut << "-inf ";
+ return;
+ }
+ if (n == kPosInfFloat)
+ {
+ strmOut << "+inf ";
+ return;
+ }
+ if (n > 9999)
+ {
+ strmOut << "****.* ";
+ return;
+ }
+ if (n < -999)
+ {
+ strmOut << "-***.* ";
+ return;
+ }
+
+ int csp = SP_PER_SLOT - 4;
+
+ int nInt = (int)(fabsf(n));
+ int nTenths = (int)fabsf((fabsf(n) - float(nInt) + 0.05f) * 10);
+ if (nTenths >= 10)
+ {
+ nTenths = 0;
+ nInt++;
+ }
+
+ if (nInt >= 1000) csp--;
+ if (nInt >= 100) csp--;
+ if (nInt >= 10) csp--;
+
+ if (n < 0) csp--;
+
+ for (int isp = 0; isp < csp; isp++)
+ strmOut << " ";
+ if (n < 0)
+ strmOut << "-";
+ strmOut << nInt << "." << nTenths << " ";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write a hex value (a glyphID or Unicode codepoint) into the table.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogHexInTable(std::ostream & strmOut, utf16 chw, bool fPlus)
+{
+ //char rgch[20];
+ if (chw <= 0x0fff) strmOut << "0";
+ if (chw <= 0x00ff) strmOut << "0";
+ if (chw <= 0x000f) strmOut << "0";
+
+ strmOut << std::hex << chw << std::dec;
+
+ for (int i = 4; i < SP_PER_SLOT - 2; i++)
+ strmOut << " ";
+
+ if (fPlus)
+ strmOut << "+ ";
+ else
+ strmOut << " ";
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write a directionality code to the table.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogDirCodeInTable(std::ostream & strmOut, int dirc)
+{
+ switch (dirc)
+ {
+ case kdircUnknown: strmOut << "??? "; break;
+ case kdircNeutral: strmOut << "ON "; break;
+ case kdircL: strmOut << "L "; break;
+ case kdircR: strmOut << "R "; break;
+ case kdircRArab: strmOut << "AR "; break;
+ case kdircEuroNum: strmOut << "EN "; break;
+ case kdircEuroSep: strmOut << "ES "; break;
+ case kdircEuroTerm: strmOut << "ET "; break;
+ case kdircArabNum: strmOut << "AN "; break;
+ case kdircComSep: strmOut << "CS "; break;
+ case kdircWhiteSpace: strmOut << "WS "; break;
+ case kdircBndNeutral: strmOut << "BN "; break;
+ case kdircNSM: strmOut << "NSM "; break;
+ case kdircLRO: strmOut << "LRO "; break;
+ case kdircRLO: strmOut << "RLO "; break;
+ case kdircLRE: strmOut << "LRE "; break;
+ case kdircRLE: strmOut << "RLE "; break;
+ case kdircPDF: strmOut << "PDF "; break;
+ case kdircPdfL: strmOut << "PDF-L "; break;
+ case kdircPdfR: strmOut << "PDF-R "; break;
+ case kdircLlb: strmOut << "L "; break;
+ case kdircRlb: strmOut << "R "; break;
+ default: LogInTable(strmOut, dirc); break;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Write a breakweight code to the table.
+----------------------------------------------------------------------------------------------*/
+void GrTableManager::LogBreakWeightInTable(std::ostream & strmOut, int lb)
+{
+ if (lb < 0)
+ {
+ lb = lb * -1;
+ switch (lb)
+ {
+ case klbWsBreak: strmOut << "-ws "; break;
+ case klbWordBreak: strmOut << "-word "; break;
+ case klbHyphenBreak: strmOut << "-intra "; break;
+ case klbLetterBreak: strmOut << "-lettr "; break;
+ case klbClipBreak: strmOut << "-clip "; break;
+ default: LogInTable(strmOut, lb); break;
+ }
+ }
+ else
+ {
+ switch (lb)
+ {
+ case klbNoBreak: strmOut << "none "; break;
+ case klbWsBreak: strmOut << "ws "; break;
+ case klbWordBreak: strmOut << "word "; break;
+ case klbHyphenBreak: strmOut << "intra "; break;
+ case klbLetterBreak: strmOut << "letter "; break;
+ case klbClipBreak: strmOut << "clip "; break;
+ default: LogInTable(strmOut, lb); break;
+ }
+ }
+}
+
+#endif // TRACING
+
+} // namespace gr
diff --git a/Build/source/libs/graphite/engine-2.3.1/src/segment/resource.h b/Build/source/libs/graphite/engine-2.3.1/src/segment/resource.h
new file mode 100644
index 00000000000..775418f76bf
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.3.1/src/segment/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Graphite.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif