2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include "gfx/pixbuf.hpp"
23 #include "gfx/pixmap.hpp"
24 #include "gfx/screen.hpp"
25 #include "gfx/pixbuffactory.hpp"
26 #include "cave/helper/colors.hpp"
27 #include "gfx/cellrenderer.hpp"
28 #include "gfx/fontmanager.hpp"
29 #include "misc/printf.hpp"
30 #include "misc/logger.hpp"
32 #include "c64_font.cpp"
36 * @brief A RenderedFont stores glyphs rendered for a given font and a given color.
37 * This is an abstract base class, the narrow and wide font are derived from this.
41 /// Number of characters on the font map.
45 NUM_OF_CHARS
=CHARS_X
*CHARS_Y
49 /// @param bitmap_ Raw font data.
50 /// @param color_ The color of drawing.
51 /// @param pixbuf_factory_ The pixbuf factory used to create glyphs.
52 RenderedFont(std::vector
<unsigned char> const& bitmap_
, unsigned font_size_
, GdColor
const& color_
, PixbufFactory
const& pixbuf_factory_
);
55 virtual ~RenderedFont();
57 /// Return the pixmap for a given character; maybe after creating it.
58 /// @param j The ASCII (or GDash) code of the character
59 Pixmap
const &get_character(int j
) const;
61 /// GdColor::get_uint() code of color, for easy searching in a font manager.
66 std::vector
<unsigned char> const& bitmap
;
68 /// Font size (pixbufs)
69 unsigned int font_size
;
71 /// Pixbuf factory for drawing.
72 PixbufFactory
const& pixbuf_factory
;
74 /// RGBA format of color in pixbufs.
77 /// RGBA format of transparent pixel in pixbufs.
80 /// The rendered glyphs are stored in this array as pixmaps.
81 mutable Pixmap
*_character
[NUM_OF_CHARS
];
83 RenderedFont(const RenderedFont
&); // not implemented
84 RenderedFont
& operator=(const RenderedFont
&); // not implemented
87 /// Render a single character. The narrow and wide fonts implement this.
88 virtual void render_character(int j
) const=0;
91 class RenderedFontNarrow
: public RenderedFont
{
93 virtual void render_character(int j
) const;
96 RenderedFontNarrow(std::vector
<unsigned char> const& bitmap_
, unsigned font_size_
, GdColor
const& color
, PixbufFactory
const& pixbuf_factory_
)
97 : RenderedFont(bitmap_
, font_size_
, color
, pixbuf_factory_
) {}
100 class RenderedFontWide
: public RenderedFont
{
102 virtual void render_character(int j
) const;
105 RenderedFontWide(std::vector
<unsigned char> const& bitmap_
, unsigned font_size_
, GdColor
const& color
, PixbufFactory
const& pixbuf_factory_
)
106 : RenderedFont(bitmap_
, font_size_
, color
, pixbuf_factory_
) {}
110 RenderedFont::RenderedFont(std::vector
<unsigned char> const& bitmap_
, unsigned font_size_
, GdColor
const& color
, PixbufFactory
const& pixbuf_factory_
)
111 : uint(color
.get_uint()),
113 font_size(font_size_
),
114 pixbuf_factory(pixbuf_factory_
),
116 g_assert(font_size_
*font_size_
*NUM_OF_CHARS
==bitmap_
.size());
117 col
=Pixbuf::rgba_pixel_from_color(color
, 0xff); /* opaque */
118 transparent
=Pixbuf::rgba_pixel_from_color(GdColor::from_rgb(0, 0, 0), 0x00); /* color does not matter as totally transparent */
121 void RenderedFontNarrow::render_character(int j
) const {
122 int y1
=(j
/CHARS_X
)*font_size
;
123 int x1
=(j
%CHARS_X
)*font_size
;
125 Pixbuf
*image
=pixbuf_factory
.create(font_size
, font_size
);
127 for (unsigned y
=0; y
<font_size
; y
++) {
128 guint32
*p
=image
->get_row(y
);
129 for (unsigned x
=0; x
<font_size
; x
++) {
130 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
131 if (bitmap
[(y1
+y
)*(CHARS_X
*font_size
)+x1
+x
]!=1) /* 1 is black there!! */
132 p
[x
]=col
; /* normal */
134 p
[x
]=transparent
; /* normal */
138 _character
[j
]=pixbuf_factory
.create_pixmap_from_pixbuf(*image
, true); // true=preserve alpha channel!
142 void RenderedFontWide::render_character(int j
) const {
143 int y1
=(j
/CHARS_X
)*font_size
;
144 int x1
=(j
%CHARS_X
)*font_size
;
146 Pixbuf
*image
=pixbuf_factory
.create(font_size
*2, font_size
);
148 for (unsigned y
=0; y
<font_size
; y
++) {
149 guint32
*p
=image
->get_row(y
);
150 for (unsigned x
=0; x
<font_size
; x
++) {
151 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
152 if (bitmap
[(y1
+y
)*(CHARS_X
*font_size
)+x1
+x
]!=1) { /* 1 is black there!! */
153 p
[0]=col
; /* normal */
157 p
[0]=transparent
; /* normal */
158 p
[1]=transparent
; /* normal */
164 _character
[j
]=pixbuf_factory
.create_pixmap_from_pixbuf(*image
, true); // true=preserve alpha channel!
168 RenderedFont::~RenderedFont() {
169 for (unsigned i
=0; i
<NUM_OF_CHARS
; ++i
)
170 delete _character
[i
];
173 Pixmap
const &RenderedFont::get_character(int j
) const {
174 g_assert(j
<NUM_OF_CHARS
);
175 if (_character
[j
]==0)
177 return *_character
[j
];
181 /* check if given surface is ok to be a gdash theme. */
182 bool FontManager::is_pixbuf_ok_for_theme(const Pixbuf
&surface
) {
183 if ((surface
.get_width() % RenderedFont::CHARS_X
!= 0)
184 || (surface
.get_height() % RenderedFont::CHARS_Y
!= 0)
185 || (surface
.get_width() / RenderedFont::CHARS_X
!= surface
.get_height() / RenderedFont::CHARS_Y
)) {
186 gd_critical(CPrintf("image should contain %d chars in a row and %d in a column!") % int(RenderedFont::CHARS_X
) % int(RenderedFont::CHARS_Y
));
189 if (!surface
.has_alpha()) {
190 gd_critical("image should have an alpha channel!");
194 return true; /* passed checks */
197 bool FontManager::is_image_ok_for_theme(PixbufFactory
&pixbuf_factory
, const char *filename
) {
199 Pixbuf
*image
=pixbuf_factory
.create_from_file(filename
);
200 /* if the image is loaded */
201 SetLoggerContextForFunction
scf(filename
);
202 bool result
=is_pixbuf_ok_for_theme(*image
);
210 bool FontManager::loadfont_image(Pixbuf
const& image
) {
211 if (!is_pixbuf_ok_for_theme(image
))
215 font
= Pixbuf::c64_gfx_data_from_pixbuf(image
);
216 font_size
= image
.get_width()/RenderedFont::CHARS_X
;
220 /* load theme from image file. */
221 /* return true if successful. */
222 bool FontManager::loadfont_file(const std::string
& filename
) {
223 /* load cell graphics */
226 Pixbuf
*image
=pixbuf_factory
.create_from_file(filename
.c_str());
227 bool result
=loadfont_image(*image
);
230 gd_critical(CPrintf("%s: invalid font bitmap") % filename
);
232 } catch (std::exception
&e
) {
233 gd_critical(CPrintf("%s: unable to load image (%s)") % filename
% e
.what());
238 /* load the theme from the given file. */
239 /* if successful, ok. */
240 /* if fails, or no theme specified, load the builtin */
241 void FontManager::load_theme(const std::string
& theme_file
) {
242 if (theme_file
!="" && loadfont_file(theme_file
)) {
243 /* loaded from png file */
245 Pixbuf
*image
=pixbuf_factory
.create_from_inline(sizeof(c64_font
), c64_font
);
246 bool result
=loadfont_image(*image
);
247 g_assert(result
==true); // to check the builting font
252 FontManager::FontManager(const PixbufFactory
& pixbuf_factory_
, const std::string
& theme_file
)
254 pixbuf_factory(pixbuf_factory_
) {
255 load_theme(theme_file
);
258 FontManager::~FontManager() {
262 struct FindRenderedFont
{
264 FindRenderedFont(guint32 uint_
): uint(uint_
) {}
265 bool operator()(const RenderedFont
* font
) const {
266 return font
->uint
==uint
;
270 RenderedFont
* FontManager::narrow(const GdColor
&c
) {
272 container::iterator it
=find_if(_narrow
.begin(), _narrow
.end(), FindRenderedFont(c
.get_uint()));
273 if (it
==_narrow
.end()) {
274 // if not found, create it
275 RenderedFont
*newfont
=new RenderedFontNarrow(font
, font_size
, c
, pixbuf_factory
);
276 _narrow
.push_front(newfont
);
277 // if list became too long, remove one from the end
278 if (_narrow
.size()>16) {
279 delete _narrow
.back();
280 _narrow
.erase(--_narrow
.end());
283 // put the font found to the beginning of the list
284 std::swap(*_narrow
.begin(), *it
);
285 return *_narrow
.begin();
288 RenderedFont
* FontManager::wide(const GdColor
&c
) {
290 container::iterator it
=find_if(_wide
.begin(), _wide
.end(), FindRenderedFont(c
.get_uint()));
291 if (it
==_wide
.end()) {
292 // if not found, create it
293 RenderedFont
*newfont
=new RenderedFontWide(font
, font_size
, c
, pixbuf_factory
);
294 _wide
.push_front(newfont
);
295 // if list became too long, remove one from the end
296 if (_wide
.size()>16) {
298 _wide
.erase(--_wide
.end());
301 // put the font found to the beginning of the list
302 std::swap(*_wide
.begin(), *it
);
304 return *_wide
.begin();
307 /* function which draws characters on the screen. used internally. */
308 /* x=-1 -> center horizontally */
309 int FontManager::blittext_internal(Screen
&screen
, int x
, int y
, char const *text
, bool widefont
) {
310 char *normalized
= g_utf8_normalize(text
, -1, G_NORMALIZE_ALL
);
311 gunichar
*ucs
= g_utf8_to_ucs4(normalized
, -1, NULL
, NULL
, NULL
);
314 RenderedFont
const *font
= widefont
? wide(current_color
) : narrow(current_color
);
315 int w
= font
->get_character(' ').get_width();
316 int h
= get_line_height();
321 for (int i
= 0; (c
= ucs
[i
]) != '\0'; ++i
) {
322 if (c
==GD_COLOR_SETCOLOR
)
323 i
+= 1; /* do not count; skip next char */
324 else if (c
>=0x300 && c
<0x370)
325 ; /* do not count, diacritical. */
327 len
++; /* count char */
329 x
= screen
.get_width()/2 - (w
*len
)/2;
334 for (int i
= 0; (c
= ucs
[i
]) != '\0'; ++i
) {
335 if (c
>=0x300 && c
<0x370) {
336 // unicode diacritical mark block
339 screen
.blit(font
->get_character(GD_ACUTE_CHAR
), xc
-w
, y
);
342 screen
.blit(font
->get_character(GD_UMLAUT_CHAR
), xc
-w
, y
);
345 screen
.blit(font
->get_character(GD_DOUBLE_ACUTE_CHAR
), xc
-w
, y
);
350 /* color change "request", next character is a gdash color code */
351 if (c
==GD_COLOR_SETCOLOR
) {
354 /* 64 was added in colors.hpp, now subtract it */
356 current_color
= GdColor::from_gdash_index(c
);
357 font
= widefont
? wide(current_color
) : narrow(current_color
);
362 /* some unicode hack - substitutions */
364 case 0x2018: c
='\''; break; /* left single quotation mark */
365 case 0x2019: c
='\''; break; /* right single quotation mark */
366 case 0x201A: c
=','; break; /* low single comma quotation mark */
367 case 0x201B: c
='\''; break; /* high-reversed-9 quotation mark */
368 case 0x201C: c
='\"'; break; /* left double quotation mark */
369 case 0x201D: c
='\"'; break; /* right double quotation mark */
370 case 0x201E: c
='\"'; break; /* low double quotation mark */
371 case 0x201F: c
='\"'; break; /* double reversed comma quotation mark */
372 case 0x2032: c
='\''; break; /* prime */
373 case 0x2033: c
='\"'; break; /* double prime */
374 case 0x2034: c
='\"'; break; /* triple prime */
375 case 0x2035: c
='\''; break; /* reversed prime */
376 case 0x2036: c
='\"'; break; /* reversed double prime */
377 case 0x2037: c
='\"'; break; /* reversed triple prime */
378 case 0x2039: c
='<'; break; /* single left-pointing angle quotation mark */
379 case 0x203A: c
='>'; break; /* single right-pointing angle quotation mark */
383 /* if it is an enter */
389 if (c
<RenderedFont::NUM_OF_CHARS
)
394 screen
.blit(font
->get_character(i
), xc
, y
);
403 void FontManager::clear() {
404 for (container::iterator it
=_narrow
.begin(); it
!=_narrow
.end(); ++it
)
407 for (container::iterator it
=_wide
.begin(); it
!=_wide
.end(); ++it
)
412 int FontManager::get_pixmap_scale() const {
413 return pixbuf_factory
.get_pixmap_scale();
416 int FontManager::get_font_height() const {
417 return font_size
*pixbuf_factory
.get_pixmap_scale();
420 int FontManager::get_line_height() const {
421 return (font_size
*1.4)*pixbuf_factory
.get_pixmap_scale();
424 int FontManager::get_font_width_wide() const {
425 return font_size
*2*pixbuf_factory
.get_pixmap_scale();
429 int FontManager::get_font_width_narrow() const {
430 return font_size
*pixbuf_factory
.get_pixmap_scale();