/* * Copyright © 2018 Adobe Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Adobe Author(s): Michiharu Ariza */ #include "hb-ot-cff2-table.hh" #include "hb-cff2-interp-cs.hh" using namespace CFF; struct ExtentsParam { void init () { path_open = false; min_x.set_int (0x7FFFFFFF); min_y.set_int (0x7FFFFFFF); max_x.set_int (-0x80000000); max_y.set_int (-0x80000000); } void start_path () { path_open = true; } void end_path () { path_open = false; } bool is_path_open () const { return path_open; } void update_bounds (const Point &pt) { if (pt.x < min_x) min_x = pt.x; if (pt.x > max_x) max_x = pt.x; if (pt.y < min_y) min_y = pt.y; if (pt.y > max_y) max_y = pt.y; } bool path_open; Number min_x; Number min_y; Number max_x; Number max_y; }; struct CFF2PathProcs_Extents : PathProcs<CFF2PathProcs_Extents, CFF2CSInterpEnv, ExtentsParam> { static void moveto (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt) { param.end_path (); env.moveto (pt); } static void line (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1) { if (!param.is_path_open ()) { param.start_path (); param.update_bounds (env.get_pt ()); } env.moveto (pt1); param.update_bounds (env.get_pt ()); } static void curve (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1, const Point &pt2, const Point &pt3) { if (!param.is_path_open ()) { param.start_path (); param.update_bounds (env.get_pt ()); } /* include control points */ param.update_bounds (pt1); param.update_bounds (pt2); env.moveto (pt3); param.update_bounds (env.get_pt ()); } }; struct CFF2CSOpSet_Extents : CFF2CSOpSet<CFF2CSOpSet_Extents, ExtentsParam, CFF2PathProcs_Extents> {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int num_coords; const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); unsigned int fd = fdSelect->get_fd (glyph); CFF2CSInterpreter<CFF2CSOpSet_Extents, ExtentsParam> interp; const ByteStr str = (*charStrings)[glyph]; interp.env.init (str, *this, fd, coords, num_coords); ExtentsParam param; param.init (); if (unlikely (!interp.interpret (param))) return false; if (param.min_x >= param.max_x) { extents->width = 0; extents->x_bearing = 0; } else { extents->x_bearing = (int32_t)param.min_x.floor (); extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; } if (param.min_y >= param.max_y) { extents->height = 0; extents->y_bearing = 0; } else { extents->y_bearing = (int32_t)param.max_y.ceil (); extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; } return true; }