1 /********************************************************************************
2 *                                                                               *
3 *                   P o s t c r i p t   F o n t   O b j e c t                   *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2003 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation;                         *
11 * version 2.1 of the License.                                                   *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *
22 * I would have released this updated version under the FOX license addendum     *
23 * that permits static linking, but its terms make that infeasible so this is    *
24 * JUST under LGPL                                                               *
25 *********************************************************************************
26 * $Id: FXPostscriptFont.cpp 3297 2015-12-14 20:30:04Z arthurcnorman $                *
27 ********************************************************************************/
28 
29 
30 // This file was written by A C Norman based on FXFont.c, for which the
31 // above copyright etc apply. The "FOX addendum" referred to can only apply to
32 // variants on FOX distributed by Jeroen, not to any modifications that he has
33 // not adopted, and hence does not apply here, thus this code is subject
34 // to just LGPL 2.1. Note that FXFont.cpp was under "LGPL 2.1 or later" but
35 // in making this derived work I choose just to select version 2.1.
36 //
37 // However as a special exception to LGPL 2.1 I grant permission for my code
38 // to be merged or linked with other code that is subject to LGPL version 3
39 // or GPL version 3. This provision does not represent permission to alter the
40 // license of my code to be that of LGPL 3 or GPL 3 - of itself and when
41 // removed from any LGPL 3 context it remains LGPL 2.1 and the freedom
42 // enshrined by that can not be reduced by adding in the additional
43 // constraints that LGPL 3 views as protections. However clearly the combined
44 // work that then includes my work would be subject to "3". But as per LGPL
45 // 2.1 (and the same would be true if I had used a BSD-style license here)
46 // notices explaining the license terms related to my code should not be
47 // removed. Anybody who changes or extends my code is permitted but not
48 // obliged to apply this exception, and perhaps by doing do they do not lock
49 // out (L)GPL 3 users but guarantee continued support for (L)GPL 2.1 in a way
50 // that the "or later" clause does not (since that permits anybody to
51 // unilaterally select just one version of the library to use, to the
52 // potential detriment of those whose choice differs).
53 
54 /* $Id: FXPostscriptFont.cpp 3297 2015-12-14 20:30:04Z arthurcnorman $ */
55 
56 #ifdef HAVE_CONFIG_H
57 #include "config.h"
58 #endif
59 
60 
61 #include <fx.h>
62 #include "FXPostscriptFont.h"
63 #include <ctype.h>
64 
65 using namespace FX;
66 
67 namespace FX {
68 
69 
70 /*******************************************************************************/
71 
72 
73 #ifdef WANTED_AND_ACTUAL
74 // A bunch of field-names changed between 1.1.45 and 1.1.49 so here for
75 // older releases I map onto the newer names. It may be that I should be a
76 // lot more carefull wrt actualXxx and wantedXxx.
77 
78 
79 // version 1.1.x is SO old now that I might properly disard this...
80 
81 #define actualName      name
82 #define actualSize      size
83 #define actualWeight    weight
84 #define actualSlant     slant
85 #define actualEncoding  encoding
86 #define actualSetwidth  setwidth
87 
88 #endif
89 
90 // Object implementation
91 FXIMPLEMENT(FXPostscriptFont,FXFont,NULL,0)
92 
93 
94 // Deserialization
FXPostscriptFont()95 FXPostscriptFont::FXPostscriptFont(){
96   font=(void*)-1L;
97   }
98 
99 
100 // Construct font from X11 font spec. Well for Postscript Fonts
101 // I will not support decoding X11 long-names...
102 
FXPostscriptFont(FXApp * a,const FXString & nm)103 FXPostscriptFont::FXPostscriptFont(FXApp* a,const FXString& nm):FXFont(a,nm){
104   FXTRACE((100,"FXPostscriptFont::FXPostscriptFont %p\n",this));
105   actualSize=0;
106   actualWeight=0;
107   actualSlant=0;
108   actualEncoding=FONTENCODING_DEFAULT;
109 #if (FOX_MINOR<=4)
110   actualSetwidth=FONTSETWIDTH_DONTCARE;
111 #else
112   actualSetwidth=0;
113 #endif
114   font=NULL;
115   }
116 
117 
118 // Construct a font with given face name, size in points(pixels), weight, slant, character set encoding, setwidth, and hints
FXPostscriptFont(FXApp * a,const FXString & face,FXuint sz,FXuint wt,FXuint sl,FXuint enc,FXuint setw,FXuint h)119 FXPostscriptFont::FXPostscriptFont(FXApp* a, const FXString &face, FXuint sz,
120     FXuint wt, FXuint sl, FXuint enc, FXuint setw, FXuint h):FXFont(a,face){
121   FXTRACE((100,"FXPostscriptFont::FXPostscriptFont %p\n",this));
122   actualSize=10*sz;
123   actualWeight=wt;
124   actualSlant=sl;
125   actualEncoding=enc;
126   actualSetwidth=setw;
127 #if (FOX_MINOR<=4)
128   hints=(h&~FONTHINT_X11);
129 #else
130   hints=(h&~FXFont::X11);
131 #endif
132   font=NULL;
133   }
134 
135 
136 // Construct font from font description
FXPostscriptFont(FXApp * a,const FXFontDesc & fontdesc)137 FXPostscriptFont::FXPostscriptFont(FXApp* a,
138      const FXFontDesc &fontdesc):FXFont(a, fontdesc){
139   FXTRACE((100,"FXPostscriptFont::FXPostscriptFont %p\n",this));
140   actualName=fontdesc.face;
141   actualSize=fontdesc.size;
142   actualWeight=fontdesc.weight;
143   actualSlant=fontdesc.slant;
144   actualEncoding=fontdesc.encoding;
145   actualSetwidth=fontdesc.setwidth;
146   hints=fontdesc.flags;
147   font=NULL;
148   }
149 
150 
151 /*******************************************************************************/
152 
153 
154 
155 
156 //
157 // When generating Postscript I need font metrics. These can be extracted
158 // from "afm" files that Adobe supply. I have a program "get-adobe-metrics.c"
159 // that can be run on a typical Linux system to extract the (minimal) metric
160 // information that I need here and build a file "font-info.cpp". By including
161 // that file here I collect info about all the standard Postscript Fonts.
162 // I will not permit a user to use any other fonts than these!
163 //
164 
165 
166 //
167 // There are 35 standard Postscript fonts that might be used with this
168 // print package. They are:
169 //      AvantGarde-Book
170 //      AvantGarde-BookOblique
171 //      AvantGarde-Demi
172 //      AvantGarde-DemiOblique
173 //      Bookman-Demi
174 //      Bookman-DemiItalic
175 //      Bookman-Light
176 //      Bookman-LightItalic
177 // *    Courier-Bold
178 // *    Courier-BoldOblique
179 // *    Courier
180 // *    Courier-Oblique
181 // *    Helvetica-Bold
182 // *    Helvetica-BoldOblique
183 //      Helvetica-NarrowBold
184 //      Helvetica-NarrowBoldOblique
185 // *    Helvetica
186 // *    Helvetica-Oblique
187 //      Helvetica-Narrow
188 //      Helvetica-NarrowOblique
189 //      NewCenturySchlbk-Bold
190 //      NewCenturySchlbk-BoldItalic
191 //      NewCenturySchlbk-Italic
192 //      NewCenturySchlbk-Roman
193 //      Palatino-Bold
194 //      Palatino-BoldItalic
195 //      Palatino-Italic
196 //      Palatino-Roman
197 // *    Symbol
198 // *    Times-Bold
199 // *    Times-BoldItalic
200 // *    Times-Italic
201 // *    Times-Roman
202 //      ZapfChancery-MediumItalic
203 //      ZapfDingbats
204 // [those marked * are the original 13]
205 //
206 //
207 
208 // Font metrics: I extract these from .afm files so that I can have
209 // rapid access to the information that I need throughout this package.
210 // The effect is that I fill a few kilobytes of memory with font tables.
211 // To avoid going over the top I will not keep per-character bearing
212 // information.  The information in the font tables is based on having a
213 // nominal character cell that is 1000 units high, which means that
214 // integer metrics are quite accurate enough for everybody.
215 
216 #include "font-info.cpp"
217 
218 // Here is the sort of info found in "font-info.cpp". Each font
219 // listed comes with its full Adobe name.
220 // [It will shortly need (max)width, height, ascent, descent,
221 // leading, (max)left-bearing (max)right-bearing]
222 // The main data is then an array of 256 short integers. This contains
223 // -1 if the character is not present, otherwise the character width.
224 // Note once again that these numbers are all based on a nominal 1pt font
225 // with units of 1/1000. Another way to think of this is that numbers are
226 // in units of 1/72000in and will need to be multiplied by the point size
227 // of a font before use.
228 //
229 //  typedef struct font_info {
230 //     char *name;
231 //     short int isfixed, fontwidth, maxleftbearing, maxrightbearing;
232 //     short int capheight, xheight, ascent, descent;
233 //     short int charwidth[256];
234 //  } font_info;
235 //
236 //  static font_info font_widths[] = {
237 //  {"AvantGarde-Demi", 0, 1280, 233, 234, 740, 555, 740, -185, {
238 //      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
239 //      ...
240 //      -1,   874,   760,   946,   771,   865,   771,   888,
241 //     967,   888,   831,   873,   927,   970,   918,    -1 }},
242 //  {(char *)0, {}}};
243 //
244 
find_metrics(const char * name)245 static font_info *find_metrics(const char *name)
246 {
247     font_info *p = font_widths;
248     while (p->name != NULL && strcmp(name, p->name)!=0) p++;
249     if (p->name != NULL) return p;
250     return &font_widths[0];  // this should never occur!
251 }
252 
253 
254 // Create font. In this case I take that to mean the process of refining
255 // the font name and fetching associated metrics.
256 
257 enum family {
258     AvantGarde,
259     Bookman,
260     Courier,
261     Helvetica,
262     NewCenturySchlbk,
263     Palatino,
264     Symbol,
265     Times,
266     ZapfChancery,
267     ZapfDingbats
268 };
269 
270 // return true of s has p as an initial sub-string, ignoring case
271 
matches(const char * s,const char * p)272 static FXbool matches(const char *s, const char *p)
273 {
274     while (*p != 0)
275     {   if (*s==0 || tolower(*s)!=tolower(*p)) return FALSE;
276         s++;
277         p++;
278     }
279     return TRUE;
280 }
281 
282 // return true if s has p as a substring, ignoring case
283 
contains(const char * s,const char * p)284 static FXbool contains(const char *s, const char *p)
285 {
286     while (*s != 0)
287     {   if (matches(s, p)) return TRUE;
288         s++;
289     }
290     return FALSE;
291 }
292 
create()293 void FXPostscriptFont::create()
294 {
295 // I will start by massaging the given name etc to provide me with one of the
296 // canonical Postscript names. Note that the tests on font families
297 // are done in an order so that later test acn override tentative decisions
298 // made by earlier ones. Eg the font with name "roman" will first be
299 // identified as asking for Times (roman, bold etc), but if the word
300 // "palatino" is see too then you get Palatino-Roman. If the name is
301 // not recognised at all you will get Times
302     family fam = Times;    // a default family to use
303     const char *n = actualName.text();
304 #if (FOX_MINOR<=4)
305     if (contains(n, "bold")) actualWeight = FONTWEIGHT_BOLD;
306     if (contains(n, "light")) actualWeight = FONTWEIGHT_LIGHT;
307     if (contains(n, "italic")) actualSlant = FONTSLANT_ITALIC;
308     if (contains(n, "oblique")) actualSlant = FONTSLANT_OBLIQUE;
309     if (contains(n, "narrow")) actualSetwidth = FONTSETWIDTH_NARROW;
310 #else
311     if (contains(n, "bold")) actualWeight = FXFont::Bold;
312     if (contains(n, "light")) actualWeight = FXFont::Light;
313     if (contains(n, "italic")) actualSlant = FXFont::Italic;
314     if (contains(n, "oblique")) actualSlant = FXFont::Oblique;
315     if (contains(n, "narrow")) actualSetwidth = FXFont::Condensed;
316 #endif
317     if (contains(n, "times") ||
318         contains(n, "serif") ||
319         contains(n, "roman")) fam = Times;
320     if (contains(n, "avant")) fam = AvantGarde;
321     if (contains(n, "bookman")) fam = Bookman;
322     if (contains(n, "courier") ||
323         contains(n, "fixed")) fam = Courier;
324     if (contains(n, "helvet") ||
325         contains(n, "ariel") ||
326         contains(n, "sanserif") ||
327         contains(n, "swiss")) fam = Helvetica;
328     if (contains(n, "newcent")) fam = NewCenturySchlbk;
329     if (contains(n, "palatin")) fam = Palatino;
330     if (contains(n, "symbol")) fam = Symbol;
331     if (contains(n, "chancery") ||
332         contains(n, "zapf")) fam = ZapfChancery;
333     if (contains(n, "dingbat")) fam = ZapfDingbats;
334 // Now a few cases that override
335 #if (FOX_MINOR<=4)
336     if (actualSetwidth != FONTSETWIDTH_DONTCARE &&
337         actualSetwidth <= FONTSETWIDTH_COMPRESSED) fam = Helvetica;
338     if (hints & (FONTPITCH_FIXED|FONTHINT_MODERN)) fam = Courier;
339     else if ((hints & FONTPITCH_VARIABLE) && fam==Courier) fam = Helvetica;
340 
341 #define four(reg, bold, ital, boldital) \
342        (actualWeight<=FONTWEIGHT_NORMAL ? \
343          (actualSlant<=FONTSLANT_REGULAR ? reg : ital) : \
344          (actualSlant<=FONTSLANT_REGULAR ? bold : boldital))
345 #else
346     if (actualSetwidth != 0 &&
347         actualSetwidth <= FXFont::Condensed) fam = Helvetica;
348     if (hints & (FXFont::Fixed|FXFont::Modern)) fam = Courier;
349     else if ((hints & FXFont::Variable) && fam==Courier) fam = Helvetica;
350 
351 #define four(reg, bold, ital, boldital) \
352        (actualWeight<=FXFont::Normal ? \
353          (actualSlant<=FXFont::Straight ? reg : ital) : \
354          (actualSlant<=FXFont::Straight ? bold : boldital))
355 #endif
356     switch (fam)
357     {
358 case AvantGarde:
359         actualName = four("AvantGarde-Book", "AvantGarde-Demi",
360                     "AvantGarde-BookOblique", "AvantGarde-DemiOblique");
361         break;
362 case Bookman:
363         actualName = four("Bookman-Light", "Bookman-Demi",
364                     "Bookman-LightItalic", "Bookman-DemiItalic");
365         break;
366 case Courier:
367         actualName = four("Courier", "Courier-Bold",
368                     "Courier-Oblique", "Courier-BoldOblique");
369         break;
370 case Helvetica:
371 #if (FOX_MINOR<=4)
372         if (actualSetwidth == FONTSETWIDTH_NARROW)
373 #else
374         if (actualSetwidth == FXFont::Condensed)
375 #endif
376           actualName = four("Helvetica-Narrowi", "Helvetica-NarrowBold",
377                       "Helvetica-NarrowOblique", "Helvetica-NarrowBoldOblique");
378         else
379           actualName = four("Helvetica", "Helvetica-Bold",
380                       "Helvetica-Oblique", "Helvetica-BoldOblique");
381         break;
382 case NewCenturySchlbk:
383         actualName = four("NewCenturySchlbk", "NewCenturySchlbk-Bold",
384                     "NewCenturySchlbk-Italic", "NewCenturySchlbk-BoldItalic");
385         break;
386 case Palatino:
387         actualName = four("Palatino-Roman", "Palatino-Bold",
388                     "Palatino-Italic", "Palatino-BoldItalic");
389         break;
390 case Symbol:
391         actualName = "Symbol";
392 #if (FOX_MINOR<=4)
393         actualWeight = FONTWEIGHT_NORMAL;
394         actualSlant = FONTSLANT_REGULAR;
395 #else
396         actualWeight = FXFont::Normal;
397         actualSlant = FXFont::Straight;
398 #endif
399         break;
400 case Times:
401 default:
402         actualName = four("Times-Roman", "Times-Bold",
403                     "Times-Italic", "Times-BoldItalic");
404         break;
405 case ZapfChancery:
406         actualName = "ZapfChancery-MediumItalic";
407 #if (FOX_MINOR<=4)
408         actualWeight = FONTWEIGHT_NORMAL;
409         actualSlant = FONTSLANT_ITALIC;
410 #else
411         actualWeight = FXFont::Normal;
412         actualSlant = FXFont::Italic;
413 #endif
414         break;
415 case ZapfDingbats:
416         actualName = "ZapfDingbats";
417 #if (FOX_MINOR<=4)
418         actualWeight = FONTWEIGHT_NORMAL;
419         actualSlant = FONTSLANT_REGULAR;
420 #else
421         actualWeight = FXFont::Normal;
422         actualSlant = FXFont::Straight;
423 #endif
424     }
425     metrics = find_metrics(actualName.text());
426 }
427 
428 
429 // Does font have given character glyph?
hasChar(FXint ch) const430 FXbool FXPostscriptFont::hasChar(FXint ch) const
431 {
432     return metrics->charwidth[ch & 0xff] != -1;
433 }
434 
435 
436 // Get first character glyph in font
437 #if (FOX_MINOR<=4)
getMinChar() const438 FXint FXPostscriptFont::getMinChar() const
439 #else
440 FXwchar FXPostscriptFont::getMinChar() const
441 #endif
442 {
443     int i;
444     for (i=0; i<256; i++)
445         if (metrics->charwidth[i] != -1) return i;
446     return 256;
447 }
448 
449 
450 // Get last character glyph in font
451 #if (FOX_MINOR<=4)
getMaxChar() const452 FXint FXPostscriptFont::getMaxChar() const
453 #else
454 FXwchar FXPostscriptFont::getMaxChar() const
455 #endif
456 {
457     int i;
458     for (i=255; i>=0; i--)
459         if (metrics->charwidth[i] != -1) return i;
460     return 0;
461 }
462 
463 
464 // Get font leading [that is lead-ing as in Pb!]
getFontLeading() const465 FXint FXPostscriptFont::getFontLeading() const
466 {
467 // I use 0.2 of the point-size as my leading. Point sizes are stored in
468 // decipoints. I return a value in millipoints.
469     return (200/10)*actualSize;
470 }
471 
472 
473 // Get font line spacing [height+leading]
getFontSpacing() const474 FXint FXPostscriptFont::getFontSpacing() const
475 {
476     return (1200/10)*actualSize;
477 }
478 
479 
480 // Left bearing
leftBearing(FXchar ch) const481 FXint FXPostscriptFont::leftBearing(FXchar ch) const
482 {
483     return (metrics->maxleftbearing*actualSize)/10;
484 }
485 
486 
487 // Right bearing
rightBearing(FXchar ch) const488 FXint FXPostscriptFont::rightBearing(FXchar ch) const
489 {
490     return (metrics->maxrightbearing*actualSize)/10;
491 }
492 
493 
494 // Is it a mono space font
isFontMono() const495 FXbool FXPostscriptFont::isFontMono() const
496 {
497     return metrics->isfixed;
498 }
499 
500 
501 // Get font width
getFontWidth() const502 FXint FXPostscriptFont::getFontWidth() const
503 {
504     return (metrics->fontwidth*actualSize)/10;
505 }
506 
507 
508 // Get font height
getFontHeight() const509 FXint FXPostscriptFont::getFontHeight() const
510 {
511     return (1000/10)*actualSize;
512 }
513 
514 
515 // Get font ascent
getFontAscent() const516 FXint FXPostscriptFont::getFontAscent() const
517 {
518     return (metrics->ascent*actualSize)/10;
519 }
520 
521 
522 // Get font descent
getFontDescent() const523 FXint FXPostscriptFont::getFontDescent() const
524 {
525     return (metrics->descent*actualSize)/10;
526 }
527 
528 
529 // Text width
getTextWidth(const FXchar * text,FXuint n) const530 FXint FXPostscriptFont::getTextWidth(const FXchar *text, FXuint n) const
531 {
532     int w = 0;
533     while (*text != 0 && (n--)!=0)  // stop on null char as well as at length
534     {   w += metrics->charwidth[*text & 0xff];
535         text++;
536     }
537     return (w*actualSize)/10;
538 }
539 
540 
541 // Text width
getTextWidth(const FXString & text) const542 FXint FXPostscriptFont::getTextWidth(const FXString &text) const
543 {
544     return getTextWidth(text.text(), text.length());
545 }
546 
547 
548 // Text height
getTextHeight(const FXchar * text,FXuint n) const549 FXint FXPostscriptFont::getTextHeight(const FXchar *text, FXuint n) const
550 {
551     return (1000/10)*actualSize;    // use font height
552 }
553 
554 
555 // Text height
getTextHeight(const FXString & text) const556 FXint FXPostscriptFont::getTextHeight(const FXString &text) const
557 {
558     return getTextHeight(text.text(), text.length());
559 }
560 
561 
562 /******************************************************************************/
563 
564 
565 
566 // Clean up
~FXPostscriptFont()567 FXPostscriptFont::~FXPostscriptFont()
568 {
569     FXTRACE((100,"FXPostscriptFont::~FXPostscriptFont %p\n",this));
570     destroy();
571 }
572 
573 }
574 
575 // end of FXPostscriptFont.cpp
576 
577