michael@0: /* michael@0: * Copyright © 2010,2011,2012 Google, Inc. michael@0: * michael@0: * This is part of HarfBuzz, a text shaping library. michael@0: * michael@0: * Permission is hereby granted, without written agreement and without michael@0: * license or royalty fees, to use, copy, modify, and distribute this michael@0: * software and its documentation for any purpose, provided that the michael@0: * above copyright notice and the following two paragraphs appear in michael@0: * all copies of this software. michael@0: * michael@0: * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR michael@0: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES michael@0: * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN michael@0: * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH michael@0: * DAMAGE. michael@0: * michael@0: * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, michael@0: * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND michael@0: * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS michael@0: * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO michael@0: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. michael@0: * michael@0: * Google Author(s): Behdad Esfahbod michael@0: */ michael@0: michael@0: #ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH michael@0: #define HB_OT_SHAPE_COMPLEX_PRIVATE_HH michael@0: michael@0: #include "hb-private.hh" michael@0: michael@0: #include "hb-ot-shape-private.hh" michael@0: #include "hb-ot-shape-normalize-private.hh" michael@0: michael@0: michael@0: michael@0: /* buffer var allocations, used by complex shapers */ michael@0: #define complex_var_u8_0() var2.u8[2] michael@0: #define complex_var_u8_1() var2.u8[3] michael@0: michael@0: michael@0: enum hb_ot_shape_zero_width_marks_type_t { michael@0: HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, michael@0: // HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY, michael@0: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE, michael@0: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, michael@0: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, michael@0: michael@0: HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE michael@0: }; michael@0: michael@0: michael@0: /* Master OT shaper list */ michael@0: #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (sea) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ michael@0: HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \ michael@0: /* ^--- Add new shapers here */ michael@0: michael@0: michael@0: struct hb_ot_complex_shaper_t michael@0: { michael@0: char name[8]; michael@0: michael@0: /* collect_features() michael@0: * Called during shape_plan(). michael@0: * Shapers should use plan->map to add their features and callbacks. michael@0: * May be NULL. michael@0: */ michael@0: void (*collect_features) (hb_ot_shape_planner_t *plan); michael@0: michael@0: /* override_features() michael@0: * Called during shape_plan(). michael@0: * Shapers should use plan->map to override features and add callbacks after michael@0: * common features are added. michael@0: * May be NULL. michael@0: */ michael@0: void (*override_features) (hb_ot_shape_planner_t *plan); michael@0: michael@0: michael@0: /* data_create() michael@0: * Called at the end of shape_plan(). michael@0: * Whatever shapers return will be accessible through plan->data later. michael@0: * If NULL is returned, means a plan failure. michael@0: */ michael@0: void *(*data_create) (const hb_ot_shape_plan_t *plan); michael@0: michael@0: /* data_destroy() michael@0: * Called when the shape_plan is being destroyed. michael@0: * plan->data is passed here for destruction. michael@0: * If NULL is returned, means a plan failure. michael@0: * May be NULL. michael@0: */ michael@0: void (*data_destroy) (void *data); michael@0: michael@0: michael@0: /* preprocess_text() michael@0: * Called during shape(). michael@0: * Shapers can use to modify text before shaping starts. michael@0: * May be NULL. michael@0: */ michael@0: void (*preprocess_text) (const hb_ot_shape_plan_t *plan, michael@0: hb_buffer_t *buffer, michael@0: hb_font_t *font); michael@0: michael@0: michael@0: hb_ot_shape_normalization_mode_t normalization_preference; michael@0: michael@0: /* decompose() michael@0: * Called during shape()'s normalization. michael@0: * May be NULL. michael@0: */ michael@0: bool (*decompose) (const hb_ot_shape_normalize_context_t *c, michael@0: hb_codepoint_t ab, michael@0: hb_codepoint_t *a, michael@0: hb_codepoint_t *b); michael@0: michael@0: /* compose() michael@0: * Called during shape()'s normalization. michael@0: * May be NULL. michael@0: */ michael@0: bool (*compose) (const hb_ot_shape_normalize_context_t *c, michael@0: hb_codepoint_t a, michael@0: hb_codepoint_t b, michael@0: hb_codepoint_t *ab); michael@0: michael@0: /* setup_masks() michael@0: * Called during shape(). michael@0: * Shapers should use map to get feature masks and set on buffer. michael@0: * Shapers may NOT modify characters. michael@0: * May be NULL. michael@0: */ michael@0: void (*setup_masks) (const hb_ot_shape_plan_t *plan, michael@0: hb_buffer_t *buffer, michael@0: hb_font_t *font); michael@0: michael@0: hb_ot_shape_zero_width_marks_type_t zero_width_marks; michael@0: michael@0: bool fallback_position; michael@0: }; michael@0: michael@0: #define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name; michael@0: HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS michael@0: #undef HB_COMPLEX_SHAPER_IMPLEMENT michael@0: michael@0: michael@0: static inline const hb_ot_complex_shaper_t * michael@0: hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) michael@0: { michael@0: switch ((hb_tag_t) planner->props.script) michael@0: { michael@0: default: michael@0: return &_hb_ot_complex_shaper_default; michael@0: michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: case HB_SCRIPT_ARABIC: michael@0: michael@0: /* Unicode-3.0 additions */ michael@0: case HB_SCRIPT_MONGOLIAN: michael@0: case HB_SCRIPT_SYRIAC: michael@0: michael@0: /* Unicode-5.0 additions */ michael@0: case HB_SCRIPT_NKO: michael@0: case HB_SCRIPT_PHAGS_PA: michael@0: michael@0: /* Unicode-6.0 additions */ michael@0: case HB_SCRIPT_MANDAIC: michael@0: michael@0: /* For Arabic script, use the Arabic shaper even if no OT script tag was found. michael@0: * This is because we do fallback shaping for Arabic script (and not others). */ michael@0: if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT || michael@0: planner->props.script == HB_SCRIPT_ARABIC) michael@0: return &_hb_ot_complex_shaper_arabic; michael@0: else michael@0: return &_hb_ot_complex_shaper_default; michael@0: michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: case HB_SCRIPT_THAI: michael@0: case HB_SCRIPT_LAO: michael@0: michael@0: return &_hb_ot_complex_shaper_thai; michael@0: michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: case HB_SCRIPT_HANGUL: michael@0: michael@0: return &_hb_ot_complex_shaper_hangul; michael@0: michael@0: michael@0: /* Unicode-2.0 additions */ michael@0: case HB_SCRIPT_TIBETAN: michael@0: michael@0: return &_hb_ot_complex_shaper_tibetan; michael@0: michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: case HB_SCRIPT_HEBREW: michael@0: michael@0: return &_hb_ot_complex_shaper_hebrew; michael@0: michael@0: michael@0: /* ^--- Add new shapers here */ michael@0: michael@0: michael@0: #if 0 michael@0: /* Note: michael@0: * michael@0: * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according michael@0: * to Martin Hosken and Jonathan Kew do not require complex shaping. michael@0: * michael@0: * TODO We should automate figuring out which scripts do not need complex shaping michael@0: * michael@0: * TODO We currently keep data for these scripts in our indic table. Need to fix the michael@0: * generator to not do that. michael@0: */ michael@0: michael@0: michael@0: /* Simple? */ michael@0: michael@0: /* Unicode-3.2 additions */ michael@0: case HB_SCRIPT_BUHID: michael@0: case HB_SCRIPT_HANUNOO: michael@0: michael@0: /* Unicode-5.1 additions */ michael@0: case HB_SCRIPT_SAURASHTRA: michael@0: michael@0: /* Unicode-6.0 additions */ michael@0: case HB_SCRIPT_BATAK: michael@0: case HB_SCRIPT_BRAHMI: michael@0: michael@0: michael@0: /* Simple */ michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: /* These have their own shaper now. */ michael@0: case HB_SCRIPT_LAO: michael@0: case HB_SCRIPT_THAI: michael@0: michael@0: /* Unicode-3.2 additions */ michael@0: case HB_SCRIPT_TAGALOG: michael@0: case HB_SCRIPT_TAGBANWA: michael@0: michael@0: /* Unicode-4.0 additions */ michael@0: case HB_SCRIPT_LIMBU: michael@0: case HB_SCRIPT_TAI_LE: michael@0: michael@0: /* Unicode-4.1 additions */ michael@0: case HB_SCRIPT_KHAROSHTHI: michael@0: case HB_SCRIPT_SYLOTI_NAGRI: michael@0: michael@0: /* Unicode-5.1 additions */ michael@0: case HB_SCRIPT_KAYAH_LI: michael@0: michael@0: /* Unicode-5.2 additions */ michael@0: case HB_SCRIPT_TAI_VIET: michael@0: michael@0: michael@0: #endif michael@0: michael@0: /* Unicode-1.1 additions */ michael@0: case HB_SCRIPT_BENGALI: michael@0: case HB_SCRIPT_DEVANAGARI: michael@0: case HB_SCRIPT_GUJARATI: michael@0: case HB_SCRIPT_GURMUKHI: michael@0: case HB_SCRIPT_KANNADA: michael@0: case HB_SCRIPT_MALAYALAM: michael@0: case HB_SCRIPT_ORIYA: michael@0: case HB_SCRIPT_TAMIL: michael@0: case HB_SCRIPT_TELUGU: michael@0: michael@0: /* Unicode-3.0 additions */ michael@0: case HB_SCRIPT_SINHALA: michael@0: michael@0: /* Unicode-5.0 additions */ michael@0: case HB_SCRIPT_BALINESE: michael@0: michael@0: /* Unicode-5.1 additions */ michael@0: case HB_SCRIPT_LEPCHA: michael@0: case HB_SCRIPT_REJANG: michael@0: case HB_SCRIPT_SUNDANESE: michael@0: michael@0: /* Unicode-5.2 additions */ michael@0: case HB_SCRIPT_JAVANESE: michael@0: case HB_SCRIPT_KAITHI: michael@0: case HB_SCRIPT_MEETEI_MAYEK: michael@0: michael@0: /* Unicode-6.0 additions */ michael@0: michael@0: /* Unicode-6.1 additions */ michael@0: case HB_SCRIPT_CHAKMA: michael@0: case HB_SCRIPT_SHARADA: michael@0: case HB_SCRIPT_TAKRI: michael@0: michael@0: /* If the designer designed the font for the 'DFLT' script, michael@0: * use the default shaper. Otherwise, use the Indic shaper. michael@0: * Note that for some simple scripts, there may not be *any* michael@0: * GSUB/GPOS needed, so there may be no scripts found! */ michael@0: if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T')) michael@0: return &_hb_ot_complex_shaper_default; michael@0: else michael@0: return &_hb_ot_complex_shaper_indic; michael@0: michael@0: case HB_SCRIPT_KHMER: michael@0: /* A number of Khmer fonts in the wild don't have a 'pref' feature, michael@0: * and as such won't shape properly via the Indic shaper; michael@0: * however, they typically have 'liga' / 'clig' features that implement michael@0: * the necessary "reordering" by means of ligature substitutions. michael@0: * So we send such pref-less fonts through the generic shaper instead. */ michael@0: if (planner->map.found_script[0] && michael@0: hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB, michael@0: planner->map.script_index[0], michael@0: planner->map.language_index[0], michael@0: HB_TAG ('p','r','e','f'), michael@0: NULL)) michael@0: return &_hb_ot_complex_shaper_indic; michael@0: else michael@0: return &_hb_ot_complex_shaper_default; michael@0: michael@0: case HB_SCRIPT_MYANMAR: michael@0: /* For Myanmar, we only want to use the Myanmar shaper if the "new" script michael@0: * tag is found. For "old" script tag we want to use the default shaper. */ michael@0: if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2')) michael@0: return &_hb_ot_complex_shaper_myanmar; michael@0: else michael@0: return &_hb_ot_complex_shaper_default; michael@0: michael@0: /* Unicode-4.1 additions */ michael@0: case HB_SCRIPT_BUGINESE: michael@0: case HB_SCRIPT_NEW_TAI_LUE: michael@0: michael@0: /* Unicode-5.1 additions */ michael@0: case HB_SCRIPT_CHAM: michael@0: michael@0: /* Unicode-5.2 additions */ michael@0: case HB_SCRIPT_TAI_THAM: michael@0: michael@0: /* If the designer designed the font for the 'DFLT' script, michael@0: * use the default shaper. Otherwise, use the Indic shaper. michael@0: * Note that for some simple scripts, there may not be *any* michael@0: * GSUB/GPOS needed, so there may be no scripts found! */ michael@0: if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T')) michael@0: return &_hb_ot_complex_shaper_default; michael@0: else michael@0: return &_hb_ot_complex_shaper_sea; michael@0: } michael@0: } michael@0: michael@0: michael@0: #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */