The Pedigree Project  0.1
Font.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Font.h"
21 #include <cerrno>
22 #include <cmath>
23 
24 #include <iconv.h>
25 
26 #include <setjmp.h>
27 #include <string.h>
28 
29 #include <sys/klog.h>
30 
31 #include "pedigree/native/graphics/Graphics.h"
32 
33 #include <ft2build.h>
34 #include FT_FREETYPE_H
35 
36 #include <cairo/cairo-ft.h>
37 #include <cairo/cairo.h>
38 
39 #include <pango/pangocairo.h>
40 
42 {
43  iconv_t m_Iconv;
44  PangoFontDescription *m_FontDesc;
45  cairo_t *m_Cairo;
46 };
47 
49  cairo_t *pCairo, size_t requestedSize, const char *pFilename, bool bCache,
50  size_t nWidth)
51  : m_CellWidth(0), m_CellHeight(0), m_Baseline(requestedSize),
52  m_ConversionCache()
53 {
54  m_FontLibraries = new FontLibraries();
55  m_FontLibraries->m_FontDesc = pango_font_description_from_string(pFilename);
56  m_FontLibraries->m_Cairo = pCairo;
57 
58  PangoFontMetrics *metrics = 0;
59  PangoFontMap *fontmap = pango_cairo_font_map_get_default();
60  PangoContext *context = pango_font_map_create_context(fontmap);
61  pango_context_set_font_description(context, m_FontLibraries->m_FontDesc);
62  metrics =
63  pango_context_get_metrics(context, m_FontLibraries->m_FontDesc, NULL);
64  g_object_unref(context);
65 
66  m_CellWidth =
67  pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
68  m_CellHeight = (pango_font_metrics_get_ascent(metrics) +
69  pango_font_metrics_get_descent(metrics)) /
70  PANGO_SCALE;
71  m_Baseline = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
72 
73  klog(LOG_INFO, "metrics: %dx%d", m_CellWidth, m_CellHeight);
74 
75  pango_font_metrics_unref(metrics);
76 
78  m_FontLibraries->m_Iconv = iconv_open("UTF-8", "UTF-32LE");
79  if (m_FontLibraries->m_Iconv == (iconv_t) -1)
80  {
81  klog(
82  LOG_WARNING, "TUI: Font instance couldn't create iconv (%s)",
83  strerror(errno));
84  }
85 
86  for (uint32_t c = 32; c < 127; ++c)
87  {
88  precache(c);
89  }
90 }
91 
92 Font::~Font()
93 {
94  iconv_close(m_FontLibraries->m_Iconv);
95 
96  // Destroy our precached glyphs.
97  for (std::map<uint32_t, char *>::iterator it = m_ConversionCache.begin();
98  it != m_ConversionCache.end(); ++it)
99  {
100  delete[] it->second;
101  }
102 
103  pango_font_description_free(m_FontLibraries->m_FontDesc);
104 
105  delete m_FontLibraries;
106 }
107 
108 size_t Font::render(
109  PedigreeGraphics::Framebuffer *pFb, uint32_t c, size_t x, size_t y,
110  uint32_t f, uint32_t b, bool bBack, bool bBold, bool bItalic,
111  bool bUnderline)
112 {
113  // Cache the character, if not already.
114  const char *convertOut = precache(c);
115  if (!convertOut)
116  {
117  klog(
118  LOG_WARNING, "TUI: Character '%x' was not able to be precached?",
119  c);
120  return 0;
121  }
122 
123  // Perform the render.
124  return render(convertOut, x, y, f, b, bBack, bBold, bItalic, bUnderline);
125 }
126 
127 size_t Font::render(
128  const char *s, size_t x, size_t y, uint32_t f, uint32_t b, bool bBack,
129  bool bBold, bool bItalic, bool bUnderline)
130 {
131  PangoAttrList *attrs = pango_attr_list_new();
132  if (bBold)
133  {
134  PangoAttribute *attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
135  pango_attr_list_insert(attrs, attr);
136  }
137  if (bItalic)
138  {
139  PangoAttribute *attr = pango_attr_style_new(PANGO_STYLE_OBLIQUE);
140  pango_attr_list_insert(attrs, attr);
141  }
142  if (bUnderline)
143  {
144  PangoAttribute *attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
145  pango_attr_list_insert(attrs, attr);
146  }
147 
148  cairo_save(m_FontLibraries->m_Cairo);
149  PangoLayout *layout = pango_cairo_create_layout(m_FontLibraries->m_Cairo);
150  pango_layout_set_attributes(layout, attrs);
151  pango_layout_set_font_description(layout, m_FontLibraries->m_FontDesc);
152  pango_layout_set_text(
153  layout, s, -1); // Not using markup here - intentional.
154  pango_attr_list_unref(attrs);
155 
156  int width = 0, height = 0;
157  pango_layout_get_size(layout, &width, &height);
158  if ((width < 0) || (height < 0))
159  {
160  // Bad layout size.
162  return 0;
163  }
164  width /= PANGO_SCALE;
165  height /= PANGO_SCALE;
166 
167  if (bBack)
168  {
169  cairo_set_operator(m_FontLibraries->m_Cairo, CAIRO_OPERATOR_SOURCE);
170  cairo_set_source_rgba(
171  m_FontLibraries->m_Cairo, ((b >> 16) & 0xFF) / 256.0,
172  ((b >> 8) & 0xFF) / 256.0, ((b) &0xFF) / 256.0, 0.8);
173 
174  // Precondition above allows this cast to be safe.
175  size_t fillW =
176  m_CellWidth > static_cast<size_t>(width) ? m_CellWidth : width;
177  size_t fillH =
178  m_CellHeight > static_cast<size_t>(height) ? m_CellHeight : height;
179  cairo_rectangle(m_FontLibraries->m_Cairo, x, y, fillW, fillH);
180  cairo_fill(m_FontLibraries->m_Cairo);
181  }
182 
183  cairo_set_operator(m_FontLibraries->m_Cairo, CAIRO_OPERATOR_OVER);
184  cairo_set_source_rgba(
185  m_FontLibraries->m_Cairo, ((f >> 16) & 0xFF) / 256.0,
186  ((f >> 8) & 0xFF) / 256.0, ((f) &0xFF) / 256.0, 1.0);
187 
188  cairo_move_to(m_FontLibraries->m_Cairo, x, y);
189  pango_cairo_show_layout(m_FontLibraries->m_Cairo, layout);
190 
191  g_object_unref(layout);
192  cairo_restore(m_FontLibraries->m_Cairo);
193 
194  return width;
195 }
196 
197 const char *Font::precache(uint32_t c)
198 {
199  if (m_FontLibraries->m_Iconv == (iconv_t) -1)
200  {
201  klog(LOG_WARNING, "TUI: Font instance with bad iconv.");
202  return 0;
203  }
204 
205  // Let's try and skip any actual conversion.
206  std::map<uint32_t, char *>::iterator it = m_ConversionCache.find(c);
207  if (it == m_ConversionCache.end())
208  {
209  // Reset iconv conversion state.
210  iconv(m_FontLibraries->m_Iconv, 0, 0, 0, 0);
211 
212  // Convert UTF-32 input character to UTF-8 for Cairo rendering.
213  uint32_t utf32[] = {c, 0};
214  char *utf32_c = (char *) utf32;
215  char *out = new char[100];
216  char *out_c = out;
217  size_t utf32_len = 8;
218  size_t out_len = 100;
219  size_t res = iconv(
220  m_FontLibraries->m_Iconv, &utf32_c, &utf32_len, &out_c, &out_len);
221 
222  if (res == ((size_t) -1))
223  {
224  klog(
225  LOG_WARNING,
226  "TUI: Font::render couldn't convert input UTF-32 %x", c);
227  delete[] out;
228  }
229  else
230  {
231  m_ConversionCache[c] = out;
232  return out;
233  }
234  }
235  else
236  {
237  return it->second;
238  }
239 
240  return 0;
241 }
242 
243 void Font::updateCairo(cairo_t *pCairo)
244 {
245  m_FontLibraries->m_Cairo = pCairo;
246 }
Font(cairo_t *pCairo, size_t requestedSize, const char *pFilename, bool bCache, size_t nWidth)
Definition: Font.cc:48