diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla index 4994b2c665fa..525ba23ab56b 100644 --- a/gfx/graphite2/README.mozilla +++ b/gfx/graphite2/README.mozilla @@ -1,6 +1,6 @@ This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev -Current version derived from upstream changeset 51e72e74b9a6 +Current version derived from upstream changeset 09707dd22634 See gfx/graphite2/moz-gr-update.sh for update procedure. diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h index 3afcace95208..4c9451eb2679 100644 --- a/gfx/graphite2/include/graphite2/Font.h +++ b/gfx/graphite2/include/graphite2/Font.h @@ -30,7 +30,7 @@ #define GR2_VERSION_MAJOR 1 #define GR2_VERSION_MINOR 2 -#define GR2_VERSION_BUGFIX 0 +#define GR2_VERSION_BUGFIX 2 #ifdef __cplusplus extern "C" diff --git a/gfx/graphite2/src/Bidi.cpp b/gfx/graphite2/src/Bidi.cpp index b612a81e6473..c97eeb1738df 100644 --- a/gfx/graphite2/src/Bidi.cpp +++ b/gfx/graphite2/src/Bidi.cpp @@ -37,10 +37,10 @@ enum DirCode { // Hungarian: dirc R = 2, // right-to-left, strong - R AL = 3, // Arabic letter, right-to-left, strong, AR EN = 4, // European number, left-to-right, weak - EN - ES = 5, // European separator, left-to-right, weak - ES + EUS = 5, // European separator, left-to-right, weak - ES ET = 6, // European number terminator, left-to-right, weak - ET AN = 7, // Arabic number, left-to-right, weak - AN - CS = 8, // Common number separator, left-to-right, weak - CS + CUS = 8, // Common number separator, left-to-right, weak - CS WS = 9, // white space, neutral - WS BN = 10, // boundary neutral - BN diff --git a/gfx/graphite2/src/CMakeLists.txt b/gfx/graphite2/src/CMakeLists.txt index ef0f8a7b6dd8..f76cbed114c4 100644 --- a/gfx/graphite2/src/CMakeLists.txt +++ b/gfx/graphite2/src/CMakeLists.txt @@ -52,6 +52,9 @@ if (GRAPHITE2_NTRACING) set(TRACING) endif (GRAPHITE2_NTRACING) +if (GRAPHITE2_TELEMETRY) + add_definitions(-DGRAPHITE2_TELEMETRY) +endif (GRAPHITE2_TELEMETRY) set(GRAPHITE_HEADERS ../include/graphite2/Font.h diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp index c5e4be0366fb..f388df9d2898 100644 --- a/gfx/graphite2/src/CmapCache.cpp +++ b/gfx/graphite2/src/CmapCache.cpp @@ -37,6 +37,7 @@ using namespace graphite2; 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())) @@ -49,6 +50,7 @@ const void * bmp_subtable(const Face::Table & cmap) 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()))) return stbl; @@ -109,6 +111,7 @@ CachedCmap::CachedCmap(const Face & face) CachedCmap::~CachedCmap() throw() { + if (!m_blocks) return; unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100; for (unsigned int i = 0; i < numBlocks; i++) free(m_blocks[i]); diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp index 656582fcee1f..66f60cdd0025 100644 --- a/gfx/graphite2/src/Code.cpp +++ b/gfx/graphite2/src/Code.cpp @@ -144,6 +144,9 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded), _constraint(is_constraint), _modify(false), _delete(false), _own(true) { +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _code_cat(face.tele.code); +#endif assert(bytecode_begin != 0); if (bytecode_begin == bytecode_end) { @@ -210,12 +213,16 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size)); _code = static_cast(realloc(_code, (_instr_count+1)*sizeof(instr))); _data = static_cast(realloc(_data, _data_size*sizeof(byte))); - - // Make this RET_ZERO, we should never reach this but just in case ... - _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint]; if (!_code) failure(alloc_failed); + + // Make this RET_ZERO, we should never reach this but just in case ... + _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint]; + +#ifdef GRAPHITE2_TELEMETRY + telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr)); +#endif } Machine::Code::~Code() throw () diff --git a/gfx/graphite2/src/Face.cpp b/gfx/graphite2/src/Face.cpp index 3428aeaccf4d..a8b8f0ce21a0 100644 --- a/gfx/graphite2/src/Face.cpp +++ b/gfx/graphite2/src/Face.cpp @@ -78,6 +78,9 @@ float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid) bool Face::readGlyphs(uint32 faceOptions) { +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _glyph_cat(tele.glyph); +#endif if (faceOptions & gr_face_cacheCmap) m_cmap = new CachedCmap(*this); else @@ -98,6 +101,9 @@ bool Face::readGlyphs(uint32 faceOptions) bool Face::readGraphite(const Table & silf) { +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _silf_cat(tele.silf); +#endif const byte * p = silf; if (!p) return false; @@ -145,7 +151,8 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const #endif bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass()); - res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses()); + if (res) + res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses()); #if !defined GRAPHITE2_NTRACING if (dbgout) diff --git a/gfx/graphite2/src/FileFace.cpp b/gfx/graphite2/src/FileFace.cpp index dc2f017ed004..79a3213530eb 100644 --- a/gfx/graphite2/src/FileFace.cpp +++ b/gfx/graphite2/src/FileFace.cpp @@ -78,7 +78,7 @@ const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name, if (appFaceHandle == 0) return 0; const FileFace & file_face = *static_cast(appFaceHandle); - char *tbl; + void *tbl; size_t tbl_offset, tbl_len; if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len)) return 0; @@ -87,7 +87,7 @@ const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name, || fseek(file_face._file, tbl_offset, SEEK_SET) != 0) return 0; - tbl = gralloc(tbl_len); + tbl = malloc(tbl_len); if (fread(tbl, 1, tbl_len, file_face._file) != tbl_len) { free(tbl); diff --git a/gfx/graphite2/src/NameTable.cpp b/gfx/graphite2/src/NameTable.cpp index d29b92bc40e1..c9eb7651fe5b 100644 --- a/gfx/graphite2/src/NameTable.cpp +++ b/gfx/graphite2/src/NameTable.cpp @@ -37,7 +37,7 @@ NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0), m_table(0), m_nameData(NULL) { - void *pdata = malloc(length); + void *pdata = gralloc(length); if (!pdata) return; memcpy(pdata, data, length); m_table = reinterpret_cast(pdata); diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp index a44648a85a62..743e260d6111 100644 --- a/gfx/graphite2/src/Pass.cpp +++ b/gfx/graphite2/src/Pass.cpp @@ -46,16 +46,16 @@ Pass::Pass() m_rules(0), m_ruleMap(0), m_startStates(0), - m_sTable(0), + m_transitions(0), m_states(0), m_flags(0), m_iMaxLoop(0), m_numGlyphs(0), m_numRules(0), - m_sRows(0), - m_sTransition(0), - m_sSuccess(0), - m_sColumns(0), + m_numStates(0), + m_numTransition(0), + m_numSuccess(0), + m_numColumns(0), m_minPreCtxt(0), m_maxPreCtxt(0) { @@ -65,14 +65,14 @@ Pass::~Pass() { free(m_cols); free(m_startStates); - free(m_sTable); + free(m_transitions); free(m_states); free(m_ruleMap); delete [] m_rules; } -bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, const Face & face) +bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED const Face & face) { const byte * p = pass_start, * const pass_end = p + pass_length; @@ -89,33 +89,34 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su * const rcCode = pass_start + be::read(p) - subtable_base, * const aCode = pass_start + be::read(p) - subtable_base; be::skip(p); - m_sRows = be::read(p); - m_sTransition = be::read(p); - m_sSuccess = be::read(p); - m_sColumns = be::read(p); + m_numStates = be::read(p); + m_numTransition = be::read(p); + m_numSuccess = be::read(p); + m_numColumns = be::read(p); numRanges = be::read(p); be::skip(p, 3); // skip searchRange, entrySelector & rangeShift. assert(p - pass_start == 40); // Perform some sanity checks. - if ( m_sTransition > m_sRows - || m_sSuccess > m_sRows - || m_sSuccess + m_sTransition < m_sRows + if ( m_numTransition > m_numStates + || m_numSuccess > m_numStates + || m_numSuccess + m_numTransition < m_numStates || numRanges == 0) return false; + m_successStart = m_numStates - m_numSuccess; if (p + numRanges * 6 - 4 > pass_end) return false; m_numGlyphs = be::peek(p + numRanges * 6 - 4) + 1; // Calculate the start of various arrays. const byte * const ranges = p; be::skip(p, numRanges*3); const byte * const o_rule_map = p; - be::skip(p, m_sSuccess + 1); + be::skip(p, m_numSuccess + 1); // More sanity checks - if (reinterpret_cast(o_rule_map + m_sSuccess*sizeof(uint16)) > pass_end + if (reinterpret_cast(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end || p > pass_end) return false; - const size_t numEntries = be::peek(o_rule_map + m_sSuccess*sizeof(uint16)); + const size_t numEntries = be::peek(o_rule_map + m_numSuccess*sizeof(uint16)); const byte * const rule_map = p; be::skip(p, numEntries); @@ -138,7 +139,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su const uint16 * const o_actions = reinterpret_cast(p); be::skip(p, m_numRules + 1); const byte * const states = p; - be::skip(p, m_sTransition*m_sColumns); + be::skip(p, m_numTransition*m_numColumns); be::skip(p); // skip reserved byte if (p != pcCode || p >= pass_end) return false; be::skip(p, pass_constraint_len); @@ -161,7 +162,10 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su if (!readRanges(ranges, numRanges)) return false; if (!readRules(rule_map, numEntries, precontext, sort_keys, o_constraint, rcCode, o_actions, aCode, face)) return false; - return readStates(start_states, states, o_rule_map); +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _states_cat(face.tele.states); +#endif + return readStates(start_states, states, o_rule_map, face); } @@ -225,36 +229,43 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries, static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 : (*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); } -bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map) +bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED const Face & face) { - m_startStates = gralloc(m_maxPreCtxt - m_minPreCtxt + 1); - m_states = gralloc(m_sRows); - m_sTable = gralloc(m_sTransition * m_sColumns); +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _states_cat(face.tele.starts); +#endif + m_startStates = gralloc(m_maxPreCtxt - m_minPreCtxt + 1); +#ifdef GRAPHITE2_TELEMETRY + telemetry::set_category(face.tele.states); +#endif + m_states = gralloc(m_numStates); +#ifdef GRAPHITE2_TELEMETRY + telemetry::set_category(face.tele.transitions); +#endif + m_transitions = gralloc(m_numTransition * m_numColumns); - if (!m_startStates || !m_states || !m_sTable) return false; + if (!m_startStates || !m_states || !m_transitions) return false; // load start states - for (State * * s = m_startStates, - * * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s) + for (uint16 * s = m_startStates, + * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s) { - *s = m_states + be::read(starts); - if (*s < m_states || *s >= m_states + m_sRows) return false; // true; + *s = be::read(starts); + if (*s >= m_numStates) return false; // true; } // load state transition table. - for (State * * t = m_sTable, - * * const t_end = t + m_sTransition*m_sColumns; t != t_end; ++t) + for (uint16 * t = m_transitions, + * const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t) { - *t = m_states + be::read(states); - if (*t < m_states || *t >= m_states + m_sRows) return false; + *t = be::read(states); + if (*t >= m_numStates) return false; } State * s = m_states, - * const transitions_end = m_states + m_sTransition, - * const success_begin = m_states + m_sRows - m_sSuccess; - const RuleEntry * rule_map_end = m_ruleMap + be::peek(o_rule_map + m_sSuccess*sizeof(uint16)); - for (size_t n = m_sRows; n; --n, ++s) + * const success_begin = m_states + m_numStates - m_numSuccess; + const RuleEntry * rule_map_end = m_ruleMap + be::peek(o_rule_map + m_numSuccess*sizeof(uint16)); + for (size_t n = m_numStates; n; --n, ++s) { - s->transitions = s < transitions_end ? m_sTable + (s-m_states)*m_sColumns : 0; RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::read(o_rule_map), * const end = s < success_begin ? 0 : m_ruleMap + be::peek(o_rule_map); @@ -279,7 +290,7 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges) * ci_end = m_cols + be::read(ranges) + 1, col = be::read(ranges); - if (ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_sColumns) + if (ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns) return false; // A glyph must only belong to one column at a time @@ -322,31 +333,30 @@ void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const } while (s); } -inline uint16 Pass::glyphToCol(const uint16 gid) const -{ - return gid < m_numGlyphs ? m_cols[gid] : 0xffffU; -} - bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const { fsm.reset(slot, m_maxPreCtxt); if (fsm.slots.context() < m_minPreCtxt) return false; - const State * state = m_startStates[m_maxPreCtxt - fsm.slots.context()]; + uint16 state = m_startStates[m_maxPreCtxt - fsm.slots.context()]; + uint8 free_slots = SlotMap::MAX_SLOTS; do { fsm.slots.pushSlot(slot); - if (fsm.slots.size() >= SlotMap::MAX_SLOTS) return false; - const uint16 col = glyphToCol(slot->gid()); - if (col == 0xffffU || !state->is_transition()) return true; + if (--free_slots == 0 + || slot->gid() >= m_numGlyphs + || m_cols[slot->gid()] == 0xffffU + || state >= m_numTransition) + return free_slots != 0; - state = state->transitions[col]; - if (state->is_success()) - fsm.rules.accumulate_rules(*state); + const uint16 * transitions = m_transitions + state*m_numColumns; + state = transitions[m_cols[slot->gid()]]; + if (state >= m_successStart) + fsm.rules.accumulate_rules(m_states[state]); slot = slot->next(); - } while (state != m_states && slot); + } while (state != 0 && slot); fsm.slots.pushSlot(slot); return true; diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp index 6e6687c3900a..ccce282bf3f4 100644 --- a/gfx/graphite2/src/Segment.cpp +++ b/gfx/graphite2/src/Segment.cpp @@ -52,6 +52,7 @@ Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int tex m_bufSize(numchars + 10), m_numGlyphs(numchars), m_numCharinfo(numchars), + m_passBits(m_silf->aPassBits() ? -1 : 0), m_defaultOriginal(0), m_dir(textDir) { @@ -128,6 +129,7 @@ void Segment::append(const Segment &other) m_numGlyphs += other.m_numGlyphs; m_advance = m_advance + other.m_advance; m_bbox = m_bbox.widen(bbox); + m_passBits &= other.passBits(); } #endif // GRAPHITE2_NSEGCACHE @@ -150,6 +152,9 @@ void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset) aSlot->prev(m_last); m_last = aSlot; if (!m_first) m_first = aSlot; + if (theGlyph && m_silf->aPassBits()) + m_passBits &= theGlyph->attrs()[m_silf->aPassBits()] + | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0); } Slot *Segment::newSlot() @@ -185,6 +190,13 @@ void Segment::freeSlot(Slot *aSlot) { if (m_last == aSlot) m_last = aSlot->prev(); if (m_first == aSlot) m_first = aSlot->next(); + if (aSlot->attachedTo()) + aSlot->attachedTo()->removeChild(aSlot); + while (aSlot->firstChild()) + { + aSlot->firstChild()->attachTo(NULL); + aSlot->removeChild(aSlot->firstChild()); + } // reset the slot incase it is reused ::new (aSlot) Slot; memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16)); diff --git a/gfx/graphite2/src/Silf.cpp b/gfx/graphite2/src/Silf.cpp index 53c138419375..74b8003611cc 100644 --- a/gfx/graphite2/src/Silf.cpp +++ b/gfx/graphite2/src/Silf.cpp @@ -55,6 +55,7 @@ Silf::Silf() throw() m_aUser(0), m_aBidi(0), m_aMirror(0), + m_aPassBits(0), m_iMaxComp(0), m_aLig(0), m_numPseudo(0), @@ -111,7 +112,7 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, const Face& m_aBreak = be::read(p); m_aBidi = be::read(p); m_aMirror = be::read(p); - be::skip(p); // skip reserved stuff + m_aPassBits = be::read(p); // Read Justification levels. m_numJusts = be::read(p); @@ -374,7 +375,8 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const #endif // test whether to reorder, prepare for positioning - m_passes[i].runGraphite(m, fsm); + if (i >= 32 || (seg->passBits() & (1 << i)) == 0) + m_passes[i].runGraphite(m, fsm); // 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 diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp index f78fee73264e..21618f7e7df3 100644 --- a/gfx/graphite2/src/Slot.cpp +++ b/gfx/graphite2/src/Slot.cpp @@ -87,7 +87,7 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R { if (attrLevel && m_attLevel > attrLevel) return Position(0, 0); float scale = 1.0; - Position shift = m_shift + Position(m_just, 0); + Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y); float tAdvance = m_advance.x + m_just; const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph()); if (font) @@ -144,7 +144,7 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R return res; } -uint32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) +int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) { Position base; Rect bbox = seg->theGlyphBBoxTemporary(gid()); @@ -247,7 +247,9 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons if (idx < map.size() && map[idx]) { Slot *other = map[idx]; - if (other != this && other->child(this)) + if (other == this) break; + if (m_parent) m_parent->removeChild(this); + if (other->child(this)) { attachTo(other); if (((seg->dir() & 1) != 0) ^ (idx > subindex)) @@ -313,7 +315,7 @@ int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value) { - if (level >= seg->silf()->numJustLevels()) return; + if (level && level >= seg->silf()->numJustLevels()) return; if (!m_justs) { SlotJustify *j = seg->newJustify(); @@ -345,6 +347,34 @@ bool Slot::sibling(Slot *ap) return true; } +bool Slot::removeChild(Slot *ap) +{ + if (this == ap || !m_child) return false; + else if (ap == m_child) + { + Slot *nSibling = m_child->nextSibling(); + m_child->sibling(NULL); + m_child = nSibling; + return true; + } + else + return m_child->removeSibling(ap); + return true; +} + +bool Slot::removeSibling(Slot *ap) +{ + if (this == ap || !m_sibling) return false; + else if (ap == m_sibling) + { + m_sibling = m_sibling->nextSibling(); + return true; + } + else + return m_sibling->removeSibling(ap); + return true; +} + void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) { m_glyphid = glyphid; @@ -365,6 +395,8 @@ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) if (aGlyph) theGlyph = aGlyph; } m_advance = Position(theGlyph->theAdvance().x, 0.); + if (seg->silf()->aPassBits()) + seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]); } void Slot::floodShift(Position adj) diff --git a/gfx/graphite2/src/gr_face.cpp b/gfx/graphite2/src/gr_face.cpp index e0f243355229..caf16b33a35b 100644 --- a/gfx/graphite2/src/gr_face.cpp +++ b/gfx/graphite2/src/gr_face.cpp @@ -38,6 +38,9 @@ namespace { bool load_face(Face & face, unsigned int options) { +#ifdef GRAPHITE2_TELEMETRY + telemetry::category _misc_cat(face.tele.misc); +#endif Face::Table silf(face, Tag::Silf); if (silf) options &= ~gr_face_dumbRendering; else if (!(options & gr_face_dumbRendering)) diff --git a/gfx/graphite2/src/gr_logging.cpp b/gfx/graphite2/src/gr_logging.cpp index 9ccd7058d9a2..f989effd3d1b 100644 --- a/gfx/graphite2/src/gr_logging.cpp +++ b/gfx/graphite2/src/gr_logging.cpp @@ -38,7 +38,6 @@ of the License or (at your option) any later version. using namespace graphite2; - extern "C" { @@ -58,19 +57,23 @@ bool gr_start_logging(gr_face * face, const char *log_path) log = _wfopen(wlog_path, L"wt"); free(wlog_path); -#else +#else // _WIN32 FILE *log = fopen(log_path, "wt"); -#endif +#endif // _WIN32 if (!log) return false; face->setLogger(log); if (!face->logger()) return false; *face->logger() << json::array; - return true; -#else - return false; +#ifdef GRAPHITE2_TELEMETRY + *face->logger() << face->tele; #endif + + return true; +#else // GRAPHITE2_NTRACING + return false; +#endif // GRAPHITE2_NTRACING } bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */) @@ -112,8 +115,37 @@ void graphite_stop_logging() } // extern "C" +#ifdef GRAPHITE2_TELEMETRY +size_t * graphite2::telemetry::_category = 0UL; +#endif + #if !defined GRAPHITE2_NTRACING +#ifdef GRAPHITE2_TELEMETRY + +json & graphite2::operator << (json & j, const telemetry & t) throw() +{ + j << json::object + << "type" << "telemetry" + << "silf" << t.silf + << "states" << t.states + << "starts" << t.starts + << "transitions" << t.transitions + << "glyphs" << t.glyph + << "code" << t.code + << "misc" << t.misc + << "total" << (t.silf + t.states + t.starts + t.transitions + t.glyph + t.code + t.misc) + << json::close; + return j; +} +#else +json & graphite2::operator << (json & j, const telemetry &) throw() +{ + return j; +} +#endif + + json & graphite2::operator << (json & j, const CharInfo & ci) throw() { return j << json::object diff --git a/gfx/graphite2/src/inc/Face.h b/gfx/graphite2/src/inc/Face.h index d5436482239b..adf8f77e5917 100644 --- a/gfx/graphite2/src/inc/Face.h +++ b/gfx/graphite2/src/inc/Face.h @@ -43,6 +43,7 @@ class GlyphCache; class NameTable; class json; + using TtfUtil::Tag; // These are the actual tags, as distinct from the consecutive IDs in TtfUtil.h @@ -103,6 +104,10 @@ protected: private: uint16 m_ascent, m_descent; +#ifdef GRAPHITE2_TELEMETRY +public: + mutable telemetry tele; +#endif }; diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h index 655d60696849..f6af44329fa7 100644 --- a/gfx/graphite2/src/inc/Machine.h +++ b/gfx/graphite2/src/inc/Machine.h @@ -36,7 +36,7 @@ of the License or (at your option) any later version. #include "inc/Main.h" #if defined(__GNUC__) -#if defined(__clang__) +#if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ * 10) < 430 #define HOT #if defined(__x86_64) #define REGPARM(n) __attribute__((regparm(n))) diff --git a/gfx/graphite2/src/inc/Main.h b/gfx/graphite2/src/inc/Main.h index 674af80e854b..0717693d6896 100644 --- a/gfx/graphite2/src/inc/Main.h +++ b/gfx/graphite2/src/inc/Main.h @@ -44,15 +44,55 @@ typedef gr_int16 int16; typedef gr_int32 int32; typedef size_t uintptr; +#if GRAPHITE2_TELEMETRY +struct telemetry +{ + class category; + + static size_t * _category; + static void set_category(size_t & t) throw() { _category = &t; } + static void stop() throw() { _category = 0; } + static void count_bytes(size_t n) throw() { if (_category) *_category += n; } + + size_t misc, + silf, + glyph, + code, + states, + starts, + transitions; + + telemetry() : misc(0), silf(0), glyph(0), code(0), states(0), starts(0), transitions(0) {} +}; + +class telemetry::category +{ + size_t * _prev; +public: + category(size_t & t) : _prev(_category) { _category = &t; } + ~category() { _category = _prev; } +}; + +#else +struct telemetry {}; +#endif + // typesafe wrapper around malloc for simple types // use free(pointer) to deallocate + template T * gralloc(size_t n) { +#if GRAPHITE2_TELEMETRY + telemetry::count_bytes(sizeof(T) * n); +#endif return reinterpret_cast(malloc(sizeof(T) * n)); } template T * grzeroalloc(size_t n) { +#if GRAPHITE2_TELEMETRY + telemetry::count_bytes(sizeof(T) * n); +#endif return reinterpret_cast(calloc(n, sizeof(T))); } @@ -71,9 +111,9 @@ inline T max(const T a, const T b) } // namespace graphite2 #define CLASS_NEW_DELETE \ - void * operator new (size_t size){ return malloc(size);} \ + void * operator new (size_t size){ return gralloc(size);} \ void * operator new (size_t, void * p) throw() { return p; } \ - void * operator new[] (size_t size) {return malloc(size);} \ + void * operator new[] (size_t size) {return gralloc(size);} \ void * operator new[] (size_t, void * p) throw() { return p; } \ void operator delete (void * p) throw() { free(p);} \ void operator delete (void *, void *) throw() {} \ diff --git a/gfx/graphite2/src/inc/Pass.h b/gfx/graphite2/src/inc/Pass.h index 6554d937f0ec..5fea65a289b4 100644 --- a/gfx/graphite2/src/inc/Pass.h +++ b/gfx/graphite2/src/inc/Pass.h @@ -61,7 +61,7 @@ private: const uint16 * o_constraint, const byte *constraint_data, const uint16 * o_action, const byte * action_data, const Face &); - bool readStates(const byte * starts, const byte * states, const byte * o_rule_map); + bool readStates(const byte * starts, const byte * states, const byte * o_rule_map, const Face &); bool readRanges(const byte * ranges, size_t num_ranges); uint16 glyphToCol(const uint16 gid) const; bool runFSM(FiniteStateMachine & fsm, Slot * slot) const; @@ -72,18 +72,19 @@ private: uint16 * m_cols; Rule * m_rules; // rules RuleEntry * m_ruleMap; - State * * m_startStates; // prectxt length - State * * m_sTable; + uint16 * m_startStates; // prectxt length + uint16 * m_transitions; State * m_states; byte m_flags; byte m_iMaxLoop; uint16 m_numGlyphs; uint16 m_numRules; - uint16 m_sRows; - uint16 m_sTransition; - uint16 m_sSuccess; - uint16 m_sColumns; + uint16 m_numStates; + uint16 m_numTransition; + uint16 m_numSuccess; + uint16 m_successStart; + uint16 m_numColumns; byte m_minPreCtxt; byte m_maxPreCtxt; vm::Machine::Code m_cPConstraint; diff --git a/gfx/graphite2/src/inc/Rule.h b/gfx/graphite2/src/inc/Rule.h index 69442658e4d2..491d985e3a70 100644 --- a/gfx/graphite2/src/inc/Rule.h +++ b/gfx/graphite2/src/inc/Rule.h @@ -64,11 +64,11 @@ struct RuleEntry inline bool operator < (const RuleEntry &r) const - { - const unsigned short lsort = rule->sort, rsort = r.rule->sort; + { + const unsigned short lsort = rule->sort, rsort = r.rule->sort; return lsort > rsort || (lsort == rsort && rule < r.rule); } - + inline bool operator == (const RuleEntry &r) const { @@ -81,29 +81,14 @@ struct State { const RuleEntry * rules, * rules_end; - const State * const * transitions; - size_t size() const; - bool is_success() const; - bool is_transition() const; + bool empty() const; }; inline -size_t State::size() const +bool State::empty() const { - return rules_end - rules; -} - -inline -bool State::is_success() const -{ - return (rules != NULL); -} - -inline -bool State::is_transition() const -{ - return (transitions != NULL); + return rules_end == rules; } @@ -222,12 +207,13 @@ inline void FiniteStateMachine::Rules::accumulate_rules(const State &state) { // Only bother if there are rules in the State object. - if (state.size() == 0) return; + if (state.empty()) return; // Merge the new sorted rules list into the current sorted result set. const RuleEntry * lre = begin(), * rre = state.rules; RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES; - const RuleEntry * lrend = out + MAX_RULES; + const RuleEntry * const lrend = out + MAX_RULES, + * const rrend = state.rules_end; m_begin = out; while (lre != end() && out != lrend) { @@ -235,14 +221,14 @@ void FiniteStateMachine::Rules::accumulate_rules(const State &state) else if (*rre < *lre) { *out++ = *rre++; } else { *out++ = *lre++; ++rre; } - if (rre == state.rules_end) + if (rre == rrend) { while (lre != end() && out != lrend) { *out++ = *lre++; } m_end = out; return; } } - while (rre != state.rules_end && out != lrend) { *out++ = *rre++; } + while (rre != rrend && out != lrend) { *out++ = *rre++; } m_end = out; } @@ -289,7 +275,7 @@ void SlotMap::reset(Slot & slot, short unsigned int ctxt) inline void SlotMap::pushSlot(Slot*const slot) { - m_slot_map[m_size++ + 1] = slot; + m_slot_map[++m_size] = slot; } inline diff --git a/gfx/graphite2/src/inc/Segment.h b/gfx/graphite2/src/inc/Segment.h index 9e9dc62e7bc7..8ddeeb8106b9 100644 --- a/gfx/graphite2/src/inc/Segment.h +++ b/gfx/graphite2/src/inc/Segment.h @@ -123,8 +123,10 @@ public: int addFeatures(const Features& feats) { m_feats.push_back(feats); return m_feats.size() - 1; } uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); } void dir(int8 val) { m_dir = val; } - uint16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; } - uint16 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const; + 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; 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; } @@ -163,7 +165,8 @@ private: Slot * m_last; // last slot in segment unsigned int m_bufSize, // how big a buffer to create when need more slots m_numGlyphs, - m_numCharinfo; // size of the array and number of input characters + m_numCharinfo, // size of the array and number of input characters + m_passBits; // if bit set then skip pass int m_defaultOriginal; // number of whitespace chars in the string int8 m_dir; }; @@ -181,7 +184,7 @@ void Segment::finalise(const Font *font) } inline -uint16 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const { +int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const { if (attrLevel > 0) { Slot *is = findRoot(iSlot); diff --git a/gfx/graphite2/src/inc/Silf.h b/gfx/graphite2/src/inc/Silf.h index 652f084c8ec6..526d9ba30bde 100644 --- a/gfx/graphite2/src/inc/Silf.h +++ b/gfx/graphite2/src/inc/Silf.h @@ -82,6 +82,7 @@ public: uint8 aPseudo() const { return m_aPseudo; } uint8 aBreak() const { return m_aBreak; } uint8 aMirror() const {return m_aMirror; } + uint8 aPassBits() const { return m_aPassBits; } uint8 substitutionPass() const { return m_sPass; } uint8 positionPass() const { return m_pPass; } uint8 justificationPass() const { return m_jPass; } @@ -111,7 +112,7 @@ private: uint8 m_sPass, m_pPass, m_jPass, m_bPass, m_flags; - uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, + uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits, m_iMaxComp; uint16 m_aLig, m_numPseudo, diff --git a/gfx/graphite2/src/inc/Slot.h b/gfx/graphite2/src/inc/Slot.h index 285d7f105670..3f0c473889a2 100644 --- a/gfx/graphite2/src/inc/Slot.h +++ b/gfx/graphite2/src/inc/Slot.h @@ -125,7 +125,9 @@ public: bool child(Slot *ap); Slot* nextSibling() const { return m_sibling; } bool sibling(Slot *ap); - uint32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel); + bool removeChild(Slot *ap); + bool removeSibling(Slot *ap); + int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel); void positionShift(Position a) { m_position += a; } void floodShift(Position adj); float just() const { return m_just; } diff --git a/gfx/graphite2/src/inc/debug.h b/gfx/graphite2/src/inc/debug.h index 6c733c6a5a48..ba77cb191514 100644 --- a/gfx/graphite2/src/inc/debug.h +++ b/gfx/graphite2/src/inc/debug.h @@ -52,10 +52,13 @@ struct objectid objectid(const Segment * const p) throw(); }; + json & operator << (json & j, const Position &) throw(); json & operator << (json & j, const CharInfo &) throw(); json & operator << (json & j, const dslot &) throw(); json & operator << (json & j, const objectid &) throw(); +json & operator << (json & j, const telemetry &) throw(); + inline diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h index 6fad29f66fcc..835e89351ff6 100644 --- a/gfx/graphite2/src/inc/opcodes.h +++ b/gfx/graphite2/src/inc/opcodes.h @@ -443,7 +443,7 @@ STARTOP(push_glyph_attr_obs) const int slot_ref = int8(param[1]); slotref slot = slotat(slot_ref); if (slot) - push(seg.glyphAttr(slot->gid(), glyph_attr)); + push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); ENDOP STARTOP(push_glyph_metric) @@ -477,7 +477,7 @@ STARTOP(push_att_to_gattr_obs) { slotref att = slot->attachedTo(); if (att) slot = att; - push(seg.glyphAttr(slot->gid(), glyph_attr)); + push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); } ENDOP @@ -491,7 +491,7 @@ STARTOP(push_att_to_glyph_metric) { slotref att = slot->attachedTo(); if (att) slot = att; - push(seg.getGlyphMetric(slot, glyph_attr, attr_level)); + push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level))); } ENDOP @@ -616,7 +616,7 @@ STARTOP(push_glyph_attr) const int slot_ref = int8(param[2]); slotref slot = slotat(slot_ref); if (slot) - push(seg.glyphAttr(slot->gid(), glyph_attr)); + push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); ENDOP STARTOP(push_att_to_glyph_attr) @@ -629,7 +629,7 @@ STARTOP(push_att_to_glyph_attr) { slotref att = slot->attachedTo(); if (att) slot = att; - push(seg.glyphAttr(slot->gid(), glyph_attr)); + push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); } ENDOP