Browse Source

Add support to load fonts from file.

v1.x
Julian Viereck 12 years ago
committed by TJ Holowaychuk
parent
commit
1d3a99d85a
  1. 29
      binding.gyp
  2. 50
      examples/font.js
  3. 108
      examples/pfennigFont/FONTLOG.txt
  4. 93
      examples/pfennigFont/OFL.txt
  5. 28053
      examples/pfennigFont/Pfennig.sfd
  6. BIN
      examples/pfennigFont/Pfennig.ttf
  7. 29531
      examples/pfennigFont/PfennigBold.sfd
  8. BIN
      examples/pfennigFont/PfennigBold.ttf
  9. 29182
      examples/pfennigFont/PfennigBoldItalic.sfd
  10. BIN
      examples/pfennigFont/PfennigBoldItalic.ttf
  11. 29697
      examples/pfennigFont/PfennigItalic.sfd
  12. BIN
      examples/pfennigFont/PfennigItalic.ttf
  13. 26
      lib/canvas.js
  14. 34
      lib/context2d.js
  15. 2
      src/CanvasGradient.cc
  16. 72
      src/CanvasRenderingContext2d.cc
  17. 12
      src/CanvasRenderingContext2d.h
  18. 99
      src/FontFace.cc
  19. 33
      src/FontFace.h
  20. 8
      src/init.cc
  21. 13
      util/has_cairo_freetype.sh

29
binding.gyp

@ -5,20 +5,22 @@
'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle
'with_jpeg%': 'false',
'with_gif%': 'false',
'with_pango%': 'false'
'with_pango%': 'false',
'with_freetype%': 'false'
}
}, { # 'OS!="win"'
'variables': {
'with_jpeg%': '<!(./util/has_lib.sh jpeg)',
'with_gif%': '<!(./util/has_lib.sh gif)',
'with_pango%': '<!(./util/has_lib.sh pangocairo)'
'with_pango%': '<!(./util/has_lib.sh pangocairo)',
'with_freetype%': '<!(./util/has_cairo_freetype.sh)'
}
}]
],
'targets': [
{
'target_name': 'canvas',
'sources': [
'sources': [
'src/Canvas.cc',
'src/CanvasGradient.cc',
'src/CanvasPattern.cc',
@ -27,7 +29,7 @@
'src/Image.cc',
'src/ImageData.cc',
'src/init.cc',
'src/PixelArray.cc',
'src/PixelArray.cc'
],
'conditions': [
['OS=="win"', {
@ -47,6 +49,25 @@
'-lcairo'
]
}],
['with_freetype=="true"', {
'defines': [
'HAVE_FREETYPE'
],
'sources': [
'src/FontFace.cc'
],
'conditions': [
['OS=="win"', {
# No support for windows right now.
}, { # 'OS!="win"'
'include_dirs': [ # tried to pass through cflags but failed.
# Need to include the header files of cairo AND freetype.
# Looking up the includes of cairo does both.
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)'
]
}]
]
}],
['with_pango=="true"', {
'defines': [
'HAVE_PANGO'

50
examples/font.js

@ -0,0 +1,50 @@
/**
* Module dependencies.
*/
var Canvas = require('../lib/canvas')
, canvas = new Canvas(320, 320)
, Font = Canvas.Font
, ctx = canvas.getContext('2d')
, fs = require('fs')
, path = require("path");
if (!Font) {
throw new Error('Need to compile with font support');
}
function fontFile(name) {
return path.join(__dirname, '/pfennigFont/', name);
}
var pfennigFont = new Font('pfennigFont', fontFile('Pfennig.ttf'));
pfennigFont.addFace(fontFile('PfennigBold.ttf'), 'bold');
pfennigFont.addFace(fontFile('PfennigItalic.ttf'), 'normal', 'italic');
pfennigFont.addFace(fontFile('PfennigBoldItalic.ttf'), 'bold', 'italic');
var canvas = new Canvas(320, 320)
var ctx = canvas.getContext('2d')
// Tell the ctx to use the font.
ctx.useFont(pfennigFont);
ctx.font = 'normal normal 50px "Times", serif';
ctx.fillText('Quo Vaids?', 0, 70);
ctx.font = 'bold 50px pfennigFont';
ctx.fillText('Quo Vaids?', 0, 140);
ctx.font = 'italic 50px pfennigFont';
ctx.fillText('Quo Vaids?', 0, 210);
ctx.font = 'bold italic 50px pfennigFont';
ctx.fillText('Quo Vaids?', 0, 280);
var out = fs.createWriteStream(__dirname + '/fontExample.png');
var stream = canvas.createPNGStream();
stream.on('data', function(chunk){
out.write(chunk);
});

108
examples/pfennigFont/FONTLOG.txt

@ -0,0 +1,108 @@
FONTLOG
Pfennig font family
==========================
This file provides detailed information on the Pfennig family of fonts.
This information should be distributed along with the Pfennig fonts and
any derivative works.
Basic Font Information
----------------------
Pfennig is a sans-serif font with support for Latin, Cyrillic, Greek and Hebrew
character sets. It contains sufficient characters for Latin-0 through Latin-10,
as well as all modern Cyrillic scripts, the full Vietnamese range, modern Greek,
modern Hebrew, and the Pan-African Alphabet. It supports the standard Roman
ligatures and uses OpenType tables for diacritic placement.
Pfennig supports the following Unicode ranges:
Range Description Coverage
..............................................
U+0020-U+007F Basic Latin Full
U+00A0-U+00FF Latin-1 Supplement Full
U+0100-U+017F Latin Extended-A Full
U+0180-U+024F Latin Extended-B 146/208
U+0250-U+02AF IPA Extensions 32/96
U+02B0-U+02FF Spacing Modifiers 18/80
U+0300-U+036F Combining Diacritics 34/112
U+0370-U+03FF Greek 74/134
U+0400-U+04FF Cyrillic 214/256
U+0500-U+052F Cyrillic Supplement 14/44
U+0590-U+05FF Hebrew 27/87
U+1DC0-U+1DFF Comb. Diacritic Supp. 4/43
U+1E00-U+1EFF Latin Extended Add'l 173/256
U+2000-U+206F General Punctuation 19/107
U+2070-U+209F Super/Subscripts 1/42
U+20A0-U+20CF Currency Symbols 1/26 (Euro sign only)
U+2100-U+214F Letterlike Symbols 2/80
U+2200-U+22FF Mathematical Operators 2/256
U+25A0-U+25FF Geometric Shapes 1/96 (Dotted circle only)
U+2C60-U+2C7F Latin Extended-C 5/32
U+A720-U+A7FF Latin Extended-D 5/129
U+FB00-U+FB06 Latin Ligatures 5/7 (all except archaic ligatures)
ChangeLog
---------
2012-04-10 Added Cyrillic glyphs for Orok, Khanty, Nenets (in Unicode
pipeline)
2012-04-07 Improved AE ligature and U+A78D; added a few glyphs with
diacritics.
2011-09-24 Added a few African Latin glyphs; improved Cyrillic breve; major
spacing improvements in italics; improved TTF hints.
2010-08-31 Further refinements of Vietnamese range in all faces.
2010-08-04 Added several obscure African letters. Corrected some stacked
diacritics. Corrected proposed codepoint for H with hook.
2010-06-23 Added modern Hebrew and Greek ranges
2010-06-17 Added all anchors needed for diacritic attachment for
Pan-African to upright fonts; italic fonts are by nature unsuitable
for Pan-African due to stylistic clashes (e.g. between a and alpha).
Improved lowercase thorn in all fonts. Added dropped umlaut on A, O
and U in upright fonts, accessible as ss01.
2010-06-04 Finished up requirements for Pan-African Alphabet;
improved Vietnamese italic & bold-italic
2010-04-23 Completed support for all Cyrillic codepoints for modern
orthographies.
2010-04-14 More glyphs: African, modern Pinyin, Amerindian
2010-04-12 Moved non-Unicode glyphs to PUA; added a few more African
glyphs.
2010-04-06 Diacritic improvement in Bold Vietnamese. Additional glyphs
for Skolt Sami, the Pan-Nigerian Alphabet, and various other
African languages.
2010-03-31 Further spacing enhancements in non-italic. Improvements in
Vietnamese range in Medium to prevent excessive diacritic
height. Spacing improvements in italic ligatures.
2009-09-18 Major overhaul of spacing in non-italic
2009-08-06 Added Vietnamese range.
2009-07-30 Kerned Latin ranges.
2009-07-29 Added Cyrillic range.
2009-07-24 Initial release
Information for Contributors
----------------------------
This font is licensed under the Open Font License (OFL). There is no Reserved
Name clause for the Pfennig font, enabling the free conversion between font
formats.
You can read more about the OFL here:
http://scripts.sil.org/OFL
If you'd like to make changes to the original font, you are free to contact
the author of the original font (for contact information, please see the
"Contributors" section below). Glyph changes should be in a FontForge .sfd
file (please make sure your version of FontForge is reasonably up-to-date).
Please send *only* the changed glyphs, not the entire font range. The author
reserves the right to reject or modify any contributions. If your contribution
is accepted, your name will appear in the Contributors section (unless you
specify otherwise).
Contributors
------------
Daniel Johnson (font maintainer)
il.basso.buffo at gmail dot com

93
examples/pfennigFont/OFL.txt

@ -0,0 +1,93 @@
Copyright (c) 2009 - 2012 Daniel Johnson (<il.basso.buffo@gmail.com>).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

28053
examples/pfennigFont/Pfennig.sfd

File diff suppressed because it is too large

BIN
examples/pfennigFont/Pfennig.ttf

Binary file not shown.

29531
examples/pfennigFont/PfennigBold.sfd

File diff suppressed because it is too large

BIN
examples/pfennigFont/PfennigBold.ttf

Binary file not shown.

29182
examples/pfennigFont/PfennigBoldItalic.sfd

File diff suppressed because it is too large

BIN
examples/pfennigFont/PfennigBoldItalic.ttf

Binary file not shown.

29697
examples/pfennigFont/PfennigItalic.sfd

File diff suppressed because it is too large

BIN
examples/pfennigFont/PfennigItalic.ttf

Binary file not shown.

26
lib/canvas.js

@ -17,6 +17,7 @@ var canvas = require('./bindings')
, Context2d = require('./context2d')
, PNGStream = require('./pngstream')
, JPEGStream = require('./jpegstream')
, FontFace = canvas.FontFace
, fs = require('fs');
/**
@ -63,6 +64,29 @@ exports.JPEGStream = JPEGStream;
exports.PixelArray = PixelArray;
exports.Image = Image;
if (FontFace) {
function Font(name, path, idx) {
this.name = name;
this._faces = {};
this.addFace(path, 'normal', 'normal', idx);
};
Font.prototype.addFace = function(path, weight, style, idx) {
style = style || 'normal';
weight = weight || 'normal';
var face = new FontFace(path, idx || 0);
this._faces[weight + '-' + style] = face;
};
Font.prototype.getFace = function(weightStyle) {
return this._faces[weightStyle] || this._faces['normal-normal'];
};
exports.Font = Font;
}
/**
* Context2d implementation.
*/
@ -116,7 +140,7 @@ Canvas.prototype.getContext = function(contextId){
* @api public
*/
Canvas.prototype.pngStream =
Canvas.prototype.pngStream =
Canvas.prototype.createPNGStream = function(){
return new PNGStream(this);
};

34
lib/context2d.js

@ -77,7 +77,7 @@ var parseFont = exports.parseFont = function(str){
font.style = captures[2] || 'normal';
font.size = parseFloat(captures[3]);
font.unit = captures[4];
font.family = captures[5].replace(/["']/g, '');
font.family = captures[5].replace(/["']/g, '').split(',')[0];
// TODO: dpi
// TODO: remaining unit conversion
@ -215,6 +215,16 @@ Context2d.prototype.__defineGetter__('strokeStyle', function(){
});
Context2d.prototype.useFont = function(font) {
if (!this._fonts) this._fonts = {};
var fonts = this._fonts;
if (fonts[font.name])
return;
fonts[font.name] = font;
};
/**
* Set font.
*
@ -228,12 +238,22 @@ Context2d.prototype.__defineSetter__('font', function(val){
var font;
if (font = parseFont(val)) {
this.lastFontString = val;
this._setFont(
font.weight
, font.style
, font.size
, font.unit
, font.family);
var fonts = this._fonts;
if (fonts && fonts[font.family]) {
var fontObj = fonts[font.family];
var type = font.weight + '-' + font.style;
var fontFace = fontObj.getFace(type);
this._setFontFace(fontFace, font.size);
} else {
this._setFont(
font.weight
, font.style
, font.size
, font.unit
, font.family);
}
}
}
});

2
src/CanvasGradient.cc

@ -90,6 +90,8 @@ Gradient::AddColorStop(const Arguments &args) {
, color.g
, color.b
, color.a);
} else {
return ThrowException(Exception::TypeError(String::New("parse color failed")));
}
return Undefined();

72
src/CanvasRenderingContext2d.cc

@ -16,6 +16,10 @@
#include "CanvasGradient.h"
#include "CanvasPattern.h"
#ifdef HAVE_FREETYPE
#include "FontFace.h"
#endif
Persistent<FunctionTemplate> Context2d::constructor;
/*
@ -113,6 +117,9 @@ Context2d::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor, "arc", Arc);
NODE_SET_PROTOTYPE_METHOD(constructor, "arcTo", ArcTo);
NODE_SET_PROTOTYPE_METHOD(constructor, "_setFont", SetFont);
#ifdef HAVE_FREETYPE
NODE_SET_PROTOTYPE_METHOD(constructor, "_setFontFace", SetFontFace);
#endif
NODE_SET_PROTOTYPE_METHOD(constructor, "_setFillColor", SetFillColor);
NODE_SET_PROTOTYPE_METHOD(constructor, "_setStrokeColor", SetStrokeColor);
NODE_SET_PROTOTYPE_METHOD(constructor, "_setFillPattern", SetFillPattern);
@ -272,8 +279,8 @@ Context2d::restorePath() {
void
Context2d::fill(bool preserve) {
if (state->fillPattern) {
cairo_set_source(_context, state->fillPattern);
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
cairo_set_source(_context, state->fillPattern);
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
// TODO repeat/repeat-x/repeat-y
} else if (state->fillGradient) {
cairo_pattern_set_filter(state->fillGradient, state->patternQuality);
@ -300,8 +307,8 @@ Context2d::fill(bool preserve) {
void
Context2d::stroke(bool preserve) {
if (state->strokePattern) {
cairo_set_source(_context, state->strokePattern);
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
cairo_set_source(_context, state->strokePattern);
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
} else if (state->strokeGradient) {
cairo_pattern_set_filter(state->strokeGradient, state->patternQuality);
cairo_set_source(_context, state->strokeGradient);
@ -396,15 +403,15 @@ Context2d::blur(cairo_surface_t *surface, int radius) {
// get width, height
int width = cairo_image_surface_get_width( surface );
int height = cairo_image_surface_get_height( surface );
unsigned* precalc =
unsigned* precalc =
(unsigned*)malloc(width*height*sizeof(unsigned));
unsigned char* src = cairo_image_surface_get_data( surface );
double mul=1.f/((radius*2)*(radius*2));
int channel;
// The number of times to perform the averaging. According to wikipedia,
// three iterations is good enough to pass for a gaussian.
const int MAX_ITERATIONS = 3;
const int MAX_ITERATIONS = 3;
int iteration;
for ( iteration = 0; iteration < MAX_ITERATIONS; iteration++ ) {
@ -435,7 +442,7 @@ Context2d::blur(cairo_surface_t *surface, int radius) {
int t = y < radius ? 0 : y - radius;
int r = x + radius >= width ? width - 1 : x + radius;
int b = y + radius >= height ? height - 1 : y + radius;
int tot = precalc[r+b*width] + precalc[l+t*width] -
int tot = precalc[r+b*width] + precalc[l+t*width] -
precalc[l+b*width] - precalc[r+t*width];
*pix=(unsigned char)(tot*mul);
pix += 4;
@ -498,7 +505,7 @@ Context2d::PutImageData(const Arguments &args) {
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
ImageData *imageData = ObjectWrap::Unwrap<ImageData>(obj);
PixelArray *arr = imageData->pixelArray();
uint8_t *src = arr->data();
uint8_t *dst = context->canvas()->data();
@ -533,8 +540,8 @@ Context2d::PutImageData(const Arguments &args) {
if (sw <= 0 || sh <= 0) return Undefined();
cols = sw;
rows = sh;
dx += sx;
dy += sy;
dx += sx;
dy += sy;
break;
default:
return ThrowException(Exception::Error(String::New("invalid arguments")));
@ -1425,7 +1432,7 @@ Context2d::Transform(const Arguments &args) {
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_transform(context->context(), &matrix);
return Undefined();
}
@ -1543,14 +1550,14 @@ Context2d::FillText(const Arguments &args) {
Handle<Value>
Context2d::StrokeText(const Arguments &args) {
HandleScope scope;
if (!args[1]->IsNumber()
|| !args[2]->IsNumber()) return Undefined();
String::Utf8Value str(args[0]->ToString());
double x = args[1]->NumberValue();
double y = args[2]->NumberValue();
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
context->savePath();
@ -1679,9 +1686,9 @@ Handle<Value>
Context2d::LineTo(const Arguments &args) {
HandleScope scope;
if (!args[0]->IsNumber())
if (!args[0]->IsNumber())
return ThrowException(Exception::TypeError(String::New("lineTo() x must be a number")));
if (!args[1]->IsNumber())
if (!args[1]->IsNumber())
return ThrowException(Exception::TypeError(String::New("lineTo() y must be a number")));
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
@ -1700,9 +1707,9 @@ Handle<Value>
Context2d::MoveTo(const Arguments &args) {
HandleScope scope;
if (!args[0]->IsNumber())
if (!args[0]->IsNumber())
return ThrowException(Exception::TypeError(String::New("moveTo() x must be a number")));
if (!args[1]->IsNumber())
if (!args[1]->IsNumber())
return ThrowException(Exception::TypeError(String::New("moveTo() y must be a number")));
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
@ -1713,6 +1720,35 @@ Context2d::MoveTo(const Arguments &args) {
return Undefined();
}
#ifdef HAVE_FREETYPE
Handle<Value>
Context2d::SetFontFace(const Arguments &args) {
HandleScope scope;
// Ignore invalid args
if (!args[0]->IsObject()
|| !args[1]->IsNumber())
return ThrowException(Exception::TypeError(String::New("Expected object and number")));
Local<Object> obj = args[0]->ToObject();
if (!FontFace::constructor->HasInstance(obj))
return ThrowException(Exception::TypeError(String::New("FontFace expected")));
FontFace *face = ObjectWrap::Unwrap<FontFace>(obj);
double size = args[1]->NumberValue();
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_t *ctx = context->context();
cairo_set_font_size(ctx, size);
cairo_set_font_face(ctx, face->cairoFace());
return Undefined();
}
#endif
/*
* Set font:
* - weight

12
src/CanvasRenderingContext2d.h

@ -12,6 +12,15 @@
#include "Canvas.h"
#include "CanvasGradient.h"
#ifdef HAVE_FREETYPE
#include <ft2build.h>
#include <cairo-ft.h>
#include FT_FREETYPE_H
#endif
#include <vector>
using namespace std;
typedef enum {
TEXT_DRAW_PATHS,
TEXT_DRAW_GLYPHS
@ -82,6 +91,9 @@ class Context2d: public node::ObjectWrap {
static Handle<Value> FillText(const Arguments &args);
static Handle<Value> StrokeText(const Arguments &args);
static Handle<Value> SetFont(const Arguments &args);
#ifdef HAVE_FREETYPE
static Handle<Value> SetFontFace(const Arguments &args);
#endif
static Handle<Value> SetFillColor(const Arguments &args);
static Handle<Value> SetStrokeColor(const Arguments &args);
static Handle<Value> SetFillPattern(const Arguments &args);

99
src/FontFace.cc

@ -0,0 +1,99 @@
//
// FontFace.cc
//
// Copyright (c) 2012 Julian Viereck <julian.viereck@gmail.com>
//
#include "FontFace.h"
Persistent<FunctionTemplate> FontFace::constructor;
/*
* Destroy ft_face.
*/
FontFace::~FontFace() {
// Decrement extra reference count added in ::New(...).
// Once there is no reference left to crFace, cairo will release the
// free type font face as well.
cairo_font_face_destroy (_crFace);
}
/*
* Initialize FontFace.
*/
void
FontFace::Initialize(Handle<Object> target) {
HandleScope scope;
// Constructor
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(FontFace::New));
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("FontFace"));
// Prototype
target->Set(String::NewSymbol("FontFace"), constructor->GetFunction());
}
/*
* Initialize a new FontFace object.
*/
FT_Library library; /* handle to library */
bool FontFace::_initLibrary = true;
static cairo_user_data_key_t key;
Handle<Value>
FontFace::New(const Arguments &args) {
HandleScope scope;
if (!args[0]->IsString()
|| !args[1]->IsNumber())
{
return ThrowException(Exception::Error(String::New("Wrong argument types passed to FontFace constructor")));
}
String::AsciiValue filePath(args[0]);
int faceIdx = int(args[1]->NumberValue());
FT_Face ftFace;
FT_Error ftError;
cairo_font_face_t *crFace;
if (_initLibrary) {
_initLibrary = false;
ftError = FT_Init_FreeType(&library);
if (ftError) {
return ThrowException(Exception::Error(String::New("Could not load library")));
}
}
// Create new freetype font face.
ftError = FT_New_Face(library, *filePath, faceIdx, &ftFace);
if (ftError) {
return ThrowException(Exception::Error(String::New("Could not load font file")));
}
// Create new cairo font face.
crFace = cairo_ft_font_face_create_for_ft_face(ftFace, 0);
// If the cairo font face is released, release the FreeType font face as well.
int status = cairo_font_face_set_user_data (crFace, &key,
ftFace, (cairo_destroy_func_t) FT_Done_Face);
if (status) {
cairo_font_face_destroy (crFace);
FT_Done_Face (ftFace);
return ThrowException(Exception::Error(String::New("Failed to setup cairo font face user data")));
}
// Explicit reference count the cairo font face. Otherwise the font face might
// get released by cairo although the JS font face object is still alive.
cairo_font_face_reference(crFace);
FontFace *face = new FontFace(ftFace, crFace);
face->Wrap(args.This());
return args.This();
}

33
src/FontFace.h

@ -0,0 +1,33 @@
//
// FontFace.h
//
// Copyright (c) 2012 Julian Viereck <julian.viereck@gmail.com>
//
#ifndef __NODE_TRUE_TYPE_FONT_FACE_H__
#define __NODE_TRUE_TYPE_FONT_FACE_H__
#include "Canvas.h"
#include <ft2build.h>
#include <cairo-ft.h>
#include FT_FREETYPE_H
class FontFace: public node::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Handle<Value> New(const Arguments &args);
FontFace(FT_Face ftFace, cairo_font_face_t *crFace)
:_ftFace(ftFace), _crFace(crFace) {}
inline cairo_font_face_t *cairoFace(){ return _crFace; }
private:
~FontFace();
FT_Face _ftFace;
cairo_font_face_t *_crFace;
static bool _initLibrary;
};
#endif

8
src/init.cc

@ -14,6 +14,10 @@
#include "CanvasPattern.h"
#include "CanvasRenderingContext2d.h"
#ifdef HAVE_FREETYPE
#include "FontFace.h"
#endif
extern "C" void
init (Handle<Object> target) {
HandleScope scope;
@ -24,6 +28,10 @@ init (Handle<Object> target) {
Context2d::Initialize(target);
Gradient::Initialize(target);
Pattern::Initialize(target);
#ifdef HAVE_FREETYPE
FontFace::Initialize(target);
#endif
target->Set(String::New("cairoVersion"), String::New(cairo_version_string()));
#ifdef HAVE_JPEG

13
util/has_cairo_freetype.sh

@ -0,0 +1,13 @@
#!/usr/bin/env bash
has_cairo_freetyep() {
pkg-config cairo --cflags-only-I | grep -E "freetype2" && return 0
return 1;
}
has_cairo_freetyep $1 > /dev/null
if test $? -eq 0; then
echo true
else
echo false
fi
Loading…
Cancel
Save