Merge pull request #745 from googlefonts/master
Interface for hb_subset, skeleton for the hb-subset cli, and basic testing rigging.
This commit is contained in:
commit
257022b178
|
@ -171,6 +171,12 @@ add_prefix_to_list(HB_OT_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||||
extract_make_variable(HB_OT_headers ${SRCSOURCES})
|
extract_make_variable(HB_OT_headers ${SRCSOURCES})
|
||||||
add_prefix_to_list(HB_OT_headers "${PROJECT_SOURCE_DIR}/src/")
|
add_prefix_to_list(HB_OT_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||||
|
|
||||||
|
extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
|
||||||
|
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||||
|
|
||||||
|
extract_make_variable(HB_SUBSET_headers ${SRCSOURCES})
|
||||||
|
add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||||
|
|
||||||
extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES})
|
extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES})
|
||||||
extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES})
|
extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES})
|
||||||
if (IN_HB_DIST)
|
if (IN_HB_DIST)
|
||||||
|
@ -185,6 +191,8 @@ extract_make_variable(HB_VIEW_sources ${UTILSOURCES})
|
||||||
add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/")
|
add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||||
extract_make_variable(HB_SHAPE_sources ${UTILSOURCES})
|
extract_make_variable(HB_SHAPE_sources ${UTILSOURCES})
|
||||||
add_prefix_to_list(HB_SHAPE_sources "${PROJECT_SOURCE_DIR}/util/")
|
add_prefix_to_list(HB_SHAPE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||||
|
extract_make_variable(HB_SUBSET_CLI_sources ${UTILSOURCES})
|
||||||
|
add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||||
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
|
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
|
||||||
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
|
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||||
|
|
||||||
|
@ -246,6 +254,8 @@ set (project_sources
|
||||||
${HB_FALLBACK_sources}
|
${HB_FALLBACK_sources}
|
||||||
${HB_OT_sources}
|
${HB_OT_sources}
|
||||||
${HB_OT_RAGEL_GENERATED_sources}
|
${HB_OT_RAGEL_GENERATED_sources}
|
||||||
|
|
||||||
|
${HB_SUBSET_sources}
|
||||||
)
|
)
|
||||||
|
|
||||||
set (project_extra_sources)
|
set (project_extra_sources)
|
||||||
|
@ -255,6 +265,7 @@ set (project_headers
|
||||||
|
|
||||||
${HB_BASE_headers}
|
${HB_BASE_headers}
|
||||||
${HB_OT_headers}
|
${HB_OT_headers}
|
||||||
|
${HB_SUBSET_headers}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -708,6 +719,9 @@ if (HB_BUILD_UTILS)
|
||||||
add_executable(hb-shape ${HB_SHAPE_sources})
|
add_executable(hb-shape ${HB_SHAPE_sources})
|
||||||
target_link_libraries(hb-shape harfbuzz)
|
target_link_libraries(hb-shape harfbuzz)
|
||||||
|
|
||||||
|
add_executable(hb-subset ${HB_SUBSET_CLI_sources})
|
||||||
|
target_link_libraries(hb-subset harfbuzz)
|
||||||
|
|
||||||
add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
|
add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
|
||||||
target_link_libraries(hb-ot-shape-closure harfbuzz)
|
target_link_libraries(hb-ot-shape-closure harfbuzz)
|
||||||
|
|
||||||
|
|
|
@ -500,6 +500,8 @@ test/shaping/Makefile
|
||||||
test/shaping/data/Makefile
|
test/shaping/data/Makefile
|
||||||
test/shaping/data/in-house/Makefile
|
test/shaping/data/in-house/Makefile
|
||||||
test/shaping/data/text-rendering-tests/Makefile
|
test/shaping/data/text-rendering-tests/Makefile
|
||||||
|
test/subset/Makefile
|
||||||
|
test/subset/data/Makefile
|
||||||
docs/Makefile
|
docs/Makefile
|
||||||
docs/version.xml
|
docs/version.xml
|
||||||
])
|
])
|
||||||
|
|
|
@ -27,7 +27,9 @@ HBNONPCLIBS =
|
||||||
HBDEPS =
|
HBDEPS =
|
||||||
HBSOURCES = $(HB_BASE_sources)
|
HBSOURCES = $(HB_BASE_sources)
|
||||||
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
|
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
|
||||||
|
HBSOURCES += $(HB_SUBSET_sources)
|
||||||
HBHEADERS = $(HB_BASE_headers)
|
HBHEADERS = $(HB_BASE_headers)
|
||||||
|
HBHEADERS += $(HB_SUBSET_headers)
|
||||||
HBNODISTHEADERS = $(HB_NODIST_headers)
|
HBNODISTHEADERS = $(HB_NODIST_headers)
|
||||||
|
|
||||||
if HAVE_OT
|
if HAVE_OT
|
||||||
|
|
|
@ -181,6 +181,15 @@ HB_UCDN_sources = hb-ucdn.cc
|
||||||
HB_ICU_sources = hb-icu.cc
|
HB_ICU_sources = hb-icu.cc
|
||||||
HB_ICU_headers = hb-icu.h
|
HB_ICU_headers = hb-icu.h
|
||||||
|
|
||||||
|
# Sources for libharfbuzz-subset
|
||||||
|
HB_SUBSET_sources = \
|
||||||
|
hb-subset.cc \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
HB_SUBSET_headers = \
|
||||||
|
hb-subset.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
HB_GOBJECT_sources = hb-gobject-structs.cc
|
HB_GOBJECT_sources = hb-gobject-structs.cc
|
||||||
HB_GOBJECT_STRUCTS_headers = hb-gobject-structs.h
|
HB_GOBJECT_STRUCTS_headers = hb-gobject-structs.h
|
||||||
HB_GOBJECT_headers = hb-gobject.h $(HB_GOBJECT_STRUCTS_headers)
|
HB_GOBJECT_headers = hb-gobject.h $(HB_GOBJECT_STRUCTS_headers)
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2009 Red Hat, Inc.
|
||||||
|
* Copyright © 2012 Google, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Google Author(s): Garret Rieger, Rod Sheeter
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb-private.hh"
|
||||||
|
|
||||||
|
#include "hb-object-private.hh"
|
||||||
|
|
||||||
|
|
||||||
|
struct hb_subset_profile_t {
|
||||||
|
hb_object_header_t header;
|
||||||
|
ASSERT_POD ();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hb_subset_input_t {
|
||||||
|
hb_object_header_t header;
|
||||||
|
ASSERT_POD ();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hb_subset_face_t {
|
||||||
|
hb_object_header_t header;
|
||||||
|
ASSERT_POD ();
|
||||||
|
|
||||||
|
hb_face_t *face;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_profile_create:
|
||||||
|
*
|
||||||
|
* Return value: New profile with default settings.
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
hb_subset_profile_t *
|
||||||
|
hb_subset_profile_create ()
|
||||||
|
{
|
||||||
|
return hb_object_create<hb_subset_profile_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_profile_destroy:
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_subset_profile_destroy (hb_subset_profile_t *profile)
|
||||||
|
{
|
||||||
|
if (!hb_object_destroy (profile)) return;
|
||||||
|
|
||||||
|
free (profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_input_create:
|
||||||
|
*
|
||||||
|
* Return value: New subset input.
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
hb_subset_input_t *
|
||||||
|
hb_subset_input_create()
|
||||||
|
{
|
||||||
|
return hb_object_create<hb_subset_input_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_input_destroy:
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_subset_input_destroy(hb_subset_input_t *subset_input)
|
||||||
|
{
|
||||||
|
if (!hb_object_destroy (subset_input)) return;
|
||||||
|
|
||||||
|
free (subset_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_face_create:
|
||||||
|
*
|
||||||
|
* Return value: New subset face.
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
hb_subset_face_t *
|
||||||
|
hb_subset_face_create(hb_face_t *face)
|
||||||
|
{
|
||||||
|
if (unlikely (!face))
|
||||||
|
face = hb_face_get_empty();
|
||||||
|
|
||||||
|
hb_subset_face_t *subset_face = hb_object_create<hb_subset_face_t> ();
|
||||||
|
subset_face->face = hb_face_reference (face);
|
||||||
|
|
||||||
|
return subset_face;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_face_destroy:
|
||||||
|
*
|
||||||
|
* Since: 1.7.5
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_subset_face_destroy(hb_subset_face_t *subset_face)
|
||||||
|
{
|
||||||
|
if (!hb_object_destroy (subset_face)) return;
|
||||||
|
|
||||||
|
hb_face_destroy(subset_face->face);
|
||||||
|
free (subset_face);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset:
|
||||||
|
* @profile: profile to use for the subsetting.
|
||||||
|
* @input: input to use for the subsetting.
|
||||||
|
* @face: font face data to be subset.
|
||||||
|
* @result: subsetting result.
|
||||||
|
*
|
||||||
|
* Subsets a font according to provided profile and input.
|
||||||
|
**/
|
||||||
|
hb_bool_t
|
||||||
|
hb_subset(hb_subset_profile_t *profile,
|
||||||
|
hb_subset_input_t *input,
|
||||||
|
hb_subset_face_t *face,
|
||||||
|
hb_blob_t **result /* OUT */)
|
||||||
|
{
|
||||||
|
if (!profile || !input || !face) return false;
|
||||||
|
|
||||||
|
*result = hb_face_reference_blob(face->face);
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2018 Google
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Google Author(s): Rod Sheeter
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_H_IN
|
||||||
|
#error "Include <hb.h> instead."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HB_SUBSET_H
|
||||||
|
#define HB_SUBSET_H
|
||||||
|
|
||||||
|
#include "hb-common.h"
|
||||||
|
#include "hb-face.h"
|
||||||
|
|
||||||
|
HB_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hb_subset_profile_t
|
||||||
|
* Things that change based on target environment, e.g. OS.
|
||||||
|
* Threadsafe for multiple concurrent subset operations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct hb_subset_profile_t hb_subset_profile_t;
|
||||||
|
|
||||||
|
HB_EXTERN hb_subset_profile_t *
|
||||||
|
hb_subset_profile_create ();
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_subset_profile_destroy (hb_subset_profile_t *profile);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hb_subset_input_t
|
||||||
|
* Things that change based on the input. Characters to keep, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct hb_subset_input_t hb_subset_input_t;
|
||||||
|
|
||||||
|
HB_EXTERN hb_subset_input_t *
|
||||||
|
hb_subset_input_create ();
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_subset_input_destroy (hb_subset_input_t *subset_input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hb_subset_face_t
|
||||||
|
* Reusable subset-ready plan for a given face. Threadsafe for multiple
|
||||||
|
* concurrent subset operations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct hb_subset_face_t hb_subset_face_t;
|
||||||
|
|
||||||
|
HB_EXTERN hb_subset_face_t *
|
||||||
|
hb_subset_face_create (hb_face_t *face);
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_subset_face_destroy (hb_subset_face_t *face);
|
||||||
|
|
||||||
|
|
||||||
|
HB_EXTERN hb_bool_t
|
||||||
|
hb_subset (hb_subset_profile_t *profile,
|
||||||
|
hb_subset_input_t *input,
|
||||||
|
hb_subset_face_t *face,
|
||||||
|
hb_blob_t **result /* OUT */);
|
||||||
|
|
||||||
|
HB_END_DECLS
|
||||||
|
|
||||||
|
#endif /* HB_SUBSET_H */
|
1
src/hb.h
1
src/hb.h
|
@ -41,6 +41,7 @@
|
||||||
#include "hb-set.h"
|
#include "hb-set.h"
|
||||||
#include "hb-shape.h"
|
#include "hb-shape.h"
|
||||||
#include "hb-shape-plan.h"
|
#include "hb-shape-plan.h"
|
||||||
|
#include "hb-subset.h"
|
||||||
#include "hb-unicode.h"
|
#include "hb-unicode.h"
|
||||||
#include "hb-version.h"
|
#include "hb-version.h"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
add_subdirectory(api)
|
add_subdirectory(api)
|
||||||
add_subdirectory(shaping)
|
add_subdirectory(shaping)
|
||||||
|
add_subdirectory(subset)
|
||||||
add_subdirectory(fuzzing)
|
add_subdirectory(fuzzing)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
NULL =
|
NULL =
|
||||||
EXTRA_DIST =
|
EXTRA_DIST =
|
||||||
SUBDIRS = api shaping fuzzing
|
SUBDIRS = api shaping fuzzing subset
|
||||||
|
|
||||||
EXTRA_DIST += \
|
EXTRA_DIST += \
|
||||||
CMakeLists.txt \
|
CMakeLists.txt \
|
||||||
|
|
|
@ -29,6 +29,7 @@ TEST_PROGS = \
|
||||||
test-object \
|
test-object \
|
||||||
test-set \
|
test-set \
|
||||||
test-shape \
|
test-shape \
|
||||||
|
test-subset \
|
||||||
test-unicode \
|
test-unicode \
|
||||||
test-version \
|
test-version \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2011 Google, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Google Author(s): Garret Rieger
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb-test.h"
|
||||||
|
|
||||||
|
/* Unit tests for hb-subset.h */
|
||||||
|
|
||||||
|
static const char test_data[] = { 0, 0, 1, 0 };
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_subset (void)
|
||||||
|
{
|
||||||
|
hb_blob_t *font_blob = hb_blob_create(test_data, sizeof(test_data),
|
||||||
|
HB_MEMORY_MODE_READONLY, NULL, NULL);
|
||||||
|
hb_face_t *face = hb_face_create(font_blob, 0);
|
||||||
|
|
||||||
|
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||||
|
hb_subset_input_t *input = hb_subset_input_create();
|
||||||
|
hb_subset_face_t *subset_face = hb_subset_face_create(face);
|
||||||
|
|
||||||
|
hb_blob_t *output;
|
||||||
|
g_assert(hb_subset(profile, input, subset_face, &output));
|
||||||
|
|
||||||
|
unsigned int output_length;
|
||||||
|
const char *output_data = hb_blob_get_data(output, &output_length);
|
||||||
|
g_assert_cmpmem(test_data, 4, output_data, output_length);
|
||||||
|
|
||||||
|
hb_blob_destroy(output);
|
||||||
|
hb_subset_face_destroy(subset_face);
|
||||||
|
hb_subset_input_destroy(input);
|
||||||
|
hb_subset_profile_destroy(profile);
|
||||||
|
hb_face_destroy(face);
|
||||||
|
hb_blob_destroy(font_blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
hb_test_init (&argc, &argv);
|
||||||
|
|
||||||
|
hb_test_add (test_subset);
|
||||||
|
|
||||||
|
return hb_test_run();
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
if (HB_BUILD_UTILS)
|
||||||
|
file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/Makefile.sources" SOURCES)
|
||||||
|
extract_make_variable (TESTS ${SOURCES})
|
||||||
|
foreach (test IN ITEMS ${TESTS})
|
||||||
|
add_test (NAME ${test}
|
||||||
|
COMMAND python run-tests.py $<TARGET_FILE:hb-subset> "data/${test}"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
endforeach ()
|
||||||
|
endif ()
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
|
NULL =
|
||||||
|
EXTRA_DIST =
|
||||||
|
CLEANFILES =
|
||||||
|
SUBDIRS = data
|
||||||
|
|
||||||
|
# Convenience targets:
|
||||||
|
lib:
|
||||||
|
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
|
||||||
|
|
||||||
|
EXTRA_DIST += \
|
||||||
|
CMakeLists.txt \
|
||||||
|
run-tests.py \
|
||||||
|
subset_test_suite.py \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
CLEANFILES += \
|
||||||
|
subset_test_suite.py[co] \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
|
NULL =
|
||||||
|
EXTRA_DIST =
|
||||||
|
CLEANFILES =
|
||||||
|
SUBDIRS =
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(TESTS) \
|
||||||
|
expected/basics \
|
||||||
|
fonts \
|
||||||
|
profiles \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
# Convenience targets:
|
||||||
|
lib:
|
||||||
|
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
|
||||||
|
|
||||||
|
TEST_EXTENSIONS = .tests
|
||||||
|
TESTS_LOG_COMPILER = $(srcdir)/../run-tests.py $(top_builddir)/util/hb-subset$(EXEEXT)
|
||||||
|
include Makefile.sources
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,9 @@
|
||||||
|
TESTS = \
|
||||||
|
tests/basics.tests \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
XFAIL_TESTS = \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
DISABLED_TESTS = \
|
||||||
|
$(NULL)
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
FONTS:
|
||||||
|
Roboto-Regular.abc.ttf
|
||||||
|
|
||||||
|
PROFILES:
|
||||||
|
default.txt
|
||||||
|
|
||||||
|
SUBSETS:
|
||||||
|
b
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Pre-generates the expected output subset files (via fonttools) for
|
||||||
|
# specified subset test suite(s).
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from subprocess import check_call
|
||||||
|
from subset_test_suite import SubsetTestSuite
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print "Usage: generate-expected-outputs.py <test suite file> ..."
|
||||||
|
|
||||||
|
|
||||||
|
def generate_expected_output(input_file, unicodes, output_path):
|
||||||
|
check_call(["fonttools", "subset",
|
||||||
|
input_file,
|
||||||
|
"--unicodes=%s" % unicodes,
|
||||||
|
"--output-file=%s" % output_path])
|
||||||
|
|
||||||
|
|
||||||
|
args = sys.argv[1:]
|
||||||
|
if not args:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
for path in args:
|
||||||
|
with io.open(path, mode="r", encoding="utf-8") as f:
|
||||||
|
test_suite = SubsetTestSuite(path, f.read())
|
||||||
|
output_directory = test_suite.get_output_directory()
|
||||||
|
|
||||||
|
print "Generating output files for %s" % output_directory
|
||||||
|
for test in test_suite.tests():
|
||||||
|
unicodes = test.unicodes()
|
||||||
|
font_name = test.get_font_name()
|
||||||
|
print "Creating subset %s/%s" % (output_directory, font_name)
|
||||||
|
generate_expected_output(test.font_path, unicodes,
|
||||||
|
os.path.join(output_directory,
|
||||||
|
font_name))
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Runs a subsetting test suite. Compares the results of subsetting via harfbuz
|
||||||
|
# to subsetting via fonttools.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from subset_test_suite import SubsetTestSuite
|
||||||
|
|
||||||
|
|
||||||
|
def cmd(command):
|
||||||
|
p = subprocess.Popen (
|
||||||
|
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
p.wait ()
|
||||||
|
print (p.stderr.read (), end="") # file=sys.stderr
|
||||||
|
return p.stdout.read (), p.returncode
|
||||||
|
|
||||||
|
def read_binary(file_path):
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
def fail_test(test, cli_args, message):
|
||||||
|
print ('ERROR: %s' % message)
|
||||||
|
print ('Test State:')
|
||||||
|
print (' test.font_path %s' % os.path.abspath(test.font_path))
|
||||||
|
print (' test.profile_path %s' % os.path.abspath(test.profile_path))
|
||||||
|
print (' test.unicodes %s' % test.unicodes())
|
||||||
|
expected_file = os.path.join(test_suite.get_output_directory(),
|
||||||
|
test.get_font_name())
|
||||||
|
print (' expected_file %s' % os.path.abspath(expected_file))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def run_test(test):
|
||||||
|
out_file = os.path.join(tempfile.mkdtemp(), test.get_font_name() + '-subset.ttf')
|
||||||
|
cli_args = [hb_subset,
|
||||||
|
"--font-file=" + test.font_path,
|
||||||
|
"--output-file=" + out_file,
|
||||||
|
"--unicodes=%s" % test.unicodes()]
|
||||||
|
_, return_code = cmd(cli_args)
|
||||||
|
|
||||||
|
if return_code:
|
||||||
|
return fail_test(test, cli_args, "%s returned %d" % (' '.join(cli_args), return_code))
|
||||||
|
|
||||||
|
expected = read_binary(os.path.join(test_suite.get_output_directory(),
|
||||||
|
test.get_font_name()))
|
||||||
|
actual = read_binary(out_file)
|
||||||
|
|
||||||
|
if len(actual) != len(expected):
|
||||||
|
return fail_test(test, cli_args, "expected %d bytes, actual %d: %s" % (
|
||||||
|
len(expected), len(actual), ' '.join(cli_args)))
|
||||||
|
|
||||||
|
if not actual == expected:
|
||||||
|
return fail_test(test, cli_args, 'files are the same length but not the same bytes')
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
args = sys.argv[1:]
|
||||||
|
if not args or sys.argv[1].find('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
|
||||||
|
print ("First argument does not seem to point to usable hb-subset.")
|
||||||
|
sys.exit (1)
|
||||||
|
hb_subset, args = args[0], args[1:]
|
||||||
|
|
||||||
|
if not len(args):
|
||||||
|
print ("No tests supplied.")
|
||||||
|
sys.exit (1)
|
||||||
|
|
||||||
|
fails = 0
|
||||||
|
for path in args:
|
||||||
|
with io.open(path, mode="r", encoding="utf-8") as f:
|
||||||
|
print ("Running tests in " + path)
|
||||||
|
test_suite = SubsetTestSuite(path, f.read())
|
||||||
|
for test in test_suite.tests():
|
||||||
|
fails += run_test(test)
|
||||||
|
|
||||||
|
if fails != 0:
|
||||||
|
print (str (fails) + " test(s) failed.")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print ("All tests passed.")
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# A single test in a subset test suite. Identifies a font
|
||||||
|
# a subsetting profile, and a subset to be cut.
|
||||||
|
class Test:
|
||||||
|
def __init__(self, font_path, profile_path, subset):
|
||||||
|
self.font_path = font_path
|
||||||
|
self.profile_path = profile_path
|
||||||
|
self.subset = subset
|
||||||
|
|
||||||
|
def unicodes(self):
|
||||||
|
return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
|
||||||
|
|
||||||
|
def get_font_name(self):
|
||||||
|
font_base_name = os.path.basename(self.font_path)
|
||||||
|
font_base_name_parts = os.path.splitext(font_base_name)
|
||||||
|
profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
|
||||||
|
|
||||||
|
return "%s.%s.%s%s" % (font_base_name_parts[0],
|
||||||
|
profile_name,
|
||||||
|
self.unicodes(),
|
||||||
|
font_base_name_parts[1])
|
||||||
|
|
||||||
|
# A group of tests to perform on the subsetter. Each test
|
||||||
|
# Identifies a font a subsetting profile, and a subset to be cut.
|
||||||
|
class SubsetTestSuite:
|
||||||
|
|
||||||
|
def __init__(self, test_path, definition):
|
||||||
|
self.test_path = test_path
|
||||||
|
self.fonts = set()
|
||||||
|
self.profiles = set()
|
||||||
|
self.subsets = set()
|
||||||
|
self._parse(definition)
|
||||||
|
|
||||||
|
def get_output_directory(self):
|
||||||
|
test_name = os.path.splitext(os.path.basename(self.test_path))[0]
|
||||||
|
data_dir = os.path.join(os.path.dirname(self.test_path), "..")
|
||||||
|
|
||||||
|
output_dir = os.path.normpath(os.path.join(data_dir, "expected", test_name))
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.mkdir(output_dir)
|
||||||
|
if not os.path.isdir(output_dir):
|
||||||
|
raise Error("%s is not a directory." % output_dir)
|
||||||
|
|
||||||
|
return output_dir
|
||||||
|
|
||||||
|
def tests(self):
|
||||||
|
for font in self.fonts:
|
||||||
|
font = os.path.join(self._base_path(), "fonts", font)
|
||||||
|
for profile in self.profiles:
|
||||||
|
profile = os.path.join(self._base_path(), "profiles", profile)
|
||||||
|
for subset in self.subsets:
|
||||||
|
yield Test(font, profile, subset)
|
||||||
|
|
||||||
|
def _base_path(self):
|
||||||
|
return os.path.dirname(os.path.dirname(self.test_path))
|
||||||
|
|
||||||
|
def _parse(self, definition):
|
||||||
|
destinations = {
|
||||||
|
"FONTS:": self.fonts,
|
||||||
|
"PROFILES:": self.profiles,
|
||||||
|
"SUBSETS:": self.subsets
|
||||||
|
}
|
||||||
|
|
||||||
|
current_destination = None
|
||||||
|
for line in definition.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if line.startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line in destinations:
|
||||||
|
current_destination = destinations[line]
|
||||||
|
elif current_destination is not None:
|
||||||
|
current_destination.add(line)
|
||||||
|
else:
|
||||||
|
raise Exception("Failed to parse test suite file.")
|
|
@ -46,6 +46,9 @@ endif # HAVE_FREETYPE
|
||||||
hb_shape_SOURCES = $(HB_SHAPE_sources)
|
hb_shape_SOURCES = $(HB_SHAPE_sources)
|
||||||
bin_PROGRAMS += hb-shape
|
bin_PROGRAMS += hb-shape
|
||||||
|
|
||||||
|
hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
|
||||||
|
bin_PROGRAMS += hb-subset
|
||||||
|
|
||||||
if HAVE_OT
|
if HAVE_OT
|
||||||
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
|
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
|
||||||
bin_PROGRAMS += hb-ot-shape-closure
|
bin_PROGRAMS += hb-ot-shape-closure
|
||||||
|
|
|
@ -28,3 +28,10 @@ HB_OT_SHAPE_CLOSURE_sources = \
|
||||||
options.hh \
|
options.hh \
|
||||||
main-font-text.hh \
|
main-font-text.hh \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
HB_SUBSET_CLI_sources = \
|
||||||
|
hb-subset.cc \
|
||||||
|
options.cc \
|
||||||
|
options.hh \
|
||||||
|
main-font-text.hh \
|
||||||
|
$(NULL)
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2010 Behdad Esfahbod
|
||||||
|
* Copyright © 2011,2012 Google, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Google Author(s): Garret Rieger, Rod Sheeter
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "main-font-text.hh"
|
||||||
|
#include "hb-subset.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command line interface to the harfbuzz font subsetter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct subset_consumer_t
|
||||||
|
{
|
||||||
|
subset_consumer_t (option_parser_t *parser)
|
||||||
|
: failed (false), options(parser) {}
|
||||||
|
|
||||||
|
void init (hb_buffer_t *buffer_,
|
||||||
|
const font_options_t *font_opts)
|
||||||
|
{
|
||||||
|
font = hb_font_reference (font_opts->get_font ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void consume_line (const char *text,
|
||||||
|
unsigned int text_len,
|
||||||
|
const char *text_before,
|
||||||
|
const char *text_after)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_bool_t
|
||||||
|
write_file (const char *output_file, hb_blob_t *blob) {
|
||||||
|
unsigned int data_length;
|
||||||
|
const char* data = hb_blob_get_data (blob, &data_length);
|
||||||
|
|
||||||
|
int fd_out = open(output_file, O_CREAT | O_WRONLY, S_IRWXU);
|
||||||
|
if (fd_out == -1) {
|
||||||
|
fprintf(stderr, "Unable to open output file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ssize_t bytes_written = write(fd_out, data, data_length);
|
||||||
|
if (bytes_written == -1) {
|
||||||
|
fprintf(stderr, "Unable to write output file\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bytes_written != data_length) {
|
||||||
|
fprintf(stderr, "Expected %u bytes written, got %ld\n", data_length,
|
||||||
|
bytes_written);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void finish (const font_options_t *font_opts)
|
||||||
|
{
|
||||||
|
// TODO(Q1) check for errors from creates and such
|
||||||
|
hb_subset_profile_t *subset_profile = hb_subset_profile_create();
|
||||||
|
hb_subset_input_t *subset_input = hb_subset_input_create();
|
||||||
|
hb_face_t *face = hb_font_get_face (font);
|
||||||
|
hb_subset_face_t *subset_face = hb_subset_face_create(face);
|
||||||
|
|
||||||
|
hb_blob_t *result = nullptr;
|
||||||
|
failed = !(hb_subset(subset_profile, subset_input, subset_face, &result)
|
||||||
|
&& write_file(options.output_file, result));
|
||||||
|
|
||||||
|
hb_subset_profile_destroy (subset_profile);
|
||||||
|
hb_subset_input_destroy (subset_input);
|
||||||
|
hb_subset_face_destroy (subset_face);
|
||||||
|
hb_blob_destroy (result);
|
||||||
|
hb_font_destroy (font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool failed;
|
||||||
|
|
||||||
|
private:
|
||||||
|
output_options_t options;
|
||||||
|
hb_font_t *font;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
main_font_text_t<subset_consumer_t, 10, 0> driver;
|
||||||
|
return driver.main (argc, argv);
|
||||||
|
}
|
Loading…
Reference in New Issue