1 /* SDL_Pango.c -- A companion library to SDL for working with Pango.
2 Copyright (C) 2004 NAKAMURA Ken'ichi
3
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.
8
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.
13
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.
17 */
18
19 /*!
20 \mainpage
21
22 \section intro Introduction
23
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.
27
28 \subsection dist Distribution
29
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.
33
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.
40
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.
46
47 \subsection api High-level API
48
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:
53
54 \code
55 <span font_family="Courier New"><i>This is Courier New and italic.</i></span>
56 \endcode
57
58 Color, size, subscript/superscript, obliquing, weight, and other many features
59 are also available in same way.
60
61 \subsection i18n Internationalized Text
62
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.
66
67 \section get Getting Started
68
69 \subsection getlatest Get latest files
70
71 Get latest files from http://sourceforge.net/projects/sdlpango/ .
72
73 \subsection install Install Header and Library
74
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...)
78
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.
81
82 In Un*x, installation consists of:
83
84 \code
85 ./configure
86 make
87 make install
88 \endcode
89
90 \subsection inc Includes
91
92 To use SDL_Pango functions in a C/C++ source code file, you must use the SDL_Pango.h
93 include file:
94
95 \code
96 #include "SDL_Pango.h"
97 \endcode
98
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.
102
103 \subsection comp Compiling
104
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.
107
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.
111
112 Simple Example for compiling an object file:
113
114 \code
115 cc -c `sdl-config --cflags` mysource.c
116 \endcode
117
118 Simple Example for linking an object file:
119
120 \code
121 cc -o myprogram mysource.o `sdl-config --libs` -lSDL_Pango
122 \endcode
123
124 Now myprogram is ready to run.
125
126 You can see a sample of autoconfiscation in 'test' directory.
127
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.
130
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.
134
135 \section devel Development
136
137 \subsection font Font Handling
138
139 In Un*x, font handling depends on fontconfig of your system.
140
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.
143
144 \subsection example Step-by-step Example
145
146 The operation of SDL_Pango is done via context.
147
148 \code
149 SDLPango_Context *context = SDLPango_CreateContext();
150 \endcode
151
152 Specify default colors and minimum surface size.
153
154 \code
155 SDLPango_SetDefaultColor(context, MATRIX_TRANSPARENT_BACK_WHITE_LETTER);
156 SDLPango_SetMinimumSize(context, 640, 0);
157 \endcode
158
159 Set markup text.
160
161 \code
162 SDLPango_SetMarkup(context, "This is <i>markup</i> text.", -1);
163 \endcode
164
165 Now you can get the size of surface.
166
167 \code
168 int w = SDLPango_GetLayoutWidth(context);
169 int h = SDLPango_GetLayoutHeight(context);
170 \endcode
171
172 Create surface to draw.
173
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
182
183 And draw on it.
184
185 \code
186 SDLPango_Draw(context, surface, margin_x, margin_y);
187 \endcode
188
189 You must free the surface by yourself.
190
191 \code
192 SDL_FreeSurface(surface);
193 \endcode
194
195 Free context.
196
197 \code
198 SDLPango_FreeContext(context);
199 \endcode
200
201 You can see actual code in \c test/testbench.cpp.
202
203 \subsection pack Packaging
204
205 In Un*x, do it yourself.
206
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.
212
213 \section ack Acknowledgment
214
215 SDL_Pango is developed with financial assistance of Information-technology Promotion Agency, Japan.
216
217 - NAKAMURA Ken'ichi <nakamura@sbp.fp.a.u-tokyo.ac.jp>
218
219 */
220
221 /*! @file
222 @brief Implementation of SDL_Pango
223
224 @author NAKAMURA Ken'ichi
225 @date 2004/12/07
226 $Revision: 1.6 $
227 */
228
229 #include <pango/pango.h>
230 #include <pango/pangoft2.h>
231
232 #include "SDL_Pango.h"
233
234 //! non-zero if initialized
235 static int IS_INITIALIZED = 0;
236
237 #define DEFAULT_FONT_FAMILY "Sans"
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
247
248 static FT_Bitmap *createFTBitmap(int width, int height);
249
250 static void freeFTBitmap(FT_Bitmap *bitmap);
251
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);
264
265 static void clearFTBitmap(FT_Bitmap *bitmap);
266
267 typedef struct _surfaceArgs {
268 Uint32 flags;
269 int depth;
270 Uint32 Rmask;
271 Uint32 Gmask;
272 Uint32 Bmask;
273 Uint32 Amask;
274 } surfaceArgs;
275
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;
287
288
289 /*!
290 Initialize the Glib and Pango API.
291 This must be called before using other functions in this library,
292 excepting SDLPango_WasInit.
293 SDL does not have to be initialized before this call.
294
295
296 @return always 0.
297 */
298 int
SDLPango_Init()299 SDLPango_Init()
300 {
301 g_type_init();
302
303 IS_INITIALIZED = -1;
304
305 return 0;
306 }
307
308 /*!
309 Query the initilization status of the Glib and Pango API.
310 You may, of course, use this before SDLPango_Init to avoid
311 initilizing twice in a row.
312
313 @return zero when already initialized.
314 non-zero when not initialized.
315 */
316 int
SDLPango_WasInit()317 SDLPango_WasInit()
318 {
319 return IS_INITIALIZED;
320 }
321
322 /*!
323 Draw glyphs on rect.
324
325 @param *context [in] Context
326 @param *surface [out] Surface to draw on it
327 @param *color_matrix [in] Foreground and background color
328 @param *font [in] Innter variable of Pango
329 @param *glyphs [in] Innter variable of Pango
330 @param *rect [in] Draw on this area
331 @param baseline [in] Horizontal location of glyphs
332 */
333 void SDLPango_CopyFTBitmapToSurface(
334 const FT_Bitmap *bitmap,
335 SDL_Surface *surface,
336 const SDLPango_Matrix *matrix,
337 SDL_Rect *rect);
338 static void
drawGlyphString(SDLPango_Context * context,SDL_Surface * surface,SDLPango_Matrix * color_matrix,PangoFont * font,PangoGlyphString * glyphs,SDL_Rect * rect,int baseline)339 drawGlyphString(
340 SDLPango_Context *context,
341 SDL_Surface *surface,
342 SDLPango_Matrix *color_matrix,
343 PangoFont *font,
344 PangoGlyphString *glyphs,
345 SDL_Rect *rect,
346 int baseline)
347 {
348 pango_ft2_render(context->tmp_ftbitmap, font, glyphs, rect->x, rect->y + baseline);
349
350 SDLPango_CopyFTBitmapToSurface(
351 context->tmp_ftbitmap,
352 surface,
353 color_matrix,
354 rect);
355
356 clearFTBitmap(context->tmp_ftbitmap);
357 }
358
359 /*!
360 Draw horizontal line of a pixel.
361
362 @param *surface [out] Surface to draw on it
363 @param *color_matrix [in] Foreground and background color
364 @param y [in] Y location of line
365 @param start [in] Left of line
366 @param end [in] Right of line
367 */
drawHLine(SDL_Surface * surface,SDLPango_Matrix * color_matrix,int y,int start,int end)368 static void drawHLine(
369 SDL_Surface *surface,
370 SDLPango_Matrix *color_matrix,
371 int y,
372 int start,
373 int end)
374 {
375 Uint8 *p;
376 Uint16 *p16;
377 Uint32 *p32;
378 Uint32 color;
379 int ix;
380 int pixel_bytes = surface->format->BytesPerPixel;
381
382 if (y < 0 || y >= surface->h)
383 return;
384
385 if (end <= 0 || start >= surface->w)
386 return;
387
388 if (start < 0)
389 start = 0;
390
391 if (end >= surface->w)
392 end = surface->w;
393
394 p = (Uint8 *)(surface->pixels) + y * surface->pitch + start * pixel_bytes;
395 color = SDL_MapRGBA(surface->format,
396 color_matrix->m[0][1],
397 color_matrix->m[1][1],
398 color_matrix->m[2][1],
399 color_matrix->m[3][1]);
400
401 switch(pixel_bytes) {
402 case 2:
403 p16 = (Uint16 *)p;
404 for (ix = 0; ix < end - start; ix++)
405 *p16++ = (Uint16)color;
406 break;
407 case 4:
408 p32 = (Uint32 *)p;
409 for (ix = 0; ix < end - start; ix++)
410 *p32++ = color;
411 break;
412 default:
413 SDL_SetError("surface->format->BytesPerPixel is invalid value");
414 break;
415 }
416 }
417
418 /*!
419 Draw a line.
420
421 @param *context [in] Context
422 @param *surface [out] Surface to draw on it
423 @param *line [in] Innter variable of Pango
424 @param x [in] X location of line
425 @param y [in] Y location of line
426 @param height [in] Height of line
427 @param baseline [in] Rise / sink of line (for super/subscript)
428 */
429 static void
drawLine(SDLPango_Context * context,SDL_Surface * surface,PangoLayoutLine * line,gint x,gint y,gint height,gint baseline)430 drawLine(
431 SDLPango_Context *context,
432 SDL_Surface *surface,
433 PangoLayoutLine *line,
434 gint x,
435 gint y,
436 gint height,
437 gint baseline)
438 {
439 GSList *tmp_list = line->runs;
440 PangoColor fg_color, bg_color;
441 PangoRectangle logical_rect;
442 PangoRectangle ink_rect;
443 int x_off = 0;
444
445 while (tmp_list) {
446 SDLPango_Matrix color_matrix = context->color_matrix;
447 PangoUnderline uline = PANGO_UNDERLINE_NONE;
448 gboolean strike, fg_set, bg_set, shape_set;
449 gint rise, risen_y;
450 PangoLayoutRun *run = tmp_list->data;
451 SDL_Rect d_rect;
452
453 tmp_list = tmp_list->next;
454
455 getItemProperties(run->item,
456 &uline, &strike, &rise,
457 &fg_color, &fg_set, &bg_color, &bg_set,
458 &shape_set, &ink_rect, &logical_rect);
459
460 risen_y = y + baseline - PANGO_PIXELS (rise);
461
462 if(fg_set) {
463 color_matrix.m[0][1] = (Uint8)(fg_color.red >> 8);
464 color_matrix.m[1][1] = (Uint8)(fg_color.green >> 8);
465 color_matrix.m[2][1] = (Uint8)(fg_color.blue >> 8);
466 color_matrix.m[3][1] = 255;
467 if(color_matrix.m[3][0] == 0) {
468 color_matrix.m[0][0] = (Uint8)(fg_color.red >> 8);
469 color_matrix.m[1][0] = (Uint8)(fg_color.green >> 8);
470 color_matrix.m[2][0] = (Uint8)(fg_color.blue >> 8);
471 }
472 }
473
474 if (bg_set) {
475 color_matrix.m[0][0] = (Uint8)(bg_color.red >> 8);
476 color_matrix.m[1][0] = (Uint8)(bg_color.green >> 8);
477 color_matrix.m[2][0] = (Uint8)(bg_color.blue >> 8);
478 color_matrix.m[3][0] = 255;
479 }
480
481 if(! shape_set) {
482 if (uline == PANGO_UNDERLINE_NONE)
483 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
484 NULL, &logical_rect);
485 else
486 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
487 &ink_rect, &logical_rect);
488
489 d_rect.w = (Uint16)PANGO_PIXELS(logical_rect.width);
490 d_rect.h = (Uint16)height;
491 d_rect.x = (Uint16)(x + PANGO_PIXELS (x_off));
492 d_rect.y = (Uint16)(risen_y - baseline);
493
494 if((! context->tmp_ftbitmap) || d_rect.w + d_rect.x > context->tmp_ftbitmap->width
495 || d_rect.h + d_rect.y > context->tmp_ftbitmap->rows)
496 {
497 freeFTBitmap(context->tmp_ftbitmap);
498 context->tmp_ftbitmap = createFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y);
499 }
500
501 drawGlyphString(context, surface,
502 &color_matrix,
503 run->item->analysis.font, run->glyphs, &d_rect, baseline);
504 }
505 switch (uline) {
506 case PANGO_UNDERLINE_NONE:
507 break;
508 case PANGO_UNDERLINE_DOUBLE:
509 drawHLine(surface, &color_matrix,
510 risen_y + 4,
511 x + PANGO_PIXELS (x_off + ink_rect.x),
512 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
513 /* Fall through */
514 case PANGO_UNDERLINE_SINGLE:
515 drawHLine(surface, &color_matrix,
516 risen_y + 2,
517 x + PANGO_PIXELS (x_off + ink_rect.x),
518 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
519 break;
520 case PANGO_UNDERLINE_ERROR:
521 {
522 int point_x;
523 int counter = 0;
524 int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
525
526 for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
527 point_x <= end_x;
528 point_x += 2)
529 {
530 if (counter)
531 drawHLine(surface, &color_matrix,
532 risen_y + 2,
533 point_x, MIN (point_x + 1, end_x));
534 else
535 drawHLine(surface, &color_matrix,
536 risen_y + 3,
537 point_x, MIN (point_x + 1, end_x));
538
539 counter = (counter + 1) % 2;
540 }
541 }
542 break;
543 case PANGO_UNDERLINE_LOW:
544 drawHLine(surface, &color_matrix,
545 risen_y + PANGO_PIXELS (ink_rect.y + ink_rect.height),
546 x + PANGO_PIXELS (x_off + ink_rect.x),
547 x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
548 break;
549 }
550
551 if (strike)
552 drawHLine(surface, &color_matrix,
553 risen_y + PANGO_PIXELS (logical_rect.y + logical_rect.height / 2),
554 x + PANGO_PIXELS (x_off + logical_rect.x),
555 x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width));
556
557 x_off += logical_rect.width;
558 }
559 }
560
561 /*!
562 Innter function of Pango. Stolen from GDK.
563
564 @param *item [in] The item to get property
565 @param *uline [out] Kind of underline
566 @param *strikethrough [out] Strike-through line
567 @param *rise [out] Rise/sink of line (for super/subscript)
568 @param *fg_color [out] Color of foreground
569 @param *fg_set [out] True if fg_color set
570 @param *bg_color [out] Color of background
571 @param *bg_set [out] True if bg_color valid
572 @param *shape_set [out] True if ink_rect and logical_rect valid
573 @param *ink_rect [out] Ink rect
574 @param *logical_rect [out] Logical rect
575 */
576 static void
getItemProperties(PangoItem * item,PangoUnderline * uline,gboolean * strikethrough,gint * rise,PangoColor * fg_color,gboolean * fg_set,PangoColor * bg_color,gboolean * bg_set,gboolean * shape_set,PangoRectangle * ink_rect,PangoRectangle * logical_rect)577 getItemProperties (
578 PangoItem *item,
579 PangoUnderline *uline,
580 gboolean *strikethrough,
581 gint *rise,
582 PangoColor *fg_color,
583 gboolean *fg_set,
584 PangoColor *bg_color,
585 gboolean *bg_set,
586 gboolean *shape_set,
587 PangoRectangle *ink_rect,
588 PangoRectangle *logical_rect)
589 {
590 GSList *tmp_list = item->analysis.extra_attrs;
591
592 if (strikethrough)
593 *strikethrough = FALSE;
594
595 if (fg_set)
596 *fg_set = FALSE;
597
598 if (bg_set)
599 *bg_set = FALSE;
600
601 if (shape_set)
602 *shape_set = FALSE;
603
604 if (rise)
605 *rise = 0;
606
607 while (tmp_list) {
608 PangoAttribute *attr = tmp_list->data;
609
610 switch (attr->klass->type) {
611 case PANGO_ATTR_UNDERLINE:
612 if (uline)
613 *uline = ((PangoAttrInt *)attr)->value;
614 break;
615
616 case PANGO_ATTR_STRIKETHROUGH:
617 if (strikethrough)
618 *strikethrough = ((PangoAttrInt *)attr)->value;
619 break;
620
621 case PANGO_ATTR_FOREGROUND:
622 if (fg_color)
623 *fg_color = ((PangoAttrColor *)attr)->color;
624 if (fg_set)
625 *fg_set = TRUE;
626 break;
627
628 case PANGO_ATTR_BACKGROUND:
629 if (bg_color)
630 *bg_color = ((PangoAttrColor *)attr)->color;
631 if (bg_set)
632 *bg_set = TRUE;
633 break;
634
635 case PANGO_ATTR_SHAPE:
636 if (shape_set)
637 *shape_set = TRUE;
638 if (logical_rect)
639 *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
640 if (ink_rect)
641 *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
642 break;
643
644 case PANGO_ATTR_RISE:
645 if (rise)
646 *rise = ((PangoAttrInt *)attr)->value;
647 break;
648
649 default:
650 break;
651 }
652 tmp_list = tmp_list->next;
653 }
654 }
655
656 /*!
657 Copy bitmap to surface.
658 From (x, y)-(w, h) to (x, y)-(w, h) of rect.
659
660 @param *bitmap [in] Grayscale bitmap
661 @param *surface [out] Surface
662 @param *matrix [in] Foreground and background color
663 @param *rect [in] Rect to copy
664 */
665 void
SDLPango_CopyFTBitmapToSurface(const FT_Bitmap * bitmap,SDL_Surface * surface,const SDLPango_Matrix * matrix,SDL_Rect * rect)666 SDLPango_CopyFTBitmapToSurface(
667 const FT_Bitmap *bitmap,
668 SDL_Surface *surface,
669 const SDLPango_Matrix *matrix,
670 SDL_Rect *rect)
671 {
672 int i;
673 Uint8 *p_ft;
674 Uint8 *p_sdl;
675 int width = rect->w;
676 int height = rect->h;
677 int x = rect->x;
678 int y = rect->y;
679
680 if(x + width > surface->w) {
681 width = surface->w - x;
682 if(width <= 0)
683 return;
684 }
685 if(y + height > surface->h) {
686 height = surface->h - y;
687 if(height <= 0)
688 return;
689 }
690
691 if(SDL_LockSurface(surface)) {
692 SDL_SetError("surface lock failed");
693 SDL_FreeSurface(surface);
694 return;
695 }
696
697 p_ft = (Uint8 *)bitmap->buffer + (bitmap->pitch * y);
698 p_sdl = (Uint8 *)surface->pixels + (surface->pitch * y);
699 for(i = 0; i < height; i ++) {
700 int k;
701 for(k = 0; k < width; k ++) {
702 /* TODO: rewrite by matrix calculation library */
703 Uint8 pixel[4]; /* 4: RGBA */
704 int n;
705
706 for(n = 0; n < 4; n ++) {
707 Uint16 w;
708 w = ((Uint16)matrix->m[n][0] * (256 - p_ft[k + x])) + ((Uint16)matrix->m[n][1] * p_ft[k + x]);
709 pixel[n] = (Uint8)(w >> 8);
710 }
711
712 switch(surface->format->BytesPerPixel) {
713 case 2:
714 ((Uint16 *)p_sdl)[k + x] = (Uint16)SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
715 break;
716 case 4:
717 ((Uint32 *)p_sdl)[k + x] = SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
718 break;
719 default:
720 SDL_SetError("surface->format->BytesPerPixel is invalid value");
721 return;
722 }
723 }
724 p_ft += bitmap->pitch;
725 p_sdl += surface->pitch;
726 }
727
728 SDL_UnlockSurface(surface);
729 }
730
731 SDLPango_Context*
SDLPango_CreateContext_GivenFontDesc(const char * font_desc)732 SDLPango_CreateContext_GivenFontDesc(const char* font_desc)
733 {
734 SDLPango_Context *context = g_malloc(sizeof(SDLPango_Context));
735 G_CONST_RETURN char *charset;
736
737 context->font_map = pango_ft2_font_map_new ();
738 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), DEFAULT_DPI, DEFAULT_DPI);
739
740 context->context = pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (context->font_map));
741
742 g_get_charset(&charset);
743 pango_context_set_language (context->context, pango_language_from_string (charset));
744 pango_context_set_base_dir (context->context, PANGO_DIRECTION_LTR);
745
746 context->font_desc = pango_font_description_from_string(font_desc);
747
748 context->layout = pango_layout_new (context->context);
749
750 SDLPango_SetSurfaceCreateArgs(context, SDL_SWSURFACE | SDL_SRCALPHA, DEFAULT_DEPTH,
751 DEFAULT_RMASK, DEFAULT_GMASK, DEFAULT_BMASK, DEFAULT_AMASK);
752
753 context->tmp_ftbitmap = NULL;
754
755 context->color_matrix = *MATRIX_TRANSPARENT_BACK_BLACK_LETTER;
756
757 context->min_height = 0;
758 context->min_width = 0;
759
760 return context;
761 }
762
763 /*!
764 Create a context which contains Pango objects.
765
766 @return A pointer to the context as a SDLPango_Context*.
767 */
768 SDLPango_Context*
SDLPango_CreateContext()769 SDLPango_CreateContext()
770 {
771 SDLPango_CreateContext_GivenFontDesc(MAKE_FONT_NAME(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
772 }
773
774 /*!
775 Free a context.
776
777 @param *context [i/o] Context to be free
778 */
779 void
SDLPango_FreeContext(SDLPango_Context * context)780 SDLPango_FreeContext(SDLPango_Context *context)
781 {
782 freeFTBitmap(context->tmp_ftbitmap);
783
784 g_object_unref (context->layout);
785
786 pango_font_description_free(context->font_desc);
787
788 g_object_unref(context->context);
789
790 g_object_unref(context->font_map);
791
792 g_free(context);
793 }
794
795 /*!
796 Specify Arguments when create a surface.
797 When SDL_Pango creates a surface, the arguments are used.
798
799 @param *context [i/o] Context
800 @param flags [in] Same as SDL_CreateRGBSurface()
801 @param depth [in] Same as SDL_CreateRGBSurface()
802 @param Rmask [in] Same as SDL_CreateRGBSurface()
803 @param Gmask [in] Same as SDL_CreateRGBSurface()
804 @param Bmask [in] Same as SDL_CreateRGBSurface()
805 @param Amask [in] Same as SDL_CreateRGBSurface()
806 */
807 void
SDLPango_SetSurfaceCreateArgs(SDLPango_Context * context,Uint32 flags,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)808 SDLPango_SetSurfaceCreateArgs(
809 SDLPango_Context *context,
810 Uint32 flags,
811 int depth,
812 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
813 {
814 context->surface_args.flags = flags;
815 context->surface_args.depth = depth;
816 context->surface_args.Rmask = Rmask;
817 context->surface_args.Gmask = Gmask;
818 context->surface_args.Bmask = Bmask;
819 context->surface_args.Amask = Amask;
820 }
821
822 /*!
823 Create a surface and draw text on it.
824 The size of surface is same as lauout size.
825
826 @param *context [in] Context
827 @return A newly created surface
828 */
SDLPango_CreateSurfaceDraw(SDLPango_Context * context)829 SDL_Surface * SDLPango_CreateSurfaceDraw(
830 SDLPango_Context *context)
831 {
832 PangoRectangle logical_rect;
833 SDL_Surface *surface;
834 int width, height;
835
836 pango_layout_get_extents (context->layout, NULL, &logical_rect);
837 width = PANGO_PIXELS (logical_rect.width);
838 height = PANGO_PIXELS (logical_rect.height);
839 if(width < context->min_width)
840 width = context->min_width;
841 if(height < context->min_height)
842 height = context->min_height;
843
844 surface = SDL_CreateRGBSurface(
845 context->surface_args.flags,
846 width, height, context->surface_args.depth,
847 context->surface_args.Rmask,
848 context->surface_args.Gmask,
849 context->surface_args.Bmask,
850 context->surface_args.Amask);
851
852 SDLPango_Draw(context, surface, 0, 0);
853
854 return surface;
855 }
856
857 /*!
858 Draw text on a existing surface.
859
860 @param *context [in] Context
861 @param *surface [i/o] Surface to draw on it
862 @param x [in] X of left-top of drawing area
863 @param y [in] Y of left-top of drawing area
864 */
865 void
SDLPango_Draw(SDLPango_Context * context,SDL_Surface * surface,int x,int y)866 SDLPango_Draw(
867 SDLPango_Context *context,
868 SDL_Surface *surface,
869 int x, int y)
870 {
871 PangoLayoutIter *iter;
872 PangoRectangle logical_rect;
873 int width, height;
874
875 if(! surface) {
876 SDL_SetError("surface is NULL");
877 return;
878 }
879
880 iter = pango_layout_get_iter (context->layout);
881
882 pango_layout_get_extents (context->layout, NULL, &logical_rect);
883 width = PANGO_PIXELS (logical_rect.width);
884 height = PANGO_PIXELS (logical_rect.height);
885
886 SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, 0));
887
888 if((! context->tmp_ftbitmap) || context->tmp_ftbitmap->width < width
889 || context->tmp_ftbitmap->rows < height)
890 {
891 freeFTBitmap(context->tmp_ftbitmap);
892 context->tmp_ftbitmap = createFTBitmap(width, height);
893 }
894
895 do {
896 PangoLayoutLine *line;
897 int baseline;
898
899 line = pango_layout_iter_get_line (iter);
900
901 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
902 baseline = pango_layout_iter_get_baseline (iter);
903
904 drawLine(
905 context,
906 surface,
907 line,
908 x + PANGO_PIXELS (logical_rect.x),
909 y + PANGO_PIXELS (logical_rect.y),
910 PANGO_PIXELS (logical_rect.height),
911 PANGO_PIXELS (baseline - logical_rect.y));
912 } while (pango_layout_iter_next_line (iter));
913
914 pango_layout_iter_free (iter);
915 }
916
917 /*!
918 Allocate buffer and create a FTBitmap object.
919
920 @param width [in] Width
921 @param height [in] Height
922 @return FTBitmap object
923 */
924 static FT_Bitmap *
createFTBitmap(int width,int height)925 createFTBitmap(
926 int width, int height)
927 {
928 FT_Bitmap *bitmap;
929 guchar *buf;
930
931 bitmap = g_malloc(sizeof(FT_Bitmap));
932 bitmap->width = width;
933 bitmap->rows = height;
934 bitmap->pitch = (width + 3) & ~3;
935 bitmap->num_grays = 256;
936 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
937 buf = g_malloc (bitmap->pitch * bitmap->rows);
938 memset (buf, 0x00, bitmap->pitch * bitmap->rows);
939 bitmap->buffer = buf;
940
941 return bitmap;
942 }
943
944 /*!
945 Free a FTBitmap object.
946
947 @param *bitmap [i/o] FTbitmap to be free
948 */
949 static void
freeFTBitmap(FT_Bitmap * bitmap)950 freeFTBitmap(
951 FT_Bitmap *bitmap)
952 {
953 if(bitmap) {
954 g_free(bitmap->buffer);
955 g_free(bitmap);
956 }
957 }
958
959 /*!
960 Clear a FTBitmap object.
961
962 @param *bitmap [i/o] FTbitmap to be clear
963 */
964 static void
clearFTBitmap(FT_Bitmap * bitmap)965 clearFTBitmap(
966 FT_Bitmap *bitmap)
967 {
968 Uint8 *p = (Uint8 *)bitmap->buffer;
969 int length = bitmap->pitch * bitmap->rows;
970
971 memset(p, 0, length);
972 }
973
974 /*!
975 Specify minimum size of drawing rect.
976
977 @param *context [i/o] Context
978 @param width [in] Width. -1 means no wrapping mode.
979 @param height [in] Height. zero/minus value means non-specified.
980 */
981 void
SDLPango_SetMinimumSize(SDLPango_Context * context,int width,int height)982 SDLPango_SetMinimumSize(
983 SDLPango_Context *context,
984 int width, int height)
985 {
986 int pango_width;
987 if(width > 0)
988 pango_width = width * PANGO_SCALE;
989 else
990 pango_width = -1;
991 pango_layout_set_width(context->layout, pango_width);
992
993 context->min_width = width;
994 context->min_height = height;
995 }
996
997 /*!
998 Specify default color.
999
1000 @param *context [i/o] Context
1001 @param *color_matrix [in] Foreground and background color
1002 */
1003 void
SDLPango_SetDefaultColor(SDLPango_Context * context,const SDLPango_Matrix * color_matrix)1004 SDLPango_SetDefaultColor(
1005 SDLPango_Context *context,
1006 const SDLPango_Matrix *color_matrix)
1007 {
1008 context->color_matrix = *color_matrix;
1009 }
1010
1011 /*!
1012 Get layout width.
1013
1014 @param *context [in] Context
1015 @return Width
1016 */
1017 int
SDLPango_GetLayoutWidth(SDLPango_Context * context)1018 SDLPango_GetLayoutWidth(
1019 SDLPango_Context *context)
1020 {
1021 PangoRectangle logical_rect;
1022
1023 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1024
1025 return PANGO_PIXELS (logical_rect.width);
1026 }
1027
1028 /*!
1029 Get layout height.
1030
1031 @param *context [in] Context
1032 @return Height
1033 */
1034 int
SDLPango_GetLayoutHeight(SDLPango_Context * context)1035 SDLPango_GetLayoutHeight(
1036 SDLPango_Context *context)
1037 {
1038 PangoRectangle logical_rect;
1039
1040 pango_layout_get_extents (context->layout, NULL, &logical_rect);
1041
1042 return PANGO_PIXELS (logical_rect.height);
1043 }
1044
1045 /*!
1046 Set markup text to context.
1047 Text must be utf-8.
1048 Markup format is same as pango.
1049
1050 @param *context [i/o] Context
1051 @param *markup [in] Markup text
1052 @param length [in] Text length. -1 means NULL-terminated text.
1053 */
1054 void
SDLPango_SetMarkup(SDLPango_Context * context,const char * markup,int length)1055 SDLPango_SetMarkup(
1056 SDLPango_Context *context,
1057 const char *markup,
1058 int length)
1059 {
1060 pango_layout_set_markup (context->layout, markup, length);
1061 pango_layout_set_auto_dir (context->layout, TRUE);
1062 pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
1063 pango_layout_set_font_description (context->layout, context->font_desc);
1064 }
1065
1066 void
SDLPango_SetText_GivenAlignment(SDLPango_Context * context,const char * text,int length,SDLPango_Alignment alignment)1067 SDLPango_SetText_GivenAlignment(
1068 SDLPango_Context *context,
1069 const char *text,
1070 int length,
1071 SDLPango_Alignment alignment)
1072 {
1073 pango_layout_set_attributes(context->layout, NULL);
1074 pango_layout_set_text (context->layout, text, length);
1075 pango_layout_set_auto_dir (context->layout, TRUE);
1076 pango_layout_set_alignment (context->layout, alignment);
1077 pango_layout_set_font_description (context->layout, context->font_desc);
1078 }
1079
1080 /*!
1081 Set plain text to context.
1082 Text must be utf-8.
1083
1084 @param *context [i/o] Context
1085 @param *text [in] Plain text
1086 @param length [in] Text length. -1 means NULL-terminated text.
1087 */
1088 void
SDLPango_SetText(SDLPango_Context * context,const char * text,int length)1089 SDLPango_SetText(
1090 SDLPango_Context *context,
1091 const char *text,
1092 int length)
1093 {
1094 SDLPango_SetText_GivenAlignment(context, text, length, SDLPANGO_ALIGN_LEFT);
1095 }
1096
1097 /*!
1098 Set DPI to context.
1099
1100 @param *context [i/o] Context
1101 @param dpi_x [in] X dpi
1102 @param dpi_y [in] Y dpi
1103 */
1104 void
SDLPango_SetDpi(SDLPango_Context * context,double dpi_x,double dpi_y)1105 SDLPango_SetDpi(
1106 SDLPango_Context *context,
1107 double dpi_x, double dpi_y)
1108 {
1109 pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), dpi_x, dpi_y);
1110 }
1111
1112 /*!
1113 Set language to context.
1114
1115 @param *context [i/o] Context
1116 @param *language_tag [in] A RFC-3066 format language tag
1117 */
SDLPango_SetLanguage(SDLPango_Context * context,const char * language_tag)1118 void SDLCALL SDLPango_SetLanguage(
1119 SDLPango_Context *context,
1120 const char *language_tag)
1121 {
1122 pango_context_set_language (context->context, pango_language_from_string (language_tag));
1123 }
1124
1125 /*!
1126 Set base direction to context.
1127
1128 @param *context [i/o] Context
1129 @param direction [in] Direction
1130 */
SDLPango_SetBaseDirection(SDLPango_Context * context,SDLPango_Direction direction)1131 void SDLCALL SDLPango_SetBaseDirection(
1132 SDLPango_Context *context,
1133 SDLPango_Direction direction)
1134 {
1135 PangoDirection pango_dir;
1136
1137 switch(direction) {
1138 case SDLPANGO_DIRECTION_LTR:
1139 pango_dir = PANGO_DIRECTION_LTR;
1140 break;
1141 case SDLPANGO_DIRECTION_RTL:
1142 pango_dir = PANGO_DIRECTION_RTL;
1143 break;
1144 case SDLPANGO_DIRECTION_WEAK_LTR:
1145 pango_dir = PANGO_DIRECTION_WEAK_LTR;
1146 break;
1147 case SDLPANGO_DIRECTION_WEAK_RTL:
1148 pango_dir = PANGO_DIRECTION_WEAK_RTL;
1149 break;
1150 case SDLPANGO_DIRECTION_NEUTRAL:
1151 pango_dir = PANGO_DIRECTION_NEUTRAL;
1152 break;
1153 default:
1154 SDL_SetError("unknown direction value");
1155 return;
1156 }
1157
1158 pango_context_set_base_dir (context->context, pango_dir);
1159 }
1160
1161 /*!
1162 Get font map from context.
1163
1164 @param *context [in] Context
1165 @return Font map
1166 */
SDLPango_GetPangoFontMap(SDLPango_Context * context)1167 PangoFontMap* SDLCALL SDLPango_GetPangoFontMap(
1168 SDLPango_Context *context)
1169 {
1170 return context->font_map;
1171 }
1172
1173 /*!
1174 Get font description from context.
1175
1176 @param *context [in] Context
1177 @return Font description
1178 */
SDLPango_GetPangoFontDescription(SDLPango_Context * context)1179 PangoFontDescription* SDLCALL SDLPango_GetPangoFontDescription(
1180 SDLPango_Context *context)
1181 {
1182 return context->font_desc;
1183 }
1184
1185 /*!
1186 Get layout from context.
1187
1188 @param *context [in] Context
1189 @return Layout
1190 */
SDLPango_GetPangoLayout(SDLPango_Context * context)1191 PangoLayout* SDLCALL SDLPango_GetPangoLayout(
1192 SDLPango_Context *context)
1193 {
1194 return context->layout;
1195 }
1196