1 #ifndef LASI_H
2 #define LASI_H
3 
4 /** @file
5  *  Defines oPostscriptStream and PostscriptDocument and various
6  *  stream manipulators.
7  */
8 
9 #include <string>
10 #include <ostream>
11 #include <sstream>
12 #include <map>
13 #include <pango/pango.h>
14 #include <ft2build.h>
15 #include FT_GLYPH_H
16 
17 class FreetypeGlyphMgr;
18 class ContextMgr;
19 
20 // These macros are needed for Visual C++ and other Windows compilers as well
21 // as gcc 4.x or higher with -fvisibility=hidden option.
22 // All functions/classes marked with LASIDLLIMPEXP can be imported
23 // from/exported to the Windows dll/gcc shared library.
24 // Has no impact on other platforms.
25 // Details handled identically to PLplot include/pldll.h(.in)
26 #if defined ( WIN32 )
27 /* Visual C/C++, Borland, MinGW and Watcom */
28   #if defined ( __VISUALC__ ) || defined ( _MSC_VER ) || defined ( __BORLANDC__ ) || defined ( __GNUC__ ) || defined ( __WATCOMC__ )
29     #define LASIDLLEXPORT    __declspec( dllexport )
30     #define LASIDLLIMPORT    __declspec( dllimport )
31   #else
32     #define LASIDLLEXPORT
33     #define LASIDLLIMPORT
34   #endif
35 #elif defined ( __CYGWIN__ )
36   #define LASIDLLEXPORT    __declspec( dllexport )
37   #define LASIDLLIMPORT    __declspec( dllimport )
38 #elif defined ( __GNUC__ ) && __GNUC__ > 3
39   // Follow ideas in http://gcc.gnu.org/wiki/Visibility for GCC version 4.x
40   // The following forces exported symbols specifically designated with
41   // LASIDLLEXPORT to be visible.
42   #define LASIDLLEXPORT    __attribute__ ( ( visibility( "default" ) ) )
43   #define LASIDLLIMPORT
44 #endif
45 
46 // For an unknown compiler or static built we clear the macros.
47 #ifndef LASIDLLEXPORT
48   #define LASIDLLEXPORT
49   #define LASIDLLIMPORT
50 #endif
51 
52 #if defined(LASi_EXPORTS)
53   #define LASIDLLIMPEXP LASIDLLEXPORT
54   #define LASIDLLIMPEXP_DATA(type) LASIDLLEXPORT type
55 #elif defined(LASi_DLL)
56   #define LASIDLLIMPEXP LASIDLLIMPORT
57   #define LASIDLLIMPEXP_DATA(type) LASIDLLIMPORT type
58 #else
59   #define LASIDLLIMPEXP
60   #define LASIDLLIMPEXP_DATA(type) type
61 #endif
62 
63 namespace LASi {
64 
65   enum FontStyle{
66     NORMAL_STYLE,
67     OBLIQUE,
68     ITALIC
69   };
70 
71   enum FontWeight{
72     ULTRALIGHT,
73     LIGHT,
74     NORMAL_WEIGHT,
75     BOLD,
76     ULTRABOLD,
77     HEAVY
78   };
79 
80   enum FontVariant{
81     NORMAL_VARIANT,
82     SMALLCAPS
83   };
84 
85   enum FontStretch{
86     ULTRACONDENSED,
87     EXTRACONDENSED,
88     CONDENSED,
89     SEMICONDENSED,
90     NORMAL_STRETCH,
91     SEMIEXPANDED,
92     EXPANDED,
93     EXTRAEXPANDED,
94     ULTRAEXPANDED
95   };
96 
97   class PostscriptDocument;
98   class write_glyph_routine_to_stream;
99 
100   /** Just like any ordinary ostringstream,
101    * but maintains a reference to the PostscriptDocument.
102    */
103   class LASIDLLIMPEXP oPostscriptStream : public std::ostringstream {
104     public:
105       friend class PostscriptDocument;
106       friend class show;
107       friend class setFont;
108       friend class setFontSize;
109 
oPostscriptStream(PostscriptDocument & psDoc)110       oPostscriptStream(PostscriptDocument& psDoc) : _psDoc(psDoc) {}
111 
112     protected:
doc()113       PostscriptDocument& doc() {return _psDoc;}
114 
115     private:
116       PostscriptDocument& _psDoc;
117   };
118 
119   template<class T>
120     inline oPostscriptStream& operator<<(oPostscriptStream& os, T t) {
121       static_cast<std::ostream&>(os) << t;
122       return os;
123     }
124 
125   /** Composes Postscript document as three separate and independant streams
126    * for header, body and footer.  Body and footer streams respond to
127    * LASi::show applicator which generates Postscript commands to display a
128    * string by using glyph routines instead of a Postscript font.
129    */
130   class LASIDLLIMPEXP PostscriptDocument {
131     public:
132       friend class write_glyph_routine_to_stream; // helper class
133       friend class show;
134 
135       PostscriptDocument();
136       ~PostscriptDocument();
137 
138       /** Sets the font that all subsequent text written
139        * to bodyStream() or footerStream() will be rendered with.
140        */
141       void setFont(
142           const char* const family = "sans",
143           LASi::FontStyle   = LASi::NORMAL_STYLE,
144           LASi::FontWeight  = LASi::NORMAL_WEIGHT,
145           LASi::FontVariant = LASi::NORMAL_VARIANT,
146           LASi::FontStretch = LASi::NORMAL_STRETCH
147       );
148 
149       /** Sets the font size, in points, that all subsequent text written
150        * to bodyStream() or footerStream() will be rendered with.
151        */
setFontSize(const double size)152       void setFontSize(const double size) {_fontSize = size;}
153 
154       /** Returns stream for Postscript header.
155        */
osHeader()156       std::ostringstream& osHeader() {return _osHeader;}
157 
158       /** Returns stream for Postscript body.
159        */
osBody()160       oPostscriptStream& osBody() {return _osBody;}
161 
162       /** Returns stream for Postscript footer.
163        */
osFooter()164       oPostscriptStream& osFooter() {return _osFooter;}
165 
166       /** Closes all streams and writes completed Postscript document to os.
167        * Header will include glyph routines for all text glyphs in body and footer.
168        *
169        * 2006.05.01.ET Addendum: To create an EPS document, just include the
170        * the four BoundingBox coordinates llx, lly, urx, ury (dimensions in points).
171        * These are optional parameters -- When not included, you'll get a regular PS
172        * document.  When included, you'll get an EPS document.
173        *
174        */
175       void write(std::ostream& os, double llx=0, double lly=0, double urx=0, double ury=0);
176 
177       /** Return string dimensions:
178         * lineSpacing: inter-line spacing
179         * xAdvance:    width of the string
180         * yMin:        y-coordinate bounding the lowest descender, Indic under-consonantal vowel, etc.
181         * yMax:        y-coordinate bounding the highest ascender, diacritic, Indic over-letter vowel, etc.
182         */
183       void get_dimensions(const char* s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL);
184       void get_dimensions(std::string s, double *lineSpacing, double *xAdvance=NULL, double *yMin=NULL, double *yMax=NULL);
185 
186     protected:
187       /** For internal use only.
188         * @internal
189         * A unique id for a glyph that is composed of its font face and a unique integer.
190         */
191       class GlyphId {
192         public:
193           friend bool operator==(const GlyphId id1, const GlyphId id2) {
194             return id1._str == id2._str;
195           }
196 
197           friend bool operator<(const GlyphId id1, const GlyphId id2) {
198             return id1._str < id2._str;
199           }
200 
GlyphId()201           GlyphId() {}
202           GlyphId(FT_Face, const FT_UInt, uint32_t unichar);
203 
204           /** @return string representation of glyph id */
str()205           std::string str() const {return _str;}
206 
207         private:
208           /** @return string representation of glyph id */
209           std::string _str;
210       };
211 
212       /** Maps glyph routine name to FT_Glyph instance.
213        */
214       typedef std::map<GlyphId, FreetypeGlyphMgr> GlyphMap;
215 
216       /** Pointer to a function that takes a reference to a glyph
217        * and to x and y coordinates.
218        * May return new x and y coordinates.
219        */
220       typedef void (PostscriptDocument::*GLYPH_FUNC)(
221           const GlyphMap::value_type&, void* contextData);
222 
223       void invoke_glyph_routine(const GlyphMap::value_type&, void* contextData);
224 
225       void accrue_dimensions( const GlyphMap::value_type&, void* contextData);
226 
227       /** For a decomposed PangoItem (that can be rendered with a single
228        * font face) that is generated by for_each_glyph_do,
229        * apply GLYPH_FUNC to each glyph in that PangoItem.
230        */
231       FT_Error PangoItem_do(const char* s, PangoItem* const pItem,
232 			     const GLYPH_FUNC func, void* contextData,
233                              bool applyOffset = false);
234 
235       /** Decomposes string into glyphs and applies GLYPH_FUNC to each glyph.
236        */
237       void for_each_glyph_do(const std::string& s, const GLYPH_FUNC func, void* contextData,
238                              bool applyOffset = false);
239 
240       PangoContext* pangoContext() const;
241 
242       /** @returns name of Postscript glyph routine
243        */
244       std::string glyphProcName() const;
245 
246       /** @return font size in points (1/72 in.)
247        */
getFontSize()248       double getFontSize() {return _fontSize;}
249 
250       /** For internal use only.
251         */
252       class write_glyph_routine_to_stream {
253         private:
254           std::ostream& os;
255           PangoContext* pangoCtx;
256 
257         public:
write_glyph_routine_to_stream(std::ostream & os,PangoContext * pangoCtx)258           write_glyph_routine_to_stream(std::ostream& os, PangoContext* pangoCtx)
259             : os(os), pangoCtx(pangoCtx) {}
260           void operator()(PostscriptDocument::GlyphMap::value_type v);
261       };
262 
263     private:
264       GlyphMap _glyphMap;
265 
266       static const unsigned int DRAWING_SCALE;
267 
268       // Use pointers instead of objects in order to minimize namespace pollution of .h file user
269       // Requires fwd declarations above.
270       ContextMgr* _pContextMgr;     // manage PangoContext*
271       double _fontSize;             // font size to be used when rendering next show()
272       std::ostringstream _osHeader; // Postscript header
273       oPostscriptStream _osBody;    // Postscript body
274       oPostscriptStream _osFooter;  // Postscript footer
275   };
276 
277   /** stream manipulator applied to oPostscriptStream.
278    */
279   class LASIDLLIMPEXP setFont {
280     public:
281       /** Stream inserter for 'setFont' stream manipulator
282        */
283       friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFont& x) {
284         x.apply(os);
285         return os;
286       }
287 
288       /** Usage:
289        *   os << setFont("Vera Sans",LASi::ITALIC,LASi::BOLD) << ...
290        */
291       setFont(
292           const char* const family = "sans",
293           const LASi::FontStyle   style   = LASi::NORMAL_STYLE,
294           const LASi::FontWeight  weight  = LASi::NORMAL_WEIGHT,
295           const LASi::FontVariant variant = LASi::NORMAL_VARIANT,
296           const LASi::FontStretch stretch = LASi::NORMAL_STRETCH )
_family(family)297           : _family(family), _style(style), _weight(weight), _variant(variant), _stretch(stretch)
298       {}
299 
300     protected:
apply(oPostscriptStream & os)301       void apply(oPostscriptStream& os) const {
302         os.doc().setFont(_family, _style,_weight, _variant,  _stretch);
303       }
304 
305     private:
306       const char* const  _family;
307       const LASi::FontStyle   _style;
308       const LASi::FontWeight  _weight;
309       const LASi::FontVariant _variant;
310       const LASi::FontStretch _stretch;
311 
312   };
313 
314   /** stream manipulator applied to oPostscriptStream.
315    */
316   class LASIDLLIMPEXP setFontSize {
317     public:
318       /** Stream inserter for 'setFontSize' stream manipulator
319        */
320       friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const setFontSize& x) {
321         x.apply(os);
322         return os;
323       }
324 
325       /** Usage:
326        *   os << setFontSize(12) << ...
327        * @param size size in points
328        */
setFontSize(double size)329       setFontSize(double size) : _size(size) {}
330 
331     protected:
apply(oPostscriptStream & os)332       void apply(oPostscriptStream& os) const {
333         os.doc().setFontSize(_size);
334       }
335 
336     private:
337       double _size;
338   };
339 
340   /** stream applicator applied to oPostscriptStream.
341    */
342   class LASIDLLIMPEXP show{
343     public:
344       /** stream inserter for 'show' stream applicator
345        */
346       friend inline oPostscriptStream& operator<<(oPostscriptStream& os, const show& x) {
347         x.apply(os);
348         return os;
349       }
350 
351       /** Usage:
352        *   os << show("some UTF-8 text") << ...
353        */
show(const char * c_str)354       show(const char* c_str   ) : _str(c_str  ) {}
show(std::string stl_str)355       show(std::string stl_str ) : _str(stl_str) {}
356 
357     protected:
358       void apply(oPostscriptStream& os) const;
359 
360     private:
361       std::string _str;
362   };
363 }
364 #endif
365 
366 /** @mainpage
367  * @section purpose Purpose
368  *
369  * LASi is Copyright (C) 2003, 2004, 2006 by Larry Siden.
370  *
371  * LASi is hosted on http://www.unifont.org
372  *
373  * LASi provides a C++ output stream interface for writing Postscript
374  * documents containing any of the world's scripts supported by Unicode
375  * 4.0 and by Pango. Right-to-left scripts like Hebrew and Arabic are
376  * accomodated as easily as left-to-right scripts.  Complex text layout (CTL)
377  * scripts such as Devanagari, Thai, Lao and Tibetan are supported to the
378  * extent provided by Pango and by the OpenType fonts installed on your system.
379  *
380  * Postscript's <b>show</b> operator and font dictionaries can
381  * only provide glyphs for up to 255 code points and thus are hopelessly
382  * inadequate for many of the world's scripts, much less any kind of
383  * multilingual or scientific text encoded in Unicode.
384  *
385  * LASi works around the limitations of Postscript's built-in font technology
386  * by generating a Postscript routine for each glyph in a string.
387  * A LASi user writes a Postscript program much as he or she may have done in the
388  * past, but now uses LASi's <b>show()</b> method instead of the Postscript
389  * <b>show</b> operator.  The user simply passes UTF-8 text strings
390  * directly to LASi's show() method.
391  *
392  * To draw the text string, LASi generates a sequence of calls
393  * to LASi-generated Postscript glyph routines.  Glyph routines are only
394  * generated for glyphs that are actually used in the text.  In this respect,
395  * LASi is efficient even for Chinese, Japanese, or Korean (CJK).
396  *
397  * In addition to being efficient, the Postscript code and routines
398  * created by LASi are intelligible to human readers which facilitates
399  * debugging of Postscript programs.
400  *
401  * @section usage Usage
402  *
403  * Please view the examples provided in the <b>examples</b> directory to see how LASi is used.
404  * The only header your program need include is <b>LASi.h</b>.
405  * View the examples' <b>Makefiles</b> to see how a program may link with libLASi.
406  *
407  */
408