main() { gs_glyph g; gs_char c; gs_const_string str; /* Test with a short name. */ g = gs_c_known_encode((gs_char)0237, 1); /* caron */ printf("caron is %u, should be %u\n", g - gs_c_min_std_encoding_glyph, I_caron); gs_c_glyph_name(g, &str); fwrite(str.data, 1, str.size, stdout); printf(" should be caron\n"); /* Test with a long name. */ g = gs_c_known_encode((gs_char)0277, 2); /* carriagereturn */ printf("carriagereturn is %u, should be %u\n", g - gs_c_min_std_encoding_glyph, I_carriagereturn); gs_c_glyph_name(g, &str); fwrite(str.data, 1, str.size, stdout); printf(" should be carriagereturn\n"); /* Test lookup with 3 kinds of names. */ g = gs_c_name_glyph((const byte *)"circlemultiply", 14); printf("circlemultiply is %u, should be %u\n", g - gs_c_min_std_encoding_glyph, I_circlemultiply); g = gs_c_name_glyph((const byte *)"numbersign", 10); printf("numbersign is %u, should be %u\n", g - gs_c_min_std_encoding_glyph, I_numbersign); g = gs_c_name_glyph((const byte *)"copyright", 9); printf("copyright is %u, should be %u\n", g - gs_c_min_std_encoding_glyph, I_copyright); /* Test reverse lookup */ c = gs_c_decode(I_caron + gs_c_min_std_encoding_glyph, 1); printf("%u (caron) looked up as %u, should be %u\n", I_caron, c, 0237); c = gs_c_decode(I_carriagereturn + gs_c_min_std_encoding_glyph, 2); printf("%u (carriagereturn) looked up as %u, should be %u\n", I_carriagereturn, c, 0277); c = gs_c_decode(I_notdefined + gs_c_min_std_encoding_glyph, 1); /* undef'd */ printf("%u (notdefined) looked up as %d , should be %d\n", I_notdefined, c, GS_NO_CHAR); exit(0); }
/* Compute the FontDescriptor metrics for a font. */ int pdf_compute_font_descriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd) { gs_font_base *bfont = pdf_base_font_font(pfd->base_font, false); gs_glyph glyph, notdef; int index; int wmode = bfont->WMode; int members = (GLYPH_INFO_WIDTH0 << wmode) | GLYPH_INFO_BBOX | GLYPH_INFO_NUM_PIECES; pdf_font_descriptor_values_t desc; gs_matrix smat; gs_matrix *pmat = NULL; int fixed_width = 0; int small_descent = 0, small_height = 0; bool small_present = false; int x_height = 0; int cap_height = 0; gs_rect bbox_colon, bbox_period, bbox_I; bool is_cid = (bfont->FontType == ft_CID_encrypted || bfont->FontType == ft_CID_TrueType); bool have_colon = false, have_period = false, have_I = false; int code; memset(&bbox_colon, 0, sizeof(bbox_colon)); /* quiet gcc warnings. */ memset(&bbox_period, 0, sizeof(bbox_period)); /* quiet gcc warnings. */ memset(&bbox_I, 0, sizeof(bbox_I)); /* quiet gcc warnings. */ memset(&desc, 0, sizeof(desc)); if (is_cid && bfont->FontBBox.p.x != bfont->FontBBox.q.x && bfont->FontBBox.p.y != bfont->FontBBox.q.y) { int scale = (bfont->FontType == ft_TrueType || bfont->FontType == ft_CID_TrueType ? 1000 : 1); desc.FontBBox.p.x = (int)(bfont->FontBBox.p.x * scale); desc.FontBBox.p.y = (int)(bfont->FontBBox.p.y * scale); desc.FontBBox.q.x = (int)(bfont->FontBBox.q.x * scale); desc.FontBBox.q.y = (int)(bfont->FontBBox.q.y * scale); desc.Ascent = desc.FontBBox.q.y; members &= ~GLYPH_INFO_BBOX; } else { desc.FontBBox.p.x = desc.FontBBox.p.y = max_int; desc.FontBBox.q.x = desc.FontBBox.q.y = min_int; } /* * Embedded TrueType fonts use a 1000-unit character space, but the * font itself uses a 1-unit space. Compensate for this here. */ switch (bfont->FontType) { case ft_TrueType: case ft_CID_TrueType: gs_make_scaling(1000.0, 1000.0, &smat); pmat = &smat; /* Type 3 fonts may use a FontMatrix in PDF, so we don't * need to deal with non-standard matrices */ case ft_GL2_531: case ft_PCL_user_defined: case ft_GL2_stick_user_defined: case ft_MicroType: case ft_user_defined: break; /* Other font types may use a non-standard (not 1000x1000) design grid * The FontMatrix is used to map to the unit square. However PDF files * don't allow FontMatrix entries, all fonts are nominally 1000x1000. * If we have a font with a non-standard matrix we must account for that * here by scaling the font outline. */ default: gs_matrix_scale(&bfont->FontMatrix, 1000.0, 1000.0, &smat); pmat = &smat; break; } /* * Scan the entire glyph space to compute Ascent, Descent, FontBBox, and * the fixed width if any. For non-symbolic fonts, also note the * bounding boxes for Latin letters and a couple of other characters, * for computing the remaining descriptor values (CapHeight, * ItalicAngle, StemV, XHeight, and flags SERIF, SCRIPT, ITALIC, * ALL_CAPS, and SMALL_CAPS). (The algorithms are pretty crude.) */ notdef = GS_NO_GLYPH; for (index = 0; (bfont->procs.enumerate_glyph((gs_font *)bfont, &index, (is_cid ? GLYPH_SPACE_INDEX : GLYPH_SPACE_NAME), &glyph)) >= 0 && index != 0; ) { gs_glyph_info_t info; gs_const_string gname; gs_glyph glyph_known_enc; gs_char position=0; code = bfont->procs.glyph_info((gs_font *)bfont, glyph, pmat, members, &info); if (code == gs_error_VMerror) return code; if (code < 0) { /* * Since this function may be indirtectly called from gx_device_finalize, * we are unable to propagate error code to the interpreter. * Therefore we skip it here hoping that few errors can be * recovered by the integration through entire glyph set. */ continue; } if (members & GLYPH_INFO_BBOX) { /* rect_merge(desc.FontBBox, info.bbox); Expanding due to type cast :*/ if (info.bbox.p.x < desc.FontBBox.p.x) desc.FontBBox.p.x = (int)info.bbox.p.x; if (info.bbox.q.x > desc.FontBBox.q.x) desc.FontBBox.q.x = (int)info.bbox.q.x; if (info.bbox.p.y < desc.FontBBox.p.y) desc.FontBBox.p.y = (int)info.bbox.p.y; if (info.bbox.q.y > desc.FontBBox.q.y) desc.FontBBox.q.y = (int)info.bbox.q.y; if (!info.num_pieces) desc.Ascent = max(desc.Ascent, (int)info.bbox.q.y); } if (notdef == GS_NO_GLYPH && gs_font_glyph_is_notdef(bfont, glyph)) { notdef = glyph; desc.MissingWidth = (int)info.width[wmode].x; } if (info.width[wmode].y != 0) fixed_width = min_int; else if (fixed_width == 0) fixed_width = (int)info.width[wmode].x; else if (info.width[wmode].x != fixed_width) fixed_width = min_int; if (desc.Flags & FONT_IS_SYMBOLIC) continue; /* skip Roman-only computation */ if (is_cid) continue; code = bfont->procs.glyph_name((gs_font *)bfont, glyph, &gname); if (code < 0) { /* If we fail to get the glyph name, best assume this is a symbolic font */ desc.Flags |= FONT_IS_SYMBOLIC; continue; } /* See if the glyph name is in any of the known encodings */ glyph_known_enc = gs_c_name_glyph(gname.data, gname.size); if (glyph_known_enc == gs_no_glyph) { desc.Flags |= FONT_IS_SYMBOLIC; continue; } /* Finally check if the encoded glyph is in Standard Encoding */ /* gs_c_decode always fails to find .notdef, its always present so * don't worry about it */ if(strncmp(".notdef", (const char *)gname.data, gname.size)) { position = gs_c_decode(glyph_known_enc, 0); if (position == GS_NO_CHAR) { desc.Flags |= FONT_IS_SYMBOLIC; continue; } } switch (gname.size) { case 5: if (!memcmp(gname.data, "colon", 5)) bbox_colon = info.bbox, have_colon = true; continue; case 6: if (!memcmp(gname.data, "period", 6)) bbox_period = info.bbox, have_period = true; continue; case 1: break; default: continue; } if (gname.data[0] >= 'A' && gname.data[0] <= 'Z') { cap_height = max(cap_height, (int)info.bbox.q.y); if (gname.data[0] == 'I') bbox_I = info.bbox, have_I = true; } else if (gname.data[0] >= 'a' && gname.data[0] <= 'z') { int y0 = (int)(info.bbox.p.y), y1 = (int)(info.bbox.q.y); small_present = true; switch (gname.data[0]) { case 'b': case 'd': case 'f': case 'h': case 'k': case 'l': case 't': /* ascender */ small_height = max(small_height, y1); case 'i': /* anomalous ascent */ break; case 'j': /* descender with anomalous ascent */ small_descent = min(small_descent, y0); break; case 'g': case 'p': case 'q': case 'y': /* descender */ small_descent = min(small_descent, y0); default: /* no ascender or descender */ x_height = max(x_height, y1); } } } if (!(desc.Flags & FONT_IS_SYMBOLIC)) { desc.Flags |= FONT_IS_ADOBE_ROMAN; /* required if not symbolic */ desc.XHeight = (int)x_height; if (!small_present && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)) desc.Flags |= FONT_IS_ALL_CAPS; desc.CapHeight = cap_height; /* * Look at various glyphs to determine ItalicAngle, StemV, * SERIF, SCRIPT, and ITALIC. */ if (have_colon && have_period) { /* Calculate the dominant angle. */ int angle = (int)(atan2((bbox_colon.q.y - bbox_colon.p.y) - (bbox_period.q.y - bbox_period.p.y), (bbox_colon.q.x - bbox_colon.p.x) - (bbox_period.q.x - bbox_period.p.x)) * radians_to_degrees) - 90; /* Normalize to [-90..90]. */ while (angle > 90) angle -= 180; while (angle < -90) angle += 180; if (angle < -30) angle = -30; else if (angle > 30) angle = 30; /* * For script or embellished fonts, we can get an angle that is * slightly off from zero even for non-italic fonts. * Compensate for this now. */ if (angle <= 2 && angle >= -2) angle = 0; desc.ItalicAngle = angle; } if (desc.ItalicAngle) desc.Flags |= FONT_IS_ITALIC; if (have_I) { double wdot = bbox_period.q.x - bbox_period.p.x; double wcolon = bbox_I.q.x - bbox_I.p.x; double wI = bbox_period.q.x - bbox_period.p.x; desc.StemV = (int)wdot; if (wI > wcolon * 2.5 || wI > (bbox_period.q.y - bbox_period.p.y) * 0.25) desc.Flags |= FONT_IS_SERIF; } } if (desc.Ascent == 0) desc.Ascent = desc.FontBBox.q.y; desc.Descent = desc.FontBBox.p.y; if (!(desc.Flags & (FONT_IS_SYMBOLIC | FONT_IS_ALL_CAPS)) && (small_descent > desc.Descent / 3 || desc.XHeight > small_height * 0.9) && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType) ) desc.Flags |= FONT_IS_SMALL_CAPS; if (fixed_width > 0 && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)) { desc.Flags |= FONT_IS_FIXED_WIDTH; desc.AvgWidth = desc.MaxWidth = desc.MissingWidth = fixed_width; } if (desc.CapHeight == 0) desc.CapHeight = desc.Ascent; if (desc.StemV == 0) desc.StemV = (int)(desc.FontBBox.q.x * 0.15); pfd->common.values = desc; return 0; }