Bug 1200098 - Update graphite2 library to release 1.3.2 from upstream. r=jdaggett

This commit is contained in:
Jonathan Kew 2015-09-11 12:31:59 +01:00
parent 947ba96744
commit 8c6cd33572
44 changed files with 749 additions and 411 deletions

View File

@ -1,6 +1,6 @@
This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev
Current version derived from upstream changeset e6539b6769cf
Current version derived from upstream changeset 0f9edca71849
See gfx/graphite2/moz-gr-update.sh for update procedure.

View File

@ -30,7 +30,7 @@
#define GR2_VERSION_MAJOR 1
#define GR2_VERSION_MINOR 3
#define GR2_VERSION_BUGFIX 0
#define GR2_VERSION_BUGFIX 2
#ifdef __cplusplus
extern "C"

View File

@ -170,7 +170,8 @@ enum gr_bidirtl {
/// 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

View File

@ -747,7 +747,7 @@ void resolveWhitespace(int baseLevel, Slot *s)
for ( ; s; s = s->prev())
{
int8 cls = s->getBidiClass();
if (cls == WS || cls & WSflag)
if (cls == WS || (cls & WSflag))
s->setBidiLevel(baseLevel);
else if (cls != BN)
break;

View File

@ -74,7 +74,6 @@ add_library(graphite2 SHARED
gr_logging.cpp
gr_segment.cpp
gr_slot.cpp
Bidi.cpp
CachedFace.cpp
CmapCache.cpp
Code.cpp
@ -107,17 +106,14 @@ set_target_properties(graphite2 PROPERTIES PUBLIC_HEADER "${GRAPHITE_HEADERS}"
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 -Wdouble-promotion"
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)
if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32)
else (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")

View File

@ -38,11 +38,11 @@ const void * bmp_subtable(const Face::Table & cmap)
{
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.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size()))
return stbl;
return 0;
}
@ -51,8 +51,8 @@ const void * smp_subtable(const Face::Table & cmap)
{
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.size())
|| TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size()))
return stbl;
return 0;
}

View File

@ -77,7 +77,6 @@ struct context
} // end namespace
byte * Machine::Code::local_memory = 0;
class Machine::Code::decoder
{
@ -90,7 +89,8 @@ public:
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();
};
@ -146,7 +146,7 @@ inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype
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,
enum passtype pt, byte * & _out)
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(_out==0)
{
@ -162,11 +162,10 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
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.
if (_out) _code = reinterpret_cast<instr *>(_out);
else _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
* (sizeof(instr)+sizeof(byte))));
if (_out) _code = reinterpret_cast<instr *>(*_out);
else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
if (!_code || !_data) {
@ -220,7 +219,7 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
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;
*_out += total_sz;
else
_code = static_cast<instr *>(realloc(_code, total_sz));
_data = reinterpret_cast<byte *>(_code + (_instr_count+1));
@ -418,9 +417,11 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
break;
case PUSH_IGLYPH_ATTR :// not implemented
++_stack_depth;
break;
case POP_RET :
if (--_stack_depth < 0)
failure(underfull_stack);
// no break
case RET_ZERO :
case RET_TRUE :
break;
@ -477,14 +478,23 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
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;
@ -493,14 +503,15 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
case PUT_SUBS :
_code._modify = true;
_analysis.set_changed(_analysis.slotref);
_analysis.set_changed(0);
// 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
@ -513,16 +524,18 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
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;
// 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;
@ -604,6 +617,7 @@ void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end
*tip = temp_copy;
++code_end;
++tempcount;
_code._delete = true;
}
_code._instr_count = code_end - code;
@ -619,8 +633,13 @@ bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * cons
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 - 1 + param_sz > _max.bytecode)
if (bc - 1 + param_sz >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
@ -654,16 +673,28 @@ void Machine::Code::failure(const status_t s) throw() {
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) 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) 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) return;
contexts[index + slotref].flags.changed = true;
if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
@ -682,10 +713,12 @@ int32 Machine::Code::run(Machine & m, slotref * & map) const
// 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 1;
// return m.run(_code, _data, map);
}
return m.run(_code, _data, map);

View File

@ -39,7 +39,7 @@ of the License or (at your option) any later version.
// 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
// #define SUBBOX_RND_ERR 0.016
using namespace graphite2;
@ -543,7 +543,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
}
}
bool res = true;
if (cslot && cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
{
// Set up the bogus slot representing the exclusion glyph.
Slot *exclSlot = seg->newSlot();
@ -925,6 +925,8 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
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);
@ -971,7 +973,6 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift
// Return the amount to kern by.
// TODO: do we need to make use of marginMin here? Probably not.
Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
{

View File

@ -1,75 +1,75 @@
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
Copyright (c) 2015, SIL International
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
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 <cassert>
#include "inc/Decompressor.h"
#include "inc/Shrinker.h"
#include "inc/Compression.h"
using namespace shrinker;
using namespace lz4;
namespace {
u8 const LONG_DIST = 0x10;
u8 const MATCH_LEN = 0x0f;
template <int M>
inline
u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
if (unlikely(l == M))
if (unlikely(l == 15) && likely(s != e))
{
u8 b = 0;
u8 b = 0;
do { l += b = *s++; } while(b==0xff && s != e);
}
return l;
}
bool read_directive(u8 const * &src, u8 const * const end, u32 & literal_len, u32 & match_len, u32 & match_dist)
bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist)
{
u8 const flag = *src++;
u8 const token = *src++;
literal_len = read_literal<7>(src, end, flag >> 5);
match_len = read_literal<15>(src, end, flag & MATCH_LEN);
literal_len = read_literal(src, end, token >> 4);
literal = src;
src += literal_len;
match_dist = *src++;
if (flag & LONG_DIST)
match_dist |= ((*src++) << 8);
if (unlikely(src > end - 2))
return false;
return match_dist != 0xffff;
match_dist = *src++;
match_dist |= *src++ << 8;
match_len = read_literal(src, end, token & 0xf);
return true;
}
}
int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_size)
int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
{
if (out_size <= in_size)
return -1;
u8 const * src = static_cast<u8 const *>(in),
* literal = 0,
* const src_end = src + in_size;
u8 * dst = static_cast<u8*>(out),
@ -78,24 +78,29 @@ int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_s
u32 literal_len = 0,
match_len = 0,
match_dist = 0;
while (read_directive(src, src_end, literal_len, match_len, match_dist))
while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist))
{
// Copy in literal
if (unlikely(dst + literal_len + sizeof(unsigned long) > dst_end)) return -1;
dst = memcpy_nooverlap(dst, src, literal_len);
src += literal_len;
// Copy in literal. At this point the last full sequence must be at
// least MINMATCH + 5 from the end of the output buffer.
if (unlikely(literal + align(literal_len) > src_end
|| 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 - 1;
if (unlikely(pcpy < static_cast<u8*>(out)
|| dst + match_len + MINMATCH + sizeof(unsigned long) > dst_end)) return -1;
dst = memcpy_(dst, pcpy, match_len + MINMATCH);
u8 const * const pcpy = dst - match_dist;
if (unlikely(pcpy < static_cast<u8*>(out)
|| dst + align(match_len + MINMATCH) > dst_end))
return -1;
dst = copy(dst, pcpy, match_len + MINMATCH);
}
if (unlikely(dst + literal_len > dst_end)) return -1;
dst = memcpy_nooverlap_surpass(dst, src, literal_len);
if (unlikely(literal + literal_len > src_end
|| dst + literal_len > dst_end))
return -1;
dst = fast_copy(dst, literal, literal_len);
return dst - (u8*)out;
}

View File

@ -46,7 +46,7 @@ namespace
enum compression
{
NONE,
SHRINKER
LZ4
};
}
@ -125,7 +125,7 @@ bool Face::readGraphite(const Table & silf)
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<uint32>(p);
if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
@ -173,6 +173,10 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
}
#endif
// 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)
{
@ -185,6 +189,7 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
#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;
@ -233,7 +238,9 @@ uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
{
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);
}
}
@ -277,7 +284,6 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
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;
}
@ -285,6 +291,15 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
decompress();
}
void Face::Table::releaseBuffers()
{
if (_compressed)
free(const_cast<byte *>(_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()
{
if (_p == rhs._p) return *this;
@ -297,6 +312,8 @@ Face::Table & Face::Table::operator = (const Table & rhs) throw()
Error Face::Table::decompress()
{
Error e;
if (e.test(_sz < 2 * sizeof(uint32) + 3, E_BADSIZE))
return e;
byte * uncompressed_table = 0;
size_t uncompressed_size = 0;
@ -308,25 +325,30 @@ Error Face::Table::decompress()
switch(compression(hdr >> 27))
{
case NONE: return e;
case SHRINKER:
case LZ4:
{
uncompressed_size = hdr & 0x07ffffff;
uncompressed_table = gralloc<byte>(uncompressed_size);
//TODO: Coverty: 1315803: FORWARD_NULL
if (!e.test(!uncompressed_table, E_OUTOFMEM))
e.test(shrinker::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
//TODO: Coverty: 1315800: CHECKED_RETURN
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)
//TODO: Coverty: 1315800: CHECKED_RETURN
e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
// Tell the provider to release the compressed form since were replacing
// it anyway.
this->~Table();
releaseBuffers();
if (e)
{

View File

@ -131,11 +131,12 @@ bool FeatureMap::readFeats(const Face & face)
const uint16 num_settings = be::read<uint16>(p);
if (version >= 0x00020000)
be::skip<uint16>(p);
const byte * const feat_setts = feat_start + be::read<uint32>(p);
const uint32 settings_offset = be::read<uint32>(p);
const uint16 flags = be::read<uint16>(p),
uiName = be::read<uint16>(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 @@ bool FeatureMap::readFeats(const Face & face)
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

View File

@ -83,7 +83,7 @@ const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name,
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;

View File

@ -62,7 +62,7 @@ namespace
// 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<W> & rhs) { return _v >= rhs._e; }
bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
value_type operator * () const {
@ -78,7 +78,8 @@ namespace
typedef _glat_iterator<uint16> glat2_iterator;
}
const Rect GlyphCache::nullRect = Rect();
const SlantBox SlantBox::empty = {0,0,0,0};
class GlyphCache::Loader
{
@ -145,7 +146,7 @@ GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
}
else if (numsubs > 0)
{
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + (numsubs-1) * 8 * sizeof(float));
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
GlyphBox * currbox = boxes;
for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
@ -277,19 +278,20 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
// 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 >= 0x00020000
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<unsigned short>(tmpnumgattrs);
p = m_pGlat;
version = be::read<uint32>(p);
if (version >= 0x00040000) // reject Glat tables that are too new
@ -347,8 +349,12 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
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<float>(xMin), static_cast<float>(yMin)),
Position(static_cast<float>(xMax), static_cast<float>(yMax)));
}
}
if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
advance = Position(static_cast<float>(nAdvWid), 0);
@ -398,7 +404,8 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
else
{
if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not?
|| gloce - glocs > _num_attrs*3*sizeof(uint16))
|| 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));
}

View File

@ -31,7 +31,7 @@ of the License or (at your option) any later version.
#include "inc/CharInfo.h"
#include "inc/Slot.h"
#include "inc/Main.h"
#include <math.h>
#include <cmath>
using namespace graphite2;
@ -70,6 +70,13 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
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();
@ -170,7 +177,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
}
currWidth += diff - error;
} while (i == 0 && int(abs(error)) > 0 && tWeight);
} while (i == 0 && int(std::abs(error)) > 0 && tWeight);
}
Slot *oldFirst = m_first;
@ -203,7 +210,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
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())
@ -212,7 +219,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
#endif
res = positionSlots(font, pSlot, pLast);
res = positionSlots(font, pSlot, pLast, m_dir);
if (silf()->flags() & 1)
{
@ -221,6 +228,9 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
m_first = oldFirst;
m_last = oldLast;
if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
reverseSlots();
return res.x;
}

View File

@ -42,6 +42,13 @@ 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),
@ -53,16 +60,20 @@ Pass::Pass()
m_states(0),
m_codes(0),
m_progs(0),
m_flags(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)
{
}
@ -88,13 +99,17 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
// Read in basic values
m_flags = be::read<byte>(p);
if (e.test((m_flags & 15) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
const byte flags = be::read<byte>(p);
if (e.test((flags & 0x1f) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
return face.error(e);
m_numCollRuns = flags & 0x7;
m_kernColls = (flags >> 3) & 0x3;
m_isReverseDir = (flags >> 5) & 0x1;
m_iMaxLoop = be::read<byte>(p);
if (m_iMaxLoop < 1) m_iMaxLoop = 1;
be::skip<byte>(p,2); // skip maxContext & maxBackup
m_numRules = be::read<uint16>(p);
if (e.test(!m_numRules && !(m_flags & 7), E_BADEMPTYPASS)) return face.error(e);
if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e);
be::skip<uint16>(p); // fsmOffset - not sure why we would want this
const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
* const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
@ -152,7 +167,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
be::skip<uint16>(p, m_numRules + 1);
const byte * const states = p;
if (e.test(p + 2 * m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
if (e.test(p + 2u*m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
be::skip<int16>(p, m_numTransition*m_numColumns);
be::skip<uint8>(p);
if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
@ -212,9 +227,10 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
// Allocate pools
m_rules = new Rule [m_numRules];
m_codes = new Code [m_numRules*2];
m_progs = static_cast<byte *>(malloc((ac_end - ac_data + rc_end - rc_data)
*(sizeof(vm::instr)+sizeof(byte))));
byte * prog_pool_free = m_progs;
const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
m_progs = gralloc<byte>(prog_pool_sz);
byte * prog_pool_free = m_progs,
* prog_pool_end = m_progs + prog_pool_sz;
if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
Rule * r = m_rules + m_numRules - 1;
@ -233,10 +249,11 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
rc_begin = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
|| rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
|| rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end
|| vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free))
return false;
r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
|| e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
@ -245,19 +262,21 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
return face.error(e);
}
// Shrink the program pool
ptrdiff_t const delta = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs)) - m_progs;
if (delta)
byte * moved_progs = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs));
if (e.test(!moved_progs, E_OUTOFMEM)) return face.error(e);
if (moved_progs != m_progs)
{
m_progs += delta;
for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c)
{
c->externalProgramMoved(delta);
c->externalProgramMoved(moved_progs - m_progs);
}
m_progs = moved_progs;
}
// Load the rule entries map
face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
//TODO: Coverty: 1315804: FORWARD_NULL
RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
if (e.test(!re, E_OUTOFMEM)) return face.error(e);
for (size_t n = num_entries; n; --n, ++re)
@ -360,10 +379,11 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
}
bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const
bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const
{
Slot *s = m.slotMap().segment.first();
if (!s || !testPassConstraint(m)) return true;
if (reverse) m.slotMap().segment.reverseSlots();
if (m_numRules)
{
Slot *currHigh = s->next();
@ -387,23 +407,25 @@ bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const
}
} while (s);
}
//TODO: Use enums for flags
const bool collisions = m_numCollRuns || m_kernColls;
if (!(m_flags & 15) || !m.slotMap().segment.hasCollisionInfo())
if (!collisions || !m.slotMap().segment.hasCollisionInfo())
return true;
if (m_flags & 7)
if (m_numCollRuns)
{
if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
{
m.slotMap().segment.positionSlots(0, 0, 0, true);
m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true);
// m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
}
if (!collisionShift(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
return false;
}
if ((m_flags & 24) && !collisionKern(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
return false;
if ((m_flags & 15) && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
return false;
return true;
}
@ -478,8 +500,8 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
if (r != re)
{
const int adv = doAction(r->rule->action, slot, m);
dumpRuleEventOutput(fsm, *r->rule, slot);
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
dumpRuleEventOutput(fsm, m, *r->rule, slot);
if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
<< json::close; // Close RuelEvent object
@ -501,7 +523,7 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
if (r != re)
{
const int adv = doAction(r->rule->action, slot, m);
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
return;
}
@ -533,7 +555,7 @@ void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEnt
}
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const
{
*fsm.dbgout << json::item << json::flat << json::object
<< "id" << &r - m_rules
@ -551,7 +573,7 @@ void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, S
<< json::close // close "input"
<< "slots" << json::array;
const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
fsm.slots.segment.positionSlots(0);
fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir());
for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
*fsm.dbgout << dslot(&fsm.slots.segment, slot);
@ -607,12 +629,16 @@ bool Pass::testConstraint(const Rule & r, Machine & m) const
}
void SlotMap::collectGarbage()
void SlotMap::collectGarbage(Slot * &aSlot)
{
for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
Slot *& slot = *s;
if(slot->isDeleted() || slot->isCopied())
{
if (slot == aSlot)
aSlot = slot->prev() ? slot->prev() : slot->next();
segment.freeSlot(slot);
}
}
}
@ -681,7 +707,6 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
{
ShiftCollider shiftcoll(dbgout);
// bool isfirst = true;
const uint8 numLoops = m_flags & 7; // number of loops permitted to fix collisions; does not include kerning
bool hasCollisions = false;
Slot *start = seg->first(); // turn on collision fixing for the first slot
Slot *end = NULL;
@ -690,7 +715,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
#if !defined GRAPHITE2_NTRACING
if (dbgout)
*dbgout << "collisions" << json::array
<< json::flat << json::object << "num-loops" << numLoops << json::close;
<< json::flat << json::object << "num-loops" << m_numCollRuns << json::close;
#endif
while (start)
@ -707,7 +732,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
&& !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
return false;
if (s != start && c->flags() & SlotCollision::COLL_END)
if (s != start && (c->flags() & SlotCollision::COLL_END))
{
end = s->next();
break;
@ -720,7 +745,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
#endif
// phase 2 : loop until happy.
for (int i = 0; i < numLoops - 1; ++i)
for (int i = 0; i < m_numCollRuns - 1; ++i)
{
if (hasCollisions || moved)
{
@ -918,7 +943,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
|| (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl)
&& (!isRev // if processing forwards then good to merge otherwise only:
|| !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff
|| (cNbor->flags() & SlotCollision::COLL_KERN && !sameCluster) // ignore other kernable clusters
|| ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster) // ignore other kernable clusters
|| (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs
&& !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
return false;
@ -944,7 +969,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
Rect bbox;
Position here = slotFix->origin() + shift;
float clusterMin = here.x;
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, false);
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false);
}
}
}
@ -1002,7 +1027,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
SlotCollision *cNbor = seg->collisionInfo(nbor);
if (bb.bl.y == 0.f && bb.tr.y == 0.f)
{
if ((m_flags & 24) == 16)
if (m_kernColls == InWord)
break;
// Add space for a space glyph.
currSpace += nbor->advance();

View File

@ -40,7 +40,7 @@ using namespace graphite2;
SegCache::SegCache(const SegCacheStore * store, const Features & feats)
: m_prefixLength(ePrefixLength),
m_maxCachedSegLength(eMaxSpliceSize),
// m_maxCachedSegLength(eMaxSpliceSize),
m_segmentCount(0),
m_features(feats),
m_totalAccessCount(0l), m_totalMisses(0l),
@ -84,7 +84,7 @@ SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs,
{
uint16 pos = 0;
if (!length) return NULL;
assert(length < m_maxCachedSegLength);
// assert(length < m_maxCachedSegLength);
SegCachePrefixArray pArray = m_prefixes;
while (pos + 1 < m_prefixLength)
{

View File

@ -36,7 +36,7 @@ of the License or (at your option) any later version.
#include "inc/Slot.h"
#include "inc/Main.h"
#include "inc/CmapCache.h"
#include "inc/Bidi.h"
//#include "inc/Bidi.h"
#include "inc/Collider.h"
#include "graphite2/Segment.h"
@ -68,8 +68,10 @@ Segment::~Segment()
{
for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
free(*i);
for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j)
free(*j);
for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
free(*i);
for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
free(*i);
delete[] m_charinfo;
}
@ -154,6 +156,12 @@ void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
aSlot->originate(id);
aSlot->before(id);
aSlot->after(id);
// uint8 aBidi = m_silf->aBidi();
// if (aBidi != 0xFF)
// {
// unsigned int bAttr = glyphAttr(gid, aBidi);
// aSlot->setBidiClass((bAttr <= 22) * bAttr);
// }
if (m_last) m_last->next(aSlot);
aSlot->prev(m_last);
m_last = aSlot;
@ -167,6 +175,9 @@ Slot *Segment::newSlot()
{
if (!m_freeSlots)
{
// check that the segment doesn't grow indefinintely
if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
return NULL;
int numUser = m_silf->numUser();
#if !defined GRAPHITE2_NTRACING
if (m_face->logger()) ++numUser;
@ -176,9 +187,8 @@ Slot *Segment::newSlot()
if (!newSlots || !newAttrs) return NULL;
for (size_t i = 0; i < m_bufSize; i++)
{
::new (newSlots + i) Slot(newAttrs + i * numUser);
newSlots[i].next(newSlots + i + 1);
newSlots[i].userAttrs(newAttrs + i * numUser);
newSlots[i].setBidiClass(-1);
}
newSlots[m_bufSize - 1].next(NULL);
newSlots[0].next(NULL);
@ -205,7 +215,7 @@ void Segment::freeSlot(Slot *aSlot)
aSlot->removeChild(aSlot->firstChild());
}
// reset the slot incase it is reused
::new (aSlot) Slot;
::new (aSlot) Slot(aSlot->userAttrs());
memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
// Update generation counter for debug
#if !defined GRAPHITE2_NTRACING
@ -309,6 +319,61 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
}
#endif // GRAPHITE2_NSEGCACHE
// reverse the slots but keep diacritics in their same position after their bases
void Segment::reverseSlots()
{
m_dir = m_dir ^ 64; // invert the reverse flag
if (m_first == m_last) return; // skip 0 or 1 glyph runs
Slot *t = 0;
Slot *curr = m_first;
Slot *tlast;
Slot *tfirst;
Slot *out = 0;
while (curr && getSlotBidiClass(curr) == 16)
curr = curr->next();
if (!curr) return;
tfirst = curr->prev();
tlast = curr;
while (curr)
{
if (getSlotBidiClass(curr) == 16)
{
Slot *d = curr->next();
while (d && getSlotBidiClass(d) == 16)
d = d->next();
d = d ? d->prev() : m_last;
Slot *p = out->next(); // one after the diacritics. out can't be null
if (p)
p->prev(d);
else
tlast = d;
t = d->next();
d->next(p);
curr->prev(out);
out->next(curr);
}
else // will always fire first time round the loop
{
if (out)
out->prev(curr);
t = curr->next();
curr->next(out);
out = curr;
}
curr = t;
}
out->prev(tfirst);
if (tfirst)
tfirst->next(out);
else
m_first = out;
m_last = tlast;
}
void Segment::linkClusters(Slot *s, Slot * end)
{
end = end->next();
@ -338,7 +403,7 @@ void Segment::linkClusters(Slot *s, Slot * end)
}
}
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isFinal)
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
{
Position currpos(0., 0.);
float clusterMin = 0.;
@ -347,12 +412,12 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
if (!iStart) iStart = m_first;
if (!iEnd) iEnd = m_last;
if (m_dir & 1)
if (isRtl)
{
for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
else
@ -360,7 +425,7 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
return currpos;
@ -437,12 +502,13 @@ bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NU
return true;
}
#if 0
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 &stack);
void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
void resolveWhitespace(int baseLevel, Slot *s);
Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0);
void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
void Segment::bidiPass(int paradir, uint8 aMirror)
{
if (slotCount() == 0)
return;
@ -453,11 +519,8 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
unsigned int ssize = 0;
for (s = first(); s; s = s->next())
{
if (s->getBidiClass() == -1)
{
unsigned int bAttr = glyphAttr(s->gid(), aBidi);
s->setBidiClass((bAttr <= 22) * bAttr);
}
if (getSlotBidiClass(s) < 0)
s->setBidiClass(0);
bmask |= (1 << s->getBidiClass());
s->setBidiLevel(baseLevel);
if (s->getBidiClass() == 21)
@ -489,6 +552,18 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
}
}
}
#endif
void Segment::doMirror(uint16 aMirror)
{
Slot * s;
for (s = m_first; s; s = s->next())
{
unsigned short g = glyphAttr(s->gid(), aMirror);
if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
s->setGlyph(this, g);
}
}
bool Segment::initCollisions()
{

View File

@ -51,6 +51,7 @@ Silf::Silf() throw()
m_jPass(0),
m_bPass(0),
m_flags(0),
m_dir(0),
m_aPseudo(0),
m_aBreak(0),
m_aUser(0),
@ -58,6 +59,7 @@ Silf::Silf() throw()
m_aMirror(0),
m_aPassBits(0),
m_iMaxComp(0),
m_aCollision(0),
m_aLig(0),
m_numPseudo(0),
m_nClass(0),
@ -141,10 +143,10 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
}
if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
m_aLig = be::read<uint16>(p);
m_aUser = be::read<uint8>(p);
m_iMaxComp = be::read<uint8>(p);
be::skip<byte>(p); // direction
m_aLig = be::read<uint16>(p);
m_aUser = be::read<uint8>(p);
m_iMaxComp = be::read<uint8>(p);
m_dir = be::read<uint8>(p) - 1;
m_aCollision = be::read<uint8>(p);
be::skip<byte>(p,3);
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
@ -198,7 +200,9 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
* const pass_end = silf_start + be::peek<uint32>(o_passes);
face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16));
if (e.test(pass_start > pass_end, E_BADPASSSTART) || e.test(pass_end > silf_end, E_BADPASSEND)) {
if (e.test(pass_start > pass_end, E_BADPASSSTART)
|| e.test(pass_start < passes_start, E_BADPASSSTART)
|| e.test(pass_end > silf_end, E_BADPASSEND)) {
releaseBuffers(); return face.error(e);
}
@ -268,6 +272,9 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error
if (max_off == ERROROFFSET) return ERROROFFSET;
if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
return ERROROFFSET;
// Check the linear offsets are sane, these must be monotonically increasing.
for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
@ -283,10 +290,10 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error
for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
{
const uint16 * lookup = m_classData + *o;
if (e.test(*o > max_off - 4, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
|| e.test(lookup[0] == 0 // A LookupClass with no looks is a suspicious thing ...
|| lookup[0] > (max_off - *o - 4)/2 // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] != lookup[0] - lookup[1], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange
|| lookup[0] * 2 + *o + 4 > max_off // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange
return ERROROFFSET;
}
@ -307,7 +314,7 @@ uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
const uint16 * cls = m_classData + m_classOffsets[cid];
if (cid < m_nLinear) // output class being used for input, shouldn't happen
{
for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
if (*cls == gid) return i;
return -1;
}
@ -348,7 +355,7 @@ uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
{
assert(seg != 0);
SlotMap map(*seg);
SlotMap map(*seg, m_dir);
FiniteStateMachine fsm(map, seg->getFace()->logger());
vm::Machine m(map);
unsigned int initSize = seg->slotCount();
@ -363,7 +370,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
return true;
lastPass = m_numPasses;
}
if (firstPass <= lbidi && lastPass >= lbidi && dobidi)
if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
lastPass++;
else
lbidi = 0xFF;
@ -379,7 +386,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
*dbgout << json::item << json::object
<< "id" << -1
<< "slots" << json::array;
seg->positionSlots(0);
seg->positionSlots(0, 0, 0, m_dir);
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close
@ -387,22 +394,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
<< json::close;
}
#endif
if (!(seg->dir() & 2))
seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
else if (m_aMirror && (seg->dir() & 1))
{
Slot * s;
for (s = seg->first(); s; s = s->next())
{
unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
s->setGlyph(seg, g);
}
}
if (seg->currdir() != m_dir)
seg->reverseSlots();
if (m_aMirror && (seg->dir() & 3) == 3)
seg->doMirror(m_aMirror);
--i;
lbidi = lastPass;
--lastPass;
lbidi = 0xFF;
continue;
}
@ -412,7 +410,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
*dbgout << json::item << json::object
<< "id" << i+1
<< "slots" << json::array;
seg->positionSlots(0);
seg->positionSlots(0, 0, 0, m_dir);
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close;
@ -420,13 +418,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
#endif
// test whether to reorder, prepare for positioning
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || (m_passes[i].flags() & 7))
&& !m_passes[i].runGraphite(m, fsm))
bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
&& !m_passes[i].runGraphite(m, fsm, reverse))
return false;
// only subsitution passes can change segment length, cached subsegments are short for their text
if (m.status() != vm::Machine::finished
|| (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
|| (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
|| (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))
return false;
}
return true;

View File

@ -34,15 +34,14 @@ of the License or (at your option) any later version.
using namespace graphite2;
Slot::Slot() :
Slot::Slot(int16 *user_attrs) :
m_next(NULL), m_prev(NULL),
m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL),
m_position(0, 0), m_shift(0, 0), m_advance(0, 0),
m_attach(0, 0), m_with(0, 0), m_just(0.),
m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), m_justs(NULL)
// Do not set m_userAttr since it is set *before* new is called since this
// is used as a positional new to reset the GrSlot
m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0),
m_userAttr(user_attrs), m_justs(NULL)
{
}
@ -86,17 +85,17 @@ void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
m_position = m_position + relpos;
}
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal)
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal)
{
SlotCollision *coll = NULL;
if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
float scale = font ? font->scale() : 1.0f;
Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y);
Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
float tAdvance = m_advance.x + m_just;
if (isFinal && (coll = seg->collisionInfo(this)))
{
const Position &collshift = coll->offset();
if (!(coll->flags() & SlotCollision::COLL_KERN) || (seg->dir() & 1))
if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
shift = shift + collshift;
}
const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
@ -134,13 +133,13 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
if (m_child && m_child != this && m_child->attachedTo() == this)
{
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, isFinal);
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal);
if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
}
if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
{
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, isFinal);
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal);
if (tRes.x > res.x) res = tRes;
}
@ -154,12 +153,14 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
return res;
}
int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl)
{
Position base;
if (glyph() >= seg->getFace()->glyphs().numGlyphs())
return 0;
Rect bbox = seg->theGlyphBBoxTemporary(glyph());
float clusterMin = 0.;
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, false);
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
switch (metrics(metric))
{
@ -192,7 +193,6 @@ int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
{
if (!this) return 0;
if (ind == gr_slatUserDefnV1)
{
ind = gr_slatUserDefn;
@ -220,9 +220,7 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
case gr_slatAttLevel : return m_attLevel;
case gr_slatBreak : return seg->charinfo(m_original)->breakWeight();
case gr_slatCompRef : return 0;
case gr_slatDir : if (m_bidiCls == -1)
const_cast<Slot *>(this)->setBidiClass(int8(seg->glyphAttr(gid(), seg->silf()->aBidi())));
return m_bidiCls;
case gr_slatDir : return seg->dir() & 1;
case gr_slatInsert : return isInsertBefore();
case gr_slatPosX : return int(m_position.x); // but need to calculate it
case gr_slatPosY : return int(m_position.y);
@ -272,7 +270,6 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
{
if (!this) return;
if (ind == gr_slatUserDefnV1)
{
ind = gr_slatUserDefn;
@ -299,7 +296,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
if (!other->isChildOf(this) && other->child(this))
{
attachTo(other);
if (((seg->dir() & 1) != 0) ^ (idx > subindex))
if ((map.dir() != 0) ^ (idx > subindex))
m_with = Position(advance(), 0);
else // normal match to previous root
m_attach = Position(other->advance(), 0);
@ -322,7 +319,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
seg->charinfo(m_original)->breakWeight(value);
break;
case gr_slatCompRef : break; // not sure what to do here
case gr_slatDir : m_bidiCls = int8(value); break;
case gr_slatDir : break;
case gr_slatInsert :
markInsertBefore(value? true : false);
break;
@ -450,6 +447,7 @@ bool Slot::removeSibling(Slot *ap)
void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
{
m_glyphid = glyphid;
m_bidiCls = -1;
if (!theGlyph)
{
theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid);
@ -461,6 +459,8 @@ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
}
}
m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()];
if (m_realglyphid > seg->getFace()->glyphs().numGlyphs())
m_realglyphid = 0;
const GlyphFace *aGlyph = theGlyph;
if (m_realglyphid)
{

View File

@ -30,7 +30,7 @@ of the License or (at your option) any later version.
using namespace graphite2;
sparse::chunk sparse::empty_chunk = {0,0};
const sparse::chunk sparse::empty_chunk = {0,0};
sparse::~sparse() throw()
{

View File

@ -62,8 +62,10 @@ Description
***********************************************************************************************/
namespace
{
#ifdef ALL_TTFUTILS
// max number of components allowed in composite glyphs
const int kMaxGlyphComponents = 8;
#endif
template <int R, typename T>
inline float fixed_to_float(const T f) {
@ -227,7 +229,7 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
using namespace Sfnt;
if (pTable == 0) return false;
if (pTable == 0 || lTableSize < 4) return false;
switch(TableId)
{
@ -235,6 +237,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::CharacterCodeMap * const pCmap
= reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable);
if (lTableSize < sizeof(Sfnt::CharacterCodeMap))
return false;
return be::swap(pCmap->version) == 0;
}
@ -242,6 +246,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::FontHeader * const pHead
= reinterpret_cast<const Sfnt::FontHeader *>(pTable);
if (lTableSize < sizeof(Sfnt::FontHeader))
return false;
bool r = be::swap(pHead->version) == OneFix
&& be::swap(pHead->magic_number) == FontHeader::MagicNumber
&& be::swap(pHead->glyph_data_format)
@ -258,6 +264,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::PostScriptGlyphName * const pPost
= reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable);
if (lTableSize < sizeof(Sfnt::PostScriptGlyphName))
return false;
const fixed format = be::swap(pPost->format);
bool r = format == PostScriptGlyphName::Format1
|| format == PostScriptGlyphName::Format2
@ -270,6 +278,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::HorizontalHeader * pHhea =
reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable);
if (lTableSize < sizeof(Sfnt::HorizontalHeader))
return false;
bool r = be::swap(pHhea->version) == OneFix
&& be::swap(pHhea->metric_data_format) == 0
&& sizeof (Sfnt::HorizontalHeader) <= lTableSize;
@ -280,6 +290,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::MaximumProfile * pMaxp =
reinterpret_cast<const Sfnt::MaximumProfile *>(pTable);
if (lTableSize < sizeof(Sfnt::MaximumProfile))
return false;
bool r = be::swap(pMaxp->version) == OneFix
&& sizeof(Sfnt::MaximumProfile) <= lTableSize;
return r;
@ -324,6 +336,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::FontNames * pName
= reinterpret_cast<const Sfnt::FontNames *>(pTable);
if (lTableSize < sizeof(Sfnt::FontNames))
return false;
return be::swap(pName->format) == 0;
}
@ -796,7 +810,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void
size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics);
if (nGlyphId < cLongHorMetrics)
{ // glyph id is acceptable
if (nGlyphId * sizeof(Sfnt::HorizontalMetric) >= lHmtxSize) return false;
if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false;
nAdvWid = be::swap(phmtx[nGlyphId].advance_width);
nLsb = be::swap(phmtx[nGlyphId].left_side_bearing);
}
@ -806,7 +820,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void
size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics +
sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes
// We test like this as LsbOffset is an offset not a length.
if (lLsbOffset > lHmtxSize - sizeof(int16))
if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0)
{
nLsb = 0;
return false;
@ -873,7 +887,7 @@ const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int
/*----------------------------------------------------------------------------------------------
Check the Microsoft Unicode subtable for expected values
----------------------------------------------------------------------------------------------*/
bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/)
{
if (!pCmapSubtable4) return false;
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
@ -882,6 +896,8 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
if (be::swap(pTable->format) != 4) return false;
const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
uint16 length = be::swap(pTable4->length);
if (length > table_len)
return false;
if (length < sizeof(Sfnt::CmapSubTableFormat4))
return false;
uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
@ -919,7 +935,7 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
lastend = end;
}
#endif
return true;;
return true;
}
/*----------------------------------------------------------------------------------------------
@ -1062,7 +1078,7 @@ unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnico
/*----------------------------------------------------------------------------------------------
Check the Microsoft UCS-4 subtable for expected values.
----------------------------------------------------------------------------------------------*/
bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/)
bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/)
{
if (!pCmapSubtable12) return false;
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
@ -1070,6 +1086,8 @@ bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/)
return false;
const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
uint32 length = be::swap(pTable12->length);
if (length > table_len)
return false;
if (length < sizeof(Sfnt::CmapSubTableFormat12))
return false;
uint32 num_groups = be::swap(pTable12->num_groups);
@ -1221,7 +1239,7 @@ size_t LocaLookup(gid16 nGlyphId,
void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen)
{
const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
if (nGlyfOffset == size_t(-1) || nGlyfOffset == size_t(-2) || nGlyfOffset >= nTableLen)
if (nGlyfOffset + pByte < pByte || nGlyfOffset + sizeof(Sfnt::Glyph) >= nTableLen)
return NULL;
return const_cast<uint8 *>(pByte + nGlyfOffset);
}
@ -1833,7 +1851,6 @@ bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca
This range is parallel to the prgnX & prgnY
Return true if successful, false otherwise. On false, all points may be INT_MIN
False may indicate a white space glyph, a multi-level composite, or a corrupt font
// TODO: doesn't support composite glyphs whose components are themselves components
It's not clear from the TTF spec when the transforms should be applied. Should the
transform be done before or after attachment point calcs? (current code - before)
Should the transform be applied to other offsets? (currently - no; however commented

View File

@ -70,6 +70,7 @@ struct regbank {
SlotMap & smap;
slotref * const map_base;
const instr * & ip;
uint8 direction;
int8 flags;
};
@ -86,6 +87,7 @@ namespace {
#define map reg.map
#define mapb reg.map_base
#define flags reg.flags
#define dir reg.direction
#include "inc/opcodes.h"
@ -96,6 +98,7 @@ namespace {
#undef map
#undef mapb
#undef flags
#undef dir
}
Machine::stack_t Machine::run(const instr * program,
@ -110,7 +113,7 @@ Machine::stack_t Machine::run(const instr * program,
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};
// Run the program
while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}

View File

@ -61,6 +61,7 @@ const void * direct_run(const bool get_table_mode,
const byte * data,
Machine::stack_t * stack,
slotref * & __map,
uint8 _dir,
SlotMap * __smap=0)
{
// We need to define and return to opcode table from within this function
@ -79,6 +80,7 @@ const void * direct_run(const bool get_table_mode,
slotref is = *__map,
* map = __map,
* const mapb = smap.begin()+smap.context();
uint8 dir = _dir;
int8 flags = 0;
// start the program
@ -109,7 +111,7 @@ Machine::stack_t Machine::run(const instr * program,
assert(program != 0);
const stack_t *sp = static_cast<const stack_t *>(
direct_run(false, program, data, _stack, is, &_map));
direct_run(false, program, data, _stack, is, _map.dir(), &_map));
const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
check_final_stack(sp);
return ret;

View File

@ -47,7 +47,6 @@ $(_NS)_SOURCES = \
$($(_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 \
@ -78,13 +77,12 @@ $(_NS)_PRIVATE_HEADERS = \
$($(_NS)_BASE)/src/inc/bits.h \
$($(_NS)_BASE)/src/inc/debug.h \
$($(_NS)_BASE)/src/inc/json.h \
$($(_NS)_BASE)/src/inc/locale2lcid.h \
$($(_NS)_BASE)/src/inc/Bidi.h \
$($(_NS)_BASE)/src/inc/CachedFace.h \
$($(_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 \
@ -110,7 +108,6 @@ $(_NS)_PRIVATE_HEADERS = \
$($(_NS)_BASE)/src/inc/SegCacheEntry.h \
$($(_NS)_BASE)/src/inc/SegCacheStore.h \
$($(_NS)_BASE)/src/inc/Segment.h \
$($(_NS)_BASE)/src/inc/Shrinker.h \
$($(_NS)_BASE)/src/inc/Silf.h \
$($(_NS)_BASE)/src/inc/Slot.h \
$($(_NS)_BASE)/src/inc/Sparse.h \

View File

@ -48,7 +48,7 @@ namespace
delete pRes;
return NULL;
}
pRes->finalise(font);
pRes->finalise(font, true);
return static_cast<gr_segment*>(pRes);
}

View File

@ -69,7 +69,6 @@ public:
};
private:
static byte * local_memory;
class decoder;
instr * _code;
@ -87,22 +86,24 @@ private:
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 &,
enum passtype pt, byte * & _out = local_memory);
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;
@ -110,10 +111,16 @@ public:
CLASS_NEW_DELETE;
};
inline
size_t Machine::Code::estimateCodeDataOut(size_t n_bc)
{
return n_bc * (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)
{
}
@ -149,41 +156,6 @@ inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw(
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()
{
return _max_ref;
}
inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
if (_code && !_own)

View File

@ -28,7 +28,7 @@ of the License or (at your option) any later version.
#include <utility>
#include "inc/List.h"
#include "inc/Slot.h"
//#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/Intervals.h"
#include "inc/debug.h"
@ -118,8 +118,8 @@ private:
}; // end of class SlotColllision
class BBox;
class SlantBox;
struct BBox;
struct SlantBox;
class ShiftCollider
{
@ -128,13 +128,7 @@ public:
typedef Vector<fpair> vfpairs;
typedef vfpairs::iterator ivfpairs;
ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
{
#if !defined GRAPHITE2_NTRACING
for (int i = 0; i < 4; ++i)
_ranges[i].setdebug(dbgout);
#endif
}
ShiftCollider(json *dbgout);
~ShiftCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
@ -176,10 +170,25 @@ protected:
}; // 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(GR_MAYBE_UNUSED json *dbg) : _miny(-1e38f), _maxy(1e38f) { };
KernCollider(json *dbg);
~KernCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
const Position &currShift, const Position &offsetPrev, int dir,
@ -213,8 +222,24 @@ private:
inline
float sqr(float x) { return x * x; }
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

View File

@ -0,0 +1,120 @@
/* 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 <cassert>
#include <cstddef>
#include <cstring>
#include <iterator>
#if ((defined GCC_VERSION && GCC_VERSION >= 302) || (defined __INTEL_COMPILER && __INTEL_COMPILER >= 800) || defined(__clang__))
#define expect(expr,value) (__builtin_expect ((expr),(value)) )
#else
#define expect(expr,value) (expr)
#endif
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
namespace
{
#if defined(_MSC_VER)
typedef unsigned __int8 u8;
typedef unsigned __int16 u16;
typedef unsigned __int32 u32;
typedef unsigned __int64 u64;
#else
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#endif
ptrdiff_t const MINMATCH = 4;
template<int S>
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 * 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<WS>(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<WS>(d, s);
d += WS;
s += WS;
}
n &= WS-1;
while (n--) {*d++ = *s++; }
return d;
}
inline
u8 * copy(u8 * d, u8 const * s, size_t n) {
if (likely(d>s+sizeof(unsigned long)))
return overrun_copy(d,s,n);
else
while (n--) *d++ = *s++;
return d;
}
} // end of anonymous namespace

View File

@ -1,51 +1,39 @@
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
Copyright (c) 2015, SIL International
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
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 <cstddef>
namespace shrinker
namespace lz4
{
// return value is either decompressed size of -1
int decompress(void const *in, size_t in_size, void *out, size_t out_size);
/*
in: inbuf --- compressed data
out: outbuf --- decompressed data to place in
size: decompressed(original) data size should be
return value:
positive integer means decompress success and it's the sizeof decompressed data,
which should be equal to size.
or -1 means decompress failed
*/
} // end of namespace shrinker

View File

@ -43,6 +43,7 @@ class FileFace;
class GlyphCache;
class NameTable;
class json;
class Font;
using TtfUtil::Tag;
@ -174,6 +175,8 @@ class Face::Table
Error decompress();
void releaseBuffers();
public:
Table() throw();
Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
@ -202,10 +205,7 @@ Face::Table::Table(const Table & rhs) throw()
inline
Face::Table::~Table() throw()
{
if (_compressed)
free(const_cast<byte *>(_p));
else if (_p && _f->m_ops.release_table)
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
releaseBuffers();
}
inline

View File

@ -56,7 +56,7 @@ class FeatureRef
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 @@ private: //unimplemented
};
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:

View File

@ -39,10 +39,11 @@ class FeatureVal;
class Segment;
class SlantBox
struct SlantBox
{
public:
SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
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
@ -51,11 +52,9 @@ public:
float da; // max
};
static SlantBox nullSlant(0, 0, 0, 0);
class BBox
struct BBox
{
public:
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; }
@ -65,7 +64,6 @@ public:
float ya; // max
};
static BBox nullBBox(0, 0, 0, 0);
class GlyphBox
{
@ -95,8 +93,6 @@ class GlyphCache
GlyphCache(const GlyphCache&);
GlyphCache& operator=(const GlyphCache&);
static const Rect nullRect;
public:
GlyphCache(const Face & face, const uint32 face_options);
~GlyphCache();
@ -110,7 +106,7 @@ public:
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() : nullRect; }
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;
@ -120,6 +116,7 @@ public:
CLASS_NEW_DELETE;
private:
const Rect _empty_slant_box;
const Loader * _glyph_loader;
const GlyphFace * * _glyphs;
GlyphBox * * _boxes;
@ -149,7 +146,7 @@ unsigned short GlyphCache::unitsPerEm() const throw()
inline
bool GlyphCache::check(unsigned short glyphid) const
{
return glyphid < _num_glyphs;
return _boxes && glyphid < _num_glyphs;
}
inline
@ -177,7 +174,7 @@ float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
{
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : nullSlant;
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
}
inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
@ -207,14 +204,12 @@ float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, u
inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
// if (b == NULL || subindex >= b->num()) return nullSlant;
return *(SlantBox *)(b->subs() + 2 * subindex + 1);
}
inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
// if (b == NULL || subindex >= b->num()) return nullBBox;
return *(BBox *)(b->subs() + 2 * subindex);
}

View File

@ -144,6 +144,9 @@ inline
Zones::Zones()
: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
{
#if !defined GRAPHITE2_NTRACING
_dbg = 0;
#endif
_exclusions.reserve(8);
}

View File

@ -105,6 +105,7 @@ void Vector<T>::reserve(size_t n)
{
const ptrdiff_t sz = size();
m_first = static_cast<T*>(realloc(m_first, n*sizeof(T)));
if (!m_first) std::abort();
m_last = m_first + sz;
m_end = m_first + n;
}

View File

@ -85,7 +85,7 @@ template <typename T> T * gralloc(size_t n)
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
return reinterpret_cast<T*>(malloc(sizeof(T) * n));
return static_cast<T*>(malloc(sizeof(T) * n));
}
template <typename T> T * grzeroalloc(size_t n)
@ -93,7 +93,7 @@ template <typename T> T * grzeroalloc(size_t n)
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
return reinterpret_cast<T*>(calloc(n, sizeof(T)));
return static_cast<T*>(calloc(n, sizeof(T)));
}
template <typename T>
@ -128,5 +128,5 @@ inline T max(const T a, const T b)
#ifdef _MSC_VER
#pragma warning(disable: 4800)
#pragma warning(once: 4355)
#pragma warning(disable: 4355)
#endif

View File

@ -53,9 +53,10 @@ public:
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) const;
bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
void init(Silf *silf) { m_silf = silf; }
byte flags() const { return m_flags; }
byte collisionLoops() const { return m_numCollRuns; }
bool reverseDir() const { return m_isReverseDir; }
CLASS_NEW_DELETE
private:
@ -73,7 +74,7 @@ private:
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;
bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
bool collisionKern(Segment *seg, int dir, json * const dbgout) const;
@ -93,7 +94,8 @@ private:
vm::Machine::Code * m_codes;
byte * m_progs;
byte m_flags;
byte m_numCollRuns;
byte m_kernColls;
byte m_iMaxLoop;
uint16 m_numGlyphs;
uint16 m_numRules;
@ -105,6 +107,7 @@ private:
byte m_minPreCtxt;
byte m_maxPreCtxt;
byte m_colThreshold;
bool m_isReverseDir;
vm::Machine::Code m_cPConstraint;
private: //defensive

View File

@ -41,8 +41,8 @@ struct Rule {
uint16 rule_idx;
#endif
Rule() : constraint(0), action(0), sort(0), preContext(0) {}
~Rule();
Rule();
~Rule() {}
CLASS_NEW_DELETE;
@ -51,8 +51,16 @@ private:
Rule & operator = (const Rule &);
};
inline Rule::~Rule()
inline
Rule::Rule()
: constraint(0),
action(0),
sort(0),
preContext(0)
{
#ifndef NDEBUG
rule_idx = 0;
#endif
}
@ -94,7 +102,7 @@ class SlotMap
{
public:
enum {MAX_SLOTS=64};
SlotMap(Segment & seg);
SlotMap(Segment & seg, uint8 direction);
Slot * * begin();
Slot * * end();
@ -105,19 +113,22 @@ public:
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;
};
@ -231,8 +242,8 @@ void FiniteStateMachine::Rules::accumulate_rules(const State &state)
}
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;
}

View File

@ -263,7 +263,7 @@ private:
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;

View File

@ -39,7 +39,7 @@ of the License or (at your option) any later version.
#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/List.h"
#include "inc/Bidi.h"
//#include "inc/Bidi.h"
#include "inc/Collider.h"
#define MAX_SEG_GROWTH_FACTOR 256
@ -48,7 +48,7 @@ namespace graphite2 {
typedef Vector<Features> FeatureList;
typedef Vector<Slot *> SlotRope;
typedef Vector<int16 *> AttributeRope;
typedef Vector<int16 *> AttributeRope;
typedef Vector<SlotJustify *> JustifyRope;
#ifndef GRAPHITE2_NSEGCACHE
@ -101,7 +101,6 @@ public:
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();
@ -124,7 +123,7 @@ public:
void freeSlot(Slot *);
SlotJustify *newJustify();
void freeJustify(SlotJustify *aJustify);
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isFinal = true);
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); }
@ -138,11 +137,13 @@ public:
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; }
@ -150,10 +151,13 @@ public:
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_collisions != 0; }
@ -163,7 +167,7 @@ public:
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 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();
@ -190,24 +194,34 @@ private:
uint8 m_flags; // General purpose flags
};
inline
int8 Segment::getSlotBidiClass(Slot *s) const
{
int8 res = s->getBidiClass();
if (res != -1) return res;
res = 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);
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);

View File

@ -94,6 +94,7 @@ public:
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; }
@ -113,7 +114,7 @@ private:
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, m_aCollision;

View File

@ -32,15 +32,13 @@ of the License or (at your option) any later version.
#include "inc/Font.h"
#include "inc/Position.h"
namespace graphite2 {
typedef gr_attrCode attrCode;
class GlyphFace;
class Segment;
class SegCacheEntry;
class Segment;
struct SlotJustify
{
@ -82,7 +80,7 @@ public:
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; }
@ -99,7 +97,7 @@ public:
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, bool isFinal);
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; }
@ -109,6 +107,7 @@ public:
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; }
@ -130,7 +129,7 @@ public:
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; }

View File

@ -56,7 +56,7 @@ private:
key_type offset;
};
static chunk empty_chunk;
static const chunk empty_chunk;
sparse(const sparse &);
sparse & operator = (const sparse &);
@ -88,7 +88,7 @@ private:
inline
sparse::sparse() throw() : m_nchunks(0)
{
m_array.map = &empty_chunk;
m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);
}
@ -113,7 +113,7 @@ sparse::sparse(I attr, const I last)
}
if (m_nchunks == 0)
{
m_array.map=&empty_chunk;
m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);
return;
}

View File

@ -137,11 +137,11 @@ public:
////////////////////////////////// cmap lookup tools
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
int nEncodingId = 1, size_t length = 0);
bool CheckCmapSubtable4(const void * pCmap31 /*, unsigned int maxgid*/);
bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, 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 /*, unsigned int maxgid*/);
bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, 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);

View File

@ -61,6 +61,7 @@ of the License or (at your option) any later version.
// 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)
@ -313,6 +314,8 @@ STARTOP(insert)
{
newSlot->originate(seg.defaultOriginal());
}
if (is == smap.highwater())
smap.highpassed(false);
is = newSlot;
seg.extendLength(1);
if (map != &smap[-1])
@ -389,7 +392,7 @@ STARTOP(attr_add)
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, 0);
@ -402,7 +405,7 @@ STARTOP(attr_sub)
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, 0);
@ -431,7 +434,7 @@ STARTOP(push_slot_attr)
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), dir);
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@ -458,7 +461,7 @@ STARTOP(push_glyph_metric)
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)
@ -496,7 +499,7 @@ STARTOP(push_att_to_glyph_metric)
{
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
@ -507,7 +510,7 @@ STARTOP(push_islot_attr)
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), dir);
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@ -552,7 +555,7 @@ STARTOP(iattr_add)
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);
@ -566,7 +569,7 @@ STARTOP(iattr_sub)
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);