Blame cairomm/fontface.cc

Packit 908522
/* Copyright (C) 2005 The cairomm Development Team
Packit 908522
 *
Packit 908522
 * This library is free software; you can redistribute it and/or
Packit 908522
 * modify it under the terms of the GNU Library General Public
Packit 908522
 * License as published by the Free Software Foundation; either
Packit 908522
 * version 2 of the License, or (at your option) any later version.
Packit 908522
 *
Packit 908522
 * This library is distributed in the hope that it will be useful,
Packit 908522
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 908522
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 908522
 * Library General Public License for more details.
Packit 908522
 *
Packit 908522
 * You should have received a copy of the GNU Library General Public
Packit 908522
 * License along with this library; if not, write to the Free Software
Packit 908522
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 908522
 * 02110-1301, USA.
Packit 908522
 */
Packit 908522
Packit 908522
#include <iostream>
Packit 908522
#include <cairomm/context.h>
Packit 908522
#include <cairomm/fontface.h>
Packit 908522
#include <cairomm/scaledfont.h>
Packit 908522
#include <cairomm/private.h>
Packit 908522
Packit 908522
namespace
Packit 908522
{
Packit 908522
Packit 908522
static const cairo_user_data_key_t USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS =  {0};
Packit 908522
Packit 908522
} // anonymous namespace
Packit 908522
Packit 908522
namespace Cairo
Packit 908522
{
Packit 908522
Packit 908522
FontFace::FontFace(cairo_font_face_t* cobject, bool has_reference)
Packit 908522
: m_cobject(nullptr)
Packit 908522
{
Packit 908522
  if(has_reference)
Packit 908522
    m_cobject = cobject;
Packit 908522
  else
Packit 908522
    m_cobject = cairo_font_face_reference(cobject);
Packit 908522
}
Packit 908522
Packit 908522
FontFace::~FontFace()
Packit 908522
{
Packit 908522
  if(m_cobject)
Packit 908522
    cairo_font_face_destroy(m_cobject);
Packit 908522
}
Packit 908522
Packit 908522
void FontFace::reference() const
Packit 908522
{
Packit 908522
 cairo_font_face_reference(m_cobject);
Packit 908522
}
Packit 908522
Packit 908522
void FontFace::unreference() const
Packit 908522
{
Packit 908522
  cairo_font_face_destroy(m_cobject);
Packit 908522
}
Packit 908522
Packit 908522
/*
Packit 908522
void* FontFace::get_user_data(const cairo_user_data_key_t *key)
Packit 908522
{
Packit 908522
  auto result = cairo_font_face_get_user_data(m_cobject, key);
Packit 908522
  check_object_status_and_throw_exception(*this);
Packit 908522
  return result;
Packit 908522
}
Packit 908522
Packit 908522
void FontFace::set_user_data(const cairo_user_data_key_t* key, void *user_data, cairo_destroy_func_t destroy)
Packit 908522
{
Packit 908522
  const auto status = (ErrorStatus)cairo_font_face_set_user_data(m_cobject, key, user_data, destroy);
Packit 908522
  check_status_and_throw_exception(status);
Packit 908522
}
Packit 908522
*/
Packit 908522
Packit 908522
FontType FontFace::get_type() const
Packit 908522
{
Packit 908522
  auto font_type = cairo_font_face_get_type(m_cobject);
Packit 908522
  check_object_status_and_throw_exception(*this);
Packit 908522
  return static_cast<FontType>(font_type);
Packit 908522
}
Packit 908522
Packit 908522
// 'Toy' fonts
Packit 908522
RefPtr<ToyFontFace>
Packit 908522
ToyFontFace::create(const std::string& family, FontSlant slant, FontWeight weight)
Packit 908522
{
Packit 908522
  return RefPtr<ToyFontFace>(new ToyFontFace(family, slant, weight));
Packit 908522
}
Packit 908522
Packit 908522
ToyFontFace::ToyFontFace(const std::string& family, FontSlant slant, FontWeight weight) :
Packit 908522
  FontFace(cairo_toy_font_face_create (family.c_str(),
Packit 908522
                                       static_cast<cairo_font_slant_t>(slant),
Packit 908522
           	                            static_cast<cairo_font_weight_t>(weight)),
Packit 908522
           true /* has reference*/)
Packit 908522
{
Packit 908522
  check_status_and_throw_exception(cairo_font_face_status(m_cobject));
Packit 908522
}
Packit 908522
Packit 908522
std::string ToyFontFace::get_family() const
Packit 908522
{
Packit 908522
  return std::string(cairo_toy_font_face_get_family(m_cobject));
Packit 908522
}
Packit 908522
Packit 908522
FontSlant ToyFontFace::get_slant() const
Packit 908522
{
Packit 908522
  return FontSlant(cairo_toy_font_face_get_slant(m_cobject));
Packit 908522
}
Packit 908522
Packit 908522
FontWeight ToyFontFace::get_weight() const
Packit 908522
{
Packit 908522
  return FontWeight(cairo_toy_font_face_get_weight(m_cobject));
Packit 908522
}
Packit 908522
Packit 908522
Packit 908522
//*************************//
Packit 908522
// UserFont Implementation //
Packit 908522
//*************************//
Packit 908522
Packit 908522
static const cairo_user_data_key_t user_font_key = {0};
Packit 908522
Packit 908522
static void
Packit 908522
log_uncaught_exception(const char* message = 0)
Packit 908522
{
Packit 908522
  std::cerr << "*** cairomm: Uncaught exception in UserFont callback";
Packit 908522
  if(message)
Packit 908522
    std::cerr << ": " << message;
Packit 908522
Packit 908522
  std::cerr << std::endl;
Packit 908522
}
Packit 908522
Packit 908522
cairo_status_t
Packit 908522
UserFontFace::init_cb(cairo_scaled_font_t* scaled_font,
Packit 908522
                      cairo_t *cr,
Packit 908522
                      cairo_font_extents_t* metrics)
Packit 908522
{
Packit 908522
  auto face = cairo_scaled_font_get_font_face(scaled_font);
Packit 908522
  // we've stored a pointer to the wrapper object in the C object's user_data
Packit 908522
  auto instance =
Packit 908522
    static_cast<UserFontFace*>(cairo_font_face_get_user_data(face,
Packit 908522
                                                             &user_font_key));
Packit 908522
Packit 908522
  if(instance)
Packit 908522
  {
Packit 908522
    try
Packit 908522
    {
Packit 908522
      return instance->init(RefPtr<ScaledFont>(new ScaledFont(scaled_font)),
Packit 908522
                            RefPtr<Context>(new Context(cr)),
Packit 908522
                            static_cast<FontExtents&>(*metrics));
Packit 908522
    }
Packit 908522
    catch(const std::exception& ex)
Packit 908522
    {
Packit 908522
      log_uncaught_exception(ex.what());
Packit 908522
    }
Packit 908522
    catch( ... )
Packit 908522
    {
Packit 908522
      log_uncaught_exception();
Packit 908522
    }
Packit 908522
  }
Packit 908522
Packit 908522
  // this should never happen
Packit 908522
  return CAIRO_STATUS_USER_FONT_ERROR;
Packit 908522
}
Packit 908522
Packit 908522
ErrorStatus
Packit 908522
UserFontFace::init(const RefPtr<ScaledFont>& /*scaled_font*/,
Packit 908522
                   const RefPtr<Context>& /*cr*/,
Packit 908522
                   FontExtents& extents)
Packit 908522
{
Packit 908522
  // fallback behavior is to set up the default text extents as described in the
Packit 908522
  // cairo API documentation
Packit 908522
  extents.ascent = 1.0;
Packit 908522
  extents.descent = 0.0;
Packit 908522
  extents.height = 1.0;
Packit 908522
  extents.max_x_advance = 1.0;
Packit 908522
  extents.max_y_advance = 0.0;
Packit 908522
  return CAIRO_STATUS_SUCCESS;
Packit 908522
}
Packit 908522
Packit 908522
cairo_status_t
Packit 908522
UserFontFace::unicode_to_glyph_cb(cairo_scaled_font_t *scaled_font,
Packit 908522
                                  unsigned long        unicode,
Packit 908522
                                  unsigned long       *glyph)
Packit 908522
{
Packit 908522
  auto face = cairo_scaled_font_get_font_face(scaled_font);
Packit 908522
  // we've stored a pointer to the wrapper object in the C object's user_data
Packit 908522
  auto instance =
Packit 908522
    static_cast<UserFontFace*>(cairo_font_face_get_user_data(face,
Packit 908522
                                                             &user_font_key));
Packit 908522
  if(instance)
Packit 908522
  {
Packit 908522
    try
Packit 908522
    {
Packit 908522
      return instance->unicode_to_glyph(RefPtr<ScaledFont>(new ScaledFont(scaled_font)),
Packit 908522
                                        unicode, *glyph);
Packit 908522
    }
Packit 908522
    catch(const std::exception& ex)
Packit 908522
    {
Packit 908522
      log_uncaught_exception(ex.what());
Packit 908522
    }
Packit 908522
    catch( ... )
Packit 908522
    {
Packit 908522
      log_uncaught_exception();
Packit 908522
    }
Packit 908522
  }
Packit 908522
Packit 908522
  // this should never happen
Packit 908522
  return CAIRO_STATUS_USER_FONT_ERROR;
Packit 908522
}
Packit 908522
Packit 908522
ErrorStatus
Packit 908522
UserFontFace::unicode_to_glyph(const RefPtr<ScaledFont>& /*scaled_font*/,
Packit 908522
                               unsigned long unicode,
Packit 908522
                               unsigned long& glyph)
Packit 908522
{
Packit 908522
  // fallback behavior is just to map 1:1
Packit 908522
  glyph = unicode;
Packit 908522
  return CAIRO_STATUS_SUCCESS;
Packit 908522
}
Packit 908522
Packit 908522
cairo_status_t
Packit 908522
UserFontFace::text_to_glyphs_cb(cairo_scaled_font_t *scaled_font,
Packit 908522
                                const char *utf8,
Packit 908522
                                int utf8_len,
Packit 908522
                                cairo_glyph_t **glyphs,
Packit 908522
                                int *num_glyphs,
Packit 908522
                                cairo_text_cluster_t **clusters,
Packit 908522
                                int *num_clusters,
Packit 908522
                                cairo_text_cluster_flags_t *cluster_flags)
Packit 908522
{
Packit 908522
  auto face = cairo_scaled_font_get_font_face(scaled_font);
Packit 908522
  // we've stored a pointer to the wrapper object in the C object's user_data
Packit 908522
  auto instance =
Packit 908522
    static_cast<UserFontFace*>(cairo_font_face_get_user_data(face,
Packit 908522
                                                             &user_font_key));
Packit 908522
Packit 908522
  if(instance)
Packit 908522
  {
Packit 908522
    try
Packit 908522
    {
Packit 908522
      std::vector<Glyph> glyph_v;
Packit 908522
      std::vector<TextCluster> cluster_v;
Packit 908522
      const std::string utf8_str(utf8, utf8 + utf8_len);
Packit 908522
      auto local_flags = static_cast<TextClusterFlags>(0);
Packit 908522
Packit 908522
      auto status =
Packit 908522
        instance->text_to_glyphs(RefPtr<ScaledFont>(new
Packit 908522
                                                    ScaledFont(scaled_font)),
Packit 908522
                                 utf8_str, glyph_v, cluster_v, local_flags);
Packit 908522
Packit 908522
      // NOTE: see explanation in text_to_glyphs()
Packit 908522
      if (cairo_font_face_get_user_data(face, &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS))
Packit 908522
      {
Packit 908522
        *num_glyphs = -1;
Packit 908522
        return status;
Packit 908522
      }
Packit 908522
Packit 908522
      // TODO: we re-allocate a new array and pass it back to the caller since
Packit 908522
      // cairo will free the the returned array.  It sucks to do this excessive
Packit 908522
      // allocation and copying, I don't see much alternative besides just
Packit 908522
      // presenting a plain-C API.  If cairo didn't free the list, we could
Packit 908522
      // possibly just pass back a .data() pointer or something...
Packit 908522
      if(num_glyphs && glyphs)
Packit 908522
      {
Packit 908522
        *num_glyphs = glyph_v.size();
Packit 908522
        if(!glyph_v.empty())
Packit 908522
        {
Packit 908522
          *glyphs = cairo_glyph_allocate(glyph_v.size());
Packit 908522
          std::copy(glyph_v.begin(), glyph_v.end(), *glyphs);
Packit 908522
        }
Packit 908522
      }
Packit 908522
      else
Packit 908522
        return CAIRO_STATUS_USER_FONT_ERROR;
Packit 908522
Packit 908522
      // TODO: same for clusters
Packit 908522
      if(num_clusters && clusters)
Packit 908522
      {
Packit 908522
        *num_clusters = cluster_v.size();
Packit 908522
        if(!cluster_v.empty())
Packit 908522
        {
Packit 908522
          *clusters = cairo_text_cluster_allocate(cluster_v.size());
Packit 908522
          std::copy(cluster_v.begin(), cluster_v.end(), *clusters);
Packit 908522
        }
Packit 908522
      }
Packit 908522
Packit 908522
      if(cluster_flags)
Packit 908522
        *cluster_flags = static_cast<cairo_text_cluster_flags_t>(local_flags);
Packit 908522
Packit 908522
      return status;
Packit 908522
    }
Packit 908522
    catch(const std::exception& ex)
Packit 908522
    {
Packit 908522
      log_uncaught_exception(ex.what());
Packit 908522
    }
Packit 908522
    catch( ... )
Packit 908522
    {
Packit 908522
      log_uncaught_exception();
Packit 908522
    }
Packit 908522
  }
Packit 908522
Packit 908522
  // this should never happen
Packit 908522
  return CAIRO_STATUS_USER_FONT_ERROR;
Packit 908522
}
Packit 908522
Packit 908522
ErrorStatus
Packit 908522
UserFontFace::text_to_glyphs(const RefPtr<ScaledFont>& /*scaled_font*/,
Packit 908522
                             const std::string& /*utf8*/,
Packit 908522
                             std::vector<Glyph>& /*glyphs*/,
Packit 908522
                             std::vector<TextCluster>& /*clusters*/,
Packit 908522
                             TextClusterFlags& /*cluster_flags*/)
Packit 908522
{
Packit 908522
  // this is a big hack to make up for the fact that we can't easily pass back a
Packit 908522
  // negative value for the size of the glyph array, which is a special value in
Packit 908522
  // the C API that means: "ignore this function and call unicode_to_glyph
Packit 908522
  // instead".  If this default virtual function is ever called, it will set a
Packit 908522
  // non-NULL value in the user_data, which we can read back in the
Packit 908522
  // text_to_glyphs_cb and used as a signal to return -1 for the num_glyphs
Packit 908522
  // parameter.
Packit 908522
  // TODO: Is there a reentrancy requirement, and is this code reentrant?
Packit 908522
  cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS,
Packit 908522
                                this, 0);
Packit 908522
  return CAIRO_STATUS_SUCCESS;
Packit 908522
}
Packit 908522
Packit 908522
cairo_status_t
Packit 908522
UserFontFace::render_glyph_cb(cairo_scaled_font_t  *scaled_font,
Packit 908522
                              unsigned long         glyph,
Packit 908522
                              cairo_t              *cr,
Packit 908522
                              cairo_text_extents_t *metrics)
Packit 908522
{
Packit 908522
  auto face = cairo_scaled_font_get_font_face(scaled_font);
Packit 908522
  // we've stored a pointer to the wrapper object in the C object's user_data
Packit 908522
  auto instance =
Packit 908522
    static_cast<UserFontFace*>(cairo_font_face_get_user_data(face,
Packit 908522
                                                             &user_font_key));
Packit 908522
  if(instance)
Packit 908522
  {
Packit 908522
    try
Packit 908522
    {
Packit 908522
      return instance->render_glyph(RefPtr<ScaledFont>(new ScaledFont(scaled_font)),
Packit 908522
                                    glyph, RefPtr<Context>(new Context(cr)),
Packit 908522
                                    static_cast<TextExtents&>(*metrics));
Packit 908522
    }
Packit 908522
    catch(const std::exception& ex)
Packit 908522
    {
Packit 908522
      log_uncaught_exception(ex.what());
Packit 908522
    }
Packit 908522
    catch( ... )
Packit 908522
    {
Packit 908522
      log_uncaught_exception();
Packit 908522
    }
Packit 908522
  }
Packit 908522
Packit 908522
  // this should never happen
Packit 908522
  return CAIRO_STATUS_USER_FONT_ERROR;
Packit 908522
}
Packit 908522
Packit 908522
// no default implementation for UserFontFace::render_glyph(), user must
Packit 908522
// implement it
Packit 908522
Packit 908522
UserFontFace::UserFontFace()
Packit 908522
  : FontFace(cairo_user_font_face_create(), true /* has reference */)
Packit 908522
{
Packit 908522
  check_status_and_throw_exception(cairo_font_face_status(m_cobject));
Packit 908522
Packit 908522
  // store a pointer to the wrapper class in the user-data, so that when one of
Packit 908522
  // the callback functions gets called (which has to be a plain-C function so
Packit 908522
  // can't be a class member), we can get a reference to the wrapper class
Packit 908522
  cairo_font_face_set_user_data(m_cobject, &user_font_key, this, 0);
Packit 908522
  cairo_user_font_face_set_init_func(cobj(), init_cb);
Packit 908522
  cairo_user_font_face_set_render_glyph_func(cobj(), render_glyph_cb);
Packit 908522
  cairo_user_font_face_set_unicode_to_glyph_func(cobj(), unicode_to_glyph_cb);
Packit 908522
  cairo_user_font_face_set_text_to_glyphs_func(cobj(), text_to_glyphs_cb);
Packit 908522
}
Packit 908522
Packit 908522
UserFontFace::~UserFontFace()
Packit 908522
{
Packit 908522
}
Packit 908522
Packit 908522
#ifdef CAIRO_HAS_FT_FONT
Packit 908522
Packit 908522
RefPtr<FtFontFace>
Packit 908522
FtFontFace::create(FT_Face face, int load_flags)
Packit 908522
{
Packit 908522
  return RefPtr<FtFontFace>(new FtFontFace(face, load_flags));
Packit 908522
}
Packit 908522
Packit 908522
FtFontFace::FtFontFace(FT_Face face, int load_flags) :
Packit 908522
  FontFace(cairo_ft_font_face_create_for_ft_face (face, load_flags),
Packit 908522
           true /* has reference*/)
Packit 908522
{
Packit 908522
  check_status_and_throw_exception(cairo_font_face_status(m_cobject));
Packit 908522
}
Packit 908522
Packit 908522
#ifdef CAIRO_HAS_FC_FONT
Packit 908522
RefPtr<FtFontFace>
Packit 908522
FtFontFace::create(FcPattern* pattern)
Packit 908522
{
Packit 908522
  return RefPtr<FtFontFace>(new FtFontFace(pattern));
Packit 908522
}
Packit 908522
Packit 908522
FtFontFace::FtFontFace(FcPattern* pattern) :
Packit 908522
  FontFace(cairo_ft_font_face_create_for_pattern (pattern),
Packit 908522
           true /* has reference*/)
Packit 908522
{
Packit 908522
  check_status_and_throw_exception(cairo_font_face_status(m_cobject));
Packit 908522
}
Packit 908522
#endif // CAIRO_HAS_FC_FONT
Packit 908522
Packit 908522
void FtFontFace::set_synthesize(FtSynthesize synth_flags)
Packit 908522
{
Packit 908522
  cairo_ft_font_face_set_synthesize(m_cobject, synth_flags);
Packit 908522
}
Packit 908522
Packit 908522
void FtFontFace::unset_synthesize(FtSynthesize synth_flags)
Packit 908522
{
Packit 908522
  cairo_ft_font_face_unset_synthesize(m_cobject, synth_flags);
Packit 908522
}
Packit 908522
Packit 908522
FtSynthesize FtFontFace::get_synthesize() const
Packit 908522
{
Packit 908522
  return (FtSynthesize)cairo_ft_font_face_get_synthesize(m_cobject);
Packit 908522
}
Packit 908522
Packit 908522
#endif // CAIRO_HAS_FT_FONT
Packit 908522
Packit 908522
} //namespace Cairo
Packit 908522
Packit 908522
// vim: ts=2 sw=2 et