2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
19 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include "gfx/pixbuf.hpp"
31 #include "gfx/screen.hpp"
32 #include "gfx/pixbuffactory.hpp"
33 #include "cave/colors.hpp"
34 #include "gfx/cellrenderer.hpp"
35 #include "gfx/fontmanager.hpp"
36 #include "misc/printf.hpp"
37 #include "misc/logger.hpp"
39 #include "c64_font.cpp"
43 * @brief A RenderedFont stores glyphs rendered for a given font and a given color.
44 * This is an abstract base class, the narrow and wide font are derived from this.
48 /// Number of characters on the font map.
52 NUM_OF_CHARS
= CHARS_X
* CHARS_Y
56 /// @param bitmap_ Raw font data.
57 /// @param color_ The color of drawing.
58 /// @param pixbuf_factory The pixbuf factory used to create glyphs.
59 RenderedFont(std::vector
<unsigned char> const &bitmap_
, unsigned font_size_
, GdColor
const &color_
, Screen
&screen
);
62 virtual ~RenderedFont();
64 /// Return the pixmap for a given character; maybe after creating it.
65 /// @param j The ASCII (or GDash) code of the character
66 Pixmap
const &get_character(int j
) const;
68 /// GdColor::get_uint() code of color, for easy searching in a font manager.
73 std::vector
<unsigned char> const &bitmap
;
75 /// Font size (pixbufs)
76 unsigned int font_size
;
78 /// The Screen for which this font is rendered.
81 /// RGBA format of color in pixbufs.
84 /// RGBA format of transparent pixel in pixbufs.
87 /// The rendered glyphs are stored in this array as pixmaps.
88 mutable Pixmap
*_character
[NUM_OF_CHARS
];
90 RenderedFont(const RenderedFont
&); // not implemented
91 RenderedFont
&operator=(const RenderedFont
&); // not implemented
94 /// Render a single character. The narrow and wide fonts implement this.
95 virtual Pixmap
*render_character(int j
) const = 0;
98 class RenderedFontNarrow
: public RenderedFont
{
100 virtual Pixmap
*render_character(int j
) const;
103 RenderedFontNarrow(std::vector
<unsigned char> const &bitmap_
, unsigned font_size_
, GdColor
const &color
, Screen
&screen
)
104 : RenderedFont(bitmap_
, font_size_
, color
, screen
) {}
107 class RenderedFontWide
: public RenderedFont
{
109 virtual Pixmap
*render_character(int j
) const;
112 RenderedFontWide(std::vector
<unsigned char> const &bitmap_
, unsigned font_size_
, GdColor
const &color
, Screen
&screen
)
113 : RenderedFont(bitmap_
, font_size_
, color
, screen
) {}
117 RenderedFont::~RenderedFont() {
118 for (unsigned i
= 0; i
< NUM_OF_CHARS
; ++i
)
119 delete _character
[i
];
123 RenderedFont::RenderedFont(std::vector
<unsigned char> const &bitmap_
, unsigned font_size_
, GdColor
const &color
, Screen
&screen
)
124 : uint(color
.get_uint()),
126 font_size(font_size_
),
129 g_assert(font_size_
*font_size_
*NUM_OF_CHARS
== bitmap_
.size());
130 col
= Pixbuf::rgba_pixel_from_color(color
, 0xff); /* opaque */
131 transparent
= Pixbuf::rgba_pixel_from_color(GdColor::from_rgb(0, 0, 0), 0x00); /* transparent black */
134 Pixmap
*RenderedFontNarrow::render_character(int j
) const {
135 int y1
= (j
/ CHARS_X
) * font_size
;
136 int x1
= (j
% CHARS_X
) * font_size
;
138 std::auto_ptr
<Pixbuf
> image(screen
.pixbuf_factory
.create(font_size
, font_size
));
139 for (unsigned y
= 0; y
< font_size
; y
++) {
140 guint32
*p
= image
->get_row(y
);
141 for (unsigned x
= 0; x
< font_size
; x
++) {
142 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
143 if (bitmap
[(y1
+ y
) * (CHARS_X
* font_size
) + x1
+ x
] != 1) /* 1 is black there!! */
144 p
[x
] = col
; /* normal */
146 p
[x
] = transparent
; /* normal */
149 return screen
.create_scaled_pixmap_from_pixbuf(*image
, true);
152 Pixmap
*RenderedFontWide::render_character(int j
) const {
153 int y1
= (j
/ CHARS_X
) * font_size
;
154 int x1
= (j
% CHARS_X
) * font_size
;
156 std::auto_ptr
<Pixbuf
> image(screen
.pixbuf_factory
.create(font_size
* 2, font_size
));
157 for (unsigned y
= 0; y
< font_size
; y
++) {
158 guint32
*p
= image
->get_row(y
);
159 for (unsigned x
= 0; x
< font_size
; x
++) {
160 /* the font array is encoded the same way as a c64-colored pixbuf. see c64_gfx_data...() */
161 if (bitmap
[(y1
+ y
) * (CHARS_X
* font_size
) + x1
+ x
] != 1) { /* 1 is black there!! */
162 p
[2 * x
+ 0] = col
; /* normal */
165 p
[2 * x
+ 0] = transparent
; /* normal */
166 p
[2 * x
+ 1] = transparent
; /* normal */
170 return screen
.create_scaled_pixmap_from_pixbuf(*image
, true);
173 Pixmap
const &RenderedFont::get_character(int j
) const {
174 g_assert(j
< NUM_OF_CHARS
);
175 if (_character
[j
] == NULL
)
176 _character
[j
] = render_character(j
);
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
));
190 return true; /* passed checks */
193 bool FontManager::is_image_ok_for_theme(PixbufFactory
&pixbuf_factory
, const char *filename
) {
195 Pixbuf
*image
= pixbuf_factory
.create_from_file(filename
);
196 /* if the image is loaded */
197 SetLoggerContextForFunction
scf(filename
);
198 bool result
= is_pixbuf_ok_for_theme(*image
);
206 bool FontManager::loadfont_image(Pixbuf
const &image
) {
207 if (!is_pixbuf_ok_for_theme(image
))
211 font
= Pixbuf::c64_gfx_data_from_pixbuf(image
);
212 font_size
= image
.get_width() / RenderedFont::CHARS_X
;
216 /* load theme from image file. */
217 /* return true if successful. */
218 bool FontManager::loadfont_file(const std::string
&filename
) {
219 /* load cell graphics */
222 Pixbuf
*image
= screen
.pixbuf_factory
.create_from_file(filename
.c_str());
223 bool result
= loadfont_image(*image
);
226 gd_critical(CPrintf("%s: invalid font bitmap") % filename
);
228 } catch (std::exception
&e
) {
229 gd_critical(CPrintf("%s: unable to load image (%s)") % filename
% e
.what());
234 /* load the theme from the given file. */
235 /* if successful, ok. */
236 /* if fails, or no theme specified, load the builtin */
237 void FontManager::load_theme(const std::string
&theme_file
) {
238 if (theme_file
!= "" && loadfont_file(theme_file
)) {
239 /* loaded from png file */
241 Pixbuf
*image
= screen
.pixbuf_factory
.create_from_inline(sizeof(c64_font
), c64_font
);
242 bool result
= loadfont_image(*image
);
243 g_assert(result
== true); // to check the builting font
248 FontManager::FontManager(Screen
&screen
, const std::string
&theme_file
)
250 PixmapStorage(screen
),
251 current_color(GD_GDASH_WHITE
),
253 load_theme(theme_file
);
256 FontManager::~FontManager() {
260 struct FindRenderedFont
{
262 FindRenderedFont(guint32 uint_
): uint(uint_
) {}
263 bool operator()(const RenderedFont
*font
) const {
264 return font
->uint
== uint
;
268 RenderedFont
*FontManager::narrow(const GdColor
&c
) {
270 container::iterator it
= find_if(_narrow
.begin(), _narrow
.end(), FindRenderedFont(c
.get_uint()));
271 if (it
== _narrow
.end()) {
272 // if not found, create it
273 RenderedFont
*newfont
= new RenderedFontNarrow(font
, font_size
, c
, screen
);
274 _narrow
.push_front(newfont
);
275 // if list became too long, remove one from the end
276 if (_narrow
.size() > 8) {
277 delete _narrow
.back();
281 // put the font found to the beginning of the list
282 std::swap(*_narrow
.begin(), *it
);
284 return *_narrow
.begin();
287 RenderedFont
*FontManager::wide(const GdColor
&c
) {
289 container::iterator it
= find_if(_wide
.begin(), _wide
.end(), FindRenderedFont(c
.get_uint()));
290 if (it
== _wide
.end()) {
291 // if not found, create it
292 RenderedFont
*newfont
= new RenderedFontWide(font
, font_size
, c
, screen
);
293 _wide
.push_front(newfont
);
294 // if list became too long, remove one from the end
295 if (_wide
.size() > 8) {
300 // put the font found to the beginning of the list
301 std::swap(*_wide
.begin(), *it
);
303 return *_wide
.begin();
306 /* function which draws characters on the screen. used internally. */
307 /* x=-1 -> center horizontally */
308 int FontManager::blittext_internal(int x
, int y
, char const *text
, bool widefont
) {
309 char *normalized
= g_utf8_normalize(text
, -1, G_NORMALIZE_ALL
);
310 gunichar
*ucs
= g_utf8_to_ucs4(normalized
, -1, NULL
, NULL
, NULL
);
313 RenderedFont
const *font
= widefont
? wide(current_color
) : narrow(current_color
);
314 int w
= font
->get_character(' ').get_width();
315 int h
= get_line_height();
320 for (int i
= 0; (c
= ucs
[i
]) != '\0'; ++i
) {
321 if (c
== GD_COLOR_SETCOLOR
)
322 i
+= 1; /* do not count; skip next char */
323 else if (c
>= 0x300 && c
< 0x370)
324 ; /* do not count, diacritical. */
326 len
++; /* count char */
328 x
= screen
.get_width() / 2 - (w
* len
) / 2;
333 for (int i
= 0; (c
= ucs
[i
]) != '\0'; ++i
) {
334 if (c
>= 0x300 && c
< 0x370) {
335 // unicode diacritical mark block
338 screen
.blit(font
->get_character(GD_ACUTE_CHAR
), xc
- w
, y
);
341 screen
.blit(font
->get_character(GD_UMLAUT_CHAR
), xc
- w
, y
);
344 screen
.blit(font
->get_character(GD_DOUBLE_ACUTE_CHAR
), xc
- w
, y
);
349 /* color change "request", next character is a gdash color code */
350 if (c
== GD_COLOR_SETCOLOR
) {
353 /* 64 was added in colors.hpp, now subtract it */
355 current_color
= GdColor::from_gdash_index(c
);
356 font
= widefont
? wide(current_color
) : narrow(current_color
);
361 /* some unicode hack - substitutions */
365 break; /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
368 break; /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
374 break; /* non-breaking hyphen */
377 break; /* figure dash */
386 break; /* horizontal bar */
389 break; /* left single quotation mark */
392 break; /* right single quotation mark */
395 break; /* low single comma quotation mark */
398 break; /* high-reversed-9 quotation mark */
401 break; /* left double quotation mark */
404 break; /* right double quotation mark */
407 break; /* low double quotation mark */
410 break; /* double reversed comma quotation mark */
416 break; /* double prime */
419 break; /* triple prime */
422 break; /* reversed prime */
425 break; /* reversed double prime */
428 break; /* reversed triple prime */
431 break; /* single left-pointing angle quotation mark */
434 break; /* single right-pointing angle quotation mark */
437 if (c
== '\n') { /* if it is an enter */
441 if (c
== '\t') { /* if it a tabulator */
444 } while ((xc
- x
) / w
% 8 != 0);
448 if (c
< RenderedFont::NUM_OF_CHARS
)
453 screen
.blit(font
->get_character(i
), xc
, y
);
462 void FontManager::clear() {
463 for (container::iterator it
= _narrow
.begin(); it
!= _narrow
.end(); ++it
)
466 for (container::iterator it
= _wide
.begin(); it
!= _wide
.end(); ++it
)
471 void FontManager::release_pixmaps() {
475 int FontManager::get_font_height() const {
476 return font_size
* screen
.get_pixmap_scale();
479 int FontManager::get_line_height() const {
480 return (font_size
* 1.4) * screen
.get_pixmap_scale();
483 int FontManager::get_font_width_wide() const {
484 return font_size
* 2 * screen
.get_pixmap_scale();
488 int FontManager::get_font_width_narrow() const {
489 return font_size
* screen
.get_pixmap_scale();