gfx/harfbuzz/src/hb-coretext.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /*
     2  * Copyright © 2012,2013  Mozilla Foundation.
     3  * Copyright © 2012,2013  Google, Inc.
     4  *
     5  *  This is part of HarfBuzz, a text shaping library.
     6  *
     7  * Permission is hereby granted, without written agreement and without
     8  * license or royalty fees, to use, copy, modify, and distribute this
     9  * software and its documentation for any purpose, provided that the
    10  * above copyright notice and the following two paragraphs appear in
    11  * all copies of this software.
    12  *
    13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    17  * DAMAGE.
    18  *
    19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    24  *
    25  * Mozilla Author(s): Jonathan Kew
    26  * Google Author(s): Behdad Esfahbod
    27  */
    29 #define HB_SHAPER coretext
    30 #include "hb-shaper-impl-private.hh"
    32 #include "hb-coretext.h"
    35 #ifndef HB_DEBUG_CORETEXT
    36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
    37 #endif
    40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
    41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
    44 /*
    45  * shaper face data
    46  */
    48 struct hb_coretext_shaper_face_data_t {
    49   CGFontRef cg_font;
    50 };
    52 static void
    53 release_data (void *info, const void *data, size_t size)
    54 {
    55   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
    56           hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
    58   hb_blob_destroy ((hb_blob_t *) info);
    59 }
    61 hb_coretext_shaper_face_data_t *
    62 _hb_coretext_shaper_face_data_create (hb_face_t *face)
    63 {
    64   hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
    65   if (unlikely (!data))
    66     return NULL;
    68   hb_blob_t *blob = hb_face_reference_blob (face);
    69   unsigned int blob_length;
    70   const char *blob_data = hb_blob_get_data (blob, &blob_length);
    71   if (unlikely (!blob_length))
    72     DEBUG_MSG (CORETEXT, face, "Face has empty blob");
    74   CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
    75   data->cg_font = CGFontCreateWithDataProvider (provider);
    76   CGDataProviderRelease (provider);
    78   if (unlikely (!data->cg_font)) {
    79     DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
    80     free (data);
    81     return NULL;
    82   }
    84   return data;
    85 }
    87 void
    88 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
    89 {
    90   CFRelease (data->cg_font);
    91   free (data);
    92 }
    94 CGFontRef
    95 hb_coretext_face_get_cg_font (hb_face_t *face)
    96 {
    97   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
    98   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    99   return face_data->cg_font;
   100 }
   103 /*
   104  * shaper font data
   105  */
   107 struct hb_coretext_shaper_font_data_t {
   108   CTFontRef ct_font;
   109 };
   111 hb_coretext_shaper_font_data_t *
   112 _hb_coretext_shaper_font_data_create (hb_font_t *font)
   113 {
   114   if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
   116   hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
   117   if (unlikely (!data))
   118     return NULL;
   120   hb_face_t *face = font->face;
   121   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   123   data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
   124   if (unlikely (!data->ct_font)) {
   125     DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
   126     free (data);
   127     return NULL;
   128   }
   130   return data;
   131 }
   133 void
   134 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
   135 {
   136   CFRelease (data->ct_font);
   137   free (data);
   138 }
   141 /*
   142  * shaper shape_plan data
   143  */
   145 struct hb_coretext_shaper_shape_plan_data_t {};
   147 hb_coretext_shaper_shape_plan_data_t *
   148 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
   149 					     const hb_feature_t *user_features HB_UNUSED,
   150 					     unsigned int        num_user_features HB_UNUSED)
   151 {
   152   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
   153 }
   155 void
   156 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
   157 {
   158 }
   160 CTFontRef
   161 hb_coretext_font_get_ct_font (hb_font_t *font)
   162 {
   163   if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
   164   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
   165   return font_data->ct_font;
   166 }
   169 /*
   170  * shaper
   171  */
   173 struct feature_record_t {
   174   unsigned int feature;
   175   unsigned int setting;
   176 };
   178 struct active_feature_t {
   179   feature_record_t rec;
   180   unsigned int order;
   182   static int cmp (const active_feature_t *a, const active_feature_t *b) {
   183     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
   184 	   a->order < b->order ? -1 : a->order > b->order ? 1 :
   185 	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
   186 	   0;
   187   }
   188   bool operator== (const active_feature_t *f) {
   189     return cmp (this, f) == 0;
   190   }
   191 };
   193 struct feature_event_t {
   194   unsigned int index;
   195   bool start;
   196   active_feature_t feature;
   198   static int cmp (const feature_event_t *a, const feature_event_t *b) {
   199     return a->index < b->index ? -1 : a->index > b->index ? 1 :
   200 	   a->start < b->start ? -1 : a->start > b->start ? 1 :
   201 	   active_feature_t::cmp (&a->feature, &b->feature);
   202   }
   203 };
   205 struct range_record_t {
   206   CTFontRef font;
   207   unsigned int index_first; /* == start */
   208   unsigned int index_last;  /* == end - 1 */
   209 };
   212 /* The following enum members are added in OS X 10.8. */
   213 #define kAltHalfWidthTextSelector		6
   214 #define kAltProportionalTextSelector		5
   215 #define kAlternateHorizKanaOffSelector		1
   216 #define kAlternateHorizKanaOnSelector		0
   217 #define kAlternateKanaType			34
   218 #define kAlternateVertKanaOffSelector		3
   219 #define kAlternateVertKanaOnSelector		2
   220 #define kCaseSensitiveLayoutOffSelector		1
   221 #define kCaseSensitiveLayoutOnSelector		0
   222 #define kCaseSensitiveLayoutType		33
   223 #define kCaseSensitiveSpacingOffSelector	3
   224 #define kCaseSensitiveSpacingOnSelector		2
   225 #define kContextualAlternatesOffSelector	1
   226 #define kContextualAlternatesOnSelector		0
   227 #define kContextualAlternatesType		36
   228 #define kContextualLigaturesOffSelector		19
   229 #define kContextualLigaturesOnSelector		18
   230 #define kContextualSwashAlternatesOffSelector	5
   231 #define kContextualSwashAlternatesOnSelector	4
   232 #define kDefaultLowerCaseSelector		0
   233 #define kDefaultUpperCaseSelector		0
   234 #define kHistoricalLigaturesOffSelector		21
   235 #define kHistoricalLigaturesOnSelector		20
   236 #define kHojoCharactersSelector			12
   237 #define kJIS2004CharactersSelector		11
   238 #define kLowerCasePetiteCapsSelector		2
   239 #define kLowerCaseSmallCapsSelector		1
   240 #define kLowerCaseType				37
   241 #define kMathematicalGreekOffSelector		11
   242 #define kMathematicalGreekOnSelector		10
   243 #define kNLCCharactersSelector			13
   244 #define kQuarterWidthTextSelector		4
   245 #define kScientificInferiorsSelector		4
   246 #define kStylisticAltEightOffSelector		17
   247 #define kStylisticAltEightOnSelector		16
   248 #define kStylisticAltEighteenOffSelector	37
   249 #define kStylisticAltEighteenOnSelector		36
   250 #define kStylisticAltElevenOffSelector		23
   251 #define kStylisticAltElevenOnSelector		22
   252 #define kStylisticAltFifteenOffSelector		31
   253 #define kStylisticAltFifteenOnSelector		30
   254 #define kStylisticAltFiveOffSelector		11
   255 #define kStylisticAltFiveOnSelector		10
   256 #define kStylisticAltFourOffSelector		9
   257 #define kStylisticAltFourOnSelector		8
   258 #define kStylisticAltFourteenOffSelector	29
   259 #define kStylisticAltFourteenOnSelector		28
   260 #define kStylisticAltNineOffSelector		19
   261 #define kStylisticAltNineOnSelector		18
   262 #define kStylisticAltNineteenOffSelector	39
   263 #define kStylisticAltNineteenOnSelector		38
   264 #define kStylisticAltOneOffSelector		3
   265 #define kStylisticAltOneOnSelector		2
   266 #define kStylisticAltSevenOffSelector		15
   267 #define kStylisticAltSevenOnSelector		14
   268 #define kStylisticAltSeventeenOffSelector	35
   269 #define kStylisticAltSeventeenOnSelector	34
   270 #define kStylisticAltSixOffSelector		13
   271 #define kStylisticAltSixOnSelector		12
   272 #define kStylisticAltSixteenOffSelector		33
   273 #define kStylisticAltSixteenOnSelector		32
   274 #define kStylisticAltTenOffSelector		21
   275 #define kStylisticAltTenOnSelector		20
   276 #define kStylisticAltThirteenOffSelector	27
   277 #define kStylisticAltThirteenOnSelector		26
   278 #define kStylisticAltThreeOffSelector		7
   279 #define kStylisticAltThreeOnSelector		6
   280 #define kStylisticAltTwelveOffSelector		25
   281 #define kStylisticAltTwelveOnSelector		24
   282 #define kStylisticAltTwentyOffSelector		41
   283 #define kStylisticAltTwentyOnSelector		40
   284 #define kStylisticAltTwoOffSelector		5
   285 #define kStylisticAltTwoOnSelector		4
   286 #define kStylisticAlternativesType		35
   287 #define kSwashAlternatesOffSelector		3
   288 #define kSwashAlternatesOnSelector		2
   289 #define kThirdWidthTextSelector			3
   290 #define kTraditionalNamesCharactersSelector	14
   291 #define kUpperCasePetiteCapsSelector		2
   292 #define kUpperCaseSmallCapsSelector		1
   293 #define kUpperCaseType				38
   295 /* Table data courtesy of Apple. */
   296 struct feature_mapping_t {
   297     FourCharCode otFeatureTag;
   298     uint16_t aatFeatureType;
   299     uint16_t selectorToEnable;
   300     uint16_t selectorToDisable;
   301 } feature_mappings[] = {
   302     { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
   303     { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
   304     { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
   305     { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
   306     { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
   307     { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
   308     { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
   309     { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
   310     { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
   311     { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
   312     { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
   313     { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
   314     { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
   315     { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
   316     { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
   317     { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
   318     { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
   319     { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
   320     { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
   321     { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
   322     { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
   323     { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
   324     { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
   325     { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
   326     { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
   327     { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
   328     { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
   329     { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
   330     { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
   331     { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
   332     { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
   333     { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
   334     { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
   335     { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
   336     { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
   337     { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
   338     { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
   339     { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
   340     { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
   341     { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
   342     { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
   343     { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
   344     { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
   345     { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
   346     { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
   347     { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
   348     { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
   349     { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
   350     { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
   351     { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
   352     { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
   353     { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
   354     { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
   355     { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
   356     { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
   357     { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
   358     { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
   359     { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
   360     { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
   361     { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
   362     { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
   363     { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
   364     { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
   365     { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
   366     { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
   367     { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
   368     { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
   369     { 'unic',   kLetterCaseType,            14,                                     15 },
   370     { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
   371     { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
   372     { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
   373     { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
   374     { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
   375     { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
   376     { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
   377 };
   379 static int
   380 _hb_feature_mapping_cmp (const void *key_, const void *entry_)
   381 {
   382   unsigned int key = * (unsigned int *) key_;
   383   const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
   384   return key < entry->otFeatureTag ? -1 :
   385 	 key > entry->otFeatureTag ? 1 :
   386 	 0;
   387 }
   389 hb_bool_t
   390 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
   391 		    hb_font_t          *font,
   392                     hb_buffer_t        *buffer,
   393                     const hb_feature_t *features,
   394                     unsigned int        num_features)
   395 {
   396   hb_face_t *face = font->face;
   397   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   398   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
   400   /*
   401    * Set up features.
   402    * (copied + modified from code from hb-uniscribe.cc)
   403    */
   404   hb_auto_array_t<feature_record_t> feature_records;
   405   hb_auto_array_t<range_record_t> range_records;
   406   if (num_features)
   407   {
   408     /* Sort features by start/end events. */
   409     hb_auto_array_t<feature_event_t> feature_events;
   410     for (unsigned int i = 0; i < num_features; i++)
   411     {
   412       const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
   413 									       feature_mappings,
   414 									       ARRAY_LENGTH (feature_mappings),
   415 									       sizeof (feature_mappings[0]),
   416 									       _hb_feature_mapping_cmp);
   417       if (!mapping)
   418         continue;
   420       active_feature_t feature;
   421       feature.rec.feature = mapping->aatFeatureType;
   422       feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
   423       feature.order = i;
   425       feature_event_t *event;
   427       event = feature_events.push ();
   428       if (unlikely (!event))
   429 	goto fail_features;
   430       event->index = features[i].start;
   431       event->start = true;
   432       event->feature = feature;
   434       event = feature_events.push ();
   435       if (unlikely (!event))
   436 	goto fail_features;
   437       event->index = features[i].end;
   438       event->start = false;
   439       event->feature = feature;
   440     }
   441     feature_events.sort ();
   442     /* Add a strategic final event. */
   443     {
   444       active_feature_t feature;
   445       feature.rec.feature = HB_TAG_NONE;
   446       feature.rec.setting = 0;
   447       feature.order = num_features + 1;
   449       feature_event_t *event = feature_events.push ();
   450       if (unlikely (!event))
   451 	goto fail_features;
   452       event->index = 0; /* This value does magic. */
   453       event->start = false;
   454       event->feature = feature;
   455     }
   457     /* Scan events and save features for each range. */
   458     hb_auto_array_t<active_feature_t> active_features;
   459     unsigned int last_index = 0;
   460     for (unsigned int i = 0; i < feature_events.len; i++)
   461     {
   462       feature_event_t *event = &feature_events[i];
   464       if (event->index != last_index)
   465       {
   466         /* Save a snapshot of active features and the range. */
   467 	range_record_t *range = range_records.push ();
   468 	if (unlikely (!range))
   469 	  goto fail_features;
   471 	unsigned int offset = feature_records.len;
   473 	if (active_features.len)
   474 	{
   475 	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
   477 	  /* TODO sort and resolve conflicting features? */
   478 	  /* active_features.sort (); */
   479 	  for (unsigned int j = 0; j < active_features.len; j++)
   480 	  {
   481 	    CFStringRef keys[2] = {
   482 	      kCTFontFeatureTypeIdentifierKey,
   483 	      kCTFontFeatureSelectorIdentifierKey
   484 	    };
   485 	    CFNumberRef values[2] = {
   486 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
   487 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
   488 	    };
   489 	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
   490 						       (const void **) keys,
   491 						       (const void **) values,
   492 						       2,
   493 						       &kCFTypeDictionaryKeyCallBacks,
   494 						       &kCFTypeDictionaryValueCallBacks);
   495 	    CFRelease (values[0]);
   496 	    CFRelease (values[1]);
   498 	    CFArrayAppendValue (features_array, dict);
   499 	    CFRelease (dict);
   501 	  }
   503 	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
   504 							   (const void **) &kCTFontFeatureSettingsAttribute,
   505 							   (const void **) &features_array,
   506 							   1,
   507 							   &kCFTypeDictionaryKeyCallBacks,
   508 							   &kCFTypeDictionaryValueCallBacks);
   509 	  CFRelease (features_array);
   511 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
   512 	  CFRelease (attributes);
   514 	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
   516 	  CFRelease (font_desc);
   517 	}
   518 	else
   519 	{
   520 	  range->font = NULL;
   521 	}
   523 	range->index_first = last_index;
   524 	range->index_last  = event->index - 1;
   526 	last_index = event->index;
   527       }
   529       if (event->start) {
   530         active_feature_t *feature = active_features.push ();
   531 	if (unlikely (!feature))
   532 	  goto fail_features;
   533 	*feature = event->feature;
   534       } else {
   535         active_feature_t *feature = active_features.find (&event->feature);
   536 	if (feature)
   537 	  active_features.remove (feature - active_features.array);
   538       }
   539     }
   541     if (!range_records.len) /* No active feature found. */
   542       goto fail_features;
   543   }
   544   else
   545   {
   546   fail_features:
   547     num_features = 0;
   548   }
   550 #define FAIL(...) \
   551   HB_STMT_START { \
   552     DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
   553     return false; \
   554   } HB_STMT_END;
   556   unsigned int scratch_size;
   557   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
   559 #define ALLOCATE_ARRAY(Type, name, len) \
   560   Type *name = (Type *) scratch; \
   561   { \
   562     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
   563     assert (_consumed <= scratch_size); \
   564     scratch += _consumed; \
   565     scratch_size -= _consumed; \
   566   }
   568 #define utf16_index() var1.u32
   570   ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
   572   unsigned int chars_len = 0;
   573   for (unsigned int i = 0; i < buffer->len; i++) {
   574     hb_codepoint_t c = buffer->info[i].codepoint;
   575     buffer->info[i].utf16_index() = chars_len;
   576     if (likely (c < 0x10000))
   577       pchars[chars_len++] = c;
   578     else if (unlikely (c >= 0x110000))
   579       pchars[chars_len++] = 0xFFFD;
   580     else {
   581       pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
   582       pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
   583     }
   584   }
   586 #undef utf16_index
   588   CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
   589                                                                pchars, chars_len,
   590                                                                kCFAllocatorNull);
   592   CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
   593   CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
   594   CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
   595 				  kCTFontAttributeName, font_data->ct_font);
   597   if (num_features)
   598   {
   599     ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
   601     /* Need log_clusters to assign features. */
   602     chars_len = 0;
   603     for (unsigned int i = 0; i < buffer->len; i++)
   604     {
   605       hb_codepoint_t c = buffer->info[i].codepoint;
   606       unsigned int cluster = buffer->info[i].cluster;
   607       log_clusters[chars_len++] = cluster;
   608       if (c >= 0x10000 && c < 0x110000)
   609 	log_clusters[chars_len++] = cluster; /* Surrogates. */
   610     }
   612     unsigned int start = 0;
   613     range_record_t *last_range = &range_records[0];
   614     for (unsigned int k = 0; k < chars_len; k++)
   615     {
   616       range_record_t *range = last_range;
   617       while (log_clusters[k] < range->index_first)
   618 	range--;
   619       while (log_clusters[k] > range->index_last)
   620 	range++;
   621       if (range != last_range)
   622       {
   623         if (last_range->font)
   624 	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
   625 					  kCTFontAttributeName, last_range->font);
   627 	start = k;
   628       }
   630       last_range = range;
   631     }
   632     if (start != chars_len && last_range->font)
   633       CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
   634 				      kCTFontAttributeName, last_range->font);
   636     for (unsigned int i = 0; i < range_records.len; i++)
   637       if (range_records[i].font)
   638 	CFRelease (range_records[i].font);
   639   }
   641   CTLineRef line = CTLineCreateWithAttributedString (attr_string);
   642   CFRelease (attr_string);
   644   CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
   645   unsigned int num_runs = CFArrayGetCount (glyph_runs);
   647   buffer->len = 0;
   649   const CFRange range_all = CFRangeMake (0, 0);
   651   for (unsigned int i = 0; i < num_runs; i++)
   652   {
   653     CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
   655     /* CoreText does automatic font fallback (AKA "cascading") for  characters
   656      * not supported by the requested font, and provides no way to turn it off,
   657      * so we detect if the returned run uses a font other than the requested
   658      * one and fill in the buffer with .notdef glyphs instead of random glyph
   659      * indices from a different font.
   660      */
   661     CFDictionaryRef attributes = CTRunGetAttributes (run);
   662     CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
   663     CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
   664     if (!CFEqual (run_cg_font, face_data->cg_font))
   665     {
   666         CFRelease (run_cg_font);
   668 	CFRange range = CTRunGetStringRange (run);
   669 	buffer->ensure (buffer->len + range.length);
   670 	if (buffer->in_error)
   671 	  FAIL ("Buffer resize failed");
   672 	hb_glyph_info_t *info = buffer->info + buffer->len;
   674 	CGGlyph notdef = 0;
   675 	double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
   677         for (CFIndex j = range.location; j < range.location + range.length; j++)
   678 	{
   679 	    UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
   680 	    if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
   681 	    {
   682 	      ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
   683 	      if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
   684 	        /* This is the second of a surrogate pair.  Don't need .notdef
   685 		 * for this one. */
   686 	        continue;
   687 	    }
   689             info->codepoint = notdef;
   690 	    /* TODO We have to fixup clusters later.  See vis_clusters in
   691 	     * hb-uniscribe.cc for example. */
   692             info->cluster = j;
   694             info->mask = advance;
   695             info->var1.u32 = 0;
   696             info->var2.u32 = 0;
   698 	    info++;
   699 	    buffer->len++;
   700         }
   701         continue;
   702     }
   703     CFRelease (run_cg_font);
   705     unsigned int num_glyphs = CTRunGetGlyphCount (run);
   706     if (num_glyphs == 0)
   707       continue;
   709     buffer->ensure (buffer->len + num_glyphs);
   711     scratch = buffer->get_scratch_buffer (&scratch_size);
   713     /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
   714      * succeed, and so copying data to our own buffer will be rare. */
   716     const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
   717     if (!glyphs) {
   718       ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
   719       CTRunGetGlyphs (run, range_all, glyph_buf);
   720       glyphs = glyph_buf;
   721     }
   723     const CGPoint* positions = CTRunGetPositionsPtr (run);
   724     if (!positions) {
   725       ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
   726       CTRunGetPositions (run, range_all, position_buf);
   727       positions = position_buf;
   728     }
   730     const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
   731     if (!string_indices) {
   732       ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
   733       CTRunGetStringIndices (run, range_all, index_buf);
   734       string_indices = index_buf;
   735     }
   737 #undef ALLOCATE_ARRAY
   739     double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
   741     for (unsigned int j = 0; j < num_glyphs; j++) {
   742       double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
   744       hb_glyph_info_t *info = &buffer->info[buffer->len];
   746       info->codepoint = glyphs[j];
   747       info->cluster = string_indices[j];
   749       /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
   750       info->mask = advance;
   751       info->var1.u32 = 0;
   752       info->var2.u32 = positions[j].y;
   754       buffer->len++;
   755     }
   756   }
   758   buffer->clear_positions ();
   760   unsigned int count = buffer->len;
   761   for (unsigned int i = 0; i < count; ++i) {
   762     hb_glyph_info_t *info = &buffer->info[i];
   763     hb_glyph_position_t *pos = &buffer->pos[i];
   765     /* TODO vertical */
   766     pos->x_advance = info->mask;
   767     pos->x_offset = info->var1.u32;
   768     pos->y_offset = info->var2.u32;
   769   }
   771   /* Fix up clusters so that we never return out-of-order indices;
   772    * if core text has reordered glyphs, we'll merge them to the
   773    * beginning of the reordered cluster.
   774    *
   775    * This does *not* mean we'll form the same clusters as Uniscribe
   776    * or the native OT backend, only that the cluster indices will be
   777    * monotonic in the output buffer. */
   778   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
   779     unsigned int prev_cluster = 0;
   780     for (unsigned int i = 0; i < count; i++) {
   781       unsigned int curr_cluster = buffer->info[i].cluster;
   782       if (curr_cluster < prev_cluster) {
   783         for (unsigned int j = i; j > 0; j--) {
   784           if (buffer->info[j - 1].cluster > curr_cluster)
   785             buffer->info[j - 1].cluster = curr_cluster;
   786           else
   787             break;
   788         }
   789       }
   790       prev_cluster = curr_cluster;
   791     }
   792   } else {
   793     unsigned int prev_cluster = (unsigned int)-1;
   794     for (unsigned int i = 0; i < count; i++) {
   795       unsigned int curr_cluster = buffer->info[i].cluster;
   796       if (curr_cluster > prev_cluster) {
   797         for (unsigned int j = i; j > 0; j--) {
   798           if (buffer->info[j - 1].cluster < curr_cluster)
   799             buffer->info[j - 1].cluster = curr_cluster;
   800           else
   801             break;
   802         }
   803       }
   804       prev_cluster = curr_cluster;
   805     }
   806   }
   808   CFRelease (string_ref);
   809   CFRelease (line);
   811   return true;
   812 }

mercurial