15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Copyright © 2012,2013 Mozilla Foundation. 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Copyright © 2012,2013 Google, Inc. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is part of HarfBuzz, a text shaping library. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission is hereby granted, without written agreement and without 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * license or royalty fees, to use, copy, modify, and distribute this 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * software and its documentation for any purpose, provided that the 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * above copyright notice and the following two paragraphs appear in 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * all copies of this software. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DAMAGE. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Mozilla Author(s): Jonathan Kew 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Google Author(s): Behdad Esfahbod 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HB_SHAPER coretext 3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define hb_coretext_shaper_face_data_t CGFont 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-shaper-impl-private.hh" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-coretext.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef HB_DEBUG_CORETEXT 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HB_DEBUG_CORETEXT (HB_DEBUG+0) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)static void 4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)release_table_data (void *user_data) 4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data); 4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) CFRelease(cf_data); 4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)static hb_blob_t * 4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data); 5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); 5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (unlikely (!cf_data)) 5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return NULL; 5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data)); 5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const size_t length = CFDataGetLength (cf_data); 5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (!data || !length) 5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return NULL; 6023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY, 6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)), 6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) release_table_data); 6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_face_t * 6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_coretext_face_create (CGFontRef cg_font) 6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease); 7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * shaper face data 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)release_data (void *info, const void *data, size_t size) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert (hb_blob_get_length ((hb_blob_t *) info) == size && 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_blob_destroy ((hb_blob_t *) info); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_coretext_shaper_face_data_t * 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_face_data_create (hb_face_t *face) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_coretext_shaper_face_data_t *data = NULL; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (face->destroy == (hb_destroy_func_t) CGFontRelease) 9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) { 9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) data = CGFontRetain ((CGFontRef) face->user_data); 9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) else 10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) { 10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_blob_t *blob = hb_face_reference_blob (face); 10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) unsigned int blob_length; 10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const char *blob_data = hb_blob_get_data (blob, &blob_length); 10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (unlikely (!blob_length)) 10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (likely (provider)) 10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) data = CGFontCreateWithDataProvider (provider); 11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CGDataProviderRelease (provider); 11203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!data)) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (data); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CGFontRef 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)hb_coretext_face_get_cg_font (hb_face_t *face) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return face_data; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * shaper font data 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct hb_coretext_shaper_font_data_t { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontRef ct_font; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_coretext_shaper_font_data_t * 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_font_data_create (hb_font_t *font) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unlikely (!data)) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_face_t *face = font->face; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL, NULL); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unlikely (!data->ct_font)) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free (data); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFRelease (data->ct_font); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free (data); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * shaper shape_plan data 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct hb_coretext_shaper_shape_plan_data_t {}; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_coretext_shaper_shape_plan_data_t * 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const hb_feature_t *user_features HB_UNUSED, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int num_user_features HB_UNUSED) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CTFontRef 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_coretext_font_get_ct_font (hb_font_t *font) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return font_data->ct_font; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/* 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * shaper 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct feature_record_t { 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int feature; 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int setting; 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct active_feature_t { 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature_record_t rec; 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int order; 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static int cmp (const active_feature_t *a, const active_feature_t *b) { 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) a->order < b->order ? -1 : a->order > b->order ? 1 : 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 0; 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool operator== (const active_feature_t *f) { 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return cmp (this, f) == 0; 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct feature_event_t { 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int index; 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool start; 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t feature; 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static int cmp (const feature_event_t *a, const feature_event_t *b) { 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return a->index < b->index ? -1 : a->index > b->index ? 1 : 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) a->start < b->start ? -1 : a->start > b->start ? 1 : 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t::cmp (&a->feature, &b->feature); 236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct range_record_t { 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CTFontRef font; 241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int index_first; /* == start */ 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int index_last; /* == end - 1 */ 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* The following enum members are added in OS X 10.8. */ 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAltHalfWidthTextSelector 6 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAltProportionalTextSelector 5 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAlternateHorizKanaOffSelector 1 250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAlternateHorizKanaOnSelector 0 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAlternateKanaType 34 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAlternateVertKanaOffSelector 3 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kAlternateVertKanaOnSelector 2 254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kCaseSensitiveLayoutOffSelector 1 255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kCaseSensitiveLayoutOnSelector 0 256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kCaseSensitiveLayoutType 33 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kCaseSensitiveSpacingOffSelector 3 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kCaseSensitiveSpacingOnSelector 2 259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualAlternatesOffSelector 1 260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualAlternatesOnSelector 0 261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualAlternatesType 36 262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualLigaturesOffSelector 19 263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualLigaturesOnSelector 18 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualSwashAlternatesOffSelector 5 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kContextualSwashAlternatesOnSelector 4 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kDefaultLowerCaseSelector 0 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kDefaultUpperCaseSelector 0 268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kHistoricalLigaturesOffSelector 21 269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kHistoricalLigaturesOnSelector 20 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kHojoCharactersSelector 12 271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kJIS2004CharactersSelector 11 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kLowerCasePetiteCapsSelector 2 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kLowerCaseSmallCapsSelector 1 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kLowerCaseType 37 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kMathematicalGreekOffSelector 11 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kMathematicalGreekOnSelector 10 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kNLCCharactersSelector 13 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kQuarterWidthTextSelector 4 279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kScientificInferiorsSelector 4 280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltEightOffSelector 17 281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltEightOnSelector 16 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltEighteenOffSelector 37 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltEighteenOnSelector 36 284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltElevenOffSelector 23 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltElevenOnSelector 22 286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFifteenOffSelector 31 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFifteenOnSelector 30 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFiveOffSelector 11 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFiveOnSelector 10 290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFourOffSelector 9 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFourOnSelector 8 292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFourteenOffSelector 29 293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltFourteenOnSelector 28 294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltNineOffSelector 19 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltNineOnSelector 18 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltNineteenOffSelector 39 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltNineteenOnSelector 38 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltOneOffSelector 3 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltOneOnSelector 2 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSevenOffSelector 15 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSevenOnSelector 14 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSeventeenOffSelector 35 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSeventeenOnSelector 34 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSixOffSelector 13 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSixOnSelector 12 306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSixteenOffSelector 33 307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltSixteenOnSelector 32 308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTenOffSelector 21 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTenOnSelector 20 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltThirteenOffSelector 27 311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltThirteenOnSelector 26 312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltThreeOffSelector 7 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltThreeOnSelector 6 314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwelveOffSelector 25 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwelveOnSelector 24 316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwentyOffSelector 41 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwentyOnSelector 40 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwoOffSelector 5 319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAltTwoOnSelector 4 320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kStylisticAlternativesType 35 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kSwashAlternatesOffSelector 3 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kSwashAlternatesOnSelector 2 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kThirdWidthTextSelector 3 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kTraditionalNamesCharactersSelector 14 325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kUpperCasePetiteCapsSelector 2 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kUpperCaseSmallCapsSelector 1 327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define kUpperCaseType 38 328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* Table data courtesy of Apple. */ 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic const struct feature_mapping_t { 331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FourCharCode otFeatureTag; 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) uint16_t aatFeatureType; 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) uint16_t selectorToEnable; 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) uint16_t selectorToDisable; 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} feature_mappings[] = { 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, 350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, 369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, 371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, 372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, 373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, 375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, 379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, 381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, 383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, 385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, 386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, 387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, 388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, 392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, 393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, 394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, 395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, 396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, 397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, 398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, 399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, 400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, 401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, 402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, 403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'unic', kLetterCaseType, 14, 15 }, 404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, 408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, 409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, 411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static int 414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)_hb_feature_mapping_cmp (const void *key_, const void *entry_) 415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles){ 416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int key = * (unsigned int *) key_; 417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const feature_mapping_t * entry = (const feature_mapping_t *) entry_; 418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return key < entry->otFeatureTag ? -1 : 419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) key > entry->otFeatureTag ? 1 : 420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 0; 421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_bool_t 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_hb_coretext_shape (hb_shape_plan_t *shape_plan, 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_font_t *font, 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_buffer_t *buffer, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const hb_feature_t *features, 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int num_features) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_face_t *face = font->face; 43123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 43403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Attach marks to their bases, to match the 'ot' shaper. 43503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Adapted from hb-ot-shape:hb_form_clusters(). 43603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Note that this only makes us be closer to the 'ot' shaper, 43703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * but by no means the same. For example, if there's 43803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will 43903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * continue pointing to B2 even though B2 was merged into B1's 44003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * cluster... */ 44103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 44203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_unicode_funcs_t *unicode = buffer->unicode; 44303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int count = buffer->len; 44403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = buffer->info; 44503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 1; i < count; i++) 44603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint))) 44703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->merge_clusters (i - 1, i + 1); 44803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 44903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 45003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_auto_array_t<feature_record_t> feature_records; 45103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_auto_array_t<range_record_t> range_records; 45203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* 454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Set up features. 455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * (copied + modified from code from hb-uniscribe.cc) 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (num_features) 458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* Sort features by start/end events. */ 460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) hb_auto_array_t<feature_event_t> feature_events; 461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (unsigned int i = 0; i < num_features; i++) 462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, 464f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature_mappings, 465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ARRAY_LENGTH (feature_mappings), 466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) sizeof (feature_mappings[0]), 467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) _hb_feature_mapping_cmp); 468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!mapping) 469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) continue; 470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t feature; 472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.rec.feature = mapping->aatFeatureType; 473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; 474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.order = i; 475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature_event_t *event; 477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event = feature_events.push (); 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (unlikely (!event)) 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->index = features[i].start; 482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->start = true; 483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->feature = feature; 484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event = feature_events.push (); 486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (unlikely (!event)) 487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->index = features[i].end; 489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->start = false; 490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->feature = feature; 491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) feature_events.qsort (); 493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* Add a strategic final event. */ 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t feature; 496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.rec.feature = HB_TAG_NONE; 497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.rec.setting = 0; 498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature.order = num_features + 1; 499f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 500f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature_event_t *event = feature_events.push (); 501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (unlikely (!event)) 502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->index = 0; /* This value does magic. */ 504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->start = false; 505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) event->feature = feature; 506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* Scan events and save features for each range. */ 509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) hb_auto_array_t<active_feature_t> active_features; 510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int last_index = 0; 511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (unsigned int i = 0; i < feature_events.len; i++) 512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) feature_event_t *event = &feature_events[i]; 514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (event->index != last_index) 516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 517f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* Save a snapshot of active features and the range. */ 518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) range_record_t *range = range_records.push (); 519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (unlikely (!range)) 520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (active_features.len) 523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 524f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 525f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* TODO sort and resolve conflicting features? */ 5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) /* active_features.qsort (); */ 528f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (unsigned int j = 0; j < active_features.len; j++) 529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFStringRef keys[2] = { 531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kCTFontFeatureTypeIdentifierKey, 532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kCTFontFeatureSelectorIdentifierKey 533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }; 534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFNumberRef values[2] = { 535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), 536f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) 537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }; 538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, 539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (const void **) keys, 540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (const void **) values, 541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2, 542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &kCFTypeDictionaryKeyCallBacks, 543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &kCFTypeDictionaryValueCallBacks); 544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (values[0]); 545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (values[1]); 546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFArrayAppendValue (features_array, dict); 548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (dict); 549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, 553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (const void **) &kCTFontFeatureSettingsAttribute, 554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (const void **) &features_array, 555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1, 556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &kCFTypeDictionaryKeyCallBacks, 557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &kCFTypeDictionaryValueCallBacks); 558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (features_array); 559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes); 561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (attributes); 562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); 564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CFRelease (font_desc); 565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) range->font = NULL; 569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) range->index_first = last_index; 572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) range->index_last = event->index - 1; 573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) last_index = event->index; 575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (event->start) { 578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t *feature = active_features.push (); 579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (unlikely (!feature)) 580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *feature = event->feature; 582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_feature_t *feature = active_features.find (&event->feature); 584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (feature) 585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) active_features.remove (feature - active_features.array); 586f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 587f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 588f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 589f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!range_records.len) /* No active feature found. */ 590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto fail_features; 591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 592f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) fail_features: 595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) num_features = 0; 596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 597f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int scratch_size; 599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 60103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \ 602f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Type *name = (Type *) scratch; \ 603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { \ 604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 60503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (_consumed > scratch_size)) \ 60603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { \ 60703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) on_no_room; \ 60803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) assert (0); \ 60903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } \ 610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scratch += _consumed; \ 611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scratch_size -= _consumed; \ 612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 61403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int chars_len = 0; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (unsigned int i = 0; i < buffer->len; i++) { 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hb_codepoint_t c = buffer->info[i].codepoint; 6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (likely (c <= 0xFFFFu)) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pchars[chars_len++] = c; 6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else if (unlikely (c > 0x10FFFFu)) 6215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pchars[chars_len++] = 0xFFFDu; 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else { 6235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); 6245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 62803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/); 62903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) chars_len = 0; 63003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < buffer->len; i++) 63103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 63203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_codepoint_t c = buffer->info[i].codepoint; 63303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int cluster = buffer->info[i].cluster; 63403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) log_clusters[chars_len++] = cluster; 63503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (hb_in_range (c, 0x10000u, 0x10FFFFu)) 63603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) log_clusters[chars_len++] = cluster; /* Surrogates. */ 63703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 63903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define FAIL(...) \ 64003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) HB_STMT_START { \ 64103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ 64203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ret = false; \ 64303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) goto fail; \ 64403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } HB_STMT_END; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 64603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) bool ret = true; 64703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFStringRef string_ref = NULL; 64803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTLineRef line = NULL; 649f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 65003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (0) 651f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 65203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)resize_and_retry: 65303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, buffer, "Buffer resize"); 65403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* string_ref uses the scratch-buffer for backing store, and line references 65503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * string_ref (via attr_string). We must release those before resizing buffer. */ 65603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) assert (string_ref); 65703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) assert (line); 65803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (string_ref); 65903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (line); 66003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) string_ref = NULL; 66103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) line = NULL; 66203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 66303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Get previous start-of-scratch-area, that we use later for readjusting 66403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * our existing scratch arrays. */ 66503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int old_scratch_used; 66603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_buffer_t::scratch_buffer_t *old_scratch; 66703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) old_scratch = buffer->get_scratch_buffer (&old_scratch_used); 66803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) old_scratch_used = scratch - old_scratch; 66903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 67003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!buffer->ensure (buffer->allocated * 2))) 67103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("Buffer resize failed"); 67203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 67303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the 67403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * cleanest way to do without completely restructuring the rest of this shaper. */ 67503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scratch = buffer->get_scratch_buffer (&scratch_size); 67603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch))); 67703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch))); 67803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scratch += old_scratch_used; 67903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scratch_size -= old_scratch_used; 68003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 68103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)retry: 68203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 68303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) string_ref = CFStringCreateWithCharactersNoCopy (NULL, 68403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pchars, chars_len, 68503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCFAllocatorNull); 68603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!string_ref)) 68703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CFStringCreateWithCharactersNoCopy failed"); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 68903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Create an attributed string, populate it, and create a line from it, then release attributed string. */ 690f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 69103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault, 69203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) chars_len); 69303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!attr_string)) 69403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CFAttributedStringCreateMutable failed"); 69503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); 69603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) 697f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) { 69803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 69903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCTVerticalFormsAttributeName, kCFBooleanTrue); 700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 70203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (buffer->props.language) 70303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 70403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)/* What's the iOS equivalent of this check? 70503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * The symbols was introduced in iOS 7.0. 70603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * At any rate, our fallback is safe and works fine. */ 70703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 70803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)# define kCTLanguageAttributeName CFSTR ("NSLanguage") 70903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif 71003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, 71103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_language_to_string (buffer->props.language), 71203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCFStringEncodingUTF8, 71303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCFAllocatorNull); 71403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!lang)) 71503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CFStringCreateWithCStringNoCopy failed"); 71603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 71703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCTLanguageAttributeName, lang); 71803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (lang); 71903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 72003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 72103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCTFontAttributeName, font_data->ct_font); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (num_features) 72403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 72503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int start = 0; 72603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) range_record_t *last_range = &range_records[0]; 72703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int k = 0; k < chars_len; k++) 72803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 72903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) range_record_t *range = last_range; 73003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) while (log_clusters[k] < range->index_first) 73103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) range--; 73203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) while (log_clusters[k] > range->index_last) 73303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) range++; 73403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (range != last_range) 73503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 73603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (last_range->font) 73703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start), 73803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCTFontAttributeName, last_range->font); 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 74003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) start = k; 74103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 74303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) last_range = range; 74403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 74503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (start != chars_len && last_range->font) 74603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start), 74703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) kCTFontAttributeName, last_range->font); 74803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 75103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level); 75203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault, 75303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) (const void **) &kCTTypesetterOptionForcedEmbeddingLevel, 75403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) (const void **) &level_number, 75503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1, 75603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) &kCFTypeDictionaryKeyCallBacks, 75703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) &kCFTypeDictionaryValueCallBacks); 75803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!options)) 75903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CFDictionaryCreate failed"); 76003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 76103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options); 76203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (options); 76303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (attr_string); 76403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!typesetter)) 76503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed"); 76603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 76703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0)); 76803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (typesetter); 76903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (unlikely (!line)) 77003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FAIL ("CTTypesetterCreateLine failed"); 77103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 77403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int num_runs = CFArrayGetCount (glyph_runs); 77503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs); 77623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 77703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->len = 0; 77803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) uint32_t status_and = ~0, status_or = 0; 77923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 78003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const CFRange range_all = CFRangeMake (0, 0); 78123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 78203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < num_runs; i++) 78303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 78403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i)); 78503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTRunStatus run_status = CTRunGetStatus (run); 78603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) status_or |= run_status; 78703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) status_and &= run_status; 78803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); 78903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 79003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* CoreText does automatic font fallback (AKA "cascading") for characters 79103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * not supported by the requested font, and provides no way to turn it off, 79203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * so we must detect if the returned run uses a font other than the requested 79303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * one and fill in the buffer with .notdef glyphs instead of random glyph 79403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * indices from a different font. 79503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 79603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFDictionaryRef attributes = CTRunGetAttributes (run); 79703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName)); 79803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!CFEqual (run_ct_font, font_data->ct_font)) 79903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 80003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* The run doesn't use our main font instance. We have to figure out 80103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * whether font fallback happened, or this is just CoreText giving us 80203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * another CTFont using the same underlying CGFont. CoreText seems 80303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * to do that in a variety of situations, one of which being vertical 80403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * text, but also perhaps for caching reasons. 80503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 80603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * First, see if it uses any of our subfonts created to set font features... 80703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 80803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Next, compare the CGFont to the one we used to create our fonts. 80903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Even this doesn't work all the time. 81003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 81103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Finally, we compare PS names, which I don't think are unique... 81203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 81303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Looks like if we really want to be sure here we have to modify the 81403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * font to change the name table, similar to what we do in the uniscribe 81503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * backend. 81603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 81703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * However, even that wouldn't work if we were passed in the CGFont to 81803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * begin with. 81903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 82003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Webkit uses a slightly different approach: it installs LastResort 82103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * as fallback chain, and then checks PS name of used font against 82203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * LastResort. That one is safe for any font except for LastResort, 82303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * as opposed to ours, which can fail if we are using any uninstalled 82403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * font that has the same name as an installed font. 82503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 82603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * See: http://github.com/behdad/harfbuzz/pull/36 82703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 82803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) bool matched = false; 82903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < range_records.len; i++) 83003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font)) 83103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 83203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) matched = true; 83303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) break; 83403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 83503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!matched) 83623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) { 83703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); 83803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (run_cg_font) 83903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 84003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) matched = CFEqual (run_cg_font, face_data); 84103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (run_cg_font); 84203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 84303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 84403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!matched) 84503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 84603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey); 84703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey); 84803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0); 84903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (run_ps_name); 85003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (font_ps_name); 85103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (result == kCFCompareEqualTo) 85203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) matched = true; 85303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 85403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!matched) 85503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 85603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRange range = CTRunGetStringRange (run); 85703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", 85803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) range.location, range.location + range.length); 85903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!buffer->ensure_inplace (buffer->len + range.length)) 86003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) goto resize_and_retry; 86103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = buffer->info + buffer->len; 86203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 86303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CGGlyph notdef = 0; 86403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1); 86503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 86603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int old_len = buffer->len; 86703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (CFIndex j = range.location; j < range.location + range.length; j++) 86803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 86903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); 87003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j) 87103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 87203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ch = CFStringGetCharacterAtIndex (string_ref, j - 1); 87303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu)) 87403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* This is the second of a surrogate pair. Don't need .notdef 87503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * for this one. */ 87603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) continue; 87703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 87803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 87903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->codepoint = notdef; 88003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->cluster = log_clusters[j]; 88103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 88203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->mask = advance; 88303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var1.u32 = 0; 88403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var2.u32 = 0; 88503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 88603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++; 88703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->len++; 88803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 88903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) 89003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->reverse_range (old_len, buffer->len); 89103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) continue; 89203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 89303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 89423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 89503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int num_glyphs = CTRunGetGlyphCount (run); 89603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (num_glyphs == 0) 89703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) continue; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 89903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!buffer->ensure_inplace (buffer->len + num_glyphs)) 90003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) goto resize_and_retry; 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 90203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *run_info = buffer->info + buffer->len; 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 90403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always 90503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * succeed, and so copying data to our own buffer will be rare. Reports 90603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * have it that this changed in OS X 10.10 Yosemite, and NULL is returned 90703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * frequently. At any rate, we can test that codepath by setting USE_PTR 90803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * to false. */ 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define USE_PTR true 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define SCRATCH_SAVE() \ 91303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int scratch_size_saved = scratch_size; \ 91403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_buffer_t::scratch_buffer_t *scratch_saved = scratch 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define SCRATCH_RESTORE() \ 91703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scratch_size = scratch_size_saved; \ 91803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scratch = scratch_saved; 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 92003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 92103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) SCRATCH_SAVE(); 92203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; 92303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!glyphs) { 92403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry); 92503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTRunGetGlyphs (run, range_all, glyph_buf); 92603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) glyphs = glyph_buf; 92703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 92803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL; 92903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!string_indices) { 93003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry); 93103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTRunGetStringIndices (run, range_all, index_buf); 93203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) string_indices = index_buf; 93303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 93403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = run_info; 93503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int j = 0; j < num_glyphs; j++) 93603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 93703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->codepoint = glyphs[j]; 93803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->cluster = log_clusters[string_indices[j]]; 93903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++; 94003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 94103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) SCRATCH_RESTORE(); 94203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 94303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 94403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) SCRATCH_SAVE(); 94503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; 94603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!positions) { 94703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry); 94803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CTRunGetPositions (run, range_all, position_buf); 94903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) positions = position_buf; 95003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 95103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); 95203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); 95303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = run_info; 95403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) 95503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 95603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int j = 0; j < num_glyphs; j++) 95703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 95803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_advance) - positions[j].x; 95903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->mask = advance; 96003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var1.u32 = positions[0].x; /* Yes, zero. */ 96103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var2.u32 = positions[j].y; 96203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++; 96303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 96403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 96503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) else 96603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 96703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) run_advance = -run_advance; 96803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int j = 0; j < num_glyphs; j++) 96903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 97003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) double advance = (j + 1 < num_glyphs ? positions[j + 1].y : positions[0].y + run_advance) - positions[j].y; 97103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->mask = advance; 97203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var1.u32 = positions[j].x; 97303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info->var2.u32 = positions[0].y; /* Yes, zero. */ 97403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++; 97503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 97603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 97703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) SCRATCH_RESTORE(); 97803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 97903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#undef SCRATCH_RESTORE 98003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#undef SCRATCH_SAVE 98103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#undef USE_PTR 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef ALLOCATE_ARRAY 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 98403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->len += num_glyphs; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 98703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Make sure all runs had the expected direction. */ 98803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 98903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) assert (bool (status_and & kCTRunStatusRightToLeft) == backward); 99003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) assert (bool (status_or & kCTRunStatusRightToLeft) == backward); 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 99203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer->clear_positions (); 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 99403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int count = buffer->len; 99503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = buffer->info; 99603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_position_t *pos = buffer->pos; 99703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) 99803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < count; i++) 99903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 100003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->x_advance = info->mask; 100103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->x_offset = info->var1.u32; 100203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->y_offset = info->var2.u32; 100303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++, pos++; 100403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 100503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) else 100603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < count; i++) 100703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 100803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->y_advance = info->mask; 100903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->x_offset = info->var1.u32; 101003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pos->y_offset = info->var2.u32; 101103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info++, pos++; 101203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 101403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /* Fix up clusters so that we never return out-of-order indices; 101503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * if core text has reordered glyphs, we'll merge them to the 101603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * beginning of the reordered cluster. CoreText is nice enough 101703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * to tell us whenever it has produced nonmonotonic results... 101803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Note that we assume the input clusters were nonmonotonic to 101903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * begin with. 102003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * 102103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * This does *not* mean we'll form the same clusters as Uniscribe 102203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * or the native OT backend, only that the cluster indices will be 102303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * monotonic in the output buffer. */ 102403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (count > 1 && (status_or & kCTRunStatusNonMonotonic)) 102503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 102603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hb_glyph_info_t *info = buffer->info; 102703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) 102803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 102903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int cluster = info[count - 1].cluster; 103003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = count - 1; i > 0; i--) 103103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 103203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) cluster = MIN (cluster, info[i - 1].cluster); 103303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info[i - 1].cluster = cluster; 103403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 103603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) else 103703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 103803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) unsigned int cluster = info[0].cluster; 103903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 1; i < count; i++) 104003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) { 104103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) cluster = MIN (cluster, info[i].cluster); 104203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) info[i].cluster = cluster; 104303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 104803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#undef FAIL 104903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 105003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)fail: 105103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (string_ref) 105203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (string_ref); 105303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (line) 105403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (line); 105503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 105603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (unsigned int i = 0; i < range_records.len; i++) 105703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (range_records[i].font) 105803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CFRelease (range_records[i].font); 1059f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 106003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return ret; 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 106223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 106323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 106423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/* 106523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * AAT shaper 106623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 106723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 106823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) 106923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) 107023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 107123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 107223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/* 107323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * shaper face data 107423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 107523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 107623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)struct hb_coretext_aat_shaper_face_data_t {}; 107723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 107823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_coretext_aat_shaper_face_data_t * 107923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_face_data_create (hb_face_t *face) 108023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 108123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT); 108223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) /* Umm, we just reference the table to check whether it exists. 108323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * Maybe add better API for this? */ 108423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (!hb_blob_get_length (mort_blob)) 108523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) { 108623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_blob_destroy (mort_blob); 108723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX); 108823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (!hb_blob_get_length (mort_blob)) 108923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) { 109023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_blob_destroy (mort_blob); 109123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return NULL; 109223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 109323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 109423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_blob_destroy (mort_blob); 109523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 109623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 109723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 109823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 109923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void 110023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED) 110123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 110223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 110323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 110423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 110523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/* 110623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * shaper font data 110723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 110823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 110923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)struct hb_coretext_aat_shaper_font_data_t {}; 111023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 111123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_coretext_aat_shaper_font_data_t * 111223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_font_data_create (hb_font_t *font) 111323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 111423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 111523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 111623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 111723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void 111823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED) 111923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 112023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 112123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 112223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 112323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/* 112423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * shaper shape_plan data 112523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 112623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 112723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)struct hb_coretext_aat_shaper_shape_plan_data_t {}; 112823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 112923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_coretext_aat_shaper_shape_plan_data_t * 113023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 113123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const hb_feature_t *user_features HB_UNUSED, 113223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) unsigned int num_user_features HB_UNUSED) 113323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 113423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 113523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 113623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 113723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void 113823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED) 113923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 114023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 114123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 114223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 114323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/* 114423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * shaper 114523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 114623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 114723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)hb_bool_t 114823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, 114923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_font_t *font, 115023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) hb_buffer_t *buffer, 115123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const hb_feature_t *features, 115223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) unsigned int num_features) 115323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles){ 115423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); 115523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 1156