diff -Nru graphite2-1.2.4/ChangeLog graphite2-1.3.6/ChangeLog
--- graphite2-1.2.4/ChangeLog 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/ChangeLog 2016-02-29 04:18:01.000000000 +0000
@@ -1,3 +1,57 @@
+1.3.6
+ . Bug fixes
+
+1.3.5
+ . Bug fixes
+ . Security bug fix
+ . Fix ARM misalignment problem
+ . Track latest cmake
+
+1.3.4
+ . Transition from Mercurial to Git
+ . Bug fixes
+ . Fix Collision Kerning ignoring some diacritics
+ . Handle pass bits 16-31 to speed up fonts with > 16 passes
+ . Various minor fuzz bug fixes
+ . Make Coverity happy
+ . Add GR_FALLTHROUGH macro for clang c++11
+
+1.3.3
+ . Slight speed up in Collision Avoidance
+ . Remove dead bidi code
+ . Bug fixes
+ . Between pass bidi reorderings and at the end
+ . Decompressor fuzz bugs
+ . Other fuzz bugs
+
+1.3.2
+ . Remove full bidi. All segments are assumed to be single directioned.
+ . Bug fixes:
+ . Decompressor corner cases
+ . Various fuzz bugs
+
+1.3.1
+ . Deprecation warning: Full bidi support is about to be deprecated. Make contact
+ if this impacts you.
+ . Change compression block format slightly to conform to LZ4
+ . Bug fixes:
+ . Handle mono direction text with diacritics consistently. Fonts
+ now see the direction they expect consistently and bidi now
+ gives expected results.
+ . Fixed lots of fuzz bugs
+ . Coverity cleanups
+ . Build now works for clang and/or asan and/or afl etc.
+
+1.3.0
+ . Add collision avoidance
+ . Shift Collider
+ . Kern Collider
+ . Octabox outlines and subboxes
+ . Add compressed Silf and Glat table support
+ . Bug fixes:
+ . Stop loops forming in the child, sibling tree
+ . Handle bidi mirroring correctly if no bidi occurring
+
1.2.4
. Face failure now has error code reporting via debug logging
. can now call gr_start_logging(NULL, fname)
@@ -8,7 +62,7 @@
. Fonts no longer require a glyf/loca table. In such cases the bounding box is always 0.
. Clang ASAN build support added for testing.
. Handle out of memory sanely.
- . Dcoumentation improvements
+ . Documentation improvements
. Bug fixes:
. Enforce fonts having to store glyph attributes by monotonically increasing attribute number
. zeropadding was not getting called on feature tags
@@ -69,14 +123,17 @@
. Tidy up perl wrappers
. Fuzz tester improvements
. Various bug fixes for bad font handling
+
1.1.2
. Support feature ids < 4 chars when space padded for inclusion in FF 14.
. More fuzztesting and removal of causes of valgrind bad reads and sigabrts
. Remove contrib/android into its own repo (http://hg.palaso.org/grandroid)
. Update comparerenderer to latest harfbuzzng api
+
1.1.1
. Missing Log.h included
. perl wrappers updated
+
1.1.0
. Refactored debug output to use json
. Renamed VM_MACHINE_TYPE to GRAPHITE2_VM_TYPE
@@ -98,7 +155,7 @@
. Moved internal .h files into src/inc
. Parallelise fuzztest
. General build improvements, particularly on Windows
-
+
1.0.3
. Fix UTF16 surrogate support
. script and lang tags may be space padded or null padded
diff -Nru graphite2-1.2.4/CMakeLists.txt graphite2-1.3.6/CMakeLists.txt
--- graphite2-1.2.4/CMakeLists.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/CMakeLists.txt 2016-02-29 04:18:01.000000000 +0000
@@ -7,11 +7,6 @@
if (NOT CMAKE_BUILD_TYPE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE Release)
endif (NOT CMAKE_BUILD_TYPE)
-#if (CMAKE_BUILD_TYPE STREQUAL ClangASN)
-# add_definitions(-fsanitize=address -fno-omit-frame-pointer)
-# set_property(CACHE CMAKE_C_COMPILER PROPERTY VALUE clang)
-# set_property(CACHE CMAKE_CXX_COMPILER PROPERTY VALUE clang)
-#endif (CMAKE_BUILD_TYPE STREQUAL ClangASN)
enable_language(CXX C)
@@ -42,7 +37,7 @@
add_definitions(-fsanitize=address -fno-omit-frame-pointer -g)
find_program(ASAN_SYMBOLIZER llvm-symbolizer
PATHS "/usr/lib" "/usr/local/lib"
- PATH_SUFFIXES "llvm-3.3/bin" "llvm-3.4/bin" "llvm-3.5/bin")
+ PATH_SUFFIXES "llvm-3.5/bin" "llvm-3.4/bin" "llvm-3.3/bin")
endif (GRAPHITE2_ASAN)
string(TOLOWER ${GRAPHITE2_VM_TYPE} GRAPHITE2_VM_TYPE)
diff -Nru graphite2-1.2.4/contrib/C#/NGraphite/FeatureRef.cs graphite2-1.3.6/contrib/C#/NGraphite/FeatureRef.cs
--- graphite2-1.2.4/contrib/C#/NGraphite/FeatureRef.cs 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/contrib/C#/NGraphite/FeatureRef.cs 2016-02-29 04:18:01.000000000 +0000
@@ -25,6 +25,8 @@
UInt32 length;
ushort langId = (ushort)Graphite2Api.StrToTag(langid);
IntPtr labelPtr = Graphite2Api.FrefLabel(_featureRef, ref langId, utf, out length);
+ if (labelPtr == IntPtr.Zero)
+ return String.Empty;
string retLabel = ConvertGraphiteLabelToString(labelPtr, utf, length);
Graphite2Api.LabelDestroy(labelPtr);
return retLabel;
@@ -50,6 +52,8 @@
UInt32 length;
ushort langId = (ushort)Graphite2Api.StrToTag(langid);
IntPtr labelPtr = Graphite2Api.FrefValueLabel(_featureRef, settingsno, ref langId, utf, out length);
+ if (labelPtr == IntPtr.Zero)
+ return String.Empty;
string retLabel = ConvertGraphiteLabelToString(labelPtr, utf, length);
Graphite2Api.LabelDestroy(labelPtr);
return retLabel;
diff -Nru graphite2-1.2.4/contrib/C#/NGraphite/NGraphite.dll.config graphite2-1.3.6/contrib/C#/NGraphite/NGraphite.dll.config
--- graphite2-1.2.4/contrib/C#/NGraphite/NGraphite.dll.config 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/contrib/C#/NGraphite/NGraphite.dll.config 2016-02-29 04:18:01.000000000 +0000
@@ -1,3 +1,3 @@
-
+
diff -Nru graphite2-1.2.4/contrib/C#/NGraphiteTests/NGraphiteTests.csproj graphite2-1.3.6/contrib/C#/NGraphiteTests/NGraphiteTests.csproj
--- graphite2-1.2.4/contrib/C#/NGraphiteTests/NGraphiteTests.csproj 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/contrib/C#/NGraphiteTests/NGraphiteTests.csproj 2016-02-29 04:18:01.000000000 +0000
@@ -30,10 +30,10 @@
-
+
mono-nunit
-
+
mono-nunit
@@ -56,4 +56,4 @@
NGraphite
-
\ No newline at end of file
+
diff -Nru graphite2-1.2.4/contrib/perl/Build.PL graphite2-1.3.6/contrib/perl/Build.PL
--- graphite2-1.2.4/contrib/perl/Build.PL 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/contrib/perl/Build.PL 2016-02-29 04:18:01.000000000 +0000
@@ -9,7 +9,7 @@
dist_version_from => 'lib/Text/Gr2.pm',
extra_compiler_flags => $^O ne 'MSWin32' ? '-Wall -Wno-unused-variable' : '',
extra_linker_flags => $^O eq 'MSWin32' ? '../../build/src/graphite2.lib' : '-lgraphite2',
- include_dirs => ['.'],
+ include_dirs => ['.', '../include'],
requires => {
'Test::More' => 0,
},
diff -Nru graphite2-1.2.4/debian/changelog graphite2-1.3.6/debian/changelog
--- graphite2-1.2.4/debian/changelog 2016-02-11 16:10:38.000000000 +0000
+++ graphite2-1.3.6/debian/changelog 2016-03-10 19:08:28.000000000 +0000
@@ -1,3 +1,21 @@
+graphite2 (1.3.6-1ubuntu0.14.04.1) trusty-security; urgency=medium
+
+ * Updated to new upstream release 1.3.6 to fix multiple security issues.
+ - CVE-2016-1977, CVE-2016-2790, CVE-2016-2791, CVE-2016-2792,
+ CVE-2016-2793, CVE-2016-2794, CVE-2016-2795, CVE-2016-2796,
+ CVE-2016-2797, CVE-2016-2798, CVE-2016-2799, CVE-2016-2800,
+ CVE-2016-2801, CVE-2016-2802
+ * Dropped upstreamed patches:
+ - include-and-libraries.diff, no-specific-nunit-version.diff,
+ soname.diff, CVE-2016-152x-1.patch, CVE-2016-152x-2.patch,
+ CVE-2016-152x-3.patch, CVE-2016-152x-4.patch, CVE-2016-152x-5.patch
+ * Updated patches for 1.3.6:
+ - no-icons.diff
+ * debian/patches/disable_tests.diff: disable tests that require the
+ fonttools package from universe.
+
+ -- Marc Deslauriers Thu, 10 Mar 2016 14:06:56 -0500
+
graphite2 (1.2.4-1ubuntu1.1) trusty-security; urgency=medium
* SECURITY UPDATE: multiple security issues
diff -Nru graphite2-1.2.4/debian/patches/CVE-2016-152x-1.patch graphite2-1.3.6/debian/patches/CVE-2016-152x-1.patch
--- graphite2-1.2.4/debian/patches/CVE-2016-152x-1.patch 2016-02-11 16:09:12.000000000 +0000
+++ graphite2-1.3.6/debian/patches/CVE-2016-152x-1.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,65 +0,0 @@
-Description: fix out of bounds access
-Origin: backport, https://github.com/silnrsi/graphite/commit/4e232ad3697bd0121fd3cbfd8c3d9e2617fce1b8
-
-Index: graphite2-1.2.4/src/Bidi.cpp
-===================================================================
---- graphite2-1.2.4.orig/src/Bidi.cpp 2016-02-11 09:07:31.504431805 -0500
-+++ graphite2-1.2.4/src/Bidi.cpp 2016-02-11 09:07:31.496431724 -0500
-@@ -571,35 +571,38 @@
- mask |= 2;
- }
- }
-- for (p = stack.start(); p; p =p->next()) // walk the stack
-+ if (stack.size())
- {
-- if (p->close() && p->mask())
-+ for (p = stack.start(); p; p =p->next()) // walk the stack
- {
-- int dir = (level & 1) + 1;
-- if (p->mask() & dir)
-- { }
-- else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
-+ if (p->close() && p->mask())
- {
-- int ldir = p->before();
-- if ((p->before() == OPP || p->before() == CPP) && p->prev())
-+ int dir = (level & 1) + 1;
-+ if (p->mask() & dir)
-+ { }
-+ else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
- {
-- for (BracketPair *q = p->prev(); q; q = q->prev())
-+ int ldir = p->before();
-+ if ((p->before() == OPP || p->before() == CPP) && p->prev())
- {
-- ldir = q->open()->getBidiClass();
-- if (ldir < 3) break;
-- ldir = q->before();
-- if (ldir < 3) break;
-+ for (BracketPair *q = p->prev(); q; q = q->prev())
-+ {
-+ ldir = q->open()->getBidiClass();
-+ if (ldir < 3) break;
-+ ldir = q->before();
-+ if (ldir < 3) break;
-+ }
-+ if (ldir > 2) ldir = 0;
- }
-- if (ldir > 2) ldir = 0;
-+ if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
-+ dir = (~level & 1) + 1;
- }
-- if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
-- dir = (~level & 1) + 1;
-+ p->open()->setBidiClass(dir);
-+ p->close()->setBidiClass(dir);
- }
-- p->open()->setBidiClass(dir);
-- p->close()->setBidiClass(dir);
- }
-+ stack.clear();
- }
-- stack.clear();
- }
-
- int GetDeferredNeutrals(int action, int level)
diff -Nru graphite2-1.2.4/debian/patches/CVE-2016-152x-2.patch graphite2-1.3.6/debian/patches/CVE-2016-152x-2.patch
--- graphite2-1.2.4/debian/patches/CVE-2016-152x-2.patch 2016-02-11 16:09:15.000000000 +0000
+++ graphite2-1.3.6/debian/patches/CVE-2016-152x-2.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,70 +0,0 @@
-Description: handle fonts with 0 features
-Origin: backport, https://github.com/silnrsi/graphite/commit/a94bbf1a651b13ecfaf9a774a841d36964c25929
-
-diff --git a/src/FeatureMap.cpp b/src/FeatureMap.cpp
-index 7cc3c72..199ff70 100644
---- a/src/FeatureMap.cpp
-+++ b/src/FeatureMap.cpp
-@@ -165,16 +165,16 @@ bool FeatureMap::readFeats(const Face & face)
- label, uiName, flags,
- uiSet, num_settings);
- }
-- m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
-+ new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
- m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
-- if (!m_defaultFeatures || !m_pNamedFeats)
-+ if (!m_pNamedFeats)
- {
- free(defVals);
- return false;
- }
- for (int i = 0; i < m_numFeats; ++i)
- {
-- m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
-+ m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
- m_pNamedFeats[i] = m_feats+i;
- }
-
-@@ -214,7 +214,7 @@ bool SillMap::readSill(const Face & face)
- uint16 numSettings = be::read(p);
- uint16 offset = be::read(p);
- if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
-- Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
-+ Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
- if (!feats) return false;
- const byte *pLSet = sill + offset;
-
-@@ -250,7 +250,7 @@ Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
- return new Features(*m_langFeats[i].m_pFeatures);
- }
- }
-- return new Features (*m_FeatureMap.m_defaultFeatures);
-+ return new Features (m_FeatureMap.m_defaultFeatures);
- }
-
-
-diff --git a/src/inc/FeatureMap.h b/src/inc/FeatureMap.h
-index bc8a5db..a199a87 100644
---- a/src/inc/FeatureMap.h
-+++ b/src/inc/FeatureMap.h
-@@ -117,9 +117,8 @@ class NameAndFeatureRef
- class FeatureMap
- {
- public:
-- FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL),
-- m_defaultFeatures(NULL) {}
-- ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; delete m_defaultFeatures; }
-+ FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL) {}
-+ ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; }
-
- bool readFeats(const Face & face);
- const FeatureRef *findFeatureRef(uint32 name) const;
-@@ -135,7 +134,7 @@ friend class SillMap;
-
- FeatureRef *m_feats;
- NameAndFeatureRef* m_pNamedFeats; //owned
-- FeatureVal* m_defaultFeatures; //owned
-+ FeatureVal m_defaultFeatures; //owned
-
- private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
- FeatureMap(const FeatureMap&);
diff -Nru graphite2-1.2.4/debian/patches/CVE-2016-152x-3.patch graphite2-1.3.6/debian/patches/CVE-2016-152x-3.patch
--- graphite2-1.2.4/debian/patches/CVE-2016-152x-3.patch 2016-02-11 16:09:19.000000000 +0000
+++ graphite2-1.3.6/debian/patches/CVE-2016-152x-3.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-Description: fix out-of-bounds read
-Origin: backport, https://github.com/silnrsi/graphite/commit/98266d29bf0c9ebc5553630385abd868767f160b
-
-Index: graphite2-1.2.4/src/TtfUtil.cpp
-===================================================================
---- graphite2-1.2.4.orig/src/TtfUtil.cpp 2016-02-11 09:34:35.537727854 -0500
-+++ graphite2-1.2.4/src/TtfUtil.cpp 2016-02-11 09:34:35.533727812 -0500
-@@ -1149,7 +1149,7 @@
- // CheckTable verifies the index_to_loc_format is valid
- if (be::swap(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
-+ if (lLocaSize > 1 && nGlyphId + 1u < lLocaSize >> 1) // allow sentinel value to be accessed
- {
- const uint16 * pShortTable = reinterpret_cast(pLoca);
- return (be::peek(pShortTable + nGlyphId) << 1);
-@@ -1158,7 +1158,7 @@
-
- if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
- { // loca entries are four bytes
-- if (nGlyphId < (lLocaSize >> 2) - 1)
-+ if (lLocaSize > 3 && nGlyphId + 1u < lLocaSize >> 2)
- {
- const uint32 * pLongTable = reinterpret_cast(pLoca);
- return be::peek(pLongTable + nGlyphId);
diff -Nru graphite2-1.2.4/debian/patches/CVE-2016-152x-4.patch graphite2-1.3.6/debian/patches/CVE-2016-152x-4.patch
--- graphite2-1.2.4/debian/patches/CVE-2016-152x-4.patch 2016-02-11 16:09:23.000000000 +0000
+++ graphite2-1.3.6/debian/patches/CVE-2016-152x-4.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-Description: check for cntxtItem misalignment
-Origin: backport, https://github.com/silnrsi/graphite/commit/6c50e793e5879a0aaf830fcdd16841dd28906f8b
-Origin: backport, https://github.com/silnrsi/graphite/commit/f9278ab70cdff869e81082016fd848e98ba184de
-
-Index: graphite2-1.2.4/src/Code.cpp
-===================================================================
---- graphite2-1.2.4.orig/src/Code.cpp 2016-02-11 10:25:52.373490083 -0500
-+++ graphite2-1.2.4/src/Code.cpp 2016-02-11 10:26:43.790054613 -0500
-@@ -94,7 +94,7 @@
-
- };
-
-- decoder(const limits & lims, Code &code) throw();
-+ decoder(limits & lims, Code &code) throw();
-
- bool load(const byte * bc_begin, const byte * bc_end);
- void apply_analysis(instr * const code, instr * code_end);
-@@ -114,14 +114,14 @@
- uint16 _rule_length;
- instr * _instr;
- byte * _data;
-- const limits & _max;
-+ limits & _max;
- analysis _analysis;
- };
-
-
- struct Machine::Code::decoder::limits
- {
-- const byte * const bytecode;
-+ const byte * bytecode;
- const uint8 pre_context;
- const uint16 rule_length,
- classes,
-@@ -130,7 +130,7 @@
- const byte attrid[gr_slatMax];
- };
-
--inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
-+inline Machine::Code::decoder::decoder(limits & lims, Code &code) throw()
- : _code(code),
- _pre_context(code._constraint ? 0 : lims.pre_context),
- _rule_length(code._constraint ? 1 : lims.rule_length),
-@@ -168,7 +168,7 @@
- return;
- }
-
-- const decoder::limits lims = {
-+ decoder::limits lims = {
- bytecode_end,
- pre_context,
- rule_length,
-@@ -237,6 +237,7 @@
-
- bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
- {
-+ _max.bytecode = bc_end;
- while (bc < bc_end)
- {
- const opcode opc = fetch_opcode(bc++);
-@@ -506,16 +507,20 @@
- byte & instr_skip = _data[-1];
- byte & data_skip = *_data++;
- ++_code._data_size;
-+ const byte *curr_end = _max.bytecode;
-
- if (load(bc, bc + instr_skip))
- {
- bc += instr_skip;
- data_skip = instr_skip - (_code._instr_count - ctxt_start);
- instr_skip = _code._instr_count - ctxt_start;
-+ _max.bytecode = curr_end;
-
- _rule_length = 1;
- _pre_context = 0;
- }
-+ else
-+ return false;
- }
-
- return bool(_code);
-@@ -554,7 +559,7 @@
- }
- const opcode_t & op = Machine::getOpcodeTable()[opc];
- const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
-- if (bc + param_sz > _max.bytecode)
-+ if (bc - 1 + param_sz >= _max.bytecode)
- {
- failure(arguments_exhausted);
- return false;
diff -Nru graphite2-1.2.4/debian/patches/CVE-2016-152x-5.patch graphite2-1.3.6/debian/patches/CVE-2016-152x-5.patch
--- graphite2-1.2.4/debian/patches/CVE-2016-152x-5.patch 2016-02-11 16:09:27.000000000 +0000
+++ graphite2-1.3.6/debian/patches/CVE-2016-152x-5.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-Description: disallow nested cntxt_item
-Origin: backport, https://github.com/silnrsi/graphite/commit/2fc07f868146f924621307925b92a5161b7bd571
-Origin: backport, https://github.com/silnrsi/graphite/commit/6106dcbd5bc4df2e6ef6a7c632c69ca71ba2b518
-
-Index: graphite2-1.2.4/src/Code.cpp
-===================================================================
---- graphite2-1.2.4.orig/src/Code.cpp 2016-02-11 10:40:10.922786019 -0500
-+++ graphite2-1.2.4/src/Code.cpp 2016-02-11 10:40:38.159076948 -0500
-@@ -116,6 +116,7 @@
- byte * _data;
- limits & _max;
- analysis _analysis;
-+ bool _in_ctxt_item;
- };
-
-
-@@ -134,7 +135,7 @@
- : _code(code),
- _pre_context(code._constraint ? 0 : lims.pre_context),
- _rule_length(code._constraint ? 1 : lims.rule_length),
-- _instr(code._code), _data(code._data), _max(lims)
-+ _instr(code._code), _data(code._data), _max(lims), _in_ctxt_item(false)
- { }
-
-
-@@ -319,8 +320,8 @@
- break;
- case CNTXT_ITEM :
- valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
-- if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
-- if (_pre_context != 0) failure(nested_context_item);
-+ if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
-+ if (_in_ctxt_item) failure(nested_context_item);
- break;
- case ATTR_SET :
- case ATTR_ADD :
-@@ -500,6 +501,7 @@
- if (opc == CNTXT_ITEM)
- {
- assert(_pre_context == 0);
-+ _in_ctxt_item = true;
- _pre_context = _max.pre_context + int8(_data[-2]);
- _rule_length = _max.rule_length;
-
-@@ -518,6 +520,7 @@
-
- _rule_length = 1;
- _pre_context = 0;
-+ _in_ctxt_item = false;
- }
- else
- return false;
diff -Nru graphite2-1.2.4/debian/patches/disable_tests.diff graphite2-1.3.6/debian/patches/disable_tests.diff
--- graphite2-1.2.4/debian/patches/disable_tests.diff 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/debian/patches/disable_tests.diff 2016-03-10 18:55:33.000000000 +0000
@@ -0,0 +1,18 @@
+Description: disable tests that require the fonttools package from universe
+Author: Marc Deslauriers
+
+Index: graphite2-1.3.6/tests/CMakeLists.txt
+===================================================================
+--- graphite2-1.3.6.orig/tests/CMakeLists.txt 2016-02-28 23:18:01.000000000 -0500
++++ graphite2-1.3.6/tests/CMakeLists.txt 2016-03-10 13:54:16.401350821 -0500
+@@ -116,10 +116,3 @@
+ feattest(charis_feat charis_r_gr.ttf)
+ feattest(scher_feat Scheherazadegr.ttf)
+
+-cmptest(padaukcmp1 Padauk.ttf my_HeadwordSyllables.txt)
+-cmptest(chariscmp1 charis_r_gr.ttf udhr_eng.txt)
+-cmptest(chariscmp2 charis_r_gr.ttf udhr_yor.txt)
+-cmptest(annacmp1 Annapurnarc2.ttf udhr_nep.txt)
+-cmptest(schercmp1 Scheherazadegr.ttf udhr_arb.txt -r)
+-cmptest(awamicmp1 Awami_test.ttf awami_tests.txt -r -e 1)
+-cmptest(awamicmp2 Awami_compressed_test.ttf awami_tests.txt -r -e 1)
diff -Nru graphite2-1.2.4/debian/patches/include-and-libraries.diff graphite2-1.3.6/debian/patches/include-and-libraries.diff
--- graphite2-1.2.4/debian/patches/include-and-libraries.diff 2013-12-06 13:27:50.000000000 +0000
+++ graphite2-1.3.6/debian/patches/include-and-libraries.diff 1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
---- graphite2-1.1.0.orig/contrib/perl/Build.PL
-+++ graphite2-1.1.0/contrib/perl/Build.PL
-@@ -9,7 +9,7 @@
- dist_version_from => 'lib/Text/Gr2.pm',
- extra_compiler_flags => $^O ne 'MSWin32' ? '-Wall -Wno-unused-variable' : '',
- extra_linker_flags => $^O eq 'MSWin32' ? '../../build/src/graphite2.lib' : '-lgraphite2',
-- include_dirs => ['.'],
-+ include_dirs => ['.', '../include'],
- requires => {
- 'Test::More' => 0,
- },
diff -Nru graphite2-1.2.4/debian/patches/no-icons.diff graphite2-1.3.6/debian/patches/no-icons.diff
--- graphite2-1.2.4/debian/patches/no-icons.diff 2016-02-11 16:08:57.000000000 +0000
+++ graphite2-1.3.6/debian/patches/no-icons.diff 2016-02-29 19:54:02.000000000 +0000
@@ -1,17 +1,15 @@
---- graphite2-1.2.4.orig/doc/CMakeLists.txt
-+++ graphite2-1.2.4/doc/CMakeLists.txt
-@@ -12,12 +12,12 @@ if(A2X)
+--- graphite2-1.3.2.orig/doc/CMakeLists.txt
++++ graphite2-1.3.2/doc/CMakeLists.txt
+@@ -12,10 +12,10 @@ if(A2X)
if(DBLATEX)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/manual.pdf
- DEPENDS ${PROJECT_SOURCE_DIR}/*.txt
+ DEPENDS ${PROJECT_SOURCE_DIR}/[a-z]*.txt
- COMMAND ${A2X} --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
+ COMMAND ${A2X} -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
- set(DOC_DEPENDS ${PROJECT_BINARY_DIR}/manual.pdf)
+ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/GTF.pdf
+ DEPENDS ${PROJECT_SOURCE_DIR}/GTF.txt
+- COMMAND ${A2X} --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/GTF.txt)
++ COMMAND ${A2X} -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/GTF.txt)
+ set(DOC_DEPENDS ${PROJECT_BINARY_DIR}/manual.pdf ${PROJECT_BINARY_DIR}/GTF.pdf)
endif(DBLATEX)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/manual.html
- DEPENDS ${PROJECT_SOURCE_DIR}/*.txt
-- COMMAND ${A2X} -f xhtml --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
-+ COMMAND ${A2X} -f xhtml -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
- set(DOC_DEPENDS ${DOC_DEPENDS} ${PROJECT_BINARY_DIR}/manual.html)
- endif(A2X)
-
diff -Nru graphite2-1.2.4/debian/patches/no-specific-nunit-version.diff graphite2-1.3.6/debian/patches/no-specific-nunit-version.diff
--- graphite2-1.2.4/debian/patches/no-specific-nunit-version.diff 2013-12-06 13:27:50.000000000 +0000
+++ graphite2-1.3.6/debian/patches/no-specific-nunit-version.diff 1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
---- graphite2-1.2.0.orig/contrib/C#/NGraphiteTests/NGraphiteTests.csproj
-+++ graphite2-1.2.0/contrib/C#/NGraphiteTests/NGraphiteTests.csproj
-@@ -30,10 +30,10 @@
-
-
-
--
-+
- mono-nunit
-
--
-+
- mono-nunit
-
-
diff -Nru graphite2-1.2.4/debian/patches/series graphite2-1.3.6/debian/patches/series
--- graphite2-1.2.4/debian/patches/series 2016-02-11 16:09:27.000000000 +0000
+++ graphite2-1.3.6/debian/patches/series 2016-03-10 19:07:50.000000000 +0000
@@ -1,9 +1,2 @@
-include-and-libraries.diff
-no-specific-nunit-version.diff
-soname.diff
no-icons.diff
-CVE-2016-152x-1.patch
-CVE-2016-152x-2.patch
-CVE-2016-152x-3.patch
-CVE-2016-152x-4.patch
-CVE-2016-152x-5.patch
+disable_tests.diff
\ No newline at end of file
diff -Nru graphite2-1.2.4/debian/patches/soname.diff graphite2-1.3.6/debian/patches/soname.diff
--- graphite2-1.2.4/debian/patches/soname.diff 2013-12-06 13:27:50.000000000 +0000
+++ graphite2-1.3.6/debian/patches/soname.diff 1970-01-01 00:00:00.000000000 +0000
@@ -1,7 +0,0 @@
---- graphite2-1.2.0.orig/contrib/C#/NGraphite/NGraphite.dll.config
-+++ graphite2-1.2.0/contrib/C#/NGraphite/NGraphite.dll.config
-@@ -1,3 +1,3 @@
-
--
-+
-
diff -Nru graphite2-1.2.4/debian-src/changelog graphite2-1.3.6/debian-src/changelog
--- graphite2-1.2.4/debian-src/changelog 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/debian-src/changelog 2016-02-29 04:18:01.000000000 +0000
@@ -1,3 +1,45 @@
+graphite2 (1.3.6-1~palaso1) trusty; urgency=medium
+
+ * New bug fix release
+
+ -- Martin Hosken Mon, 29 Feb 2016 11:17:04 +0700
+
+graphite2 (1.3.5-1~palaso1) trusty; urgency=medium
+
+ * New bug fix release
+
+ -- Martin Hosken Fri, 15 Jan 2016 10:59:57 +0700
+
+graphite2 (1.3.4-1~palaso1) trusty; urgency=medium
+
+ * New bug fix release
+
+ -- Martin Hosken Thu, 22 Oct 2015 14:36:40 +0700
+
+graphite2 (1.3.3-1~palaso1) trusty; urgency=medium
+
+ * New bug fix release
+
+ -- Martin Hosken Mon, 21 Sep 2015 11:37:45 +0700
+
+graphite2 (1.3.2-1~palaso1) trusty; urgency=medium
+
+ * New bug fix release
+
+ -- Martin Hosken Wed, 09 Sep 2015 14:46:49 +0700
+
+graphite2 (1.3.1-1~palaso1) trusty; urgency=medium
+
+ * New main source release. Mainly bug fixes.
+
+ -- Martin Hosken Mon, 31 Aug 2015 10:06:14 +0700
+
+graphite2 (1.3.0-1~palaso1) trusty; urgency=medium
+
+ * New main source release
+
+ -- Martin Hosken Thu, 30 Jul 2015 12:53:11 +0700
+
graphite2 (1.2.3-1~palaso1) precise; urgency=low
* Bug fixes release
diff -Nru graphite2-1.2.4/debian-src/control graphite2-1.3.6/debian-src/control
--- graphite2-1.2.4/debian-src/control 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/debian-src/control 2016-02-29 04:18:01.000000000 +0000
@@ -3,7 +3,7 @@
Section: libs
Maintainer: Debian LibreOffice Team
Uploaders: Rene Engelhard , Daniel Glassey
-Build-Depends: debhelper (>= 7.0), cmake, libfreetype6-dev, libgraphite-dev, libicu-dev, python (>= 2.6)
+Build-Depends: debhelper (>= 7.0), cmake, python (>= 2.6), fonttools
# perl: libmodule-build-perl
Build-Depends-Indep: asciidoc, dblatex, doxygen, docbook-xsl, latex-xcolor, libxml2-utils
Standards-Version: 3.9.1
diff -Nru graphite2-1.2.4/debian-src/libgraphite2-dev.install graphite2-1.3.6/debian-src/libgraphite2-dev.install
--- graphite2-1.2.4/debian-src/libgraphite2-dev.install 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/debian-src/libgraphite2-dev.install 2016-02-29 04:18:01.000000000 +0000
@@ -1,3 +1,4 @@
debian/tmp/usr/include
debian/tmp/usr/lib/lib*.so
debian/tmp/usr/lib/pkgconfig
+debian/tmp/usr/bin/gr2fonttest
diff -Nru graphite2-1.2.4/debian-src/rules graphite2-1.3.6/debian-src/rules
--- graphite2-1.2.4/debian-src/rules 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/debian-src/rules 2016-02-29 04:18:01.000000000 +0000
@@ -17,7 +17,7 @@
override_dh_auto_install:
dh_auto_install
- rm -rf debian/tmp/usr/bin
+# rm -rf debian/tmp/usr/bin
# cd perl && \
# ./Build install destdir=$(CURDIR)/debian/libtext-graphite2-perl
# # hack
diff -Nru graphite2-1.2.4/doc/building.txt graphite2-1.3.6/doc/building.txt
--- graphite2-1.2.4/doc/building.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/doc/building.txt 2016-02-29 04:18:01.000000000 +0000
@@ -22,16 +22,23 @@
packages. There are various option settings see
<>>.
-It is possible to use clang and also the addresss sanitizer (in clang 3.3 or later)
-to build and test Graphite. Use this build command:
+On amd64 architecture if you wish build and test 32 bit binaries this is
+possible using the following cmake ivocation:
----
-C=clang CXX=clang cmake .. -DGRAPHITE2_ASAN:BOOL=True
+CFLAGS=-m32 CXXFLAGS=-m32 cmake ..
make
+make test
----
+You will need g++-multilib support see <>
-Bear in mind that ASAN will not work with ulimit constraints so running the fuzztest
-may result in problems.
+It is possible to use clang to build and test Graphite. Use this build command:
+
+----
+CC=clang CXX=clang++ cmake ..
+make
+----
+You will need libc++ libc++-abi see clang-asan section of <>.
=== Windows ===
@@ -47,7 +54,7 @@
You need to specify the CMAKE_BUILD_TYPE as some Windows generators require it.
+
----
-cmake -DCMAKE_BUILD_TYPE:STRING=Release
+cmake -DCMAKE_BUILD_TYPE:STRING=Release ..
----
+
CMake will automatically detect your build system and generate a project for
@@ -60,13 +67,13 @@
example for Visual Studio 8:
+
----
-cmake -G "Visual Studio 8 2005" -DCMAKE_BUILD_TYPE:STRING=Release
+cmake -G "Visual Studio 8 2005" -DCMAKE_BUILD_TYPE:STRING=Release ..
----
+
or for MinGW
+
----
-cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE:STRING=Release
+cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE:STRING=Release ..
----
+
TIP: You can get a list of generators CMakes supports with `cmake --help`.
@@ -110,7 +117,7 @@
They are described here, along with their type and possible and default values.
Boolean values may take the value OFF or ON. Options may be set using
the -Doption=value command line option.
-For example: -DGRAPHITE2_COMPARE_RENDERER=ON
+For example: -DGRAPHITE2_COMPARE_RENDERER:BOOL=ON
CMAKE_BUILD_TYPE:STRING::
This specifies which type of build to do. It is a string and may take the
@@ -142,6 +149,18 @@
The value of call tells the system to use the slower but more cross
compiler portable call based machine.
+GRAPHITE2_ASAN:BOOL::
+ This turns on copmile time support for Google's
+ https://code.google.com/p/address-sanitizer/[ASAN] Address Sanitizer.
+ This works with both gcc and clang, however under clang any tests driven by
+ Python will not be run. These tests require the ASAN runtime as a shared
+ library and currently clang only provides static version.
+
+Bear in mind that ASAN will not work with ulimit constraints so running the
+fuzztest may result in problems.
+
+
+[[X2]]
=== Limitations ===
There are some hard build dependencies:
@@ -153,15 +172,17 @@
Other configuration related dependencies:
-silgraphite::
- Required to build the comparerender test and benchmarking tool and in turn
- to allow extra tests to be run which check graphite2's rendering against
- silgraphite.
-
-freetype::
- Also required by comparerender
-
-harfbuzz, harfbuzng, icule::
- If found comparerenderer will be built with support for these but they are
- not required to build or run any tests
+fonttools::
+ This python library supports truetype font reading.
+
+g++-multilib::
+ If building 32bit binaries under a 64bit Linux host this is
+ required for successful linking. These are the `g++-multilib` and
+ `libc6-dev-i386` packages on Debian and derivatives and `glibc-devel.i686`,
+ `glibc-devel` and `libstdc++-devel.i686` on Redhat OSs
+
+clang::
+ To build with clang under linux you will need to ensure you have installed
+ libc++ and libc++abi packages. The easiest way to do on Debian & derivatives
+ is to install the libc++-dev and libc++abi-dev packages.
diff -Nru graphite2-1.2.4/doc/CMakeLists.txt graphite2-1.3.6/doc/CMakeLists.txt
--- graphite2-1.2.4/doc/CMakeLists.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/doc/CMakeLists.txt 2016-02-29 04:18:01.000000000 +0000
@@ -11,14 +11,20 @@
if(A2X)
if(DBLATEX)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/manual.pdf
- DEPENDS ${PROJECT_SOURCE_DIR}/*.txt
+ DEPENDS ${PROJECT_SOURCE_DIR}/[a-z]*.txt
COMMAND ${A2X} --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
- set(DOC_DEPENDS ${PROJECT_BINARY_DIR}/manual.pdf)
+ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/GTF.pdf
+ DEPENDS ${PROJECT_SOURCE_DIR}/GTF.txt
+ COMMAND ${A2X} --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/GTF.txt)
+ set(DOC_DEPENDS ${PROJECT_BINARY_DIR}/manual.pdf ${PROJECT_BINARY_DIR}/GTF.pdf)
endif(DBLATEX)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/manual.html
- DEPENDS ${PROJECT_SOURCE_DIR}/*.txt
- COMMAND ${A2X} -f xhtml --icons -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
- set(DOC_DEPENDS ${DOC_DEPENDS} ${PROJECT_BINARY_DIR}/manual.html)
+ DEPENDS ${PROJECT_SOURCE_DIR}/[a-z]*.txt ${PROJECT_SOURCE_DIR}/graphite.css
+ COMMAND ${A2X} -f xhtml --stylesheet=graphite.css -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/manual.txt)
+ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/GTF.html
+ DEPENDS ${PROJECT_SOURCE_DIR}/GTF.txt ${PROJECT_SOURCE_DIR}/graphite.css
+ COMMAND ${A2X} -f xhtml --stylesheet=graphite.css -D ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/GTF.txt)
+ set(DOC_DEPENDS ${DOC_DEPENDS} ${PROJECT_BINARY_DIR}/manual.html ${PROJECT_BINARY_DIR}/GTF.html)
endif(A2X)
if(DOXYGEN AND LATEX)
diff -Nru graphite2-1.2.4/doc/font.txt graphite2-1.3.6/doc/font.txt
--- graphite2-1.2.4/doc/font.txt 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/font.txt 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,78 @@
+== Font Topics ==
+
+=== Guard Space ===
+
+Graphite introduces guard space around diacritics. Sometimes a diacritic is
+wider than its base and the diacritic is in danger of crashing into clusters on
+either side of it. To stop that happening, graphite allows the font designer to
+signal that they want guard space to be ensured around a diacritic. For example,
+if a diacritic glyph is designed with a positive left side bearing and a
+positive right side bearing, the graphite engine will ensure that the cluster
+honours those side bearings for the diacritic. Of course, if the base character
+is wider than the diacritic, then no guard space is needed.
+
+The basic principle for cluster adjustment is that if a diacritic has a non-zero
+advance and after positioning, the advance of the diacritic is greater than the
+advance of the base then the advance of the base is increased to be the same as
+the positioned advance of the diacritic. Likewise if the origin of the diacritic
+is to the left of the origin of the base character, then the cluster is adjusted
+so that the origin of the diacritic is now where the origin of the base
+character was and the base character is moved to the right. Notice that this
+only happens if the origin of the diacritic is to the left of where it is
+attached or the advance is non-zero.
+
+In the following image, we use a dotless i with a combining tilde over it, which
+is wider than the dotless i. The four scenarios show how positioning the tilde
+and setting its advance controls the origin and advance of the attached cluster:
+
+image::guardspace.png[]
+
+Each line shows the two glyphs as they are designed with the origin and advance
+(if any). The third element on the line is the combined cluster. Again the
+origin and advance for the cluster is shown with solid lines and any subglyph
+origins and advances that don't coincide with a solid line, are shown dotted.
+Notice that we don't show the implied attachment point used to attach the tilde
+to the dotless i.
+
+The first line shows the diacritic as if it were a full base character, with
+positive left and right side bearings. When the glyphs attach the origin and the
+advance of the dotless i (shown as dotted lines) are pushed out to the origin
+and advance of the diacritic. Notice that graphite uses the wider advance and
+origin regardless of which component of the cluster they come from.
+
+The second line shows the other extreme. Here no guard space is inserted. The
+diacritic is to the left of the origin and the advance is zero. The cluster
+origin and advance are taken from the base glyph. The dotted line shows the
+origin and advance of the diacritic.
+
+These two lines are the most common cases that people want to use for rendering
+diacritics and whether space is automatically inserted to avoid collisions. The
+next two are rarely used but help to explain how the mechanism works.
+
+The third line has guard space on the left only. For this the diacritic is drawn
+to the right of the origin but the advance width is set to 0. The effect is that
+guard space is inserted on the left, because there is a positive left side
+bearing (or more precisely the origin of the diacritic is to the left of the
+origin of the base when the two glyphs combine). Thus the dotless i origin
+(shown as a dotted line) is pushed out. Actually the whole cluster is pushed to
+the right so that the origin of the diacritic is aligned with where the origin
+of the base glyph was.
+
+The fourth line gives guard space only after the diacritic. In this case, the
+diacritic is drawn to the left of the origin, and so no left guard space can
+occur, since the origin of the diacritic is to the right of the dotless i. The
+diacritic has also been drawn so that it finishes at the origin. This ensures
+that the guard space to the right is the same as the advance. It need not be.
+The cluster has the same origin as the base glyph. The base glyph advance is
+shown as a dotted line, which while not necessarily coinciding with the origin
+of the diacritic, will be close. Finally the advance for the cluster is the
+advance from the diacritic.
+
+Since it is possible to change the advance width of a glyph (or at least for a
+particular instance of a glyph or slot), it is possible to dynamically control
+some of the guard space mechanism within GDL. It is possible to use a rule to
+change from both to or from left only. Likewise it is possible to use a rule to
+change from none to or from right only. But, unfortunately, it is not possible
+to shift glyphs within their drawn space and so switch between both and none,
+purely from GDL.
+
diff -Nru graphite2-1.2.4/doc/graphite.css graphite2-1.3.6/doc/graphite.css
--- graphite2-1.2.4/doc/graphite.css 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/graphite.css 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,334 @@
+/*
+ CSS stylesheet for XHTML produced by DocBook XSL stylesheets.
+*/
+
+body {
+ font-family: Georgia,serif;
+}
+
+code, pre {
+ font-family: "Courier New", Courier, monospace;
+}
+
+span.strong {
+ font-weight: bold;
+}
+
+body blockquote {
+ margin-top: .75em;
+ line-height: 1.5;
+ margin-bottom: .75em;
+}
+
+html body {
+ margin: 1em 5% 1em 5%;
+ line-height: 1.2;
+}
+
+body div {
+ margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6
+{
+ color: #527bbd;
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+div.toc p:first-child,
+div.list-of-figures p:first-child,
+div.list-of-tables p:first-child,
+div.list-of-examples p:first-child,
+div.example p.title,
+div.sidebar p.title
+{
+ font-weight: bold;
+ color: #527bbd;
+ font-family: Arial,Helvetica,sans-serif;
+ margin-bottom: 0.2em;
+}
+
+body h1 {
+ margin: .0em 0 0 -4%;
+ line-height: 1.3;
+ border-bottom: 2px solid silver;
+}
+
+body h2 {
+ margin: 0.5em 0 0 -4%;
+ line-height: 1.3;
+ border-bottom: 2px solid silver;
+}
+
+body h3 {
+ margin: .8em 0 0 -3%;
+ line-height: 1.3;
+}
+
+body h4 {
+ margin: .8em 0 0 -3%;
+ line-height: 1.3;
+}
+
+body h5 {
+ margin: .8em 0 0 -2%;
+ line-height: 1.3;
+}
+
+body h6 {
+ margin: .8em 0 0 -1%;
+ line-height: 1.3;
+}
+
+body hr {
+ border: none; /* Broken on IE6 */
+}
+div.footnotes hr {
+ border: 1px solid silver;
+}
+
+div.navheader th, div.navheader td, div.navfooter td {
+ font-family: Arial,Helvetica,sans-serif;
+ font-size: 0.9em;
+ font-weight: bold;
+ color: #527bbd;
+}
+div.navheader img, div.navfooter img {
+ border-style: none;
+}
+div.navheader a, div.navfooter a {
+ font-weight: normal;
+}
+div.navfooter hr {
+ border: 1px solid silver;
+}
+
+body td {
+ /* line-height: 1.2 */
+}
+
+td p {
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+}
+
+body th {
+ line-height: 1.2;
+}
+
+ol {
+ line-height: 1.2;
+}
+
+ul, body dir, body menu {
+ line-height: 1.2;
+}
+
+html {
+ margin: 0;
+ padding: 0;
+}
+
+body h1, body h2, body h3, body h4, body h5, body h6 {
+ margin-left: 0
+}
+
+body pre {
+ margin: 0.5em 10% 0.5em 1em;
+ line-height: 1.0;
+ color: navy;
+}
+
+tt.literal, code.literal {
+ color: navy;
+}
+
+.programlisting, .screen {
+ border: 1px solid silver;
+ background: #f4f4f4;
+ margin: 0.5em 10% 0.5em 0;
+ padding: 0.5em 1em;
+}
+
+div.sidebar {
+ background: #ffffee;
+ margin: 1.0em 10% 0.5em 0;
+ padding: 0.5em 1em;
+ border: 1px solid silver;
+}
+div.sidebar * { padding: 0; }
+div.sidebar div { margin: 0; }
+div.sidebar p.title {
+ margin-top: 0.5em;
+ margin-bottom: 0.2em;
+}
+
+div.bibliomixed {
+ margin: 0.5em 5% 0.5em 1em;
+}
+
+div.glossary dt {
+ font-weight: bold;
+}
+div.glossary dd p {
+ margin-top: 0.2em;
+}
+
+dl {
+ margin: .8em 0;
+ line-height: 1.2;
+}
+
+dt {
+ margin-top: 0.5em;
+}
+
+dt span.term {
+ font-style: normal;
+ color: navy;
+}
+
+div.variablelist dd p {
+ margin-top: 0;
+}
+
+div.itemizedlist li, div.orderedlist li {
+ margin-left: -0.8em;
+ margin-top: 0.5em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+
+div.sidebar ul, div.sidebar ol {
+ margin-left: 2.8em;
+}
+
+div.itemizedlist p.title,
+div.orderedlist p.title,
+div.variablelist p.title
+{
+ margin-bottom: -0.8em;
+}
+
+div.revhistory table {
+ border-collapse: collapse;
+ border: none;
+}
+div.revhistory th {
+ border: none;
+ color: #527bbd;
+ font-family: Arial,Helvetica,sans-serif;
+}
+div.revhistory td {
+ border: 1px solid silver;
+}
+
+/* Keep TOC and index lines close together. */
+div.toc dl, div.toc dt,
+div.list-of-figures dl, div.list-of-figures dt,
+div.list-of-tables dl, div.list-of-tables dt,
+div.indexdiv dl, div.indexdiv dt
+{
+ line-height: normal;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+/*
+ Table styling does not work because of overriding attributes in
+ generated HTML.
+*/
+div.table table,
+div.informaltable table
+{
+ margin-left: 0;
+ margin-right: 5%;
+ margin-bottom: 0.8em;
+}
+div.informaltable table
+{
+ margin-top: 0.4em
+}
+div.table thead,
+div.table tfoot,
+div.table tbody,
+div.informaltable thead,
+div.informaltable tfoot,
+div.informaltable tbody
+{
+ /* No effect in IE6. */
+ border-top: 3px solid #527bbd;
+ border-bottom: 3px solid #527bbd;
+}
+div.table thead, div.table tfoot,
+div.informaltable thead, div.informaltable tfoot
+{
+ font-weight: bold;
+}
+
+div.mediaobject img {
+ margin-bottom: 0.8em;
+}
+div.figure p.title,
+div.table p.title
+{
+ margin-top: 1em;
+ margin-bottom: 0.4em;
+}
+
+div.calloutlist p
+{
+ margin-top: 0em;
+ margin-bottom: 0.4em;
+}
+
+a img {
+ border-style: none;
+}
+
+@media print {
+ div.navheader, div.navfooter { display: none; }
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
diff -Nru graphite2-1.2.4/doc/GTF-docinfo.xml graphite2-1.3.6/doc/GTF-docinfo.xml
--- graphite2-1.2.4/doc/GTF-docinfo.xml 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/GTF-docinfo.xml 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,139 @@
+
+
+ Martin
+ Hosken
+
+
+
+ Sharon
+ Correll
+
+
+
+
+
+ 4.0
+ 25 Feb 2011
+
+ Added version 2.0 of Glat table
+
+
+
+
+ 3.0
+ 31 Jan 2006
+
+ Added Sill table
+
+
+
+
+ 2.0
+ 10 Feb 2004
+
+ Added description of Feat table
+
+
+
+
+ 1.5
+ Jan 2004
+
+ Added justification levels
+
+
+
+
+ 1.4
+ 20 Aug 2003
+
+ Added SILe table; changed title to Graphite Table Format
+
+
+
+
+ 1.3
+
+
+ Added pass constraints
+
+
+
+
+ 1.2
+ 22 Jul 2003
+
+ Added fields for critical features.
+
+
+
+
+ 1.1
+ 18 Mar 2003
+
+ Changed Unicode field of PseudoMap class to ULONG
+
+
+
+
+ 0.08
+ 18 Mar 2003
+
+ Fixed problems with version numbers
+
+
+
+
+ 0.07
+ 4 Feb 2002
+
+ Reworked explanation of FSM behaviour
+
+
+
+
+ 0.06
+ 22 Nov 2000
+
+ Added constants and arrays for finite state machine rework (SIL_Pass table: min/maxRulePreContext, startStates, ruleSortKeys);
+ Added extraAscent and extraDescent (SIL_Sub table)
+
+
+
+
+ 0.05
+ 11 Sept 2000
+
+ Changed WinRend to Graphite
+
+
+
+
+ 0.04
+ 18 Jan 2000
+
+ Modifications based on actual implementation;
+ Added a LinearClass structure
+
+
+
+
+ 0.03
+ 25 June 99
+
+ Fill in details of state table;
+ Sort out Action class;
+ Add special glyph attribute indices;
+ Add Sild table;
+
+
+
+
+ 0.02
+ 22 March 99
+
+ Added debug information;
+ Changed version information from USHORT to FIXED to conform with TrueType convensions
+
+
+
diff -Nru graphite2-1.2.4/doc/GTF.txt graphite2-1.3.6/doc/GTF.txt
--- graphite2-1.2.4/doc/GTF.txt 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/GTF.txt 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,920 @@
+= Graphite Table Format =
+
+:docinfo:
+:numbered:
+
+== Introduction ==
+
+The Graphite font table format is structured in order that a Graphite
+binary description may be incorporated into a TrueType font. Thus the
+binary format uses the TrueType table structure, identically to how it
+is used in a TrueType font. The only difference between using an
+external file containing Graphite binary information in tables, and
+inserting the binary information into tables in the font is that tables
+are considered local to their file and are considered to override those
+found in the font file. This allows there to be multiple, independent
+descriptions held in separate files. Those independent descriptions
+would have to be merged, in a way described in this document, if they
+were to be held together in the same font file or binary file.
+
+The description consists of a set of table descriptions. The format of a
+file follows that of a TrueType font containing only those tables
+pertinent to the description (i.e. for a separate binary description,
+those tables listed here).
+
+As is standard for all TrueType tables, the data is in big-endian format
+(most significant byte first).
+
+== Version ==
+
+This file describes version 4.0 of the Graphite font table
+specification. Modifications from previous versions are indicated in the
+“Version notes” column of the various tables.
+
+== Tables ==
+
+This document describes several additional TrueType table types. The
+“Silf” and “Sile” tables are unique to the needs of Graphite, whilst
+“Gloc” and “Glat” provide an extended glyph attribute mechanism. The
+“Feat” table is based very closely on the GX “feat” table. (If necessary
+the tables could be restructured to be stored inside the single “Silf”
+table.) In addition, use is made of the “name” table type.
+
+This version of the Graphite format includes the ability to compress
+“Glat” and “Silf” tables, the extensions to those table provide a
+compression scheme field permitting up to 32 compression schemes.
+Currently only 2 schemes are defined: 0 – no compression, and 1 – an LZ4 block
+decompressor. This is not the LZ4 framing format just the inner block level
+format without any checksum.
+
+All compressed tables have the same form the original table's 32bit
+version number followed by a 32 bit compression header. This consists of
+the top 5 bits for the scheme and 27 remaining bits for the uncompressed
+table size. This is then followed by the compression scheme's data.
+
+[[comp_table]]
+.Compressed table
+[cols="3,3,8,3",options="unbreakable,header,compact",width="90%",frame="topbot",grid="none"]
+|===========================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Uncompressed Table version number |
+|ULONG:5 |scheme |Compression scheme must not be 0 |5.0 – added
+|ULONG:27 |full_size |Size of uncompressed table |5.0 – added
+|BYTE[] |compressed_data |Compression scheme data |5.0 – added
+|===========================================================================
+
+The uncompressed form is the complete table including the version number but
+with the scheme always set to 0. The remaining 27 bits are available to the
+uncompressed table.
+
+=== Glat ===
+
+The Glat table type is used for storing glyph attributes. Each glyph may
+be considered to have a sparse array of, at the most, 65536 16-bit
+signed attributes. The Glat table is the mechanism by which they are
+stored.
+
+The Glat table consists of a table header and an array of Glat_entry
+items. Two formats for the Glat table are typically used. Most fonts will
+use a version 2 table without Octabox metrics. Those few fonts that
+have collision avoidance support, will use a version 3 table.
+
+.Glat version 2
+[cols="3,3,8,3",options="unbreakable,header,compact",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00030000 |4.0 – 00020000
+|Glat_entry[] |entries |Glyph attribute entries |
+|=======================================================================
+
+
+.Glat version 3
+[cols="3,3,8,3",options="unbreakable,header,compact",width="90%",frame="topbot",grid="none"]
+|========================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00030000 |5.0 – 00030000
+|ULONG:5 |scheme |Compression scheme must be 0 |5.0 – added
+|ULONG:28 |reserved | |5.0 – added
+|ULONG:1 |octaboxes |Octaboxes are present flag |5.0 – added
+|Glyph_attrs[] |entries |Glyph attribute entries |
+|========================================================================
+For the compressed layout see <>.
+
+.Glyph_attrs
+[cols="3,3,8,3",options="unbreakable,header,compact",width="90%",frame="topbot",grid="none"]
+|========================================================================
+|Type |Name |Description |Version notes
+
+|Octabox_metrics |octabox |Octabox metrics, only present
+ if the Glat header indicates |5.0 – added
+|Glat_entry[] |entries |Glyph attribute entries |
+|========================================================================
+
+If the octaboxes flag is set in the Glat header then for each per glyph block
+of data specified by the Gloc table, first set of data includes metrics that
+approximate the glyph’s curves. The approximation uses “octoboxes”—rectangles
+with corners that may be cut out at an angle of 45 degrees. Each octobox
+requires 8 values to define. There are metrics for the entire glyph and for a
+4x4 approximation grid, resulting in up to 16 sub-boxes. For some glyphs, no
+sub-box data will be present, in which case the bitmap will be zero.
+Note that the rectangle for the full glyph is not included here, as the
+bounding box rectangle is stored elsewhere in the font.
+
+.Octabox_metrics
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|================================================================================
+|Type |Name |Description |Version notes
+
+|USHORT |subbox_bitmap |Which subboxes exist on 4x4 grid; +
+ bit-index = (y-index*4) + x-index |
+|BYTE |diag_neg_min |Defines minimum negatively-sloped diagonal |
+|BYTE |diag_neg_max |Defines maximum negatively-sloped diagonal |
+|BYTE |diag_pos_min |Defines minimum positively-sloped diagonal |
+|BYTE |diag_pos_max |Defines maximum positively-sloped diagonal |
+|Subbox_entry[] |subboxes |One entry per bit in subbox_bitmap |
+|================================================================================
+
+Note that in the subbox bitmap, bit 3 indicates the presence of the
+lower right cell, and bit 12 the upper left cell as per this diagram.
+
+.subbox_bitmap
+[cols=",,,",width="20%",grid="all"]
+|==============
+|12 |13 |14 |15
+| 8 | 9 |10 |11
+| 4 | 5 | 6 | 7
+| 0 | 1 | 2 | 3
+|==============
+
+.Subbox_entry
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|===============================================================================
+|Type |Name |Description |Version notes
+
+|BYTE |left |Left of subbox |
+|BYTE |right |Right of subbox |
+|BYTE |bottom |Bottom of subbox |
+|BYTE |top |Top of subbox |
+|BYTE |diag_pos_min |Defines minimum positively-sloped diagonal |
+|BYTE |diag_pos_max |Defines maximum positively-sloped diagonal |
+|BYTE |diag_neg_min |Defines minimum negatively-sloped diagonal |
+|BYTE |diag_neg_max |Defines maximum negatively -sloped diagonal |
+|===============================================================================
+
+Following the glyph curve approximation data, the glyph attributes
+appear. The glyph attributes associated with a particular glyph are
+identified by number and value. To conserve space, this storage is
+run-length encoded. Thus a glyph will have a series of Glat_entrys
+corresponding to each non-contiguous set of attributes. The structure of
+a Glat_entry is:
+
+.Glat_entry, version 2 & 3
+[cols="2,2,8,5",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|SHORT |attNum |Attribute number of first attribute |4.0 – BYTE to SHORT
+|SHORT |num |Number of attributes in this run |4.0 – BYTE to SHORT
+|SHORT |attributes[] |Array of num attributes |
+|=======================================================================
+
+Notice that all glyph attributes are 16-bit signed values. If a 32-bit
+value is required, then two attributes should be assigned and joined
+together by the application.
+
+Attribute numbers are application specific.
+
+Note that if the font does not require more than 256 glyph attributes,
+version 1 of the Glat table will be generated, which is defined as
+follows.
+
+.Glat version 1
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00010000 |
+
+|Glat_entry[] |entries |Glyph attribute entries |
+|=======================================================================
+
+.Glat_entry, version 1
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|BYTE |attNum |Attribute number of first attribute |
+
+|BYTE |num |Number of attributes in this run |
+
+|SHORT |attributes[ ] |Array of num attributes |
+|=======================================================================
+
+=== Gloc ===
+
+The Gloc table is used to index the Glat table. It is structured
+identically to the loca table type, except that it has a header.
+
+TODO: add a field indicating the number of glyphs in the table (the
+current dependence on the Silf table is not architecturally clean).
+
+.Gloc
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00010000 |
+
+|USHORT |flags |bit 0 = 1 for Long format, = 0 for short formatbit 1 = 1
+for attribute names, = 0 for stripped |
+
+|USHORT |numAttribs |Number of attributes |
+
+|USHORT/ULONG |locations[ ] |Offsets into Glat table for each glyph;
+(number of glyph IDs + 1) of these |
+
+|USHORT |attribIds[ ] |Debug id for each attribute |
+|=======================================================================
+
+The flags entry contains a bit to indicate whether the locations array
+is of type USHORT or ULONG. The locations array is identically
+structured to that of the loca table. There is one entry per glyph and
+an extra entry to identify the length of the final glyph’s attribute
+entries. Offsets are given to a Glat_entry in the Glat table. The second
+bit indicates whether there is an attribIds array at the end of this
+table. If there is, then it contains name IDs for each attribute. If
+this bit is not set, then there is no array and the table ends after the
+locations array.
+
+As of version 2 of the Silf table, the values of the breakweight
+attribute are interpreted as follows:
+
+....
+BREAK_WHITESPACE = 10
+BREAK_WORD = 15
+BREAK_INTRA = 20
+BREAK_LETTER = 30
+BREAK_CLIP = 40
+....
+
+=== Feat ===
+
+Graphite stores features in a table whose format is very similar to the
+GX feat table. This makes reference to the name table which is use for
+storing feature names and feature value names.
+
+.Feat
+[cols="3,3,8,5",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00020000 |3.0 – changed from 00010000 to
+00020000
+
+|USHORT |numFeat |Number of features |
+
+|USHORT |reserved | |
+
+|ULONG |reserved | |
+
+|FeatureDefn |features[ ] |Array of numFeat features |
+
+|FeatureSettingDefn |featSettings[ ] |Array of feature setting values,
+indexed by offset |
+|=======================================================================
+
+.FeatureDefn
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|ULONG |id |Feature ID number |3.0 – added
+
+|USHORT |numSettings |Number of settings |
+
+|USHORT |reserved | |3.0 – inserted
+
+|ULONG |offset |Offset into featSettings list |
+
+|USHORT |flags | |
+
+|USHORT |label |Index into name table for UI label |
+|=======================================================================
+
+.FeatureSettingDefn
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|SHORT |value |Feature setting value |
+
+|USHORT |label |Index into name table for UI label |
+|=======================================================================
+
+=== Silf ===
+
+The “Silf” table will be used for storing rules and actions for the
+various types of tables in a rendering description. The structure of the
+Silf table is:
+
+.Silf
+[cols="2,3,8,5",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00050000 |2.0 – changed to 00020000
+| | | |3.0 – changed to 00030000
+| | | |5.0 – changed to 00050000
+|ULONG:5 |scheme |Compression scheme must be 0 |5.0 – added
+|FIXED:27 |compilerVersion |Compiler version that
+ generated this font |3.0 – added +
+ 5.0 – changed to 27 bits
+|USHORT |numSub |Number of SIL subtables |
+|USHORT |reserved | |
+|ULONG |offset[] |Array of numSub offsets to the subtables
+ relative to the start of this table |
+|SIL_Sub |tables[] |Array of independent rendering description
+ subtables |
+|==================================================================================
+For the compressed layout see <>.
+Since one TrueType file may hold multiple independent rendering
+descriptions, each rendering description is described in a subtable. The
+subtable contains all that is necessary to describe the rendering of one
+set of writing systems.
+
+.SIL_Sub
+[cols="4,6,28,7",options="header",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |ruleVersion |Version of stack-machine language used in rules
+|3.0 – added
+
+|USHORT |passOffset |offset of oPasses[0] relative to start of sub-table
+|3.0 – added
+
+|USHORT |pseudosOffset |offset of pMaps[0] relative to start of
+sub-table |3.0 – added
+
+|USHORT |maxGlyphID |Maximum valid glyph ID (including line-break &
+pseudo-glyphs) |
+
+|SHORT |extraAscent |Em-units to be added to the font’s ascent |
+
+|SHORT |extraDescent |Em-units to be added to the font’s descent |
+
+|BYTE |numPasses |Number of rendering description passes |
+
+|BYTE |iSubst |Index of first substitution pass |
+
+|BYTE |iPos |Index of first Positioning pass |
+
+|BYTE |iJust |Index of first Justification pass |
+
+|BYTE |iBidi |Index of first pass after the bidi pass(must be <= iPos);
+0xFF implies no bidi pass |
+
+|BYTE |flags | 0 - has line end contextuals, 1 - contextuals,
+2-4 - space contextuals, 5 - has collision pass |4.0 – added Bit 1
+
+|BYTE |maxPreContext |Max range for preceding cross-line-boundary
+contextualization |
+
+|BYTE |maxPostContext |Max range for following cross-line-boundary
+contextualization |
+
+|BYTE |attrPsuedo |Glyph attribute number that is used for actual glyph
+ID for a pseudo glyph |
+
+|BYTE |attrBreakWeight |Glyph attribute number of breakweight attribute |
+
+|BYTE |attrDirectionality |Glyph attribute number for directionality
+attribute |
+
+|BYTE |attrMirroring |Glyph attribute number for mirror.glyph
+(mirror.isEncoded directly after) |2.0 – added;4.0 – used
+
+|BYTE |attrSkipPasses |Glyph attribute of bitmap indicating key glyphs
+for pass optimization |2.0 – added;4.0 – used
+
+|BYTE |numJLevels |Number of justification levels; 0 if no justification
+|2.0 – added
+
+|Justification-Level |jLevels[ ] |Justification information for each
+level. |2.0 – added
+
+|USHORT |numLigComp |Number of initial glyph attributes that represent
+ligature components |
+
+|BYTE |numUserDefn |Number of user-defined slot attributes |
+
+|BYTE |maxCompPerLig |Maximum number of components per ligature |
+
+|BYTE |direction |Supported direction(s) |
+
+|BYTE |attCollisions | First of a set of attributes that hold collision flags and constraint box | 5.0 - used
+
+|BYTE |reserved | |
+
+|BYTE |reserved | |
+
+|BYTE |reserved | |2.0 – added
+
+|BYTE |numCritFeatures |Number of critical features |2.0 – added
+
+|USHORT |critFeatures[ ] |Array of critical features |2.0 – added
+
+|BYTE |reserved | |2.0 – added
+
+|BYTE |numScriptTag |Number of scripts this subtable supports |
+
+|ULONG |scriptTag[ ] |Array of numScriptTag script tags |
+
+|USHORT |lbGID |Glyph ID for line-break psuedo-glyph |
+
+|ULONG |oPasses[ ] |Offets to passes relative to the start of this
+subtable; numPasses + 1 of these |
+
+|USHORT |numPseudo |Number of Unicode -> pseudo-glyph mappings |
+
+|USHORT |searchPseudo |(max power of 2 <= numPseudo) * sizeof(PseudoMap) |
+
+|USHORT |pseudoSelector |log2(max power of 2<= numPseudo) |
+
+|USHORT |pseudoShift |numPseudo - searchPseudo |
+
+|PseudoMap |pMaps[ ] |Mappings between Unicode and pseudo-glyphs in
+order of Unicode |
+
+|ClassMap |classes |Classes object storing replacement classes used in
+actions |
+
+|SIL_Pass |passes[ ] |Array of passes |
+|=======================================================================
+
+Each justification level has several glyph attributes associated with
+it.
+
+This structure was new as of version 2.0.
+
+.JustificationLevel
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|BYTE |attrStretch |Glyph attribute number for justify.X.stretch |
+
+|BYTE |attrShrink |Glyph attribute number for justify.X.shrink |
+
+|BYTE |attrStep |Glyph attribute number for justify.X.step |
+
+|BYTE |attrWeight |Glyph attribute number for justify.X.weight |
+
+|BYTE |runto |Which level starts the next stage |
+
+|BYTE |reserved | |
+
+|BYTE |reserved | |
+
+|BYTE |reserved | |
+|=======================================================================
+
+A pseudo-glyph is a glyph which contains no font metrics (it has a GID
+greater than the numGlyphs entry in the maxp table) but is used in the
+rendering process. Each pseudo-glyph has an attribute which is the glyph
+ID of a real glyph which will be used to actually render the glyph. The
+pseudo-glyph map contains a mapping between Unicode and pseudo-glyph
+number:
+
+.PseudoMap
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|ULONG |unicode |Unicode codepoint |2.0 – changed from USHORT to ULONG
+
+|USHORT |nPseudo |Glyph ID of pseudo-glyph |
+|=======================================================================
+
+The ClassMap stores the replacement class information for the passes in
+this description. Replacement classes are used during substitution where
+a glyph id is looked up in one class and the glyph ID at the
+corresponding index in another class is substituted. The difficulty with
+the storage of such classes is in looking up a glyph ID in an
+arbitrarily ordered list. One approach is to use a linear search; this
+is very slow, but is stored very simply. Another approach is to order
+the glyphs in the class and to store the index against the glyph. Both
+approaches are supported in the ClassMap table structure:
+
+.ClassMap
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|USHORT |numClass |Number of replacement classes |
+
+|USHORT |numLinear |Number of linearly stored replacement classes |
+
+|ULONG |oClass[ ] |Array of numClass + 1 offsets to class arrays from
+the beginning of the class map | 4.0 changed from USHORT
+
+|USHORT |glyphs[ ] |Glyphs for linear classes |
+
+|LookupClass |lookups[ ] |An array of numClass – numLinear lookups |
+|=======================================================================
+
+The LookupClass stores a fast lookup association between glyph ID and
+index. Each lookup consists of an ordered list of glyph IDs with the
+corresponding index for that glyph. The number of elements in the lookup
+is specified by numIds along with a search Range and shift to initialize
+a fast binary search engine:
+
+.LookupClass
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|USHORT |numIDs |Number of elements in the lookup |
+
+|USHORT |searchRange |(max power of 2<= numIDs) |
+
+|USHORT |entrySelector |log2(max power of 2<= numIDs) |
+
+|USHORT |rangeShift |numIds – searchRange |
+
+|LookupPair |lookups[ ] |lookups; there are numIDs of these |
+|=======================================================================
+
+Each element in the lookup consists of a glyphId and the corresponding
+index in the original ordered list.
+
+.LookupPair
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|USHORT |glyphId |glyph id to be compared |
+
+|USHORT |index |index corresponding to this glyph id in ordered list |
+|=======================================================================
+
+=== Pass ===
+
+Each processing pass consists of a finite state machine description for
+rule finding, and the actions that are executed when a rule is matched.
+
+.SIL_Pass
+[cols="5,9,34,8",options="header",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|BYTE |flags |0-2 - number of collision runs; 3-4 - kerning collisions;
+5 - reverse direction pass | 5.0 - added bits 0-5
+
+|BYTE |maxRuleLoop |MaxRuleLoop for this pass |
+
+|BYTE |maxRuleContext |Number of slots of input needed to run this pass |
+
+|BYTE |maxBackup |Number of slots by which the following pass needs to
+trail this pass (ie, the maximum this pass is allowed to back up) |
+
+|USHORT |numRules |Number of action code blocks |
+
+|USHORT |fsmOffset |offset to numRows relative to the beginning of the
+SIL_Pass block |2.0 - added; 3.0 - use as fsmOffset
+
+|ULONG |pcCode |Offset to start of pass constraint code from start of
+subtable (*passConstraints[0]*) |2.0 - added
+
+|ULONG |rcCode |Offset to start of rule constraint code from start of
+subtable (*ruleConstraints[0]*) |
+
+|ULONG |aCode |Offset to start of action code relative to start of
+subtable (*actions[0]*) |
+
+|ULONG |oDebug |Offset to debug arrays (*dActions[0]*); equals 0 if
+debug stripped |
+
+|USHORT |numRows |Number of FSM states |
+
+|USHORT |numTransitional |Number of transitional states in the FSM
+(length of *states* matrix) |
+
+|USHORT |numSuccess |Number of success states in the FSM (size of
+*oRuleMap* array) |
+
+|USHORT |numColumns |Number of FSM columns |
+
+|USHORT |numRange |Number of contiguous glyph ID ranges which map to
+columns |
+
+|USHORT |searchRange |(maximum power of 2 <=
+numRange)*sizeof(Pass_Range) |
+
+|USHORT |entrySelector |log2(maximum power of 2 <= numRange) |
+
+|USHORT |rangeShift |numRange*sizeof(Pass_Range)-searchRange |
+
+|Pass_Range |ranges[ ] |Ranges of glyph IDs for this FSM; *numRange* of
+these |
+
+|USHORT |oRuleMap[ ] |Maps from success state to offset into ruleMap
+array from start of array. First item corresponds to state # (numRows –
+numSuccess); ie, non-success states are omitted. [0xFFFF implies rule
+number is equal to state number (i.e. no entry in ruleMap) – NOT
+IMPLEMENTED] |
+
+|USHORT |ruleMap[ ] |Array of rule numbers corresponding to an success
+state number |
+
+|BYTE |minRulePreContext |Minimum number of items in any rule’s context
+before the first modified rule item |
+
+|BYTE |maxRulePreContext |Maximum number of items in any rule’s context
+before the first modified rule item |
+
+|SHORT |startStates[ ] |Array of size (maxRulePreContext –
+minRulePreContext + 1), indicating the start state in the state machine
+based on how many pre-context items a rule has |
+
+|USHORT |ruleSortKeys[ ] |Array of *numRules* sort keys, indicating
+precedence of rules |
+
+|BYTE |rulePreContext[ ] |Array of *numRules* items indicating the
+number of items in the context before the first modified item, one for
+each rule |
+
+|BYTE |collisionThreshold | |2.0 - inserted, 5.0 – used
+
+|USHORT |pConstraint |Length of passConstraint block |2.0 – added
+
+|USHORT |oConstraints[ ] |numRules + 1 offsets to constraint code blocks
+relative to *rcCode* and start of subtable |
+
+|USHORT |oActions[ ] |numRules + 1 offsets to action code blocks
+relative to *aCode* and start of subtable |
+
+|USHORT |stateTrans[ ][ ] |Array of *numTransitional* rows of
+*numColumns* state transitions. |
+
+|BYTE |reserved | |2.0 – inserted
+
+|BYTE |passConstraints[ ] |Sequences of constraint code for pass-level
+constraints |2.0 – added
+
+|BYTE |ruleConstraints[ ] |Sequences of constraint code for rules |
+
+|BYTE |actions[ ] |Sequences of action code |
+
+|footnote:[ Should debug tables go at the end, and be marked via a flag
+as per Gloc?]USHORT |dActions[ ] |Name index for each action for
+documentation purposes. 0 = stripped. numRules of these |
+
+|USHORT |dStates[ ] |Name index for each intermediateFSM row/state for
+debugging. 0 = stripped. Corresponds to the last numRows – numRules |
+
+|USHORT |dCols[ ] |Name index for each state (numRows of these) |
+|=======================================================================
+
+Notice that the ranges array has fast lookup information on the front to
+allow for the quick identification of which range a particular glyph id
+is in. Each range consists of the first and last glyph id in the range.
+
+.Pass_Range
+[cols="3,3,8",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description
+
+|USHORT |firstId |First Glyph id in the range
+
+|USHORT |lastId |Last Glyph id in the range
+
+|USHORT |colId |Column index for this range
+|=======================================================================
+
+==== Pass Contents ====
+
+A pass contains a Finite State Machine (FSM) which is used to match
+input strings to rules. It also contains constraints for further testing
+whether a matched string should fire, and it contains the action code to
+execute against the matched string.
+
+The FSM consists of a set of states. A state consists of a row of
+transitions between that state and another state dependent upon the next
+glyph in the input stream. Each state may be an acceptance state, in
+which case it corresponds to a rule match, or a transition state, in
+which case the state is on the way to matching a rule, or both. A null
+state transition is one in which the occurrence of this particular class
+of the following glyph, will result in no extension of a rule match
+anywhere, just fail on all further searching. A final state is one in
+which all its transitions are null transitions.
+
+Note that the stateTrans array only needs to represent transitional
+states, not final states. Similarly, the oRuleMap array only needs
+entries for acceptance states (whether final or transitional). For this
+reason the FSM is set up (conceptually) in the following order:
+transitional non-accepting states first, followed by transitional
+accepting states, followed by final (accepting) states.
+
+Note also that because there may be more than one matched rule for a
+given state, oRuleMap indicates a list of rule indices in the ruleMap
+array; oRuleMap[i+1] – oRuleMap[i] indicates how many there are for
+state i.
+
+Normally the start state for an FSM is zero. But for each pass there is
+the idea of a “pre-context,” that is, there are slots that need to be
+taken into consideration in the rule-matching process that are before
+the current position of the input stream. If we are very near the
+beginning of the input, we may need to adjust by skipping some states,
+which corresponds to skipping the “pre-context” slots that not present
+due to being prior to the beginning of the input. This is what the
+maxRulePreContext, minRulePreContext, and startStates items are used
+for. Specifically, we need to skip the number of transitions equal to
+the difference between the maxRulePreContext and the current stream
+position, if greater than zero. The startStates array indicates what the
+adjusted start state should be. If the current input position is less
+than minRulePreContext, no rule will match at all.
+
+Rules are matched in order of length, so that longest rules are given
+precedence over shorter rules. However, the length of some rules may
+have been adjusted to allow for a consistent “pre-context” for all
+rules, so the number of matched states in the FSM may not correspond to
+the actual number of matched items in the rule. For this reason, it is
+not adequate to simply order rules based on the number of traversed
+states in the FSM. Rather, rules are given sort keys indicating their
+precedence, which is based primarily on the length of the rule and
+secondarily on its original position within the source code.
+
+The FSM engine keeps track of all the acceptance states it passes
+through on its path to a final state. This results in a list of rules
+matched by the string sorted by precedence. The engine takes the first
+rule index off the list and looks up the offset to some constraint code.
+This code is executed and if the constraint passes, then the action code
+associated with that offset is executed and the FSM restarts at the
+returned slot position. If the constraint fails, then the FSM considers
+the next-preferred rule, tests that constraint, and so forth. If no
+accepting state is found or all rules fail their constraints, then no
+rule applies, in which case a single glyph is put into the output stream
+and the current position advances by one slot.
+
+The action strings are simply byte strings of actions, much like hinting
+code, but using a completely different language. (See “Stack Machine
+Commands.doc”.)
+
+=== Sile ===
+
+This table is used in Graphite table files that rely on an external font
+for rendering of the glyphs. When this table is present, the Graphite
+file is in effect a minimal font that contains information about the
+actual font to use in rendering. This information is stored in the Sile
+table.
+
+This table was added as of version 2. It is not currently being used.
+
+.Sile
+[cols="3,3,8",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description
+
+|FIXED |version |Table version: 00010000
+
+|ULONG |checksum |master checksum (checkSumAdjustment) from the head
+table of the base font
+
+|ULONG |createTime[2] |Create time of the base font (64-bits) from the
+head table
+
+|ULONG |modifyTime[2] |Modify time of the base font (64-bits) from the
+head table
+
+|USHORT |fontNameLength |Number of characters in fontName
+
+|USHORT |fontName[ ] |Family name of base font
+
+|USHORT |fontFileLength |Number of characters in baseFile
+
+|USHORT |baseFile[ ] |Original path and name of base font file
+|=======================================================================
+
+There are four possible situations with regard to the Sile table. The
+first two are considered normal and the second two pathological.
+
+No Sile table is present. In this case, it is assumed that the Graphite
+table file is a normal font containing not only the Graphite tables but
+also the glyphs and metrics needed for rendering.
+
+The base font named in the Sile table is present on the system, and its
+master checksum and dates match those in the Sile table. In this case,
+the Graphite tables are read from the Graphite table file, but the
+glyphs, metrics, and cmap from the base font are what are used for
+rendering (with the modification performed by the Graphite tables).
+
+The base font named in the Sile table is present, but its master
+checksum and/or dates do not match those in the Sile table. In this case
+the base font is used to perform the rendering, but with no Graphite
+behaviors.
+
+The base font named in the Sile table is not present on the system. In
+this case the Graphite table file is used for the rendering, with no
+Graphite behaviors, resulting in square boxes in place of the expected
+glyphs.
+
+=== Sill ===
+
+This table maps ISO-639-3 language codes onto feature values. Each
+language code can be a maxmum of 4 ASCII characters (although 2 or 3
+characters is what is used by the ISO standard).
+
+This table was added as of version 3.
+
+.Sill
+[cols="4,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|FIXED |version |Table version: 00010000 |
+
+|USHORT |numLangs |Number of languages supported |
+
+|USHORT |searchRange |(maximum power of 2 <= numLangs) |
+
+|USHORT |entrySelector |log2(maximum power of 2 <= numLangs) |
+
+|USHORT |rangeShift |numLangs - searchRange |
+
+|LanguageEntry |entries[ ] |Languages and pointers to feature settings;
+there are numLang + 1 of these |
+
+|LangFeatureSetting |settings[ ] |Feature ID / value pairs |
+|=======================================================================
+
+Each language entry contains a 4-character language code and an offset
+to the list of features. There is one bogus entry at the end that
+facilitates finding the size of the last entry. The offsets are relative
+to the beginning of the Sill table.
+
+The language code is left-aligned with any unused characters padded with
+NULLs. For instance, the code “en” is represented by the four bytes
+[101, 110, 0, 0].
+
+.LanguageEntry
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|BYTE |langcode[4] |4-char ISO-639-3 language code |
+
+|USHORT |numSettings |Number of feature settings for this language |
+
+|USHORT |offset |Offset to first feature setting for this language |
+|=======================================================================
+
+.LangFeatureSetting
+[cols="3,3,8,3",options="unbreakable,header",width="90%",frame="topbot",grid="none"]
+|=======================================================================
+|Type |Name |Description |Version notes
+
+|ULONG |featureId |Feature identifer number (matches ID in Feat table) |
+
+|SHORT |value |Default feature value for this language |
+
+|USHORT |reserved |Pad bytes |
+|=======================================================================
+
+=== Sild ===
+
+This table holds the debug strings for debugging purposes. Since the
+strings are only used for debugging, they are held somewhat optimised
+for space over speed and are not considered to be multilingual. Thus
+strings are considered to be 7-bit ASCII, with a possible extension to
+UTF-8 at a later stage. The table consists of a sequence of strings each
+preceded by a length byte. The first string is id 0 and so on to the end
+of the table.
+
+NOTE: this table has not been implemented.
+
+== Multiple Descriptions ==
+
+In the case where multiple descriptions are to be stored in the same set
+of tables, the following unifications need to occur:
+
+The feature sets must be unified, thus limiting two features with the
+same name to having the same settings and corresponding values.
+
+The glyph attributes must be unified. This can be done by using
+different attribute number ranges, or by examining for identical
+attribute mappings or for non-intersecting attribute mappings.
+
+The use of the name table must be unified to ensure that two features or
+feature settings do not refer to the same entry in the name table.
+
+Notice that the requirement that any tables declared in an external
+binary description override the corresponding font table in the font,
+means that a name table in an external binary description must be
+complete, including all the strings from the original font.
+
+include::OpCodes.txt[]
+
Binary files /tmp/tmpumIjIP/e37R5ywTxx/graphite2-1.2.4/doc/guardspace.png and /tmp/tmpumIjIP/HlZY4WD3aM/graphite2-1.3.6/doc/guardspace.png differ
diff -Nru graphite2-1.2.4/doc/guardspace.svg graphite2-1.3.6/doc/guardspace.svg
--- graphite2-1.2.4/doc/guardspace.svg 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/guardspace.svg 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,492 @@
+
+
+
+
diff -Nru graphite2-1.2.4/doc/hacking.txt graphite2-1.3.6/doc/hacking.txt
--- graphite2-1.2.4/doc/hacking.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/doc/hacking.txt 2016-02-29 04:18:01.000000000 +0000
@@ -24,6 +24,13 @@
If set removes all dllimport or dllexport declspecs on the Graphtie2 API functions and makes them
exportable for a clean static library build on Windows.
+GRAPHITE2_BUILTINS::
+ If set this will use gcc or clang __builtin intrinsics where appropriate when compilling for
+ some architectures (Intel with SSE4.2 or later and ARMv7a with a NEON capable FPU) this
+ will cause the compiler to emit specialised instructions where it can or fall back to library code.
+ Currently this is only used for __builtin_popcount and should only be turned when you know the instruction
+ will be emitted as the gcc __builtin_popcount is 2x slower on Intel than Graphite's own version.
+
GRAPHITE2_NSEGCACHE::
If set, the segment caching code is not compiled into the library. This can be used to save space
if the engine is under space constraints both for code and memory. The default is that this is not
diff -Nru graphite2-1.2.4/doc/manual.txt graphite2-1.3.6/doc/manual.txt
--- graphite2-1.2.4/doc/manual.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/doc/manual.txt 2016-02-29 04:18:01.000000000 +0000
@@ -7,5 +7,6 @@
include::building.txt[]
include::calling.txt[]
include::features.txt[]
+include::font.txt[]
include::hacking.txt[]
include::testing.txt[]
diff -Nru graphite2-1.2.4/doc/OpCodes.txt graphite2-1.3.6/doc/OpCodes.txt
--- graphite2-1.2.4/doc/OpCodes.txt 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/doc/OpCodes.txt 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,88 @@
+== Stack Machine Commands ==
+
+This document describes the commands that are defined in Graphite’s stack machine, which are used to run rules and test their constraints.
+By default arguments are 8-bits wide unless stated as being short (16-bit) or long (32-bit). Angle brackets () indicate a signed value, curly braces ({arg}) indicate an unsigned value. All values larger than a byte are stored big endian with the most significant byte first.
+ is a slot offset relative to the current slot that opcodes act upon.
+Any opcode with a value outside the range of opcodes listed here (currently 0x00-0x3E) is considered illegal and will cause the font to fail to load.
+
+=== General arithmetic operations ===
+[cols="1,2,1,11",options="unbreakable,header,compact",width="100%",frame="topbot",grid="none"]
+|=======================================================================
+|Code |Name |Param |Description
+|00 |NOP | |Do nothing.
+|01 |PushByte | |Push the given 8-bit signed number onto the stack.
+|02 |PushByteU |\{byte\} |Push the given 8-bit unsigned number onto the stack.
+|03 |PushShort | |Push the 2 byte number onto the stack.
+|04 |PushShortU |\{short\} |Push the 2 byte unsigned number onto the stack.
+|05 |PushLong | |Push the 4 byte number onto the stack. There is no sign extension so no need for an unsigned opcode
+|06 |Add ||Pop the top two items off the stack, add them, and push the result.
+|07 |Sub ||Pop the top two items off the stack, subtract the first (top-most) from the second, and push the result.
+|08 |Mul ||Pop the top two items off the stack, multiply them, and push the result.
+|09 |Div ||Pop the top two items off the stack, divide the second by the first (top-most), and push the result.
+|0A |Min ||Pop the top two items off the stack and push the minimum.
+|0B |Max ||Pop the top two items off the stack and push the maximum.
+|0C |Neg ||Pop the top item off the stack and push the negation.
+|0D |Trunc8 ||Pop the top item off the stack and push the value truncated to 8 bits.
+|0E |Trunc16 ||Pop the top item off the stack and push the value truncated to 16 bits.
+|0F |Cond ||Pop the top three items off the stack. If the first == 0 (false), push the third back on, otherwise push the second back on.
+|10 |And ||Pop the top two items off the stack and push their logical and. Zero is treated as false; all other values are treated as true.
+|11 |Or ||Pop the top two items off the stack and push their logical or. Zero is treated as false; all other values are treated as true.
+|12 |Not ||Pop the top item off the stack and push its logical negation (1 if it equals zero, 0 otherwise.
+|13 |Equal ||Pop the top two items off the stack and push 1 if they are equal, 0 if not.
+|14 |NotEqu ||Pop the top two items off the stack and push 0 if they are equal, 1 if not.
+|15 |Less ||Pop the top two items off the stack and push 1 if the next-to-the-top is less than the top-most; push 0 othewise.
+|16 |Gtr ||Pop the top two items off the stack and push 1 if the next-to-the-top is greater than the top-most; push 0 othewise.
+|17 |LessEq ||Pop the top two items off the stack and push 1 if the next-to-the-top is less than or equal to the top-most; push 0 otherwise.
+|18 |GtrEq ||Pop the top two items off the stack and push 1 if the next-to-the-top is greater than or equal to the top-most; push 0 otherwise
+|=======================================================================
+
+=== Rule processing and constraints ===
+[cols="1,4,3,3,3,22",options="unbreakable,header,compact",width="100%",frame="topbot",grid="none"]
+|=======================================================================
+|Code |Name |Param |Param |Param |Description
+|19 |Next ||||Move the current slot pointer forward one slot (used after we have finished processing that slot).
+|1A |NextN | |||Not Implemented: Move the current slot pointer by the given number of slots (used after we have finished processing the current slot). The count may be positive or negative. Should not be used to copy a range of slots; CopyNext is needed for that.
+|1B |CopyNext ||||Copy the current slot from the input to the output and move the current slot pointer forward one slot.
+|1C |PutGlyph |\{outclass\}|||Put the first glyph of the specified class into the output. Normally used when there is only one member of the class, and when inserting.
+|1D |PutSubs | |\{inclass\} |\{outclass\} |Determine the index of the glyph that was the input in the given slot within the input class, and place the corresponding glyph from the output class in the current slot. The slot number is relative to the current input position.
+|1E |PutCopy | ... | |Set the associations for the current slot to be the given slot(s) in the input. The first argument indicates how many slots follow. The slot offsets are relative to the current input slot.
+|22 |ContextItem | |\{byte-count\} ||If the slot currently being tested is not the slot specified by the argument (relative to the stream position, the first modified item in the rule), skip the given number of bytes of stack-machine code. These bytes represent a test that is irrelevant for this slot.
+|23 |AttrSet |\{slotattr\} |||Pop the stack and set the value of the given attribute to the resulting numerical value.
+|24 |AttrAdd |\{slotattr\} |||Pop the stack and adjust the value of the given attribute by adding the popped value.
+|25 |AttrSub |\{slotattr\} |||Pop the stack and adjust the value of the given attribute by subtracting the popped value.
+|26 |AttrSetSlot |\{slotattr\} |||Pop the stack and set the given attribute to the value, which is a reference to another slot, making an adjustment for the stream position. The value is relative to the current stream position. [Note that corresponding add and subtract operations are not needed since it never makes sense to add slot references.]
+|27 |IAttrSetSlot |\{slotattr\} |\{index\} ||Pop the stack and set the given indexed attribute of the current slot to the value, which is a reference to another slot, making an adjustment for the stream position. The value is relative to the current stream position. [Currently the only indexed slot attributes are component.X.ref.]
+|28 |PushSlotAttr |\{slotattr\} | ||Look up the value of the given slot attribute of the given slot and push the result on the stack. The slot offset is relative to the current input position.
+|29 |PushGlyph-Attr |\{glyphattr\} | ||Look up the value of the given glyph attribute of the given slot and push the result on the stack. The slot offset is relative to the current input position.
+|2A |PushGlyph-Metric |\{glyph-metric\} | | |Look up the value of the given glyph metric of the given slot and push the result on the stack. The slot offset is relative to the current input position. The level indicates the attachment level for cluster metrics.
+|2B |PushFeat |\{feat\} | ||Push the value of the given feature for the current slot onto the stack.
+|2C |PushAttrTo-GlyphAttr |\{glyphattr\} | ||Look up the value of the given glyph attribute for the slot indicated by the given slot’s attach.to attribute. Push the result on the stack.
+|2D |PushAttTo-GlyphMetric |\{glyph-metric\} | | |Look up the value of the given glyph metric for the slot indicated by the given slot’s attach.to attribute. Push the result on the stack.
+|2E |PushISlotAttr |\{slotattr\} | | |Push the value of the indexed slot attribute onto the stack. [The current indexed slot attributes are component.X.ref and userX.]
+|2F |PushIGlyph-Attr |\{glyphattr\} | | |Not Implemented: Push the value of the indexed glyph attribute onto the stack. [Examples of indexed glyph attributes are component.X.box.top, component.X.box.bottom, etc.]
+|30 |PopRet ||||No more processing is needed for this rule. Pop the top of the stack and return that value. For rule action code, the return value is the number of positions to move the stream position forward (or backward, if the number is negative) for the next rule. For constraint code, the return value is a boolean indicating whether the constraint succeeded.
+|31 |RetZero ||||Terminate the processing and return zero.
+|32 |RetTrue ||||Terminate the processing and return true (1).
+|33 |IAttrSet |\{slotattr\} |\{index\} ||Pop the stack and set the value of the given indexed attribute to the resulting numerical value. Not to be used for attributes whose value is a slot reference. [Currently the only non-slot-reference indexed slot attributes are userX.]
+Not supported in version 1.0 of the font tables.
+|34 |IAttrAdd |\{slotattr\} |\{index\} ||Pop the stack and adjust the value of the given indexed slot attribute by adding the popped value. Not to be used for attributes whose value is a slot reference. [Currently the only non-slot-reference indexed slot attributes are userX.]
+Not supported in version 1.0 of the font tables.
+|35 |IAttrSub |\{slotattr\} |\{index\} ||Pop the stack and adjust the value of the given indexed slot attribute by subtracting the popped value. Not to be used for attributes whose value is a slot reference. [Currently the only non-slot-reference indexed slot attributes are userX.]
+|36 |PushProcState |\{byte\} |||Not Implemented: Pushes the processor state value identifier by the argument onto the stack.
+|37 |PushVersion ||||Pushes the version of the engine onto the stack as a 32 bit number. The stack holds 32 bit values.
+|38 |PutSubs | |\{inclass-short\} |\{outclass-short\} |Equivalent to PutSubs (0x1D) but with 16-bit class identifiers.
+|39 |PutSubs2 ||||Not Implemented
+|3A |PutSubs3 ||||Not Implemented
+|3B |PutGlyph |\{outclass-short\} |||Equivalent to PutGlyph (0x1C) but with 16-bit class identifier.
+|3C |PushGlyph-Attr |\{glyphattr-short\} | ||Equivalent to PushGlyphAttr (0x29) but with 16-bit glyph attribute identifier.
+|3D |PushAttTo-GlyphAttr |\{glyphattr-short\} | ||Equivalent to PushAttToGlyphAttr (0x2C) but with 16-bit glyph attribute identifier.
+|3E |BitAnd ||||Pop the top two items off the stack, perform a bitwise AND, and push the result.
+|3F |BitOr ||||Pop the top two items off the stack, perform a bitwise OR, and push the result.
+|40 |BitNot ||||Pop the top item off the stack, perform a bitwise NOT, and push the result.
+|41 |SetBits ||||Pop the top item off the stack, clear the mask bits, set the value bits, and push the result.
+|42 |SetFeat |\{feat\} | ||Pop a value off the stack and set the given feature on referenced slot to that value. The value is clipped at the maximum permissible value for that feature.
+|=======================================================================
+
diff -Nru graphite2-1.2.4/doc/release.txt graphite2-1.3.6/doc/release.txt
--- graphite2-1.2.4/doc/release.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/doc/release.txt 2016-02-29 04:18:01.000000000 +0000
@@ -16,7 +16,9 @@
The release is done by:
-. hg archive graphite-.tgz
+. git tag -s
+. git archive -o graphite2-.tgz --prefix=graphite2-
+. git archive -o graphite2-minimal-.tgz --prefix=graphite2-/ include src LICENSE COPYING README.md
. Then push up to sf.net/projects/silgraphite and projects.palaso.org/graphiteng-dev
=== How to do a test pdebuild ===
diff -Nru graphite2-1.2.4/gr2fonttest/CMakeLists.txt graphite2-1.3.6/gr2fonttest/CMakeLists.txt
--- graphite2-1.2.4/gr2fonttest/CMakeLists.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/gr2fonttest/CMakeLists.txt 2016-02-29 04:18:01.000000000 +0000
@@ -4,8 +4,6 @@
enable_testing()
-include_directories(${PROJECT_SOURCE_DIR})
-
if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -DUNICODE)
endif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
@@ -14,18 +12,9 @@
target_link_libraries(gr2fonttest graphite2)
if (GRAPHITE2_ASAN)
- set(GRAPHITE_LINK_FLAGS "-fsanitize=address")
+ set_target_properties(gr2fonttest PROPERTIES LINK_FLAGS "-fsanitize=address")
endif (GRAPHITE2_ASAN)
-if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
- # -lgcc LINKER_LANGUAGE C
- add_definitions(-fno-rtti -fno-exceptions)
- set_target_properties(gr2fonttest PROPERTIES LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}" LINKER_LANGUAGE C)
- set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
- # This script just fails
- nolib_test(stdc++ $)
-endif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
-
# copy the DLL so that gr2fonttest can find it
add_custom_target(${PROJECT_NAME}_copy_dll ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${graphite2_core_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}graphite2${CMAKE_SHARED_LIBRARY_SUFFIX} ${PROJECT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
diff -Nru graphite2-1.2.4/gr2fonttest/gr2FontTest.cpp graphite2-1.3.6/gr2fonttest/gr2FontTest.cpp
--- graphite2-1.2.4/gr2fonttest/gr2FontTest.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/gr2fonttest/gr2FontTest.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -517,7 +517,7 @@
fprintf(log, "\t");
for (size_t j = 4; j; --j)
{
- const char c = lang_id >> (j*8-8);
+ const unsigned char c = lang_id >> (j*8-8);
if ((c >= 0x20) && (c < 0x80))
fprintf(log, "%c", c);
}
@@ -761,7 +761,7 @@
fprintf(stderr,"\nIf a font, but no text is specified, then a list of features will be shown.\n");
fprintf(stderr,"-feat f=g\tSet feature f to value g. Separate multiple features with ,\n");
fprintf(stderr,"-log out.log\tSet log file to use rather than stdout\n");
- fprintf(stderr,"-trace trace.xml\tDefine a file for the XML trace log\n");
+ fprintf(stderr,"-trace trace.json\tDefine a file for the JSON trace log\n");
fprintf(stderr,"-demand\tDemand load glyphs and cmap cache\n");
fprintf(stderr,"-cache\tEnable Segment Cache\n");
fprintf(stderr,"-bytes\tword size for character transfer [1,2,4] defaults to 4\n");
diff -Nru graphite2-1.2.4/gr2fonttest/UtfCodec.h graphite2-1.3.6/gr2fonttest/UtfCodec.h
--- graphite2-1.2.4/gr2fonttest/UtfCodec.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/gr2fonttest/UtfCodec.h 2016-02-29 04:18:01.000000000 +0000
@@ -139,9 +139,12 @@
bool toolong = false;
switch(seq_sz) {
- case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); // no break
- case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); // no break
- case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); // no break
+ case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10);
+ // no break
+ case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20);
+ // no break
+ case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80);
+ // no break
case 1: break;
case 0: l = -1; return 0xFFFD;
}
diff -Nru graphite2-1.2.4/Graphite.cmake graphite2-1.3.6/Graphite.cmake
--- graphite2-1.2.4/Graphite.cmake 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/Graphite.cmake 2016-02-29 04:18:01.000000000 +0000
@@ -25,7 +25,6 @@
FUNCTION(CREATE_LIBTOOL_FILE _target _install_DIR)
- GET_TARGET_PROPERTY(_target_location ${_target} LOCATION)
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_static_lib ${_target} STATIC_LIB "")
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_dependency_libs ${_target} LT_DEPENDENCY_LIBS "")
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_current ${_target} LT_VERSION_CURRENT 0)
@@ -35,9 +34,10 @@
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_shouldnotlink ${_target} LT_SHOULDNOTLINK no)
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_dlopen ${_target} LT_DLOPEN "")
GET_TARGET_PROPERTY_WITH_DEFAULT(_target_dlpreopen ${_target} LT_DLPREOPEN "")
- GET_FILENAME_COMPONENT(_lanamewe ${_target_location} NAME_WE)
- GET_FILENAME_COMPONENT(_soname ${_target_location} NAME)
- GET_FILENAME_COMPONENT(_soext ${_target_location} EXT)
+
+ SET(_lanamewe ${CMAKE_SHARED_LIBRARY_PREFIX}${_target})
+ SET(_soname ${_lanamewe}${CMAKE_SHARED_LIBRARY_SUFFIX})
+ SET(_soext ${CMAKE_SHARED_LIBRARY_SUFFIX})
SET(_laname ${PROJECT_BINARY_DIR}/${_lanamewe}.la)
FILE(WRITE ${_laname} "# ${_lanamewe}.la - a libtool library file\n")
FILE(APPEND ${_laname} "# Generated by CMake ${CMAKE_VERSION} (like GNU libtool)\n")
@@ -45,8 +45,8 @@
FILE(APPEND ${_laname} "# The name that we can dlopen(3).\n")
FILE(APPEND ${_laname} "dlname='${_soname}'\n\n")
FILE(APPEND ${_laname} "# Names of this library.\n")
- if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
- FILE(APPEND ${_laname} "library_names='${_lanamwe}.${_target_current}.${_target_revision}.${_target_age}.${_soext} ${_lanamewe}.${_target_current}.${_soext} ${_soname}'\n\n")
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+ FILE(APPEND ${_laname} "library_names='${_lanamewe}.${_target_current}.${_target_revision}.${_target_age}${_soext} ${_lanamewe}.${_target_current}${_soext} ${_soname}'\n\n")
else (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
FILE(APPEND ${_laname} "library_names='${_soname}.${_target_current}.${_target_revision}.${_target_age} ${_soname}.${_target_current} ${_soname}'\n\n")
endif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
@@ -100,8 +100,26 @@
if (NOT (GRAPHITE2_NSEGCACHE OR GRAPHITE2_NFILEFACE))
add_test(NAME ${TESTNAME} COMMAND $ -log ${PROJECT_BINARY_DIR}/${TESTNAME}.log ${PROJECT_SOURCE_DIR}/fonts/${FONTFILE})
set_tests_properties(${TESTNAME} PROPERTIES TIMEOUT 3)
+ if (GRAPHITE2_ASAN)
+ set_property(TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT "ASAN_SYMBOLIZER_PATH=${ASAN_SYMBOLIZER}")
+ endif (GRAPHITE2_ASAN)
add_test(NAME ${TESTNAME}Output COMMAND ${CMAKE_COMMAND} -E compare_files ${PROJECT_BINARY_DIR}/${TESTNAME}.log ${PROJECT_SOURCE_DIR}/standards/${TESTNAME}${PLATFORM_TEST_SUFFIX}.log)
set_tests_properties(${TESTNAME}Output PROPERTIES DEPENDS ${TESTNAME})
endif (NOT (GRAPHITE2_NSEGCACHE OR GRAPHITE2_NFILEFACE))
endfunction(feattest)
+function(cmptest TESTNAME FONTFILE TEXTFILE)
+ if (EXISTS ${PROJECT_SOURCE_DIR}/standards/${TESTNAME}${CMAKE_SYSTEM_NAME}.json)
+ set(PLATFORM_TEST_SUFFIX ${CMAKE_SYSTEM_NAME})
+ endif (EXISTS ${PROJECT_SOURCE_DIR}/standards/${TESTNAME}${CMAKE_SYSTEM_NAME}.json)
+ if ((NOT GRAPHITE2_NFILEFACE) AND ((NOT GRAPHITE2_ASAN) OR CMAKE_COMPILER_IS_GNUCXX))
+ add_test(NAME ${TESTNAME} COMMAND python ${PROJECT_SOURCE_DIR}/fnttxtrender --graphite_library=$ -t ${PROJECT_SOURCE_DIR}/texts/${TEXTFILE} -o ${PROJECT_BINARY_DIR}/${TESTNAME}.json -c ${PROJECT_SOURCE_DIR}/standards/${TESTNAME}${PLATFORM_TEST_SUFFIX}.json ${ARGN} ${PROJECT_SOURCE_DIR}/fonts/${FONTFILE})
+ if (GRAPHITE2_ASAN)
+ set_property(TEST ${TESTNAME} APPEND
+ PROPERTY ENVIRONMENT "ASAN_SYMBOLIZER_PATH=${ASAN_SYMBOLIZER}"
+ "LD_PRELOAD=libasan.so.1")
+ endif (GRAPHITE2_ASAN)
+ endif ((NOT GRAPHITE2_NFILEFACE) AND ((NOT GRAPHITE2_ASAN) OR CMAKE_COMPILER_IS_GNUCXX))
+endfunction(cmptest)
+
+
diff -Nru graphite2-1.2.4/.hg_archival.txt graphite2-1.3.6/.hg_archival.txt
--- graphite2-1.2.4/.hg_archival.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/.hg_archival.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-repo: 999e2033695c3bcf2f65d611737ac9008805bd58
-node: 1efd96aeade964b4d00b7b14e6158a74f0f6593e
-branch: default
-latesttag: 1.2.4
-latesttagdistance: 1
diff -Nru graphite2-1.2.4/.hgeol graphite2-1.3.6/.hgeol
--- graphite2-1.2.4/.hgeol 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/.hgeol 1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
-[patterns]
-**.c = native
-**.cfg = native
-**.cpp = native
-**.gdh = native
-**.h = native
-**.json = native
-**.log = native
-**.pdf = BIN
-**.sh = native
-**.txt = native
-**.ttf = BIN
-
-[repository]
-native=LF
diff -Nru graphite2-1.2.4/.hgignore graphite2-1.3.6/.hgignore
--- graphite2-1.2.4/.hgignore 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/.hgignore 1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-syntax:glob
-*~
-*.bak
-m4
-autom4te.cache
-config
-configure
-config.status
-config.log
-aclocal.m4
-libtool
-Makefile.in
-Makefile
-msvs9
-vs9
-nmake*
-*.o
-*.lo
-*.Plo
-*.swp
-*.la
-*.kdev4
-.cproject
-.project
-.pydevproject
-
-syntax:regexp
-\.libs/
-\.deps/
-\.externalToolBuilders
-build*/
-release/
-debug/
-dev/
diff -Nru graphite2-1.2.4/.hgtags graphite2-1.3.6/.hgtags
--- graphite2-1.2.4/.hgtags 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/.hgtags 1970-01-01 00:00:00.000000000 +0000
@@ -1,31 +0,0 @@
-c36cd69f32ac9daace9f8784063567d81328e778 base
-e0db725d6db85c49389176f2ee460366f080c023 Release 0.9
-3a92b51d7167e16c31b963924bd01964d6eb7e63 r0.9.1
-5369cdd121206c950113de37f4886152aa86cc98 0.9.2
-3ec0de96c2229e975b1452f9a92c4ab3845c0ad2 0.9.3
-50901246031365c63fb826a18a5ca52099201d93 0.9.4
-b8a64c4a89f5d742553a7cc3cfddb6b3e08e1fa0 1.0.0
-bedb05f72d56f24ca0fc333fd14eabb1ec553902 1.0.1
-bedb05f72d56f24ca0fc333fd14eabb1ec553902 1.0.1
-0000000000000000000000000000000000000000 1.0.1
-0000000000000000000000000000000000000000 1.0.1
-01df4f7cc7b0f31f8490b4246b298ac10d92675e 1.0.1
-0fa690ff089ce0bc382a553cc01c0b721fbdee5c 1.0.2
-0fa690ff089ce0bc382a553cc01c0b721fbdee5c 1.0.2
-b10bcaf1302411513a5961d1854ff8c02e5ad5e6 1.0.2
-8795e344f7964bdf8ef4607004f01b94c41e5775 1.0.3
-8795e344f7964bdf8ef4607004f01b94c41e5775 1.0.3
-0000000000000000000000000000000000000000 1.0.3
-0000000000000000000000000000000000000000 1.0.3
-f148746a0d99d2f9bc050906ce78815565a0d0b4 1.0.3
-afdc9c2e4cf341560dfcb985b66e52793d1987af 1.1.0
-afdc9c2e4cf341560dfcb985b66e52793d1987af 1.1.0
-22dfbf9cd047667eef87602eacf2ac1e84ec20d7 1.1.0
-e095cd8b635aa985c8054717761555b6d46dbdb6 1.1.1
-1ffaabe61f501b7a0b9217f4b82f21ac6a7af212 1.1.2
-d8c8ce7898a9e73a9cb11c25b9ff6a198fdf8d80 1.1.3
-fb4b0c347a953f6aa656a4e414f8e42e91c00c2b 1.2.0
-9ca2c8c1469f6107cd366e4be2035ce0dfa09b65 1.2.1
-7b0a153b4873117ff726ac8c780f7bd994845285 1.2.2
-4605b74e26f3a119753b700524c49b98e7e45639 1.2.3
-89895200933d3b0ce799b2d230dd6840106750b1 1.2.4
diff -Nru graphite2-1.2.4/include/graphite2/Font.h graphite2-1.3.6/include/graphite2/Font.h
--- graphite2-1.2.4/include/graphite2/Font.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/include/graphite2/Font.h 2016-02-29 04:18:01.000000000 +0000
@@ -29,8 +29,8 @@
#include "graphite2/Types.h"
#define GR2_VERSION_MAJOR 1
-#define GR2_VERSION_MINOR 2
-#define GR2_VERSION_BUGFIX 4
+#define GR2_VERSION_MINOR 3
+#define GR2_VERSION_BUGFIX 6
#ifdef __cplusplus
extern "C"
diff -Nru graphite2-1.2.4/include/graphite2/Segment.h graphite2-1.3.6/include/graphite2/Segment.h
--- graphite2-1.2.4/include/graphite2/Segment.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/include/graphite2/Segment.h 2016-02-29 04:18:01.000000000 +0000
@@ -120,13 +120,45 @@
/// Justification weight for this glyph (not implemented)
gr_slatJWeight,
/// Amount this slot mush shrink or stretch in design units
- gr_slatJWidth,
+ gr_slatJWidth = 29,
/// SubSegment split point
gr_slatSegSplit = gr_slatJStretch + 29,
/// User defined attribute, see subattr for user attr number
gr_slatUserDefn,
/// Bidi level
- gr_slatBidiLevel,
+ gr_slatBidiLevel = 56,
+ /// Collision flags
+ gr_slatColFlags,
+ /// Collision constraint rectangle left (bl.x)
+ gr_slatColLimitblx,
+ /// Collision constraint rectangle lower (bl.y)
+ gr_slatColLimitbly,
+ /// Collision constraint rectangle right (tr.x)
+ gr_slatColLimittrx,
+ /// Collision constraint rectangle upper (tr.y)
+ gr_slatColLimittry,
+ /// Collision shift x
+ gr_slatColShiftx,
+ /// Collision shift y
+ gr_slatColShifty,
+ /// Collision margin
+ gr_slatColMargin,
+ /// Margin cost weight
+ gr_slatColMarginWt,
+ // Additional glyph that excludes movement near this one:
+ gr_slatColExclGlyph,
+ gr_slatColExclOffx,
+ gr_slatColExclOffy,
+ // Collision sequence enforcing attributes:
+ gr_slatSeqClass,
+ gr_slatSeqProxClass,
+ gr_slatSeqOrder,
+ gr_slatSeqAboveXoff,
+ gr_slatSeqAboveWt,
+ gr_slatSeqBelowXlim,
+ gr_slatSeqBelowWt,
+ gr_slatSeqValignHt,
+ gr_slatSeqValignWt,
/// not implemented
gr_slatMax,
@@ -138,7 +170,8 @@
/// Underlying paragraph direction is RTL
gr_rtl = 1,
/// Set this to not run the bidi pass internally, even if the font asks for it.
- /// This presumes that the segment is in a single direction.
+ /// This presumes that the segment is in a single direction. Most of the time
+ /// this bit should be set unless you know you are passing full paragraphs of text.
gr_nobidi = 2,
/// Disable auto mirroring for rtl text
gr_nomirror = 4
diff -Nru graphite2-1.2.4/include/graphite2/Types.h graphite2-1.3.6/include/graphite2/Types.h
--- graphite2-1.2.4/include/graphite2/Types.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/include/graphite2/Types.h 2016-02-29 04:18:01.000000000 +0000
@@ -58,12 +58,15 @@
#endif
#endif
#define GR2_LOCAL
-#else
- #if __GNUC__ >= 4
- #define GR2_API __attribute__ ((visibility("default")))
- #define GR2_LOCAL __attribute__ ((visibility("hidden")))
+#elif __GNUC__ >= 4
+ #if defined GRAPHITE2_STATIC
+ #define GR2_API __attribute__ ((visibility("hidden")))
#else
- #define GR2_API
- #define GR2_LOCAL
+ #define GR2_API __attribute__ ((visibility("default")))
#endif
+ #define GR2_LOCAL __attribute__ ((visibility("hidden")))
+#else
+ #define GR2_API
+ #define GR2_LOCAL
#endif
+
diff -Nru graphite2-1.2.4/README.md graphite2-1.3.6/README.md
--- graphite2-1.2.4/README.md 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/README.md 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,32 @@
+# Graphite engine
+
+## What is Graphite?
+
+Graphite is a system that can be used to create “smart fonts” capable of displaying writing systems with various complex behaviors. A smart font contains not only letter shapes but also additional instructions indicating how to combine and position the letters in complex ways.
+
+Graphite was primarily developed to provide the flexibility needed for minority languages which often need to be written according to slightly different rules than well-known languages that use the same script.
+
+Examples of complex script behaviors Graphite can handle include:
+
+* contextual shaping
+* ligatures
+* reordering
+* split glyphs
+* bidirectionality
+* stacking diacritics
+* complex positioning
+* shape aware kerning
+* automatic diacritic collision avoidance
+
+See [examples of scripts with complex rendering](http://scripts.sil.org/CmplxRndExamples).
+
+## Graphite system overview
+The Graphite system consists of:
+
+* A rule-based programming language [Graphite Description Language](http://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_devFont#gdl) (GDL) that can be used to describe the behavior of a writing system
+* A compiler for that language
+* A rendering engine that can serve as the layout component of a text-processing application
+
+Graphite renders TrueType fonts that have been extended by means of compiling a GDL program.
+
+Further technical information is available on the [Graphite technical overview](http://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_techAbout) page.
diff -Nru graphite2-1.2.4/src/Bidi.cpp graphite2-1.3.6/src/Bidi.cpp
--- graphite2-1.2.4/src/Bidi.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/Bidi.cpp 1970-01-01 00:00:00.000000000 +0000
@@ -1,823 +0,0 @@
-/* GRAPHITE2 LICENSING
-
- Copyright 2011, SIL International
- All rights reserved.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should also have received a copy of the GNU Lesser General Public
- License along with this library in the file named "LICENSE".
- If not, write to the Free Software Foundation, 51 Franklin Street,
- suite 500, Boston, MA 02110-1335, USA or visit their web page on the
- internet at http://www.fsf.org/licenses/lgpl.html.
-
-Alternatively, the contents of this file may be used under the terms of the
-Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-License, as published by the Free Software Foundation, either version 2
-of the License or (at your option) any later version.
-*/
-#include "inc/Main.h"
-#include "inc/Slot.h"
-#include "inc/Segment.h"
-#include "inc/Bidi.h"
-
-using namespace graphite2;
-
-enum DirCode { // Hungarian: dirc
- Unk = -1,
- N = 0, // other neutrals (default) - ON
- L = 1, // left-to-right, strong - L
- R = 2, // right-to-left, strong - R
- AL = 3, // Arabic letter, right-to-left, strong, AR
- EN = 4, // European number, left-to-right, weak - EN
- EUS = 5, // European separator, left-to-right, weak - ES
- ET = 6, // European number terminator, left-to-right, weak - ET
- AN = 7, // Arabic number, left-to-right, weak - AN
- CUS = 8, // Common number separator, left-to-right, weak - CS
- WS = 9, // white space, neutral - WS
- BN = 10, // boundary neutral - BN
-
- LRO = 11, // LTR override
- RLO = 12, // RTL override
- LRE = 13, // LTR embedding
- RLE = 14, // RTL embedding
- PDF = 15, // pop directional format
- NSM = 16, // non-space mark
- LRI = 17, // LRI isolate
- RLI = 18, // RLI isolate
- FSI = 19, // FSI isolate
- PDI = 20, // pop isolate
- OPP = 21, // opening paired parenthesis
- CPP = 22, // closing paired parenthesis
-
- ON = N
-};
-
-enum DirMask {
- WSflag = (1 << 7), // keep track of WS for eos handling
- WSMask = ~(1 << 7)
-};
-
-inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; }
-
-unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 };
-// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
-
-void resolveWeak(Slot *start, int sos, int eos);
-void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos);
-void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack);
-
-inline int calc_base_level(Slot *s)
-{
- int count = 0;
- for ( ; s; s = s->next())
- {
- int cls = s->getBidiClass();
- if (count)
- {
- switch(cls)
- {
- case LRI :
- case RLI :
- case FSI :
- ++count;
- break;
- case PDI :
- --count;
- }
- }
- else
- {
- switch(cls)
- {
- case L :
- return 0;
- case R :
- case AL :
- return 1;
- case LRI :
- case RLI :
- case FSI :
- ++count;
- }
- }
- }
- return 0;
-}
-
-// inline or not?
-void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack)
-{
- if (bmask & 0x1F1178)
- resolveWeak(start, sos, eos);
- if (bmask & 0x200000)
- processParens(start, seg, aMirror, level, stack);
- if (bmask & 0x7E0361)
- resolveNeutrals(start, level, sos, eos);
- bmask = 0;
-}
-
-enum maxs
-{
- MAX_LEVEL = 125,
-};
-
-// returns where we are up to in processing
-Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &bstack)
-{
- int bmask = 0;
- Slot *s = start;
- Slot *slast = start;
- Slot *scurr = 0;
- Slot *stemp;
- int lnextLevel = nextLevel;
- int newLevel;
- int empty = 1;
- for ( ; s; s = s ? s->next() : s)
- {
- int cls = s->getBidiClass();
- bmask |= (1 << cls);
- s->setBidiLevel(level);
- // we keep s->prev() pointing backwards for PDI repeating
-
- switch (cls)
- {
- case BN :
- if (slast == s) slast = s->next(); // ignore if at front of text
- continue;
- case LRE :
- case LRO :
- case RLE :
- case RLO :
- switch (cls)
- {
- case LRE :
- case LRO :
- newLevel = level + (level & 1 ? 1 : 2);
- break;
- case RLE :
- case RLO :
- newLevel = level + (level & 1 ? 2 : 1);
- break;
- }
- s->setBidiClass(BN);
- if (isolerr || newLevel > MAX_LEVEL || embederr)
- {
- if (!isolerr) ++embederr;
- break;
- }
- stemp = scurr;
- if (scurr)
- scurr->prev(0); // don't include control in string
- lnextLevel = newLevel;
- scurr = s;
- s->setBidiLevel(newLevel); // to make it vanish
- // recurse for the new subsequence. A sequence only contains text at the same level
- s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
- // s points at PDF or end of sequence
- // try to keep extending the run and not process it until we have to
- if (lnextLevel != level || !s) // if the subsequence really had something in it, or we are at the end of the run
- {
- if (slast != scurr) // process the run now, don't try to extend it
- {
- // process text preceeding embedding
- do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
- empty = 0;
- nextLevel = level;
- }
- else if (lnextLevel != level) // the subsequence had something
- {
- empty = 0; // so we aren't empty either
- nextLevel = lnextLevel; // but since we really are empty, pass back our level from the subsequence
- }
- if (s) // if still more to process
- {
- prelevel = lnextLevel; // future text starts out with sos of the higher subsequence
- lnextLevel = level; // and eos is our level
- }
- slast = s ? s->next() : s;
- }
- else if (stemp)
- stemp->prev(s);
- break;
-
- case PDF :
- s->setBidiClass(BN);
- s->prev(0); // unstitch us since we skip final stitching code when we return
- if (isol || isolerr || init) // boundary error conditions
- break;
- if (embederr)
- {
- --embederr;
- break;
- }
- if (slast != s)
- {
- scurr->prev(0); // if slast, then scurr. Terminate before here
- do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack);
- empty = 0;
- }
- if (empty)
- {
- nextLevel = prelevel; // no contents? set our level to that of parent
- s->setBidiLevel(prelevel);
- }
- return s;
-
- case FSI :
- case LRI :
- case RLI :
- switch (cls)
- {
- case FSI :
- if (calc_base_level(s->next()))
- newLevel = level + (level & 1 ? 2 : 1);
- else
- newLevel = level + (level & 1 ? 1 : 2);
- break;
- case LRI :
- newLevel = level + (level & 1 ? 1 : 2);
- break;
- case RLI :
- newLevel = level + (level & 1 ? 2 : 1);
- break;
- }
- if (newLevel > MAX_LEVEL || isolerr)
- {
- ++isolerr;
- s->setBidiClass(ON | WSflag);
- break;
- }
- ++cisol;
- if (scurr) scurr->prev(s);
- scurr = s; // include FSI
- lnextLevel = newLevel;
- // recurse for the new sub sequence
- s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
- // s points at PDI
- if (s)
- {
- bmask |= 1 << BaseClass(s); // include the PDI in the mask
- s->setBidiLevel(level); // reset its level to our level
- }
- lnextLevel = level;
- break;
-
- case PDI :
- if (isolerr)
- {
- --isolerr;
- s->setBidiClass(ON | WSflag);
- break;
- }
- if (init || !cisol)
- {
- s->setBidiClass(ON | WSflag);
- break;
- }
- embederr = 0;
- if (!isol) // we are in an embedded subsequence, we have to return through all those
- {
- if (empty) // if empty, reset the level to tell embedded parent
- nextLevel = prelevel;
- return s->prev(); // keep working up the stack pointing at this PDI until we get to an isolate entry
- }
- else // we are terminating an isolate sequence
- {
- if (slast != s) // process any remaining content in this subseqence
- {
- scurr->prev(0);
- do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack);
- }
- --cisol; // pop the isol sequence from the stack
- return s;
- }
-
- default :
- if (dirover)
- s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS)));
- }
- if (s) s->prev(0); // unstitch us
- if (scurr) // stitch in text for processing
- scurr->prev(s);
- scurr = s; // add us to text to process
- }
- if (slast != s)
- {
- do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
- empty = 0;
- }
- if (empty || isol)
- nextLevel = prelevel;
- return s;
-}
-
-// === RESOLVE WEAK TYPES ================================================
-
-enum bidi_state // possible states
-{
- xa, // arabic letter
- xr, // right leter
- xl, // left letter
-
- ao, // arabic lett. foll by ON
- ro, // right lett. foll by ON
- lo, // left lett. foll by ON
-
- rt, // ET following R
- lt, // ET following L
-
- cn, // EN, AN following AL
- ra, // arabic number foll R
- re, // european number foll R
- la, // arabic number foll L
- le, // european number foll L
-
- ac, // CS following cn
- rc, // CS following ra
- rs, // CS,ES following re
- lc, // CS following la
- ls, // CS,ES following le
-
- ret, // ET following re
- let, // ET following le
-} ;
-
-const bidi_state stateWeak[][10] =
-{
- // N, L, R, AN, EN, AL,NSM, CS, ES, ET,
-{ /*xa*/ ao, xl, xr, cn, cn, xa, xa, ao, ao, ao, /* arabic letter */ },
-{ /*xr*/ ro, xl, xr, ra, re, xa, xr, ro, ro, rt, /* right letter */ },
-{ /*xl*/ lo, xl, xr, la, le, xa, xl, lo, lo, lt, /* left letter */ },
-
-{ /*ao*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* arabic lett. foll by ON*/ },
-{ /*ro*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* right lett. foll by ON */ },
-{ /*lo*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* left lett. foll by ON */ },
-
-{ /*rt*/ ro, xl, xr, ra, re, xa, rt, ro, ro, rt, /* ET following R */ },
-{ /*lt*/ lo, xl, xr, la, le, xa, lt, lo, lo, lt, /* ET following L */ },
-
-{ /*cn*/ ao, xl, xr, cn, cn, xa, cn, ac, ao, ao, /* EN, AN following AL */ },
-{ /*ra*/ ro, xl, xr, ra, re, xa, ra, rc, ro, rt, /* arabic number foll R */ },
-{ /*re*/ ro, xl, xr, ra, re, xa, re, rs, rs,ret, /* european number foll R */ },
-{ /*la*/ lo, xl, xr, la, le, xa, la, lc, lo, lt, /* arabic number foll L */ },
-{ /*le*/ lo, xl, xr, la, le, xa, le, ls, ls,let, /* european number foll L */ },
-
-{ /*ac*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* CS following cn */ },
-{ /*rc*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS following ra */ },
-{ /*rs*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS,ES following re */ },
-{ /*lc*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la */ },
-{ /*ls*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le */ },
-
-{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ },
-{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ },
-
-
-};
-
-enum bidi_action // possible actions
-{
- // primitives
- IX = 0x100, // increment
- XX = 0xF, // no-op
-
- // actions
- xxx = (XX << 4) + XX, // no-op
- xIx = IX + xxx, // increment run
- xxN = (XX << 4) + ON, // set current to N
- xxE = (XX << 4) + EN, // set current to EN
- xxA = (XX << 4) + AN, // set current to AN
- xxR = (XX << 4) + R, // set current to R
- xxL = (XX << 4) + L, // set current to L
- Nxx = (ON << 4) + 0xF, // set run to neutral
- Axx = (AN << 4) + 0xF, // set run to AN
- ExE = (EN << 4) + EN, // set run to EN, set current to EN
- NIx = (ON << 4) + 0xF + IX, // set run to N, increment
- NxN = (ON << 4) + ON, // set run to N, set current to N
- NxR = (ON << 4) + R, // set run to N, set current to R
- NxE = (ON << 4) + EN, // set run to N, set current to EN
-
- AxA = (AN << 4) + AN, // set run to AN, set current to AN
- NxL = (ON << 4) + L, // set run to N, set current to L
- LxL = (L << 4) + L, // set run to L, set current to L
-};
-
-
-const bidi_action actionWeak[][10] =
-{
- // N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET,
-{ /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter */ },
-{ /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter */ },
-{ /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter */ },
-
-{ /*ao*/ xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN, /* arabic lett. foll by ON */ },
-{ /*ro*/ xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx, /* right lett. foll by ON */ },
-{ /*lo*/ xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx, /* left lett. foll by ON */ },
-
-{ /*rt*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx, /* ET following R */ },
-{ /*lt*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx, /* ET following L */ },
-
-{ /*cn*/ xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN, /* EN, AN following AL */ },
-{ /*ra*/ xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx, /* arabic number foll R */ },
-{ /*re*/ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE, /* european number foll R */ },
-{ /*la*/ xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx, /* arabic number foll L */ },
-{ /*le*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL, /* european number foll L */ },
-
-{ /*ac*/ Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN, /* CS following cn */ },
-{ /*rc*/ Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx, /* CS following ra */ },
-{ /*rs*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx, /* CS,ES following re */ },
-{ /*lc*/ Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx, /* CS following la */ },
-{ /*ls*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx, /* CS,ES following le */ },
-
-{ /*ret*/xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE, /* ET following re */ },
-{ /*let*/xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL, /* ET following le */ },
-};
-
-inline uint8 GetDeferredType(bidi_action a) { return (a >> 4) & 0xF; }
-inline uint8 GetResolvedType(bidi_action a) { return a & 0xF; }
-inline DirCode EmbeddingDirection(int l) { return l & 1 ? R : L; }
-
-// Neutrals
-enum neutral_action
-{
- // action to resolve previous input
- nL = L, // resolve EN to L
- En = 3 << 4, // resolve neutrals run to embedding level direction
- Rn = R << 4, // resolve neutrals run to strong right
- Ln = L << 4, // resolved neutrals run to strong left
- In = (1<<8), // increment count of deferred neutrals
- LnL = (1<<4)+L, // set run and EN to L
-};
-
-// ->prev() here means ->next()
-void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
-{
- if (!sRun || s == sRun) return;
- for (Slot *p = sRun; p != s; p = p->prev())
- if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
- else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
-}
-
-void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval)
-{
- if (!sRun) return;
- for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev())
- if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
- else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
-}
-
-void resolveWeak(Slot *start, int sos, int eos)
-{
- int state = (sos & 1) ? xr : xl;
- int cls;
- Slot *s = start;
- Slot *sRun = NULL;
- Slot *sLast = s;
-
- for ( ; s; s = s->prev())
- {
- sLast = s;
- cls = BaseClass(s);
- switch (cls)
- {
- case BN :
- if (s == start) start = s->prev(); // skip initial BNs for NSM resolving
- continue;
- case LRI :
- case RLI :
- case FSI :
- case PDI :
- {
- Slot *snext = s->prev();
- if (snext && snext->getBidiClass() == NSM)
- snext->setBidiClass(ON);
- s->setBidiClass(ON | WSflag);
- }
- break;
-
- case NSM :
- if (s == start)
- {
- cls = EmbeddingDirection(sos);
- s->setBidiClass(cls);
- }
- break;
- }
-
- bidi_action action = actionWeak[state][bidi_class_map[cls]];
- int clsRun = GetDeferredType(action);
- if (clsRun != XX)
- {
- SetDeferredRunClass(s, sRun, clsRun);
- sRun = NULL;
- }
- int clsNew = GetResolvedType(action);
- if (clsNew != XX)
- s->setBidiClass(clsNew);
- if (!sRun && (IX & action))
- sRun = s;
- state = stateWeak[state][bidi_class_map[cls]];
- }
-
- cls = EmbeddingDirection(eos);
- int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
- if (clsRun != XX)
- SetThisDeferredRunClass(sLast, sRun, clsRun);
-}
-
-void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack)
-{
- uint8 mask = 0;
- int8 lastDir = -1;
- BracketPair *p;
- for ( ; s; s = s->prev()) // walk the sequence
- {
- uint16 ogid = seg->glyphAttr(s->gid(), aMirror);
- int cls = BaseClass(s);
-
- switch(cls)
- {
- case OPP :
- stack.orin(mask);
- stack.push(ogid, s, lastDir, lastDir != CPP);
- mask = 0;
- lastDir = OPP;
- break;
- case CPP :
- stack.orin(mask);
- p = stack.scan(s->gid());
- if (!p) break;
- mask = 0;
- stack.close(p, s);
- lastDir = CPP;
- break;
- case L :
- lastDir = L;
- mask |= 1;
- break;
- case R :
- case AL :
- case AN :
- case EN :
- lastDir = R;
- mask |= 2;
- }
- }
- for (p = stack.start(); p; p =p->next()) // walk the stack
- {
- if (p->close() && p->mask())
- {
- int dir = (level & 1) + 1;
- if (p->mask() & dir)
- { }
- else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
- {
- int ldir = p->before();
- if ((p->before() == OPP || p->before() == CPP) && p->prev())
- {
- for (BracketPair *q = p->prev(); q; q = q->prev())
- {
- ldir = q->open()->getBidiClass();
- if (ldir < 3) break;
- ldir = q->before();
- if (ldir < 3) break;
- }
- if (ldir > 2) ldir = 0;
- }
- if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
- dir = (~level & 1) + 1;
- }
- p->open()->setBidiClass(dir);
- p->close()->setBidiClass(dir);
- }
- }
- stack.clear();
-}
-
-int GetDeferredNeutrals(int action, int level)
-{
- action = (action >> 4) & 0xF;
- if (action == (En >> 4))
- return EmbeddingDirection(level);
- else
- return action;
-}
-
-int GetResolvedNeutrals(int action)
-{
- return action & 0xF;
-}
-
-// state values
-enum neutral_state
-{
- // new temporary class
- r, // R and characters resolved to R
- l, // L and characters resolved to L
- rn, // N preceded by right
- ln, // N preceded by left
- a, // AN preceded by left (the abbrev 'la' is used up above)
- na, // N preceeded by a
-} ;
-
-const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-const int actionNeutrals[][5] =
-{
-// cls= N, L, R, AN, EN, state =
-{ In, 0, 0, 0, 0, }, // r right
-{ In, 0, 0, 0, L, }, // l left
-
-{ In, En, Rn, Rn, Rn, }, // rn N preceded by right
-{ In, Ln, En, En, LnL, }, // ln N preceded by left
-
-{ In, 0, 0, 0, L, }, // a AN preceded by left
-{ In, En, Rn, Rn, En, }, // na N preceded by a
-} ;
-
-const int stateNeutrals[][5] =
-{
-// cls= N, L, R, AN, EN state =
-{ rn, l, r, r, r, }, // r right
-{ ln, l, r, a, l, }, // l left
-
-{ rn, l, r, r, r, }, // rn N preceded by right
-{ ln, l, r, a, l, }, // ln N preceded by left
-
-{ na, l, r, a, l, }, // a AN preceded by left
-{ na, l, r, a, l, }, // na N preceded by la
-} ;
-
-void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos)
-{
- int state = (sos & 1) ? r : l;
- int cls;
- Slot *sRun = NULL;
- Slot *sLast = s;
- int level = baseLevel;
-
- for ( ; s; s = s->prev())
- {
- sLast = s;
- cls = BaseClass(s);
- switch (cls)
- {
- case BN :
- continue;
- case LRI :
- case RLI :
- case FSI :
- s->setBidiClass(BN | WSflag);
- continue;
-
- default :
- int action = actionNeutrals[state][neutral_class_map[cls]];
- int clsRun = GetDeferredNeutrals(action, level);
- if (clsRun != N)
- {
- SetDeferredRunClass(s, sRun, clsRun);
- sRun = NULL;
- }
- int clsNew = GetResolvedNeutrals(action);
- if (clsNew != N)
- s->setBidiClass(clsNew);
- if (!sRun && (action & In))
- sRun = s;
- state = stateNeutrals[state][neutral_class_map[cls]];
- }
- }
- cls = EmbeddingDirection(eos);
- int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level);
- if (clsRun != N)
- SetThisDeferredRunClass(sLast, sRun, clsRun);
-}
-
-const int addLevel[][4] =
-{
- // cls = L, R, AN, EN level =
-/* even */ { 0, 1, 2, 2, }, // EVEN
-/* odd */ { 1, 0, 1, 1, }, // ODD
-
-};
-
-void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror)
-{
- bool rtl = seg->dir() & 1;
- int level = rtl;
- Slot *slast = 0;
- for ( ; s; s = s->next())
- {
- int cls = BaseClass(s);
- s->prev(slast); // restitch the prev() side of the doubly linked list
- slast = s;
- if (cls == AN)
- cls = AL; // use AL value as the index for AN, no property change
- if (cls < 5 && cls > 0)
- {
- level = s->getBidiLevel();
- level += addLevel[level & 1][cls - 1];
- s->setBidiLevel(level);
- }
- if (aMirror)
- {
- int hasChar = seg->glyphAttr(s->gid(), aMirror + 1);
- if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar))
- || ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) )
- {
- unsigned short g = seg->glyphAttr(s->gid(), aMirror);
- if (g) s->setGlyph(seg, g);
- }
- }
- }
-}
-
-void resolveWhitespace(int baseLevel, Slot *s)
-{
- for ( ; s; s = s->prev())
- {
- int8 cls = s->getBidiClass();
- if (cls == WS || cls & WSflag)
- s->setBidiLevel(baseLevel);
- else if (cls != BN)
- break;
- }
-}
-
-
-/*
-Stitch two spans together to make another span (with ends tied together).
-If the level is odd then swap the order of the two spans
-*/
-inline
-Slot * join(int level, Slot * a, Slot * b)
-{
- if (!a) return b;
- if (level & 1) { Slot * const t = a; a = b; b = t; }
- Slot * const t = b->prev();
- a->prev()->next(b); b->prev(a->prev()); // splice middle
- t->next(a); a->prev(t); // splice ends
- return a;
-}
-
-/*
-Given the first slot in a run of slots with the same bidi level, turn the run
-into it's own little doubly linked list ring (a span) with the two ends joined together.
-If the run is rtl then reverse its direction.
-Returns the first slot after the span
-*/
-Slot * span(Slot * & cs, const bool rtl)
-{
- Slot * r = cs, * re = cs; cs = cs->next();
- if (rtl)
- {
- Slot * t = r->next(); r->next(r->prev()); r->prev(t);
- for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->prev())
- {
- re = cs;
- t = cs->next(); cs->next(cs->prev()); cs->prev(t);
- }
- r->next(re);
- re->prev(r);
- r = re;
- }
- else
- {
- for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->next())
- re = cs;
- r->prev(re);
- re->next(r);
- }
- if (cs) cs->prev(0);
- return r;
-}
-
-inline int getlevel(const Slot *cs, const int level)
-{
- while (cs && cs->getBidiClass() == BN)
- { cs = cs->next(); }
- if (cs)
- return cs->getBidiLevel();
- else
- return level;
-}
-
-Slot *resolveOrder(Slot * & cs, const bool reordered, const int level)
-{
- Slot * r = 0;
- int ls;
- while (cs && level <= (ls = getlevel(cs, level) - reordered))
- {
- r = join(level, r, level < ls
- ? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level
- : span(/* updates */cs, level & 1));
- }
- return r;
-}
diff -Nru graphite2-1.2.4/src/call_machine.cpp graphite2-1.3.6/src/call_machine.cpp
--- graphite2-1.2.4/src/call_machine.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/call_machine.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -70,7 +70,9 @@
SlotMap & smap;
slotref * const map_base;
const instr * & ip;
+ uint8 direction;
int8 flags;
+ Machine::status_t & status;
};
typedef bool (* ip_t)(registers);
@@ -86,6 +88,8 @@
#define map reg.map
#define mapb reg.map_base
#define flags reg.flags
+#define dir reg.direction
+#define status reg.status
#include "inc/opcodes.h"
@@ -96,6 +100,7 @@
#undef map
#undef mapb
#undef flags
+#undef dir
}
Machine::stack_t Machine::run(const instr * program,
@@ -110,7 +115,7 @@
const byte * dp = data;
stack_t * sp = _stack + Machine::STACK_GUARD,
* const sb = sp;
- regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, 0};
+ regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0, _status};
// Run the program
while ((reinterpret_cast(*++ip))(dp, sp, sb, reg)) {}
diff -Nru graphite2-1.2.4/src/CMakeLists.txt graphite2-1.3.6/src/CMakeLists.txt
--- graphite2-1.2.4/src/CMakeLists.txt 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/CMakeLists.txt 2016-02-29 04:18:01.000000000 +0000
@@ -74,19 +74,21 @@
gr_logging.cpp
gr_segment.cpp
gr_slot.cpp
- Bidi.cpp
CachedFace.cpp
CmapCache.cpp
Code.cpp
+ Collider.cpp
+ Decompressor.cpp
Face.cpp
FeatureMap.cpp
Font.cpp
GlyphFace.cpp
GlyphCache.cpp
+ Intervals.cpp
Justifier.cpp
NameTable.cpp
Pass.cpp
- Rule.cpp
+ Position.cpp
Segment.cpp
Silf.cpp
Slot.cpp
@@ -104,17 +106,18 @@
LT_VERSION_REVISION ${GRAPHITE_API_REVISION}
LT_VERSION_AGE ${GRAPHITE_API_AGE})
-if (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
- set(GRAPHITE_LINK_FLAGS "-fsanitize=address")
-else (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
- set(GRAPHITE_LINK_FLAGS "")
-endif (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
-
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set_target_properties(graphite2 PROPERTIES
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}"
LINKER_LANGUAGE C)
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ add_definitions(-Wdouble-promotion)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+ message(STATUS "Compiler ID is: ${CMAKE_CXX_COMPILER_ID}")
+ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
+ add_definitions(-Wimplicit-fallthrough)
+ endif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32)
else (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
@@ -132,7 +135,7 @@
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set_target_properties(graphite2 PROPERTIES
- COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
+ COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wimplicit-fallthrough -Wendif-labels -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
LINK_FLAGS "-nodefaultlibs"
LINKER_LANGUAGE C)
target_link_libraries(graphite2 c)
diff -Nru graphite2-1.2.4/src/CmapCache.cpp graphite2-1.3.6/src/CmapCache.cpp
--- graphite2-1.2.4/src/CmapCache.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/CmapCache.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -38,11 +38,11 @@
{
const void * stbl;
if (!cmap.size()) return 0;
- if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()))
- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()))
- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()))
- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()))
- || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size())))
+ if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size())
+ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size())
+ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size())
+ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size())
+ || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size()))
return stbl;
return 0;
}
@@ -51,8 +51,8 @@
{
const void * stbl;
if (!cmap.size()) return 0;
- if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()))
- || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size())))
+ if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size())
+ || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size()))
return stbl;
return 0;
}
@@ -64,7 +64,7 @@
int rangeKey = 0;
uint32 codePoint = NextCodePoint(cst, 0, &rangeKey),
prevCodePoint = 0;
- while (codePoint != limit)
+ while (codePoint < limit)
{
unsigned int block = codePoint >> 8;
if (!blocks[block])
diff -Nru graphite2-1.2.4/src/Code.cpp graphite2-1.3.6/src/Code.cpp
--- graphite2-1.2.4/src/Code.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/Code.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -84,17 +84,19 @@
struct limits;
struct analysis
{
+ static const int NUMCONTEXTS = 256;
uint8 slotref;
- context contexts[256];
+ context contexts[NUMCONTEXTS];
byte max_ref;
analysis() : slotref(0), max_ref(0) {};
- void set_ref(int index) throw();
+ void set_ref(int index, bool incinsert=false) throw();
+ void set_noref(int index) throw();
void set_changed(int index) throw();
};
- decoder(const limits & lims, Code &code) throw();
+ decoder(limits & lims, Code &code, enum passtype pt) throw();
bool load(const byte * bc_begin, const byte * bc_end);
void apply_analysis(instr * const code, instr * code_end);
@@ -107,6 +109,7 @@
bool emit_opcode(opcode opc, const byte * & bc);
bool validate_opcode(const opcode opc, const byte * const bc);
bool valid_upto(const uint16 limit, const uint16 x) const throw();
+ bool test_context() const throw();
void failure(const status_t s) const throw() { _code.failure(s); }
Code & _code;
@@ -114,14 +117,17 @@
uint16 _rule_length;
instr * _instr;
byte * _data;
- const limits & _max;
+ limits & _max;
analysis _analysis;
+ enum passtype _passtype;
+ int _stack_depth;
+ bool _in_ctxt_item;
};
struct Machine::Code::decoder::limits
{
- const byte * const bytecode;
+ const byte * bytecode;
const uint8 pre_context;
const uint16 rule_length,
classes,
@@ -130,19 +136,22 @@
const byte attrid[gr_slatMax];
};
-inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
+inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
: _code(code),
_pre_context(code._constraint ? 0 : lims.pre_context),
_rule_length(code._constraint ? 1 : lims.rule_length),
- _instr(code._code), _data(code._data), _max(lims)
+ _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
+ _stack_depth(0),
+ _in_ctxt_item(false)
{ }
Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
- uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
+ uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
+ enum passtype pt, byte * * const _out)
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
- _constraint(is_constraint), _modify(false), _delete(false), _own(true)
+ _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
{
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _code_cat(face.tele.code);
@@ -150,25 +159,24 @@
assert(bytecode_begin != 0);
if (bytecode_begin == bytecode_end)
{
- ::new (this) Code();
+ // ::new (this) Code();
return;
}
assert(bytecode_end > bytecode_begin);
const opcode_t * op_to_fn = Machine::getOpcodeTable();
- // Allocate code and dat target buffers, these sizes are a worst case
+ // Allocate code and data target buffers, these sizes are a worst case
// estimate. Once we know their real sizes the we'll shrink them.
- _code = static_cast(malloc((bytecode_end - bytecode_begin)
- * sizeof(instr)));
- _data = static_cast(malloc((bytecode_end - bytecode_begin)
- * sizeof(byte)));
+ if (_out) _code = reinterpret_cast(*_out);
+ else _code = static_cast(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
+ _data = reinterpret_cast(_code + (bytecode_end - bytecode_begin));
if (!_code || !_data) {
failure(alloc_failed);
return;
}
- const decoder::limits lims = {
+ decoder::limits lims = {
bytecode_end,
pre_context,
rule_length,
@@ -184,7 +192,7 @@
0,0,0,0,0,0,0, silf.numUser()}
};
- decoder dec(lims, *this);
+ decoder dec(lims, *this, pt);
if(!dec.load(bytecode_begin, bytecode_end))
return;
@@ -209,10 +217,15 @@
// Now we know exactly how much code and data the program really needs
// realloc the buffers to exactly the right size so we don't waste any
// memory.
- assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_instr_count));
- assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size));
- _code = static_cast(realloc(_code, (_instr_count+1)*sizeof(instr)));
- _data = static_cast(realloc(_data, _data_size*sizeof(byte)));
+ assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
+ assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
+ memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
+ size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
+ if (_out)
+ *_out += total_sz;
+ else
+ _code = static_cast(realloc(_code, total_sz));
+ _data = reinterpret_cast(_code + (_instr_count+1));
if (!_code)
{
@@ -237,6 +250,7 @@
bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
{
+ _max.bytecode = bc_end;
while (bc < bc_end)
{
const opcode opc = fetch_opcode(bc++);
@@ -266,98 +280,142 @@
switch (opc)
{
case NOP :
+ break;
case PUSH_BYTE :
case PUSH_BYTEU :
case PUSH_SHORT :
case PUSH_SHORTU :
case PUSH_LONG :
+ ++_stack_depth;
+ break;
case ADD :
case SUB :
case MUL :
case DIV :
case MIN_ :
case MAX_ :
- case NEG :
- case TRUNC8 :
- case TRUNC16 :
- case COND :
case AND :
case OR :
- case NOT :
case EQUAL :
case NOT_EQ :
case LESS :
case GTR :
case LESS_EQ :
case GTR_EQ :
+ case BITOR :
+ case BITAND :
+ if (--_stack_depth <= 0)
+ failure(underfull_stack);
+ break;
+ case NEG :
+ case TRUNC8 :
+ case TRUNC16 :
+ case NOT :
+ case BITNOT :
+ case BITSET :
+ if (_stack_depth <= 0)
+ failure(underfull_stack);
+ break;
+ case COND :
+ _stack_depth -= 2;
+ if (_stack_depth <= 0)
+ failure(underfull_stack);
break;
case NEXT :
case NEXT_N : // runtime checked
case COPY_NEXT :
+ test_context();
++_pre_context;
break;
case PUT_GLYPH_8BIT_OBS :
valid_upto(_max.classes, bc[0]);
+ test_context();
break;
case PUT_SUBS_8BIT_OBS :
valid_upto(_rule_length, _pre_context + int8(bc[0]));
valid_upto(_max.classes, bc[1]);
valid_upto(_max.classes, bc[2]);
+ test_context();
break;
case PUT_COPY :
valid_upto(_rule_length, _pre_context + int8(bc[0]));
+ test_context();
break;
case INSERT :
- --_pre_context;
+ if (_passtype >= PASS_TYPE_POSITIONING)
+ failure(invalid_opcode);
+ else
+ --_pre_context;
break;
case DELETE :
+ if (_passtype >= PASS_TYPE_POSITIONING)
+ failure(invalid_opcode);
+ test_context();
break;
case ASSOC :
for (uint8 num = bc[0]; num; --num)
valid_upto(_rule_length, _pre_context + int8(bc[num]));
+ test_context();
break;
case CNTXT_ITEM :
valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
- if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
- if (_pre_context != 0) failure(nested_context_item);
+ if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
+ if (_in_ctxt_item) failure(nested_context_item);
break;
case ATTR_SET :
case ATTR_ADD :
case ATTR_SUB :
case ATTR_SET_SLOT :
+ if (--_stack_depth < 0)
+ failure(underfull_stack);
valid_upto(gr_slatMax, bc[0]);
+ if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
+ failure(out_of_range_data);
+ test_context();
break;
case IATTR_SET_SLOT :
+ if (--_stack_depth < 0)
+ failure(underfull_stack);
if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
+ test_context();
break;
case PUSH_SLOT_ATTR :
+ ++_stack_depth;
valid_upto(gr_slatMax, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
+ if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
+ failure(out_of_range_data);
break;
case PUSH_GLYPH_ATTR_OBS :
+ ++_stack_depth;
valid_upto(_max.glyf_attrs, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
break;
case PUSH_GLYPH_METRIC :
+ ++_stack_depth;
valid_upto(kgmetDescent, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
// level: dp[2] no check necessary
break;
case PUSH_FEAT :
+ ++_stack_depth;
valid_upto(_max.features, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
break;
case PUSH_ATT_TO_GATTR_OBS :
+ ++_stack_depth;
valid_upto(_max.glyf_attrs, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
break;
case PUSH_ATT_TO_GLYPH_METRIC :
+ ++_stack_depth;
valid_upto(kgmetDescent, bc[0]);
valid_upto(_rule_length, _pre_context + int8(bc[1]));
// level: dp[2] no check necessary
break;
case PUSH_ISLOT_ATTR :
+ ++_stack_depth;
if (valid_upto(gr_slatMax, bc[0]))
{
valid_upto(_rule_length, _pre_context + int8(bc[1]));
@@ -365,32 +423,45 @@
}
break;
case PUSH_IGLYPH_ATTR :// not implemented
+ ++_stack_depth;
+ break;
case POP_RET :
+ if (--_stack_depth < 0)
+ failure(underfull_stack);
+ GR_FALLTHROUGH;
+ // no break
case RET_ZERO :
case RET_TRUE :
break;
case IATTR_SET :
case IATTR_ADD :
case IATTR_SUB :
+ if (--_stack_depth < 0)
+ failure(underfull_stack);
if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
+ test_context();
break;
case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
case PUSH_VERSION :
+ ++_stack_depth;
break;
case PUT_SUBS :
valid_upto(_rule_length, _pre_context + int8(bc[0]));
valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
+ test_context();
break;
case PUT_SUBS2 : // not implemented
case PUT_SUBS3 : // not implemented
break;
case PUT_GLYPH :
valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
+ test_context();
break;
case PUSH_GLYPH_ATTR :
case PUSH_ATT_TO_GLYPH_ATTR :
+ ++_stack_depth;
valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
valid_upto(_rule_length, _pre_context + int8(bc[2]));
break;
@@ -415,14 +486,23 @@
case PUT_GLYPH_8BIT_OBS :
case PUT_GLYPH :
_code._modify = true;
- _analysis.set_changed(_analysis.slotref);
+ _analysis.set_changed(0);
+ break;
+ case ATTR_SET :
+ case ATTR_ADD :
+ case ATTR_SET_SLOT :
+ case IATTR_SET_SLOT :
+ case IATTR_SET :
+ case IATTR_ADD :
+ case IATTR_SUB :
+ _analysis.set_noref(0);
break;
case NEXT :
case COPY_NEXT :
if (!_analysis.contexts[_analysis.slotref].flags.inserted)
++_analysis.slotref;
_analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
- if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
+ // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
break;
case INSERT :
_analysis.contexts[_analysis.slotref].flags.inserted = true;
@@ -431,18 +511,21 @@
case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
case PUT_SUBS :
_code._modify = true;
- _analysis.set_changed(_analysis.slotref);
+ _analysis.set_changed(0);
+ GR_FALLTHROUGH;
// no break
case PUT_COPY :
{
- if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
+ if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; }
if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
- _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
- else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
+ _analysis.set_ref(arg[0], true);
+ else if (arg[0] > 0)
+ _analysis.set_ref(arg[0], true);
break;
}
case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
if (_code._constraint) return;
+ GR_FALLTHROUGH;
// no break
case PUSH_GLYPH_ATTR_OBS :
case PUSH_SLOT_ATTR :
@@ -451,16 +534,19 @@
case PUSH_ISLOT_ATTR :
case PUSH_FEAT :
if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
- _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
- else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
+ _analysis.set_ref(arg[1], true);
+ else if (arg[1] > 0)
+ _analysis.set_ref(arg[1], true);
break;
case PUSH_ATT_TO_GLYPH_ATTR :
if (_code._constraint) return;
+ GR_FALLTHROUGH;
// no break
case PUSH_GLYPH_ATTR :
if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
- _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
- else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
+ _analysis.set_ref(arg[2], true);
+ else if (arg[2] > 0)
+ _analysis.set_ref(arg[2], true);
break;
case ASSOC : // slotrefs in varargs
break;
@@ -499,6 +585,7 @@
if (opc == CNTXT_ITEM)
{
assert(_pre_context == 0);
+ _in_ctxt_item = true;
_pre_context = _max.pre_context + int8(_data[-2]);
_rule_length = _max.rule_length;
@@ -506,15 +593,23 @@
byte & instr_skip = _data[-1];
byte & data_skip = *_data++;
++_code._data_size;
+ const byte *curr_end = _max.bytecode;
if (load(bc, bc + instr_skip))
{
bc += instr_skip;
data_skip = instr_skip - (_code._instr_count - ctxt_start);
instr_skip = _code._instr_count - ctxt_start;
+ _max.bytecode = curr_end;
_rule_length = 1;
_pre_context = 0;
+ _in_ctxt_item = false;
+ }
+ else
+ {
+ _pre_context = 0;
+ return false;
}
}
@@ -538,6 +633,7 @@
*tip = temp_copy;
++code_end;
++tempcount;
+ _code._delete = true;
}
_code._instr_count = code_end - code;
@@ -553,8 +649,13 @@
return false;
}
const opcode_t & op = Machine::getOpcodeTable()[opc];
+ if (op.param_sz == VARARGS && bc >= _max.bytecode)
+ {
+ failure(arguments_exhausted);
+ return false;
+ }
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
- if (bc + param_sz > _max.bytecode)
+ if (bc - 1 + param_sz >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
@@ -565,11 +666,20 @@
bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
{
- const bool t = x < limit;
+ const bool t = (limit != 0) && (x < limit);
if (!t) failure(out_of_range_data);
return t;
}
+bool Machine::Code::decoder::test_context() const throw()
+{
+ if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1)
+ {
+ failure(out_of_range_data);
+ return false;
+ }
+ return true;
+}
inline
void Machine::Code::failure(const status_t s) throw() {
@@ -579,23 +689,35 @@
inline
-void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
- contexts[index].flags.referenced = true;
- if (index > max_ref) max_ref = index;
+void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
+ if (incinsert && contexts[slotref].flags.inserted) --index;
+ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+ contexts[index + slotref].flags.referenced = true;
+ if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
inline
-void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
- contexts[index].flags.changed = true;
- if (index > max_ref) max_ref = index;
+void Machine::Code::decoder::analysis::set_noref(int index) throw() {
+ if (contexts[slotref].flags.inserted) --index;
+ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+ if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
+}
+
+
+inline
+void Machine::Code::decoder::analysis::set_changed(int index) throw() {
+ if (contexts[slotref].flags.inserted) --index;
+ if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+ contexts[index + slotref].flags.changed = true;
+ if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
void Machine::Code::release_buffers() throw()
{
- free(_code);
- free(_data);
+ if (_own)
+ free(_code);
_code = 0;
_data = 0;
_own = false;
@@ -604,14 +726,15 @@
int32 Machine::Code::run(Machine & m, slotref * & map) const
{
- assert(_own);
+// assert(_own);
assert(*this); // Check we are actually runnable
- if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()))
+ if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
+ || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
{
m._status = Machine::slot_offset_out_bounds;
-// return (m.slotMap().end() - map);
return 1;
+// return m.run(_code, _data, map);
}
return m.run(_code, _data, map);
diff -Nru graphite2-1.2.4/src/Collider.cpp graphite2-1.3.6/src/Collider.cpp
--- graphite2-1.2.4/src/Collider.cpp 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/Collider.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,1088 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2010, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include
+#include
+#include
+#include
+#include
+#include "inc/Collider.h"
+#include "inc/Segment.h"
+#include "inc/Slot.h"
+#include "inc/GlyphCache.h"
+#include "inc/Sparse.h"
+
+#define ISQRT2 0.707106781f
+
+// Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4
+// (values in font range from 0..256)
+// #define SUBBOX_RND_ERR 0.016
+
+using namespace graphite2;
+
+//// SHIFT-COLLIDER ////
+
+// Initialize the Collider to hold the basic movement limits for the
+// target slot, the one we are focusing on fixing.
+bool ShiftCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin, float marginWeight,
+ const Position &currShift, const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout)
+{
+ int i;
+ float mx, mn;
+ float a, shift;
+ const GlyphCache &gc = seg->getFace()->glyphs();
+ unsigned short gid = aSlot->gid();
+ if (!gc.check(gid))
+ return false;
+ const BBox &bb = gc.getBoundingBBox(gid);
+ const SlantBox &sb = gc.getBoundingSlantBox(gid);
+ //float sx = aSlot->origin().x + currShift.x;
+ //float sy = aSlot->origin().y + currShift.y;
+ if (currOffset.x != 0.f || currOffset.y != 0.f)
+ _limit = Rect(limit.bl - currOffset, limit.tr - currOffset);
+ else
+ _limit = limit;
+ // For a ShiftCollider, these indices indicate which vector we are moving by:
+ // each _ranges represents absolute space with respect to the origin of the slot. Thus take into account true origins but subtract the vmin for the slot
+ for (i = 0; i < 4; ++i)
+ {
+ switch (i) {
+ case 0 : // x direction
+ mn = _limit.bl.x + currOffset.x;
+ mx = _limit.tr.x + currOffset.x;
+ _len[i] = bb.xa - bb.xi;
+ a = currOffset.y + currShift.y;
+ _ranges[i].initialise(mn, mx, margin, marginWeight, a);
+ break;
+ case 1 : // y direction
+ mn = _limit.bl.y + currOffset.y;
+ mx = _limit.tr.y + currOffset.y;
+ _len[i] = bb.ya - bb.yi;
+ a = currOffset.x + currShift.x;
+ _ranges[i].initialise(mn, mx, margin, marginWeight, a);
+ break;
+ case 2 : // sum (negatively sloped diagonal boundaries)
+ // pick closest x,y limit boundaries in s direction
+ shift = currOffset.x + currOffset.y + currShift.x + currShift.y;
+ mn = -2 * min(currShift.x - _limit.bl.x, currShift.y - _limit.bl.y) + shift;
+ mx = 2 * min(_limit.tr.x - currShift.x, _limit.tr.y - currShift.y) + shift;
+ _len[i] = sb.sa - sb.si;
+ a = currOffset.x - currOffset.y + currShift.x - currShift.y;
+ _ranges[i].initialise(mn, mx, margin / ISQRT2, marginWeight, a);
+ break;
+ case 3 : // diff (positively sloped diagonal boundaries)
+ // pick closest x,y limit boundaries in d direction
+ shift = currOffset.x - currOffset.y + currShift.x - currShift.y;
+ mn = -2 * min(currShift.x - _limit.bl.x, _limit.tr.y - currShift.y) + shift;
+ mx = 2 * min(_limit.tr.x - currShift.x, currShift.y - _limit.bl.y) + shift;
+ _len[i] = sb.da - sb.di;
+ a = currOffset.x + currOffset.y + currShift.x + currShift.y;
+ _ranges[i].initialise(mn, mx, margin / ISQRT2, marginWeight, a);
+ break;
+ }
+ }
+
+ _target = aSlot;
+ if ((dir & 1) == 0)
+ {
+ // For LTR, switch and negate x limits.
+ _limit.bl.x = -1 * limit.tr.x;
+ //_limit.tr.x = -1 * limit.bl.x;
+ }
+ _currOffset = currOffset;
+ _currShift = currShift;
+ _origin = aSlot->origin() - currOffset; // the original anchor position of the glyph
+
+ _margin = margin;
+ _marginWt = marginWeight;
+
+ SlotCollision *c = seg->collisionInfo(aSlot);
+ _seqClass = c->seqClass();
+ _seqProxClass = c->seqProxClass();
+ _seqOrder = c->seqOrder();
+ return true;
+}
+
+template
+float sdm(float vi, float va, float mx, float my, O op)
+{
+ float res = 2 * mx - vi;
+ if (op(res, vi + 2 * my))
+ {
+ res = va + 2 * my;
+ if (op(res, 2 * mx - va))
+ res = mx + my;
+ }
+ return res;
+}
+
+// Mark an area with a cost that can vary along the x or y axis. The region is expressed in terms of the centre of the target glyph in each axis
+void ShiftCollider::addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int axis)
+{
+ float a, c;
+ switch (axis) {
+ case 0 :
+ if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
+ {
+ a = org.y + 0.5f * (bb.yi + bb.ya);
+ c = 0.5f * (bb.xi + bb.xa);
+ if (isx)
+ _ranges[axis].weighted(box.bl.x - c, box.tr.x - c, weight, a, m,
+ (minright ? box.tr.x : box.bl.x) - c, a, 0, false);
+ else
+ _ranges[axis].weighted(box.bl.x - c, box.tr.x - c, weight, a, 0, 0, org.y,
+ m * (a * a + sqr((minright ? box.tr.y : box.bl.y) - 0.5f * (bb.yi + bb.ya))), false);
+ }
+ break;
+ case 1 :
+ if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
+ {
+ a = org.x + 0.5f * (bb.xi + bb.xa);
+ c = 0.5f * (bb.yi + bb.ya);
+ if (isx)
+ _ranges[axis].weighted(box.bl.y - c, box.tr.y - c, weight, a, 0, 0, org.x,
+ m * (a * a + sqr((minright ? box.tr.x : box.bl.x) - 0.5f * (bb.xi + bb.xa))), false);
+ else
+ _ranges[axis].weighted(box.bl.y - c, box.tr.y - c, weight, a, m,
+ (minright ? box.tr.y : box.bl.y) - c, a, 0, false);
+ }
+ break;
+ case 2 :
+ if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di)
+ {
+ float d = org.x - org.y + 0.5f * (sb.di + sb.da);
+ c = 0.5f * (sb.si + sb.sa);
+ float smax = min(2 * box.tr.x - d, 2 * box.tr.y + d);
+ float smin = max(2 * box.bl.x - d, 2 * box.bl.y + d);
+ if (smin > smax) return;
+ float si;
+ a = d;
+ if (isx)
+ si = 2 * (minright ? box.tr.x : box.bl.x) - a;
+ else
+ si = 2 * (minright ? box.tr.y : box.bl.y) + a;
+ _ranges[axis].weighted(smin - c, smax - c, weight / 2, a, m / 2, si, 0, 0, isx);
+ }
+ break;
+ case 3 :
+ if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si)
+ {
+ float s = org.x + org.y + 0.5f * (sb.si + sb.sa);
+ c = 0.5f * (sb.di + sb.da);
+ float dmax = min(2 * box.tr.x - s, s - 2 * box.bl.y);
+ float dmin = max(2 * box.bl.x - s, s - 2 * box.tr.y);
+ if (dmin > dmax) return;
+ float di;
+ a = s;
+ if (isx)
+ di = 2 * (minright ? box.tr.x : box.bl.x) - a;
+ else
+ di = 2 * (minright ? box.tr.y : box.bl.y) + a;
+ _ranges[axis].weighted(dmin - c, dmax - c, weight / 2, a, m / 2, di, 0, 0, !isx);
+ }
+ break;
+ default :
+ break;
+ }
+ return;
+}
+
+// Mark an area with an absolute cost, making it completely inaccessible.
+inline void ShiftCollider::removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int axis)
+{
+ float c;
+ switch (axis) {
+ case 0 :
+ if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
+ {
+ c = 0.5f * (bb.xi + bb.xa);
+ _ranges[axis].exclude(box.bl.x - c, box.tr.x - c);
+ }
+ break;
+ case 1 :
+ if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
+ {
+ c = 0.5f * (bb.yi + bb.ya);
+ _ranges[axis].exclude(box.bl.y - c, box.tr.y - c);
+ }
+ break;
+ case 2 :
+ if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di
+ && box.width() > 0 && box.height() > 0)
+ {
+ float di = org.x - org.y + sb.di;
+ float da = org.x - org.y + sb.da;
+ float smax = sdm(di, da, box.tr.x, box.tr.y, std::greater());
+ float smin = sdm(da, di, box.bl.x, box.bl.y, std::less());
+ c = 0.5f * (sb.si + sb.sa);
+ _ranges[axis].exclude(smin - c, smax - c);
+ }
+ break;
+ case 3 :
+ if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si
+ && box.width() > 0 && box.height() > 0)
+ {
+ float si = org.x + org.y + sb.si;
+ float sa = org.x + org.y + sb.sa;
+ float dmax = sdm(si, sa, box.tr.x, -box.bl.y, std::greater());
+ float dmin = sdm(sa, si, box.bl.x, -box.tr.y, std::less());
+ c = 0.5f * (sb.di + sb.da);
+ _ranges[axis].exclude(dmin - c, dmax - c);
+ }
+ break;
+ default :
+ break;
+ }
+ return;
+}
+
+// Adjust the movement limits for the target to avoid having it collide
+// with the given neighbor slot. Also determine if there is in fact a collision
+// between the target and the given slot.
+bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift,
+ bool isAfter, // slot is logically after _target
+ bool sameCluster, bool &hasCol, bool isExclusion,
+ GR_MAYBE_UNUSED json * const dbgout )
+{
+ bool isCol = false;
+ const float sx = slot->origin().x - _origin.x + currShift.x;
+ const float sy = slot->origin().y - _origin.y + currShift.y;
+ const float sd = sx - sy;
+ const float ss = sx + sy;
+ float vmin, vmax;
+ float omin, omax, otmin, otmax;
+ float cmin, cmax; // target limits
+ float torg;
+ const GlyphCache &gc = seg->getFace()->glyphs();
+ const unsigned short gid = slot->gid();
+ if (!gc.check(gid))
+ return false;
+ const BBox &bb = gc.getBoundingBBox(gid);
+
+ SlotCollision * cslot = seg->collisionInfo(slot);
+ int orderFlags = 0;
+ bool sameClass = _seqProxClass == 0 && cslot->seqClass() == _seqClass;
+ if (sameCluster && _seqClass
+ && (sameClass || (_seqProxClass != 0 && cslot->seqClass() == _seqProxClass)))
+ // Force the target glyph to be in the specified direction from the slot we're testing.
+ orderFlags = _seqOrder;
+
+ // short circuit if only interested in direct collision and we are out of range
+ if (orderFlags || (sx + bb.xa + _margin >= _limit.bl.x && sx + bb.xi - _margin <= _limit.tr.x)
+ || (sy + bb.ya + _margin >= _limit.bl.y && sy + bb.yi - _margin <= _limit.tr.y))
+
+ {
+ const float tx = _currOffset.x + _currShift.x;
+ const float ty = _currOffset.y + _currShift.y;
+ const float td = tx - ty;
+ const float ts = tx + ty;
+ const SlantBox &sb = gc.getBoundingSlantBox(gid);
+ const unsigned short tgid = _target->gid();
+ const BBox &tbb = gc.getBoundingBBox(tgid);
+ const SlantBox &tsb = gc.getBoundingSlantBox(tgid);
+ float seq_above_wt = cslot->seqAboveWt();
+ float seq_below_wt = cslot->seqBelowWt();
+ float seq_valign_wt = cslot->seqValignWt();
+ // if isAfter, invert orderFlags for diagonal orders.
+ if (isAfter)
+ {
+ // invert appropriate bits
+ orderFlags ^= (sameClass ? 0x3F : 0x3);
+ // consider 2 bits at a time, non overlapping. If both bits set, clear them
+ orderFlags = orderFlags ^ ((((orderFlags >> 1) & orderFlags) & 0x15) * 3);
+ }
+
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ dbgout->setenv(0, slot);
+#endif
+
+ // Process main bounding octabox.
+ for (int i = 0; i < 4; ++i)
+ {
+ switch (i) {
+ case 0 : // x direction
+ vmin = max(max(bb.xi - tbb.xa + sx, sb.di - tsb.da + ty + sd), sb.si - tsb.sa - ty + ss);
+ vmax = min(min(bb.xa - tbb.xi + sx, sb.da - tsb.di + ty + sd), sb.sa - tsb.si - ty + ss);
+ otmin = tbb.yi + ty;
+ otmax = tbb.ya + ty;
+ omin = bb.yi + sy;
+ omax = bb.ya + sy;
+ torg = _currOffset.x;
+ cmin = _limit.bl.x + torg;
+ cmax = _limit.tr.x - tbb.xi + tbb.xa + torg;
+ break;
+ case 1 : // y direction
+ vmin = max(max(bb.yi - tbb.ya + sy, tsb.di - sb.da + tx - sd), sb.si - tsb.sa - tx + ss);
+ vmax = min(min(bb.ya - tbb.yi + sy, tsb.da - sb.di + tx - sd), sb.sa - tsb.si - tx + ss);
+ otmin = tbb.xi + tx;
+ otmax = tbb.xa + tx;
+ omin = bb.xi + sx;
+ omax = bb.xa + sx;
+ torg = _currOffset.y;
+ cmin = _limit.bl.y + torg;
+ cmax = _limit.tr.y - tbb.yi + tbb.ya + torg;
+ break;
+ case 2 : // sum - moving along the positively-sloped vector, so the boundaries are the
+ // negatively-sloped boundaries.
+ vmin = max(max(sb.si - tsb.sa + ss, 2 * (bb.yi - tbb.ya + sy) + td), 2 * (bb.xi - tbb.xa + sx) - td);
+ vmax = min(min(sb.sa - tsb.si + ss, 2 * (bb.ya - tbb.yi + sy) + td), 2 * (bb.xa - tbb.xi + sx) - td);
+ otmin = tsb.di + td;
+ otmax = tsb.da + td;
+ omin = sb.di + sd;
+ omax = sb.da + sd;
+ torg = _currOffset.x + _currOffset.y;
+ cmin = _limit.bl.x + _limit.bl.y + torg;
+ cmax = _limit.tr.x + _limit.tr.y - tsb.si + tsb.sa + torg;
+ break;
+ case 3 : // diff - moving along the negatively-sloped vector, so the boundaries are the
+ // positively-sloped boundaries.
+ vmin = max(max(sb.di - tsb.da + sd, 2 * (bb.xi - tbb.xa + sx) - ts), -2 * (bb.ya - tbb.yi + sy) + ts);
+ vmax = min(min(sb.da - tsb.di + sd, 2 * (bb.xa - tbb.xi + sx) - ts), -2 * (bb.yi - tbb.ya + sy) + ts);
+ otmin = tsb.si + ts;
+ otmax = tsb.sa + ts;
+ omin = sb.si + ss;
+ omax = sb.sa + ss;
+ torg = _currOffset.x - _currOffset.y;
+ cmin = _limit.bl.x - _limit.tr.y + torg;
+ cmax = _limit.tr.x - _limit.bl.y - tsb.di + tsb.da + torg;
+ break;
+ default :
+ continue;
+ }
+
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ dbgout->setenv(1, reinterpret_cast(-1));
+#define DBGTAG(x) if (dbgout) dbgout->setenv(1, reinterpret_cast(-x));
+#else
+#define DBGTAG(x)
+#endif
+
+ if (orderFlags)
+ {
+ Position org(tx, ty);
+ float xminf = _limit.bl.x + _currOffset.x + tbb.xi;
+ float xpinf = _limit.tr.x + _currOffset.x + tbb.xa;
+ float ypinf = _limit.tr.y + _currOffset.y + tbb.ya;
+ float yminf = _limit.bl.y + _currOffset.y + tbb.yi;
+ switch (orderFlags) {
+ case SlotCollision::SEQ_ORDER_RIGHTUP :
+ {
+ float r1Xedge = cslot->seqAboveXoff() + 0.5f * (bb.xi + bb.xa) + sx;
+ float r3Xedge = cslot->seqBelowXlim() + bb.xa + sx + 0.5f * (tbb.xa - tbb.xi);
+ float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
+
+ // DBGTAG(1x) means the regions are up and right
+ // region 1
+ DBGTAG(11)
+ addBox_slope(true, Rect(Position(xminf, r2Yedge), Position(r1Xedge, ypinf)),
+ tbb, tsb, org, 0, seq_above_wt, true, i);
+ // region 2
+ DBGTAG(12)
+ removeBox(Rect(Position(xminf, yminf), Position(r3Xedge, r2Yedge)), tbb, tsb, org, i);
+ // region 3, which end is zero is irrelevant since m weight is 0
+ DBGTAG(13)
+ addBox_slope(true, Rect(Position(r3Xedge, yminf), Position(xpinf, r2Yedge - cslot->seqValignHt())),
+ tbb, tsb, org, seq_below_wt, 0, true, i);
+ // region 4
+ DBGTAG(14)
+ addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge), Position(xpinf, r2Yedge + cslot->seqValignHt())),
+ tbb, tsb, org, 0, seq_valign_wt, true, i);
+ // region 5
+ DBGTAG(15)
+ addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge - cslot->seqValignHt()), Position(xpinf, r2Yedge)),
+ tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
+ break;
+ }
+ case SlotCollision::SEQ_ORDER_LEFTDOWN :
+ {
+ float r1Xedge = 0.5f * (bb.xi + bb.xa) + cslot->seqAboveXoff() + sx;
+ float r3Xedge = bb.xi - cslot->seqBelowXlim() + sx - 0.5f * (tbb.xa - tbb.xi);
+ float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
+ // DBGTAG(2x) means the regions are up and right
+ // region 1
+ DBGTAG(21)
+ addBox_slope(true, Rect(Position(r1Xedge, yminf), Position(xpinf, r2Yedge)),
+ tbb, tsb, org, 0, seq_above_wt, false, i);
+ // region 2
+ DBGTAG(22)
+ removeBox(Rect(Position(r3Xedge, r2Yedge), Position(xpinf, ypinf)), tbb, tsb, org, i);
+ // region 3
+ DBGTAG(23)
+ addBox_slope(true, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()), Position(r3Xedge, ypinf)),
+ tbb, tsb, org, seq_below_wt, 0, false, i);
+ // region 4
+ DBGTAG(24)
+ addBox_slope(false, Rect(Position(xminf, r2Yedge), Position(sx + bb.xa, r2Yedge + cslot->seqValignHt())),
+ tbb, tsb, org, 0, seq_valign_wt, true, i);
+ // region 5
+ DBGTAG(25)
+ addBox_slope(false, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()),
+ Position(sx + bb.xa, r2Yedge)), tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
+ break;
+ }
+ case SlotCollision::SEQ_ORDER_NOABOVE : // enforce neighboring glyph being above
+ DBGTAG(31);
+ removeBox(Rect(Position(bb.xi - tbb.xa + sx, sy + bb.ya),
+ Position(bb.xa - tbb.xi + sx, ypinf)), tbb, tsb, org, i);
+ break;
+ case SlotCollision::SEQ_ORDER_NOBELOW : // enforce neighboring glyph being below
+ DBGTAG(32);
+ removeBox(Rect(Position(bb.xi - tbb.xa + sx, yminf),
+ Position(bb.xa - tbb.xi + sx, sy + bb.yi)), tbb, tsb, org, i);
+ break;
+ case SlotCollision::SEQ_ORDER_NOLEFT : // enforce neighboring glyph being to the left
+ DBGTAG(33)
+ removeBox(Rect(Position(xminf, bb.yi - tbb.ya + sy),
+ Position(bb.xi - tbb.xa + sx, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
+ break;
+ case SlotCollision::SEQ_ORDER_NORIGHT : // enforce neighboring glyph being to the right
+ DBGTAG(34)
+ removeBox(Rect(Position(bb.xa - tbb.xi + sx, bb.yi - tbb.ya + sy),
+ Position(xpinf, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
+ break;
+ default :
+ break;
+ }
+ }
+
+ if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
+ continue;
+
+ // Process sub-boxes that are defined for this glyph.
+ // We only need to do this if there was in fact a collision with the main octabox.
+ uint8 numsub = gc.numSubBounds(gid);
+ if (numsub > 0)
+ {
+ bool anyhits = false;
+ for (int j = 0; j < numsub; ++j)
+ {
+ const BBox &sbb = gc.getSubBoundingBBox(gid, j);
+ const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, j);
+ switch (i) {
+ case 0 : // x
+ vmin = max(max(sbb.xi-tbb.xa+sx, ssb.di-tsb.da+sd+ty), ssb.si-tsb.sa+ss-ty);
+ vmax = min(min(sbb.xa-tbb.xi+sx, ssb.da-tsb.di+sd+ty), ssb.sa-tsb.si+ss-ty);
+ omin = sbb.yi + sy;
+ omax = sbb.ya + sy;
+ break;
+ case 1 : // y
+ vmin = max(max(sbb.yi-tbb.ya+sy, tsb.di-ssb.da-sd+tx), ssb.si-tsb.sa+ss-tx);
+ vmax = min(min(sbb.ya-tbb.yi+sy, tsb.da-ssb.di-sd+tx), ssb.sa-tsb.si+ss-tx);
+ omin = sbb.xi + sx;
+ omax = sbb.xa + sx;
+ break;
+ case 2 : // sum
+ vmin = max(max(ssb.si-tsb.sa+ss, 2*(sbb.yi-tbb.ya+sy)+td), 2*(sbb.xi-tbb.xa+sx)-td);
+ vmax = min(min(ssb.sa-tsb.si+ss, 2*(sbb.ya-tbb.yi+sy)+td), 2*(sbb.xa-tbb.xi+sx)-td);
+ omin = ssb.di + sd;
+ omax = ssb.da + sd;
+ break;
+ case 3 : // diff
+ vmin = max(max(ssb.di-tsb.da+sd, 2*(sbb.xi-tbb.xa+sx)-ts), -2*(sbb.ya-tbb.yi+sy)+ts);
+ vmax = min(min(ssb.da-tsb.di+sd, 2*(sbb.xa-tbb.xi+sx)-ts), -2*(sbb.yi-tbb.ya+sy)+ts);
+ omin = ssb.si + ss;
+ omax = ssb.sa + ss;
+ break;
+ }
+ if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
+ continue;
+
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ dbgout->setenv(1, reinterpret_cast(j));
+#endif
+ if (omin > otmax)
+ _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
+ sqr(_margin - omin + otmax) * _marginWt, false);
+ else if (omax < otmin)
+ _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
+ sqr(_margin - otmin + omax) * _marginWt, false);
+ else
+ _ranges[i].exclude_with_margins(vmin, vmax, i);
+ anyhits = true;
+ }
+ if (anyhits)
+ isCol = true;
+ }
+ else // no sub-boxes
+ {
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ dbgout->setenv(1, reinterpret_cast(-1));
+#endif
+ isCol = true;
+ if (omin > otmax)
+ _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
+ sqr(_margin - omin + otmax) * _marginWt, false);
+ else if (omax < otmin)
+ _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
+ sqr(_margin - otmin + omax) * _marginWt, false);
+ else
+ _ranges[i].exclude_with_margins(vmin, vmax, i);
+
+ }
+ }
+ }
+ bool res = true;
+ if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
+ {
+ // Set up the bogus slot representing the exclusion glyph.
+ Slot *exclSlot = seg->newSlot();
+ exclSlot->setGlyph(seg, cslot->exclGlyph());
+ Position exclOrigin(slot->origin() + cslot->exclOffset());
+ exclSlot->origin(exclOrigin);
+ res &= mergeSlot(seg, exclSlot, currShift, isAfter, sameCluster, isCol, true, dbgout );
+ seg->freeSlot(exclSlot);
+ }
+ hasCol |= isCol;
+ return res;
+
+} // end of ShiftCollider::mergeSlot
+
+
+// Figure out where to move the target glyph to, and return the amount to shift by.
+Position ShiftCollider::resolve(GR_MAYBE_UNUSED Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout)
+{
+ float tbase;
+ float totalCost = (float)(std::numeric_limits::max() / 2);
+ Position resultPos = Position(0, 0);
+#if !defined GRAPHITE2_NTRACING
+ int bestAxis = -1;
+ if (dbgout)
+ {
+ outputJsonDbgStartSlot(dbgout, seg);
+ *dbgout << "vectors" << json::array;
+ }
+#endif
+ isCol = true;
+ for (int i = 0; i < 4; ++i)
+ {
+ float bestCost = -1;
+ float bestPos;
+ // Calculate the margin depending on whether we are moving diagonally or not:
+ switch (i) {
+ case 0 : // x direction
+ tbase = _currOffset.x;
+ break;
+ case 1 : // y direction
+ tbase = _currOffset.y;
+ break;
+ case 2 : // sum (negatively-sloped diagonals)
+ tbase = _currOffset.x + _currOffset.y;
+ break;
+ case 3 : // diff (positively-sloped diagonals)
+ tbase = _currOffset.x - _currOffset.y;
+ break;
+ }
+ Position testp;
+ bestPos = _ranges[i].closest(0, bestCost) - tbase; // Get the best relative position
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ outputJsonDbgOneVector(dbgout, seg, i, tbase, bestCost, bestPos) ;
+#endif
+ if (bestCost >= 0.0f)
+ {
+ isCol = false;
+ switch (i) {
+ case 0 : testp = Position(bestPos, _currShift.y); break;
+ case 1 : testp = Position(_currShift.x, bestPos); break;
+ case 2 : testp = Position(0.5f * (_currShift.x - _currShift.y + bestPos), 0.5f * (_currShift.y - _currShift.x + bestPos)); break;
+ case 3 : testp = Position(0.5f * (_currShift.x + _currShift.y + bestPos), 0.5f * (_currShift.x + _currShift.y - bestPos)); break;
+ }
+ if (bestCost < totalCost - 0.01f)
+ {
+ totalCost = bestCost;
+ resultPos = testp;
+#if !defined GRAPHITE2_NTRACING
+ bestAxis = i;
+#endif
+ }
+ }
+ } // end of loop over 4 directions
+
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ outputJsonDbgEndSlot(dbgout, resultPos, bestAxis, isCol);
+#endif
+
+ return resultPos;
+
+} // end of ShiftCollider::resolve
+
+
+#if !defined GRAPHITE2_NTRACING
+
+void ShiftCollider::outputJsonDbg(json * const dbgout, Segment *seg, int axis)
+{
+ int axisMax = axis;
+ if (axis < 0) // output all axes
+ {
+ *dbgout << "gid" << _target->gid()
+ << "limit" << _limit
+ << "target" << json::object
+ << "origin" << _target->origin()
+ << "margin" << _margin
+ << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
+ << "slantbox" << seg->getFace()->glyphs().slant(_target->gid())
+ << json::close; // target object
+ *dbgout << "ranges" << json::array;
+ axis = 0;
+ axisMax = 3;
+ }
+ for (int iAxis = axis; iAxis <= axisMax; ++iAxis)
+ {
+ *dbgout << json::flat << json::array << _ranges[iAxis].position();
+ for (Zones::const_iterator s = _ranges[iAxis].begin(), e = _ranges[iAxis].end(); s != e; ++s)
+ *dbgout << json::flat << json::array
+ << Position(s->x, s->xm) << s->sm << s->smx << s->c
+ << json::close;
+ *dbgout << json::close;
+ }
+ if (axis < axisMax) // looped through the _ranges array for all axes
+ *dbgout << json::close; // ranges array
+}
+
+void ShiftCollider::outputJsonDbgStartSlot(json * const dbgout, Segment *seg)
+{
+ *dbgout << json::object // slot - not closed till the end of the caller method
+ << "slot" << objectid(dslot(seg, _target))
+ << "gid" << _target->gid()
+ << "limit" << _limit
+ << "target" << json::object
+ << "origin" << _origin
+ << "currShift" << _currShift
+ << "currOffset" << seg->collisionInfo(_target)->offset()
+ << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
+ << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
+ << "fix" << "shift";
+ *dbgout << json::close; // target object
+}
+
+void ShiftCollider::outputJsonDbgEndSlot(GR_MAYBE_UNUSED json * const dbgout,
+ Position resultPos, int bestAxis, bool isCol)
+{
+ *dbgout << json::close // vectors array
+ << "result" << resultPos
+ //<< "scraping" << _scraping[bestAxis]
+ << "bestAxis" << bestAxis
+ << "stillBad" << isCol
+ << json::close; // slot object
+}
+
+void ShiftCollider::outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis,
+ float tleft, float bestCost, float bestVal)
+{
+ const char * label;
+ switch (axis)
+ {
+ case 0: label = "x"; break;
+ case 1: label = "y"; break;
+ case 2: label = "sum (NE-SW)"; break;
+ case 3: label = "diff (NW-SE)"; break;
+ default: label = "???"; break;
+ }
+
+ *dbgout << json::object // vector
+ << "direction" << label
+ << "targetMin" << tleft;
+
+ outputJsonDbgRemovals(dbgout, axis, seg);
+
+ *dbgout << "ranges";
+ outputJsonDbg(dbgout, seg, axis);
+
+ *dbgout << "bestCost" << bestCost
+ << "bestVal" << bestVal + tleft
+ << json::close; // vectors object
+}
+
+void ShiftCollider::outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg)
+{
+ *dbgout << "removals" << json::array;
+ _ranges[axis].jsonDbgOut(seg);
+ *dbgout << json::close; // removals array
+}
+
+#endif // !defined GRAPHITE2_NTRACING
+
+
+//// KERN-COLLIDER ////
+
+inline
+static float localmax (float al, float au, float bl, float bu, float x)
+{
+ if (al < bl)
+ { if (au < bu) return au < x ? au : x; }
+ else if (au > bu) return bl < x ? bl : x;
+ return x;
+}
+
+inline
+static float localmin(float al, float au, float bl, float bu, float x)
+{
+ if (bl > al)
+ { if (bu > au) return bl > x ? bl : x; }
+ else if (au > bu) return al > x ? al : x;
+ return x;
+}
+
+// Return the given edge of the glyph at height y, taking any slant box into account.
+static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, bool isRight)
+{
+ const GlyphCache &gc = seg->getFace()->glyphs();
+ unsigned short gid = s->gid();
+ float sx = s->origin().x + shift.x;
+ float sy = s->origin().y + shift.y;
+ uint8 numsub = gc.numSubBounds(gid);
+ float res = isRight ? (float)-1e38 : (float)1e38;
+
+ if (numsub > 0)
+ {
+ for (int i = 0; i < numsub; ++i)
+ {
+ const BBox &sbb = gc.getSubBoundingBBox(gid, i);
+ const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, i);
+ if (sy + sbb.yi > y + width / 2 || sy + sbb.ya < y - width / 2)
+ continue;
+ if (isRight)
+ {
+ float x = sx + sbb.xa;
+ if (x > res)
+ {
+ float td = sx - sy + ssb.da + y;
+ float ts = sx + sy + ssb.sa - y;
+ x = localmax(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
+ if (x > res)
+ res = x;
+ }
+ }
+ else
+ {
+ float x = sx + sbb.xi;
+ if (x < res)
+ {
+ float td = sx - sy + ssb.di + y;
+ float ts = sx + sy + ssb.si - y;
+ x = localmin(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
+ if (x < res)
+ res = x;
+ }
+ }
+ }
+ }
+ else
+ {
+ const BBox &bb = gc.getBoundingBBox(gid);
+ const SlantBox &sb = gc.getBoundingSlantBox(gid);
+ float td = sx - sy + y;
+ float ts = sx + sy - y;
+ if (isRight)
+ res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa);
+ else
+ res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi);
+ }
+ return res;
+}
+
+
+bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin,
+ const Position &currShift, const Position &offsetPrev, int dir,
+ float ymin, float ymax, GR_MAYBE_UNUSED json * const dbgout)
+{
+ const GlyphCache &gc = seg->getFace()->glyphs();
+ const Slot *base = aSlot;
+ // const Slot *last = aSlot;
+ const Slot *s;
+ int numSlices;
+ while (base->attachedTo())
+ base = base->attachedTo();
+ if (margin < 10) margin = 10;
+
+ _limit = limit;
+ _offsetPrev = offsetPrev; // kern from a previous pass
+
+ // Calculate the height of the glyph and how many horizontal slices to use.
+ if (_maxy >= 1e37f)
+ {
+ _maxy = ymax;
+ _miny = ymin;
+ _sliceWidth = margin / 1.5f;
+ numSlices = int((_maxy - _miny + 2) / (_sliceWidth / 1.5f) + 1.f); // +2 helps with rounding errors
+ _edges.clear();
+ _edges.insert(_edges.begin(), numSlices, (dir & 1) ? 1e38f : -1e38f);
+ _xbound = (dir & 1) ? (float)1e38f : (float)-1e38f;
+ }
+ else if (_maxy != ymax || _miny != ymin)
+ {
+ if (_miny != ymin)
+ {
+ numSlices = int((ymin - _miny) / _sliceWidth - 1);
+ _miny += numSlices * _sliceWidth;
+ if (numSlices < 0)
+ _edges.insert(_edges.begin(), -numSlices, (dir & 1) ? 1e38f : -1e38f);
+ else if ((unsigned)numSlices < _edges.size()) // this shouldn't fire since we always grow the range
+ {
+ Vector::iterator e = _edges.begin();
+ while (numSlices--)
+ ++e;
+ _edges.erase(_edges.begin(), e);
+ }
+ }
+ if (_maxy != ymax)
+ {
+ numSlices = int((ymax - _miny) / _sliceWidth + 1);
+ _maxy = numSlices * _sliceWidth + _miny;
+ if (numSlices > (int)_edges.size())
+ _edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
+ else if (numSlices < (int)_edges.size()) // this shouldn't fire since we always grow the range
+ {
+ while ((int)_edges.size() > numSlices)
+ _edges.pop_back();
+ }
+ }
+ }
+ numSlices = _edges.size();
+
+#if !defined GRAPHITE2_NTRACING
+ // Debugging
+ _seg = seg;
+ _slotNear.clear();
+ _slotNear.insert(_slotNear.begin(), numSlices, NULL);
+ _nearEdges.clear();
+ _nearEdges.insert(_nearEdges.begin(), numSlices, (dir & 1) ? -1e38f : +1e38f);
+#endif
+
+ // Determine the trailing edge of each slice (ie, left edge for a RTL glyph).
+ for (s = base; s; s = s->nextInCluster(s))
+ {
+ SlotCollision *c = seg->collisionInfo(s);
+ if (!gc.check(s->gid()))
+ return false;
+ const BBox &bs = gc.getBoundingBBox(s->gid());
+ float x = s->origin().x + c->shift().x + ((dir & 1) ? bs.xi : bs.xa);
+ // Loop over slices.
+ // Note smin might not be zero if glyph s is not at the bottom of the cluster; similarly for smax.
+ float toffset = c->shift().y - _miny + 1 + s->origin().y;
+ int smin = max(0, int((bs.yi + toffset) / _sliceWidth));
+ int smax = min(numSlices - 1, int((bs.ya + toffset) / _sliceWidth + 1));
+ for (int i = smin; i <= smax; ++i)
+ {
+ float t;
+ float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice
+ if ((dir & 1) && x < _edges[i])
+ {
+ t = get_edge(seg, s, c->shift(), y, _sliceWidth, false);
+ if (t < _edges[i])
+ {
+ _edges[i] = t;
+ if (t < _xbound)
+ _xbound = t;
+ }
+ }
+ else if (!(dir & 1) && x > _edges[i])
+ {
+ t = get_edge(seg, s, c->shift(), y, _sliceWidth, true);
+ if (t > _edges[i])
+ {
+ _edges[i] = t;
+ if (t > _xbound)
+ _xbound = t;
+ }
+ }
+ }
+ }
+ _mingap = (float)1e38;
+ _target = aSlot;
+ _margin = margin;
+ _currShift = currShift;
+ return true;
+} // end of KernCollider::initSlot
+
+
+// Determine how much the target slot needs to kern away from the given slot.
+// In other words, merge information from given slot's position with what the target slot knows
+// about how it can kern.
+// Return false if we know there is no collision, true if we think there might be one.
+bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
+{
+ int rtl = (dir & 1) * 2 - 1;
+ if (!seg->getFace()->glyphs().check(slot->gid()))
+ return false;
+ const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
+ const float sx = slot->origin().x + currShift.x;
+ float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x);
+ // this isn't going to reduce _mingap so skip
+ if ((rtl > 0 && x < _xbound - _mingap - currSpace) || (rtl <= 0 && x > _xbound + _mingap + currSpace))
+ return false;
+
+ const float sy = slot->origin().y + currShift.y;
+ int smin = max(0, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1));
+ int smax = min((int)_edges.size() - 1, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1));
+ bool collides = false;
+
+ for (int i = smin; i <= smax; ++i)
+ {
+ float t;
+ float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth); // vertical center of slice
+ if (x * rtl > _edges[i] * rtl - _mingap - currSpace)
+ {
+ // 2 * currSpace to account for the space that is already separating them and the space we want to add
+ float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) + 2 * rtl * currSpace;
+ t = rtl * (_edges[i] - m);
+ // Check slices above and below (if any).
+ if (i < (int)_edges.size() - 1) t = min(t, rtl * (_edges[i+1] - m));
+ if (i > 0) t = min(t, rtl * (_edges[i-1] - m));
+ // _mingap is positive to shrink
+ if (t < _mingap)
+ {
+ _mingap = t;
+ collides = true;
+ }
+#if !defined GRAPHITE2_NTRACING
+ // Debugging - remember the closest neighboring edge for this slice.
+ if (rtl * m > rtl * _nearEdges[i])
+ {
+ _slotNear[i] = slot;
+ _nearEdges[i] = m;
+ }
+#endif
+ }
+ }
+ return collides; // note that true is not a necessarily reliable value
+
+} // end of KernCollider::mergeSlot
+
+
+// Return the amount to kern by.
+Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
+ int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
+{
+ float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
+ float result = min(_limit.tr.x - _offsetPrev.x, max(resultNeeded, _limit.bl.x - _offsetPrev.x));
+
+#if !defined GRAPHITE2_NTRACING
+ if (dbgout)
+ {
+ *dbgout << json::object // slot
+ << "slot" << objectid(dslot(seg, _target))
+ << "gid" << _target->gid()
+ << "margin" << _margin
+ << "limit" << _limit
+ << "miny" << _miny
+ << "maxy" << _maxy
+ << "slicewidth" << _sliceWidth
+ << "target" << json::object
+ << "origin" << _target->origin()
+ //<< "currShift" << _currShift
+ << "offsetPrev" << _offsetPrev
+ << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
+ << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
+ << "fix" << "kern"
+ << json::close; // target object
+
+ *dbgout << "slices" << json::array;
+ for (int is = 0; is < (int)_edges.size(); is++)
+ {
+ *dbgout << json::flat << json::object
+ << "i" << is
+ << "targetEdge" << _edges[is]
+ << "neighbor" << objectid(dslot(seg, _slotNear[is]))
+ << "nearEdge" << _nearEdges[is]
+ << json::close;
+ }
+ *dbgout << json::close; // slices array
+
+ *dbgout
+ << "xbound" << _xbound
+ << "minGap" << _mingap
+ << "needed" << resultNeeded
+ << "result" << result
+ << "stillBad" << (result != resultNeeded)
+ << json::close; // slot object
+ }
+#endif
+
+ return Position(result, 0.);
+
+} // end of KernCollider::resolve
+
+void KernCollider::shift(const Position &mv, int dir)
+{
+ for (Vector::iterator e = _edges.begin(); e != _edges.end(); ++e)
+ *e += mv.x;
+ _xbound += (1 - 2 * (dir & 1)) * mv.x;
+}
+
+//// SLOT-COLLISION ////
+
+// Initialize the collision attributes for the given slot.
+SlotCollision::SlotCollision(Segment *seg, Slot *slot)
+{
+ initFromSlot(seg, slot);
+}
+
+void SlotCollision::initFromSlot(Segment *seg, Slot *slot)
+{
+ // Initialize slot attributes from glyph attributes.
+ // The order here must match the order in the grcompiler code,
+ // GrcSymbolTable::AssignInternalGlyphAttrIDs.
+ uint16 gid = slot->gid();
+ uint16 aCol = seg->silf()->aCollision(); // flags attr ID
+ const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(gid);
+ if (!glyphFace)
+ return;
+ const sparse &p = glyphFace->attrs();
+ _flags = p[aCol];
+ _limit = Rect(Position(p[aCol+1], p[aCol+2]),
+ Position(p[aCol+3], p[aCol+4]));
+ _margin = p[aCol+5];
+ _marginWt = p[aCol+6];
+
+ _seqClass = p[aCol+7];
+ _seqProxClass = p[aCol+8];
+ _seqOrder = p[aCol+9];
+ _seqAboveXoff = p[aCol+10];
+ _seqAboveWt = p[aCol+11];
+ _seqBelowXlim = p[aCol+12];
+ _seqBelowWt = p[aCol+13];
+ _seqValignHt = p[aCol+14];
+ _seqValignWt = p[aCol+15];
+
+ // These attributes do not have corresponding glyph attribute:
+ _exclGlyph = 0;
+ _exclOffset = Position(0, 0);
+}
+
+float SlotCollision::getKern(int dir) const
+{
+ if ((_flags & SlotCollision::COLL_KERN) != 0)
+ return float(_shift.x * ((dir & 1) ? -1 : 1));
+ else
+ return 0;
+}
+
diff -Nru graphite2-1.2.4/src/Decompressor.cpp graphite2-1.3.6/src/Decompressor.cpp
--- graphite2-1.2.4/src/Decompressor.cpp 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/Decompressor.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,113 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2015, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include
+
+#include "inc/Decompressor.h"
+#include "inc/Compression.h"
+
+using namespace lz4;
+
+namespace {
+
+inline
+u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
+ if (l == 15 && s != e)
+ {
+ u8 b = 0;
+ do { l += b = *s++; } while(b==0xff && s != e);
+ }
+ return l;
+}
+
+bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist)
+{
+ u8 const token = *src++;
+
+ literal_len = read_literal(src, end, token >> 4);
+ literal = src;
+ src += literal_len;
+
+ if (src > end - 2)
+ return false;
+
+ match_dist = *src++;
+ match_dist |= *src++ << 8;
+ match_len = read_literal(src, end, token & 0xf);
+
+ return src <= end-5;
+}
+
+}
+
+int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
+{
+ if (out_size <= in_size || in_size < sizeof(unsigned long)+1)
+ return -1;
+
+ u8 const * src = static_cast(in),
+ * literal = 0,
+ * const src_end = src + in_size;
+
+ u8 * dst = static_cast(out),
+ * const dst_end = dst + out_size;
+
+ u32 literal_len = 0,
+ match_len = 0,
+ match_dist = 0;
+
+ while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist))
+ {
+ if (literal_len != 0)
+ {
+ // Copy in literal. At this point the last full sequence must be at
+ // least MINMATCH + 5 from the end of the output buffer.
+ if (dst + align(literal_len) > dst_end - (MINMATCH+5))
+ return -1;
+ dst = overrun_copy(dst, literal, literal_len);
+ }
+
+ // Copy, possibly repeating, match from earlier in the
+ // decoded output.
+ u8 const * const pcpy = dst - match_dist;
+ if (pcpy < static_cast(out)
+ || dst + match_len + MINMATCH > dst_end - 5)
+ return -1;
+ if (dst > pcpy+sizeof(unsigned long)
+ && dst + align(match_len + MINMATCH) <= dst_end)
+ dst = overrun_copy(dst, pcpy, match_len + MINMATCH);
+ else
+ dst = safe_copy(dst, pcpy, match_len + MINMATCH);
+ }
+
+ if (literal + literal_len > src_end
+ || dst + literal_len > dst_end)
+ return -1;
+ dst = fast_copy(dst, literal, literal_len);
+
+ return dst - (u8*)out;
+}
+
diff -Nru graphite2-1.2.4/src/direct_machine.cpp graphite2-1.3.6/src/direct_machine.cpp
--- graphite2-1.2.4/src/direct_machine.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/direct_machine.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -61,6 +61,8 @@
const byte * data,
Machine::stack_t * stack,
slotref * & __map,
+ uint8 _dir,
+ Machine::status_t & status,
SlotMap * __smap=0)
{
// We need to define and return to opcode table from within this function
@@ -70,16 +72,17 @@
return opcode_table;
// Declare virtual machine registers
- const instr * ip = program;
- const byte * dp = data;
- Machine::stack_t * sp = stack + Machine::STACK_GUARD,
- * const sb = sp;
- SlotMap & smap = *__smap;
- Segment & seg = smap.segment;
- slotref is = *__map,
- * map = __map,
- * const mapb = smap.begin()+smap.context();
- int8 flags = 0;
+ const instr * ip = program;
+ const byte * dp = data;
+ Machine::stack_t * sp = stack + Machine::STACK_GUARD,
+ * const sb = sp;
+ SlotMap & smap = *__smap;
+ Segment & seg = smap.segment;
+ slotref is = *__map,
+ * map = __map,
+ * const mapb = smap.begin()+smap.context();
+ uint8 dir = _dir;
+ int8 flags = 0;
// start the program
goto **ip;
@@ -98,7 +101,8 @@
const opcode_t * Machine::getOpcodeTable() throw()
{
slotref * dummy;
- return static_cast(direct_run(true, 0, 0, 0, dummy, 0));
+ Machine::status_t dumstat = Machine::finished;
+ return static_cast(direct_run(true, 0, 0, 0, dummy, 0, dumstat));
}
@@ -109,7 +113,7 @@
assert(program != 0);
const stack_t *sp = static_cast(
- direct_run(false, program, data, _stack, is, &_map));
+ direct_run(false, program, data, _stack, is, _map.dir(), _status, &_map));
const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
check_final_stack(sp);
return ret;
diff -Nru graphite2-1.2.4/src/Face.cpp graphite2-1.3.6/src/Face.cpp
--- graphite2-1.2.4/src/Face.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/Face.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -28,6 +28,7 @@
#include "graphite2/Segment.h"
#include "inc/CmapCache.h"
#include "inc/debug.h"
+#include "inc/Decompressor.h"
#include "inc/Endian.h"
#include "inc/Face.h"
#include "inc/FileFace.h"
@@ -40,6 +41,16 @@
using namespace graphite2;
+namespace
+{
+enum compression
+{
+ NONE,
+ LZ4
+};
+
+}
+
Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
: m_appFaceHandle(appFaceHandle),
m_pFileFace(NULL),
@@ -84,20 +95,22 @@
telemetry::category _glyph_cat(tele.glyph);
#endif
error_context(EC_READGLYPHS);
- if (faceOptions & gr_face_cacheCmap)
- m_cmap = new CachedCmap(*this);
- else
- m_cmap = new DirectCmap(*this);
-
m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
+
if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
|| e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
- || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM)
- || e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
+ || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
{
return error(e);
}
+ if (faceOptions & gr_face_cacheCmap)
+ m_cmap = new CachedCmap(*this);
+ else
+ m_cmap = new DirectCmap(*this);
+ if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
+ return error(e);
+
if (faceOptions & gr_face_preloadGlyphs)
nameTable(); // preload the name table along with the glyphs.
@@ -112,17 +125,19 @@
Error e;
error_context(EC_READSILF);
const byte * p = silf;
- if (e.test(!p, E_NOSILF)) return error(e);
+ if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
const uint32 version = be::read(p);
if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
if (version >= 0x00030000)
be::skip(p); // compilerVersion
m_numSilf = be::read(p);
+
be::skip(p); // reserved
bool havePasses = false;
m_silfs = new Silf[m_numSilf];
+ if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
for (int i = 0; i < m_numSilf; i++)
{
error_context(EC_ASILF + (i << 8));
@@ -158,19 +173,28 @@
}
#endif
- bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true);
+// if ((seg->dir() & 1) != aSilf->dir())
+// seg->reverseSlots();
+ if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
+ seg->doMirror(aSilf->aMirror());
+ bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
if (res)
- res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
+ {
+ seg->associateChars(0, seg->charInfoCount());
+ if (aSilf->flags() & 0x20)
+ res &= seg->initCollisions();
+ res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
+ }
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
+ seg->positionSlots(0, 0, 0, aSilf->dir());
*dbgout << json::item
<< json::close // Close up the passes array
<< "output" << json::array;
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
- seg->finalise(0); // Call this here to fix up charinfo back indexes.
*dbgout << json::close
<< "advance" << seg->advance()
<< "chars" << json::array;
@@ -213,7 +237,9 @@
{
case kgmetAscent : return m_ascent;
case kgmetDescent : return m_descent;
- default: return glyphs().glyph(gid)->getMetric(metric);
+ default:
+ if (gid >= glyphs().numGlyphs()) return 0;
+ return glyphs().glyph(gid)->getMetric(metric);
}
}
@@ -245,17 +271,32 @@
return 0;
}
-Face::Table::Table(const Face & face, const Tag n) throw()
-: _f(&face)
+
+
+Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
+: _f(&face), _compressed(false)
{
size_t sz = 0;
- _p = reinterpret_cast((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
+ _p = static_cast((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
_sz = uint32(sz);
+
if (!TtfUtil::CheckTable(n, _p, _sz))
{
this->~Table(); // Make sure we release the table buffer even if the table filed it's checks
- _p = 0; _sz = 0;
+ return;
}
+
+ if (be::peek(_p) >= version)
+ decompress();
+}
+
+void Face::Table::releaseBuffers()
+{
+ if (_compressed)
+ free(const_cast(_p));
+ else if (_p && _f->m_ops.release_table)
+ (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
+ _p = 0; _sz = 0;
}
Face::Table & Face::Table::operator = (const Table & rhs) throw()
@@ -267,3 +308,58 @@
return *this;
}
+Error Face::Table::decompress()
+{
+ Error e;
+ if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
+ return e;
+ byte * uncompressed_table = 0;
+ size_t uncompressed_size = 0;
+
+ const byte * p = _p;
+ const uint32 version = be::read(p); // Table version number.
+
+ // The scheme is in the top 5 bits of the 1st uint32.
+ const uint32 hdr = be::read(p);
+ switch(compression(hdr >> 27))
+ {
+ case NONE: return e;
+
+ case LZ4:
+ {
+ uncompressed_size = hdr & 0x07ffffff;
+ uncompressed_table = gralloc(uncompressed_size);
+ if (!e.test(!uncompressed_table, E_OUTOFMEM))
+ // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
+ // coverity[checked_return : FALSE] - we test e later
+ e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
+ break;
+ }
+
+ default:
+ e.error(E_BADSCHEME);
+ };
+
+ // Check the uncompressed version number against the original.
+ if (!e)
+ // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
+ // coverity[checked_return : FALSE] - we test e later
+ e.test(be::peek(uncompressed_table) != version, E_SHRINKERFAILED);
+
+ // Tell the provider to release the compressed form since were replacing
+ // it anyway.
+ releaseBuffers();
+
+ if (e)
+ {
+ free(uncompressed_table);
+ uncompressed_table = 0;
+ uncompressed_size = 0;
+ }
+
+ _p = uncompressed_table;
+ _sz = uncompressed_size;
+ _compressed = true;
+
+ return e;
+}
diff -Nru graphite2-1.2.4/src/FeatureMap.cpp graphite2-1.3.6/src/FeatureMap.cpp
--- graphite2-1.2.4/src/FeatureMap.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/FeatureMap.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -131,11 +131,12 @@
const uint16 num_settings = be::read(p);
if (version >= 0x00020000)
be::skip(p);
- const byte * const feat_setts = feat_start + be::read(p);
+ const uint32 settings_offset = be::read(p);
const uint16 flags = be::read(p),
uiName = be::read(p);
- if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end)
+ if (settings_offset > size_t(feat_end - feat_start)
+ || settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start))
{
free(defVals);
return false;
@@ -151,7 +152,7 @@
free(defVals);
return false;
}
- maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
+ maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings);
defVals[i] = uiSet[0].value();
}
else
@@ -165,16 +166,16 @@
label, uiName, flags,
uiSet, num_settings);
}
- m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
+ new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
- if (!m_defaultFeatures || !m_pNamedFeats)
+ if (!m_pNamedFeats)
{
free(defVals);
return false;
}
for (int i = 0; i < m_numFeats; ++i)
{
- m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
+ m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
m_pNamedFeats[i] = m_feats+i;
}
@@ -214,7 +215,7 @@
uint16 numSettings = be::read(p);
uint16 offset = be::read(p);
if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
- Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
+ Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
if (!feats) return false;
const byte *pLSet = sill + offset;
@@ -250,7 +251,7 @@
return new Features(*m_langFeats[i].m_pFeatures);
}
}
- return new Features (*m_FeatureMap.m_defaultFeatures);
+ return new Features (m_FeatureMap.m_defaultFeatures);
}
diff -Nru graphite2-1.2.4/src/FileFace.cpp graphite2-1.3.6/src/FileFace.cpp
--- graphite2-1.2.4/src/FileFace.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/FileFace.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -60,8 +60,12 @@
if (!TtfUtil::GetTableDirInfo(_header_tbl, tbl_offset, tbl_len)) return;
_table_dir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc(tbl_len);
if (fseek(_file, tbl_offset, SEEK_SET)) return;
- if (_table_dir)
- if (fread(_table_dir, 1, tbl_len, _file) != tbl_len) return;
+ if (_table_dir && fread(_table_dir, 1, tbl_len, _file) != tbl_len)
+ {
+ free(_table_dir);
+ _table_dir = NULL;
+ }
+ return;
}
FileFace::~FileFace()
@@ -83,7 +87,7 @@
if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len))
return 0;
- if (tbl_offset + tbl_len > file_face._file_len
+ if (tbl_offset > file_face._file_len || tbl_len > file_face._file_len - tbl_offset
|| fseek(file_face._file, tbl_offset, SEEK_SET) != 0)
return 0;
diff -Nru graphite2-1.2.4/src/files.mk graphite2-1.3.6/src/files.mk
--- graphite2-1.2.4/src/files.mk 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/files.mk 2016-02-29 04:18:01.000000000 +0000
@@ -47,19 +47,22 @@
$($(_NS)_BASE)/src/gr_segment.cpp \
$($(_NS)_BASE)/src/gr_slot.cpp \
$($(_NS)_BASE)/src/json.cpp \
- $($(_NS)_BASE)/src/Bidi.cpp \
$($(_NS)_BASE)/src/CachedFace.cpp \
$($(_NS)_BASE)/src/CmapCache.cpp \
$($(_NS)_BASE)/src/Code.cpp \
+ $($(_NS)_BASE)/src/Collider.cpp \
+ $($(_NS)_BASE)/src/Decompressor.cpp \
$($(_NS)_BASE)/src/Face.cpp \
$($(_NS)_BASE)/src/FeatureMap.cpp \
$($(_NS)_BASE)/src/FileFace.cpp \
$($(_NS)_BASE)/src/Font.cpp \
$($(_NS)_BASE)/src/GlyphCache.cpp \
$($(_NS)_BASE)/src/GlyphFace.cpp \
+ $($(_NS)_BASE)/src/Intervals.cpp \
$($(_NS)_BASE)/src/Justifier.cpp \
$($(_NS)_BASE)/src/NameTable.cpp \
$($(_NS)_BASE)/src/Pass.cpp \
+ $($(_NS)_BASE)/src/Position.cpp \
$($(_NS)_BASE)/src/SegCache.cpp \
$($(_NS)_BASE)/src/SegCacheEntry.cpp \
$($(_NS)_BASE)/src/SegCacheStore.cpp \
@@ -78,6 +81,9 @@
$($(_NS)_BASE)/src/inc/CharInfo.h \
$($(_NS)_BASE)/src/inc/CmapCache.h \
$($(_NS)_BASE)/src/inc/Code.h \
+ $($(_NS)_BASE)/src/inc/Collider.h \
+ $($(_NS)_BASE)/src/inc/Compression.h \
+ $($(_NS)_BASE)/src/inc/Decompressor.h \
$($(_NS)_BASE)/src/inc/Endian.h \
$($(_NS)_BASE)/src/inc/Error.h \
$($(_NS)_BASE)/src/inc/Face.h \
@@ -87,6 +93,7 @@
$($(_NS)_BASE)/src/inc/Font.h \
$($(_NS)_BASE)/src/inc/GlyphCache.h \
$($(_NS)_BASE)/src/inc/GlyphFace.h \
+ $($(_NS)_BASE)/src/inc/Intervals.h \
$($(_NS)_BASE)/src/inc/List.h \
$($(_NS)_BASE)/src/inc/locale2lcid.h \
$($(_NS)_BASE)/src/inc/Machine.h \
diff -Nru graphite2-1.2.4/src/GlyphCache.cpp graphite2-1.3.6/src/GlyphCache.cpp
--- graphite2-1.2.4/src/GlyphCache.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/GlyphCache.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -31,6 +31,7 @@
#include "inc/GlyphCache.h"
#include "inc/GlyphFace.h"
#include "inc/Endian.h"
+#include "inc/bits.h"
using namespace graphite2;
@@ -61,7 +62,7 @@
// This is strictly a >= operator. A true == operator could be
// implemented that test for overlap but it would be more expensive a
// test.
- bool operator == (const _glat_iterator & rhs) { return _v >= rhs._e; }
+ bool operator == (const _glat_iterator & rhs) { return _v >= rhs._e - 1; }
bool operator != (const _glat_iterator & rhs) { return !operator==(rhs); }
value_type operator * () const {
@@ -70,13 +71,15 @@
protected:
const byte * _e, * _v;
- ptrdiff_t _n;
+ size_t _n;
};
typedef _glat_iterator glat_iterator;
typedef _glat_iterator glat2_iterator;
}
+const SlantBox SlantBox::empty = {0,0,0,0};
+
class GlyphCache::Loader
{
@@ -87,8 +90,10 @@
unsigned short int units_per_em() const throw();
unsigned short int num_glyphs() const throw();
unsigned short int num_attrs() const throw();
+ bool has_boxes() const throw();
- const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
+ const GlyphFace * read_glyph(unsigned short gid, GlyphFace &, int *numsubs) const throw();
+ GlyphBox * read_box(uint16 gid, GlyphBox *curr, const GlyphFace & face) const throw();
CLASS_NEW_DELETE;
private:
@@ -101,6 +106,7 @@
m_pGloc;
bool _long_fmt;
+ bool _has_boxes;
unsigned short _num_glyphs_graphics, //i.e. boundary box and advance
_num_glyphs_attributes,
_num_attrs; // number of glyph attributes per glyph
@@ -111,31 +117,49 @@
GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
: _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
_glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc(_glyph_loader->num_glyphs()) : 0),
+ _boxes(_glyph_loader && _glyph_loader->has_boxes() ? grzeroalloc(_glyph_loader->num_glyphs()) : 0),
_num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
_num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
_upem(_glyphs ? _glyph_loader->units_per_em() : 0)
{
if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
{
+ int numsubs = 0;
GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
if (!glyphs)
return;
// The 0 glyph is definately required.
- _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
+ _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
// glyphs[0] has the same address as the glyphs array just allocated,
// thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
// to the entire array.
const GlyphFace * loaded = _glyphs[0];
for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
- _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
+ _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
if (!loaded)
{
_glyphs[0] = 0;
delete [] glyphs;
}
+ else if (numsubs > 0)
+ {
+ GlyphBox * boxes = (GlyphBox *)gralloc(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
+ GlyphBox * currbox = boxes;
+
+ for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
+ {
+ _boxes[gid] = currbox;
+ currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
+ }
+ if (!currbox)
+ {
+ free(boxes);
+ _boxes[0] = 0;
+ }
+ }
delete _glyph_loader;
_glyph_loader = 0;
}
@@ -144,6 +168,11 @@
{
free(_glyphs);
_glyphs = 0;
+ if (_boxes)
+ {
+ free(_boxes);
+ _boxes = 0;
+ }
_num_glyphs = _num_attrs = _upem = 0;
}
}
@@ -163,6 +192,18 @@
delete [] _glyphs[0];
free(_glyphs);
}
+ if (_boxes)
+ {
+ if (_glyph_loader)
+ {
+ GlyphBox * * g = _boxes;
+ for (uint16 n = _num_glyphs; n; --n, ++g)
+ free(*g);
+ }
+ else
+ free(_boxes[0]);
+ free(_boxes);
+ }
delete _glyph_loader;
}
@@ -171,13 +212,23 @@
const GlyphFace * & p = _glyphs[glyphid];
if (p == 0 && _glyph_loader)
{
+ int numsubs = 0;
GlyphFace * g = new GlyphFace();
- if (g) p = _glyph_loader->read_glyph(glyphid, *g);
+ if (g) p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
if (!p)
{
delete g;
return *_glyphs;
}
+ if (_boxes)
+ {
+ _boxes[glyphid] = (GlyphBox *)gralloc(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
+ if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
+ {
+ free(_boxes[glyphid]);
+ _boxes[glyphid] = 0;
+ }
+ }
}
return p;
}
@@ -191,6 +242,7 @@
_glyf(face, Tag::glyf),
_loca(face, Tag::loca),
_long_fmt(false),
+ _has_boxes(false),
_num_glyphs_graphics(0),
_num_glyphs_attributes(0),
_num_attrs(0)
@@ -203,7 +255,7 @@
_num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
// This will fail if the number of glyphs is wildly out of range.
- if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
+ if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
{
_head = Face::Table();
return;
@@ -211,33 +263,49 @@
if (!dumb_font)
{
- if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
+ if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
|| (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
- || m_pGloc.size() < 6)
+ || m_pGloc.size() < 8)
{
_head = Face::Table();
return;
}
const byte * p = m_pGloc;
- const int version = be::read(p);
+ int version = be::read(p);
const uint16 flags = be::read(p);
_num_attrs = be::read(p);
// We can accurately calculate the number of attributed glyphs by
// subtracting the length of the attribids array (numAttribs long if present)
// and dividing by either 2 or 4 depending on shor or lonf format
_long_fmt = flags & 1;
- _num_glyphs_attributes = (m_pGloc.size()
+ int tmpnumgattrs = (m_pGloc.size()
- (p - m_pGloc)
- sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
/ (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
- if (version != 0x00010000
+ if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
|| _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
- || _num_glyphs_graphics > _num_glyphs_attributes)
+ || _num_glyphs_graphics > tmpnumgattrs)
+ {
+ _head = Face::Table();
+ return;
+ }
+
+ _num_glyphs_attributes = static_cast(tmpnumgattrs);
+ p = m_pGlat;
+ version = be::read(p);
+ if (version >= 0x00040000) // reject Glat tables that are too new
{
_head = Face::Table();
return;
}
+ else if (version >= 0x00030000)
+ {
+ unsigned int glatflags = be::read(p);
+ _has_boxes = glatflags & 1;
+ // delete this once the compiler is fixed
+ _has_boxes = true;
+ }
}
}
@@ -265,7 +333,13 @@
return _num_attrs;
}
-const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
+inline
+bool GlyphCache::Loader::has_boxes () const throw()
+{
+ return _has_boxes;
+}
+
+const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
{
Rect bbox;
Position advance;
@@ -281,8 +355,12 @@
void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
+ {
+ if ((xMin > xMax) || (yMin > yMax))
+ return 0;
bbox = Rect(Position(static_cast(xMin), static_cast(yMin)),
Position(static_cast(xMax), static_cast(yMax)));
+ }
}
if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
advance = Position(static_cast(nAdvWid), 0);
@@ -312,30 +390,90 @@
return 0;
const uint32 glat_version = be::peek(m_pGlat);
+ if (glat_version == 0x00030000)
+ {
+ const byte * p = m_pGlat + glocs;
+ uint16 bmap = be::read(p);
+ int num = bit_set_count((uint32)bmap);
+ if (numsubs) *numsubs += num;
+ glocs += 6 + 8 * num;
+ if (glocs > gloce)
+ return 0;
+ }
if (glat_version < 0x00020000)
{
if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
|| gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
- {
- return 0;
- }
-
+ return 0;
new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
}
else
{
- if (gloce - glocs < 3*sizeof(uint16)
- || gloce - glocs > _num_attrs*3*sizeof(uint16))
- {
- return 0;
- }
-
+ if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not?
+ || gloce - glocs > _num_attrs*3*sizeof(uint16)
+ || glocs > m_pGlat.size() - 2*sizeof(uint16))
+ return 0;
new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
}
-
if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
return 0;
}
-
return &glyph;
}
+
+inline float scale_to(uint8 t, float zmin, float zmax)
+{
+ return (zmin + t * (zmax - zmin) / 255);
+}
+
+Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
+{
+ return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
+ Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
+}
+
+GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
+{
+ if (gid >= _num_glyphs_attributes) return 0;
+
+ const byte * gloc = m_pGloc;
+ size_t glocs = 0, gloce = 0;
+
+ be::skip(gloc);
+ be::skip(gloc,2);
+ if (_long_fmt)
+ {
+ be::skip(gloc, gid);
+ glocs = be::read(gloc);
+ gloce = be::peek(gloc);
+ }
+ else
+ {
+ be::skip(gloc, gid);
+ glocs = be::read(gloc);
+ gloce = be::peek(gloc);
+ }
+
+ if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
+ return 0;
+
+ const byte * p = m_pGlat + glocs;
+ uint16 bmap = be::read(p);
+ int num = bit_set_count((uint32)bmap);
+
+ Rect bbox = glyph.theBBox();
+ Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
+ Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
+ Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
+ ::new (curr) GlyphBox(num, bmap, &diabound);
+ be::skip(p, 4);
+
+ for (int i = 0; i < num * 2; ++i)
+ {
+ Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
+ curr->addSubBox(i >> 1, i & 1, &box);
+ be::skip(p, 4);
+ }
+ return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
+}
+
diff -Nru graphite2-1.2.4/src/gr_face.cpp graphite2-1.3.6/src/gr_face.cpp
--- graphite2-1.2.4/src/gr_face.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/gr_face.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -46,7 +46,7 @@
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _misc_cat(face.tele.misc);
#endif
- Face::Table silf(face, Tag::Silf);
+ Face::Table silf(face, Tag::Silf, 0x00050000);
if (silf) options &= ~gr_face_dumbRendering;
else if (!(options & gr_face_dumbRendering))
return false;
diff -Nru graphite2-1.2.4/src/gr_logging.cpp graphite2-1.3.6/src/gr_logging.cpp
--- graphite2-1.2.4/src/gr_logging.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/gr_logging.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -32,6 +32,7 @@
#include "inc/Slot.h"
#include "inc/Segment.h"
#include "inc/json.h"
+#include "inc/Collider.h"
#if defined _WIN32
#include "windows.h"
@@ -184,6 +185,7 @@
assert(ds.second);
const Segment & seg = *ds.first;
const Slot & s = *ds.second;
+ const SlotCollision *cslot = seg.collisionInfo(ds.second);
j << json::object
<< "id" << objectid(ds)
@@ -220,6 +222,28 @@
j << objectid(dslot(&seg, c));
j << json::close;
}
+ if (cslot)
+ {
+ // Note: the reason for using Positions to lump together related attributes is to make the
+ // JSON output slightly more compact.
+ j << "collision" << json::flat << json::object
+// << "shift" << cslot->shift() -- not used pass level, only within the collision routine itself
+ << "offset" << cslot->offset()
+ << "limit" << cslot->limit()
+ << "flags" << cslot->flags()
+ << "margin" << Position(cslot->margin(), cslot->marginWt())
+ << "exclude" << cslot->exclGlyph()
+ << "excludeoffset" << cslot->exclOffset();
+ if (cslot->seqOrder() != 0)
+ {
+ j << "seqclass" << Position(cslot->seqClass(), cslot->seqProxClass())
+ << "seqorder" << cslot->seqOrder()
+ << "seqabove" << Position(cslot->seqAboveXoff(), cslot->seqAboveWt())
+ << "seqbelow" << Position(cslot->seqBelowXlim(), cslot->seqBelowWt())
+ << "seqvalign" << Position(cslot->seqValignHt(), cslot->seqValignWt());
+ }
+ j << json::close;
+ }
return j << json::close;
}
diff -Nru graphite2-1.2.4/src/gr_segment.cpp graphite2-1.3.6/src/gr_segment.cpp
--- graphite2-1.2.4/src/gr_segment.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/gr_segment.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -48,11 +48,7 @@
delete pRes;
return NULL;
}
- // run the line break passes
- // run the substitution passes
- pRes->prepare_pos(font);
- // run the positioning passes
- pRes->finalise(font);
+ pRes->finalise(font, true);
return static_cast(pRes);
}
diff -Nru graphite2-1.2.4/src/gr_slot.cpp graphite2-1.3.6/src/gr_slot.cpp
--- graphite2-1.2.4/src/gr_slot.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/gr_slot.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -103,11 +103,11 @@
return res;
}
-float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, const gr_face *face, const gr_font *font)
+float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, GR_MAYBE_UNUSED const gr_face *face, const gr_font *font)
{
assert(p);
float res = p->advancePos().y;
- if (font && (face || !face))
+ if (font)
return res * font->scale();
else
return res;
diff -Nru graphite2-1.2.4/src/inc/Bidi.h graphite2-1.3.6/src/inc/Bidi.h
--- graphite2-1.2.4/src/inc/Bidi.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Bidi.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,126 +0,0 @@
-/* GRAPHITE2 LICENSING
-
- Copyright 2013, SIL International
- All rights reserved.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should also have received a copy of the GNU Lesser General Public
- License along with this library in the file named "LICENSE".
- If not, write to the Free Software Foundation, 51 Franklin Street,
- Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
- internet at http://www.fsf.org/licenses/lgpl.html.
-
-Alternatively, the contents of this file may be used under the terms of the
-Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
-License, as published by the Free Software Foundation, either version 2
-of the License or (at your option) any later version.
-*/
-#pragma once
-
-namespace graphite2
-{
-
-class BracketPair
-{
-public:
- BracketPair(uint16 g, Slot *s, uint8 b, BracketPair *p, BracketPair *l) : _open(s), _close(0), _parent(p), _next(0), _prev(l), _gid(g), _mask(0), _before(b) {};
- uint16 gid() const { return _gid; }
- Slot *open() const { return _open; }
- Slot *close() const { return _close; }
- uint8 mask() const { return _mask; }
- int8 before() const { return _before; }
- BracketPair *parent() const { return _parent; }
- void close(Slot *s) { _close = s; }
- BracketPair *next() const { return _next; }
- BracketPair *prev() const { return _prev; }
- void next(BracketPair *n) { _next = n; }
- void orin(uint8 m) { _mask |= m; }
-private:
- Slot * _open; // Slot of opening paren
- Slot * _close; // Slot of closing paren
- BracketPair * _parent; // pair this pair is in or NULL
- BracketPair * _next; // next pair along the string
- BracketPair * _prev; // pair that closed last before we opened
- uint16 _gid; // gid of closing paren
- uint8 _mask; // bitmap (2 bits) of directions within the pair
- int8 _before; // most recent strong type (L, R, OPP, CPP)
-};
-
-class BracketPairStack
-{
-public:
- BracketPairStack(int s) : _stack(grzeroalloc(s)), _ip(_stack - 1), _top(0), _last(0), _lastclose(0), _size(s) {}
- ~BracketPairStack() { free(_stack); }
-
-public:
- BracketPair *scan(uint16 gid);
- void close(BracketPair *tos, Slot *s);
- BracketPair *push(uint16 gid, Slot *pos, uint8 before, int prevopen);
- void orin(uint8 mask);
- void clear() { _ip = _stack - 1; _top = 0; _last = 0; _lastclose = 0; }
- int size() const { return _size; }
- BracketPair *start() const { return _stack; }
-
- CLASS_NEW_DELETE
-
-private:
-
- BracketPair *_stack; // start of storage
- BracketPair *_ip; // where to add the next pair
- BracketPair *_top; // current parent
- BracketPair *_last; // end of next() chain
- BracketPair *_lastclose; // last pair to close
- int _size; // capacity
-};
-
-inline BracketPair *BracketPairStack::scan(uint16 gid)
-{
- BracketPair *res = _top;
- while (res >= _stack)
- {
- if (res->gid() == gid)
- return res;
- res = res->parent();
- }
- return 0;
-}
-
-inline void BracketPairStack::close(BracketPair *tos, Slot *s)
-{
- for ( ; _last && _last != tos && !_last->close(); _last = _last->parent())
- { }
- tos->close(s);
- _last->next(NULL);
- _lastclose = tos;
- _top = tos->parent();
-}
-
-inline BracketPair *BracketPairStack::push(uint16 gid, Slot *pos, uint8 before, int prevopen)
-{
- if (++_ip - _stack < _size && _stack)
- {
- ::new (_ip) BracketPair(gid, pos, before, _top, prevopen ? _last : _lastclose);
- if (_last) _last->next(_ip);
- _last = _ip;
- }
- _top = _ip;
- return _ip;
-}
-
-inline void BracketPairStack::orin(uint8 mask)
-{
- BracketPair *t = _top;
- for ( ; t; t = t->parent())
- t->orin(mask);
-}
-
-}
diff -Nru graphite2-1.2.4/src/inc/bits.h graphite2-1.3.6/src/inc/bits.h
--- graphite2-1.2.4/src/inc/bits.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/bits.h 2016-02-29 04:18:01.000000000 +0000
@@ -29,15 +29,63 @@
namespace graphite2
{
+
+#if defined GRAPHITE2_BUILTINS && (defined __GNUC__ || defined __clang__)
+
template
inline unsigned int bit_set_count(T v)
{
- v = v - ((v >> 1) & T(~T(0)/3)); // temp
- v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3)); // temp
- v = (v + (v >> 4)) & T(~T(0)/255*15); // temp
- return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8; // count
+ return __builtin_popcount(v);
+}
+
+template<>
+inline unsigned int bit_set_count(int16 v)
+{
+ return __builtin_popcount(static_cast(v));
+}
+
+template<>
+inline unsigned int bit_set_count(int8 v)
+{
+ return __builtin_popcount(static_cast(v));
}
+template<>
+inline unsigned int bit_set_count(unsigned long v)
+{
+ return __builtin_popcountl(v);
+}
+
+template<>
+inline unsigned int bit_set_count(signed long v)
+{
+ return __builtin_popcountl(v);
+}
+
+template<>
+inline unsigned int bit_set_count(unsigned long long v)
+{
+ return __builtin_popcountll(v);
+}
+
+template<>
+inline unsigned int bit_set_count(signed long long v)
+{
+ return __builtin_popcountll(v);
+}
+#else
+
+template
+inline unsigned int bit_set_count(T v)
+{
+ v = v - ((v >> 1) & T(~(0UL)/3)); // temp
+ v = (v & T(~(0UL)/15*3)) + ((v >> 2) & T(~(0UL)/15*3)); // temp
+ v = (v + (v >> 4)) & T(~(0UL)/255*15); // temp
+ return (T)(v * T(~(0UL)/255)) >> (sizeof(T)-1)*8; // count
+}
+
+#endif
+
template
inline unsigned long _mask_over_val(unsigned long v)
@@ -87,4 +135,12 @@
return T((has_zero(x^t) >> 7)*n);
}
+#if 0
+inline float float_round(float x, uint32 m)
+{
+ *reinterpret_cast(&x) &= m;
+ return *reinterpret_cast(&x);
+}
+#endif
+
}
diff -Nru graphite2-1.2.4/src/inc/Code.h graphite2-1.3.6/src/inc/Code.h
--- graphite2-1.2.4/src/inc/Code.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Code.h 2016-02-29 04:18:01.000000000 +0000
@@ -41,6 +41,14 @@
class Silf;
class Face;
+enum passtype {
+ PASS_TYPE_UNKNOWN = 0,
+ PASS_TYPE_LINEBREAK,
+ PASS_TYPE_SUBSTITUTE,
+ PASS_TYPE_POSITIONING,
+ PASS_TYPE_JUSTIFICATION
+};
+
namespace vm {
class Machine::Code
@@ -56,7 +64,8 @@
jump_past_end,
arguments_exhausted,
missing_return,
- nested_context_item
+ nested_context_item,
+ underfull_stack
};
private:
@@ -77,30 +86,41 @@
void failure(const status_t) throw();
public:
+ static size_t estimateCodeDataOut(size_t num_bytecodes);
+
Code() throw();
Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
- uint8 pre_context, uint16 rule_length, const Silf &, const Face &);
+ uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
+ enum passtype pt, byte * * const _out = 0);
Code(const Machine::Code &) throw();
~Code() throw();
Code & operator=(const Code &rhs) throw();
- operator bool () const throw();
- status_t status() const throw();
- bool constraint() const throw();
- size_t dataSize() const throw();
- size_t instructionCount() const throw();
- bool immutable() const throw();
- bool deletes() const throw();
- size_t maxRef() const throw();
+ operator bool () const throw() { return _code && status() == loaded; }
+ status_t status() const throw() { return _status; }
+ bool constraint() const throw() { return _constraint; }
+ size_t dataSize() const throw() { return _data_size; }
+ size_t instructionCount() const throw() { return _instr_count; }
+ bool immutable() const throw() { return !(_delete || _modify); }
+ bool deletes() const throw() { return _delete; }
+ size_t maxRef() const throw() { return _max_ref; }
+ void externalProgramMoved(ptrdiff_t) throw();
int32 run(Machine &m, slotref * & map) const;
CLASS_NEW_DELETE;
};
+inline
+size_t Machine::Code::estimateCodeDataOut(size_t n_bc)
+{
+ return (n_bc + 1) * (sizeof(instr)+sizeof(byte));
+}
+
+
inline Machine::Code::Code() throw()
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
- _status(loaded), _constraint(false), _modify(false),_delete(false),
+ _status(loaded), _constraint(false), _modify(false), _delete(false),
_own(false)
{
}
@@ -136,39 +156,13 @@
return *this;
}
-inline Machine::Code::operator bool () const throw () {
- return _code && status() == loaded;
-}
-
-inline Machine::Code::status_t Machine::Code::status() const throw() {
- return _status;
-}
-
-inline bool Machine::Code::constraint() const throw() {
- return _constraint;
-}
-
-inline size_t Machine::Code::dataSize() const throw() {
- return _data_size;
-}
-
-inline size_t Machine::Code::instructionCount() const throw() {
- return _instr_count;
-}
-
-inline bool Machine::Code::immutable() const throw()
-{
- return !(_delete || _modify);
-}
-
-inline bool Machine::Code::deletes() const throw()
-{
- return _delete;
-}
-
-inline size_t Machine::Code::maxRef() const throw()
+inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
- return _max_ref;
+ if (_code && !_own)
+ {
+ _code += dist / sizeof(instr);
+ _data += dist;
+ }
}
} // namespace vm
diff -Nru graphite2-1.2.4/src/inc/Collider.h graphite2-1.3.6/src/inc/Collider.h
--- graphite2-1.2.4/src/inc/Collider.h 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/inc/Collider.h 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,242 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2010, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "inc/List.h"
+#include "inc/Position.h"
+#include "inc/Intervals.h"
+#include "inc/debug.h"
+
+namespace graphite2 {
+
+class json;
+class Slot;
+class Segment;
+
+#define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; }
+#define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; }
+#define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; }
+
+// Slot attributes related to collision-fixing
+class SlotCollision
+{
+public:
+ enum {
+ // COLL_TESTONLY = 0, // default - test other glyphs for collision with this one, but don't move this one
+ COLL_FIX = 1, // fix collisions involving this glyph
+ COLL_IGNORE = 2, // ignore this glyph altogether
+ COLL_START = 4, // start of range of possible collisions
+ COLL_END = 8, // end of range of possible collisions
+ COLL_KERN = 16, // collisions with this glyph are fixed by adding kerning space after it
+ COLL_ISCOL = 32, // this glyph has a collision
+ COLL_KNOWN = 64, // we've figured out what's happening with this glyph
+ COLL_TEMPLOCK = 128, // Lock glyphs that have been given priority positioning
+ ////COLL_JUMPABLE = 128, // moving glyphs may jump this stationary glyph in any direction - DELETE
+ ////COLL_OVERLAP = 256, // use maxoverlap to restrict - DELETE
+ };
+
+ // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
+ // Allows for easier inversion.
+ enum {
+ SEQ_ORDER_LEFTDOWN = 1,
+ SEQ_ORDER_RIGHTUP = 2,
+ SEQ_ORDER_NOABOVE = 4,
+ SEQ_ORDER_NOBELOW = 8,
+ SEQ_ORDER_NOLEFT = 16,
+ SEQ_ORDER_NORIGHT = 32
+ };
+
+ SlotCollision(Segment *seg, Slot *slot);
+ void initFromSlot(Segment *seg, Slot *slot);
+
+ const Rect &limit() const { return _limit; }
+ void setLimit(const Rect &r) { _limit = r; }
+ SLOTCOLSETPOSITIONPROP(shift, setShift)
+ SLOTCOLSETPOSITIONPROP(offset, setOffset)
+ SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset)
+ SLOTCOLSETUINTPROP(margin, setMargin)
+ SLOTCOLSETUINTPROP(marginWt, setMarginWt)
+ SLOTCOLSETUINTPROP(flags, setFlags)
+ SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph)
+ SLOTCOLSETUINTPROP(seqClass, setSeqClass)
+ SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass)
+ SLOTCOLSETUINTPROP(seqOrder, setSeqOrder)
+ SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
+ SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
+ SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
+ SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
+ SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
+ SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
+
+ float getKern(int dir) const;
+
+private:
+ Rect _limit;
+ Position _shift; // adjustment within the given pass
+ Position _offset; // total adjustment for collisions
+ Position _exclOffset;
+ uint16 _margin;
+ uint16 _marginWt;
+ uint16 _flags;
+ uint16 _exclGlyph;
+ uint16 _seqClass;
+ uint16 _seqProxClass;
+ uint16 _seqOrder;
+ int16 _seqAboveXoff;
+ uint16 _seqAboveWt;
+ int16 _seqBelowXlim;
+ uint16 _seqBelowWt;
+ uint16 _seqValignHt;
+ uint16 _seqValignWt;
+
+}; // end of class SlotColllision
+
+struct BBox;
+struct SlantBox;
+
+class ShiftCollider
+{
+public:
+ typedef std::pair fpair;
+ typedef Vector vfpairs;
+ typedef vfpairs::iterator ivfpairs;
+
+ ShiftCollider(json *dbgout);
+ ~ShiftCollider() throw() { };
+
+ bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
+ float margin, float marginMin, const Position &currShift,
+ const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout);
+ bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, bool isAfter,
+ bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
+ Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
+ void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode);
+ void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode);
+ const Position &origin() const { return _origin; }
+
+#if !defined GRAPHITE2_NTRACING
+ void outputJsonDbg(json * const dbgout, Segment *seg, int axis);
+ void outputJsonDbgStartSlot(json * const dbgout, Segment *seg);
+ void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol);
+ void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal);
+ void outputJsonDbgRawRanges(json * const dbgout, int axis);
+ void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg);
+#endif
+
+ CLASS_NEW_DELETE;
+
+protected:
+ Zones _ranges[4]; // possible movements in 4 directions (horizontally, vertically, diagonally);
+ Slot * _target; // the glyph to fix
+ Rect _limit;
+ Position _currShift;
+ Position _currOffset;
+ Position _origin; // Base for all relative calculations
+ float _margin;
+ float _marginWt;
+ float _len[4];
+ uint16 _seqClass;
+ uint16 _seqProxClass;
+ uint16 _seqOrder;
+
+ //bool _scraping[4];
+
+}; // end of class ShiftCollider
+
+inline
+ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
+: _target(0),
+ _margin(0.0),
+ _marginWt(0.0),
+ _seqClass(0),
+ _seqProxClass(0),
+ _seqOrder(0)
+{
+#if !defined GRAPHITE2_NTRACING
+ for (int i = 0; i < 4; ++i)
+ _ranges[i].setdebug(dbgout);
+#endif
+}
+
+class KernCollider
+{
+public:
+ KernCollider(json *dbg);
+ ~KernCollider() throw() { };
+ bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
+ const Position &currShift, const Position &offsetPrev, int dir,
+ float ymin, float ymax, json * const dbgout);
+ bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
+ Position resolve(Segment *seg, Slot *slot, int dir, float margin, json * const dbgout);
+ void shift(const Position &mv, int dir);
+
+ CLASS_NEW_DELETE;
+
+private:
+ Slot * _target; // the glyph to fix
+ Rect _limit;
+ float _margin;
+ Position _offsetPrev; // kern from a previous pass
+ Position _currShift; // NOT USED??
+ float _miny; // y-coordinates offset by global slot position
+ float _maxy;
+ Vector _edges; // edges of horizontal slices
+ float _sliceWidth; // width of each slice
+ float _mingap;
+ float _xbound; // max or min edge
+
+#if !defined GRAPHITE2_NTRACING
+ // Debugging
+ Segment * _seg;
+ Vector _nearEdges; // closest potential collision in each slice
+ Vector _slotNear;
+#endif
+}; // end of class KernCollider
+
+
+inline
+float sqr(float x) {
+ return x * x;
+}
+
+inline
+KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
+: _target(0),
+ _margin(0.0f),
+ _miny(-1e38f),
+ _maxy(1e38f),
+ _sliceWidth(0.0f),
+ _mingap(0.0f),
+ _xbound(0.0)
+{
+#if !defined GRAPHITE2_NTRACING
+ _seg = 0;
+#endif
+};
+
+}; // end of namespace graphite2
+
diff -Nru graphite2-1.2.4/src/inc/Compression.h graphite2-1.3.6/src/inc/Compression.h
--- graphite2-1.2.4/src/inc/Compression.h 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/inc/Compression.h 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,103 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2015, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace
+{
+
+#if defined(_MSC_VER)
+typedef unsigned __int8 u8;
+typedef unsigned __int16 u16;
+typedef unsigned __int32 u32;
+typedef unsigned __int64 u64;
+#else
+#include
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+#endif
+
+ptrdiff_t const MINMATCH = 4;
+
+template
+inline
+void unaligned_copy(void * d, void const * s) {
+ ::memcpy(d, s, S);
+}
+
+inline
+size_t align(size_t p) {
+ return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1);
+}
+
+inline
+u8 * safe_copy(u8 * d, u8 const * s, size_t n) {
+ while (n--) *d++ = *s++;
+ return d;
+}
+
+inline
+u8 * overrun_copy(u8 * d, u8 const * s, size_t n) {
+ size_t const WS = sizeof(unsigned long);
+ u8 const * e = s + n;
+ do
+ {
+ unaligned_copy(d, s);
+ d += WS;
+ s += WS;
+ }
+ while (s < e);
+ d-=(s-e);
+
+ return d;
+}
+
+
+inline
+u8 * fast_copy(u8 * d, u8 const * s, size_t n) {
+ size_t const WS = sizeof(unsigned long);
+ size_t wn = n/WS;
+ while (wn--)
+ {
+ unaligned_copy(d, s);
+ d += WS;
+ s += WS;
+ }
+ n &= WS-1;
+ return safe_copy(d, s, n);
+}
+
+
+} // end of anonymous namespace
+
+
diff -Nru graphite2-1.2.4/src/inc/debug.h graphite2-1.3.6/src/inc/debug.h
--- graphite2-1.2.4/src/inc/debug.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/debug.h 2016-02-29 04:18:01.000000000 +0000
@@ -54,6 +54,7 @@
json & operator << (json & j, const Position &) throw();
+json & operator << (json & j, const Rect &) throw();
json & operator << (json & j, const CharInfo &) throw();
json & operator << (json & j, const dslot &) throw();
json & operator << (json & j, const objectid &) throw();
@@ -68,6 +69,13 @@
}
+inline
+json & operator << (json & j, const Rect & p) throw()
+{
+ return j << json::flat << json::array << p.bl.x << p.bl.y << p.tr.x << p.tr.y << json::close;
+}
+
+
inline
json & operator << (json & j, const objectid & sid) throw()
{
diff -Nru graphite2-1.2.4/src/inc/Decompressor.h graphite2-1.3.6/src/inc/Decompressor.h
--- graphite2-1.2.4/src/inc/Decompressor.h 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/inc/Decompressor.h 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,56 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2015, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#pragma once
+
+#include
+
+namespace lz4
+{
+
+// decompress an LZ4 block
+// Parameters:
+// @in - Input buffer containing an LZ4 block.
+// @in_size - Size of the input LZ4 block in bytes.
+// @out - Output buffer to hold decompressed results.
+// @out_size - The size of the buffer pointed to by @out.
+// Invariants:
+// @in - This buffer must be at least 1 machine word in length,
+// regardless of the actual LZ4 block size.
+// @in_size - This must be at least 4 and must also be <= to the
+// allocated buffer @in.
+// @out - This must be bigger than the input buffer and at least
+// 13 bytes.
+// @out_size - Must always be big enough to hold the expected size.
+// Return:
+// -1 - Decompression failed.
+// size - Actual number of bytes decompressed.
+int decompress(void const *in, size_t in_size, void *out, size_t out_size);
+
+} // end of namespace shrinker
+
+
diff -Nru graphite2-1.2.4/src/inc/Error.h graphite2-1.3.6/src/inc/Error.h
--- graphite2-1.2.4/src/inc/Error.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Error.h 2016-02-29 04:18:01.000000000 +0000
@@ -111,16 +111,24 @@
E_BADRULEMAPPING = 50, // The structure of the rule mapping is bad
E_BADRANGE = 51, // Bad column range structure including a glyph in more than one column
E_BADRULENUM = 52, // A reference to a rule is out of range (too high)
+ E_BADACOLLISION = 53, // Bad Silf table collision attribute number (too high)
+ E_BADEMPTYPASS = 54, // Can't have empty passes (no rules) except for collision passes
+ E_BADSILFVERSION = 55, // The Silf table has a bad version (probably too high)
+ E_BADCOLLISIONPASS = 56, // Collision flags set on a non positioning pass
+ E_BADNUMCOLUMNS = 57, // Arbitrarily limit number of columns in fsm
// Code errors
E_CODEFAILURE = 60, // Base code error. The following subcodes must align with Machine::Code::status_t in Code.h
- E_CODEALLOC = 61, // Out of memory
- E_INVALIDOPCODE = 62, // Invalid op code
- E_UNIMPOPCODE = 63, // Unimplemented op code encountered
- E_OUTOFRANGECODE = 64, // Code argument out of range
- E_BADJUMPCODE = 65, // Code jumps past end of op codes
- E_CODEBADARGS = 66, // Code arguments exhausted
- E_CODENORETURN = 67, // Missing return type op code at end of code
- E_CODENESTEDCTXT = 68 // Nested context encountered in code
+ E_CODEALLOC = 61, // Out of memory
+ E_INVALIDOPCODE = 62, // Invalid op code
+ E_UNIMPOPCODE = 63, // Unimplemented op code encountered
+ E_OUTOFRANGECODE = 64, // Code argument out of range
+ E_BADJUMPCODE = 65, // Code jumps past end of op codes
+ E_CODEBADARGS = 66, // Code arguments exhausted
+ E_CODENORETURN = 67, // Missing return type op code at end of code
+ E_CODENESTEDCTXT = 68, // Nested context encountered in code
+// Compression errors
+ E_BADSCHEME = 69,
+ E_SHRINKERFAILED = 70,
};
}
diff -Nru graphite2-1.2.4/src/inc/Face.h graphite2-1.3.6/src/inc/Face.h
--- graphite2-1.2.4/src/inc/Face.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Face.h 2016-02-29 04:18:01.000000000 +0000
@@ -43,6 +43,7 @@
class GlyphCache;
class NameTable;
class json;
+class Font;
using TtfUtil::Tag;
@@ -170,10 +171,15 @@
const Face * _f;
mutable const byte * _p;
uint32 _sz;
+ bool _compressed;
+
+ Error decompress();
+
+ void releaseBuffers();
public:
Table() throw();
- Table(const Face & face, const Tag n) throw();
+ Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
Table(const Table & rhs) throw();
~Table() throw();
@@ -185,13 +191,13 @@
inline
Face::Table::Table() throw()
-: _f(0), _p(0), _sz(0)
+: _f(0), _p(0), _sz(0), _compressed(false)
{
}
inline
Face::Table::Table(const Table & rhs) throw()
-: _f(rhs._f), _p(rhs._p), _sz(rhs._sz)
+: _f(rhs._f), _p(rhs._p), _sz(rhs._sz), _compressed(rhs._compressed)
{
rhs._p = 0;
}
@@ -199,8 +205,7 @@
inline
Face::Table::~Table() throw()
{
- if (_p && _f->m_ops.release_table)
- (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
+ releaseBuffers();
}
inline
diff -Nru graphite2-1.2.4/src/inc/FeatureMap.h graphite2-1.3.6/src/inc/FeatureMap.h
--- graphite2-1.2.4/src/inc/FeatureMap.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/FeatureMap.h 2016-02-29 04:18:01.000000000 +0000
@@ -56,7 +56,7 @@
static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8;
public:
- FeatureRef() : m_nameValues(0) {}
+ FeatureRef();
FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val,
uint32 name, uint16 uiName, uint16 flags,
FeatureSetting *settings, uint16 num_set) throw();
@@ -99,6 +99,16 @@
};
+inline
+FeatureRef::FeatureRef()
+: m_pFace(0), m_nameValues(0),
+ m_mask(0), m_max(0), m_id(0),
+ m_nameid(0), m_flags(0), m_numSet(0),
+ m_bits(0), m_index(0)
+{
+}
+
+
class NameAndFeatureRef
{
public:
@@ -117,9 +127,8 @@
class FeatureMap
{
public:
- FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL),
- m_defaultFeatures(NULL) {}
- ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; delete m_defaultFeatures; }
+ FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL) {}
+ ~FeatureMap() { delete [] m_feats; delete[] m_pNamedFeats; }
bool readFeats(const Face & face);
const FeatureRef *findFeatureRef(uint32 name) const;
@@ -135,7 +144,7 @@
FeatureRef *m_feats;
NameAndFeatureRef* m_pNamedFeats; //owned
- FeatureVal* m_defaultFeatures; //owned
+ FeatureVal m_defaultFeatures; //owned
private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
FeatureMap(const FeatureMap&);
diff -Nru graphite2-1.2.4/src/inc/GlyphCache.h graphite2-1.3.6/src/inc/GlyphCache.h
--- graphite2-1.2.4/src/inc/GlyphCache.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/GlyphCache.h 2016-02-29 04:18:01.000000000 +0000
@@ -29,14 +29,63 @@
#include "graphite2/Font.h"
#include "inc/Main.h"
+#include "inc/Position.h"
+#include "inc/GlyphFace.h"
namespace graphite2 {
class Face;
class FeatureVal;
-class GlyphFace;
class Segment;
+
+struct SlantBox
+{
+ static const SlantBox empty;
+
+// SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
+ float width() const { return sa - si; }
+ float height() const { return da - di; }
+ float si; // min
+ float di; // min
+ float sa; // max
+ float da; // max
+};
+
+
+struct BBox
+{
+ BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
+ float width() const { return xa - xi; }
+ float height() const { return ya - yi; }
+ float xi; // min
+ float yi; // min
+ float xa; // max
+ float ya; // max
+};
+
+
+class GlyphBox
+{
+ GlyphBox(const GlyphBox &);
+ GlyphBox & operator = (const GlyphBox &);
+
+public:
+ GlyphBox(uint8 numsubs, unsigned short bitmap, Rect *slanted) : _num(numsubs), _bitmap(bitmap), _slant(*slanted) {};
+
+ void addSubBox(int subindex, int boundary, Rect *val) { _subs[subindex * 2 + boundary] = *val; }
+ Rect &subVal(int subindex, int boundary) { return _subs[subindex * 2 + boundary]; }
+ const Rect &slant() const { return _slant; }
+ uint8 num() const { return _num; }
+ const Rect *subs() const { return _subs; }
+
+private:
+ uint8 _num;
+ unsigned short _bitmap;
+ Rect _slant;
+ Rect _subs[1];
+};
+
class GlyphCache
{
class Loader;
@@ -54,12 +103,24 @@
const GlyphFace *glyph(unsigned short glyphid) const; //result may be changed by subsequent call with a different glyphid
const GlyphFace *glyphSafe(unsigned short glyphid) const;
+ float getBoundingMetric(unsigned short glyphid, uint8 metric) const;
+ uint8 numSubBounds(unsigned short glyphid) const;
+ float getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
+ const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
+ const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
+ const BBox & getBoundingBBox(unsigned short glyphid) const;
+ const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
+ const BBox & getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
+ bool check(unsigned short glyphid) const;
+ bool hasBoxes() const { return _boxes != 0; }
CLASS_NEW_DELETE;
private:
+ const Rect _empty_slant_box;
const Loader * _glyph_loader;
const GlyphFace * * _glyphs;
+ GlyphBox * * _boxes;
unsigned short _num_glyphs,
_num_attrs,
_upem;
@@ -84,9 +145,79 @@
}
inline
+bool GlyphCache::check(unsigned short glyphid) const
+{
+ return _boxes && glyphid < _num_glyphs;
+}
+
+inline
const GlyphFace *GlyphCache::glyphSafe(unsigned short glyphid) const
{
return glyphid < _num_glyphs ? glyph(glyphid) : NULL;
}
+inline
+float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
+{
+ if (glyphid >= _num_glyphs) return 0.;
+ switch (metric) {
+ case 0: return (float)(glyph(glyphid)->theBBox().bl.x); // x_min
+ case 1: return (float)(glyph(glyphid)->theBBox().bl.y); // y_min
+ case 2: return (float)(glyph(glyphid)->theBBox().tr.x); // x_max
+ case 3: return (float)(glyph(glyphid)->theBBox().tr.y); // y_max
+ case 4: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.x : 0.f); // sum_min
+ case 5: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.y : 0.f); // diff_min
+ case 6: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.x : 0.f); // sum_max
+ case 7: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.y : 0.f); // diff_max
+ default: return 0.;
+ }
+}
+
+inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
+{
+ return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
+}
+
+inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
+{
+ return *(BBox *)(&(glyph(glyphid)->theBBox()));
+}
+
+inline
+float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const
+{
+ GlyphBox *b = _boxes[glyphid];
+ if (b == NULL || subindex >= b->num()) return 0;
+
+ switch (metric) {
+ case 0: return b->subVal(subindex, 0).bl.x;
+ case 1: return b->subVal(subindex, 0).bl.y;
+ case 2: return b->subVal(subindex, 0).tr.x;
+ case 3: return b->subVal(subindex, 0).tr.y;
+ case 4: return b->subVal(subindex, 1).bl.x;
+ case 5: return b->subVal(subindex, 1).bl.y;
+ case 6: return b->subVal(subindex, 1).tr.x;
+ case 7: return b->subVal(subindex, 1).tr.y;
+ default: return 0.;
+ }
+}
+
+inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
+{
+ GlyphBox *b = _boxes[glyphid];
+ return *(SlantBox *)(b->subs() + 2 * subindex + 1);
+}
+
+inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
+{
+ GlyphBox *b = _boxes[glyphid];
+ return *(BBox *)(b->subs() + 2 * subindex);
+}
+
+inline
+uint8 GlyphCache::numSubBounds(unsigned short glyphid) const
+{
+ return _boxes[glyphid] ? _boxes[glyphid]->num() : 0;
+}
+
} // namespace graphite2
diff -Nru graphite2-1.2.4/src/inc/Intervals.h graphite2-1.3.6/src/inc/Intervals.h
--- graphite2-1.2.4/src/inc/Intervals.h 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/inc/Intervals.h 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,234 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2010, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include
+
+#include "inc/Main.h"
+#include "inc/List.h"
+#include "inc/json.h"
+#include "inc/Position.h"
+
+// An IntervalSet represents the possible movement of a given glyph in a given direction
+// (horizontally, vertically, or diagonally).
+// A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750.
+// Each pair represents the min/max of a sub-range.
+
+namespace graphite2 {
+
+class Segment;
+
+enum zones_t {SD, XY};
+
+class Zones
+{
+ struct Exclusion
+ {
+ template
+ static Exclusion weighted(float xmin, float xmax, float f, float a0,
+ float m, float xi, float ai, float c, bool nega);
+
+ float x, // x position
+ xm, // xmax position
+ c, // constant + sum(MiXi^2)
+ sm, // sum(Mi)
+ smx; // sum(MiXi)
+ bool open;
+
+ Exclusion(float x, float w, float smi, float smxi, float c);
+ Exclusion & operator += (Exclusion const & rhs);
+ uint8 outcode(float p) const;
+
+ Exclusion split_at(float p);
+ void left_trim(float p);
+
+ bool track_cost(float & cost, float & x, float origin) const;
+
+ private:
+ float test_position(float origin) const;
+ float cost(float x) const;
+ };
+
+ typedef Vector exclusions;
+
+ typedef exclusions::iterator iterator;
+ typedef Exclusion * pointer;
+ typedef Exclusion & reference;
+ typedef std::reverse_iterator reverse_iterator;
+
+public:
+ typedef exclusions::const_iterator const_iterator;
+ typedef Exclusion const * const_pointer;
+ typedef Exclusion const & const_reference;
+ typedef std::reverse_iterator const_reverse_iterator;
+
+#if !defined GRAPHITE2_NTRACING
+ struct Debug
+ {
+ Exclusion _excl;
+ bool _isdel;
+ Vector _env;
+
+ Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { };
+ };
+
+ typedef Vector debugs;
+ typedef debugs::const_iterator idebugs;
+ void addDebug(Exclusion *e);
+ void removeDebug(float pos, float posm);
+ void setdebug(json *dbgout) { _dbg = dbgout; }
+ idebugs dbgs_begin() const { return _dbgs.begin(); }
+ idebugs dbgs_end() const { return _dbgs.end(); }
+ void jsonDbgOut(Segment *seg) const;
+ Position position() const { return Position(_pos, _posm); }
+#endif
+
+ Zones();
+ template
+ void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao);
+
+ void exclude(float xmin, float xmax);
+ void exclude_with_margins(float xmin, float xmax, int axis);
+
+ template
+ void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
+ void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
+
+ float closest( float origin, float &cost) const;
+
+ const_iterator begin() const { return _exclusions.begin(); }
+ const_iterator end() const { return _exclusions.end(); }
+
+private:
+ exclusions _exclusions;
+#if !defined GRAPHITE2_NTRACING
+ json * _dbg;
+ debugs _dbgs;
+#endif
+ float _margin_len,
+ _margin_weight,
+ _pos,
+ _posm;
+
+ void insert(Exclusion e);
+ void remove(float x, float xm);
+ const_iterator find_exclusion_under(float x) const;
+};
+
+
+inline
+Zones::Zones()
+: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
+{
+#if !defined GRAPHITE2_NTRACING
+ _dbg = 0;
+#endif
+ _exclusions.reserve(8);
+}
+
+inline
+Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_)
+: x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false)
+{ }
+
+template
+inline
+void Zones::initialise(float xmin, float xmax, float margin_len,
+ float margin_weight, float a0)
+{
+ _margin_len = margin_len;
+ _margin_weight = margin_weight;
+ _pos = xmin;
+ _posm = xmax;
+ _exclusions.clear();
+ _exclusions.push_back(Exclusion::weighted(xmin, xmax, 1, a0, 0, 0, 0, 0, false));
+ _exclusions.front().open = true;
+#if !defined GRAPHITE2_NTRACING
+ _dbgs.clear();
+#endif
+}
+
+inline
+void Zones::exclude(float xmin, float xmax) {
+ remove(xmin, xmax);
+}
+
+template
+inline
+void Zones::weighted(float xmin, float xmax, float f, float a0,
+ float m, float xi, float ai, float c, bool nega) {
+ insert(Exclusion::weighted(xmin, xmax, f, a0, m, xi, ai, c, nega));
+}
+
+inline
+void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0,
+ float m, float xi, float ai, float c, bool nega) {
+ if (axis < 2)
+ weighted(xmin, xmax, f, a0, m, xi, ai, c, nega);
+ else
+ weighted(xmin, xmax, f, a0, m, xi, ai, c, nega);
+}
+
+#if !defined GRAPHITE2_NTRACING
+inline
+void Zones::addDebug(Exclusion *e) {
+ if (_dbg)
+ _dbgs.push_back(Debug(e, false, _dbg));
+}
+
+inline
+void Zones::removeDebug(float pos, float posm) {
+ if (_dbg)
+ {
+ Exclusion e(pos, posm, 0, 0, 0);
+ _dbgs.push_back(Debug(&e, true, _dbg));
+ }
+}
+#endif
+
+template<>
+inline
+Zones::Exclusion Zones::Exclusion::weighted(float xmin, float xmax, float f, float a0,
+ float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) {
+ return Exclusion(xmin, xmax,
+ m + f,
+ m * xi,
+ m * xi * xi + f * a0 * a0 + c);
+}
+
+template<>
+inline
+Zones::Exclusion Zones::Exclusion::weighted(float xmin, float xmax, float f, float a0,
+ float m, float xi, float ai,float c, bool nega) {
+ float xia = nega ? xi - ai : xi + ai;
+ return Exclusion(xmin, xmax,
+ 0.25f * (m + 2.f * f),
+ 0.25f * m * xia,
+ 0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c);
+}
+
+} // end of namespace graphite2
diff -Nru graphite2-1.2.4/src/inc/json.h graphite2-1.3.6/src/inc/json.h
--- graphite2-1.2.4/src/inc/json.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/json.h 2016-02-29 04:18:01.000000000 +0000
@@ -29,9 +29,11 @@
// Author: Tim Eves
#pragma once
+
#include "inc/Main.h"
#include
#include
+#include "inc/List.h"
namespace graphite2 {
@@ -49,6 +51,7 @@
* _context, // current context (top of stack)
* _flatten; // if !0 points to context above which
// pretty printed output should occur.
+ Vector _env;
void context(const char current) throw();
void indent(const int d=0) throw();
@@ -64,6 +67,10 @@
typedef bool boolean;
static const _null_t null;
+ void setenv(unsigned int index, void *val) { _env.reserve(index + 1); if (index >= _env.size()) _env.insert(_env.end(), _env.size() - index + 1, 0); _env[index] = val; }
+ void *getenv(unsigned int index) const { return _env[index]; }
+ const Vector &getenvs() const { return _env; }
+
static void flat(json &) throw();
static void close(json &) throw();
static void object(json &) throw();
diff -Nru graphite2-1.2.4/src/inc/List.h graphite2-1.3.6/src/inc/List.h
--- graphite2-1.2.4/src/inc/List.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/List.h 2016-02-29 04:18:01.000000000 +0000
@@ -70,6 +70,7 @@
size_t capacity() const{ return m_end - m_first; }
void reserve(size_t n);
+ void resize(size_t n, const T & v = T());
reference front() { assert(size() > 0); return *begin(); }
const_reference front() const { assert(size() > 0); return *begin(); }
@@ -82,7 +83,7 @@
void assign(size_t n, const T& u) { clear(); insert(begin(), n, u); }
void assign(const_iterator first, const_iterator last) { clear(); insert(begin(), first, last); }
- iterator insert(iterator p, const T & x) { p = _insert_default(p, 1); *p = x; return p; }
+ iterator insert(iterator p, const T & x) { p = _insert_default(p, 1); new (p) T(x); return p; }
void insert(iterator p, size_t n, const T & x);
void insert(iterator p, const_iterator first, const_iterator last);
void pop_back() { assert(size() > 0); --m_last; }
@@ -104,18 +105,27 @@
{
const ptrdiff_t sz = size();
m_first = static_cast(realloc(m_first, n*sizeof(T)));
+ if (!m_first) std::abort();
m_last = m_first + sz;
m_end = m_first + n;
}
}
+template
+inline
+void Vector::resize(size_t n, const T & v) {
+ const ptrdiff_t d = n-size();
+ if (d < 0) erase(end()+d, end());
+ else if (d > 0) insert(end(), d, v);
+}
+
template
inline
typename Vector::iterator Vector::_insert_default(iterator p, size_t n)
{
assert(begin() <= p && p <= end());
const ptrdiff_t i = p - begin();
- reserve((size() + n + 7) >> 3 << 3);
+ reserve(((size() + n + 7) >> 3) << 3);
p = begin() + i;
// Move tail if there is one
if (p != end()) memmove(p + n, p, distance(p,end())*sizeof(T));
diff -Nru graphite2-1.2.4/src/inc/Machine.h graphite2-1.3.6/src/inc/Machine.h
--- graphite2-1.2.4/src/inc/Machine.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Machine.h 2016-02-29 04:18:01.000000000 +0000
@@ -110,7 +110,9 @@
PUSH_PROC_STATE, PUSH_VERSION,
PUT_SUBS, PUT_SUBS2, PUT_SUBS3,
PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR,
- MAX_OPCODE,
+ BITOR, BITAND, BITNOT,
+ BITSET, SET_FEAT,
+ MAX_OPCODE,
// private opcodes for internal use only, comes after all other on disk opcodes
TEMP_COPY = MAX_OPCODE
};
@@ -138,7 +140,8 @@
stack_underflow,
stack_not_empty,
stack_overflow,
- slot_offset_out_bounds
+ slot_offset_out_bounds,
+ died_early
};
Machine(SlotMap &) throw();
@@ -148,7 +151,7 @@
SlotMap & slotMap() const throw();
status_t status() const throw();
- operator bool () const throw();
+// operator bool () const throw();
private:
void check_final_stack(const stack_t * const sp);
diff -Nru graphite2-1.2.4/src/inc/Main.h graphite2-1.3.6/src/inc/Main.h
--- graphite2-1.2.4/src/inc/Main.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Main.h 2016-02-29 04:18:01.000000000 +0000
@@ -85,7 +85,7 @@
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
- return reinterpret_cast(malloc(sizeof(T) * n));
+ return static_cast(malloc(sizeof(T) * n));
}
template T * grzeroalloc(size_t n)
@@ -93,7 +93,7 @@
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
- return reinterpret_cast(calloc(n, sizeof(T)));
+ return static_cast(calloc(n, sizeof(T)));
}
template
@@ -120,8 +120,27 @@
void operator delete[] (void * p)throw() { free(p); } \
void operator delete[] (void *, void *) throw() {}
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
#define GR_MAYBE_UNUSED __attribute__((unused))
#else
#define GR_MAYBE_UNUSED
#endif
+
+#if defined(__clang__) && __cplusplus >= 201103L
+ /* clang's fallthrough annotations are only available starting in C++11. */
+ #define GR_FALLTHROUGH [[clang::fallthrough]]
+#elif defined(_MSC_VER)
+ /*
+ * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
+ * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
+ */
+ #include
+ #define GR_FALLTHROUGH __fallthrough
+#else
+ #define GR_FALLTHROUGH /* fallthrough */
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4800)
+#pragma warning(disable: 4355)
+#endif
diff -Nru graphite2-1.2.4/src/inc/opcodes.h graphite2-1.3.6/src/inc/opcodes.h
--- graphite2-1.2.4/src/inc/opcodes.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/opcodes.h 2016-02-29 04:18:01.000000000 +0000
@@ -61,6 +61,7 @@
// isl = The last positioned slot
// ip = The current instruction pointer
// endPos = Position of advance of last cluster
+// dir = writing system directionality of the font
// #define NOT_IMPLEMENTED assert(false)
@@ -75,7 +76,7 @@
#define push(n) { *++sp = n; }
#define pop() (*sp--)
#define slotat(x) (map[(x)])
-#define DIE { is=seg.last(); EXIT(1); }
+#define DIE { is=seg.last(); status = Machine::died_early; EXIT(1); }
#define POSITIONED 1
STARTOP(nop)
@@ -241,20 +242,24 @@
STARTOP(put_copy)
declare_params(1);
const int slot_ref = int8(*param);
- if (is && (slot_ref ||is != *map))
+ if (is)
{
- int16 *tempUserAttrs = is->userAttrs();
slotref ref = slotat(slot_ref);
- if (ref)
+ if (ref && ref != is)
{
- memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
+ int16 *tempUserAttrs = is->userAttrs();
+ if (is->attachedTo() || is->firstChild()) DIE
Slot *prev = is->prev();
Slot *next = is->next();
- memcpy(is, slotat(slot_ref), sizeof(Slot));
+ memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
+ memcpy(is, ref, sizeof(Slot));
+ is->firstChild(NULL);
+ is->nextSibling(NULL);
is->userAttrs(tempUserAttrs);
is->next(next);
is->prev(prev);
- is->sibling(NULL);
+ if (is->attachedTo())
+ is->attachedTo()->child(is);
}
is->markCopied(false);
is->markDeleted(false);
@@ -309,6 +314,8 @@
{
newSlot->originate(seg.defaultOriginal());
}
+ if (is == smap.highwater())
+ smap.highpassed(false);
is = newSlot;
seg.extendLength(1);
if (map != &smap[-1])
@@ -316,7 +323,7 @@
ENDOP
STARTOP(delete_)
- if (!is) DIE
+ if (!is || is->isDeleted()) DIE
is->markDeleted(true);
if (is->prev())
is->prev()->next(is->next());
@@ -385,7 +392,7 @@
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, 0);
@@ -398,7 +405,7 @@
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, 0);
@@ -427,7 +434,7 @@
const int slot_ref = int8(param[1]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@@ -454,7 +461,7 @@
const signed int attr_level = uint8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
- push(seg.getGlyphMetric(slot, glyph_attr, attr_level));
+ push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
ENDOP
STARTOP(push_feat)
@@ -492,7 +499,7 @@
{
slotref att = slot->attachedTo();
if (att) slot = att;
- push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level)));
+ push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
}
ENDOP
@@ -503,7 +510,7 @@
idx = uint8(param[2]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@@ -548,7 +555,7 @@
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, idx);
@@ -562,7 +569,7 @@
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
- seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
+ seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, idx);
@@ -636,7 +643,7 @@
STARTOP(temp_copy)
slotref newSlot = seg.newSlot();
- if (!newSlot) DIE;
+ if (!newSlot || !is) DIE;
int16 *tempUserAttrs = newSlot->userAttrs();
memcpy(newSlot, is, sizeof(Slot));
memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
@@ -644,3 +651,37 @@
newSlot->markCopied(true);
*map = newSlot;
ENDOP
+
+STARTOP(band)
+ binop(&);
+ENDOP
+
+STARTOP(bor)
+ binop(|);
+ENDOP
+
+STARTOP(bnot)
+ *sp = ~*sp;
+ENDOP
+
+STARTOP(setbits)
+ declare_params(4);
+ const uint16 m = uint16(param[0]) << 8
+ | uint8(param[1]);
+ const uint16 v = uint16(param[2]) << 8
+ | uint8(param[3]);
+ *sp = ((*sp) & ~m) | v;
+ENDOP
+
+STARTOP(set_feat)
+ declare_params(2);
+ const unsigned int feat = uint8(param[0]);
+ const int slot_ref = int8(param[1]);
+ slotref slot = slotat(slot_ref);
+ if (slot)
+ {
+ uint8 fid = seg.charinfo(slot->original())->fid();
+ seg.setFeature(fid, feat, pop());
+ }
+ENDOP
+
diff -Nru graphite2-1.2.4/src/inc/opcode_table.h graphite2-1.3.6/src/inc/opcode_table.h
--- graphite2-1.2.4/src/inc/opcode_table.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/opcode_table.h 2016-02-29 04:18:01.000000000 +0000
@@ -43,7 +43,7 @@
// level - any byte
static const opcode_t opcode_table[] =
{
- {{do2(nop)}, 0, "NOP"},
+ {{do2(nop)}, 0, "NOP"},
{{do2(push_byte)}, 1, "PUSH_BYTE"}, // number
{{do2(push_byte_u)}, 1, "PUSH_BYTE_U"}, // number
@@ -114,6 +114,11 @@
{{do_(put_glyph), NILOP}, 2, "PUT_GLYPH"}, // output_class output_class
{{do2(push_glyph_attr)}, 3, "PUSH_GLYPH_ATTR"}, // gattrnum gattrnum slot
{{do2(push_att_to_glyph_attr)}, 3, "PUSH_ATT_TO_GLYPH_ATTR"}, // gattrnum gattrnum slot
+ {{do2(bor)}, 0, "BITOR"},
+ {{do2(band)}, 0, "BITAND"},
+ {{do2(bnot)}, 0, "BITNOT"}, // 0x40
+ {{do2(setbits)}, 4, "BITSET"},
+ {{do2(set_feat)}, 2, "SET_FEAT"},
// private opcodes for internal use only, comes after all other on disk opcodes.
{{do_(temp_copy), NILOP}, 0, "TEMP_COPY"}
};
diff -Nru graphite2-1.2.4/src/inc/Pass.h graphite2-1.3.6/src/inc/Pass.h
--- graphite2-1.2.4/src/inc/Pass.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Pass.h 2016-02-29 04:18:01.000000000 +0000
@@ -39,6 +39,11 @@
struct State;
class FiniteStateMachine;
class Error;
+class ShiftCollider;
+class KernCollider;
+class json;
+
+enum passtype;
class Pass
{
@@ -46,10 +51,12 @@
Pass();
~Pass();
- bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face, Error &e);
- void runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
+ bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face,
+ enum passtype pt, uint32 version, Error &e);
+ bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
void init(Silf *silf) { m_silf = silf; }
- byte spaceContextuals() const { return (m_flags & 0x0E) >> 1; }
+ byte collisionLoops() const { return m_numCollRuns; }
+ bool reverseDir() const { return m_isReverseDir; }
CLASS_NEW_DELETE
private:
@@ -61,23 +68,34 @@
const byte *precontext, const uint16 * sort_key,
const uint16 * o_constraint, const byte *constraint_data,
const uint16 * o_action, const byte * action_data,
- Face &, Error &e);
+ Face &, enum passtype pt, Error &e);
bool readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
bool readRanges(const byte * ranges, size_t num_ranges, Error &e);
uint16 glyphToCol(const uint16 gid) const;
bool runFSM(FiniteStateMachine & fsm, Slot * slot) const;
void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
- void dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
+ void dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
- const Silf* m_silf;
- uint16 * m_cols;
- Rule * m_rules; // rules
- RuleEntry * m_ruleMap;
- uint16 * m_startStates; // prectxt length
- uint16 * m_transitions;
- State * m_states;
-
- byte m_flags;
+ bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
+ bool collisionKern(Segment *seg, int dir, json * const dbgout) const;
+ bool collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
+ bool resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
+ int dir, bool &moved, bool &hasCol, json * const dbgout) const;
+ float resolveKern(Segment *seg, Slot *slot, Slot *start, KernCollider &coll, int dir,
+ float &ymin, float &ymax, json *const dbgout) const;
+
+ const Silf * m_silf;
+ uint16 * m_cols;
+ Rule * m_rules; // rules
+ RuleEntry * m_ruleMap;
+ uint16 * m_startStates; // prectxt length
+ uint16 * m_transitions;
+ State * m_states;
+ vm::Machine::Code * m_codes;
+ byte * m_progs;
+
+ byte m_numCollRuns;
+ byte m_kernColls;
byte m_iMaxLoop;
uint16 m_numGlyphs;
uint16 m_numRules;
@@ -88,6 +106,8 @@
uint16 m_numColumns;
byte m_minPreCtxt;
byte m_maxPreCtxt;
+ byte m_colThreshold;
+ bool m_isReverseDir;
vm::Machine::Code m_cPConstraint;
private: //defensive
diff -Nru graphite2-1.2.4/src/inc/Position.h graphite2-1.3.6/src/inc/Position.h
--- graphite2-1.2.4/src/inc/Position.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Position.h 2016-02-29 04:18:01.000000000 +0000
@@ -50,7 +50,16 @@
Rect(const Position& botLeft, const Position& topRight): bl(botLeft), tr(topRight) {}
Rect widen(const Rect& other) { return Rect(Position(bl.x > other.bl.x ? other.bl.x : bl.x, bl.y > other.bl.y ? other.bl.y : bl.y), Position(tr.x > other.tr.x ? tr.x : other.tr.x, tr.y > other.tr.y ? tr.y : other.tr.y)); }
Rect operator + (const Position &a) const { return Rect(Position(bl.x + a.x, bl.y + a.y), Position(tr.x + a.x, tr.y + a.y)); }
+ Rect operator - (const Position &a) const { return Rect(Position(bl.x - a.x, bl.y - a.y), Position(tr.x - a.x, tr.y - a.y)); }
Rect operator * (float m) const { return Rect(Position(bl.x, bl.y) * m, Position(tr.x, tr.y) * m); }
+ float width() const { return tr.x - bl.x; }
+ float height() const { return tr.y - bl.y; }
+
+ bool hitTest(Rect &other);
+
+ // returns Position(overlapx, overlapy) where overlap<0 if overlapping else positive)
+ Position overlap(Position &offset, Rect &other, Position &otherOffset);
+ //Position constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox);
Position bl;
Position tr;
diff -Nru graphite2-1.2.4/src/inc/Rule.h graphite2-1.3.6/src/inc/Rule.h
--- graphite2-1.2.4/src/inc/Rule.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Rule.h 2016-02-29 04:18:01.000000000 +0000
@@ -41,8 +41,8 @@
uint16 rule_idx;
#endif
- Rule() : constraint(0), action(0), sort(0), preContext(0) {}
- ~Rule();
+ Rule();
+ ~Rule() {}
CLASS_NEW_DELETE;
@@ -51,10 +51,16 @@
Rule & operator = (const Rule &);
};
-inline Rule::~Rule()
+inline
+Rule::Rule()
+: constraint(0),
+ action(0),
+ sort(0),
+ preContext(0)
{
- delete constraint;
- delete action;
+#ifndef NDEBUG
+ rule_idx = 0;
+#endif
}
@@ -96,7 +102,7 @@
{
public:
enum {MAX_SLOTS=64};
- SlotMap(Segment & seg);
+ SlotMap(Segment & seg, uint8 direction);
Slot * * begin();
Slot * * end();
@@ -107,19 +113,22 @@
Slot * const & operator[](int n) const;
Slot * & operator [] (int);
void pushSlot(Slot * const slot);
- void collectGarbage();
+ void collectGarbage(Slot *& aSlot);
Slot * highwater() { return m_highwater; }
void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
bool highpassed() const { return m_highpassed; }
void highpassed(bool v) { m_highpassed = v; }
+ uint8 dir() const { return m_dir; }
+
Segment & segment;
private:
Slot * m_slot_map[MAX_SLOTS+1];
unsigned short m_size;
unsigned short m_precontext;
Slot * m_highwater;
+ uint8 m_dir;
bool m_highpassed;
};
@@ -233,8 +242,8 @@
}
inline
-SlotMap::SlotMap(Segment & seg)
-: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_highpassed(false)
+SlotMap::SlotMap(Segment & seg, uint8 direction)
+: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false)
{
m_slot_map[0] = 0;
}
diff -Nru graphite2-1.2.4/src/inc/SegCache.h graphite2-1.3.6/src/inc/SegCache.h
--- graphite2-1.2.4/src/inc/SegCache.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/SegCache.h 2016-02-29 04:18:01.000000000 +0000
@@ -263,7 +263,7 @@
unsigned long long minAccessCount, unsigned long long oldAccessTime);
uint16 m_prefixLength;
- uint16 m_maxCachedSegLength;
+// uint16 m_maxCachedSegLength;
size_t m_segmentCount;
SegCachePrefixArray m_prefixes;
Features m_features;
diff -Nru graphite2-1.2.4/src/inc/Segment.h graphite2-1.3.6/src/inc/Segment.h
--- graphite2-1.2.4/src/inc/Segment.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Segment.h 2016-02-29 04:18:01.000000000 +0000
@@ -35,11 +35,10 @@
#include "inc/FeatureVal.h"
#include "inc/GlyphCache.h"
#include "inc/GlyphFace.h"
-//#include "inc/Silf.h"
#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/List.h"
-#include "inc/Bidi.h"
+#include "inc/Collider.h"
#define MAX_SEG_GROWTH_FACTOR 256
@@ -47,7 +46,7 @@
typedef Vector FeatureList;
typedef Vector SlotRope;
-typedef Vector AttributeRope;
+typedef Vector AttributeRope;
typedef Vector JustifyRope;
#ifndef GRAPHITE2_NSEGCACHE
@@ -86,6 +85,12 @@
Segment& operator=(const Segment&);
public:
+
+ enum {
+ SEG_INITCOLLISIONS = 1,
+ SEG_HASCOLLISIONS = 2
+ };
+
unsigned int slotCount() const { return m_numGlyphs; } //one slot per glyph
void extendLength(int num) { m_numGlyphs += num; }
Position advance() const { return m_advance; }
@@ -95,7 +100,6 @@
unsigned int charInfoCount() const { return m_numCharinfo; }
const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }
- int8 dir() const { return m_dir; }
Segment(unsigned int numchars, const Face* face, uint32 script, int dir);
~Segment();
@@ -107,6 +111,8 @@
Slot * endSlot, const Slot * srcSlot,
const size_t numGlyphs);
#endif
+ uint8 flags() const { return m_flags; }
+ void flags(uint8 f) { m_flags = f; }
Slot *first() { return m_first; }
void first(Slot *p) { m_first = p; }
Slot *last() { return m_last; }
@@ -116,18 +122,27 @@
void freeSlot(Slot *);
SlotJustify *newJustify();
void freeJustify(SlotJustify *aJustify);
- Position positionSlots(const Font *font, Slot *first=0, Slot *last=0);
+ Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true);
void associateChars(int offset, int num);
void linkClusters(Slot *first, Slot *last);
uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
int addFeatures(const Features& feats) { m_feats.push_back(feats); return m_feats.size() - 1; }
uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); }
+ void setFeature(int index, uint8 findex, uint32 val) {
+ const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex);
+ if (pFR)
+ {
+ if (val > pFR->maxVal()) val = pFR->maxVal();
+ pFR->applyValToFeature(val, m_feats[index]);
+ } }
+ int8 dir() const { return m_dir; }
void dir(int8 val) { m_dir = val; }
+ bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; }
unsigned int passBits() const { return m_passBits; }
void mergePassBits(const unsigned int val) { m_passBits &= val; }
int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; }
- int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const;
+ int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const;
float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; }
const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); } //warning value may become invalid when another glyph is accessed
Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; }
@@ -135,20 +150,24 @@
int defaultOriginal() const { return m_defaultOriginal; }
const Face * getFace() const { return m_face; }
const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
- void bidiPass(uint8 aBidi, int paradir, uint8 aMirror);
+ void bidiPass(int paradir, uint8 aMirror);
+ int8 getSlotBidiClass(Slot *s) const;
+ void doMirror(uint16 aMirror);
Slot *addLineEnd(Slot *nSlot);
void delLineEnd(Slot *s);
bool hasJustification() const { return m_justifies.size() != 0; }
+ void reverseSlots();
bool isWhitespace(const int cid) const;
-
+ bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS); }
+ SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
CLASS_NEW_DELETE
public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
- void prepare_pos(const Font *font);
- void finalise(const Font *font);
+ void finalise(const Font *font, bool reverse=false);
float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
+ bool initCollisions();
private:
Position m_advance; // whole segment advance
@@ -159,6 +178,7 @@
Slot * m_freeSlots; // linked list of free slots
SlotJustify * m_freeJustifies; // Slot justification blocks free list
CharInfo * m_charinfo; // character info, one per input character
+ SlotCollision * m_collisions;
const Face * m_face; // GrFace
const Silf * m_silf;
Slot * m_first; // first slot in segment
@@ -169,26 +189,37 @@
m_passBits; // if bit set then skip pass
int m_defaultOriginal; // number of whitespace chars in the string
int8 m_dir;
+ uint8 m_flags; // General purpose flags
};
-
+inline
+int8 Segment::getSlotBidiClass(Slot *s) const
+{
+ int8 res = s->getBidiClass();
+ if (res != -1) return res;
+ res = int8(glyphAttr(s->gid(), m_silf->aBidi()));
+ s->setBidiClass(res);
+ return res;
+}
inline
-void Segment::finalise(const Font *font)
+void Segment::finalise(const Font *font, bool reverse)
{
if (!m_first) return;
- m_advance = positionSlots(font);
- associateChars(0, m_numCharinfo);
+ m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true);
+ //associateChars(0, m_numCharinfo);
+ if (reverse && currdir() != (m_dir & 1))
+ reverseSlots();
linkClusters(m_first, m_last);
}
inline
-int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const {
+int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const {
if (attrLevel > 0)
{
Slot *is = findRoot(iSlot);
- return is->clusterMetric(this, metric, attrLevel);
+ return is->clusterMetric(this, metric, attrLevel, rtl);
}
else
return m_face->getGlyphMetric(iSlot->gid(), metric);
@@ -211,62 +242,6 @@
+ (cid == 0x3000)) != 0;
}
-//inline
-//bool Segment::isWhitespace(const int cid) const
-//{
-// switch (cid >> 8)
-// {
-// case 0x00:
-// switch (cid)
-// {
-// case 0x09:
-// case 0x0A:
-// case 0x0B:
-// case 0x0C:
-// case 0x0D:
-// case 0x20:
-// return true;
-// default:
-// break;
-// }
-// break;
-// case 0x16:
-// return cid == 0x1680;
-// break;
-// case 0x18:
-// return cid == 0x180E;
-// break;
-// case 0x20:
-// switch (cid)
-// {
-// case 0x00:
-// case 0x01:
-// case 0x02:
-// case 0x03:
-// case 0x04:
-// case 0x05:
-// case 0x06:
-// case 0x07:
-// case 0x08:
-// case 0x09:
-// case 0x0A:
-// case 0x28:
-// case 0x29:
-// case 0x2F:
-// case 0x5F:
-// return true
-// default:
-// break;
-// }
-// break;
-// case 0x30:
-// return cid == 0x3000;
-// break;
-// }
-//
-// return false;
-//}
-
} // namespace graphite2
struct gr_segment : public graphite2::Segment {};
diff -Nru graphite2-1.2.4/src/inc/Silf.h graphite2-1.3.6/src/inc/Silf.h
--- graphite2-1.2.4/src/inc/Silf.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Silf.h 2016-02-29 04:18:01.000000000 +0000
@@ -85,6 +85,7 @@
uint8 aMirror() const {return m_aMirror; }
uint8 aPassBits() const { return m_aPassBits; }
uint8 aBidi() const { return m_aBidi; }
+ uint8 aCollision() const { return m_aCollision; }
uint8 substitutionPass() const { return m_sPass; }
uint8 positionPass() const { return m_pPass; }
uint8 justificationPass() const { return m_jPass; }
@@ -93,6 +94,7 @@
uint8 maxCompPerLig() const { return m_iMaxComp; }
uint16 numClasses() const { return m_nClass; }
byte flags() const { return m_flags; }
+ byte dir() const { return m_dir; }
uint8 numJustLevels() const { return m_numJusts; }
Justinfo *justAttrs() const { return m_justs; }
uint16 endLineGlyphid() const { return m_gEndLine; }
@@ -112,15 +114,12 @@
uint8 m_numPasses;
uint8 m_numJusts;
uint8 m_sPass, m_pPass, m_jPass, m_bPass,
- m_flags;
+ m_flags, m_dir;
- uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
- m_iMaxComp;
- uint16 m_aLig,
- m_numPseudo,
- m_nClass,
- m_nLinear,
- m_gEndLine;
+ uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
+ m_iMaxComp, m_aCollision;
+ uint16 m_aLig, m_numPseudo, m_nClass, m_nLinear,
+ m_gEndLine;
gr_faceinfo m_silfinfo;
void releaseBuffers() throw();
diff -Nru graphite2-1.2.4/src/inc/Slot.h graphite2-1.3.6/src/inc/Slot.h
--- graphite2-1.2.4/src/inc/Slot.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Slot.h 2016-02-29 04:18:01.000000000 +0000
@@ -32,15 +32,13 @@
#include "inc/Font.h"
#include "inc/Position.h"
-
-
namespace graphite2 {
typedef gr_attrCode attrCode;
class GlyphFace;
-class Segment;
class SegCacheEntry;
+class Segment;
struct SlotJustify
{
@@ -75,13 +73,14 @@
unsigned short gid() const { return m_glyphid; }
Position origin() const { return m_position; }
float advance() const { return m_advance.x; }
+ void advance(Position &val) { m_advance = val; }
Position advancePos() const { return m_advance; }
int before() const { return m_before; }
int after() const { return m_after; }
uint32 index() const { return m_index; }
void index(uint32 val) { m_index = val; }
- Slot();
+ Slot(int16 *m_userAttr = NULL);
void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars);
Slot *next() const { return m_next; }
void next(Slot *s) { m_next = s; }
@@ -98,7 +97,7 @@
void after(int ind) { m_after = ind; }
bool isBase() const { return (!m_parent); }
void update(int numSlots, int numCharInfo, Position &relpos);
- Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin);
+ Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal);
bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
bool isCopied() const { return (m_flags & COPIED) ? true : false; }
@@ -108,6 +107,7 @@
bool isInsertBefore() const { return !(m_flags & INSERTED); }
uint8 getBidiLevel() const { return m_bidiLevel; }
void setBidiLevel(uint8 level) { m_bidiLevel = level; }
+ int8 getBidiClass(const Segment *seg);
int8 getBidiClass() const { return m_bidiCls; }
void setBidiClass(int8 cls) { m_bidiCls = cls; }
int16 *userAttrs() const { return m_userAttr; }
@@ -122,16 +122,20 @@
Slot *attachedTo() const { return m_parent; }
Position attachOffset() const { return m_attach - m_with; }
Slot* firstChild() const { return m_child; }
+ void firstChild(Slot *ap) { m_child = ap; }
bool child(Slot *ap);
Slot* nextSibling() const { return m_sibling; }
+ void nextSibling(Slot *ap) { m_sibling = ap; }
bool sibling(Slot *ap);
bool removeChild(Slot *ap);
bool removeSibling(Slot *ap);
- int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel);
+ int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
void positionShift(Position a) { m_position += a; }
void floodShift(Position adj);
float just() const { return m_just; }
void just(float j) { m_just = j; }
+ Slot *nextInCluster(const Slot *s) const;
+ bool isChildOf(const Slot *base) const;
CLASS_NEW_DELETE
diff -Nru graphite2-1.2.4/src/inc/Sparse.h graphite2-1.3.6/src/inc/Sparse.h
--- graphite2-1.2.4/src/inc/Sparse.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/Sparse.h 2016-02-29 04:18:01.000000000 +0000
@@ -56,7 +56,7 @@
key_type offset;
};
- static chunk empty_chunk;
+ static const chunk empty_chunk;
sparse(const sparse &);
sparse & operator = (const sparse &);
@@ -88,7 +88,7 @@
inline
sparse::sparse() throw() : m_nchunks(0)
{
- m_array.map = &empty_chunk;
+ m_array.map = const_cast(&empty_chunk);
}
@@ -113,7 +113,7 @@
}
if (m_nchunks == 0)
{
- m_array.map=&empty_chunk;
+ m_array.map=const_cast(&empty_chunk);
return;
}
@@ -127,6 +127,7 @@
return;
}
+ // coverity[forward_null : FALSE] Since m_array is union and m_array.values is not NULL
chunk * ci = m_array.map;
ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
mapped_type * vi = m_array.values + ci->offset;
diff -Nru graphite2-1.2.4/src/inc/TtfUtil.h graphite2-1.3.6/src/inc/TtfUtil.h
--- graphite2-1.2.4/src/inc/TtfUtil.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/TtfUtil.h 2016-02-29 04:18:01.000000000 +0000
@@ -137,11 +137,11 @@
////////////////////////////////// cmap lookup tools
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
int nEncodingId = 1, size_t length = 0);
- bool CheckCmapSubtable4(const void * pCmap31);
+ bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/);
gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
int * pRangeKey = 0);
- bool CheckCmapSubtable12(const void *pCmap310);
+ bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/);
gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
int * pRangeKey = 0);
diff -Nru graphite2-1.2.4/src/inc/UtfCodec.h graphite2-1.3.6/src/inc/UtfCodec.h
--- graphite2-1.2.4/src/inc/UtfCodec.h 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/inc/UtfCodec.h 2016-02-29 04:18:01.000000000 +0000
@@ -131,9 +131,12 @@
bool toolong = false;
switch(seq_sz) {
- case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); // no break
- case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); // no break
- case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); // no break
+ case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); GR_FALLTHROUGH;
+ // no break
+ case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); GR_FALLTHROUGH;
+ // no break
+ case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); GR_FALLTHROUGH;
+ // no break
case 1: break;
case 0: l = -1; return 0xFFFD;
}
diff -Nru graphite2-1.2.4/src/Intervals.cpp graphite2-1.3.6/src/Intervals.cpp
--- graphite2-1.2.4/src/Intervals.cpp 1970-01-01 00:00:00.000000000 +0000
+++ graphite2-1.3.6/src/Intervals.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -0,0 +1,294 @@
+/* GRAPHITE2 LICENSING
+
+ Copyright 2010, SIL International
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should also have received a copy of the GNU Lesser General Public
+ License along with this library in the file named "LICENSE".
+ If not, write to the Free Software Foundation, 51 Franklin Street,
+ Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+ internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include
+#include
+#include
+
+#include "inc/Intervals.h"
+#include "inc/Segment.h"
+#include "inc/Slot.h"
+#include "inc/debug.h"
+#include "inc/bits.h"
+
+using namespace graphite2;
+
+#include
+
+inline
+Zones::Exclusion Zones::Exclusion::split_at(float p) {
+ Exclusion r(*this);
+ r.xm = x = p;
+ return r;
+}
+
+inline
+void Zones::Exclusion::left_trim(float p) {
+ x = p;
+}
+
+inline
+Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
+ c += rhs.c; sm += rhs.sm; smx += rhs.smx; open = false;
+ return *this;
+}
+
+inline
+uint8 Zones::Exclusion::outcode(float val) const {
+ float p = val;
+ return ((p >= xm) << 1) | (p < x);
+}
+
+void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
+ remove(xmin, xmax);
+ weightedAxis(axis, xmin-_margin_len, xmin, 0, 0, _margin_weight, xmin-_margin_len, 0, 0, false);
+ weightedAxis(axis, xmax, xmax+_margin_len, 0, 0, _margin_weight, xmax+_margin_len, 0, 0, false);
+}
+
+namespace
+{
+
+inline
+bool separated(float a, float b) {
+ return a != b;
+ //return std::fabs(a-b) > std::numeric_limits::epsilon(); // std::epsilon may not work. but 0.5 fails exising 64 bit tests
+ //return std::fabs(a-b) > 0.5f;
+}
+
+}
+
+void Zones::insert(Exclusion e)
+{
+#if !defined GRAPHITE2_NTRACING
+ addDebug(&e);
+#endif
+ e.x = max(e.x, _pos);
+ e.xm = min(e.xm, _posm);
+ if (e.x >= e.xm) return;
+
+ for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie && e.x < e.xm; ++i)
+ {
+ const uint8 oca = e.outcode(i->x),
+ ocb = e.outcode(i->xm);
+ if ((oca & ocb) != 0) continue;
+
+ switch (oca ^ ocb) // What kind of overlap?
+ {
+ case 0: // e completely covers i
+ // split e at i.x into e1,e2
+ // split e2 at i.mx into e2,e3
+ // drop e1 ,i+e2, e=e3
+ *i += e;
+ e.left_trim(i->xm);
+ break;
+ case 1: // e overlaps on the rhs of i
+ // split i at e->x into i1,i2
+ // split e at i.mx into e1,e2
+ // trim i1, insert i2+e1, e=e2
+ if (!separated(i->xm, e.x)) break;
+ if (separated(i->x,e.x)) { i = _exclusions.insert(i,i->split_at(e.x)); ++i; }
+ *i += e;
+ e.left_trim(i->xm);
+ break;
+ case 2: // e overlaps on the lhs of i
+ // split e at i->x into e1,e2
+ // split i at e.mx into i1,i2
+ // drop e1, insert e2+i1, trim i2
+ if (!separated(e.xm, i->x)) return;
+ if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
+ *i += e;
+ return;
+ case 3: // i completely covers e
+ // split i at e.x into i1,i2
+ // split i2 at e.mx into i2,i3
+ // insert i1, insert e+i2
+ if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
+ i = _exclusions.insert(i, i->split_at(e.x));
+ *++i += e;
+ return;
+ }
+
+ ie = _exclusions.end();
+ }
+}
+
+
+void Zones::remove(float x, float xm)
+{
+#if !defined GRAPHITE2_NTRACING
+ removeDebug(x, xm);
+#endif
+ x = max(x, _pos);
+ xm = min(xm, _posm);
+ if (x >= xm) return;
+
+ for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie; ++i)
+ {
+ const uint8 oca = i->outcode(x),
+ ocb = i->outcode(xm);
+ if ((oca & ocb) != 0) continue;
+
+ switch (oca ^ ocb) // What kind of overlap?
+ {
+ case 0: // i completely covers e
+ if (separated(i->x, x)) { i = _exclusions.insert(i,i->split_at(x)); ++i; }
+ GR_FALLTHROUGH;
+ // no break
+ case 1: // i overlaps on the rhs of e
+ i->left_trim(xm);
+ return;
+ case 2: // i overlaps on the lhs of e
+ i->xm = x;
+ if (separated(i->x, i->xm)) break;
+ GR_FALLTHROUGH;
+ // no break
+ case 3: // e completely covers i
+ i = _exclusions.erase(i);
+ --i;
+ break;
+ }
+
+ ie = _exclusions.end();
+ }
+}
+
+
+Zones::const_iterator Zones::find_exclusion_under(float x) const
+{
+ int l = 0, h = _exclusions.size();
+
+ while (l < h)
+ {
+ int const p = (l+h) >> 1;
+ switch (_exclusions[p].outcode(x))
+ {
+ case 0 : return _exclusions.begin()+p;
+ case 1 : h = p; break;
+ case 2 :
+ case 3 : l = p+1; break;
+ }
+ }
+
+ return _exclusions.begin()+l;
+}
+
+
+float Zones::closest(float origin, float & cost) const
+{
+ float best_c = std::numeric_limits::max(),
+ best_x = 0;
+
+ const const_iterator start = find_exclusion_under(origin);
+
+ // Forward scan looking for lowest cost
+ for (const_iterator i = start, ie = _exclusions.end(); i != ie; ++i)
+ if (i->track_cost(best_c, best_x, origin)) break;
+
+ // Backward scan looking for lowest cost
+ // We start from the exclusion to the immediate left of start since we've
+ // already tested start with the right most scan above.
+ for (const_iterator i = start-1, ie = _exclusions.begin()-1; i != ie; --i)
+ if (i->track_cost(best_c, best_x, origin)) break;
+
+ cost = (best_c == std::numeric_limits::max() ? -1 : best_c);
+ return best_x;
+}
+
+
+// Cost and test position functions
+
+bool Zones::Exclusion::track_cost(float & best_cost, float & best_pos, float origin) const {
+ const float p = test_position(origin),
+ localc = cost(p - origin);
+ if (open && localc > best_cost) return true;
+
+ if (localc < best_cost)
+ {
+ best_cost = localc;
+ best_pos = p;
+ }
+ return false;
+}
+
+inline
+float Zones::Exclusion::cost(float p) const {
+ return (sm * p - 2 * smx) * p + c;
+}
+
+
+float Zones::Exclusion::test_position(float origin) const {
+ if (sm < 0)
+ {
+ // sigh, test both ends and perhaps the middle too!
+ float res = x;
+ float cl = cost(x);
+ if (x < origin && xm > origin)
+ {
+ float co = cost(origin);
+ if (co < cl)
+ {
+ cl = co;
+ res = origin;
+ }
+ }
+ float cr = cost(xm);
+ return cl > cr ? xm : res;
+ }
+ else
+ {
+ float zerox = smx / sm + origin;
+ if (zerox < x) return x;
+ else if (zerox > xm) return xm;
+ else return zerox;
+ }
+}
+
+
+#if !defined GRAPHITE2_NTRACING
+
+void Zones::jsonDbgOut(Segment *seg) const {
+
+ if (_dbg)
+ {
+ for (Zones::idebugs s = dbgs_begin(), e = dbgs_end(); s != e; ++s)
+ {
+ *_dbg << json::flat << json::array
+ << objectid(dslot(seg, (Slot *)(s->_env[0])))
+ << reinterpret_cast(s->_env[1]);
+ if (s->_isdel)
+ *_dbg << "remove" << Position(s->_excl.x, s->_excl.xm);
+ else
+ *_dbg << "exclude" << json::flat << json::array
+ << s->_excl.x << s->_excl.xm
+ << s->_excl.sm << s->_excl.smx << s->_excl.c
+ << json::close;
+ *_dbg << json::close;
+ }
+ }
+}
+
+#endif
+
diff -Nru graphite2-1.2.4/src/json.cpp graphite2-1.3.6/src/json.cpp
--- graphite2-1.2.4/src/json.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/json.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -30,6 +30,7 @@
#if !defined GRAPHITE2_NTRACING
#include
+#include
#include "inc/json.h"
using namespace graphite2;
@@ -116,7 +117,20 @@
return *this;
}
-json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; }
+json & json::operator << (json::number f) throw()
+{
+ context(seq);
+ if (std::numeric_limits::infinity() == f)
+ fputs("Infinity", _stream);
+ else if (-std::numeric_limits::infinity() == f)
+ fputs("-Infinity", _stream);
+ else if (std::numeric_limits::quiet_NaN() == f ||
+ std::numeric_limits::signaling_NaN() == f)
+ fputs("NaN", _stream);
+ else
+ fprintf(_stream, "%g", f);
+ return *this;
+}
json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
diff -Nru graphite2-1.2.4/src/Justifier.cpp graphite2-1.3.6/src/Justifier.cpp
--- graphite2-1.2.4/src/Justifier.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/Justifier.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -31,7 +31,7 @@
#include "inc/CharInfo.h"
#include "inc/Slot.h"
#include "inc/Main.h"
-#include
+#include
using namespace graphite2;
@@ -60,7 +60,7 @@
m_tWeight += s->getJustify(seg, level, 3);
}
-float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags flags, Slot *pFirst, Slot *pLast)
+float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags jflags, Slot *pFirst, Slot *pLast)
{
Slot *s, *end;
float currWidth = 0.0;
@@ -70,17 +70,24 @@
if (width < 0 && !(silf()->flags()))
return width;
+ if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
+ {
+ reverseSlots();
+ s = pFirst;
+ pFirst = pLast;
+ pLast = s;
+ }
if (!pFirst) pFirst = pSlot;
while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
if (!pLast) pLast = last();
while (!pLast->isBase()) pLast = pLast->attachedTo();
const float base = pFirst->origin().x / scale;
width = width / scale;
- if ((flags & gr_justEndInline) == 0)
+ if ((jflags & gr_justEndInline) == 0)
{
do {
Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
- if (bbox.bl.x != 0. || bbox.bl.y != 0. || bbox.tr.x != 0. || bbox.tr.y == 0.)
+ if (bbox.bl.x != 0.f || bbox.bl.y != 0.f || bbox.tr.x != 0.f || bbox.tr.y == 0.f)
break;
pLast = pLast->prev();
} while (pLast != pFirst);
@@ -116,8 +123,7 @@
++numLevels;
}
- JustifyTotal *stats = new JustifyTotal[numLevels];
- if (!stats) return -1.0;
+ Vector stats(numLevels);
for (s = pFirst; s != end; s = s->nextSibling())
{
float w = s->origin().x / scale + s->advance() - base;
@@ -127,7 +133,7 @@
s->just(0);
}
- for (int i = (width < 0.0) ? -1 : numLevels - 1; i >= 0; --i)
+ for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
{
float diff;
float error = 0.;
@@ -159,7 +165,7 @@
if (-pref > max) pref = -max;
else tWeight += w;
}
- int actual = step ? int(pref / step) * step : int(pref);
+ int actual = int(pref / step) * step;
if (actual)
{
@@ -171,7 +177,7 @@
}
}
currWidth += diff - error;
- } while (i == 0 && int(abs(error)) > 0 && tWeight);
+ } while (i == 0 && int(std::abs(error)) > 0 && tWeight);
}
Slot *oldFirst = m_first;
@@ -197,14 +203,14 @@
<< "passes" << json::array;
#endif
- if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0. || (silf()->flags() & 1)))
+ if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0.f || (silf()->flags() & 1)))
m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
*dbgout << json::item << json::close; // Close up the passes array
- positionSlots(NULL, pSlot, pLast);
+ positionSlots(NULL, pSlot, pLast, m_dir);
Slot *lEnd = pLast->nextSibling();
*dbgout << "output" << json::array;
for(Slot * t = pSlot; t != lEnd; t = t->next())
@@ -213,7 +219,7 @@
}
#endif
- res = positionSlots(font, pSlot, pLast);
+ res = positionSlots(font, pSlot, pLast, m_dir);
if (silf()->flags() & 1)
{
@@ -222,6 +228,9 @@
}
m_first = oldFirst;
m_last = oldLast;
+
+ if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
+ reverseSlots();
return res.x;
}
diff -Nru graphite2-1.2.4/src/Pass.cpp graphite2-1.3.6/src/Pass.cpp
--- graphite2-1.2.4/src/Pass.cpp 2013-11-29 06:21:26.000000000 +0000
+++ graphite2-1.3.6/src/Pass.cpp 2016-02-29 04:18:01.000000000 +0000
@@ -31,15 +31,24 @@
#include
#include
#include
+#include
#include "inc/Segment.h"
#include "inc/Code.h"
#include "inc/Rule.h"
#include "inc/Error.h"
+#include "inc/Collider.h"
using namespace graphite2;
using vm::Machine;
typedef Machine::Code Code;
+enum KernCollison
+{
+ None = 0,
+ CrossSpace = 1,
+ InWord = 2,
+ reserved = 3
+};
Pass::Pass()
: m_silf(0),
@@ -49,16 +58,22 @@
m_startStates(0),
m_transitions(0),
m_states(0),
- m_flags(0),
+ m_codes(0),
+ m_progs(0),
+ m_numCollRuns(0),
+ m_kernColls(0),
m_iMaxLoop(0),
m_numGlyphs(0),
m_numRules(0),
m_numStates(0),
m_numTransition(0),
m_numSuccess(0),
+ m_successStart(0),
m_numColumns(0),
m_minPreCtxt(0),
- m_maxPreCtxt(0)
+ m_maxPreCtxt(0),
+ m_colThreshold(0),
+ m_isReverseDir(false)
{
}
@@ -70,21 +85,33 @@
free(m_states);
free(m_ruleMap);
- delete [] m_rules;
+ if (m_rules) delete [] m_rules;
+ if (m_codes) delete [] m_codes;
+ free(m_progs);
}
-bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e)
+bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base,
+ GR_MAYBE_UNUSED Face & face, passtype pt, GR_MAYBE_UNUSED uint32 version, Error &e)
{
- const byte * p = pass_start,
- * const pass_end = p + pass_length;
+ const byte * p = pass_start,
+ * const pass_end = p + pass_length;
size_t numRanges;
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
// Read in basic values
- m_flags = be::read(p);
+ const byte flags = be::read(p);
+ if (e.test((flags & 0x1f) &&
+ (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
+ E_BADCOLLISIONPASS))
+ return face.error(e);
+ m_numCollRuns = flags & 0x7;
+ m_kernColls = (flags >> 3) & 0x3;
+ m_isReverseDir = (flags >> 5) & 0x1;
m_iMaxLoop = be::read(p);
+ if (m_iMaxLoop < 1) m_iMaxLoop = 1;
be::skip(p,2); // skip maxContext & maxBackup
m_numRules = be::read(p);
+ if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e);
be::skip(p); // fsmOffset - not sure why we would want this
const byte * const pcCode = pass_start + be::read(p) - subtable_base,
* const rcCode = pass_start + be::read(p) - subtable_base,
@@ -101,11 +128,13 @@
if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS)
|| e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS)
|| e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES)
- || e.test(numRanges == 0, E_NORANGES))
+ || e.test(m_numRules && numRanges == 0, E_NORANGES)
+ || e.test(m_numColumns > 0x7FFF, E_BADNUMCOLUMNS))
return face.error(e);
m_successStart = m_numStates - m_numSuccess;
- if (e.test(p + numRanges * 6 - 4 > pass_end, E_BADPASSLENGTH)) return face.error(e);
+ // test for beyond end - 1 to account for reading uint16
+ if (e.test(p + numRanges * 6 - 2 > pass_end, E_BADPASSLENGTH)) return face.error(e);
m_numGlyphs = be::peek