Fix a bunch of compiler warnings
[sdlpango.git] / src / SDL_Pango.c
blob62adc23d484c5188bc1ca33a6d8ccf9cbff72c41
1 /* SDL_Pango.c -- A companion library to SDL for working with Pango.
2 Copyright (C) 2004 NAKAMURA Ken'ichi
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 /*!
20 \mainpage
22 \section intro Introduction
24 Pango is the text rendering engine of GNOME 2.x. SDL_Pango connects the
25 engine to SDL. In Windows, pre-built binary package (MSI and merge module)
26 is provided.
28 \subsection dist Distribution
30 If you are a game software developer, you should know the difficulties of
31 distribution. So I will start to introduce SDL_Pango from the viewpoint
32 of distribution.
34 In Un*x, SDL_Pango is hard to use as system-independent module, because
35 it depends on fontconfig and Pango which are designed as system-singleton
36 modules. If you use SDL_Pango, your software will require those modules
37 installed to target system. If your software is shipped as shrink-wrap
38 package, it may cause much problem on your support desk. You should
39 carefully design your installation process.
41 In Windows, SDL_Pango is distributed as "merge module" which contains
42 fontconfig and Pango. Those binaries are modified as side-by-side components.
43 You should use Windows Installer and merge the module
44 on your MSI package. The merge module not only contains files, but also includes
45 custom action which must be run at installation.
47 \subsection api High-level API
49 From the viewpoint of text rendering, the heart of SDL_Pango is high-level API.
50 Other text rendering APIs, like DrawText() of Windows, font and text must be
51 specified separately. In SDL_Pango, font specification is embedded in text like
52 HTML:
54 \code
55 <span font_family="Courier New"><i>This is Courier New and italic.</i></span>
56 \endcode
58 Color, size, subscript/superscript, obliquing, weight, and other many features
59 are also available in same way.
61 \subsection i18n Internationalized Text
63 Internationalized text is another key feature. Text is specified by UTF-8. RTL
64 script (Arabic and Hebrew) and complicated rendering (Arabic, Indic and Thai) are
65 supported. You can see it with GNOME 2.x.
67 \section get Getting Started
69 \subsection getlatest Get latest files
71 Get latest files from http://sourceforge.net/projects/sdlpango/ .
73 \subsection install Install Header and Library
75 In Windows and VS2003, I strongly recommend you to install MSI package. It contains Pango
76 and fontconfig binaries which are modified as side-by-side components. It is
77 nearly impossible to build them. (I spent much time to build them...)
79 In MinGW, I recommend you to use VS2003. Otherwise you may run into the maze of
80 distribution. If you insist MinGW, you should use MinGW binary archive.
82 In Un*x, installation consists of:
84 \code
85 ./configure
86 make
87 make install
88 \endcode
90 \subsection inc Includes
92 To use SDL_Pango functions in a C/C++ source code file, you must use the SDL_Pango.h
93 include file:
95 \code
96 #include "SDL_Pango.h"
97 \endcode
99 In Windows, SDL_Pango.h is installed on \c \%ProgramFiles\%\\SDL_Pango \c Development\\include
100 (usually \c C:\\Program \c Files\\SDL_Pango \c Development\\include). You should add this
101 directory to include path.
103 \subsection comp Compiling
105 In Un*x, to link with SDL_Pango you should use sdl-config to get the required SDL
106 compilation options. After that, compiling with SDL_Pango is quite easy.
108 Note: Some systems may not have the SDL_Pango library and include file in the same
109 place as the SDL library and includes are located, in that case you will need to
110 add more -I and -L paths to these command lines.
112 Simple Example for compiling an object file:
114 \code
115 cc -c `sdl-config --cflags` mysource.c
116 \endcode
118 Simple Example for linking an object file:
120 \code
121 cc -o myprogram mysource.o `sdl-config --libs` -lSDL_Pango
122 \endcode
124 Now myprogram is ready to run.
126 You can see a sample of autoconfiscation in 'test' directory.
128 In Windows, MSI package installs many dlls to \c \%ProgramFiles\%\\SDL_Pango \c Development\\import_lib.
129 To link with SDL_Pango you should use SDL_Pango.lib.
131 SDL_Pango.dll depends on many dlls and other many files. Those dlls are installed on
132 \c \%ProgramFiles\%\\SDL_Pango \c Development\\bin. MSI package adds the directory to PATH environment
133 variable.
135 \section devel Development
137 \subsection font Font Handling
139 In Un*x, font handling depends on fontconfig of your system.
141 In Windows, local.conf of fontconfig is placed on \c \%ProgramFiles\%\\SDL_Pango \c Development\\etc\\fonts.
142 You should know about fontconfig's font cache mechanism.
144 \subsection example Step-by-step Example
146 The operation of SDL_Pango is done via context.
148 \code
149 SDLPango_Context *context = SDLPango_CreateContext();
150 \endcode
152 Specify default colors and minimum surface size.
154 \code
155 SDLPango_SetDefaultColor(context, MATRIX_TRANSPARENT_BACK_WHITE_LETTER);
156 SDLPango_SetMinimumSize(context, 640, 0);
157 \endcode
159 Set markup text.
161 \code
162 SDLPango_SetMarkup(context, "This is <i>markup</i> text.", -1);
163 \endcode
165 Now you can get the size of surface.
167 \code
168 int w = SDLPango_GetLayoutWidth(context);
169 int h = SDLPango_GetLayoutHeight(context);
170 \endcode
172 Create surface to draw.
174 \code
175 int margin_x = 10;
176 int margin_y = 10;
177 SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
178 w + margin_x * 2, h + margin_y * 2,
179 32, (Uint32)(255 << (8 * 3)), (Uint32)(255 << (8 * 2)),
180 (Uint32)(255 << (8 * 1)), 255);
181 \endcode
183 And draw on it.
185 \code
186 SDLPango_Draw(context, surface, margin_x, margin_y);
187 \endcode
189 You must free the surface by yourself.
191 \code
192 SDL_FreeSurface(surface);
193 \endcode
195 Free context.
197 \code
198 SDLPango_FreeContext(context);
199 \endcode
201 You can see actual code in \c test/testbench.cpp.
203 \subsection pack Packaging
205 In Un*x, do it yourself.
207 In Windows, font files must be installed on apprication folder (usually
208 \c C:\\Program \c Files\\[Manufacturer]\\[ProductName]). The property of
209 apprication folder must be \c TARGETDIR (this is default setting of VS2003).
210 SDL.dll also must be installed on apprication folder. Add SDL_Pango.msm to
211 your MSI package.
213 \section ack Acknowledgment
215 SDL_Pango is developed with financial assistance of Information-technology Promotion Agency, Japan.
217 - NAKAMURA Ken'ichi <nakamura@sbp.fp.a.u-tokyo.ac.jp>
221 /*! @file
222 @brief Implementation of SDL_Pango
224 @author NAKAMURA Ken'ichi
225 @date 2004/12/07
226 $Revision: 1.6 $
229 #include <pango/pango.h>
230 #include <pango/pangoft2.h>
232 #include "SDL_Pango.h"
234 //! non-zero if initialized
235 static int IS_INITIALIZED = 0;
237 #define DEFAULT_FONT_FAMILY "sans-serif"
238 #define DEFAULT_FONT_SIZE 12
239 #define DEFAULT_DPI 96
240 #define _MAKE_FONT_NAME(family, size) family " " #size
241 #define MAKE_FONT_NAME(family, size) _MAKE_FONT_NAME(family, size)
242 #define DEFAULT_DEPTH 32
243 #define DEFAULT_RMASK (Uint32)(255 << (8 * 3))
244 #define DEFAULT_GMASK (Uint32)(255 << (8 * 2))
245 #define DEFAULT_BMASK (Uint32)(255 << (8 * 1))
246 #define DEFAULT_AMASK (Uint32)255
248 static FT_Bitmap *createFTBitmap(int width, int height);
250 static void freeFTBitmap(FT_Bitmap *bitmap);
252 static void getItemProperties (
253 PangoItem *item,
254 PangoUnderline *uline,
255 gboolean *strikethrough,
256 gint *rise,
257 PangoColor *fg_color,
258 gboolean *fg_set,
259 PangoColor *bg_color,
260 gboolean *bg_set,
261 gboolean *shape_set,
262 PangoRectangle *ink_rect,
263 PangoRectangle *logical_rect);
265 static void clearFTBitmap(FT_Bitmap *bitmap);
267 typedef struct _surfaceArgs {
268 Uint32 flags;
269 int depth;
270 Uint32 Rmask;
271 Uint32 Gmask;
272 Uint32 Bmask;
273 Uint32 Amask;
274 } surfaceArgs;
276 typedef struct _contextImpl {
277 PangoContext *context;
278 PangoFontMap *font_map;
279 PangoFontDescription *font_desc;
280 PangoLayout *layout;
281 surfaceArgs surface_args;
282 FT_Bitmap *tmp_ftbitmap;
283 SDLPango_Matrix color_matrix;
284 int min_width;
285 int min_height;
286 } contextImpl;
289 const SDLPango_Matrix _MATRIX_WHITE_BACK
290 = {{{255, 0, 0, 0},
291 {255, 0, 0, 0},
292 {255, 0, 0, 0},
293 {255, 255, 0, 0}}};
296 Specifies white back and black letter.
298 const SDLPango_Matrix *MATRIX_WHITE_BACK = &_MATRIX_WHITE_BACK;
300 const SDLPango_Matrix _MATRIX_BLACK_BACK
301 = {{{0, 255, 0, 0},
302 {0, 255, 0, 0},
303 {0, 255, 0, 0},
304 {255, 255, 0, 0}}};
306 Specifies black back and white letter.
308 const SDLPango_Matrix *MATRIX_BLACK_BACK = &_MATRIX_BLACK_BACK;
310 const SDLPango_Matrix _MATRIX_TRANSPARENT_BACK_BLACK_LETTER
311 = {{{0, 0, 0, 0},
312 {0, 0, 0, 0},
313 {0, 0, 0, 0},
314 {0, 255, 0, 0}}};
316 Specifies transparent back and black letter.
318 const SDLPango_Matrix *MATRIX_TRANSPARENT_BACK_BLACK_LETTER = &_MATRIX_TRANSPARENT_BACK_BLACK_LETTER;
320 const SDLPango_Matrix _MATRIX_TRANSPARENT_BACK_WHITE_LETTER
321 = {{{255, 255, 0, 0},
322 {255, 255, 0, 0},
323 {255, 255, 0, 0},
324 {0, 255, 0, 0}}};
326 Specifies transparent back and white letter.
328 const SDLPango_Matrix *MATRIX_TRANSPARENT_BACK_WHITE_LETTER = &_MATRIX_TRANSPARENT_BACK_WHITE_LETTER;
330 const SDLPango_Matrix _MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER
331 = {{{255, 255, 0, 0},
332 {255, 255, 0, 0},
333 {255, 255, 0, 0},
334 {0, 0, 0, 0}}};
336 Specifies transparent back and transparent letter.
337 This is useful for KARAOKE like rendering.
339 const SDLPango_Matrix *MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER = &_MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER;
343 Initialize the Glib and Pango API.
344 This must be called before using other functions in this library,
345 excepting SDLPango_WasInit.
346 SDL does not have to be initialized before this call.
349 @return always 0.
352 SDLPango_Init()
354 g_type_init();
356 IS_INITIALIZED = -1;
358 return 0;
362 Query the initilization status of the Glib and Pango API.
363 You may, of course, use this before SDLPango_Init to avoid
364 initilizing twice in a row.
366 @return zero when already initialized.
367 non-zero when not initialized.
370 SDLPango_WasInit()
372 return IS_INITIALIZED;
376 Draw glyphs on rect.
378 @param *context [in] Context
379 @param *surface [out] Surface to draw on it
380 @param *color_matrix [in] Foreground and background color
381 @param *font [in] Innter variable of Pango
382 @param *glyphs [in] Innter variable of Pango
383 @param *rect [in] Draw on this area
384 @param baseline [in] Horizontal location of glyphs
386 static void
387 drawGlyphString(
388 SDLPango_Context *context,
389 SDL_Surface *surface,
390 SDLPango_Matrix *color_matrix,
391 PangoFont *font,
392 PangoGlyphString *glyphs,
393 SDL_Rect *rect,
394 int baseline)
396 pango_ft2_render(context->tmp_ftbitmap, font, glyphs, rect->x, rect->y + baseline);
398 SDLPango_CopyFTBitmapToSurface(
399 context->tmp_ftbitmap,
400 surface,
401 color_matrix,
402 rect);
404 clearFTBitmap(context->tmp_ftbitmap);
408 Draw horizontal line of a pixel.
410 @param *surface [out] Surface to draw on it
411 @param *color_matrix [in] Foreground and background color
412 @param y [in] Y location of line
413 @param start [in] Left of line
414 @param end [in] Right of line
416 static void drawHLine(
417 SDL_Surface *surface,
418 SDLPango_Matrix *color_matrix,
419 int y,
420 int start,
421 int end)
423 Uint8 *p;
424 Uint16 *p16;
425 Uint32 *p32;
426 Uint32 color;
427 int ix;
428 int pixel_bytes = surface->format->BytesPerPixel;
430 if (y < 0 || y >= surface->h)
431 return;
433 if (end <= 0 || start >= surface->w)
434 return;
436 if (start < 0)
437 start = 0;
439 if (end >= surface->w)
440 end = surface->w;
442 p = (Uint8 *)(surface->pixels) + y * surface->pitch + start * pixel_bytes;
443 color = SDL_MapRGBA(surface->format,
444 color_matrix->m[0][1],
445 color_matrix->m[1][1],
446 color_matrix->m[2][1],
447 color_matrix->m[3][1]);
449 switch(pixel_bytes) {
450 case 2:
451 p16 = (Uint16 *)p;
452 for (ix = 0; ix < end - start; ix++)
453 *p16++ = (Uint16)color;
454 break;
455 case 4:
456 p32 = (Uint32 *)p;
457 for (ix = 0; ix < end - start; ix++)
458 *p32++ = color;
459 break;
460 default:
461 SDL_SetError("surface->format->BytesPerPixel is invalid value");
462 break;
467 Draw a line.
469 @param *context [in] Context
470 @param *surface [out] Surface to draw on it
471 @param *line [in] Innter variable of Pango
472 @param x [in] X location of line
473 @param y [in] Y location of line
474 @param height [in] Height of line
475 @param baseline [in] Rise / sink of line (for super/subscript)
477 static void
478 drawLine(
479 SDLPango_Context *context,
480 SDL_Surface *surface,
481 PangoLayoutLine *line,
482 gint x,
483 gint y,
484 gint height,
485 gint baseline)
487 GSList *tmp_list = line->runs;
488 PangoColor fg_color, bg_color;
489 PangoRectangle logical_rect;
490 PangoRectangle ink_rect;
491 int x_off = 0;
493 /* only suppress warning */
494 fg_color.red = fg_color.green = fg_color.blue = 0;
495 bg_color.red = bg_color.green = bg_color.blue = 0;
497 while (tmp_list) {
498 SDLPango_Matrix color_matrix = context->color_matrix;
499 PangoUnderline uline = PANGO_UNDERLINE_NONE;
500 gboolean strike, fg_set, bg_set, shape_set;
501 gint rise, risen_y;
502 PangoLayoutRun *run = tmp_list->data;
503 SDL_Rect d_rect;
505 tmp_list = tmp_list->next;
507 getItemProperties(run->item,
508 &uline, &strike, &rise,
509 &fg_color, &fg_set, &bg_color, &bg_set,
510 &shape_set, &ink_rect, &logical_rect);
512 risen_y = y + baseline - PANGO_PIXELS (rise);
514 if(fg_set) {
515 color_matrix.m[0][1] = (Uint8)(fg_color.red >> 8);
516 color_matrix.m[1][1] = (Uint8)(fg_color.green >> 8);
517 color_matrix.m[2][1] = (Uint8)(fg_color.blue >> 8);
518 color_matrix.m[3][1] = 255;
519 if(color_matrix.m[3][0] == 0) {
520 color_matrix.m[0][0] = (Uint8)(fg_color.red >> 8);
521 color_matrix.m[1][0] = (Uint8)(fg_color.green >> 8);
522 color_matrix.m[2][0] = (Uint8)(fg_color.blue >> 8);
526 if (bg_set) {
527 color_matrix.m[0][0] = (Uint8)(bg_color.red >> 8);
528 color_matrix.m[1][0] = (Uint8)(bg_color.green >> 8);
529 color_matrix.m[2][0] = (Uint8)(bg_color.blue >> 8);
530 color_matrix.m[3][0] = 255;
533 if(! shape_set) {
534 if (uline == PANGO_UNDERLINE_NONE)
535 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
536 NULL, &logical_rect);
537 else
538 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
539 &ink_rect, &logical_rect);
541 d_rect.w = (Uint16)PANGO_PIXELS(logical_rect.width);
542 d_rect.h = (Uint16)height;
543 d_rect.x = (Uint16)(x + PANGO_PIXELS (x_off));
544 d_rect.y = (Uint16)(risen_y - baseline);
546 if((! context->tmp_ftbitmap) || d_rect.w + d_rect.x > context->tmp_ftbitmap->width
547 || d_rect.h + d_rect.y > context->tmp_ftbitmap->rows)
549 freeFTBitmap(context->tmp_ftbitmap);
550 context->tmp_ftbitmap = createFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y);
553 drawGlyphString(context, surface,
554 &color_matrix,
555 run->item->analysis.font, run->glyphs, &d_rect, baseline);
557 switch (uline) {
558 case PANGO_UNDERLINE_NONE:
559 break;
560 case PANGO_UNDERLINE_DOUBLE:
561 drawHLine(surface, &color_matrix,
562 risen_y + 4,
563 x + PANGO_PIXELS (x_off + ink_rect.x),
564 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
565 /* Fall through */
566 case PANGO_UNDERLINE_SINGLE:
567 drawHLine(surface, &color_matrix,
568 risen_y + 2,
569 x + PANGO_PIXELS (x_off + ink_rect.x),
570 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
571 break;
572 case PANGO_UNDERLINE_ERROR:
574 int point_x;
575 int counter = 0;
576 int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
578 for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
579 point_x <= end_x;
580 point_x += 2)
582 if (counter)
583 drawHLine(surface, &color_matrix,
584 risen_y + 2,
585 point_x, MIN (point_x + 1, end_x));
586 else
587 drawHLine(surface, &color_matrix,
588 risen_y + 3,
589 point_x, MIN (point_x + 1, end_x));
591 counter = (counter + 1) % 2;
594 break;
595 case PANGO_UNDERLINE_LOW:
596 drawHLine(surface, &color_matrix,
597 risen_y + PANGO_PIXELS (ink_rect.y + ink_rect.height),
598 x + PANGO_PIXELS (x_off + ink_rect.x),
599 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
600 break;
603 if (strike)
604 drawHLine(surface, &color_matrix,
605 risen_y + PANGO_PIXELS (logical_rect.y + logical_rect.height / 2),
606 x + PANGO_PIXELS (x_off + logical_rect.x),
607 x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width));
609 x_off += logical_rect.width;
614 Innter function of Pango. Stolen from GDK.
616 @param *item [in] The item to get property
617 @param *uline [out] Kind of underline
618 @param *strikethrough [out] Strike-through line
619 @param *rise [out] Rise/sink of line (for super/subscript)
620 @param *fg_color [out] Color of foreground
621 @param *fg_set [out] True if fg_color set
622 @param *bg_color [out] Color of background
623 @param *bg_set [out] True if bg_color valid
624 @param *shape_set [out] True if ink_rect and logical_rect valid
625 @param *ink_rect [out] Ink rect
626 @param *logical_rect [out] Logical rect
628 static void
629 getItemProperties (
630 PangoItem *item,
631 PangoUnderline *uline,
632 gboolean *strikethrough,
633 gint *rise,
634 PangoColor *fg_color,
635 gboolean *fg_set,
636 PangoColor *bg_color,
637 gboolean *bg_set,
638 gboolean *shape_set,
639 PangoRectangle *ink_rect,
640 PangoRectangle *logical_rect)
642 GSList *tmp_list = item->analysis.extra_attrs;
644 if (strikethrough)
645 *strikethrough = FALSE;
647 if (fg_set)
648 *fg_set = FALSE;
650 if (bg_set)
651 *bg_set = FALSE;
653 if (shape_set)
654 *shape_set = FALSE;
656 if (rise)
657 *rise = 0;
659 while (tmp_list) {
660 PangoAttribute *attr = tmp_list->data;
662 switch (attr->klass->type) {
663 case PANGO_ATTR_UNDERLINE:
664 if (uline)
665 *uline = ((PangoAttrInt *)attr)->value;
666 break;
668 case PANGO_ATTR_STRIKETHROUGH:
669 if (strikethrough)
670 *strikethrough = ((PangoAttrInt *)attr)->value;
671 break;
673 case PANGO_ATTR_FOREGROUND:
674 if (fg_color)
675 *fg_color = ((PangoAttrColor *)attr)->color;
676 if (fg_set)
677 *fg_set = TRUE;
678 break;
680 case PANGO_ATTR_BACKGROUND:
681 if (bg_color)
682 *bg_color = ((PangoAttrColor *)attr)->color;
683 if (bg_set)
684 *bg_set = TRUE;
685 break;
687 case PANGO_ATTR_SHAPE:
688 if (shape_set)
689 *shape_set = TRUE;
690 if (logical_rect)
691 *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
692 if (ink_rect)
693 *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
694 break;
696 case PANGO_ATTR_RISE:
697 if (rise)
698 *rise = ((PangoAttrInt *)attr)->value;
699 break;
701 default:
702 break;
704 tmp_list = tmp_list->next;
709 Copy bitmap to surface.
710 From (x, y)-(w, h) to (x, y)-(w, h) of rect.
712 @param *bitmap [in] Grayscale bitmap
713 @param *surface [out] Surface
714 @param *matrix [in] Foreground and background color
715 @param *rect [in] Rect to copy
717 void
718 SDLPango_CopyFTBitmapToSurface(
719 const FT_Bitmap *bitmap,
720 SDL_Surface *surface,
721 const SDLPango_Matrix *matrix,
722 SDL_Rect *rect)
724 int i;
725 Uint8 *p_ft;
726 Uint8 *p_sdl;
727 int width = rect->w;
728 int height = rect->h;
729 int x = rect->x;
730 int y = rect->y;
732 if(x < 0) {
733 width += x; x = 0;
735 if(x + width > surface->w) {
736 width = surface->w - x;
738 if(width <= 0)
739 return;
741 if(y < 0) {
742 height += y; y = 0;
744 if(y + height > surface->h) {
745 height = surface->h - y;
747 if(height <= 0)
748 return;
750 if(SDL_LockSurface(surface)) {
751 SDL_SetError("surface lock failed");
752 SDL_FreeSurface(surface);
753 return;
756 p_ft = (Uint8 *)bitmap->buffer + (bitmap->pitch * y);
757 p_sdl = (Uint8 *)surface->pixels + (surface->pitch * y);
758 for(i = 0; i < height; i ++) {
759 int k;
760 for(k = 0; k < width; k ++) {
761 /* TODO: rewrite by matrix calculation library */
762 Uint8 pixel[4]; /* 4: RGBA */
763 int n;
765 for(n = 0; n < 4; n ++) {
766 Uint16 w;
767 w = ((Uint16)matrix->m[n][0] * (256 - p_ft[k + x])) + ((Uint16)matrix->m[n][1] * p_ft[k + x]);
768 pixel[n] = (Uint8)(w >> 8);
771 switch(surface->format->BytesPerPixel) {
772 case 2:
773 ((Uint16 *)p_sdl)[k + x] = (Uint16)SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
774 break;
775 case 4:
776 ((Uint32 *)p_sdl)[k + x] = SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
777 break;
778 default:
779 SDL_SetError("surface->format->BytesPerPixel is invalid value");
780 return;
783 p_ft += bitmap->pitch;
784 p_sdl += surface->pitch;
787 SDL_UnlockSurface(surface);
791 SDLPango_Context*
792 SDLPango_CreateContext_GivenFontDesc(const char* font_desc)
794 SDLPango_Context *context = g_malloc(sizeof(SDLPango_Context));
795 G_CONST_RETURN char *charset;
797 context->font_map = pango_ft2_font_map_new ();
798 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), DEFAULT_DPI, DEFAULT_DPI);
800 context->context = pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (context->font_map));
802 g_get_charset(&charset);
803 pango_context_set_language (context->context, pango_language_from_string (charset));
804 pango_context_set_base_dir (context->context, PANGO_DIRECTION_LTR);
806 context->font_desc = pango_font_description_from_string(font_desc);
808 context->layout = pango_layout_new (context->context);
810 SDLPango_SetSurfaceCreateArgs(context, SDL_SWSURFACE | SDL_SRCALPHA, DEFAULT_DEPTH,
811 DEFAULT_RMASK, DEFAULT_GMASK, DEFAULT_BMASK, DEFAULT_AMASK);
813 context->tmp_ftbitmap = NULL;
815 context->color_matrix = *MATRIX_TRANSPARENT_BACK_BLACK_LETTER;
817 context->min_height = 0;
818 context->min_width = 0;
820 return context;
824 Create a context which contains Pango objects.
826 @return A pointer to the context as a SDLPango_Context*.
828 SDLPango_Context*
829 SDLPango_CreateContext()
831 SDLPango_CreateContext_GivenFontDesc(MAKE_FONT_NAME(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
835 Free a context.
837 @param *context [i/o] Context to be free
839 void
840 SDLPango_FreeContext(SDLPango_Context *context)
842 freeFTBitmap(context->tmp_ftbitmap);
844 g_object_unref (context->layout);
846 pango_font_description_free(context->font_desc);
848 g_object_unref(context->context);
850 g_object_unref(context->font_map);
852 g_free(context);
856 Specify Arguments when create a surface.
857 When SDL_Pango creates a surface, the arguments are used.
859 @param *context [i/o] Context
860 @param flags [in] Same as SDL_CreateRGBSurface()
861 @param depth [in] Same as SDL_CreateRGBSurface()
862 @param Rmask [in] Same as SDL_CreateRGBSurface()
863 @param Gmask [in] Same as SDL_CreateRGBSurface()
864 @param Bmask [in] Same as SDL_CreateRGBSurface()
865 @param Amask [in] Same as SDL_CreateRGBSurface()
867 void
868 SDLPango_SetSurfaceCreateArgs(
869 SDLPango_Context *context,
870 Uint32 flags,
871 int depth,
872 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
874 context->surface_args.flags = flags;
875 context->surface_args.depth = depth;
876 context->surface_args.Rmask = Rmask;
877 context->surface_args.Gmask = Gmask;
878 context->surface_args.Bmask = Bmask;
879 context->surface_args.Amask = Amask;
883 Create a surface and draw text on it.
884 The size of surface is same as lauout size.
886 @param *context [in] Context
887 @return A newly created surface
889 SDL_Surface * SDLPango_CreateSurfaceDraw(
890 SDLPango_Context *context)
892 PangoRectangle logical_rect;
893 SDL_Surface *surface;
894 int width, height;
896 pango_layout_get_extents (context->layout, NULL, &logical_rect);
897 width = PANGO_PIXELS (logical_rect.width);
898 height = PANGO_PIXELS (logical_rect.height);
899 if(width < context->min_width)
900 width = context->min_width;
901 if(height < context->min_height)
902 height = context->min_height;
904 surface = SDL_CreateRGBSurface(
905 context->surface_args.flags,
906 width, height, context->surface_args.depth,
907 context->surface_args.Rmask,
908 context->surface_args.Gmask,
909 context->surface_args.Bmask,
910 context->surface_args.Amask);
912 SDLPango_Draw(context, surface, 0, 0);
914 return surface;
918 Draw text on a existing surface.
920 @param *context [in] Context
921 @param *surface [i/o] Surface to draw on it
922 @param x [in] X of left-top of drawing area
923 @param y [in] Y of left-top of drawing area
925 void
926 SDLPango_Draw(
927 SDLPango_Context *context,
928 SDL_Surface *surface,
929 int x, int y)
931 PangoLayoutIter *iter;
932 PangoRectangle logical_rect;
933 int width, height;
935 if(! surface) {
936 SDL_SetError("surface is NULL");
937 return;
940 iter = pango_layout_get_iter (context->layout);
942 pango_layout_get_extents (context->layout, NULL, &logical_rect);
943 width = PANGO_PIXELS (logical_rect.width);
944 height = PANGO_PIXELS (logical_rect.height);
946 if (width && height) {
947 SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, 0));
950 if((! context->tmp_ftbitmap) || context->tmp_ftbitmap->width < width
951 || context->tmp_ftbitmap->rows < height)
953 freeFTBitmap(context->tmp_ftbitmap);
954 context->tmp_ftbitmap = createFTBitmap(width, height);
957 do {
958 PangoLayoutLine *line;
959 int baseline;
961 line = pango_layout_iter_get_line (iter);
963 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
964 baseline = pango_layout_iter_get_baseline (iter);
966 drawLine(
967 context,
968 surface,
969 line,
970 x + PANGO_PIXELS (logical_rect.x),
971 y + PANGO_PIXELS (logical_rect.y),
972 PANGO_PIXELS (logical_rect.height),
973 PANGO_PIXELS (baseline - logical_rect.y));
974 } while (pango_layout_iter_next_line (iter));
976 pango_layout_iter_free (iter);
980 Allocate buffer and create a FTBitmap object.
982 @param width [in] Width
983 @param height [in] Height
984 @return FTBitmap object
986 static FT_Bitmap *
987 createFTBitmap(
988 int width, int height)
990 FT_Bitmap *bitmap;
991 guchar *buf;
993 bitmap = g_malloc(sizeof(FT_Bitmap));
994 bitmap->width = width;
995 bitmap->rows = height;
996 bitmap->pitch = (width + 3) & ~3;
997 bitmap->num_grays = 256;
998 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
999 buf = g_malloc (bitmap->pitch * bitmap->rows);
1000 memset (buf, 0x00, bitmap->pitch * bitmap->rows);
1001 bitmap->buffer = buf;
1003 return bitmap;
1007 Free a FTBitmap object.
1009 @param *bitmap [i/o] FTbitmap to be free
1011 static void
1012 freeFTBitmap(
1013 FT_Bitmap *bitmap)
1015 if(bitmap) {
1016 g_free(bitmap->buffer);
1017 g_free(bitmap);
1022 Clear a FTBitmap object.
1024 @param *bitmap [i/o] FTbitmap to be clear
1026 static void
1027 clearFTBitmap(
1028 FT_Bitmap *bitmap)
1030 Uint8 *p = (Uint8 *)bitmap->buffer;
1031 int length = bitmap->pitch * bitmap->rows;
1033 memset(p, 0, length);
1037 Specify minimum size of drawing rect.
1039 @param *context [i/o] Context
1040 @param width [in] Width. -1 means no wrapping mode.
1041 @param height [in] Height. zero/minus value means non-specified.
1043 void
1044 SDLPango_SetMinimumSize(
1045 SDLPango_Context *context,
1046 int width, int height)
1048 int pango_width;
1049 if(width > 0)
1050 pango_width = width * PANGO_SCALE;
1051 else
1052 pango_width = -1;
1053 pango_layout_set_width(context->layout, pango_width);
1055 context->min_width = width;
1056 context->min_height = height;
1060 Specify default color.
1062 @param *context [i/o] Context
1063 @param *color_matrix [in] Foreground and background color
1065 void
1066 SDLPango_SetDefaultColor(
1067 SDLPango_Context *context,
1068 const SDLPango_Matrix *color_matrix)
1070 context->color_matrix = *color_matrix;
1074 Get layout width.
1076 @param *context [in] Context
1077 @return Width
1080 SDLPango_GetLayoutWidth(
1081 SDLPango_Context *context)
1083 PangoRectangle logical_rect;
1085 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1087 return PANGO_PIXELS (logical_rect.width);
1091 Get layout height.
1093 @param *context [in] Context
1094 @return Height
1097 SDLPango_GetLayoutHeight(
1098 SDLPango_Context *context)
1100 PangoRectangle logical_rect;
1102 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1104 return PANGO_PIXELS (logical_rect.height);
1108 Set markup text to context.
1109 Text must be utf-8.
1110 Markup format is same as pango.
1112 @param *context [i/o] Context
1113 @param *markup [in] Markup text
1114 @param length [in] Text length. -1 means NULL-terminated text.
1116 void
1117 SDLPango_SetMarkup(
1118 SDLPango_Context *context,
1119 const char *markup,
1120 int length)
1122 pango_layout_set_markup (context->layout, markup, length);
1123 pango_layout_set_auto_dir (context->layout, TRUE);
1124 pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
1125 pango_layout_set_font_description (context->layout, context->font_desc);
1128 void
1129 SDLPango_SetText_GivenAlignment(
1130 SDLPango_Context *context,
1131 const char *text,
1132 int length,
1133 SDLPango_Alignment alignment)
1135 pango_layout_set_attributes(context->layout, NULL);
1136 pango_layout_set_text (context->layout, text, length);
1137 pango_layout_set_auto_dir (context->layout, TRUE);
1138 pango_layout_set_alignment (context->layout, alignment);
1139 pango_layout_set_font_description (context->layout, context->font_desc);
1143 Set plain text to context.
1144 Text must be utf-8.
1146 @param *context [i/o] Context
1147 @param *text [in] Plain text
1148 @param length [in] Text length. -1 means NULL-terminated text.
1150 void
1151 SDLPango_SetText(
1152 SDLPango_Context *context,
1153 const char *text,
1154 int length)
1156 SDLPango_SetText_GivenAlignment(context, text, length, SDLPANGO_ALIGN_LEFT);
1160 Set DPI to context.
1162 @param *context [i/o] Context
1163 @param dpi_x [in] X dpi
1164 @param dpi_y [in] Y dpi
1166 void
1167 SDLPango_SetDpi(
1168 SDLPango_Context *context,
1169 double dpi_x, double dpi_y)
1171 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), dpi_x, dpi_y);
1175 Set language to context.
1177 @param *context [i/o] Context
1178 @param *language_tag [in] A RFC-3066 format language tag
1180 void SDLCALL SDLPango_SetLanguage(
1181 SDLPango_Context *context,
1182 const char *language_tag)
1184 pango_context_set_language (context->context, pango_language_from_string (language_tag));
1188 Set base direction to context.
1190 @param *context [i/o] Context
1191 @param direction [in] Direction
1193 void SDLCALL SDLPango_SetBaseDirection(
1194 SDLPango_Context *context,
1195 SDLPango_Direction direction)
1197 PangoDirection pango_dir;
1199 switch(direction) {
1200 case SDLPANGO_DIRECTION_LTR:
1201 pango_dir = PANGO_DIRECTION_LTR;
1202 break;
1203 case SDLPANGO_DIRECTION_RTL:
1204 pango_dir = PANGO_DIRECTION_RTL;
1205 break;
1206 case SDLPANGO_DIRECTION_WEAK_LTR:
1207 pango_dir = PANGO_DIRECTION_WEAK_LTR;
1208 break;
1209 case SDLPANGO_DIRECTION_WEAK_RTL:
1210 pango_dir = PANGO_DIRECTION_WEAK_RTL;
1211 break;
1212 case SDLPANGO_DIRECTION_NEUTRAL:
1213 pango_dir = PANGO_DIRECTION_NEUTRAL;
1214 break;
1215 default:
1216 SDL_SetError("unknown direction value");
1217 return;
1220 pango_context_set_base_dir (context->context, pango_dir);
1224 Get font map from context.
1226 @param *context [in] Context
1227 @return Font map
1229 PangoFontMap* SDLCALL SDLPango_GetPangoFontMap(
1230 SDLPango_Context *context)
1232 return context->font_map;
1236 Get font description from context.
1238 @param *context [in] Context
1239 @return Font description
1241 PangoFontDescription* SDLCALL SDLPango_GetPangoFontDescription(
1242 SDLPango_Context *context)
1244 return context->font_desc;
1248 Get layout from context.
1250 @param *context [in] Context
1251 @return Layout
1253 PangoLayout* SDLCALL SDLPango_GetPangoLayout(
1254 SDLPango_Context *context)
1256 return context->layout;