Implement an internal emojis dumper tool (#909)

Later to be expanded to a more general tool but for now it only supports CBDT, SVG and CBDT.
This commit is contained in:
Ebrahim Byagowi 2018-03-27 16:57:09 +04:30 committed by GitHub
parent 430f82817d
commit 8fd55422c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 307 additions and 46 deletions

View File

@ -368,11 +368,15 @@ dist_check_SCRIPTS += \
endif endif
check_PROGRAMS += \ check_PROGRAMS += \
dump-emoji \
dump-indic-data \ dump-indic-data \
dump-khmer-data \ dump-khmer-data \
dump-myanmar-data \ dump-myanmar-data \
dump-use-data \ dump-use-data \
$(NULL) $(NULL)
dump_emoji_SOURCES = dump-emoji.cc
dump_emoji_CPPFLAGS = $(HBCFLAGS)
dump_emoji_LDADD = libharfbuzz.la $(HBLIBS)
dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
dump_indic_data_CPPFLAGS = $(HBCFLAGS) dump_indic_data_CPPFLAGS = $(HBCFLAGS)
dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS) dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)

141
src/dump-emoji.cc Normal file
View File

@ -0,0 +1,141 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "hb.h"
#include "hb-private.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
#ifdef HAVE_GLIB
#include <glib.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#ifndef HB_NO_VISIBILITY
const void * const OT::_hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
#endif
void cbdt_callback (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)
{
char outName[255];
sprintf (outName, "out/cbdt-%d-%d.png", group, gid);
FILE *f = fopen (outName, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
void sbix_callback (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)
{
char outName[255];
sprintf (outName, "out/sbix-%d-%d.png", group, gid);
FILE *f = fopen (outName, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
void svg_callback (const uint8_t* data, unsigned int length,
unsigned int start_glyph, unsigned int end_glyph)
{
char outName[255];
if (start_glyph == end_glyph)
sprintf (outName, "out/svg-%d.svg", start_glyph);
else
sprintf (outName, "out/svg-%d-%d.svg", start_glyph, end_glyph);
// append "z" if the content is gzipped
if ((data[0] == 0x1F) && (data[1] == 0x8B))
strcat (outName, "z");
FILE *f = fopen (outName, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
exit (1);
}
hb_blob_t *blob = nullptr;
{
const char *font_data;
unsigned int len;
hb_destroy_func_t destroy;
void *user_data;
hb_memory_mode_t mm;
#ifdef HAVE_GLIB
GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
font_data = g_mapped_file_get_contents (mf);
len = g_mapped_file_get_length (mf);
destroy = (hb_destroy_func_t) g_mapped_file_unref;
user_data = (void *) mf;
mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
#else
FILE *f = fopen (argv[1], "rb");
fseek (f, 0, SEEK_END);
len = ftell (f);
fseek (f, 0, SEEK_SET);
font_data = (const char *) malloc (len);
if (!font_data) len = 0;
len = fread ((char *) font_data, 1, len, f);
destroy = free;
user_data = (void *) font_data;
fclose (f);
mm = HB_MEMORY_MODE_WRITABLE;
#endif
blob = hb_blob_create (font_data, len, mm, user_data, destroy);
}
hb_face_t *face = hb_face_create (blob, 0);
hb_font_t *font = hb_font_create (face);
OT::CBDT::accelerator_t cbdt;
cbdt.init (face);
cbdt.dump (cbdt_callback);
cbdt.fini ();
OT::sbix::accelerator_t sbix;
sbix.init (face);
sbix.dump (sbix_callback);
sbix.fini ();
OT::SVG::accelerator_t svg;
svg.init (face);
svg.dump (svg_callback);
svg.fini ();
hb_font_destroy (font);
hb_face_destroy (face);
hb_blob_destroy (blob);
return 0;
}

View File

@ -223,6 +223,8 @@ struct IndexSubtableRecord
struct IndexSubtableArray struct IndexSubtableArray
{ {
friend struct CBDT;
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -257,6 +259,7 @@ struct IndexSubtableArray
struct BitmapSizeTable struct BitmapSizeTable
{ {
friend struct CBLC; friend struct CBLC;
friend struct CBDT;
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
@ -304,6 +307,21 @@ struct GlyphBitmapDataFormat17
DEFINE_SIZE_ARRAY(9, data); DEFINE_SIZE_ARRAY(9, data);
}; };
struct GlyphBitmapDataFormat18
{
BigGlyphMetrics glyphMetrics;
ArrayOf<HBUINT8, HBUINT32> data;
public:
DEFINE_SIZE_ARRAY(12, data);
};
struct GlyphBitmapDataFormat19
{
ArrayOf<HBUINT8, HBUINT32> data;
public:
DEFINE_SIZE_ARRAY(4, data);
};
/* /*
* CBLC -- Color Bitmap Location Table * CBLC -- Color Bitmap Location Table
@ -444,6 +462,59 @@ struct CBDT
return true; return true;
} }
inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)) const
{
if (!cblc)
return; // Not a color bitmap font.
for (unsigned int i = 0; i < cblc->sizeTables.len; ++i)
{
const BitmapSizeTable &sizeTable = cblc->sizeTables[i];
const IndexSubtableArray &subtable_array = cblc+sizeTable.indexSubtableArrayOffset;
for (unsigned int j = 0; j < sizeTable.numberOfIndexSubtables; ++j)
{
const IndexSubtableRecord &subtable_record = subtable_array.indexSubtablesZ[j];
for (unsigned int gid = subtable_record.firstGlyphIndex;
gid <= subtable_record.lastGlyphIndex; ++gid)
{
unsigned int image_offset = 0, image_length = 0, image_format = 0;
if (!subtable_record.get_image_data (gid,
&image_offset, &image_length, &image_format))
continue;
switch (image_format)
{
case 17: {
const GlyphBitmapDataFormat17& glyphFormat17 =
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
callback ((const uint8_t *) &glyphFormat17.data.array,
glyphFormat17.data.len, i, gid);
}
break;
case 18: {
const GlyphBitmapDataFormat18& glyphFormat18 =
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
callback ((const uint8_t *) &glyphFormat18.data.array,
glyphFormat18.data.len, i, gid);
}
break;
case 19: {
const GlyphBitmapDataFormat19& glyphFormat19 =
StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
callback ((const uint8_t *) &glyphFormat19.data.array,
glyphFormat19.data.len, i, gid);
}
break;
default:
continue;
}
}
}
}
}
private: private:
hb_blob_t *cblc_blob; hb_blob_t *cblc_blob;
hb_blob_t *cbdt_blob; hb_blob_t *cbdt_blob;

View File

@ -27,7 +27,7 @@
#include "hb-open-type-private.hh" #include "hb-open-type-private.hh"
#define HB_OT_TAG_SBIX HB_TAG('s','b','i','x') #define HB_OT_TAG_sbix HB_TAG('s','b','i','x')
namespace OT { namespace OT {
@ -55,6 +55,8 @@ struct SBIXGlyph
struct SBIXStrike struct SBIXStrike
{ {
friend struct sbix;
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -77,22 +79,12 @@ struct SBIXStrike
/* /*
* sbix -- Standard Bitmap Graphics Table * sbix -- Standard Bitmap Graphics Table
* https://docs.microsoft.com/en-us/typography/opentype/spec/sbix
*/ */
// It should be called with something like this so it can have
// access to num_glyph while sanitizing.
//
// static inline const OT::sbix*
// _get_sbix (hb_face_t *face)
// {
// OT::Sanitizer<OT::sbix> sanitizer;
// sanitizer.set_num_glyphs (face->get_num_glyphs ());
// hb_blob_t *sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SBIX));
// return OT::Sanitizer<OT::sbix>::lock_instance (sbix_blob);
// }
//
struct sbix struct sbix
{ {
static const hb_tag_t tableTag = HB_OT_TAG_SBIX; static const hb_tag_t tableTag = HB_OT_TAG_sbix;
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
@ -100,21 +92,50 @@ struct sbix
return_trace (c->check_struct (this) && strikes.sanitize (c, this)); return_trace (c->check_struct (this) && strikes.sanitize (c, this));
} }
// inline void dump (unsigned int num_glyphs, unsigned int group) const struct accelerator_t
// { {
// const SBIXStrike &strike = strikes[group](this); inline void init (hb_face_t *face)
// for (unsigned int i = 0; i < num_glyphs; ++i) {
// if (strike.imageOffsetsZ[i + 1] - strike.imageOffsetsZ[i] > 0) num_glyphs = hb_face_get_glyph_count (face);
// {
// const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[i]((const void *) &strike); OT::Sanitizer<OT::sbix> sanitizer;
// char outName[255]; sanitizer.set_num_glyphs (num_glyphs);
// sprintf (outName, "out/%d-%d.png", group, i); sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix));
// FILE *f = fopen (outName, "wb"); sbix_len = hb_blob_get_length (sbix_blob);
// fwrite (sbixGlyph.data, 1, sbix_table = OT::Sanitizer<OT::sbix>::lock_instance (sbix_blob);
// strike.imageOffsetsZ[i + 1] - strike.imageOffsetsZ[i] - 8, f);
// fclose (f); }
// }
// } inline void fini (void)
{
hb_blob_destroy (sbix_blob);
}
inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)) const
{
for (unsigned group = 0; group < sbix_table->strikes.len; ++group)
{
const SBIXStrike &strike = sbix_table->strikes[group](sbix_table);
for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph)
if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0)
{
const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike);
callback ((const uint8_t*) sbixGlyph.data,
strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8,
group, glyph);
}
}
}
private:
hb_blob_t *sbix_blob;
const sbix *sbix_table;
unsigned int sbix_len;
unsigned int num_glyphs;
};
protected: protected:
HBUINT16 version; /* Table version number — set to 1 */ HBUINT16 version; /* Table version number — set to 1 */

View File

@ -39,7 +39,7 @@ namespace OT {
struct SVGDocumentIndexEntry struct SVGDocumentIndexEntry
{ {
// friend struct SVGDocumentIndex; friend struct SVG;
inline bool sanitize (hb_sanitize_context_t *c, const void* base) const inline bool sanitize (hb_sanitize_context_t *c, const void* base) const
{ {
@ -64,27 +64,15 @@ struct SVGDocumentIndexEntry
struct SVGDocumentIndex struct SVGDocumentIndex
{ {
friend struct SVG;
inline bool sanitize (hb_sanitize_context_t *c) const inline bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
// dump ();
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
entries.sanitize (c, this)); entries.sanitize (c, this));
} }
// inline void dump () const
// {
// for (unsigned int i = 0; i < entries.len; ++i)
// {
// char outName[255];
// sprintf (outName, "out/%d.svg", i);
// const SVGDocumentIndexEntry &entry = entries[i];
// FILE *f = fopen (outName, "wb");
// fwrite (&entry.svgDoc (this), 1, entry.svgDocLength, f);
// fclose (f);
// }
// }
protected: protected:
ArrayOf<SVGDocumentIndexEntry> ArrayOf<SVGDocumentIndexEntry>
entries; /* Array of SVG Document Index Entries. */ entries; /* Array of SVG Document Index Entries. */
@ -103,6 +91,42 @@ struct SVG
svgDocIndex (this).sanitize (c)); svgDocIndex (this).sanitize (c));
} }
struct accelerator_t
{
inline void init (hb_face_t *face)
{
OT::Sanitizer<OT::SVG> sanitizer;
svg_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SVG));
svg_len = hb_blob_get_length (svg_blob);
svg = OT::Sanitizer<OT::SVG>::lock_instance (svg_blob);
}
inline void fini (void)
{
hb_blob_destroy (svg_blob);
}
inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
unsigned int start_glyph, unsigned int end_glyph)) const
{
const SVGDocumentIndex &index = svg->svgDocIndex (svg);
const ArrayOf<SVGDocumentIndexEntry> &entries = index.entries;
for (unsigned int i = 0; i < entries.len; ++i)
{
const SVGDocumentIndexEntry &entry = entries[i];
callback ((const uint8_t*) &entry.svgDoc (&index), entry.svgDocLength,
entry.startGlyphID, entry.endGlyphID);
}
}
private:
hb_blob_t *svg_blob;
const SVG *svg;
unsigned int svg_len;
};
protected: protected:
HBUINT16 version; /* Table version (starting at 0). */ HBUINT16 version; /* Table version (starting at 0). */
LOffsetTo<SVGDocumentIndex> LOffsetTo<SVGDocumentIndex>