1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2011 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef FONT_SUPPORT_H_
8 #define FONT_SUPPORT_H_
9 
10 #include <list>
11 
12 #include "Wt/WDllDefs.h"
13 
14 #ifdef WT_TARGET_JAVA
15 #define WT_FONTSUPPORT_SIMPLE
16 #endif // WT_TARGET_JAVA
17 #ifdef WT_FONTSUPPORT_SIMPLE
18 #include <string>
19 #endif // WT_FONTSUPPORT_SIMPLE
20 #ifdef WT_FONTSUPPORT_PANGO
21 #include <pango/pango.h>
22 #endif // WT_FONTSUPPORT_PANGO
23 #ifdef WT_FONTSUPPORT_DIRECTWRITE
24 #include <dwrite.h>
25 #endif // WT_FONTSUPPORT_DIRECTWRITE
26 
27 #include "Wt/WFont.h"
28 #include "Wt/WPaintDevice.h"
29 
30 namespace Wt {
31 
32 /*
33  * A private utility class that provides improved font matching.
34  *
35  * This utility class uses libpango for font selection and layout if
36  * available, otherwise uses a simple font matching which choses a
37  * single font and does not take into account its supported glyphs.
38  */
39 class FontSupport
40 {
41 public:
42 #ifndef WT_TARGET_JAVA
43   class Bitmap {
44   public:
45     Bitmap(int width, int height);
46     ~Bitmap();
47 
width()48     int width() const { return width_; }
height()49     int height() const { return height_; }
pitch()50     int pitch() const { return pitch_; }
51 
value(int x,int y)52     unsigned char value(int x, int y) const { return buffer_[y * pitch_ + x]; }
53 
buffer()54     unsigned char *buffer() { return buffer_; }
55 
56   private:
57     int width_, height_, pitch_;
58 
59     unsigned char *buffer_;
60   };
61 #endif
62 
63   /*  For limiting font formats in FontMatch constructor
64    */
65   enum EnabledFontFormats { AnyFont,      // Any available font format
66                             TrueTypeOnly  // Only .ttf or .ttc fonts
67   };
68 
69   class FontMatch {
70   public:
71 #ifdef WT_FONTSUPPORT_SIMPLE
72 
73     FontMatch();
74     FontMatch(const std::string& fileName, double quality);
75 
matched()76     bool matched() const { return quality_ > 0; }
77 
fileName()78     std::string fileName() const { return file_; }
setFileName(const std::string & file)79     void setFileName(const std::string &file) { file_ = file; }
quality()80     double quality() const { return quality_; }
setQuality(double quality)81     void setQuality(double quality) { quality_ = quality; }
82 
83 #endif // WT_FONTSUPPORT_SIMPLE
84 
85 #ifdef WT_FONTSUPPORT_PANGO
86 
87     FontMatch(PangoFont *font, PangoFontDescription *desc);
88 
matched()89     bool matched() const { return true; }
90     std::string fileName() const;
pangoFont()91     PangoFont *pangoFont() const { return font_; }
pangoFontDescription()92     PangoFontDescription *pangoFontDescription() const { return desc_; }
93 
94 #endif // WT_FONTSUPPORT_PANGO
95 
96 #ifdef WT_FONTSUPPORT_DIRECTWRITE
97     FontMatch();
98     FontMatch(IDWriteTextFormat *textFormat,
99       IDWriteFontFamily *fontFamily,
100       IDWriteFont *font,
101       std::string fontFamilyFileName);
102     ~FontMatch();
103 
104     FontMatch(const FontMatch &other);
105     FontMatch &operator=(const FontMatch &other);
106 #ifdef WT_CXX11
107     FontMatch(FontMatch &&other);
108     FontMatch &operator=(FontMatch &&other);
109 #endif // WT_CXX11
110 
111     bool matched() const;
112     std::string fileName() const;
113 
114     std::wstring fontFamilyName() const;
115 
116     // For use in WRasterImage-d2d1.C
textFormat()117     IDWriteTextFormat *textFormat() { return textFormat_; }
fontFamily()118     IDWriteFontFamily *fontFamily() { return fontFamily_; }
font()119     IDWriteFont *font() { return font_; }
120 #endif // WT_FONTSUPPORT_DIRECTWRITE
121   private:
122 
123 #ifdef WT_FONTSUPPORT_SIMPLE
124     std::string file_;
125     double quality_;
126 #endif // WT_FONTSUPPORT_SIMPLE
127 #ifdef WT_FONTSUPPORT_PANGO
128     mutable PangoFont *font_;
129     PangoFontDescription *desc_;
130 #endif // WT_FONTSUPPORT_PANGO
131 #ifdef WT_FONTSUPPORT_DIRECTWRITE
132     IDWriteTextFormat *textFormat_;
133     IDWriteFontFamily *fontFamily_;
134     IDWriteFont *font_;
135     mutable std::string fontFamilyFileName_;
136 #endif // WT_FONTSUPPORT_DIRECTWRITE
137   };
138 
139   FontSupport(WPaintDevice *device, EnabledFontFormats enabledFontFormats=AnyFont);
140   ~FontSupport();
141 
142   void setDevice(WPaintDevice *device);
143 
144   /*
145    * Returns the best matching true type font.
146    */
147   FontMatch matchFont(const WFont& f) const;
148 
149   /*
150    * Returns font metrics
151    */
152   WFontMetrics fontMetrics(const WFont& f);
153 
154   /*
155    * Measures the text, taking into account actual font choices.
156    *
157    * When there is a device_, the actual measurements are delegated to the
158    * device. Otherwise, pango is used for measurements.
159    */
160   WTextItem measureText(const WFont& f, const WString& text, double maxWidth,
161 			bool wordWrap);
162 
163   /*
164    * Draws the text, using pango for font choices, but delegating the actual
165    * drawing to the device
166    *
167    * Precondition: device_ != nullptr
168    */
169   void drawText(const WFont& f,
170 		const WRectF& rect,
171 		WFlags<AlignmentFlag> alignmentFlags, const WString& text);
172 
173   /*
174    * Returns true while in measureText() or drawText()
175    */
176   bool busy() const;
177 
178   /*
179    * Returns the currently matched font path (while busy()).
180    */
181   std::string drawingFontPath() const;
182 
183   /*
184    * Returns whether the implementation can actually render (which is only
185    * the case for pango
186    */
187   bool canRender() const;
188 
189 #ifndef WT_TARGET_JAVA
190   /*
191    * Draws the text, using pango and libfreetype to do the actual rendering
192    *
193    * Precondition: device_ == nullptr
194    */
195   void drawText(const WFont& f,
196 		const WRectF& rect,
197 		const WTransform& transform,
198 		Bitmap& bitmap,
199 		WFlags<AlignmentFlag> alignmentFlags, const WString& text);
200 #endif
201 
202   /*
203    * If libpango support is available, this is a no-op.
204    */
205   void addFontCollection(const std::string& directory, bool recursive = true);
206 
207 #ifdef WT_FONTSUPPORT_DIRECTWRITE
208   /*
209    * Direct access to IDWriteFactory for WRasterImage-d2d1
210    */
writeFactory()211   IDWriteFactory *writeFactory() { return writeFactory_; }
212 #endif // WT_FONTSUPPORT_DIRECTWRITE
213 
214 private:
215   WPaintDevice *device_;
216 
217 #ifdef WT_FONTSUPPORT_SIMPLE
218 
219   struct FontCollection {
220     std::string directory;
221     bool recursive;
222   };
223 
224   std::vector<FontCollection> fontCollections_;
225 
226   struct Matched {
227     WFont font;
228     FontMatch match;
229 
MatchedMatched230     Matched() : font(), match() { }
231   };
232 
233   typedef std::list<Matched> MatchCache;
234   mutable MatchCache cache_;
235 
236   const WFont *font_;
237 
238   FontMatch matchFont(const WFont& font, const std::string& directory,
239 		      bool recursive) const;
240   void matchFont(const WFont& font,
241 		 const std::vector<std::string>& fontNames,
242 		 const std::string& path,
243 		 bool recursive,
244 		 FontMatch& match) const;
245   void matchFont(const WFont& font,
246 		 const std::vector<std::string>& fontNames,
247 		 const std::string& path,
248 		 FontMatch& match) const;
249 
250 #endif // WT_FONTSUPPORT_SIMPLE
251 
252 #ifdef WT_FONTSUPPORT_PANGO
253 
254   PangoContext *context_;
255   PangoFont *currentFont_;
256   EnabledFontFormats enabledFontFormats_;
257 
258   struct Matched {
259     WFont font;
260     PangoFont *match;
261     PangoFontDescription *desc;
262 
MatchedMatched263     Matched() : font(), match(nullptr), desc(nullptr) { }
MatchedMatched264     Matched(const WFont& f, PangoFont *m, PangoFontDescription *d) : font(f), match(m), desc(d) { }
265   };
266 
267   typedef std::list<Matched> MatchCache;
268   mutable MatchCache cache_;
269 
270   PangoFontDescription *createFontDescription(const WFont& f) const;
271   static std::string fontPath(PangoFont *font);
272   GList *layoutText(const WFont& font, const std::string& utf8,
273 		    std::vector<PangoGlyphString *>& glyphs, int& width);
274 
275   friend class FontMatch;
276 
277 #endif // WT_FONTSUPPORT_PANGO
278 
279 #ifdef WT_FONTSUPPORT_DIRECTWRITE
280   EnabledFontFormats enabledFontFormats_;
281 
282   IDWriteFactory *writeFactory_;
283 
284   const WFont *font_;
285   std::string drawingFontPath_;
286 
287   struct Matched {
288     WFont font;
289     FontMatch match;
290 
MatchedMatched291     Matched()
292       : font(), match()
293     { }
294 
MatchedMatched295     Matched(const WFont &f,
296             FontMatch &&m)
297       : font(f), match(m)
298     { }
299   };
300 
301   typedef std::list<Matched> MatchCache;
302   mutable MatchCache cache_;
303 
304   struct TextFragment {
TextFragmentTextFragment305     TextFragment(std::string fontPath,
306       std::size_t start,
307       std::size_t length,
308       double width)
309       : fontPath(fontPath),
310         start(start),
311         length(length),
312         width(width)
313     { }
314 
315     std::string fontPath;
316     std::size_t start;
317     std::size_t length;
318     double width;
319   };
320   class TextFragmentRenderer;
321 
322   void layoutText(const WFont &f, std::vector<TextFragment> &v, const std::wstring &s, double &width, double &nextWidth, double maxWidth, bool wordWrap);
323 #endif // WT_FONTSUPPORT_DIRECTWRITE
324 };
325 
326 }
327 
328 #endif // FONT_SUPPORT_H_
329