src/hb-open-type-private.hh | 33 ++++++--- src/hb-ot-layout-common-private.hh | 133 +++++++++++++++++++++++++++++++++++-- src/hb-ot-layout.cc | 107 ++++++++++++++++++++++++++--- src/hb-ot-layout.h | 8 +- src/hb-private.hh | 4 + src/test-size-params.cc | 13 +-- 6 files changed, 259 insertions(+), 39 deletions(-)
New commits: commit 85bc44b90a19c6a669ed567a9cd8513448600afe Author: Behdad Esfahbod <[email protected]> Date: Wed Dec 12 11:38:49 2012 -0500 [OTLayout] More 'size' feature sanity checking We still don't look for the old incorrect place of the featureParams. I'll wait till someone actually complains about it... diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 61ba31a..f7a54bb 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -658,33 +658,92 @@ hb_ot_layout_get_size_params (hb_face_t *face, const OT::Feature &f = gpos.get_feature (i); const OT::FeatureParamsSize ¶ms = f.get_feature_params ().u.size; -#define PARAM(a, A) if (a) *a = params.A + /* This subtable has some "history", if you will. Some earlier versions of + * Adobe tools calculated the offset of the FeatureParams sutable from the + * beginning of the FeatureList table! Now, we don't check for that possibility, + * but we want to at least detect junk data and reject it. + * + * Read Roberts wrote on 9/15/06 on [email protected] : + * + * Yes, it is correct that a new version of the AFDKO (version 2.0) will be + * coming out soon, and that the makeotf program will build a font with a + * 'size' feature that is correct by the specification. + * + * The specification for this feature tag is in the "OpenType Layout Tag + * Registry". You can see a copy of this at: + * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size + * + * Here is one set of rules to determine if the 'size' feature is built + * correctly, or as by the older versions of MakeOTF. You may be able to do + * better. + * + * Assume that the offset to the size feature is according to specification, + * and make the following value checks. If it fails, assume the the size + * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. + * If this fails, reject the 'size' feature. The older makeOTF's calculated the + * offset from the beginning of the FeatureList table, rather than from the + * beginning of the 'size' Feature table. + * + * If "design size" == 0: + * fails check + * + * Else if ("subfamily identifier" == 0 and + * "range start" == 0 and + * "range end" == 0 and + * "range start" == 0 and + * "menu name ID" == 0) + * passes check: this is the format used when there is a design size + * specified, but there is no recommended size range. + * + * Else if ("design size" < "range start" or + * "design size" > "range end" or + * "range end" <= "range start" or + * "menu name ID" < 256 or + * "menu name ID" > 32767 or + * menu name ID is not a name ID which is actually in the name table) + * fails test + * Else + * passes test. + */ + if (!params.designSize) - goto zero_all; - PARAM (design_size, designSize); - if (!params.subfamilyID) - { + ret = false; + else if (params.subfamilyID == 0 && + params.subfamilyNameID == 0 && + params.rangeStart == 0 && + params.rangeEnd == 0) + ret = true; + else if (params.designSize < params.rangeStart || + params.designSize > params.rangeEnd || + params.subfamilyNameID < 256 || + params.subfamilyNameID > 32767) + ret = false; + else ret = true; - goto zero_most; - }; - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); -#undef PARAM - return true; +#define PARAM(a, A) if (a) *a = params.A + if (ret) + { + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); + break; + } +#undef PARAM } } #define PARAM(a, A) if (a) *a = 0 -zero_all: - PARAM (design_size, designSize); -zero_most: - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); + if (!ret) + { + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); + } #undef PARAM return ret; commit 0bae50a36f3022f9bb6b2c001c191eeaaa4ef954 Author: Behdad Esfahbod <[email protected]> Date: Tue Dec 11 16:01:31 2012 -0500 [OTLayout] Add FeatureParamsCharacterVariants struct No API yet. diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh index 4a8116e..da6c8f9 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common-private.hh @@ -329,6 +329,48 @@ struct FeatureParamsStylisticSet DEFINE_SIZE_STATIC (4); }; +struct FeatureParamsCharacterVariants +{ + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + return TRACE_RETURN (c->check_struct (this) && + characters.sanitize (c)); + } + /* TODO: This is made private since we don't have the facilities in + * FeatureParams to correctly sanitize this. */ + private: + USHORT format; /* Format number is set to 0. */ + USHORT featUILableNameID; /* The ânameâ table name ID that + * specifies a string (or strings, + * for multiple languages) for a + * user-interface label for this + * feature. (May be NULL.) */ + USHORT featUITooltipTextNameID;/* The ânameâ table name ID that + * specifies a string (or strings, + * for multiple languages) that an + * application can use for tooltip + * text for this feature. (May be + * NULL.) */ + USHORT sampleTextNameID; /* The ânameâ table name ID that + * specifies sample text that + * illustrates the effect of this + * feature. (May be NULL.) */ + USHORT numNamedParameters; /* Number of named parameters. (May + * be zero.) */ + USHORT firstParamUILabelNameID;/* The first ânameâ table name ID + * used to specify strings for + * user-interface labels for the + * feature parameters. (Must be zero + * if numParameters is zero.) */ + ArrayOf<UINT24> + characters; /* Array of the Unicode Scalar Value + * of the characters for which this + * feature provides glyph variants. + * (May be zero.) */ + public: + DEFINE_SIZE_ARRAY (14, characters); +}; + struct FeatureParams { /* Note: @@ -339,6 +381,9 @@ struct FeatureParams * subtable possible. This may nuke a possibly valid subtable if it's unfortunate * enough to happen at the very end of the GSUB/GPOS table. But that's very * unlikely (I hope!). + * + * When we fully implement FeatureParamsCharacterVariants, we should fix this + * shortcoming... */ inline bool sanitize (hb_sanitize_context_t *c) { @@ -347,10 +392,11 @@ struct FeatureParams } union { - FeatureParamsSize size; - FeatureParamsStylisticSet stylisticSet; + FeatureParamsSize size; + FeatureParamsStylisticSet stylisticSet; + FeatureParamsCharacterVariants characterVariants; } u; - DEFINE_SIZE_STATIC (10); + DEFINE_SIZE_STATIC (17); }; struct Feature commit bd61bc13ea8ff350ada5449b2cfeb612e66ecafa Author: Behdad Esfahbod <[email protected]> Date: Tue Dec 11 16:00:43 2012 -0500 [OTLayout] Add UINT24 type diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh index e57558e..347e299 100644 --- a/src/hb-open-type-private.hh +++ b/src/hb-open-type-private.hh @@ -534,32 +534,43 @@ struct BEInt<Type, 4> inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); } private: uint8_t v[4]; }; +template <typename Type> +struct BEInt<Type, 3> +{ + public: + inline void set (Type i) { hb_be_uint24_put (v,i); } + inline operator Type (void) const { return hb_be_uint24_get (v); } + inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); } + inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); } + private: uint8_t v[3]; +}; /* Integer types in big-endian order and no alignment requirement */ -template <typename Type> +template <typename Type, unsigned int Size> struct IntType { inline void set (Type i) { v.set (i); } inline operator Type(void) const { return v; } - inline bool operator == (const IntType<Type> &o) const { return v == o.v; } - inline bool operator != (const IntType<Type> &o) const { return v != o.v; } - static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { return b->cmp (*a); } - inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } + inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; } + inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; } + static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); } + inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); return TRACE_RETURN (likely (c->check_struct (this))); } protected: - BEInt<Type, sizeof (Type)> v; + BEInt<Type, Size> v; public: - DEFINE_SIZE_STATIC (sizeof (Type)); + DEFINE_SIZE_STATIC (Size); }; -typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ -typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ -typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ -typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ +typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */ +typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */ +typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */ +typedef IntType<int32_t, 4> LONG; /* 32-bit signed integer. */ +typedef IntType<uint32_t, 3> UINT24; /* 24-bit unsigned integer. */ /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ typedef SHORT FWORD; diff --git a/src/hb-private.hh b/src/hb-private.hh index 3a62c67..be0d505 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -509,6 +509,10 @@ static inline uint32_t hb_uint32_swap (const uint32_t v) #define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3]) #define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) +#define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] (V); } HB_STMT_END +#define hb_be_uint24_get(v) (uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2]) +#define hb_be_uint24_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) + /* ASCII tag/character handling */ commit 9cf7f9d4f61741932570afbefdee5edf61f79ae4 Author: Behdad Esfahbod <[email protected]> Date: Tue Dec 11 14:31:13 2012 -0500 Make test-size-params write size in points diff --git a/src/test-size-params.cc b/src/test-size-params.cc index 0caef97..947b566 100644 --- a/src/test-size-params.cc +++ b/src/test-size-params.cc @@ -84,20 +84,10 @@ main (int argc, char **argv) hb_blob_destroy (blob); blob = NULL; - unsigned int params[5]; - if (!hb_ot_layout_get_size_params (face, - params, - params+1, - params+2, - params+3, - params+4)) - return 1; + unsigned int p[5]; + bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4); - for (unsigned int i = 0; i < 5; i++) { - if (i) printf (" "); - printf ("%u", params[i]); - } - printf ("\n"); + printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.); - return 0; + return !ret; } commit 372fe2b67b1757e809bf33e1e9055a00c5bed304 Author: Behdad Esfahbod <[email protected]> Date: Tue Dec 11 14:30:57 2012 -0500 [OTLayout] Make hb_ot_layout_get_size_params() do some checks diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index cf485bd..61ba31a 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -647,6 +647,7 @@ hb_ot_layout_get_size_params (hb_face_t *face, unsigned int *range_start, /* OUT. May be NULL */ unsigned int *range_end /* OUT. May be NULL */) { + bool ret = false; const OT::GPOS &gpos = _get_gpos (face); unsigned int num_features = gpos.get_feature_count (); @@ -658,7 +659,14 @@ hb_ot_layout_get_size_params (hb_face_t *face, const OT::FeatureParamsSize ¶ms = f.get_feature_params ().u.size; #define PARAM(a, A) if (a) *a = params.A + if (!params.designSize) + goto zero_all; PARAM (design_size, designSize); + if (!params.subfamilyID) + { + ret = true; + goto zero_most; + }; PARAM (subfamily_id, subfamilyID); PARAM (subfamily_name_id, subfamilyNameID); PARAM (range_start, rangeStart); @@ -670,12 +678,14 @@ hb_ot_layout_get_size_params (hb_face_t *face, } #define PARAM(a, A) if (a) *a = 0 +zero_all: PARAM (design_size, designSize); +zero_most: PARAM (subfamily_id, subfamilyID); PARAM (subfamily_name_id, subfamilyNameID); PARAM (range_start, rangeStart); PARAM (range_end, rangeEnd); #undef PARAM - return false; + return ret; } commit 875a5cbc9c37f4264241c43b80afad2628eab749 Author: Behdad Esfahbod <[email protected]> Date: Tue Dec 11 14:17:01 2012 -0500 [OTLayout] Change hb_ot_layout_get_params() API And add implementation for StylisticSet UINameID. No API yet. diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh index 0b753b8..4a8116e 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common-private.hh @@ -248,6 +248,8 @@ struct Script typedef RecordListOf<Script> ScriptList; + +/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ struct FeatureParamsSize { inline bool sanitize (hb_sanitize_context_t *c) { @@ -255,15 +257,89 @@ struct FeatureParamsSize return TRACE_RETURN (c->check_struct (this)); } - USHORT params[5]; + USHORT designSize; /* Represents the design size in 720/inch + * units (decipoints). The design size entry + * must be non-zero. When there is a design + * size but no recommended size range, the + * rest of the array will consist of zeros. */ + USHORT subfamilyID; /* Has no independent meaning, but serves + * as an identifier that associates fonts + * in a subfamily. All fonts which share a + * Preferred or Font Family name and which + * differ only by size range shall have the + * same subfamily value, and no fonts which + * differ in weight or style shall have the + * same subfamily value. If this value is + * zero, the remaining fields in the array + * will be ignored. */ + USHORT subfamilyNameID;/* If the preceding value is non-zero, this + * value must be set in the range 256 - 32767 + * (inclusive). It records the value of a + * field in the name table, which must + * contain English-language strings encoded + * in Windows Unicode and Macintosh Roman, + * and may contain additional strings + * localized to other scripts and languages. + * Each of these strings is the name an + * application should use, in combination + * with the family name, to represent the + * subfamily in a menu. Applications will + * choose the appropriate version based on + * their selection criteria. */ + USHORT rangeStart; /* Large end of the recommended usage range + * (inclusive), stored in 720/inch units + * (decipoints). */ + USHORT rangeEnd; /* Small end of the recommended usage range + (exclusive), stored in 720/inch units + * (decipoints). */ public: DEFINE_SIZE_STATIC (10); }; +/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ +struct FeatureParamsStylisticSet +{ + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + /* Right now minorVersion is at zero. Which means, any table supports + * the uiNameID field. */ + return TRACE_RETURN (c->check_struct (this)); + } + + USHORT minorVersion; /* (set to 0): This corresponds to a âminorâ + * version number. Additional data may be + * added to the end of this Feature Parameters + * table in the future. */ + + USHORT uiNameID; /* The 'name' table name ID that specifies a + * string (or strings, for multiple languages) + * for a user-interface label for this + * feature. The values of uiLabelNameId and + * sampleTextNameId are expected to be in the + * font-specific name ID range (256-32767), + * though that is not a requirement in this + * Feature Parameters specification. The + * user-interface label for the feature can + * be provided in multiple languages. An + * English string should be included as a + * fallback. The string should be kept to a + * minimal length to fit comfortably with + * different application interfaces. */ + public: + DEFINE_SIZE_STATIC (4); +}; + struct FeatureParams { - /* Note: currently the only feature with params is 'size', so we hardcode - * the length of the table to that of the FeatureParamsSize. */ + /* Note: + * + * FeatureParams structures unfortunately don't have a generic length argument, + * so their length depends on the feature name / requested use. We don't have + * that information at sanitize time. As such, we sanitize for the longest + * subtable possible. This may nuke a possibly valid subtable if it's unfortunate + * enough to happen at the very end of the GSUB/GPOS table. But that's very + * unlikely (I hope!). + */ inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); @@ -271,7 +347,8 @@ struct FeatureParams } union { - FeatureParamsSize size; + FeatureParamsSize size; + FeatureParamsStylisticSet stylisticSet; } u; DEFINE_SIZE_STATIC (10); }; diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 441b3ea..cf485bd 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -640,8 +640,12 @@ hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t ze } hb_bool_t -hb_ot_layout_get_size_params (hb_face_t *face, - uint16_t *data /* OUT, 5 items */) +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + unsigned int *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */) { const OT::GPOS &gpos = _get_gpos (face); @@ -651,17 +655,27 @@ hb_ot_layout_get_size_params (hb_face_t *face, if (HB_TAG ('s','i','z','e') == gpos.get_feature_tag (i)) { const OT::Feature &f = gpos.get_feature (i); - const OT::FeatureParams ¶ms = f.get_feature_params (); + const OT::FeatureParamsSize ¶ms = f.get_feature_params ().u.size; - for (unsigned int i = 0; i < 5; i++) - data[i] = params.u.size.params[i]; +#define PARAM(a, A) if (a) *a = params.A + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); +#undef PARAM return true; } } - for (unsigned int i = 0; i < 5; i++) - data[i] = 0; +#define PARAM(a, A) if (a) *a = 0 + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); +#undef PARAM return false; } diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index f8fab24..134f1a6 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -280,8 +280,12 @@ Xhb_ot_layout_lookup_position (hb_font_t *font, /* Optical 'size' feature info. Returns true if found. * http://www.microsoft.com/typography/otspec/features_pt.htm#size */ hb_bool_t -hb_ot_layout_get_size_params (hb_face_t *face, - uint16_t *data /* OUT, 5 items */); +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + unsigned int *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */); HB_END_DECLS diff --git a/src/test-size-params.cc b/src/test-size-params.cc index a60aa10..0caef97 100644 --- a/src/test-size-params.cc +++ b/src/test-size-params.cc @@ -84,8 +84,13 @@ main (int argc, char **argv) hb_blob_destroy (blob); blob = NULL; - uint16_t params[5]; - if (!hb_ot_layout_get_size_params (face, params)) + unsigned int params[5]; + if (!hb_ot_layout_get_size_params (face, + params, + params+1, + params+2, + params+3, + params+4)) return 1; for (unsigned int i = 0; i < 5; i++) {
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
