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-ot-cff2-table.hh"
  28 #include "hb-cff2-interp-cs.hh"
  29 
  30 using namespace CFF;
  31 
  32 struct extents_param_t
  33 {
  34   void init ()
  35   {
  36     path_open = false;
  37     min_x.set_int (0x7FFFFFFF);
  38     min_y.set_int (0x7FFFFFFF);
  39     max_x.set_int (-0x80000000);
  40     max_y.set_int (-0x80000000);
  41   }
  42 
  43   void start_path ()         { path_open = true; }
  44   void end_path ()           { path_open = false; }
  45   bool is_path_open () const { return path_open; }
  46 
  47   void update_bounds (const point_t &pt)
  48   {
  49     if (pt.x < min_x) min_x = pt.x;
  50     if (pt.x > max_x) max_x = pt.x;
  51     if (pt.y < min_y) min_y = pt.y;
  52     if (pt.y > max_y) max_y = pt.y;
  53   }
  54 
  55   bool  path_open;
  56   number_t min_x;
  57   number_t min_y;
  58   number_t max_x;
  59   number_t max_y;
  60 };
  61 
  62 struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, extents_param_t>
  63 {
  64   static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
  65   {
  66     param.end_path ();
  67     env.moveto (pt);
  68   }
  69 
  70   static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
  71   {
  72     if (!param.is_path_open ())
  73     {
  74       param.start_path ();
  75       param.update_bounds (env.get_pt ());
  76     }
  77     env.moveto (pt1);
  78     param.update_bounds (env.get_pt ());
  79   }
  80 
  81   static void curve (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
  82   {
  83     if (!param.is_path_open ())
  84     {
  85       param.start_path ();
  86       param.update_bounds (env.get_pt ());
  87     }
  88     /* include control points */
  89     param.update_bounds (pt1);
  90     param.update_bounds (pt2);
  91     env.moveto (pt3);
  92     param.update_bounds (env.get_pt ());
  93   }
  94 };
  95 
  96 struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, extents_param_t, cff2_path_procs_extents_t> {};
  97 
  98 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
  99                                            hb_codepoint_t glyph,
 100                                            hb_glyph_extents_t *extents) const
 101 {
 102   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 103 
 104   unsigned int num_coords;
 105   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
 106   unsigned int fd = fdSelect->get_fd (glyph);
 107   cff2_cs_interpreter_t<cff2_cs_opset_extents_t, extents_param_t> interp;
 108   const byte_str_t str = (*charStrings)[glyph];
 109   interp.env.init (str, *this, fd, coords, num_coords);
 110   extents_param_t  param;
 111   param.init ();
 112   if (unlikely (!interp.interpret (param))) return false;
 113 
 114   if (param.min_x >= param.max_x)
 115   {
 116     extents->width = 0;
 117     extents->x_bearing = 0;
 118   }
 119   else
 120   {
 121     extents->x_bearing = (int32_t)param.min_x.floor ();
 122     extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing;
 123   }
 124   if (param.min_y >= param.max_y)
 125   {
 126     extents->height = 0;
 127     extents->y_bearing = 0;
 128   }
 129   else
 130   {
 131     extents->y_bearing = (int32_t)param.max_y.ceil ();
 132     extents->height = (int32_t)param.min_y.floor () - extents->y_bearing;
 133   }
 134 
 135   return true;
 136 }