Fix a blit overflow if rect->x or rect->y < 0
[sdlpango.git] / src / SDL_Pango.c
blob590924a2d6538ce6fad165c0e89120ccc2f508b7
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 while (tmp_list) {
494 SDLPango_Matrix color_matrix = context->color_matrix;
495 PangoUnderline uline = PANGO_UNDERLINE_NONE;
496 gboolean strike, fg_set, bg_set, shape_set;
497 gint rise, risen_y;
498 PangoLayoutRun *run = tmp_list->data;
499 SDL_Rect d_rect;
501 tmp_list = tmp_list->next;
503 getItemProperties(run->item,
504 &uline, &strike, &rise,
505 &fg_color, &fg_set, &bg_color, &bg_set,
506 &shape_set, &ink_rect, &logical_rect);
508 risen_y = y + baseline - PANGO_PIXELS (rise);
510 if(fg_set) {
511 color_matrix.m[0][1] = (Uint8)(fg_color.red >> 8);
512 color_matrix.m[1][1] = (Uint8)(fg_color.green >> 8);
513 color_matrix.m[2][1] = (Uint8)(fg_color.blue >> 8);
514 color_matrix.m[3][1] = 255;
515 if(color_matrix.m[3][0] == 0) {
516 color_matrix.m[0][0] = (Uint8)(fg_color.red >> 8);
517 color_matrix.m[1][0] = (Uint8)(fg_color.green >> 8);
518 color_matrix.m[2][0] = (Uint8)(fg_color.blue >> 8);
522 if (bg_set) {
523 color_matrix.m[0][0] = (Uint8)(bg_color.red >> 8);
524 color_matrix.m[1][0] = (Uint8)(bg_color.green >> 8);
525 color_matrix.m[2][0] = (Uint8)(bg_color.blue >> 8);
526 color_matrix.m[3][0] = 255;
529 if(! shape_set) {
530 if (uline == PANGO_UNDERLINE_NONE)
531 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
532 NULL, &logical_rect);
533 else
534 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
535 &ink_rect, &logical_rect);
537 d_rect.w = (Uint16)PANGO_PIXELS(logical_rect.width);
538 d_rect.h = (Uint16)height;
539 d_rect.x = (Uint16)(x + PANGO_PIXELS (x_off));
540 d_rect.y = (Uint16)(risen_y - baseline);
542 if((! context->tmp_ftbitmap) || d_rect.w + d_rect.x > context->tmp_ftbitmap->width
543 || d_rect.h + d_rect.y > context->tmp_ftbitmap->rows)
545 freeFTBitmap(context->tmp_ftbitmap);
546 context->tmp_ftbitmap = createFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y);
549 drawGlyphString(context, surface,
550 &color_matrix,
551 run->item->analysis.font, run->glyphs, &d_rect, baseline);
553 switch (uline) {
554 case PANGO_UNDERLINE_NONE:
555 break;
556 case PANGO_UNDERLINE_DOUBLE:
557 drawHLine(surface, &color_matrix,
558 risen_y + 4,
559 x + PANGO_PIXELS (x_off + ink_rect.x),
560 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
561 /* Fall through */
562 case PANGO_UNDERLINE_SINGLE:
563 drawHLine(surface, &color_matrix,
564 risen_y + 2,
565 x + PANGO_PIXELS (x_off + ink_rect.x),
566 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
567 break;
568 case PANGO_UNDERLINE_ERROR:
570 int point_x;
571 int counter = 0;
572 int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
574 for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
575 point_x <= end_x;
576 point_x += 2)
578 if (counter)
579 drawHLine(surface, &color_matrix,
580 risen_y + 2,
581 point_x, MIN (point_x + 1, end_x));
582 else
583 drawHLine(surface, &color_matrix,
584 risen_y + 3,
585 point_x, MIN (point_x + 1, end_x));
587 counter = (counter + 1) % 2;
590 break;
591 case PANGO_UNDERLINE_LOW:
592 drawHLine(surface, &color_matrix,
593 risen_y + PANGO_PIXELS (ink_rect.y + ink_rect.height),
594 x + PANGO_PIXELS (x_off + ink_rect.x),
595 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
596 break;
599 if (strike)
600 drawHLine(surface, &color_matrix,
601 risen_y + PANGO_PIXELS (logical_rect.y + logical_rect.height / 2),
602 x + PANGO_PIXELS (x_off + logical_rect.x),
603 x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width));
605 x_off += logical_rect.width;
610 Innter function of Pango. Stolen from GDK.
612 @param *item [in] The item to get property
613 @param *uline [out] Kind of underline
614 @param *strikethrough [out] Strike-through line
615 @param *rise [out] Rise/sink of line (for super/subscript)
616 @param *fg_color [out] Color of foreground
617 @param *fg_set [out] True if fg_color set
618 @param *bg_color [out] Color of background
619 @param *bg_set [out] True if bg_color valid
620 @param *shape_set [out] True if ink_rect and logical_rect valid
621 @param *ink_rect [out] Ink rect
622 @param *logical_rect [out] Logical rect
624 static void
625 getItemProperties (
626 PangoItem *item,
627 PangoUnderline *uline,
628 gboolean *strikethrough,
629 gint *rise,
630 PangoColor *fg_color,
631 gboolean *fg_set,
632 PangoColor *bg_color,
633 gboolean *bg_set,
634 gboolean *shape_set,
635 PangoRectangle *ink_rect,
636 PangoRectangle *logical_rect)
638 GSList *tmp_list = item->analysis.extra_attrs;
640 if (strikethrough)
641 *strikethrough = FALSE;
643 if (fg_set)
644 *fg_set = FALSE;
646 if (bg_set)
647 *bg_set = FALSE;
649 if (shape_set)
650 *shape_set = FALSE;
652 if (rise)
653 *rise = 0;
655 while (tmp_list) {
656 PangoAttribute *attr = tmp_list->data;
658 switch (attr->klass->type) {
659 case PANGO_ATTR_UNDERLINE:
660 if (uline)
661 *uline = ((PangoAttrInt *)attr)->value;
662 break;
664 case PANGO_ATTR_STRIKETHROUGH:
665 if (strikethrough)
666 *strikethrough = ((PangoAttrInt *)attr)->value;
667 break;
669 case PANGO_ATTR_FOREGROUND:
670 if (fg_color)
671 *fg_color = ((PangoAttrColor *)attr)->color;
672 if (fg_set)
673 *fg_set = TRUE;
674 break;
676 case PANGO_ATTR_BACKGROUND:
677 if (bg_color)
678 *bg_color = ((PangoAttrColor *)attr)->color;
679 if (bg_set)
680 *bg_set = TRUE;
681 break;
683 case PANGO_ATTR_SHAPE:
684 if (shape_set)
685 *shape_set = TRUE;
686 if (logical_rect)
687 *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
688 if (ink_rect)
689 *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
690 break;
692 case PANGO_ATTR_RISE:
693 if (rise)
694 *rise = ((PangoAttrInt *)attr)->value;
695 break;
697 default:
698 break;
700 tmp_list = tmp_list->next;
705 Copy bitmap to surface.
706 From (x, y)-(w, h) to (x, y)-(w, h) of rect.
708 @param *bitmap [in] Grayscale bitmap
709 @param *surface [out] Surface
710 @param *matrix [in] Foreground and background color
711 @param *rect [in] Rect to copy
713 void
714 SDLPango_CopyFTBitmapToSurface(
715 const FT_Bitmap *bitmap,
716 SDL_Surface *surface,
717 const SDLPango_Matrix *matrix,
718 SDL_Rect *rect)
720 int i;
721 Uint8 *p_ft;
722 Uint8 *p_sdl;
723 int width = rect->w;
724 int height = rect->h;
725 int x = rect->x;
726 int y = rect->y;
728 if(x < 0) {
729 width += x; x = 0;
731 if(x + width > surface->w) {
732 width = surface->w - x;
734 if(width <= 0)
735 return;
737 if(y < 0) {
738 height += y; y = 0;
740 if(y + height > surface->h) {
741 height = surface->h - y;
743 if(height <= 0)
744 return;
746 if(SDL_LockSurface(surface)) {
747 SDL_SetError("surface lock failed");
748 SDL_FreeSurface(surface);
749 return;
752 p_ft = (Uint8 *)bitmap->buffer + (bitmap->pitch * y);
753 p_sdl = (Uint8 *)surface->pixels + (surface->pitch * y);
754 for(i = 0; i < height; i ++) {
755 int k;
756 for(k = 0; k < width; k ++) {
757 /* TODO: rewrite by matrix calculation library */
758 Uint8 pixel[4]; /* 4: RGBA */
759 int n;
761 for(n = 0; n < 4; n ++) {
762 Uint16 w;
763 w = ((Uint16)matrix->m[n][0] * (256 - p_ft[k + x])) + ((Uint16)matrix->m[n][1] * p_ft[k + x]);
764 pixel[n] = (Uint8)(w >> 8);
767 switch(surface->format->BytesPerPixel) {
768 case 2:
769 ((Uint16 *)p_sdl)[k + x] = (Uint16)SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
770 break;
771 case 4:
772 ((Uint32 *)p_sdl)[k + x] = SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
773 break;
774 default:
775 SDL_SetError("surface->format->BytesPerPixel is invalid value");
776 return;
779 p_ft += bitmap->pitch;
780 p_sdl += surface->pitch;
783 SDL_UnlockSurface(surface);
787 SDLPango_Context*
788 SDLPango_CreateContext_GivenFontDesc(const char* font_desc)
790 SDLPango_Context *context = g_malloc(sizeof(SDLPango_Context));
791 G_CONST_RETURN char *charset;
793 context->font_map = pango_ft2_font_map_new ();
794 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), DEFAULT_DPI, DEFAULT_DPI);
796 context->context = pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (context->font_map));
798 g_get_charset(&charset);
799 pango_context_set_language (context->context, pango_language_from_string (charset));
800 pango_context_set_base_dir (context->context, PANGO_DIRECTION_LTR);
802 context->font_desc = pango_font_description_from_string(font_desc);
804 context->layout = pango_layout_new (context->context);
806 SDLPango_SetSurfaceCreateArgs(context, SDL_SWSURFACE | SDL_SRCALPHA, DEFAULT_DEPTH,
807 DEFAULT_RMASK, DEFAULT_GMASK, DEFAULT_BMASK, DEFAULT_AMASK);
809 context->tmp_ftbitmap = NULL;
811 context->color_matrix = *MATRIX_TRANSPARENT_BACK_BLACK_LETTER;
813 context->min_height = 0;
814 context->min_width = 0;
816 return context;
820 Create a context which contains Pango objects.
822 @return A pointer to the context as a SDLPango_Context*.
824 SDLPango_Context*
825 SDLPango_CreateContext()
827 SDLPango_CreateContext_GivenFontDesc(MAKE_FONT_NAME(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
831 Free a context.
833 @param *context [i/o] Context to be free
835 void
836 SDLPango_FreeContext(SDLPango_Context *context)
838 freeFTBitmap(context->tmp_ftbitmap);
840 g_object_unref (context->layout);
842 pango_font_description_free(context->font_desc);
844 g_object_unref(context->context);
846 g_object_unref(context->font_map);
848 g_free(context);
852 Specify Arguments when create a surface.
853 When SDL_Pango creates a surface, the arguments are used.
855 @param *context [i/o] Context
856 @param flags [in] Same as SDL_CreateRGBSurface()
857 @param depth [in] Same as SDL_CreateRGBSurface()
858 @param Rmask [in] Same as SDL_CreateRGBSurface()
859 @param Gmask [in] Same as SDL_CreateRGBSurface()
860 @param Bmask [in] Same as SDL_CreateRGBSurface()
861 @param Amask [in] Same as SDL_CreateRGBSurface()
863 void
864 SDLPango_SetSurfaceCreateArgs(
865 SDLPango_Context *context,
866 Uint32 flags,
867 int depth,
868 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
870 context->surface_args.flags = flags;
871 context->surface_args.depth = depth;
872 context->surface_args.Rmask = Rmask;
873 context->surface_args.Gmask = Gmask;
874 context->surface_args.Bmask = Bmask;
875 context->surface_args.Amask = Amask;
879 Create a surface and draw text on it.
880 The size of surface is same as lauout size.
882 @param *context [in] Context
883 @return A newly created surface
885 SDL_Surface * SDLPango_CreateSurfaceDraw(
886 SDLPango_Context *context)
888 PangoRectangle logical_rect;
889 SDL_Surface *surface;
890 int width, height;
892 pango_layout_get_extents (context->layout, NULL, &logical_rect);
893 width = PANGO_PIXELS (logical_rect.width);
894 height = PANGO_PIXELS (logical_rect.height);
895 if(width < context->min_width)
896 width = context->min_width;
897 if(height < context->min_height)
898 height = context->min_height;
900 surface = SDL_CreateRGBSurface(
901 context->surface_args.flags,
902 width, height, context->surface_args.depth,
903 context->surface_args.Rmask,
904 context->surface_args.Gmask,
905 context->surface_args.Bmask,
906 context->surface_args.Amask);
908 SDLPango_Draw(context, surface, 0, 0);
910 return surface;
914 Draw text on a existing surface.
916 @param *context [in] Context
917 @param *surface [i/o] Surface to draw on it
918 @param x [in] X of left-top of drawing area
919 @param y [in] Y of left-top of drawing area
921 void
922 SDLPango_Draw(
923 SDLPango_Context *context,
924 SDL_Surface *surface,
925 int x, int y)
927 PangoLayoutIter *iter;
928 PangoRectangle logical_rect;
929 int width, height;
931 if(! surface) {
932 SDL_SetError("surface is NULL");
933 return;
936 iter = pango_layout_get_iter (context->layout);
938 pango_layout_get_extents (context->layout, NULL, &logical_rect);
939 width = PANGO_PIXELS (logical_rect.width);
940 height = PANGO_PIXELS (logical_rect.height);
942 if (width && height) {
943 SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, 0));
946 if((! context->tmp_ftbitmap) || context->tmp_ftbitmap->width < width
947 || context->tmp_ftbitmap->rows < height)
949 freeFTBitmap(context->tmp_ftbitmap);
950 context->tmp_ftbitmap = createFTBitmap(width, height);
953 do {
954 PangoLayoutLine *line;
955 int baseline;
957 line = pango_layout_iter_get_line (iter);
959 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
960 baseline = pango_layout_iter_get_baseline (iter);
962 drawLine(
963 context,
964 surface,
965 line,
966 x + PANGO_PIXELS (logical_rect.x),
967 y + PANGO_PIXELS (logical_rect.y),
968 PANGO_PIXELS (logical_rect.height),
969 PANGO_PIXELS (baseline - logical_rect.y));
970 } while (pango_layout_iter_next_line (iter));
972 pango_layout_iter_free (iter);
976 Allocate buffer and create a FTBitmap object.
978 @param width [in] Width
979 @param height [in] Height
980 @return FTBitmap object
982 static FT_Bitmap *
983 createFTBitmap(
984 int width, int height)
986 FT_Bitmap *bitmap;
987 guchar *buf;
989 bitmap = g_malloc(sizeof(FT_Bitmap));
990 bitmap->width = width;
991 bitmap->rows = height;
992 bitmap->pitch = (width + 3) & ~3;
993 bitmap->num_grays = 256;
994 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
995 buf = g_malloc (bitmap->pitch * bitmap->rows);
996 memset (buf, 0x00, bitmap->pitch * bitmap->rows);
997 bitmap->buffer = buf;
999 return bitmap;
1003 Free a FTBitmap object.
1005 @param *bitmap [i/o] FTbitmap to be free
1007 static void
1008 freeFTBitmap(
1009 FT_Bitmap *bitmap)
1011 if(bitmap) {
1012 g_free(bitmap->buffer);
1013 g_free(bitmap);
1018 Clear a FTBitmap object.
1020 @param *bitmap [i/o] FTbitmap to be clear
1022 static void
1023 clearFTBitmap(
1024 FT_Bitmap *bitmap)
1026 Uint8 *p = (Uint8 *)bitmap->buffer;
1027 int length = bitmap->pitch * bitmap->rows;
1029 memset(p, 0, length);
1033 Specify minimum size of drawing rect.
1035 @param *context [i/o] Context
1036 @param width [in] Width. -1 means no wrapping mode.
1037 @param height [in] Height. zero/minus value means non-specified.
1039 void
1040 SDLPango_SetMinimumSize(
1041 SDLPango_Context *context,
1042 int width, int height)
1044 int pango_width;
1045 if(width > 0)
1046 pango_width = width * PANGO_SCALE;
1047 else
1048 pango_width = -1;
1049 pango_layout_set_width(context->layout, pango_width);
1051 context->min_width = width;
1052 context->min_height = height;
1056 Specify default color.
1058 @param *context [i/o] Context
1059 @param *color_matrix [in] Foreground and background color
1061 void
1062 SDLPango_SetDefaultColor(
1063 SDLPango_Context *context,
1064 const SDLPango_Matrix *color_matrix)
1066 context->color_matrix = *color_matrix;
1070 Get layout width.
1072 @param *context [in] Context
1073 @return Width
1076 SDLPango_GetLayoutWidth(
1077 SDLPango_Context *context)
1079 PangoRectangle logical_rect;
1081 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1083 return PANGO_PIXELS (logical_rect.width);
1087 Get layout height.
1089 @param *context [in] Context
1090 @return Height
1093 SDLPango_GetLayoutHeight(
1094 SDLPango_Context *context)
1096 PangoRectangle logical_rect;
1098 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1100 return PANGO_PIXELS (logical_rect.height);
1104 Set markup text to context.
1105 Text must be utf-8.
1106 Markup format is same as pango.
1108 @param *context [i/o] Context
1109 @param *markup [in] Markup text
1110 @param length [in] Text length. -1 means NULL-terminated text.
1112 void
1113 SDLPango_SetMarkup(
1114 SDLPango_Context *context,
1115 const char *markup,
1116 int length)
1118 pango_layout_set_markup (context->layout, markup, length);
1119 pango_layout_set_auto_dir (context->layout, TRUE);
1120 pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
1121 pango_layout_set_font_description (context->layout, context->font_desc);
1124 void
1125 SDLPango_SetText_GivenAlignment(
1126 SDLPango_Context *context,
1127 const char *text,
1128 int length,
1129 SDLPango_Alignment alignment)
1131 pango_layout_set_attributes(context->layout, NULL);
1132 pango_layout_set_text (context->layout, text, length);
1133 pango_layout_set_auto_dir (context->layout, TRUE);
1134 pango_layout_set_alignment (context->layout, alignment);
1135 pango_layout_set_font_description (context->layout, context->font_desc);
1139 Set plain text to context.
1140 Text must be utf-8.
1142 @param *context [i/o] Context
1143 @param *text [in] Plain text
1144 @param length [in] Text length. -1 means NULL-terminated text.
1146 void
1147 SDLPango_SetText(
1148 SDLPango_Context *context,
1149 const char *text,
1150 int length)
1152 SDLPango_SetText_GivenAlignment(context, text, length, SDLPANGO_ALIGN_LEFT);
1156 Set DPI to context.
1158 @param *context [i/o] Context
1159 @param dpi_x [in] X dpi
1160 @param dpi_y [in] Y dpi
1162 void
1163 SDLPango_SetDpi(
1164 SDLPango_Context *context,
1165 double dpi_x, double dpi_y)
1167 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), dpi_x, dpi_y);
1171 Set language to context.
1173 @param *context [i/o] Context
1174 @param *language_tag [in] A RFC-3066 format language tag
1176 void SDLCALL SDLPango_SetLanguage(
1177 SDLPango_Context *context,
1178 const char *language_tag)
1180 pango_context_set_language (context->context, pango_language_from_string (language_tag));
1184 Set base direction to context.
1186 @param *context [i/o] Context
1187 @param direction [in] Direction
1189 void SDLCALL SDLPango_SetBaseDirection(
1190 SDLPango_Context *context,
1191 SDLPango_Direction direction)
1193 PangoDirection pango_dir;
1195 switch(direction) {
1196 case SDLPANGO_DIRECTION_LTR:
1197 pango_dir = PANGO_DIRECTION_LTR;
1198 break;
1199 case SDLPANGO_DIRECTION_RTL:
1200 pango_dir = PANGO_DIRECTION_RTL;
1201 break;
1202 case SDLPANGO_DIRECTION_WEAK_LTR:
1203 pango_dir = PANGO_DIRECTION_WEAK_LTR;
1204 break;
1205 case SDLPANGO_DIRECTION_WEAK_RTL:
1206 pango_dir = PANGO_DIRECTION_WEAK_RTL;
1207 break;
1208 case SDLPANGO_DIRECTION_NEUTRAL:
1209 pango_dir = PANGO_DIRECTION_NEUTRAL;
1210 break;
1211 default:
1212 SDL_SetError("unknown direction value");
1213 return;
1216 pango_context_set_base_dir (context->context, pango_dir);
1220 Get font map from context.
1222 @param *context [in] Context
1223 @return Font map
1225 PangoFontMap* SDLCALL SDLPango_GetPangoFontMap(
1226 SDLPango_Context *context)
1228 return context->font_map;
1232 Get font description from context.
1234 @param *context [in] Context
1235 @return Font description
1237 PangoFontDescription* SDLCALL SDLPango_GetPangoFontDescription(
1238 SDLPango_Context *context)
1240 return context->font_desc;
1244 Get layout from context.
1246 @param *context [in] Context
1247 @return Layout
1249 PangoLayout* SDLCALL SDLPango_GetPangoLayout(
1250 SDLPango_Context *context)
1252 return context->layout;