1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
|
/* Copyright (C) 2001-2012 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied,
modified or distributed except as expressly authorized under the terms
of the license contained in the file LICENSE in this distribution.
Refer to licensing information at http://www.artifex.com or contact
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
CA 94903, U.S.A., +1(415)492-9861, for further information.
*/
/* PostScript/PDF font writing utilities */
#include "memory_.h"
#include <stdlib.h> /* for qsort */
#include "gx.h"
#include "gserrors.h"
#include "gsmatrix.h" /* for gxfont.h */
#include "gxfont.h"
#include "gdevpsf.h"
/* Begin enumerating the glyphs in a font or a font subset. */
static int
enumerate_font_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
{
gs_font *font = ppge->font;
int index = (int)ppge->index;
int code = font->procs.enumerate_glyph(font, &index,
ppge->glyph_space, pglyph);
ppge->index = index;
return (index == 0 ? 1 : code < 0 ? code : 0);
}
static int
enumerate_glyphs_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
{
if (ppge->index >= ppge->subset.size)
return 1;
*pglyph = ppge->subset.selected.list[ppge->index++];
return 0;
}
static int
enumerate_range_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
{
if (ppge->index >= ppge->subset.size)
return 1;
*pglyph = (gs_glyph)(ppge->index++ + gs_min_cid_glyph);
return 0;
}
void
psf_enumerate_list_begin(psf_glyph_enum_t *ppge, gs_font *font,
const gs_glyph *subset_list, uint subset_size,
gs_glyph_space_t glyph_space)
{
ppge->font = font;
ppge->subset.selected.list = subset_list;
ppge->subset.size = subset_size;
ppge->glyph_space = glyph_space;
ppge->enumerate_next =
(subset_list ? enumerate_glyphs_next :
subset_size ? enumerate_range_next : enumerate_font_next);
psf_enumerate_glyphs_reset(ppge);
}
/* Begin enumerating CID or TT glyphs in a subset given by a bit vector. */
static int
enumerate_bits_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
{
for (; ppge->index < ppge->subset.size; ppge->index++)
if (ppge->subset.selected.bits[ppge->index >> 3] & (0x80 >> (ppge->index & 7))) {
*pglyph = (gs_glyph)(ppge->index++ + gs_min_cid_glyph);
return 0;
}
return 1;
}
void
psf_enumerate_bits_begin(psf_glyph_enum_t *ppge, gs_font *font,
const byte *subset_bits, uint subset_size,
gs_glyph_space_t glyph_space)
{
ppge->font = font;
ppge->subset.selected.bits = subset_bits;
ppge->subset.size = subset_size;
ppge->glyph_space = glyph_space;
ppge->enumerate_next =
(subset_bits ? enumerate_bits_next :
subset_size ? enumerate_range_next : enumerate_font_next);
psf_enumerate_glyphs_reset(ppge);
}
/* Reset a glyph enumeration. */
void
psf_enumerate_glyphs_reset(psf_glyph_enum_t *ppge)
{
ppge->index = 0;
}
/* Enumerate the next glyph in a font or a font subset. */
/* Return 0 if more glyphs, 1 if done, <0 if error. */
int
psf_enumerate_glyphs_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
{
return ppge->enumerate_next(ppge, pglyph);
}
/*
* Add composite glyph pieces to a list of glyphs. Does not sort or
* remove duplicates. max_pieces is the maximum number of pieces that a
* single glyph can have: if this value is not known, the caller should
* use max_count.
*/
int
psf_add_subset_pieces(gs_glyph *glyphs, uint *pcount, uint max_count,
uint max_pieces, gs_font *font)
{
uint i;
uint count = *pcount;
for (i = 0; i < count; ++i) {
gs_glyph_info_t info;
int code;
if (count + max_pieces > max_count) {
/* Check first to make sure there is enough room. */
code = font->procs.glyph_info(font, glyphs[i], NULL,
GLYPH_INFO_NUM_PIECES, &info);
if (code < 0)
continue;
if (count + info.num_pieces > max_count)
return_error(gs_error_rangecheck);
}
info.pieces = &glyphs[count];
code = font->procs.glyph_info(font, glyphs[i], NULL,
GLYPH_INFO_NUM_PIECES |
GLYPH_INFO_PIECES, &info);
if (code >= 0)
count += info.num_pieces;
}
*pcount = count;
return 0;
}
/*
* Sort a list of glyphs and remove duplicates. Return the number of glyphs
* in the result.
*/
static int
compare_glyphs(const void *pg1, const void *pg2)
{
gs_glyph g1 = *(const gs_glyph *)pg1, g2 = *(const gs_glyph *)pg2;
return (g1 < g2 ? -1 : g1 > g2 ? 1 : 0);
}
int
psf_sort_glyphs(gs_glyph *glyphs, int count)
{
int i, n;
qsort(glyphs, count, sizeof(*glyphs), compare_glyphs);
for (i = n = 0; i < count; ++i)
if (i == 0 || glyphs[i] != glyphs[i - 1])
glyphs[n++] = glyphs[i];
return n;
}
/*
* Return the index of a given glyph in a sorted list of glyphs, or -1
* if the glyph is not present.
*/
int
psf_sorted_glyphs_index_of(const gs_glyph *glyphs, int count, gs_glyph glyph)
{
int lo = 0, hi = count - 1;
if (hi < 0)
return -1;
if (glyph < glyphs[0] || glyph > glyphs[hi])
return -1;
/*
* Loop invariants: hi > lo;
* glyphs[lo] <= glyph <= glyphs[hi].
*/
while (hi - lo > 1) {
int mid = (lo + hi) >> 1;
if (glyph >= glyphs[mid])
lo = mid;
else
hi = mid;
}
return (glyph == glyphs[lo] ? lo : glyph == glyphs[hi] ? hi : -1);
}
/* Determine whether a sorted list of glyphs includes a given glyph. */
bool
psf_sorted_glyphs_include(const gs_glyph *glyphs, int count, gs_glyph glyph)
{
return psf_sorted_glyphs_index_of(glyphs, count, glyph) >= 0;
}
/* Check that all selected glyphs can be written. */
int
psf_check_outline_glyphs(gs_font_base *pfont, psf_glyph_enum_t *ppge,
glyph_data_proc_t glyph_data)
{
uint members = GLYPH_INFO_WIDTH0 << pfont->WMode;
gs_glyph glyph;
int code, good_glyphs = 0;
while ((code = psf_enumerate_glyphs_next(ppge, &glyph)) != 1) {
gs_glyph_data_t gdata;
gs_font_type1 *ignore_font;
gs_glyph_info_t info;
if (code < 0)
return code;
gdata.memory = pfont->memory;
code = glyph_data(pfont, glyph, &gdata, &ignore_font);
/*
* If the glyph isn't defined by a CharString, glyph_data will
* return a typecheck error. But if there's merely a glyph in
* in the Encoding that isn't defined, glyph_data will return an
* undefined error, which is OK.
*/
if (code < 0) {
if (code == gs_error_undefined)
continue;
return code;
}
gs_glyph_data_free(&gdata, "psf_check_outline_glyphs");
/*
* If the font has a CDevProc or calls a non-standard OtherSubr,
* glyph_info will return a rangecheck error.
*/
code = pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL,
members, &info);
/* It may be that a single glyph is bad (eg no (h)sbw), we'll ignore it */
/* here, the glyph may not be included in any subset, or not used at all */
/* (ie the /.notdef). If an invalid glyoh is actually used then the text */
/* processing will still signal an error causing the document to fail. */
if(code == gs_error_invalidfont)
continue;
if (code < 0)
return code;
good_glyphs++;
}
if(good_glyphs)
return 0;
else
return_error(gs_error_invalidfont);
}
/* Gather glyph information for a Type 1 or Type 2 font. */
int
psf_get_outline_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_base *pfont,
gs_glyph *orig_subset_glyphs, uint orig_subset_size,
glyph_data_proc_t glyph_data)
{
gs_glyph notdef = gs_no_glyph;
gs_glyph *subset_glyphs = orig_subset_glyphs;
uint subset_size = orig_subset_size;
if (subset_glyphs) {
if (subset_size > countof(pglyphs->subset_data))
return_error(gs_error_limitcheck);
memcpy(pglyphs->subset_data, orig_subset_glyphs,
sizeof(gs_glyph) * subset_size);
subset_glyphs = pglyphs->subset_data;
}
{
/*
* Make sure that this font can be written out. Specifically, it
* must have no CharStrings defined by PostScript procedures, no
* non-standard OtherSubrs, and no CDevProc.
*/
psf_glyph_enum_t genum;
int code;
psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs,
(subset_glyphs ? subset_size : 0),
GLYPH_SPACE_NAME);
code = psf_check_outline_glyphs(pfont, &genum, glyph_data);
if (code < 0)
return code;
}
{
/*
* Detect the .notdef glyph, needed for subset fonts and to
* eliminate unnecessary Encoding assignments.
*/
psf_glyph_enum_t genum;
gs_glyph glyph;
int code;
psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, NULL, 0,
GLYPH_SPACE_NAME);
while ((code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1) {
if (gs_font_glyph_is_notdef(pfont, glyph)) {
notdef = glyph;
break;
}
}
}
if (subset_glyphs) {
/*
* For subset fonts, we must ensure that characters referenced
* by seac are also included. Note that seac creates at most
* 2 pieces.
*/
int code = psf_add_subset_pieces(subset_glyphs, &subset_size,
countof(pglyphs->subset_data) - 1, 2,
(gs_font *)pfont);
uint keep_size, i;
if (code < 0)
return code;
/* Subset fonts require .notdef. */
if (notdef == gs_no_glyph)
return_error(gs_error_rangecheck);
/* Remove undefined glyphs. */
for (i = 0, keep_size = 0; i < subset_size; ++i) {
gs_glyph_info_t info;
gs_glyph glyph = subset_glyphs[i];
/*
* The documentation for the glyph_info procedure says that
* using members = 0 is an inexpensive way to find out
* whether a given glyph exists, but the implementations
* don't actually do this. Request an inexpensive value.
*/
if (pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL,
GLYPH_INFO_NUM_PIECES, &info) >= 0)
subset_glyphs[keep_size++] = glyph;
}
subset_size = keep_size;
/* Sort the glyphs. Make sure .notdef is included. */
subset_glyphs[subset_size++] = notdef;
subset_size = psf_sort_glyphs(subset_glyphs, subset_size);
}
pglyphs->notdef = notdef;
pglyphs->subset_glyphs = subset_glyphs;
pglyphs->subset_size = subset_size;
return 0;
}
|