Merge branch 'truetype-subsetting' into cairo

Conflicts:

	src/Makefile.am
	src/cairo-font-subset.c
	src/cairo-pdf-surface.c
	src/cairo-ps-surface.c
This commit is contained in:
Carl Worth 2006-06-13 15:46:14 -07:00
commit c7b194c595
5 changed files with 418 additions and 76 deletions

View file

@ -1,14 +1,19 @@
font_subset_sources = \
cairo-font-subset.c \
cairo-font-subset-private.h \
cairo-scaled-font-subsets.c \
cairo-scaled-font-subsets-private.h
if CAIRO_HAS_PS_SURFACE
libcairo_ps_headers = cairo-ps.h
libcairo_ps_sources = cairo-ps-surface.c cairo-ps-test.h cairo-scaled-font-subsets.c cairo-scaled-font-subsets-private.h
libcairo_font_subset_sources = cairo-font-subset.c cairo-font-subset-private.h
libcairo_ps_sources = cairo-ps-surface.c cairo-ps-test.h
libcairo_font_subset_sources = $(font_subset_sources)
endif
if CAIRO_HAS_PDF_SURFACE
libcairo_pdf_headers = cairo-pdf.h
libcairo_pdf_sources = cairo-pdf-surface.c cairo-pdf-test.h
libcairo_font_subset_sources = cairo-font-subset.c cairo-font-subset-private.h
libcairo_font_subset_sources = $(font_subset_sources)
endif
if CAIRO_HAS_PNG_FUNCTIONS
@ -18,6 +23,7 @@ endif
if CAIRO_HAS_SVG_SURFACE
libcairo_svg_headers = cairo-svg.h
libcairo_svg_sources = cairo-svg-surface.c cairo-svg-test.h
libcairo_font_subset_sources = $(font_subset_sources)
endif
if CAIRO_HAS_TEST_SURFACES

View file

@ -35,6 +35,7 @@
#include "cairoint.h"
#include "cairo-font-subset-private.h"
#include "cairo-scaled-font-subsets-private.h"
/* XXX: Eventually, we need to handle other font backends */
#include "cairo-ft-private.h"
@ -51,28 +52,31 @@ struct ft_subset_glyph {
unsigned long location;
};
struct cairo_font_subset_backend {
int (*use_glyph) (void *abstract_font,
int glyph);
cairo_status_t (*generate) (void *abstract_font,
const char **data,
unsigned long *length);
void (*destroy) (void *abstract_font);
};
typedef struct _cairo_ft_font {
cairo_scaled_font_subset_t *scaled_font_subset;
struct {
cairo_unscaled_font_t *unscaled_font;
unsigned int font_id;
char *base_font;
int num_glyphs;
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
} base;
typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
struct cairo_pdf_ft_font {
cairo_font_subset_t base;
ft_subset_glyph_t *glyphs;
FT_Face face;
int checksum_index;
cairo_array_t output;
int *parent_to_subset;
cairo_status_t status;
};
} cairo_pdf_ft_font_t;
static int
cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph);
cairo_pdf_ft_font_use_glyph (cairo_pdf_ft_font_t *font, int glyph);
#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
@ -113,56 +117,44 @@ be32_to_cpu(unsigned long v)
#endif
static cairo_font_subset_backend_t cairo_pdf_ft_font_backend;
int
_cairo_font_subset_use_glyph (cairo_font_subset_t *font, int glyph)
{
return font->backend->use_glyph (font, glyph);
}
cairo_status_t
_cairo_font_subset_generate (cairo_font_subset_t *font,
const char **data, unsigned long *length)
{
return font->backend->generate (font, data, length);
}
void
_cairo_font_subset_destroy (cairo_font_subset_t *font)
{
font->backend->destroy (font);
}
cairo_font_subset_t *
_cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font)
static cairo_status_t
_cairo_pdf_ft_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_pdf_ft_font_t **font_return)
{
cairo_unscaled_font_t *unscaled_font;
cairo_ft_unscaled_font_t *ft_unscaled_font;
FT_Face face;
cairo_status_t status = CAIRO_STATUS_NO_MEMORY;
cairo_pdf_ft_font_t *font;
FT_Face face;
unsigned long size;
int i, j;
/* XXX: Need to fix this to work with a general cairo_unscaled_font_t. */
if (! _cairo_unscaled_font_is_ft (unscaled_font))
return NULL;
if (!_cairo_scaled_font_is_ft (scaled_font_subset->scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font);
ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font;
face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
if (face == NULL)
/* Assume out of memory */
return CAIRO_STATUS_NO_MEMORY;
/* We currently only support freetype truetype fonts. */
size = 0;
if (!FT_IS_SFNT (face) ||
FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
return NULL;
return CAIRO_INT_STATUS_UNSUPPORTED;
font = malloc (sizeof (cairo_pdf_ft_font_t));
if (font == NULL)
return NULL;
return CAIRO_STATUS_NO_MEMORY;
font->scaled_font_subset = scaled_font_subset;
font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font);
font->base.backend = &cairo_pdf_ft_font_backend;
_cairo_array_init (&font->output, sizeof (char));
if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
@ -176,7 +168,7 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font)
if (font->parent_to_subset == NULL)
goto fail3;
font->base.num_glyphs = 1;
font->base.num_glyphs = 0;
font->base.x_min = face->bbox.xMin;
font->base.y_min = face->bbox.yMin;
font->base.x_max = face->bbox.xMax;
@ -202,7 +194,9 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font)
font->status = CAIRO_STATUS_SUCCESS;
return &font->base;
*font_return = font;
return CAIRO_STATUS_SUCCESS;
fail5:
free (font->base.base_font);
@ -214,14 +208,13 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font)
_cairo_array_fini (&font->output);
fail1:
free (font);
return NULL;
return status;
}
static void
cairo_pdf_ft_font_destroy (void *abstract_font)
cairo_pdf_ft_font_destroy (cairo_pdf_ft_font_t *font)
{
cairo_pdf_ft_font_t *font = abstract_font;
_cairo_unscaled_font_destroy (font->base.unscaled_font);
free (font->base.base_font);
free (font->parent_to_subset);
@ -735,10 +728,8 @@ cairo_pdf_ft_font_generate (void *abstract_font,
}
static int
cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
cairo_pdf_ft_font_use_glyph (cairo_pdf_ft_font_t *font, int glyph)
{
cairo_pdf_ft_font_t *font = abstract_font;
if (font->parent_to_subset[glyph] == 0) {
font->parent_to_subset[glyph] = font->base.num_glyphs;
font->glyphs[font->base.num_glyphs].parent_index = glyph;
@ -748,8 +739,72 @@ cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
return font->parent_to_subset[glyph];
}
static cairo_font_subset_backend_t cairo_pdf_ft_font_backend = {
cairo_pdf_ft_font_use_glyph,
cairo_pdf_ft_font_generate,
cairo_pdf_ft_font_destroy
};
cairo_status_t
_cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
cairo_scaled_font_subset_t *font_subset)
{
cairo_pdf_ft_font_t *font;
cairo_status_t status;
const char *data;
unsigned long length, parent_glyph;
int i;
status = _cairo_pdf_ft_font_create (font_subset, &font);
if (status)
return status;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
parent_glyph = font->scaled_font_subset->glyphs[i];
cairo_pdf_ft_font_use_glyph (font, parent_glyph);
}
status = cairo_pdf_ft_font_generate (font, &data, &length);
if (status)
goto fail1;
truetype_subset->base_font = strdup (font->base.base_font);
if (truetype_subset->base_font == NULL)
goto fail1;
truetype_subset->widths = calloc (sizeof (int), font->base.num_glyphs);
if (truetype_subset->widths == NULL)
goto fail2;
for (i = 0; i < font->base.num_glyphs; i++)
truetype_subset->widths[i] = font->base.widths[i];
truetype_subset->x_min = font->base.x_min;
truetype_subset->y_min = font->base.y_min;
truetype_subset->x_max = font->base.x_max;
truetype_subset->y_max = font->base.y_max;
truetype_subset->ascent = font->base.ascent;
truetype_subset->descent = font->base.descent;
truetype_subset->data = malloc (length);
if (truetype_subset->data == NULL)
goto fail3;
memcpy (truetype_subset->data, data, length);
truetype_subset->data_length = length;
cairo_pdf_ft_font_destroy (font);
return CAIRO_STATUS_SUCCESS;
fail3:
free (truetype_subset->widths);
fail2:
free (truetype_subset->base_font);
fail1:
cairo_pdf_ft_font_destroy (font);
return status;
}
void
_cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
{
free (subset->base_font);
free (subset->widths);
free (subset->data);
}

View file

@ -1579,6 +1579,108 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
"endobj\r\n");
}
static cairo_status_t
_cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_pdf_resource_t stream, descriptor, subset_resource;
cairo_status_t status;
cairo_pdf_font_t font;
cairo_truetype_subset_t subset;
unsigned long compressed_length;
char *compressed;
int i;
status = _cairo_truetype_subset_init (&subset, font_subset);
if (status)
return status;
compressed = compress_dup (subset.data, subset.data_length,
&compressed_length);
if (compressed == NULL) {
_cairo_truetype_subset_fini (&subset);
return CAIRO_STATUS_NO_MEMORY;
}
stream = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Filter /FlateDecode\r\n"
" /Length %lu\r\n"
" /Length1 %lu\r\n"
">>\r\n"
"stream\r\n",
stream.id,
compressed_length,
subset.data_length);
_cairo_output_stream_write (surface->output, compressed, compressed_length);
_cairo_output_stream_printf (surface->output,
"\r\n"
"endstream\r\n"
"endobj\r\n");
free (compressed);
descriptor = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
" /FontName /7%s\r\n"
" /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
" /Ascent %ld\r\n"
" /Descent %ld\r\n"
" /CapHeight 500\r\n"
" /StemV 80\r\n"
" /StemH 80\r\n"
" /FontFile2 %u 0 R\r\n"
">>\r\n"
"endobj\r\n",
descriptor.id,
subset.base_font,
subset.x_min,
subset.y_min,
subset.x_max,
subset.y_max,
subset.ascent,
subset.descent,
stream.id);
subset_resource = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /Font\r\n"
" /Subtype /TrueType\r\n"
" /BaseFont /%s\r\n"
" /FirstChar 0\r\n"
" /LastChar %d\r\n"
" /FontDescriptor %d 0 R\r\n"
" /Widths [",
subset_resource.id,
subset.base_font,
font_subset->num_glyphs,
descriptor.id);
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->output,
" %d",
subset.widths[i]);
_cairo_output_stream_printf (surface->output,
" ]\r\n"
">>\r\n"
"endobj\r\n");
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
_cairo_truetype_subset_fini (&subset);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_outline_glyph_data (cairo_pdf_surface_t *surface,
cairo_scaled_font_t *scaled_font,
@ -1678,19 +1780,19 @@ _cairo_pdf_surface_emit_glyph (cairo_pdf_surface_t *surface,
_cairo_surface_set_error (&surface->base, status);
}
static void
_cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
static cairo_status_t
_cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_pdf_surface_t *surface = closure;
cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource;
cairo_pdf_font_t font;
cairo_matrix_t matrix;
int i;
glyphs = malloc (font_subset->num_glyphs * sizeof (cairo_pdf_resource_t));
if (glyphs == NULL) {
_cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
return;
return CAIRO_STATUS_NO_MEMORY;
}
for (i = 0; i < font_subset->num_glyphs; i++) {
@ -1726,17 +1828,23 @@ _cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
"endobj\r\n");
subset_resource = _cairo_pdf_surface_new_object (surface);
matrix = font_subset->scaled_font->scale;
cairo_matrix_invert (&matrix);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /Font\r\n"
" /Subtype /Type3\r\n"
" /FontBBox [0 0 0 0]\r\n"
" /FontMatrix\t[1 0 0 1 0 0]\r\n"
" /FontMatrix [ %f %f %f %f 0 0 ]\r\n"
" /Encoding %d 0 R\r\n"
" /CharProcs %d 0 R\r\n"
" /FirstChar 0\r\n"
" /LastChar %d\r\n",
subset_resource.id,
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy,
encoding.id,
char_procs.id,
font_subset->num_glyphs - 1);
@ -1756,6 +1864,24 @@ _cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_pdf_surface_t *surface = closure;
cairo_status_t status;
status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
}
static cairo_status_t
@ -2330,6 +2456,9 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"BT\r\n");
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
scaled_font, glyphs[i].index,
@ -2343,13 +2472,22 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
font_id, subset_id);
current_subset_id = subset_id;
}
_cairo_output_stream_printf (surface->output,
"BT %f %f Td <%c%c> Tj ET\r\n",
glyphs[i].x, glyphs[i].y,
"%f %f %f %f %f %f Tm <%c%c> Tj\r\n",
scaled_font->scale.xx,
scaled_font->scale.yx,
-scaled_font->scale.xy,
-scaled_font->scale.yy,
glyphs[i].x,
glyphs[i].y,
hex_digit (subset_glyph_index >> 4),
hex_digit (subset_glyph_index));
}
_cairo_output_stream_printf (surface->output,
"ET\r\n");
return _cairo_output_stream_get_status (surface->output);
}

View file

@ -209,6 +209,73 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
}
}
static cairo_status_t
_cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_truetype_subset_t subset;
cairo_status_t status;
int i;
status = _cairo_truetype_subset_init (&subset, font_subset);
if (status)
return status;
/* FIXME: Figure out document structure convention for fonts */
_cairo_output_stream_printf (surface->final_stream,
"%% _cairo_ps_surface_emit_truetype_font_subset\n");
_cairo_output_stream_printf (surface->final_stream,
"11 dict begin\n"
"/FontType 42 def\n"
"/FontName /CairoFont-%d-%d def\n"
"/PaintType 0 def\n"
"/FontMatrix [ 1 0 0 1 0 0 ] def\n"
"/FontBBox [ 0 0 0 0 ] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n",
font_subset->font_id,
font_subset->subset_id);
/* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
for (i = 1; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->final_stream,
"Encoding %d /g%d put\n", i, i);
_cairo_output_stream_printf (surface->final_stream,
"/CharStrings %d dict dup begin\n"
"/.notdef 0 def\n",
font_subset->num_glyphs);
for (i = 1; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->final_stream,
"/g%d %d def\n", i, i);
_cairo_output_stream_printf (surface->final_stream,
"end readonly def\n");
/* FIXME: We need to break up fonts bigger than 64k so we don't
* exceed string size limitation. At glyph boundaries. Stupid
* postscript. */
_cairo_output_stream_printf (surface->final_stream,
"/sfnts [<");
_cairo_output_stream_write_hex_string (surface->final_stream,
subset.data, subset.data_length);
_cairo_output_stream_printf (surface->final_stream,
">] def\n"
"FontName currentdict end definefont pop\n");
_cairo_truetype_subset_fini (&subset);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_emit_outline_glyph_data (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
@ -304,27 +371,35 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
_cairo_surface_set_error (&surface->base, status);
}
static void
_cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
static cairo_status_t
_cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_ps_surface_t *surface = closure;
cairo_matrix_t matrix;
int i;
_cairo_output_stream_printf (surface->final_stream,
"%% _cairo_ps_surface_emit_font_subset\n");
"%% _cairo_ps_surface_emit_type3_font_subset\n");
_cairo_output_stream_printf (surface->final_stream,
"/CairoFont-%d-%d <<\n",
font_subset->font_id,
font_subset->subset_id);
matrix = font_subset->scaled_font->scale;
cairo_matrix_invert (&matrix);
_cairo_output_stream_printf (surface->final_stream,
"\t/FontType\t3\n"
"\t/FontMatrix\t[1 0 0 1 0 0]\n"
"\t/FontMatrix\t[%f %f %f %f 0 0]\n"
"\t/Encoding\t[0]\n"
"\t/FontBBox\t[0 0 10 10]\n"
"\t/Glyphs [\n");
"\t/Glyphs [\n",
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy);
for (i = 0; i < font_subset->num_glyphs; i++) {
_cairo_ps_surface_emit_glyph (surface,
@ -339,6 +414,25 @@ _cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
"\t\texch get exec\n"
"\t}\n"
">> definefont pop\n");
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_ps_surface_t *surface = closure;
cairo_status_t status;
status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
}
static cairo_status_t
@ -1785,10 +1879,18 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (subset_id != current_subset_id) {
_cairo_output_stream_printf (surface->stream,
"/CairoFont-%d-%d 1 selectfont\n",
font_id, subset_id);
"/CairoFont-%d-%d findfont\n"
"[ %f %f %f %f 0 0 ] makefont\n"
"setfont\n",
font_id,
subset_id,
scaled_font->scale.xx,
scaled_font->scale.yx,
-scaled_font->scale.xy,
-scaled_font->scale.yy);
current_subset_id = subset_id;
}
_cairo_output_stream_printf (surface->stream,
"%f %f M <%c%c> S\n",
glyphs[i].x, glyphs[i].y,

View file

@ -179,4 +179,45 @@ _cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
typedef struct _cairo_truetype_subset {
char *base_font;
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
char *data;
unsigned long data_length;
} cairo_truetype_subset_t;
/**
* _cairo_truetype_subset_init:
* @truetype_subset: a #cairo_truetype_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* cairo_scaled_font_t and the font backend in use) generate a
* truetype file corresponding to @font_subset and initialize
* @truetype_subset with information about the subset and the truetype
* data.
*
* Return value: CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* truetype file, or an non-zero value indicating an error. Possible
* errors include CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_truetype_subset_fini:
* @truetype_subset: a #cairo_truetype_subset_t
*
* Free all resources associated with @truetype_subset. After this
* call, @truetype_subset should not be used again without a
* subsequent call to _cairo_truetype_subset_init() again first.
**/
cairo_private void
_cairo_truetype_subset_fini (cairo_truetype_subset_t *truetype_subset);
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */