summaryrefslogtreecommitdiff
path: root/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/harfbuzz/src/hb-ot-cmap-table.hh')
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh200
1 files changed, 138 insertions, 62 deletions
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index fde57cdc5b..09c9fe93f3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -27,6 +27,8 @@
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-shaper-arabic-pua.hh"
#include "hb-open-type.hh"
#include "hb-set.hh"
@@ -44,7 +46,7 @@ struct CmapSubtableFormat0
bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -109,22 +111,26 @@ struct CmapSubtableFormat4
while (it) {
// Start a new range
- start_cp = (*it).first;
- prev_run_start_cp = (*it).first;
- run_start_cp = (*it).first;
- end_cp = (*it).first;
- last_gid = (*it).second;
- run_length = 1;
- prev_delta = 0;
-
- delta = (*it).second - (*it).first;
+ {
+ const auto& pair = *it;
+ start_cp = pair.first;
+ prev_run_start_cp = start_cp;
+ run_start_cp = start_cp;
+ end_cp = start_cp;
+ last_gid = pair.second;
+ run_length = 1;
+ prev_delta = 0;
+ }
+
+ delta = last_gid - start_cp;
mode = FIRST_SUB_RANGE;
it++;
while (it) {
// Process range
- hb_codepoint_t next_cp = (*it).first;
- hb_codepoint_t next_gid = (*it).second;
+ const auto& pair = *it;
+ hb_codepoint_t next_cp = pair.first;
+ hb_codepoint_t next_gid = pair.second;
if (next_cp != end_cp + 1) {
// Current range is over, stop processing.
break;
@@ -282,23 +288,22 @@ struct CmapSubtableFormat4
}
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ hb_requires (hb_is_iterator (Iterator))>
HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
- Iterator it,
+ Iterator it,
HBUINT16 *endCode,
HBUINT16 *startCode,
HBINT16 *idDelta,
unsigned segcount)
{
- hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
- + it | hb_sink (cp_to_gid);
+ hb_map_t cp_to_gid { it };
HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
for (unsigned i : + hb_range (segcount)
- | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
+ | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
{
idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
@@ -323,22 +328,31 @@ struct CmapSubtableFormat4
{ return _.first <= 0xFFFF; })
;
- if (format4_iter.len () == 0) return;
+ if (!format4_iter) return;
unsigned table_initpos = c->length ();
if (unlikely (!c->extend_min (this))) return;
this->format = 4;
+ hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
+ format4_iter
+ };
+
//serialize endCode[], startCode[], idDelta[]
HBUINT16* endCode = c->start_embed<HBUINT16> ();
- unsigned segcount = serialize_find_segcount (format4_iter);
- if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount)))
+ unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
+ if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
return;
HBUINT16 *startCode = endCode + segcount + 1;
HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
- HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
+ HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
+ cp_to_gid.iter (),
+ endCode,
+ startCode,
+ idDelta,
+ segcount);
if (unlikely (!c->check_success (idRangeOffset))) return;
this->length = c->length () - table_initpos;
@@ -401,7 +415,7 @@ struct CmapSubtableFormat4
2,
_hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
this->segCount + 1);
- if (!found)
+ if (unlikely (!found))
return false;
unsigned int i = found - endCount;
@@ -421,7 +435,7 @@ struct CmapSubtableFormat4
gid += this->idDelta[i];
}
gid &= 0xFFFFu;
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -440,14 +454,14 @@ struct CmapSubtableFormat4
hb_codepoint_t start = this->startCount[i];
hb_codepoint_t end = this->endCount[i];
unsigned int rangeOffset = this->idRangeOffset[i];
+ out->add_range(start, end);
if (rangeOffset == 0)
{
for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
{
hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
if (unlikely (!gid))
- continue;
- out->add (codepoint);
+ out->del(codepoint);
}
}
else
@@ -456,11 +470,13 @@ struct CmapSubtableFormat4
{
unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
if (unlikely (index >= this->glyphIdArrayLength))
+ {
+ out->del_range (codepoint, end);
break;
+ }
hb_codepoint_t gid = this->glyphIdArray[index];
if (unlikely (!gid))
- continue;
- out->add (codepoint);
+ out->del(codepoint);
}
}
}
@@ -469,6 +485,8 @@ struct CmapSubtableFormat4
void collect_mapping (hb_set_t *unicodes, /* OUT */
hb_map_t *mapping /* OUT */) const
{
+ // TODO(grieger): optimize similar to collect_unicodes
+ // (ie. use add_range())
unsigned count = this->segCount;
if (count && this->startCount[count - 1] == 0xFFFFu)
count--; /* Skip sentinel segment. */
@@ -620,7 +638,7 @@ struct CmapSubtableTrimmed
{
/* Rely on our implicit array bound-checking. */
hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -674,7 +692,7 @@ struct CmapSubtableTrimmed
};
struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
template <typename T>
struct CmapSubtableLongSegmented
@@ -684,7 +702,7 @@ struct CmapSubtableLongSegmented
bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
- if (!gid)
+ if (unlikely (!gid))
return false;
*glyph = gid;
return true;
@@ -714,7 +732,7 @@ struct CmapSubtableLongSegmented
if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
end = start + (hb_codepoint_t) num_glyphs - gid;
- out->add_range (start, end);
+ out->add_range (start, hb_min (end, 0x10FFFFu));
}
}
@@ -722,11 +740,19 @@ struct CmapSubtableLongSegmented
hb_map_t *mapping, /* OUT */
unsigned num_glyphs) const
{
+ hb_codepoint_t last_end = 0;
for (unsigned i = 0; i < this->groups.len; i++)
{
hb_codepoint_t start = this->groups[i].startCharCode;
hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
(hb_codepoint_t) HB_UNICODE_MAX);
+ if (unlikely (start > end || start < last_end)) {
+ // Range is not in order and is invalid, skip it.
+ continue;
+ }
+ last_end = end;
+
+
hb_codepoint_t gid = this->groups[i].glyphID;
if (!gid)
{
@@ -778,16 +804,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
void serialize (hb_serialize_context_t *c,
Iterator it)
{
- if (it.len () == 0) return;
+ if (!it) return;
unsigned table_initpos = c->length ();
if (unlikely (!c->extend_min (this))) return;
- hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
+ hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
hb_codepoint_t glyphID = 0;
for (const auto& _ : +it)
{
- if (startCharCode == 0xFFFF)
+ if (startCharCode == (hb_codepoint_t) -1)
{
startCharCode = _.first;
endCharCode = _.first;
@@ -818,7 +844,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
this->format = 12;
this->reserved = 0;
this->length = c->length () - table_initpos;
- this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size;
+ this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
}
static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
@@ -883,7 +909,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
hb_codepoint_t first = arrayZ[i].startUnicodeValue;
hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
(hb_codepoint_t) HB_UNICODE_MAX);
- out->add_range (first, last);
+ out->add_range (first, hb_min (last, 0x10FFFFu));
}
}
@@ -1448,6 +1474,51 @@ struct EncodingRecord
DEFINE_SIZE_STATIC (8);
};
+struct SubtableUnicodesCache {
+
+ private:
+ const void* base;
+ hb_hashmap_t<intptr_t, hb::unique_ptr<hb_set_t>> cached_unicodes;
+
+ public:
+ SubtableUnicodesCache(const void* cmap_base)
+ : base(cmap_base), cached_unicodes() {}
+
+ hb_set_t* set_for (const EncodingRecord* record)
+ {
+ if (!cached_unicodes.has ((intptr_t) record))
+ {
+ hb_set_t *s = hb_set_create ();
+ if (unlikely (s->in_error ()))
+ return hb_set_get_empty ();
+
+ (base+record->subtable).collect_unicodes (s);
+
+ if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr<hb_set_t> {s})))
+ return hb_set_get_empty ();
+
+ return s;
+ }
+ return cached_unicodes.get ((intptr_t) record);
+ }
+
+};
+
+static inline uint_fast16_t
+_hb_symbol_pua_map (unsigned codepoint)
+{
+ if (codepoint <= 0x00FFu)
+ {
+ /* For symbol-encoded OpenType fonts, we duplicate the
+ * U+F000..F0FF range at U+0000..U+00FF. That's what
+ * Windows seems to do, and that's hinted about at:
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
+ * under "Non-Standard (Symbol) Fonts". */
+ return 0xF000u + codepoint;
+ }
+ return 0;
+}
+
struct cmap
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
@@ -1467,6 +1538,7 @@ struct cmap
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
auto snap = c->snapshot ();
+ SubtableUnicodesCache unicodes_cache (base);
for (const EncodingRecord& _ : encodingrec_iter)
{
if (c->in_error ())
@@ -1475,12 +1547,11 @@ struct cmap
unsigned format = (base+_.subtable).u.format;
if (format != 4 && format != 12 && format != 14) continue;
- hb_set_t unicodes_set;
- (base+_.subtable).collect_unicodes (&unicodes_set);
+ hb_set_t* unicodes_set = unicodes_cache.set_for (&_);
if (!drop_format_4 && format == 4)
{
- c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+ c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
if (c->in_error () && c->only_overflow ())
{
// cmap4 overflowed, reset and retry serialization without format 4 subtables.
@@ -1495,8 +1566,8 @@ struct cmap
else if (format == 12)
{
- if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
- c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
+ if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue;
+ c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
}
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
}
@@ -1514,6 +1585,7 @@ struct cmap
bool _can_drop (const EncodingRecord& cmap12,
const hb_set_t& cmap12_unicodes,
const void* base,
+ SubtableUnicodesCache& unicodes_cache,
Iterator subset_unicodes,
EncodingRecordIterator encoding_records)
{
@@ -1544,11 +1616,10 @@ struct cmap
|| (base+_.subtable).get_language() != target_language)
continue;
- hb_set_t sibling_unicodes;
- (base+_.subtable).collect_unicodes (&sibling_unicodes);
+ hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_);
auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
- auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
+ auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
for (; cmap12 && sibling; cmap12++, sibling++)
{
unsigned a = *cmap12;
@@ -1616,13 +1687,7 @@ struct cmap
if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
auto it =
- + hb_iter (c->plan->unicodes)
- | hb_map ([&] (hb_codepoint_t _)
- {
- hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID;
- c->plan->new_gid_for_codepoint (_, &new_gid);
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
- })
+ + c->plan->unicode_to_new_gid_list.iter ()
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
{ return (_.second != HB_MAP_VALUE_INVALID); })
;
@@ -1677,7 +1742,24 @@ struct cmap
this->get_glyph_data = subtable;
if (unlikely (symbol))
- this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
+ {
+ switch ((unsigned) face->table.OS2->get_font_page ()) {
+ case OS2::font_page_t::FONT_PAGE_NONE:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
+ break;
+#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
+ case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
+ break;
+ case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
+ this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
+ break;
+#endif
+ default:
+ this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
+ break;
+ }
+ }
else
{
switch (subtable->u.format) {
@@ -1759,6 +1841,7 @@ struct cmap
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
+ typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
template <typename Type>
HB_INTERNAL static bool get_glyph_from (const void *obj,
@@ -1769,7 +1852,7 @@ struct cmap
return typed_obj->get_glyph (codepoint, glyph);
}
- template <typename Type>
+ template <typename Type, hb_pua_remap_func_t remap>
HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
@@ -1778,15 +1861,8 @@ struct cmap
if (likely (typed_obj->get_glyph (codepoint, glyph)))
return true;
- if (codepoint <= 0x00FFu)
- {
- /* For symbol-encoded OpenType fonts, we duplicate the
- * U+F000..F0FF range at U+0000..U+00FF. That's what
- * Windows seems to do, and that's hinted about at:
- * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
- * under "Non-Standard (Symbol) Fonts". */
- return typed_obj->get_glyph (0xF000u + codepoint, glyph);
- }
+ if (hb_codepoint_t c = remap (codepoint))
+ return typed_obj->get_glyph (c, glyph);
return false;
}