[API] Changes to main shape API

hb_shape() now accepts a shaper_options and a shaper_list argument.
Both can be set to NULL to emulate previous API.  And in most situations
they are expected to be set to NULL.

hb_shape() also returns a boolean for now.  If shaper_list is NULL, the
return value can be ignored.

shaper_options is ignored for now, but otherwise it should be a
NULL-terminated list of strings.

shaper_list is a NULL-terminated list of strings.  Currently recognized
strings are "ot" for native OpenType Layout implementation, "uniscribe"
for the Uniscribe backend, and "fallback" for the non-complex backend
(that will be implemented shortly).  The fallback backend never fails.

The env var HB_SHAPER_LIST is also parsed and honored.  It's a
colon-separated list of shaper names.  The fallback shaper is invoked if
none of the env-listed shapers succeed.

New API hb_buffer_guess_properties() added.
This commit is contained in:
Behdad Esfahbod 2011-08-04 22:31:05 -04:00
parent 57692adf12
commit 02aeca985b
17 changed files with 270 additions and 103 deletions

2
TODO
View File

@ -23,8 +23,6 @@ API issues to fix before 1.0:
- Add sanitize API (and a cached version, that saves result on blob user-data)
- hb_shape() currently does a bit more than hb_ot_shape(). Shouldn't.
- Add glib GBoxedType stuff and introspection

View File

@ -138,12 +138,21 @@ AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
dnl ===========================================================================
have_ot=true;
if $have_ot; then
AC_DEFINE(HAVE_OT, 1, [Have native OpenType Layout backend])
fi
AM_CONDITIONAL(HAVE_OT, $have_ot)
dnl ===========================================================================
AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true, have_uniscribe=false)
if $have_uniscribe; then
UNISCRIBE_CFLAGS=
UNISCRIBE_LIBS="-lusp10 -lgdi32"
AC_SUBST(UNISCRIBE_CFLAGS)
AC_SUBST(UNISCRIBE_LIBS)
AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe backend])
fi
AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)

View File

@ -18,6 +18,8 @@ HBSOURCES = \
hb-buffer-private.hh \
hb-buffer.cc \
hb-common.cc \
hb-fallback-shape-private.hh \
hb-fallback-shape.cc \
hb-font-private.hh \
hb-font.cc \
hb-mutex-private.hh \
@ -30,6 +32,7 @@ HBSOURCES = \
hb-shape.cc \
hb-unicode-private.hh \
hb-unicode.cc \
hb-ot-tag.cc \
$(NULL)
HBHEADERS = \
hb.h \
@ -42,6 +45,11 @@ HBHEADERS = \
hb-version.h \
$(NULL)
MAINTAINERCLEANFILES += \
$(srcdir)/hb-version.h \
$(NULL)
if HAVE_OT
HBSOURCES += \
hb-ot-layout.cc \
hb-ot-layout-common-private.hh \
@ -62,7 +70,6 @@ HBSOURCES += \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize.cc \
hb-ot-shape-private.hh \
hb-ot-tag.cc \
$(NULL)
HBHEADERS += \
hb-ot.h \
@ -70,10 +77,7 @@ HBHEADERS += \
hb-ot-shape.h \
hb-ot-tag.h \
$(NULL)
MAINTAINERCLEANFILES += \
$(srcdir)/hb-version.h \
$(NULL)
endif
if HAVE_GLIB
HBCFLAGS += $(GLIB_CFLAGS)

View File

@ -94,6 +94,7 @@ struct _hb_buffer_t {
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse (void);
HB_INTERNAL void reverse_clusters (void);
HB_INTERNAL void guess_properties (void);
HB_INTERNAL void swap_buffers (void);
HB_INTERNAL void clear_output (void);

View File

@ -402,6 +402,35 @@ hb_buffer_t::reverse_clusters (void)
reverse_range (start, i);
}
void
hb_buffer_t::guess_properties (void)
{
/* If script is set to INVALID, guess from buffer contents */
if (props.script == HB_SCRIPT_INVALID) {
for (unsigned int i = 0; i < len; i++) {
hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
if (likely (script != HB_SCRIPT_COMMON &&
script != HB_SCRIPT_INHERITED &&
script != HB_SCRIPT_UNKNOWN)) {
props.script = script;
break;
}
}
}
/* If direction is set to INVALID, guess from script */
if (props.direction == HB_DIRECTION_INVALID) {
props.direction = hb_script_get_horizontal_direction (props.script);
}
/* If language is not set, use default language from locale */
if (props.language == HB_LANGUAGE_INVALID) {
/* TODO get_default_for_script? using $LANGUAGE */
props.language = hb_language_get_default ();
}
}
static inline void
dump_var_allocation (const hb_buffer_t *buffer)
{
@ -675,6 +704,12 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
buffer->reverse_clusters ();
}
void
hb_buffer_guess_properties (hb_buffer_t *buffer)
{
buffer->guess_properties ();
}
#define ADD_UTF(T) \
HB_STMT_START { \
const T *next = (const T *) text + item_offset; \

View File

@ -132,6 +132,9 @@ hb_buffer_reverse (hb_buffer_t *buffer);
void
hb_buffer_reverse_clusters (hb_buffer_t *buffer);
void
hb_buffer_guess_properties (hb_buffer_t *buffer);
/* Filling the buffer in */

View File

@ -0,0 +1,48 @@
/*
* 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): Behdad Esfahbod
*/
#ifndef HB_FALLBACK_SHAPE_PRIVATE_HH
#define HB_FALLBACK_SHAPE_PRIVATE_HH
#include "hb-private.hh"
#include "hb-shape.h"
HB_BEGIN_DECLS
HB_INTERNAL hb_bool_t
hb_fallback_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char *shaper_options);
HB_END_DECLS
#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */

43
src/hb-fallback-shape.cc Normal file
View File

@ -0,0 +1,43 @@
/*
* 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): Behdad Esfahbod
*/
#include "hb-fallback-shape-private.hh"
#include "hb-buffer-private.hh"
hb_bool_t
hb_fallback_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char *shaper_options)
{
buffer->guess_properties ();
return TRUE;
}

View File

@ -428,16 +428,21 @@ hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
hb_ot_shape_execute_internal (&c);
}
void
hb_bool_t
hb_ot_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
unsigned int num_features,
const char *shaper_options)
{
hb_ot_shape_plan_t plan;
buffer->guess_properties ();
hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
hb_ot_shape_execute (&plan, font, buffer, features, num_features);
return TRUE;
}

View File

@ -34,11 +34,12 @@
HB_BEGIN_DECLS
void
hb_bool_t
hb_ot_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
unsigned int num_features,
const char *shaper_options);
HB_END_DECLS

View File

@ -30,62 +30,89 @@
#include "hb-buffer-private.hh"
#include "hb-ot-shape.h"
#ifdef HAVE_GRAPHITE
#include "hb-graphite.h"
#ifdef HAVE_UNISCRIBE
# include "hb-uniscribe.h"
#endif
#ifdef HAVE_OT
# include "hb-ot-shape.h"
#endif
#include "hb-fallback-shape-private.hh"
typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char *shaper_options);
#define HB_SHAPER_IMPLEMENT(name) {#name, hb_##name##_shape}
static const struct hb_shaper_pair_t {
const char name[16];
hb_shape_func_t func;
} shapers[] = {
/* v--- Add new shapers in the right place here */
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe),
#endif
#ifdef HAVE_OT
HB_SHAPER_IMPLEMENT (ot),
#endif
HB_SHAPER_IMPLEMENT (fallback) /* should be last */
};
#undef HB_SHAPER_IMPLEMENT
static void
hb_shape_internal (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
static class static_shaper_list_t {
public:
static_shaper_list_t (void) {
char *env = getenv ("HB_SHAPER_LIST");
shaper_list = NULL;
if (!env || !*env)
return;
unsigned int count = 3; /* initial, fallback, null */
for (const char *p = env; (p == strchr (p, ':')) && p++; )
count++;
if (count <= ARRAY_LENGTH (static_shaper_list))
shaper_list = static_shaper_list;
else
shaper_list = (const char **) malloc (count * sizeof (shaper_list[0]));
count = 0;
shaper_list[count++] = env;
for (char *p = env; (p == strchr (p, ':')) && (*p = '\0', TRUE) && p++; )
shaper_list[count++] = p;
shaper_list[count++] = "fallback";
shaper_list[count] = NULL;
}
const char **shaper_list;
const char *static_shaper_list[10];
} env_shaper_list;
hb_bool_t
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char *shaper_options,
const char **shaper_list)
{
hb_ot_shape (font, buffer, features, num_features);
}
if (likely (!shaper_list))
shaper_list = env_shaper_list.shaper_list;
void
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
hb_segment_properties_t orig_props;
orig_props = buffer->props;
/* If script is set to INVALID, guess from buffer contents */
if (buffer->props.script == HB_SCRIPT_INVALID) {
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++) {
hb_script_t script = hb_unicode_script (unicode, buffer->info[i].codepoint);
if (likely (script != HB_SCRIPT_COMMON &&
script != HB_SCRIPT_INHERITED &&
script != HB_SCRIPT_UNKNOWN)) {
buffer->props.script = script;
break;
}
if (likely (!shaper_list)) {
for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++)
if (likely (shapers[i].func (font, buffer,
features, num_features,
shaper_options)))
return TRUE;
} else {
while (*shaper_list) {
for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++)
if (0 == strcmp (*shaper_list, shapers[i].name) &&
likely (shapers[i].func (font, buffer,
features, num_features,
shaper_options)))
return TRUE;
shaper_list++;
}
}
/* If direction is set to INVALID, guess from script */
if (buffer->props.direction == HB_DIRECTION_INVALID) {
buffer->props.direction = hb_script_get_horizontal_direction (buffer->props.script);
}
/* If language is not set, use default language from locale */
if (buffer->props.language == HB_LANGUAGE_INVALID) {
/* TODO get_default_for_script? using $LANGUAGE */
buffer->props.language = hb_language_get_default ();
}
hb_shape_internal (font, buffer, features, num_features);
buffer->props = orig_props;
return FALSE;
}

View File

@ -41,11 +41,14 @@ typedef struct _hb_feature_t {
unsigned int end;
} hb_feature_t;
void
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
hb_bool_t
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char *shaper_options,
const char **shaper_list);
HB_END_DECLS

View File

@ -56,13 +56,6 @@ DWORD GetFontData(
);
*/
static void
fallback_shape (hb_font_t *font,
hb_buffer_t *buffer)
{
DEBUG_MSG (UNISCRIBE, NULL, "Fallback shaper invoked");
}
static void
populate_log_font (LOGFONTW *lf,
HDC hdc,
@ -78,18 +71,19 @@ populate_log_font (LOGFONTW *lf,
lf->lfFaceName[i] = family_name[i];
}
void
hb_bool_t
hb_uniscribe_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
unsigned int num_features,
const char *shaper_options)
{
buffer->guess_properties ();
HRESULT hr;
if (unlikely (!buffer->len)) {
fallback:
fallback_shape (font, buffer);
}
if (unlikely (!buffer->len))
return TRUE;
retry:
@ -138,10 +132,10 @@ retry:
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#define FALLBACK(...) \
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
goto fallback; \
return FALSE; \
} HB_STMT_END;
@ -164,7 +158,7 @@ retry:
script_tags,
&item_count);
if (unlikely (FAILED (hr)))
FALLBACK ("ScriptItemizeOpenType() failed: %d", hr);
FAIL ("ScriptItemizeOpenType() failed: %d", hr);
#undef MAX_ITEMS
@ -178,17 +172,13 @@ retry:
hb_blob_t *blob = hb_face_get_blob (font->face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length)) {
hb_blob_destroy (blob);
FALLBACK ("Empty font blob");
}
if (unlikely (!blob_length))
FAIL ("Empty font blob");
DWORD num_fonts_installed;
HANDLE fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed);
if (unlikely (!fh)) {
hb_blob_destroy (blob);
FALLBACK ("AddFontMemResourceEx() failed");
}
if (unlikely (!fh))
FAIL ("AddFontMemResourceEx() failed");
/* FREE stuff, specially when taking fallback... */
@ -230,16 +220,16 @@ retry:
(int *) &glyphs_len);
if (unlikely (items[i].a.fNoGlyphIndex))
FALLBACK ("ScriptShapeOpenType() set fNoGlyphIndex");
FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
if (unlikely (hr == E_OUTOFMEMORY))
{
buffer->ensure (buffer->allocated * 2);
if (buffer->in_error)
FALLBACK ("Buffer resize failed");
FAIL ("Buffer resize failed");
goto retry;
}
if (unlikely (FAILED (hr)))
FALLBACK ("ScriptShapeOpenType() failed: %d", hr);
FAIL ("ScriptShapeOpenType() failed: %d", hr);
hr = ScriptPlaceOpenType (hdc,
&script_cache,
@ -261,7 +251,7 @@ retry:
offsets + glyphs_offset,
NULL);
if (unlikely (FAILED (hr)))
FALLBACK ("ScriptPlaceOpenType() failed: %d", hr);
FAIL ("ScriptPlaceOpenType() failed: %d", hr);
glyphs_offset += glyphs_len;
}
@ -285,9 +275,9 @@ retry:
buffer->ensure (glyphs_len);
if (buffer->in_error)
FALLBACK ("Buffer in error");
FAIL ("Buffer in error");
#undef FALLBACK
#undef FAIL
/* Set glyph infos */
for (unsigned int i = 0; i < glyphs_len; i++)
@ -317,7 +307,7 @@ retry:
}
/* Wow, done! */
return;
return TRUE;
}

View File

@ -34,11 +34,12 @@
HB_BEGIN_DECLS
void
hb_bool_t
hb_uniscribe_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
unsigned int num_features,
const char *shaper_options);
HB_END_DECLS

View File

@ -370,7 +370,7 @@ _hb_cr_text_glyphs (cairo_t *cr,
len = strlen (utf8);
hb_buffer_add_utf8 (hb_buffer, utf8, len, 0, len);
hb_shape (hb_font, hb_buffer, features, num_features);
hb_shape (hb_font, hb_buffer, features, num_features, NULL, NULL);
num_glyphs = hb_buffer_get_length (hb_buffer);
hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);

View File

@ -30,7 +30,6 @@
#endif
#include "hb.h"
#include "hb-uniscribe.h"
#ifdef HAVE_GLIB
#include <glib.h>
@ -97,7 +96,7 @@ main (int argc, char **argv)
hb_buffer_add_utf8 (buffer, "test", 4, 0, 4);
hb_uniscribe_shape (font, buffer, NULL, 0);
hb_shape (font, buffer, NULL, 0, NULL, NULL);
unsigned int count = hb_buffer_get_length (buffer);
hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);

View File

@ -110,7 +110,7 @@ test_shape (void)
hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
hb_buffer_add_utf8 (buffer, TesT, 4, 0, 4);
hb_shape (font, buffer, NULL, 0);
hb_shape (font, buffer, NULL, 0, NULL, NULL);
len = hb_buffer_get_length (buffer);
glyphs = hb_buffer_get_glyph_infos (buffer, NULL);