| 1 | /* | 
|---|
| 2 | * Copyright © 2018 Adobe Inc. | 
|---|
| 3 | * | 
|---|
| 4 | *  This is part of HarfBuzz, a text shaping library. | 
|---|
| 5 | * | 
|---|
| 6 | * Permission is hereby granted, without written agreement and without | 
|---|
| 7 | * license or royalty fees, to use, copy, modify, and distribute this | 
|---|
| 8 | * software and its documentation for any purpose, provided that the | 
|---|
| 9 | * above copyright notice and the following two paragraphs appear in | 
|---|
| 10 | * all copies of this software. | 
|---|
| 11 | * | 
|---|
| 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 
|---|
| 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 
|---|
| 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 
|---|
| 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 
|---|
| 16 | * DAMAGE. | 
|---|
| 17 | * | 
|---|
| 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 
|---|
| 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
|---|
| 20 | * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS | 
|---|
| 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 
|---|
| 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 
|---|
| 23 | * | 
|---|
| 24 | * Adobe Author(s): Michiharu Ariza | 
|---|
| 25 | */ | 
|---|
| 26 |  | 
|---|
| 27 | #include "hb.hh" | 
|---|
| 28 |  | 
|---|
| 29 | #ifndef HB_NO_CFF | 
|---|
| 30 |  | 
|---|
| 31 | #include "hb-ot-cff1-table.hh" | 
|---|
| 32 | #include "hb-cff1-interp-cs.hh" | 
|---|
| 33 |  | 
|---|
| 34 | using namespace CFF; | 
|---|
| 35 |  | 
|---|
| 36 | /* SID to code */ | 
|---|
| 37 | static const uint8_t standard_encoding_to_code [] = | 
|---|
| 38 | { | 
|---|
| 39 | 0,   32,   33,   34,   35,   36,   37,   38,  39,   40,   41,   42,   43,   44,   45,   46, | 
|---|
| 40 | 47,   48,   49,   50,   51,   52,   53,   54,  55,   56,   57,   58,   59,   60,   61,   62, | 
|---|
| 41 | 63,   64,   65,   66,   67,   68,   69,   70,  71,   72,   73,   74,   75,   76,   77,   78, | 
|---|
| 42 | 79,   80,   81,   82,   83,   84,   85,   86,  87,   88,   89,   90,   91,   92,   93,   94, | 
|---|
| 43 | 95,   96,   97,   98,   99,  100,  101,  102, 103,  104,  105,  106,  107,  108,  109,  110, | 
|---|
| 44 | 111,  112,  113,  114,  115,  116,  117,  118, 119,  120,  121,  122,  123,  124,  125,  126, | 
|---|
| 45 | 161,  162,  163,  164,  165,  166,  167,  168, 169,  170,  171,  172,  173,  174,  175,  177, | 
|---|
| 46 | 178,  179,  180,  182,  183,  184,  185,  186, 187,  188,  189,  191,  193,  194,  195,  196, | 
|---|
| 47 | 197,  198,  199,  200,  202,  203,  205,  206, 207,  208,  225,  227,  232,  233,  234,  235, | 
|---|
| 48 | 241,  245,  248,  249,  250,  251 | 
|---|
| 49 | }; | 
|---|
| 50 |  | 
|---|
| 51 | /* SID to code */ | 
|---|
| 52 | static const uint8_t expert_encoding_to_code [] = | 
|---|
| 53 | { | 
|---|
| 54 | 0,   32,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   44,   45,   46, | 
|---|
| 55 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   58,   59,    0,    0,    0, | 
|---|
| 56 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 57 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 58 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 59 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 60 | 0,    0,    0,   47,    0,    0,    0,    0,    0,    0,    0,    0,    0,   87,   88,    0, | 
|---|
| 61 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 62 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 63 | 0,    0,    0,    0,    0,    0,  201,    0,    0,    0,    0,  189,    0,    0,  188,    0, | 
|---|
| 64 | 0,    0,    0,  190,  202,    0,    0,    0,    0,  203,    0,    0,    0,    0,    0,    0, | 
|---|
| 65 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 66 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 67 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 68 | 0,    0,    0,    0,    0,   33,   34,   36,   37,   38,   39,   40,   41,   42,   43,   48, | 
|---|
| 69 | 49,   50,   51,   52,   53,   54,   55,   56,   57,   60,   61,   62,   63,   65,   66,   67, | 
|---|
| 70 | 68,   69,   73,   76,   77,   78,   79,   82,   83,   84,   86,   89,   90,   91,   93,   94, | 
|---|
| 71 | 95,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110, | 
|---|
| 72 | 111,  112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126, | 
|---|
| 73 | 161,  162,  163,  166,  167,  168,  169,  170,  172,  175,  178,  179,  182,  183,  184,  191, | 
|---|
| 74 | 192,  193,  194,  195,  196,  197,  200,  204,  205,  206,  207,  208,  209,  210,  211,  212, | 
|---|
| 75 | 213,  214,  215,  216,  217,  218,  219,  220,  221,  222,  223,  224,  225,  226,  227,  228, | 
|---|
| 76 | 229,  230,  231,  232,  233,  234,  235,  236,  237,  238,  239,  240,  241,  242,  243,  244, | 
|---|
| 77 | 245,  246,  247,  248,  249,  250,  251,  252,  253,  254,  255 | 
|---|
| 78 | }; | 
|---|
| 79 |  | 
|---|
| 80 | /* glyph ID to SID */ | 
|---|
| 81 | static const uint16_t expert_charset_to_sid [] = | 
|---|
| 82 | { | 
|---|
| 83 | 0,    1,  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,   13,   14,   15,   99, | 
|---|
| 84 | 239,  240,  241,  242,  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  252, | 
|---|
| 85 | 253,  254,  255,  256,  257,  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110, | 
|---|
| 86 | 267,  268,  269,  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,  280,  281,  282, | 
|---|
| 87 | 283,  284,  285,  286,  287,  288,  289,  290,  291,  292,  293,  294,  295,  296,  297,  298, | 
|---|
| 88 | 299,  300,  301,  302,  303,  304,  305,  306,  307,  308,  309,  310,  311,  312,  313,  314, | 
|---|
| 89 | 315,  316,  317,  318,  158,  155,  163,  319,  320,  321,  322,  323,  324,  325,  326,  150, | 
|---|
| 90 | 164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,  340, | 
|---|
| 91 | 341,  342,  343,  344,  345,  346,  347,  348,  349,  350,  351,  352,  353,  354,  355,  356, | 
|---|
| 92 | 357,  358,  359,  360,  361,  362,  363,  364,  365,  366,  367,  368,  369,  370,  371,  372, | 
|---|
| 93 | 373,  374,  375,  376,  377,  378 | 
|---|
| 94 | }; | 
|---|
| 95 |  | 
|---|
| 96 | /* glyph ID to SID */ | 
|---|
| 97 | static const uint16_t expert_subset_charset_to_sid [] = | 
|---|
| 98 | { | 
|---|
| 99 | 0,    1,  231,  232,  235,  236,  237,  238,   13,   14,   15,   99,  239,  240,  241,  242, | 
|---|
| 100 | 243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  253,  254,  255,  256,  257, | 
|---|
| 101 | 258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,  267,  268,  269,  270,  272, | 
|---|
| 102 | 300,  301,  302,  305,  314,  315,  158,  155,  163,  320,  321,  322,  323,  324,  325,  326, | 
|---|
| 103 | 150,  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339, | 
|---|
| 104 | 340,  341,  342,  343,  344,  345,  346 | 
|---|
| 105 | }; | 
|---|
| 106 |  | 
|---|
| 107 | /* code to SID */ | 
|---|
| 108 | static const uint8_t standard_encoding_to_sid [] = | 
|---|
| 109 | { | 
|---|
| 110 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 111 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 112 | 1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16, | 
|---|
| 113 | 17,  18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32, | 
|---|
| 114 | 33,  34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48, | 
|---|
| 115 | 49,  50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64, | 
|---|
| 116 | 65,  66,   67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80, | 
|---|
| 117 | 81,  82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,    0, | 
|---|
| 118 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 119 | 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 120 | 0,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110, | 
|---|
| 121 | 0,  111,  112,  113,  114,    0,  115,  116,  117,  118,  119,  120,  121,  122,    0,  123, | 
|---|
| 122 | 0,  124,  125,  126,  127,  128,  129,  130,  131,    0,  132,  133,    0,  134,  135,  136, | 
|---|
| 123 | 137,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, | 
|---|
| 124 | 0,   138,   0,  139,    0,    0,    0,    0,  140,  141,  142,  143,    0,    0,    0,    0, | 
|---|
| 125 | 0,   144,   0,    0,    0,  145,    0,    0,  146,  147,  148,  149,    0,    0,    0,    0 | 
|---|
| 126 | }; | 
|---|
| 127 |  | 
|---|
| 128 | hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid) | 
|---|
| 129 | { | 
|---|
| 130 | if (sid < ARRAY_LENGTH (standard_encoding_to_code)) | 
|---|
| 131 | return (hb_codepoint_t)standard_encoding_to_code[sid]; | 
|---|
| 132 | else | 
|---|
| 133 | return 0; | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid) | 
|---|
| 137 | { | 
|---|
| 138 | if (sid < ARRAY_LENGTH (expert_encoding_to_code)) | 
|---|
| 139 | return (hb_codepoint_t)expert_encoding_to_code[sid]; | 
|---|
| 140 | else | 
|---|
| 141 | return 0; | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph) | 
|---|
| 145 | { | 
|---|
| 146 | if (glyph < ARRAY_LENGTH (expert_charset_to_sid)) | 
|---|
| 147 | return (hb_codepoint_t)expert_charset_to_sid[glyph]; | 
|---|
| 148 | else | 
|---|
| 149 | return 0; | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph) | 
|---|
| 153 | { | 
|---|
| 154 | if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid)) | 
|---|
| 155 | return (hb_codepoint_t)expert_subset_charset_to_sid[glyph]; | 
|---|
| 156 | else | 
|---|
| 157 | return 0; | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code) | 
|---|
| 161 | { | 
|---|
| 162 | if (code < ARRAY_LENGTH (standard_encoding_to_sid)) | 
|---|
| 163 | return (hb_codepoint_t)standard_encoding_to_sid[code]; | 
|---|
| 164 | else | 
|---|
| 165 | return CFF_UNDEF_SID; | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | struct bounds_t | 
|---|
| 169 | { | 
|---|
| 170 | void init () | 
|---|
| 171 | { | 
|---|
| 172 | min.set_int (INT_MAX, INT_MAX); | 
|---|
| 173 | max.set_int (INT_MIN, INT_MIN); | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | void update (const point_t &pt) | 
|---|
| 177 | { | 
|---|
| 178 | if (pt.x < min.x) min.x = pt.x; | 
|---|
| 179 | if (pt.x > max.x) max.x = pt.x; | 
|---|
| 180 | if (pt.y < min.y) min.y = pt.y; | 
|---|
| 181 | if (pt.y > max.y) max.y = pt.y; | 
|---|
| 182 | } | 
|---|
| 183 |  | 
|---|
| 184 | void merge (const bounds_t &b) | 
|---|
| 185 | { | 
|---|
| 186 | if (empty ()) | 
|---|
| 187 | *this = b; | 
|---|
| 188 | else if (!b.empty ()) | 
|---|
| 189 | { | 
|---|
| 190 | if (b.min.x < min.x) min.x = b.min.x; | 
|---|
| 191 | if (b.max.x > max.x) max.x = b.max.x; | 
|---|
| 192 | if (b.min.y < min.y) min.y = b.min.y; | 
|---|
| 193 | if (b.max.y > max.y) max.y = b.max.y; | 
|---|
| 194 | } | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | void offset (const point_t &delta) | 
|---|
| 198 | { | 
|---|
| 199 | if (!empty ()) | 
|---|
| 200 | { | 
|---|
| 201 | min.move (delta); | 
|---|
| 202 | max.move (delta); | 
|---|
| 203 | } | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|
| 206 | bool empty () const { return (min.x >= max.x) || (min.y >= max.y); } | 
|---|
| 207 |  | 
|---|
| 208 | point_t min; | 
|---|
| 209 | point_t max; | 
|---|
| 210 | }; | 
|---|
| 211 |  | 
|---|
| 212 | struct cff1_extents_param_t | 
|---|
| 213 | { | 
|---|
| 214 | void init (const OT::cff1::accelerator_t *_cff) | 
|---|
| 215 | { | 
|---|
| 216 | path_open = false; | 
|---|
| 217 | cff = _cff; | 
|---|
| 218 | bounds.init (); | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 | void start_path   ()       { path_open = true; } | 
|---|
| 222 | void end_path     ()       { path_open = false; } | 
|---|
| 223 | bool is_path_open () const { return path_open; } | 
|---|
| 224 |  | 
|---|
| 225 | bool path_open; | 
|---|
| 226 | bounds_t bounds; | 
|---|
| 227 |  | 
|---|
| 228 | const OT::cff1::accelerator_t *cff; | 
|---|
| 229 | }; | 
|---|
| 230 |  | 
|---|
| 231 | struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t> | 
|---|
| 232 | { | 
|---|
| 233 | static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt) | 
|---|
| 234 | { | 
|---|
| 235 | param.end_path (); | 
|---|
| 236 | env.moveto (pt); | 
|---|
| 237 | } | 
|---|
| 238 |  | 
|---|
| 239 | static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1) | 
|---|
| 240 | { | 
|---|
| 241 | if (!param.is_path_open ()) | 
|---|
| 242 | { | 
|---|
| 243 | param.start_path (); | 
|---|
| 244 | param.bounds.update (env.get_pt ()); | 
|---|
| 245 | } | 
|---|
| 246 | env.moveto (pt1); | 
|---|
| 247 | param.bounds.update (env.get_pt ()); | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) | 
|---|
| 251 | { | 
|---|
| 252 | if (!param.is_path_open ()) | 
|---|
| 253 | { | 
|---|
| 254 | param.start_path (); | 
|---|
| 255 | param.bounds.update (env.get_pt ()); | 
|---|
| 256 | } | 
|---|
| 257 | /* include control points */ | 
|---|
| 258 | param.bounds.update (pt1); | 
|---|
| 259 | param.bounds.update (pt2); | 
|---|
| 260 | env.moveto (pt3); | 
|---|
| 261 | param.bounds.update (env.get_pt ()); | 
|---|
| 262 | } | 
|---|
| 263 | }; | 
|---|
| 264 |  | 
|---|
| 265 | static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false); | 
|---|
| 266 |  | 
|---|
| 267 | struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t> | 
|---|
| 268 | { | 
|---|
| 269 | static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param) | 
|---|
| 270 | { | 
|---|
| 271 | unsigned int  n = env.argStack.get_count (); | 
|---|
| 272 | point_t delta; | 
|---|
| 273 | delta.x = env.argStack[n-4]; | 
|---|
| 274 | delta.y = env.argStack[n-3]; | 
|---|
| 275 | hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ()); | 
|---|
| 276 | hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); | 
|---|
| 277 |  | 
|---|
| 278 | bounds_t  base_bounds, accent_bounds; | 
|---|
| 279 | if (likely (!env.in_seac && base && accent | 
|---|
| 280 | && _get_bounds (param.cff, base, base_bounds, true) | 
|---|
| 281 | && _get_bounds (param.cff, accent, accent_bounds, true))) | 
|---|
| 282 | { | 
|---|
| 283 | param.bounds.merge (base_bounds); | 
|---|
| 284 | accent_bounds.offset (delta); | 
|---|
| 285 | param.bounds.merge (accent_bounds); | 
|---|
| 286 | } | 
|---|
| 287 | else | 
|---|
| 288 | env.set_error (); | 
|---|
| 289 | } | 
|---|
| 290 | }; | 
|---|
| 291 |  | 
|---|
| 292 | bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac) | 
|---|
| 293 | { | 
|---|
| 294 | bounds.init (); | 
|---|
| 295 | if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; | 
|---|
| 296 |  | 
|---|
| 297 | unsigned int fd = cff->fdSelect->get_fd (glyph); | 
|---|
| 298 | cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp; | 
|---|
| 299 | const byte_str_t str = (*cff->charStrings)[glyph]; | 
|---|
| 300 | interp.env.init (str, *cff, fd); | 
|---|
| 301 | interp.env.set_in_seac (in_seac); | 
|---|
| 302 | cff1_extents_param_t  param; | 
|---|
| 303 | param.init (cff); | 
|---|
| 304 | if (unlikely (!interp.interpret (param))) return false; | 
|---|
| 305 | bounds = param.bounds; | 
|---|
| 306 | return true; | 
|---|
| 307 | } | 
|---|
| 308 |  | 
|---|
| 309 | bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const | 
|---|
| 310 | { | 
|---|
| 311 | #ifdef HB_NO_OT_FONT_CFF | 
|---|
| 312 | /* XXX Remove check when this code moves to .hh file. */ | 
|---|
| 313 | return true; | 
|---|
| 314 | #endif | 
|---|
| 315 |  | 
|---|
| 316 | bounds_t bounds; | 
|---|
| 317 |  | 
|---|
| 318 | if (!_get_bounds (this, glyph, bounds)) | 
|---|
| 319 | return false; | 
|---|
| 320 |  | 
|---|
| 321 | if (bounds.min.x >= bounds.max.x) | 
|---|
| 322 | { | 
|---|
| 323 | extents->width = 0; | 
|---|
| 324 | extents->x_bearing = 0; | 
|---|
| 325 | } | 
|---|
| 326 | else | 
|---|
| 327 | { | 
|---|
| 328 | extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); | 
|---|
| 329 | extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ()); | 
|---|
| 330 | } | 
|---|
| 331 | if (bounds.min.y >= bounds.max.y) | 
|---|
| 332 | { | 
|---|
| 333 | extents->height = 0; | 
|---|
| 334 | extents->y_bearing = 0; | 
|---|
| 335 | } | 
|---|
| 336 | else | 
|---|
| 337 | { | 
|---|
| 338 | extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); | 
|---|
| 339 | extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ()); | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | return true; | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | struct get_seac_param_t | 
|---|
| 346 | { | 
|---|
| 347 | void init (const OT::cff1::accelerator_t *_cff) | 
|---|
| 348 | { | 
|---|
| 349 | cff = _cff; | 
|---|
| 350 | base = 0; | 
|---|
| 351 | accent = 0; | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | bool has_seac () const { return base && accent; } | 
|---|
| 355 |  | 
|---|
| 356 | const OT::cff1::accelerator_t *cff; | 
|---|
| 357 | hb_codepoint_t  base; | 
|---|
| 358 | hb_codepoint_t  accent; | 
|---|
| 359 | }; | 
|---|
| 360 |  | 
|---|
| 361 | struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t> | 
|---|
| 362 | { | 
|---|
| 363 | static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param) | 
|---|
| 364 | { | 
|---|
| 365 | unsigned int  n = env.argStack.get_count (); | 
|---|
| 366 | hb_codepoint_t  base_char = (hb_codepoint_t)env.argStack[n-2].to_int (); | 
|---|
| 367 | hb_codepoint_t  accent_char = (hb_codepoint_t)env.argStack[n-1].to_int (); | 
|---|
| 368 |  | 
|---|
| 369 | param.base = param.cff->std_code_to_glyph (base_char); | 
|---|
| 370 | param.accent = param.cff->std_code_to_glyph (accent_char); | 
|---|
| 371 | } | 
|---|
| 372 | }; | 
|---|
| 373 |  | 
|---|
| 374 | bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const | 
|---|
| 375 | { | 
|---|
| 376 | if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; | 
|---|
| 377 |  | 
|---|
| 378 | unsigned int fd = fdSelect->get_fd (glyph); | 
|---|
| 379 | cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp; | 
|---|
| 380 | const byte_str_t str = (*charStrings)[glyph]; | 
|---|
| 381 | interp.env.init (str, *this, fd); | 
|---|
| 382 | get_seac_param_t  param; | 
|---|
| 383 | param.init (this); | 
|---|
| 384 | if (unlikely (!interp.interpret (param))) return false; | 
|---|
| 385 |  | 
|---|
| 386 | if (param.has_seac ()) | 
|---|
| 387 | { | 
|---|
| 388 | *base = param.base; | 
|---|
| 389 | *accent = param.accent; | 
|---|
| 390 | return true; | 
|---|
| 391 | } | 
|---|
| 392 | return false; | 
|---|
| 393 | } | 
|---|
| 394 |  | 
|---|
| 395 |  | 
|---|
| 396 | #endif | 
|---|
| 397 |  | 
|---|