Blame examples/text/user-font.cc

Packit Service e3b512
#include <cairomm/cairomm.h>
Packit Service e3b512
#include <iostream>
Packit Service e3b512
#include <map>
Packit Service e3b512
Packit Service e3b512
const double HEIGHT = 200.0;
Packit Service e3b512
const double WIDTH = 400.0;
Packit Service e3b512
const double FONT_SIZE = 64.0;
Packit Service e3b512
const double TEXT_ORIGIN_Y = (HEIGHT / 2.0) + (FONT_SIZE / 2.0);
Packit Service e3b512
const double TEXT_ORIGIN_X = 50.0;  // arbitrary
Packit Service e3b512
const double GLYPH_SPACING = 0.1;
Packit Service e3b512
Packit Service e3b512
struct GlyphBounds
Packit Service e3b512
{
Packit Service e3b512
  unsigned long glyph;
Packit Service e3b512
  double width;
Packit Service e3b512
  double height;
Packit Service e3b512
};
Packit Service e3b512
Packit Service e3b512
// an array that stores the bounds of the glyphs that we're going to draw
Packit Service e3b512
static const GlyphBounds glyphs[] =
Packit Service e3b512
{
Packit Service e3b512
  { 'c', 0.45, 0.5 },
Packit Service e3b512
  { 'a', 0.45, 0.5 },
Packit Service e3b512
  { 'i', 0.2, 0.75 },
Packit Service e3b512
  { 'r', 0.4, 0.5 },
Packit Service e3b512
  { 'o', 0.44, 0.5 },
Packit Service e3b512
  { 'm', 0.75, 0.5 },
Packit Service e3b512
  { '!', 0.2, 0.75 }
Packit Service e3b512
};
Packit Service e3b512
Packit Service e3b512
// A *very* simple font that just draws a box for every glyph
Packit Service e3b512
class BoxFontFace : public Cairo::UserFontFace
Packit Service e3b512
{
Packit Service e3b512
public:
Packit Service e3b512
  // Derived user font classes should have a factory method to create an object
Packit Service e3b512
  // and return it with a RefPtr
Packit Service e3b512
  static Cairo::RefPtr<BoxFontFace> create()
Packit Service e3b512
  {
Packit Service e3b512
    return Cairo::RefPtr<BoxFontFace>(new BoxFontFace());
Packit Service e3b512
  }
Packit Service e3b512
Packit Service e3b512
  Cairo::ErrorStatus
Packit Service e3b512
    init(const Cairo::RefPtr<Cairo::ScaledFont>& /*scaled_font*/,
Packit Service e3b512
         const Cairo::RefPtr<Cairo::Context>& /*cr*/,
Packit Service e3b512
         Cairo::FontExtents &extents) override
Packit Service e3b512
  {
Packit Service e3b512
    double max = 0;
Packit Service e3b512
    for (unsigned int i = 0; i < sizeof (glyphs) / sizeof (GlyphBounds); ++i) {
Packit Service e3b512
      if (glyphs[i].width > max)
Packit Service e3b512
        max = glyphs[i].width;
Packit Service e3b512
    }
Packit Service e3b512
    // add some spacing between characters
Packit Service e3b512
    max += GLYPH_SPACING;
Packit Service e3b512
    extents.max_x_advance = max;
Packit Service e3b512
    return CAIRO_STATUS_SUCCESS;
Packit Service e3b512
  }
Packit Service e3b512
Packit Service e3b512
  Cairo::ErrorStatus
Packit Service e3b512
  unicode_to_glyph (const Cairo::RefPtr<Cairo::ScaledFont>& /*scaled_font*/,
Packit Service e3b512
                    unsigned long unicode, unsigned long& glyph) override
Packit Service e3b512
  {
Packit Service e3b512
    glyph = 0;
Packit Service e3b512
    // yes this is a stupid an ineffienct way to do this but we only have a few
Packit Service e3b512
    // glyphs and this is just demonstration code
Packit Service e3b512
    for (unsigned int i = 0; i < sizeof (glyphs) / sizeof (GlyphBounds); ++i) {
Packit Service e3b512
      if (glyphs[i].glyph == unicode) {
Packit Service e3b512
        // glyph 0 is often a special glyph-not-found value, so offset it by 1
Packit Service e3b512
        glyph = i+1;
Packit Service e3b512
        break;
Packit Service e3b512
      }
Packit Service e3b512
    }
Packit Service e3b512
    return CAIRO_STATUS_SUCCESS;
Packit Service e3b512
  }
Packit Service e3b512
Packit Service e3b512
  Cairo::ErrorStatus
Packit Service e3b512
  render_glyph(const Cairo::RefPtr<Cairo::ScaledFont>& /*scaled_font*/,
Packit Service e3b512
               unsigned long glyph,
Packit Service e3b512
               const Cairo::RefPtr<Cairo::Context>& cr,
Packit Service e3b512
               Cairo::TextExtents& metrics) override
Packit Service e3b512
  {
Packit Service e3b512
    // check that the glyph is in our table
Packit Service e3b512
    if (glyph >= 1 && glyph <= sizeof(glyphs)/sizeof(GlyphBounds)) {
Packit Service e3b512
      cr->set_line_width(0.05);
Packit Service e3b512
      // Need a negative Y value since the text origin is at the bottom left point
Packit Service e3b512
      // and cairo's positive Y axis is down and we want to draw up
Packit Service e3b512
      cr->rectangle(0.0, 0.0, glyphs[glyph-1].width, -glyphs[glyph-1].height);
Packit Service e3b512
      cr->stroke();
Packit Service e3b512
      metrics.x_advance = glyphs[glyph-1].width + GLYPH_SPACING;
Packit Service e3b512
    }
Packit Service e3b512
    return CAIRO_STATUS_SUCCESS;
Packit Service e3b512
  }
Packit Service e3b512
Packit Service e3b512
protected:
Packit Service e3b512
  // FontFace is a ref-counted object, so the constructor should be protected so
Packit Service e3b512
  // it is not created without a refptr to manage it.  See the create() method
Packit Service e3b512
  BoxFontFace() : UserFontFace() { }
Packit Service e3b512
};
Packit Service e3b512
Packit Service e3b512
int main(int, char**)
Packit Service e3b512
{
Packit Service e3b512
  auto surface =
Packit Service e3b512
    Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, WIDTH, HEIGHT);
Packit Service e3b512
  auto cr = Cairo::Context::create(surface);
Packit Service e3b512
  // fill background in white
Packit Service e3b512
  cr->set_source_rgb(1.0, 1.0, 1.0);
Packit Service e3b512
  cr->paint();
Packit Service e3b512
Packit Service e3b512
  // draw a little dot at the point where text will be drawn
Packit Service e3b512
  cr->arc(TEXT_ORIGIN_X, TEXT_ORIGIN_Y, FONT_SIZE / 4.0, 0, 2*M_PI);
Packit Service e3b512
  cr->set_source_rgba(0.0, 1.0, 0.0, 0.5);
Packit Service e3b512
  cr->fill();
Packit Service e3b512
Packit Service e3b512
  // draw the text
Packit Service e3b512
  cr->move_to(TEXT_ORIGIN_X, TEXT_ORIGIN_Y);
Packit Service e3b512
  cr->set_source_rgb(0.8, 0.2, 0.2);
Packit Service e3b512
  auto font = BoxFontFace::create();
Packit Service e3b512
  cr->set_font_face(font);
Packit Service e3b512
  cr->set_font_size(FONT_SIZE);
Packit Service e3b512
  cr->show_text("cairomm!");
Packit Service e3b512
Packit Service e3b512
  // Now show it with the toy text API to demonstrate how the glyphs match up
Packit Service e3b512
  cr->move_to(TEXT_ORIGIN_X, TEXT_ORIGIN_Y);
Packit Service e3b512
  cr->set_source_rgba(0.2, 0.2, 0.2, 0.3);
Packit Service e3b512
  auto toy_font =
Packit Service e3b512
    Cairo::ToyFontFace::create("Bitstream Charter",
Packit Service e3b512
                               Cairo::FONT_SLANT_NORMAL,
Packit Service e3b512
                               Cairo::FONT_WEIGHT_BOLD);
Packit Service e3b512
  cr->set_font_face(toy_font);
Packit Service e3b512
  cr->set_font_size(FONT_SIZE);
Packit Service e3b512
  cr->show_text("cairomm!");
Packit Service e3b512
Packit Service e3b512
  const char* filename = "user-font.png";
Packit Service e3b512
  try {
Packit Service e3b512
    surface->write_to_png(filename);
Packit Service e3b512
    std::cout << "Wrote Image " << filename << std::endl;
Packit Service e3b512
    return 0;
Packit Service e3b512
  } catch (const std::exception& e)
Packit Service e3b512
  {
Packit Service e3b512
    std::cout << "** Unable to write Image " << filename << std::endl;
Packit Service e3b512
    return 1;
Packit Service e3b512
  }
Packit Service e3b512
}