зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1473064 - Update HarfBuzz to version 1.8.3. r=jfkthame
--HG-- extra : rebase_source : 3c306d165a8c22c9f38f6faa9aa755d07ad197c8
This commit is contained in:
Родитель
1f2b809d39
Коммит
16fa6aac83
|
@ -1,3 +1,18 @@
|
|||
Overview of changes leading to 1.8.3
|
||||
Wednesday, July 11, 2018
|
||||
====================================
|
||||
- A couple of Indic / USE bug fixes.
|
||||
- Disable vectorization, as it was causing unaligned access bus error on
|
||||
certain 32bit architectures.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.2
|
||||
Tuesday, July 3, 2018
|
||||
====================================
|
||||
- Fix infinite loop in Khmer shaper.
|
||||
- Improve hb_blob_create_from_file() for streams.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.1
|
||||
Tuesday, June 12, 2018
|
||||
====================================
|
||||
|
@ -5,6 +20,7 @@ Tuesday, June 12, 2018
|
|||
- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
|
||||
- Remove HB_SUBSET_BUILTIN build option. Not necessary.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.0
|
||||
Tuesday, June 5, 2018
|
||||
====================================
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
gfx/harfbuzz status as of 2018-06-12:
|
||||
This directory contains the HarfBuzz source from the upstream repo:
|
||||
https://github.com/harfbuzz/harfbuzz
|
||||
|
||||
This directory contains the HarfBuzz source from the 'master' branch of
|
||||
https://github.com/behdad/harfbuzz.
|
||||
|
||||
Current version: 1.8.1
|
||||
Current version: 1.8.3 [commit 2b76767bf572364d3d647cdd139f2044a7ad06b2]
|
||||
|
||||
UPDATING:
|
||||
|
||||
|
@ -11,5 +9,9 @@ Our in-tree copy of HarfBuzz does not depend on any generated files from the
|
|||
upstream build system. Therefore, it should be sufficient to simply overwrite
|
||||
the in-tree files one the updated ones from upstream to perform updates.
|
||||
|
||||
To simplify this, the in-tree copy can be updated by running
|
||||
sh update.sh
|
||||
from within the gfx/harfbuzz directory.
|
||||
|
||||
If the collection of source files changes, manual updates to moz.build may be
|
||||
needed as we don't use the upstream makefiles.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[1.8.1],
|
||||
[1.8.3],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
@ -78,7 +78,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
|
|||
])
|
||||
|
||||
# Functions and headers
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
|
||||
|
||||
save_libs="$LIBS"
|
||||
LIBS="$LIBS -lm"
|
||||
|
|
|
@ -277,13 +277,13 @@ endif
|
|||
check: $(DEF_FILES) # For check-symbols.sh
|
||||
CLEANFILES += $(DEF_FILES)
|
||||
harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
|
||||
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-subset.def: $(HB_SUBSET_headers)
|
||||
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-icu.def: $(HB_ICU_headers)
|
||||
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
|
||||
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
|
||||
|
||||
GENERATORS = \
|
||||
|
|
|
@ -4,8 +4,14 @@ from __future__ import print_function, division, absolute_import
|
|||
|
||||
import io, os, re, sys
|
||||
|
||||
if len (sys.argv) < 3:
|
||||
sys.exit("usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]")
|
||||
|
||||
output_file = sys.argv[1]
|
||||
header_paths = sys.argv[2:]
|
||||
|
||||
headers_content = []
|
||||
for h in os.environ["headers"].split (' '):
|
||||
for h in header_paths:
|
||||
if h.endswith (".h"):
|
||||
with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
|
||||
|
||||
|
@ -13,7 +19,7 @@ result = """EXPORTS
|
|||
%s
|
||||
LIBRARY lib%s-0.dll""" % (
|
||||
"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
|
||||
sys.argv[1].replace ('.def', '')
|
||||
output_file.replace ('.def', '')
|
||||
)
|
||||
|
||||
with open (sys.argv[1], "w") as f: f.write (result)
|
||||
with open (output_file, "w") as f: f.write (result)
|
||||
|
|
|
@ -47,6 +47,9 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
|
|||
data[0][0x034F] = defaults[0]
|
||||
data[0][0x2060] = defaults[0]
|
||||
data[0][0x20F0] = defaults[0]
|
||||
# TODO https://github.com/roozbehp/unicode-data/issues/9
|
||||
data[0][0x11C44] = 'Consonant_Placeholder'
|
||||
data[0][0x11C45] = 'Consonant_Placeholder'
|
||||
for u in range (0xFE00, 0xFE0F + 1):
|
||||
data[0][u] = defaults[0]
|
||||
|
||||
|
@ -165,7 +168,7 @@ def is_BASE(U, UISC, UGC):
|
|||
def is_BASE_IND(U, UISC, UGC):
|
||||
#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
|
||||
return (UISC in [Consonant_Dead, Modifying_Letter] or
|
||||
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45]) or
|
||||
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
|
||||
False # SPEC-DRAFT-OUTDATED! U == 0x002D
|
||||
)
|
||||
def is_BASE_NUM(U, UISC, UGC):
|
||||
|
@ -344,6 +347,9 @@ def map_to_use(data):
|
|||
if 0xA926 <= U <= 0xA92A: UIPC = Top
|
||||
if U == 0x111CA: UIPC = Bottom
|
||||
if U == 0x11300: UIPC = Top
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
|
||||
if U == 0x11302: UIPC = Top
|
||||
if U == 0x1133C: UIPC = Bottom
|
||||
if U == 0x1171E: UIPC = Left # Correct?!
|
||||
if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
|
||||
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
|
||||
|
|
|
@ -172,7 +172,7 @@ struct trak
|
|||
hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
/* TODO This is wrong. */
|
||||
buffer->pos[start].x_offset += advance_to_add;
|
||||
buffer->pos[start].x_advance += advance_to_add;
|
||||
buffer->pos[end].x_advance += advance_to_add;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ struct trak
|
|||
hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
/* TODO This is wrong. */
|
||||
buffer->pos[start].y_offset += advance_to_add;
|
||||
buffer->pos[start].y_advance += advance_to_add;
|
||||
buffer->pos[end].y_advance += advance_to_add;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_blob_t
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#endif
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-blob-private.hh"
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
|
@ -489,10 +488,10 @@ hb_blob_t::try_make_writable (void)
|
|||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef _O_BINARY
|
||||
# define _O_BINARY 0
|
||||
#else
|
||||
# ifndef _O_BINARY
|
||||
# define _O_BINARY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef MAP_NORESERVE
|
||||
|
@ -508,6 +507,7 @@ struct hb_mapped_file_t
|
|||
#endif
|
||||
};
|
||||
|
||||
#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
|
||||
static void
|
||||
_hb_mapped_file_destroy (hb_mapped_file_t *file)
|
||||
{
|
||||
|
@ -517,11 +517,12 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file)
|
|||
UnmapViewOfFile (file->contents);
|
||||
CloseHandle (file->mapping);
|
||||
#else
|
||||
free (file->contents);
|
||||
assert (0); // If we don't have mmap we shouldn't reach here
|
||||
#endif
|
||||
|
||||
free (file);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_blob_create_from_file:
|
||||
|
@ -534,77 +535,109 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file)
|
|||
hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name)
|
||||
{
|
||||
// Adopted from glib's gmappedfile.c with Matthias Clasen and
|
||||
// Allison Lortie permission but changed a lot to suit our need.
|
||||
bool writable = false;
|
||||
hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
|
||||
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
|
||||
Allison Lortie permission but changed a lot to suit our need. */
|
||||
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
|
||||
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
|
||||
# define CLOSE close
|
||||
int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
|
||||
if (unlikely (fd == -1)) goto fail_without_close;
|
||||
|
||||
struct stat st;
|
||||
if (unlikely (fstat (fd, &st) == -1)) goto fail;
|
||||
|
||||
// See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142
|
||||
if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail;
|
||||
|
||||
file->length = (unsigned long) st.st_size;
|
||||
file->contents = (char *) mmap (nullptr, file->length,
|
||||
writable ? PROT_READ|PROT_WRITE : PROT_READ,
|
||||
file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
|
||||
MAP_PRIVATE | MAP_NORESERVE, fd, 0);
|
||||
|
||||
if (unlikely (file->contents == MAP_FAILED)) goto fail;
|
||||
|
||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||
HANDLE fd = CreateFile (file_name,
|
||||
writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ,
|
||||
FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
|
||||
# define CLOSE CloseHandle
|
||||
close (fd);
|
||||
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||
|
||||
fail:
|
||||
close (fd);
|
||||
fail_without_close:
|
||||
free (file);
|
||||
|
||||
#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
|
||||
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||
|
||||
HANDLE fd;
|
||||
unsigned int size = strlen (file_name) + 1;
|
||||
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
|
||||
nullptr);
|
||||
free (wchar_file_name);
|
||||
|
||||
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
||||
|
||||
file->length = (unsigned long) GetFileSize (fd, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr,
|
||||
writable ? PAGE_WRITECOPY : PAGE_READONLY,
|
||||
0, 0, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (unlikely (file->mapping == nullptr)) goto fail;
|
||||
|
||||
file->contents = (char *) MapViewOfFile (file->mapping,
|
||||
writable ? FILE_MAP_COPY : FILE_MAP_READ,
|
||||
0, 0, 0);
|
||||
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (unlikely (file->contents == nullptr)) goto fail;
|
||||
|
||||
#else
|
||||
mm = HB_MEMORY_MODE_WRITABLE;
|
||||
|
||||
FILE *fd = fopen (file_name, "rb");
|
||||
# define CLOSE fclose
|
||||
if (unlikely (!fd)) goto fail_without_close;
|
||||
|
||||
fseek (fd, 0, SEEK_END);
|
||||
file->length = ftell (fd);
|
||||
rewind (fd);
|
||||
file->contents = (char *) malloc (file->length);
|
||||
if (unlikely (!file->contents)) goto fail;
|
||||
|
||||
if (unlikely (fread (file->contents, 1, file->length, fd) != file->length))
|
||||
goto fail;
|
||||
|
||||
#endif
|
||||
|
||||
CLOSE (fd);
|
||||
return hb_blob_create (file->contents, file->length, mm, (void *) file,
|
||||
CloseHandle (fd);
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||
|
||||
fail:
|
||||
CLOSE (fd);
|
||||
#undef CLOSE
|
||||
CloseHandle (fd);
|
||||
fail_without_close:
|
||||
free (file);
|
||||
|
||||
#endif
|
||||
|
||||
/* The following tries to read a file without knowing its size beforehand
|
||||
It's used as a fallback for systems without mmap or to read from pipes */
|
||||
unsigned long len = 0, allocated = BUFSIZ * 16;
|
||||
char *data = (char *) malloc (allocated);
|
||||
if (unlikely (data == nullptr)) return hb_blob_get_empty ();
|
||||
|
||||
FILE *fp = fopen (file_name, "rb");
|
||||
if (unlikely (fp == nullptr)) goto fread_fail_without_close;
|
||||
|
||||
while (!feof (fp))
|
||||
{
|
||||
if (allocated - len < BUFSIZ)
|
||||
{
|
||||
allocated *= 2;
|
||||
/* Don't allocate and go more than ~536MB, our mmap reader still
|
||||
can cover files like that but lets limit our fallback reader */
|
||||
if (unlikely (allocated > (2 << 28))) goto fread_fail;
|
||||
char *new_data = (char *) realloc (data, allocated);
|
||||
if (unlikely (new_data == nullptr)) goto fread_fail;
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
unsigned long addition = fread (data + len, 1, allocated - len, fp);
|
||||
|
||||
int err = ferror (fp);
|
||||
#ifdef EINTR // armcc doesn't have it
|
||||
if (unlikely (err == EINTR)) continue;
|
||||
#endif
|
||||
if (unlikely (err)) goto fread_fail;
|
||||
|
||||
len += addition;
|
||||
}
|
||||
|
||||
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
||||
(hb_destroy_func_t) free);
|
||||
|
||||
fread_fail:
|
||||
fclose (fp);
|
||||
fread_fail_without_close:
|
||||
free (data);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#define HB_BUFFER_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-unicode-private.hh"
|
||||
|
||||
|
||||
|
|
|
@ -124,14 +124,14 @@ hb_buffer_t::enlarge (unsigned int size)
|
|||
hb_glyph_info_t *new_info = nullptr;
|
||||
bool separate_out = out_info != info;
|
||||
|
||||
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
|
||||
if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))
|
||||
goto done;
|
||||
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 32;
|
||||
|
||||
static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
|
||||
if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
|
||||
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
|
||||
goto done;
|
||||
|
||||
new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-mutex-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
|
@ -545,6 +543,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
|
|||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
|
||||
case HB_SCRIPT_OLD_ITALIC:
|
||||
case HB_SCRIPT_RUNIC:
|
||||
|
||||
return HB_DIRECTION_INVALID;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#define HB_SHAPER coretext
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define HB_DEBUG_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
|
||||
|
||||
#ifndef HB_DEBUG
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#define HB_SHAPER directwrite
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
|
|
|
@ -30,6 +30,243 @@
|
|||
#include "hb-private.hh"
|
||||
|
||||
|
||||
/* Void! For when we need a expression-type of void. */
|
||||
typedef const struct _hb_void_t *hb_void_t;
|
||||
#define HB_VOID ((const _hb_void_t *) nullptr)
|
||||
|
||||
|
||||
/*
|
||||
* Bithacks.
|
||||
*/
|
||||
|
||||
/* Return the number of 1 bits in v. */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_popcount (T v)
|
||||
{
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_popcount (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_popcountl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_popcountll (v);
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "HACKMEM 169" */
|
||||
uint32_t y;
|
||||
y = (v >> 1) &033333333333;
|
||||
y = v - y - ((y >>1) & 033333333333);
|
||||
return (((y + (y >> 3)) & 030707070707) % 077);
|
||||
}
|
||||
|
||||
if (sizeof (T) == 8)
|
||||
{
|
||||
unsigned int shift = 32;
|
||||
return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
|
||||
}
|
||||
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of bits needed to store number */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_bit_storage (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return sizeof (unsigned int) * 8 - __builtin_clz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# if _WIN64
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse64 (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16};
|
||||
unsigned int r = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
|
||||
unsigned int r = 0;
|
||||
for (int i = 5; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
|
||||
hb_bit_storage<uint64_t> ((uint64_t) v);
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of zero bits in the least significant side of v */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_ctz (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_ctz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_ctzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_ctzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward (&where, v);
|
||||
return where;
|
||||
}
|
||||
# if _WIN64
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward64 (&where, v);
|
||||
return where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 32;
|
||||
v &= - (int32_t) v;
|
||||
if (v) c--;
|
||||
if (v & 0x0000FFFF) c -= 16;
|
||||
if (v & 0x00FF00FF) c -= 8;
|
||||
if (v & 0x0F0F0F0F) c -= 4;
|
||||
if (v & 0x33333333) c -= 2;
|
||||
if (v & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 64;
|
||||
v &= - (int64_t) (v);
|
||||
if (v) c--;
|
||||
if (v & 0x00000000FFFFFFFFULL) c -= 32;
|
||||
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
|
||||
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
|
||||
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
|
||||
if (v & 0x3333333333333333ULL) c -= 2;
|
||||
if (v & 0x5555555555555555ULL) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
|
||||
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tiny stuff.
|
||||
*/
|
||||
|
||||
#undef MIN
|
||||
template <typename Type>
|
||||
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
|
||||
|
||||
#undef MAX
|
||||
template <typename Type>
|
||||
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
|
||||
|
||||
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
|
||||
{ return (a + (b - 1)) / b; }
|
||||
|
||||
|
||||
#undef ARRAY_LENGTH
|
||||
template <typename Type, unsigned int n>
|
||||
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
|
||||
/* A const version, but does not detect erratically being called on pointers. */
|
||||
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
static inline bool
|
||||
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
|
||||
{
|
||||
return (size > 0) && (count >= ((unsigned int) -1) / size);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hb_ceil_to_4 (unsigned int v)
|
||||
{
|
||||
return ((v - 1) | 3) + 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sort and search.
|
||||
*/
|
||||
|
||||
static inline void *
|
||||
hb_bsearch_r (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
|
@ -53,7 +290,6 @@ hb_bsearch_r (const void *key, const void *base,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* From https://github.com/noporpoise/sort_r */
|
||||
|
||||
/* Isaac Turner 29 April 2014 Public Domain */
|
||||
|
@ -158,4 +394,471 @@ static inline void hb_sort_r(void *base, size_t nel, size_t width,
|
|||
sort_r_simple(base, nel, width, compar, arg);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T2> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
|
||||
{
|
||||
for (unsigned int i = 1; i < len; i++)
|
||||
{
|
||||
unsigned int j = i;
|
||||
while (j && compar (&array[j - 1], &array[i]) > 0)
|
||||
j--;
|
||||
if (i == j)
|
||||
continue;
|
||||
/* Move item i to occupy place for item j, shift what's in between. */
|
||||
{
|
||||
T t = array[i];
|
||||
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
|
||||
array[j] = t;
|
||||
}
|
||||
if (array2)
|
||||
{
|
||||
T2 t = array2[i];
|
||||
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
|
||||
array2[j] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
|
||||
{
|
||||
hb_stable_sort (array, len, compar, (int *) nullptr);
|
||||
}
|
||||
|
||||
static inline hb_bool_t
|
||||
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
|
||||
{
|
||||
/* Pain because we don't know whether s is nul-terminated. */
|
||||
char buf[64];
|
||||
len = MIN (ARRAY_LENGTH (buf) - 1, len);
|
||||
strncpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
unsigned long v = strtoul (buf, &end, base);
|
||||
if (errno) return false;
|
||||
if (*end) return false;
|
||||
*out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define HB_VECTOR_INIT {0, 0, false, nullptr}
|
||||
template <typename Type, unsigned int StaticSize=8>
|
||||
struct hb_vector_t
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int allocated;
|
||||
bool successful;
|
||||
Type *arrayZ;
|
||||
Type static_array[StaticSize];
|
||||
|
||||
void init (void)
|
||||
{
|
||||
len = 0;
|
||||
allocated = ARRAY_LENGTH (static_array);
|
||||
successful = true;
|
||||
arrayZ = static_array;
|
||||
}
|
||||
|
||||
inline Type& operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Crap (Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Null(Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline Type *push (void)
|
||||
{
|
||||
if (unlikely (!resize (len + 1)))
|
||||
return &Crap(Type);
|
||||
return &arrayZ[len - 1];
|
||||
}
|
||||
inline Type *push (const Type& v)
|
||||
{
|
||||
Type *p = push ();
|
||||
*p = v;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Allocate for size but don't adjust len. */
|
||||
inline bool alloc (unsigned int size)
|
||||
{
|
||||
if (unlikely (!successful))
|
||||
return false;
|
||||
|
||||
if (likely (size <= allocated))
|
||||
return true;
|
||||
|
||||
/* Reallocate */
|
||||
|
||||
unsigned int new_allocated = allocated;
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 8;
|
||||
|
||||
Type *new_array = nullptr;
|
||||
|
||||
if (arrayZ == static_array)
|
||||
{
|
||||
new_array = (Type *) calloc (new_allocated, sizeof (Type));
|
||||
if (new_array)
|
||||
memcpy (new_array, arrayZ, len * sizeof (Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
|
||||
if (likely (!overflows))
|
||||
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
|
||||
}
|
||||
|
||||
if (unlikely (!new_array))
|
||||
{
|
||||
successful = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
arrayZ = new_array;
|
||||
allocated = new_allocated;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool resize (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (!alloc (size))
|
||||
return false;
|
||||
|
||||
if (size > len)
|
||||
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
|
||||
|
||||
len = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pop (void)
|
||||
{
|
||||
if (!len) return;
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void remove (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return;
|
||||
memmove (static_cast<void *> (&arrayZ[i]),
|
||||
static_cast<void *> (&arrayZ[i + 1]),
|
||||
(len - i - 1) * sizeof (Type));
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void shrink (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (size < len)
|
||||
len = size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *find (T v) {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *find (T v) const {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void qsort (int (*cmp)(const void*, const void*))
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), cmp);
|
||||
}
|
||||
|
||||
inline void qsort (void)
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
inline void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *lsearch (const T &x)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (0 == this->arrayZ[i].cmp (&x))
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *bsearch (const T &x)
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *bsearch (const T &x) const
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool bfind (const T &x, unsigned int *i) const
|
||||
{
|
||||
int min = 0, max = (int) this->len - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int c = this->arrayZ[mid].cmp (&x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
if (arrayZ != static_array)
|
||||
free (arrayZ);
|
||||
arrayZ = nullptr;
|
||||
allocated = len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define HB_LOCKABLE_SET_INIT {HB_VECTOR_INIT}
|
||||
template <typename item_t, typename lock_t>
|
||||
struct hb_lockable_set_t
|
||||
{
|
||||
hb_vector_t <item_t, 1> items;
|
||||
|
||||
inline void init (void) { items.init (); }
|
||||
|
||||
template <typename T>
|
||||
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
if (replace) {
|
||||
item_t old = *item;
|
||||
*item = v;
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
}
|
||||
else {
|
||||
item = nullptr;
|
||||
l.unlock ();
|
||||
}
|
||||
} else {
|
||||
item = items.push (v);
|
||||
l.unlock ();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void remove (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
item_t old = *item;
|
||||
*item = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
} else {
|
||||
l.unlock ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool find (T v, item_t *i, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item)
|
||||
*i = *item;
|
||||
l.unlock ();
|
||||
return !!item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline item_t *find_or_insert (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (!item) {
|
||||
item = items.push (v);
|
||||
}
|
||||
l.unlock ();
|
||||
return item;
|
||||
}
|
||||
|
||||
inline void fini (lock_t &l)
|
||||
{
|
||||
if (!items.len) {
|
||||
/* No need for locking. */
|
||||
items.fini ();
|
||||
return;
|
||||
}
|
||||
l.lock ();
|
||||
while (items.len) {
|
||||
item_t old = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
l.lock ();
|
||||
}
|
||||
items.fini ();
|
||||
l.unlock ();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename Type>
|
||||
struct hb_auto_t : Type
|
||||
{
|
||||
hb_auto_t (void) { Type::init (); }
|
||||
~hb_auto_t (void) { Type::fini (); }
|
||||
private: /* Hide */
|
||||
void init (void) {}
|
||||
void fini (void) {}
|
||||
};
|
||||
|
||||
struct hb_bytes_t
|
||||
{
|
||||
inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
|
||||
inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
|
||||
|
||||
inline int cmp (const hb_bytes_t &a) const
|
||||
{
|
||||
if (len != a.len)
|
||||
return (int) a.len - (int) len;
|
||||
|
||||
return memcmp (a.bytes, bytes, len);
|
||||
}
|
||||
static inline int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
hb_bytes_t *a = (hb_bytes_t *) pa;
|
||||
hb_bytes_t *b = (hb_bytes_t *) pb;
|
||||
return b->cmp (*a);
|
||||
}
|
||||
|
||||
const char *bytes;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
|
||||
struct HbOpOr
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
|
||||
};
|
||||
struct HbOpAnd
|
||||
{
|
||||
static const bool passthru_left = false;
|
||||
static const bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
|
||||
};
|
||||
struct HbOpMinus
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
|
||||
};
|
||||
struct HbOpXor
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
|
||||
};
|
||||
|
||||
|
||||
/* Compiler-assisted vectorization. */
|
||||
|
||||
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
|
||||
* using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
|
||||
* Define that to 0 to disable. */
|
||||
template <typename elt_t, unsigned int byte_size>
|
||||
struct hb_vector_size_t
|
||||
{
|
||||
elt_t& operator [] (unsigned int i) { return u.v[i]; }
|
||||
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
|
||||
|
||||
template <class Op>
|
||||
inline hb_vector_size_t process (const hb_vector_size_t &o) const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
|
||||
return r;
|
||||
}
|
||||
inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpOr> (o); }
|
||||
inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpAnd> (o); }
|
||||
inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpXor> (o); }
|
||||
inline hb_vector_size_t operator ~ () const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE && 0
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
r.u.vec[i] = ~u.vec[i];
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
r.u.v[i] = ~u.v[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
|
||||
union {
|
||||
elt_t v[byte_size / sizeof (elt_t)];
|
||||
#if HB_VECTOR_SIZE
|
||||
typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
|
||||
vec_t vec[byte_size / sizeof (vec_t)];
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_DSALGS_HH */
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
#include "hb-shape-plan-private.hh"
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-face-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
|
||||
#include "hb-ft.h"
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_MAP_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
|
||||
template <typename T>
|
||||
|
@ -89,7 +88,7 @@ struct hb_map_t
|
|||
{
|
||||
if (unlikely (!successful)) return false;
|
||||
|
||||
unsigned int power = _hb_bit_storage (population * 2 + 8);
|
||||
unsigned int power = hb_bit_storage (population * 2 + 8);
|
||||
unsigned int new_size = 1u << power;
|
||||
item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
|
||||
if (unlikely (!new_items))
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#define HB_OBJECT_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
|
||||
|
|
|
@ -286,6 +286,197 @@ struct TTCHeader
|
|||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Mac Resource Fork
|
||||
*/
|
||||
|
||||
struct ResourceRefItem
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
// actual data sanitization is done on ResourceForkHeader sanitizer
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
HBINT16 id; /* Resource ID, is really should be signed? */
|
||||
HBINT16 nameOffset; /* Offset from beginning of resource name list
|
||||
* to resource name, minus means there is no */
|
||||
HBUINT8 attr; /* Resource attributes */
|
||||
HBUINT24 dataOffset; /* Offset from beginning of resource data to
|
||||
* data for this resource */
|
||||
HBUINT32 reserved; /* Reserved for handle to resource */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
struct ResourceTypeItem
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
// RefList sanitization is done on ResourceMap sanitizer
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
inline unsigned int get_resource_count () const
|
||||
{
|
||||
return numRes + 1;
|
||||
}
|
||||
|
||||
inline bool is_sfnt () const
|
||||
{
|
||||
return type == HB_TAG ('s','f','n','t');
|
||||
}
|
||||
|
||||
inline const ResourceRefItem& get_ref_item (const void *base,
|
||||
unsigned int i) const
|
||||
{
|
||||
return (base+refList)[i];
|
||||
}
|
||||
|
||||
protected:
|
||||
Tag type; /* Resource type */
|
||||
HBUINT16 numRes; /* Number of resource this type in map minus 1 */
|
||||
OffsetTo<UnsizedArrayOf<ResourceRefItem> >
|
||||
refList; /* Offset from beginning of resource type list
|
||||
* to reference list for this type */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct ResourceMap
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
for (unsigned int i = 0; i < get_types_count (); ++i)
|
||||
{
|
||||
const ResourceTypeItem& type = get_type (i);
|
||||
if (unlikely (!type.sanitize (c)))
|
||||
return_trace (false);
|
||||
for (unsigned int j = 0; j < type.get_resource_count (); ++j)
|
||||
if (unlikely (!get_ref_item (type, j).sanitize (c)))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline const ResourceTypeItem& get_type (unsigned int i) const
|
||||
{
|
||||
// Why offset from the second byte of the object? I'm not sure
|
||||
return ((&reserved[2])+typeList)[i];
|
||||
}
|
||||
|
||||
inline unsigned int get_types_count () const
|
||||
{
|
||||
return nTypes + 1;
|
||||
}
|
||||
|
||||
inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type,
|
||||
unsigned int i) const
|
||||
{
|
||||
return type.get_ref_item (&(this+typeList), i);
|
||||
}
|
||||
|
||||
inline const PString& get_name (const ResourceRefItem &item,
|
||||
unsigned int i) const
|
||||
{
|
||||
if (item.nameOffset == -1)
|
||||
return Null (PString);
|
||||
|
||||
return StructAtOffset<PString> (this, nameList + item.nameOffset);
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT8 reserved[16]; /* Reserved for copy of resource header */
|
||||
LOffsetTo<ResourceMap>
|
||||
reserved1; /* Reserved for handle to next resource map */
|
||||
HBUINT16 reserved2; /* Reserved for file reference number */
|
||||
HBUINT16 attr; /* Resource fork attribute */
|
||||
OffsetTo<UnsizedArrayOf<ResourceTypeItem> >
|
||||
typeList; /* Offset from beginning of map to
|
||||
* resource type list */
|
||||
HBUINT16 nameList; /* Offset from beginning of map to
|
||||
* resource name list */
|
||||
HBUINT16 nTypes; /* Number of types in the map minus 1 */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (30);
|
||||
};
|
||||
|
||||
struct ResourceForkHeader
|
||||
{
|
||||
inline unsigned int get_face_count () const
|
||||
{
|
||||
const ResourceMap &resource_map = this+map;
|
||||
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
|
||||
{
|
||||
const ResourceTypeItem& type = resource_map.get_type (i);
|
||||
if (type.is_sfnt ())
|
||||
return type.get_resource_count ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline const LArrayOf<HBUINT8>& get_data (const ResourceTypeItem& type,
|
||||
unsigned int idx) const
|
||||
{
|
||||
const ResourceMap &resource_map = this+map;
|
||||
unsigned int offset = dataOffset;
|
||||
offset += resource_map.get_ref_item (type, idx).dataOffset;
|
||||
return StructAtOffset<LArrayOf<HBUINT8> > (this, offset);
|
||||
}
|
||||
|
||||
inline const OpenTypeFontFace& get_face (unsigned int idx) const
|
||||
{
|
||||
const ResourceMap &resource_map = this+map;
|
||||
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
|
||||
{
|
||||
const ResourceTypeItem& type = resource_map.get_type (i);
|
||||
if (type.is_sfnt () && idx < type.get_resource_count ())
|
||||
return (OpenTypeFontFace&) get_data (type, idx).arrayZ;
|
||||
}
|
||||
return Null (OpenTypeFontFace);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
const ResourceMap &resource_map = this+map;
|
||||
if (unlikely (!resource_map.sanitize (c)))
|
||||
return_trace (false);
|
||||
|
||||
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
|
||||
{
|
||||
const ResourceTypeItem& type = resource_map.get_type (i);
|
||||
for (unsigned int j = 0; j < type.get_resource_count (); ++j)
|
||||
{
|
||||
const LArrayOf<HBUINT8>& data = get_data (type, j);
|
||||
if (unlikely (!(data.sanitize (c) &&
|
||||
((OpenTypeFontFace&) data.arrayZ).sanitize (c))))
|
||||
return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 dataOffset; /* Offset from beginning of resource fork
|
||||
* to resource data */
|
||||
LOffsetTo<ResourceMap>
|
||||
map; /* Offset from beginning of resource fork
|
||||
* to resource map */
|
||||
HBUINT32 dataLen; /* Length of resource data */
|
||||
HBUINT32 mapLen; /* Length of resource map */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (16);
|
||||
};
|
||||
|
||||
/*
|
||||
* OpenType Font File
|
||||
|
@ -299,6 +490,7 @@ struct OpenTypeFontFile
|
|||
CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
|
||||
TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
|
||||
TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */
|
||||
DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */
|
||||
TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */
|
||||
Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */
|
||||
};
|
||||
|
@ -313,6 +505,7 @@ struct OpenTypeFontFile
|
|||
case Typ1Tag:
|
||||
case TrueTypeTag: return 1;
|
||||
case TTCTag: return u.ttcHeader.get_face_count ();
|
||||
// case DFontTag: return u.rfHeader.get_face_count ();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -327,6 +520,7 @@ struct OpenTypeFontFile
|
|||
case Typ1Tag:
|
||||
case TrueTypeTag: return u.fontFace;
|
||||
case TTCTag: return u.ttcHeader.get_face (i);
|
||||
// case DFontTag: return u.rfHeader.get_face (i);
|
||||
default: return Null(OpenTypeFontFace);
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +547,7 @@ struct OpenTypeFontFile
|
|||
case Typ1Tag:
|
||||
case TrueTypeTag: return_trace (u.fontFace.sanitize (c));
|
||||
case TTCTag: return_trace (u.ttcHeader.sanitize (c));
|
||||
// case DFontTag: return_trace (u.rfHeader.sanitize (c));
|
||||
default: return_trace (true);
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +557,7 @@ struct OpenTypeFontFile
|
|||
Tag tag; /* 4-byte identifier. */
|
||||
OpenTypeFontFace fontFace;
|
||||
TTCHeader ttcHeader;
|
||||
ResourceForkHeader rfHeader;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_UNION (4, tag);
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#define HB_OPEN_TYPE_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-blob-private.hh"
|
||||
#include "hb-face-private.hh"
|
||||
|
||||
|
@ -230,7 +229,7 @@ struct hb_sanitize_context_t :
|
|||
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
|
||||
bool overflows = hb_unsigned_mul_overflows (len, record_size);
|
||||
unsigned int array_size = record_size * len;
|
||||
bool ok = !overflows && this->check_range (base, array_size);
|
||||
|
||||
|
@ -1033,6 +1032,7 @@ struct ArrayOf
|
|||
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
|
||||
};
|
||||
template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
|
||||
typedef ArrayOf<HBUINT8, HBUINT8> PString;
|
||||
|
||||
/* Array of Offset's */
|
||||
template <typename Type, typename OffsetType=HBUINT16>
|
||||
|
@ -1177,7 +1177,7 @@ struct BinSearchHeader
|
|||
{
|
||||
len.set (v);
|
||||
assert (len == v);
|
||||
entrySelector.set (MAX (1u, _hb_bit_storage (v)) - 1);
|
||||
entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
|
||||
searchRange.set (16 * (1u << entrySelector));
|
||||
rangeShift.set (v * 16 > searchRange
|
||||
? 16 * v - searchRange
|
||||
|
|
|
@ -89,7 +89,7 @@ struct CmapSubtableFormat4
|
|||
this->length.set (get_sub_table_size (segments));
|
||||
|
||||
this->segCountX2.set (segments.len * 2);
|
||||
this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
|
||||
this->entrySelector.set (MAX (1u, hb_bit_storage (segments.len)) - 1);
|
||||
this->searchRange.set (2 * (1u << this->entrySelector));
|
||||
this->rangeShift.set (segments.len * 2 > this->searchRange
|
||||
? 2 * segments.len - this->searchRange
|
||||
|
|
|
@ -199,7 +199,7 @@ struct hdmx
|
|||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && version == 0 &&
|
||||
!_hb_unsigned_int_mul_overflows (num_records, size_device_record) &&
|
||||
!hb_unsigned_mul_overflows (num_records, size_device_record) &&
|
||||
size_device_record >= DeviceRecord::min_size &&
|
||||
c->check_range (this, get_size()));
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-ot-layout-private.hh"
|
||||
#include "hb-open-type-private.hh"
|
||||
#include "hb-set-private.hh"
|
||||
|
@ -832,7 +831,12 @@ struct CoverageFormat2
|
|||
c = &c_;
|
||||
coverage = 0;
|
||||
i = 0;
|
||||
j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
|
||||
j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
|
||||
if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
|
||||
{
|
||||
/* Broken table. Skip. */
|
||||
i = c->rangeRecord.len;
|
||||
}
|
||||
}
|
||||
inline bool more (void) { return i < c->rangeRecord.len; }
|
||||
inline void next (void)
|
||||
|
@ -842,7 +846,14 @@ struct CoverageFormat2
|
|||
i++;
|
||||
if (more ())
|
||||
{
|
||||
hb_codepoint_t old = j;
|
||||
j = c->rangeRecord[i].start;
|
||||
if (unlikely (j <= old))
|
||||
{
|
||||
/* Broken table. Skip. Important to avoid DoS. */
|
||||
i = c->rangeRecord.len;
|
||||
return;
|
||||
}
|
||||
coverage = c->rangeRecord[i].value;
|
||||
}
|
||||
return;
|
||||
|
@ -855,7 +866,8 @@ struct CoverageFormat2
|
|||
|
||||
private:
|
||||
const struct CoverageFormat2 *c;
|
||||
unsigned int i, j, coverage;
|
||||
unsigned int i, coverage;
|
||||
hb_codepoint_t j;
|
||||
};
|
||||
private:
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ struct ValueFormat : HBUINT16
|
|||
#endif
|
||||
|
||||
inline unsigned int get_len (void) const
|
||||
{ return _hb_popcount ((unsigned int) *this); }
|
||||
{ return hb_popcount ((unsigned int) *this); }
|
||||
inline unsigned int get_size (void) const
|
||||
{ return get_len () * Value::static_size; }
|
||||
|
||||
|
@ -374,7 +374,7 @@ struct AnchorMatrix
|
|||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!c->check_struct (this)) return_trace (false);
|
||||
if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
|
||||
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
|
||||
unsigned int count = rows * cols;
|
||||
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
|
@ -1074,10 +1074,13 @@ struct MarkBasePosFormat1
|
|||
if (!skippy_iter.prev ()) return_trace (false);
|
||||
/* We only want to attach to the first of a MultipleSubst sequence.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/740
|
||||
* Reject others. */
|
||||
* Reject others...
|
||||
* ...but stop if we find a mark in the MultipleSubst sequence:
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1020 */
|
||||
if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
|
||||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
|
||||
(skippy_iter.idx == 0 ||
|
||||
_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
|
||||
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
|
||||
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
|
||||
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
|
||||
|
|
|
@ -511,7 +511,7 @@ struct AlternateSubstFormat1
|
|||
hb_mask_t lookup_mask = c->lookup_mask;
|
||||
|
||||
/* Note: This breaks badly if two features enabled this lookup together. */
|
||||
unsigned int shift = _hb_ctz (lookup_mask);
|
||||
unsigned int shift = hb_ctz (lookup_mask);
|
||||
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
||||
|
||||
if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-buffer-private.hh"
|
||||
#include "hb-map-private.hh"
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
|
@ -388,7 +387,7 @@ struct hb_ot_apply_context_t :
|
|||
inline bool prev (void)
|
||||
{
|
||||
assert (num_items > 0);
|
||||
while (idx >= num_items)
|
||||
while (idx > num_items - 1)
|
||||
{
|
||||
idx--;
|
||||
const hb_glyph_info_t &info = c->buffer->out_info[idx];
|
||||
|
|
|
@ -145,7 +145,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
|||
{
|
||||
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
|
||||
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
|
||||
unsigned int global_bit_shift = _hb_popcount (HB_GLYPH_FLAG_DEFINED);
|
||||
unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
|
||||
|
||||
m.global_mask = global_bit_mask;
|
||||
|
||||
|
@ -209,7 +209,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
|||
bits_needed = 0;
|
||||
else
|
||||
/* Limit to 8 bits per feature. */
|
||||
bits_needed = MIN(8u, _hb_bit_storage (info->max_value));
|
||||
bits_needed = MIN(8u, hb_bit_storage (info->max_value));
|
||||
|
||||
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
|
||||
continue; /* Feature disabled, or not enough bits. */
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_OT_OS2_UNICODE_RANGES_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_OT_POST_TABLE_HH
|
||||
|
||||
#include "hb-open-type-private.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
#define HB_STRING_ARRAY_NAME format1_names
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-ot-shape-complex-arabic-private.hh"
|
||||
#include "hb-ot-shape-private.hh"
|
||||
|
||||
|
|
|
@ -668,8 +668,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
*
|
||||
* Reports suggest that in some scripts Uniscribe does this only if there
|
||||
* is *not* a Halant after last consonant already (eg. Kannada), while it
|
||||
* does it unconditionally in other scripts (eg. Malayalam). We don't
|
||||
* currently know about other scripts, so we single out Malayalam for now.
|
||||
* does it unconditionally in other scripts (eg. Malayalam, Bengali). We
|
||||
* don't currently know about other scripts, so we whitelist Malayalam and
|
||||
* Bengali for now.
|
||||
*
|
||||
* Kannada test case:
|
||||
* U+0C9A,U+0CCD,U+0C9A,U+0CCD
|
||||
|
@ -679,10 +680,16 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* Malayalam test case:
|
||||
* U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
|
||||
* With lohit-ttf-20121122/Lohit-Malayalam.ttf
|
||||
*
|
||||
* Bengali test case
|
||||
* U+0998,U+09CD,U+09AF,U+09CD
|
||||
* With Windows XP vrinda.ttf
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1073
|
||||
*/
|
||||
if (indic_plan->is_old_spec)
|
||||
{
|
||||
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
|
||||
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM &&
|
||||
buffer->props.script != HB_SCRIPT_BENGALI;
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if (info[i].indic_category() == OT_H)
|
||||
{
|
||||
|
@ -1120,6 +1127,24 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* defined as “after last standalone halant glyph, after initial matra
|
||||
* position and before the main consonant”. If ZWJ or ZWNJ follow this
|
||||
* halant, position is moved after it.
|
||||
*
|
||||
* IMPLEMENTATION NOTES:
|
||||
*
|
||||
* It looks like the last sentence is wrong. Testing, with Windows 7 Uniscribe
|
||||
* and Devanagari shows that the behavior is best described as:
|
||||
*
|
||||
* "If ZWJ follows this halant, matra is NOT repositioned after this halant.
|
||||
* If ZWNJ follows this halant, position is moved after it."
|
||||
*
|
||||
* Test case, with Adobe Devanagari or Nirmala UI:
|
||||
*
|
||||
* U+091F,U+094D,U+200C,U+092F,U+093F
|
||||
* (Matra moves to the middle, after ZWNJ.)
|
||||
*
|
||||
* U+091F,U+094D,U+200D,U+092F,U+093F
|
||||
* (Matra does NOT move, stays to the left.)
|
||||
*
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1070
|
||||
*/
|
||||
|
||||
if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
|
||||
|
@ -1133,6 +1158,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
|||
*/
|
||||
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
|
||||
{
|
||||
search:
|
||||
while (new_pos > start &&
|
||||
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H)))))
|
||||
new_pos--;
|
||||
|
@ -1143,9 +1169,27 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
|||
if (is_halant (info[new_pos]) &&
|
||||
info[new_pos].indic_position() != POS_PRE_M)
|
||||
{
|
||||
#if 0 // See comment above
|
||||
/* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
|
||||
if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
|
||||
new_pos++;
|
||||
#endif
|
||||
if (new_pos + 1 < end)
|
||||
{
|
||||
/* -> If ZWJ follows this halant, matra is NOT repositioned after this halant. */
|
||||
if (info[new_pos + 1].indic_category() == OT_ZWJ)
|
||||
{
|
||||
/* Keep searching. */
|
||||
if (new_pos > start)
|
||||
{
|
||||
new_pos--;
|
||||
goto search;
|
||||
}
|
||||
}
|
||||
/* -> If ZWNJ follows this halant, position is moved after it. */
|
||||
if (info[new_pos + 1].indic_category() == OT_ZWNJ)
|
||||
new_pos++;
|
||||
}
|
||||
}
|
||||
else
|
||||
new_pos = start; /* No move. */
|
||||
|
|
|
@ -372,22 +372,25 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Note! syllable() is a one-byte field. */
|
||||
for (unsigned int i = base; i < end; i++)
|
||||
if (info[i].syllable() != 255)
|
||||
{
|
||||
unsigned int max = i;
|
||||
unsigned int j = start + info[i].syllable();
|
||||
while (j != i)
|
||||
if (unlikely (end - start >= 127))
|
||||
buffer->merge_clusters (start, end);
|
||||
else
|
||||
/* Note! syllable() is a one-byte field. */
|
||||
for (unsigned int i = base; i < end; i++)
|
||||
if (info[i].syllable() != 255)
|
||||
{
|
||||
max = MAX (max, j);
|
||||
unsigned int next = start + info[j].syllable();
|
||||
info[j].syllable() = 255; /* So we don't process j later again. */
|
||||
j = next;
|
||||
unsigned int max = i;
|
||||
unsigned int j = start + info[i].syllable();
|
||||
while (j != i)
|
||||
{
|
||||
max = MAX (max, j);
|
||||
unsigned int next = start + info[j].syllable();
|
||||
info[j].syllable() = 255; /* So we don't process j later again. */
|
||||
j = next;
|
||||
}
|
||||
if (i != max)
|
||||
buffer->merge_clusters (i, max + 1);
|
||||
}
|
||||
if (i != max)
|
||||
buffer->merge_clusters (i, max + 1);
|
||||
}
|
||||
|
||||
/* Put syllable back in. */
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
|
|
|
@ -560,7 +560,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
|
|||
|
||||
/* Grantha */
|
||||
|
||||
/* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
|
||||
/* 11300 */ VMAbv, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
|
||||
/* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
|
||||
/* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst,
|
||||
|
@ -673,7 +673,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
|
|||
/* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
|
||||
/* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H,
|
||||
/* 11C40 */ B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
|
||||
/* 11C40 */ B, O, O, O, GB, GB, O, O, O, O, O, O, O, O, O, O,
|
||||
/* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
|
||||
|
||||
|
|
|
@ -829,12 +829,12 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
|
|||
{
|
||||
c->buffer->deallocate_var_all ();
|
||||
c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
|
||||
if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
|
||||
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
|
||||
{
|
||||
c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
|
||||
(unsigned) HB_BUFFER_MAX_LEN_MIN);
|
||||
}
|
||||
if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
|
||||
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
|
||||
{
|
||||
c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
|
||||
(unsigned) HB_BUFFER_MAX_OPS_MIN);
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#define HB_PASTE1(a,b) a##b
|
||||
#define HB_PASTE(a,b) HB_PASTE1(a,b)
|
||||
|
||||
|
||||
/* Compile-time custom allocator support. */
|
||||
|
||||
#if defined(hb_malloc_impl) \
|
||||
|
@ -72,18 +73,41 @@ extern "C" void hb_free_impl(void *ptr);
|
|||
#define calloc hb_calloc_impl
|
||||
#define realloc hb_realloc_impl
|
||||
#define free hb_free_impl
|
||||
|
||||
#if defined(hb_memalign_impl)
|
||||
extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
|
||||
#define posix_memalign hb_memalign_impl
|
||||
#else
|
||||
#undef HAVE_POSIX_MEMALIGN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Compiler attributes */
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct _hb_alignof
|
||||
{
|
||||
struct s
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
static constexpr unsigned int value = offsetof (s, t);
|
||||
};
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
|
||||
#ifndef nullptr
|
||||
#define nullptr NULL
|
||||
#endif
|
||||
|
||||
#ifndef constexpr
|
||||
#define constexpr const
|
||||
#endif
|
||||
|
||||
// Static assertions
|
||||
#ifndef static_assert
|
||||
#define static_assert(e, msg) \
|
||||
|
@ -98,6 +122,10 @@ extern "C" void hb_free_impl(void *ptr);
|
|||
#define thread_local
|
||||
#endif
|
||||
|
||||
#ifndef alignof
|
||||
#define alignof(x) (_hb_alignof<x>::value)
|
||||
#endif // alignof
|
||||
|
||||
#endif // __cplusplus < 201103L
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
|
||||
|
@ -251,26 +279,6 @@ static int errno = 0; /* Use something better? */
|
|||
# undef HB_USE_ATEXIT
|
||||
#endif
|
||||
|
||||
/* Basics */
|
||||
|
||||
#undef MIN
|
||||
template <typename Type>
|
||||
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
|
||||
|
||||
#undef MAX
|
||||
template <typename Type>
|
||||
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
|
||||
|
||||
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
|
||||
{ return (a + (b - 1)) / b; }
|
||||
|
||||
|
||||
#undef ARRAY_LENGTH
|
||||
template <typename Type, unsigned int n>
|
||||
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
|
||||
/* A const version, but does not detect erratically being called on pointers. */
|
||||
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
#define HB_STMT_START do
|
||||
#define HB_STMT_END while (0)
|
||||
|
||||
|
@ -322,223 +330,6 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
|
|||
# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
|
||||
|
||||
|
||||
|
||||
/* Tiny functions */
|
||||
|
||||
/*
|
||||
* Void!
|
||||
*/
|
||||
typedef const struct _hb_void_t *hb_void_t;
|
||||
#define HB_VOID ((const _hb_void_t *) nullptr)
|
||||
|
||||
/* Return the number of 1 bits in v. */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_popcount (T v)
|
||||
{
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_popcount (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_popcountl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_popcountll (v);
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "HACKMEM 169" */
|
||||
uint32_t y;
|
||||
y = (v >> 1) &033333333333;
|
||||
y = v - y - ((y >>1) & 033333333333);
|
||||
return (((y + (y >> 3)) & 030707070707) % 077);
|
||||
}
|
||||
|
||||
if (sizeof (T) == 8)
|
||||
{
|
||||
unsigned int shift = 32;
|
||||
return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
|
||||
}
|
||||
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift));
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of bits needed to store number */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_bit_storage (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return sizeof (unsigned int) * 8 - __builtin_clz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# if _WIN64
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse64 (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16};
|
||||
unsigned int r = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
|
||||
unsigned int r = 0;
|
||||
for (int i = 5; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
|
||||
_hb_bit_storage<uint64_t> ((uint64_t) v);
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of zero bits in the least significant side of v */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_ctz (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_ctz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_ctzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_ctzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward (&where, v);
|
||||
return where;
|
||||
}
|
||||
# if _WIN64
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward64 (&where, v);
|
||||
return where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 32;
|
||||
v &= - (int32_t) v;
|
||||
if (v) c--;
|
||||
if (v & 0x0000FFFF) c -= 16;
|
||||
if (v & 0x00FF00FF) c -= 8;
|
||||
if (v & 0x0F0F0F0F) c -= 4;
|
||||
if (v & 0x33333333) c -= 2;
|
||||
if (v & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 64;
|
||||
v &= - (int64_t) (v);
|
||||
if (v) c--;
|
||||
if (v & 0x00000000FFFFFFFFULL) c -= 32;
|
||||
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
|
||||
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
|
||||
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
|
||||
if (v & 0x3333333333333333ULL) c -= 2;
|
||||
if (v & 0x5555555555555555ULL) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) :
|
||||
_hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift;
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
static inline bool
|
||||
_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
|
||||
{
|
||||
return (size > 0) && (count >= ((unsigned int) -1) / size);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
_hb_ceil_to_4 (unsigned int v)
|
||||
{
|
||||
return ((v - 1) | 3) + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Utility types
|
||||
*
|
||||
*/
|
||||
|
||||
#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
@ -620,321 +411,6 @@ struct CrapOrNull<const Type> {
|
|||
#define CrapOrNull(Type) CrapOrNull<Type>::get ()
|
||||
|
||||
|
||||
|
||||
/* arrays and maps */
|
||||
|
||||
|
||||
#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
|
||||
template <typename Type, unsigned int StaticSize=8>
|
||||
struct hb_vector_t
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int allocated;
|
||||
bool successful;
|
||||
Type *arrayZ;
|
||||
Type static_array[StaticSize];
|
||||
|
||||
void init (void)
|
||||
{
|
||||
len = 0;
|
||||
allocated = ARRAY_LENGTH (static_array);
|
||||
successful = true;
|
||||
arrayZ = static_array;
|
||||
}
|
||||
|
||||
inline Type& operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Crap (Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Null(Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline Type *push (void)
|
||||
{
|
||||
if (unlikely (!resize (len + 1)))
|
||||
return &Crap(Type);
|
||||
return &arrayZ[len - 1];
|
||||
}
|
||||
inline Type *push (const Type& v)
|
||||
{
|
||||
Type *p = push ();
|
||||
*p = v;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Allocate for size but don't adjust len. */
|
||||
inline bool alloc (unsigned int size)
|
||||
{
|
||||
if (unlikely (!successful))
|
||||
return false;
|
||||
|
||||
if (likely (size <= allocated))
|
||||
return true;
|
||||
|
||||
/* Reallocate */
|
||||
|
||||
unsigned int new_allocated = allocated;
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 8;
|
||||
|
||||
Type *new_array = nullptr;
|
||||
|
||||
if (arrayZ == static_array)
|
||||
{
|
||||
new_array = (Type *) calloc (new_allocated, sizeof (Type));
|
||||
if (new_array)
|
||||
memcpy (new_array, arrayZ, len * sizeof (Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
|
||||
if (likely (!overflows))
|
||||
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
|
||||
}
|
||||
|
||||
if (unlikely (!new_array))
|
||||
{
|
||||
successful = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
arrayZ = new_array;
|
||||
allocated = new_allocated;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool resize (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (!alloc (size))
|
||||
return false;
|
||||
|
||||
if (size > len)
|
||||
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
|
||||
|
||||
len = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pop (void)
|
||||
{
|
||||
if (!len) return;
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void remove (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return;
|
||||
memmove (static_cast<void *> (&arrayZ[i]),
|
||||
static_cast<void *> (&arrayZ[i + 1]),
|
||||
(len - i - 1) * sizeof (Type));
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void shrink (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (size < len)
|
||||
len = size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *find (T v) {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *find (T v) const {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void qsort (int (*cmp)(const void*, const void*))
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), cmp);
|
||||
}
|
||||
|
||||
inline void qsort (void)
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
inline void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *lsearch (const T &x)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (0 == this->arrayZ[i].cmp (&x))
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *bsearch (const T &x)
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *bsearch (const T &x) const
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool bfind (const T &x, unsigned int *i) const
|
||||
{
|
||||
int min = 0, max = (int) this->len - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int c = this->arrayZ[mid].cmp (&x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
if (arrayZ != static_array)
|
||||
free (arrayZ);
|
||||
arrayZ = nullptr;
|
||||
allocated = len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct hb_auto_t : Type
|
||||
{
|
||||
hb_auto_t (void) { Type::init (); }
|
||||
~hb_auto_t (void) { Type::fini (); }
|
||||
private: /* Hide */
|
||||
void init (void) {}
|
||||
void fini (void) {}
|
||||
};
|
||||
template <typename Type>
|
||||
struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {};
|
||||
|
||||
|
||||
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
|
||||
template <typename item_t, typename lock_t>
|
||||
struct hb_lockable_set_t
|
||||
{
|
||||
hb_vector_t <item_t, 1> items;
|
||||
|
||||
inline void init (void) { items.init (); }
|
||||
|
||||
template <typename T>
|
||||
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
if (replace) {
|
||||
item_t old = *item;
|
||||
*item = v;
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
}
|
||||
else {
|
||||
item = nullptr;
|
||||
l.unlock ();
|
||||
}
|
||||
} else {
|
||||
item = items.push (v);
|
||||
l.unlock ();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void remove (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
item_t old = *item;
|
||||
*item = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
} else {
|
||||
l.unlock ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool find (T v, item_t *i, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item)
|
||||
*i = *item;
|
||||
l.unlock ();
|
||||
return !!item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline item_t *find_or_insert (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (!item) {
|
||||
item = items.push (v);
|
||||
}
|
||||
l.unlock ();
|
||||
return item;
|
||||
}
|
||||
|
||||
inline void fini (lock_t &l)
|
||||
{
|
||||
if (!items.len) {
|
||||
/* No need for locking. */
|
||||
items.fini ();
|
||||
return;
|
||||
}
|
||||
l.lock ();
|
||||
while (items.len) {
|
||||
item_t old = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
l.lock ();
|
||||
}
|
||||
items.fini ();
|
||||
l.unlock ();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* ASCII tag/character handling */
|
||||
|
||||
static inline bool ISALPHA (unsigned char c)
|
||||
|
@ -1027,145 +503,29 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
|||
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
|
||||
|
||||
|
||||
template <typename T, typename T2> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
|
||||
{
|
||||
for (unsigned int i = 1; i < len; i++)
|
||||
{
|
||||
unsigned int j = i;
|
||||
while (j && compar (&array[j - 1], &array[i]) > 0)
|
||||
j--;
|
||||
if (i == j)
|
||||
continue;
|
||||
/* Move item i to occupy place for item j, shift what's in between. */
|
||||
{
|
||||
T t = array[i];
|
||||
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
|
||||
array[j] = t;
|
||||
}
|
||||
if (array2)
|
||||
{
|
||||
T2 t = array2[i];
|
||||
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
|
||||
array2[j] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
|
||||
{
|
||||
hb_stable_sort (array, len, compar, (int *) nullptr);
|
||||
}
|
||||
|
||||
static inline hb_bool_t
|
||||
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
|
||||
{
|
||||
/* Pain because we don't know whether s is nul-terminated. */
|
||||
char buf[64];
|
||||
len = MIN (ARRAY_LENGTH (buf) - 1, len);
|
||||
strncpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
unsigned long v = strtoul (buf, &end, base);
|
||||
if (errno) return false;
|
||||
if (*end) return false;
|
||||
*out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Vectorization */
|
||||
|
||||
struct HbOpOr
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
|
||||
};
|
||||
struct HbOpAnd
|
||||
{
|
||||
static const bool passthru_left = false;
|
||||
static const bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
|
||||
};
|
||||
struct HbOpMinus
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
|
||||
};
|
||||
struct HbOpXor
|
||||
{
|
||||
static const bool passthru_left = true;
|
||||
static const bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
|
||||
};
|
||||
|
||||
|
||||
/* Compiler-assisted vectorization. */
|
||||
|
||||
/*
|
||||
* Disable vectorization for now. To correctly use them, we should
|
||||
* use posix_memalign() to allocate them. Otherwise, can cause
|
||||
* misaligned access.
|
||||
*
|
||||
* https://bugs.chromium.org/p/chromium/issues/detail?id=860184
|
||||
*/
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# define HB_VECTOR_SIZE 0
|
||||
#endif
|
||||
|
||||
/* The `vector_size' attribute was introduced in gcc 3.1. */
|
||||
#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
|
||||
#define HB_VECTOR_SIZE 128
|
||||
#elif !defined(HB_VECTOR_SIZE)
|
||||
#define HB_VECTOR_SIZE 0
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
|
||||
# define HB_VECTOR_SIZE 128
|
||||
# else
|
||||
# define HB_VECTOR_SIZE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
|
||||
template <typename elt_t, unsigned int byte_size>
|
||||
struct hb_vector_size_t
|
||||
{
|
||||
elt_t& operator [] (unsigned int i) { return u.v[i]; }
|
||||
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
|
||||
|
||||
template <class Op>
|
||||
inline hb_vector_size_t process (const hb_vector_size_t &o) const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
|
||||
return r;
|
||||
}
|
||||
inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpOr> (o); }
|
||||
inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpAnd> (o); }
|
||||
inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpXor> (o); }
|
||||
inline hb_vector_size_t operator ~ () const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE && 0
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
r.u.vec[i] = ~u.vec[i];
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
r.u.v[i] = ~u.v[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
|
||||
union {
|
||||
elt_t v[byte_size / sizeof (elt_t)];
|
||||
#if HB_VECTOR_SIZE
|
||||
typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
|
||||
vec_t vec[byte_size / sizeof (vec_t)];
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/* Global runtime options. */
|
||||
|
||||
|
@ -1199,43 +559,52 @@ hb_options (void)
|
|||
#define VAR 1
|
||||
|
||||
|
||||
/* String type. */
|
||||
|
||||
struct hb_bytes_t
|
||||
{
|
||||
inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
|
||||
inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
|
||||
|
||||
inline int cmp (const hb_bytes_t &a) const
|
||||
{
|
||||
if (len != a.len)
|
||||
return (int) a.len - (int) len;
|
||||
|
||||
return memcmp (a.bytes, bytes, len);
|
||||
}
|
||||
static inline int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
hb_bytes_t *a = (hb_bytes_t *) pa;
|
||||
hb_bytes_t *b = (hb_bytes_t *) pb;
|
||||
return b->cmp (*a);
|
||||
}
|
||||
|
||||
const char *bytes;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
|
||||
/* fallback for round() */
|
||||
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
|
||||
static inline double
|
||||
round (double x)
|
||||
_hb_round (double x)
|
||||
{
|
||||
if (x >= 0)
|
||||
return floor (x + 0.5);
|
||||
else
|
||||
return ceil (x - 0.5);
|
||||
}
|
||||
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
|
||||
#define round(x) _hb_round(x)
|
||||
#endif
|
||||
|
||||
|
||||
/* fallback for posix_memalign() */
|
||||
static inline int
|
||||
_hb_memalign(void **memptr, size_t alignment, size_t size)
|
||||
{
|
||||
if (unlikely (0 != (alignment & (alignment - 1)) ||
|
||||
!alignment ||
|
||||
0 != (alignment & (sizeof (void *) - 1))))
|
||||
return EINVAL;
|
||||
|
||||
char *p = (char *) malloc (size + alignment - 1);
|
||||
if (unlikely (!p))
|
||||
return ENOMEM;
|
||||
|
||||
size_t off = (size_t) p & (alignment - 1);
|
||||
if (off)
|
||||
p += alignment - off;
|
||||
|
||||
*memptr = (void *) p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN)
|
||||
#define posix_memalign _hb_memalign
|
||||
#endif
|
||||
|
||||
|
||||
/* Headers we include for everyone. Keep sorted. They express dependency amongst
|
||||
* themselves, but no other file should include them.*/
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
#endif /* HB_PRIVATE_HH */
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_SET_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -94,7 +93,7 @@ struct hb_set_t
|
|||
{
|
||||
unsigned int pop = 0;
|
||||
for (unsigned int i = 0; i < len (); i++)
|
||||
pop += _hb_popcount (v[i]);
|
||||
pop += hb_popcount (v[i]);
|
||||
return pop;
|
||||
}
|
||||
|
||||
|
@ -161,8 +160,8 @@ struct hb_set_t
|
|||
static const unsigned int PAGE_BITS = 512;
|
||||
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
|
||||
|
||||
static inline unsigned int elt_get_min (const elt_t &elt) { return _hb_ctz (elt); }
|
||||
static inline unsigned int elt_get_max (const elt_t &elt) { return _hb_bit_storage (elt) - 1; }
|
||||
static inline unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
|
||||
static inline unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
|
||||
|
||||
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
|
||||
|
||||
|
@ -405,6 +404,7 @@ struct hb_set_t
|
|||
if (get_population () > larger_set->get_population ())
|
||||
return false;
|
||||
|
||||
/* TODO Optimize to use pages. */
|
||||
hb_codepoint_t c = INVALID;
|
||||
while (next (&c))
|
||||
if (!larger_set->has (c))
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_SHAPE_PLAN_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-shape-plan-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
#include "hb-font-private.hh"
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-subset-private.hh"
|
||||
#include "hb-set-private.hh"
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "hb-subset.h"
|
||||
#include "hb-subset-private.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-map-private.hh"
|
||||
|
||||
struct hb_subset_plan_t
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-open-type-private.hh"
|
||||
|
||||
#include "hb-subset-glyf.hh"
|
||||
|
@ -154,7 +153,7 @@ _hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
|
|||
unsigned int face_length = table_count * 16 + 12;
|
||||
|
||||
for (unsigned int i = 0; i < table_count; i++)
|
||||
face_length += _hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
|
||||
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
|
||||
|
||||
char *buf = (char *) malloc (face_length);
|
||||
if (unlikely (!buf))
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#define HB_UNICODE_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
|
||||
extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#define HB_SHAPER uniscribe
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ HB_BEGIN_DECLS
|
|||
|
||||
#define HB_VERSION_MAJOR 1
|
||||
#define HB_VERSION_MINOR 8
|
||||
#define HB_VERSION_MICRO 1
|
||||
#define HB_VERSION_MICRO 3
|
||||
|
||||
#define HB_VERSION_STRING "1.8.1"
|
||||
#define HB_VERSION_STRING "1.8.3"
|
||||
|
||||
#define HB_VERSION_ATLEAST(major,minor,micro) \
|
||||
((major)*10000+(minor)*100+(micro) <= \
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#if defined(HB_ATOMIC_INT_NIL)
|
||||
#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
|
||||
|
|
|
@ -78,6 +78,9 @@ main (int argc, char **argv)
|
|||
case OpenTypeFontFile::Typ1Tag:
|
||||
printf ("Obsolete Apple Type1 font in SFNT container\n");
|
||||
break;
|
||||
case OpenTypeFontFile::DFontTag:
|
||||
printf ("DFont Mac Resource Fork\n");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown font format\n");
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Script to update the mozilla in-tree copy of the HarfBuzz library.
|
||||
# Run this within the /gfx/harfbuzz directory of the source tree.
|
||||
|
||||
MY_TEMP_DIR=`mktemp -d -t harfbuzz_update.XXXXXX` || exit 1
|
||||
|
||||
VERSION=1.8.3
|
||||
|
||||
git clone https://github.com/harfbuzz/harfbuzz ${MY_TEMP_DIR}/harfbuzz
|
||||
git -C ${MY_TEMP_DIR}/harfbuzz checkout ${VERSION}
|
||||
|
||||
COMMIT=$(git -C ${MY_TEMP_DIR}/harfbuzz rev-parse HEAD)
|
||||
perl -p -i -e "s/(\d+\.)(\d+\.)(\d+)/${VERSION}/" README-mozilla;
|
||||
perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README-mozilla;
|
||||
|
||||
FILES="AUTHORS autogen.sh configure.ac COPYING git.mk harfbuzz.doap Makefile.am NEWS README src THANKS TODO"
|
||||
|
||||
for f in $FILES; do
|
||||
rm -rf $f
|
||||
mv ${MY_TEMP_DIR}/harfbuzz/$f $f
|
||||
done
|
||||
rm -rf src/hb-ucdn
|
||||
rm -rf ${MY_TEMP_DIR}
|
||||
|
||||
hg revert -r . src/moz.build
|
||||
hg addremove
|
||||
|
||||
echo "###"
|
||||
echo "### Updated HarfBuzz to $COMMIT."
|
||||
echo "### Remember to verify and commit the changes to source control!"
|
||||
echo "###"
|
Загрузка…
Ссылка в новой задаче