~ubuntu-branches/ubuntu/trusty/sdlpango/trusty

« back to all changes in this revision

Viewing changes to src/SDL_Pango.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette
  • Date: 2006-09-28 23:50:02 UTC
  • Revision ID: james.westby@ubuntu.com-20060928235002-qn0dl0ktodhmieax
Tags: upstream-0.1.2
ImportĀ upstreamĀ versionĀ 0.1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
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
 
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
static void
 
334
drawGlyphString(
 
335
    SDLPango_Context *context,
 
336
    SDL_Surface *surface,
 
337
    SDLPango_Matrix *color_matrix,
 
338
    PangoFont *font,
 
339
    PangoGlyphString *glyphs,
 
340
    SDL_Rect *rect,
 
341
    int baseline)
 
342
{
 
343
    pango_ft2_render(context->tmp_ftbitmap, font, glyphs, rect->x, rect->y + baseline);
 
344
 
 
345
    SDLPango_CopyFTBitmapToSurface(
 
346
        context->tmp_ftbitmap,
 
347
        surface,
 
348
        color_matrix,
 
349
        rect);
 
350
 
 
351
    clearFTBitmap(context->tmp_ftbitmap);
 
352
}
 
353
 
 
354
/*!
 
355
    Draw horizontal line of a pixel.
 
356
 
 
357
    @param *surface [out] Surface to draw on it
 
358
    @param *color_matrix [in] Foreground and background color
 
359
    @param y [in] Y location of line
 
360
    @param start [in] Left of line
 
361
    @param end [in] Right of line
 
362
*/
 
363
static void drawHLine(
 
364
    SDL_Surface *surface,
 
365
    SDLPango_Matrix *color_matrix,
 
366
    int y,
 
367
    int start,
 
368
    int end)
 
369
{
 
370
    Uint8 *p;
 
371
    Uint16 *p16;
 
372
    Uint32 *p32;
 
373
    Uint32 color;
 
374
    int ix;
 
375
    int pixel_bytes = surface->format->BytesPerPixel;
 
376
 
 
377
    if (y < 0 || y >= surface->h)
 
378
        return;
 
379
 
 
380
    if (end <= 0 || start >= surface->w)
 
381
        return;
 
382
 
 
383
    if (start < 0)
 
384
        start = 0;
 
385
 
 
386
    if (end >= surface->w)
 
387
        end = surface->w;
 
388
 
 
389
    p = (Uint8 *)(surface->pixels) + y * surface->pitch + start * pixel_bytes;
 
390
    color = SDL_MapRGBA(surface->format,
 
391
        color_matrix->m[0][1],
 
392
        color_matrix->m[1][1], 
 
393
        color_matrix->m[2][1], 
 
394
        color_matrix->m[3][1]);
 
395
 
 
396
    switch(pixel_bytes) {
 
397
    case 2:
 
398
        p16 = (Uint16 *)p;
 
399
        for (ix = 0; ix < end - start; ix++)
 
400
            *p16++ = (Uint16)color;
 
401
        break;
 
402
    case 4:
 
403
        p32 = (Uint32 *)p;
 
404
        for (ix = 0; ix < end - start; ix++)
 
405
            *p32++ = color;
 
406
        break;
 
407
    default:
 
408
        SDL_SetError("surface->format->BytesPerPixel is invalid value");
 
409
        break;
 
410
    }
 
411
}
 
412
 
 
413
/*!
 
414
    Draw a line.
 
415
 
 
416
    @param *context [in] Context
 
417
    @param *surface [out] Surface to draw on it
 
418
    @param *line [in] Innter variable of Pango
 
419
    @param x [in] X location of line
 
420
    @param y [in] Y location of line
 
421
    @param height [in] Height of line
 
422
    @param baseline [in] Rise / sink of line (for super/subscript)
 
423
*/
 
424
static void
 
425
drawLine(
 
426
    SDLPango_Context *context,
 
427
    SDL_Surface *surface,
 
428
    PangoLayoutLine *line,
 
429
    gint x, 
 
430
    gint y, 
 
431
    gint height,
 
432
    gint baseline)
 
433
{
 
434
    GSList *tmp_list = line->runs;
 
435
    PangoColor fg_color, bg_color;
 
436
    PangoRectangle logical_rect;
 
437
    PangoRectangle ink_rect;
 
438
    int x_off = 0;
 
439
 
 
440
    while (tmp_list) {
 
441
        SDLPango_Matrix color_matrix = context->color_matrix;
 
442
        PangoUnderline uline = PANGO_UNDERLINE_NONE;
 
443
        gboolean strike, fg_set, bg_set, shape_set;
 
444
        gint rise, risen_y;
 
445
        PangoLayoutRun *run = tmp_list->data;
 
446
        SDL_Rect d_rect;
 
447
 
 
448
        tmp_list = tmp_list->next;
 
449
 
 
450
        getItemProperties(run->item,
 
451
            &uline, &strike, &rise,
 
452
            &fg_color, &fg_set, &bg_color, &bg_set,
 
453
            &shape_set, &ink_rect, &logical_rect);
 
454
 
 
455
        risen_y = y + baseline - PANGO_PIXELS (rise);
 
456
 
 
457
        if(fg_set) {
 
458
            color_matrix.m[0][1] = (Uint8)(fg_color.red >> 8);
 
459
            color_matrix.m[1][1] = (Uint8)(fg_color.green >> 8);
 
460
            color_matrix.m[2][1] = (Uint8)(fg_color.blue >> 8);
 
461
            color_matrix.m[3][1] = 255;
 
462
            if(color_matrix.m[3][0] == 0) {
 
463
                color_matrix.m[0][0] = (Uint8)(fg_color.red >> 8);
 
464
                color_matrix.m[1][0] = (Uint8)(fg_color.green >> 8);
 
465
                color_matrix.m[2][0] = (Uint8)(fg_color.blue >> 8);
 
466
            }
 
467
        }
 
468
 
 
469
        if (bg_set) {
 
470
            color_matrix.m[0][0] = (Uint8)(bg_color.red >> 8);
 
471
            color_matrix.m[1][0] = (Uint8)(bg_color.green >> 8);
 
472
            color_matrix.m[2][0] = (Uint8)(bg_color.blue >> 8);
 
473
            color_matrix.m[3][0] = 255;
 
474
        }
 
475
 
 
476
        if(! shape_set) {
 
477
            if (uline == PANGO_UNDERLINE_NONE)
 
478
                pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
 
479
                                            NULL, &logical_rect);
 
480
            else
 
481
                pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
 
482
                                            &ink_rect, &logical_rect);
 
483
 
 
484
            d_rect.w = (Uint16)PANGO_PIXELS(logical_rect.width);
 
485
            d_rect.h = (Uint16)height;
 
486
            d_rect.x = (Uint16)(x + PANGO_PIXELS (x_off));
 
487
            d_rect.y = (Uint16)(risen_y - baseline);
 
488
 
 
489
            if((! context->tmp_ftbitmap) || d_rect.w + d_rect.x > context->tmp_ftbitmap->width
 
490
                || d_rect.h + d_rect.y > context->tmp_ftbitmap->rows)
 
491
            {
 
492
                freeFTBitmap(context->tmp_ftbitmap);
 
493
                context->tmp_ftbitmap = createFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y);
 
494
            }
 
495
 
 
496
            drawGlyphString(context, surface, 
 
497
                &color_matrix, 
 
498
                run->item->analysis.font, run->glyphs, &d_rect, baseline);
 
499
        }
 
500
        switch (uline) {
 
501
        case PANGO_UNDERLINE_NONE:
 
502
            break;
 
503
        case PANGO_UNDERLINE_DOUBLE:
 
504
            drawHLine(surface, &color_matrix,
 
505
                risen_y + 4,
 
506
                x + PANGO_PIXELS (x_off + ink_rect.x),
 
507
                x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
 
508
          /* Fall through */
 
509
        case PANGO_UNDERLINE_SINGLE:
 
510
            drawHLine(surface, &color_matrix,
 
511
                risen_y + 2,
 
512
                x + PANGO_PIXELS (x_off + ink_rect.x),
 
513
                x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
 
514
            break;
 
515
        case PANGO_UNDERLINE_ERROR:
 
516
            {
 
517
                int point_x;
 
518
                int counter = 0;
 
519
                int end_x = x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width);
 
520
 
 
521
                for (point_x = x + PANGO_PIXELS (x_off + ink_rect.x) - 1;
 
522
                    point_x <= end_x;
 
523
                    point_x += 2)
 
524
                {
 
525
                    if (counter)
 
526
                        drawHLine(surface, &color_matrix,
 
527
                            risen_y + 2,
 
528
                            point_x, MIN (point_x + 1, end_x));
 
529
                    else
 
530
                        drawHLine(surface, &color_matrix,
 
531
                            risen_y + 3,
 
532
                            point_x, MIN (point_x + 1, end_x));
 
533
                
 
534
                    counter = (counter + 1) % 2;
 
535
                }
 
536
            }
 
537
            break;
 
538
        case PANGO_UNDERLINE_LOW:
 
539
            drawHLine(surface, &color_matrix,
 
540
                risen_y + PANGO_PIXELS (ink_rect.y + ink_rect.height),
 
541
                x + PANGO_PIXELS (x_off + ink_rect.x),
 
542
                x + PANGO_PIXELS (x_off + ink_rect.x + ink_rect.width));
 
543
          break;
 
544
        }
 
545
 
 
546
        if (strike)
 
547
            drawHLine(surface, &color_matrix,
 
548
                risen_y + PANGO_PIXELS (logical_rect.y + logical_rect.height / 2),
 
549
                x + PANGO_PIXELS (x_off + logical_rect.x),
 
550
                x + PANGO_PIXELS (x_off + logical_rect.x + logical_rect.width));
 
551
 
 
552
        x_off += logical_rect.width;
 
553
    }
 
554
}
 
555
 
 
556
/*!
 
557
    Innter function of Pango. Stolen from GDK.
 
558
 
 
559
    @param *item [in] The item to get property
 
560
    @param *uline [out] Kind of underline
 
561
    @param *strikethrough [out] Strike-through line
 
562
    @param *rise [out] Rise/sink of line (for super/subscript)
 
563
    @param *fg_color [out] Color of foreground
 
564
    @param *fg_set [out] True if fg_color set
 
565
    @param *bg_color [out] Color of background
 
566
    @param *bg_set [out] True if bg_color valid
 
567
    @param *shape_set [out] True if ink_rect and logical_rect valid
 
568
    @param *ink_rect [out] Ink rect
 
569
    @param *logical_rect [out] Logical rect
 
570
*/
 
571
static void
 
572
getItemProperties (
 
573
    PangoItem *item,
 
574
    PangoUnderline *uline,
 
575
    gboolean *strikethrough,
 
576
    gint *rise,
 
577
    PangoColor *fg_color,
 
578
    gboolean *fg_set,
 
579
    PangoColor *bg_color,
 
580
    gboolean *bg_set,
 
581
    gboolean *shape_set,
 
582
    PangoRectangle *ink_rect,
 
583
    PangoRectangle *logical_rect)
 
584
{
 
585
    GSList *tmp_list = item->analysis.extra_attrs;
 
586
 
 
587
    if (strikethrough)
 
588
        *strikethrough = FALSE;
 
589
  
 
590
    if (fg_set)
 
591
        *fg_set = FALSE;
 
592
 
 
593
    if (bg_set)
 
594
        *bg_set = FALSE;
 
595
 
 
596
    if (shape_set)
 
597
        *shape_set = FALSE;
 
598
 
 
599
    if (rise)
 
600
        *rise = 0;
 
601
 
 
602
    while (tmp_list) {
 
603
        PangoAttribute *attr = tmp_list->data;
 
604
 
 
605
        switch (attr->klass->type) {
 
606
        case PANGO_ATTR_UNDERLINE:
 
607
            if (uline)
 
608
                *uline = ((PangoAttrInt *)attr)->value;
 
609
            break;
 
610
 
 
611
        case PANGO_ATTR_STRIKETHROUGH:
 
612
            if (strikethrough)
 
613
                *strikethrough = ((PangoAttrInt *)attr)->value;
 
614
            break;
 
615
        
 
616
        case PANGO_ATTR_FOREGROUND:
 
617
            if (fg_color)
 
618
                *fg_color = ((PangoAttrColor *)attr)->color;
 
619
            if (fg_set)
 
620
                *fg_set = TRUE;
 
621
            break;
 
622
        
 
623
        case PANGO_ATTR_BACKGROUND:
 
624
            if (bg_color)
 
625
                *bg_color = ((PangoAttrColor *)attr)->color;
 
626
            if (bg_set)
 
627
                *bg_set = TRUE;
 
628
            break;
 
629
 
 
630
        case PANGO_ATTR_SHAPE:
 
631
            if (shape_set)
 
632
                *shape_set = TRUE;
 
633
            if (logical_rect)
 
634
                *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
 
635
            if (ink_rect)
 
636
                *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
 
637
            break;
 
638
 
 
639
        case PANGO_ATTR_RISE:
 
640
            if (rise)
 
641
                *rise = ((PangoAttrInt *)attr)->value;
 
642
            break;
 
643
        
 
644
        default:
 
645
            break;
 
646
        }
 
647
        tmp_list = tmp_list->next;
 
648
    }
 
649
}
 
650
 
 
651
/*!
 
652
    Copy bitmap to surface. 
 
653
    From (x, y)-(w, h) to (x, y)-(w, h) of rect. 
 
654
 
 
655
    @param *bitmap [in] Grayscale bitmap
 
656
    @param *surface [out] Surface
 
657
    @param *matrix [in] Foreground and background color
 
658
    @param *rect [in] Rect to copy
 
659
*/
 
660
void
 
661
SDLPango_CopyFTBitmapToSurface(
 
662
    const FT_Bitmap *bitmap,
 
663
    SDL_Surface *surface,
 
664
    const SDLPango_Matrix *matrix,
 
665
    SDL_Rect *rect)
 
666
{
 
667
    int i;
 
668
    Uint8 *p_ft;
 
669
    Uint8 *p_sdl;
 
670
    int width = rect->w;
 
671
    int height = rect->h;
 
672
    int x = rect->x;
 
673
    int y = rect->y;
 
674
 
 
675
    if(x + width > surface->w) {
 
676
        width = surface->w - x;
 
677
        if(width <= 0)
 
678
            return;
 
679
    }
 
680
    if(y + height > surface->h) {
 
681
        height = surface->h - y;
 
682
        if(height <= 0)
 
683
            return;
 
684
    }
 
685
 
 
686
    if(SDL_LockSurface(surface)) {
 
687
        SDL_SetError("surface lock failed");
 
688
        SDL_FreeSurface(surface);
 
689
        return;
 
690
    }
 
691
 
 
692
    p_ft = (Uint8 *)bitmap->buffer + (bitmap->pitch * y);
 
693
    p_sdl = (Uint8 *)surface->pixels + (surface->pitch * y);
 
694
    for(i = 0; i < height; i ++) {
 
695
        int k;
 
696
        for(k = 0; k < width; k ++) {
 
697
            /* TODO: rewrite by matrix calculation library */
 
698
            Uint8 pixel[4];     /* 4: RGBA */
 
699
            int n;
 
700
 
 
701
            for(n = 0; n < 4; n ++) {
 
702
                Uint16 w;
 
703
                w = ((Uint16)matrix->m[n][0] * (256 - p_ft[k + x])) + ((Uint16)matrix->m[n][1] * p_ft[k + x]);
 
704
                pixel[n] = (Uint8)(w >> 8);
 
705
            }
 
706
 
 
707
            switch(surface->format->BytesPerPixel) {
 
708
            case 2:
 
709
                ((Uint16 *)p_sdl)[k + x] = (Uint16)SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
 
710
                break;
 
711
            case 4:
 
712
                ((Uint32 *)p_sdl)[k + x] = SDL_MapRGBA(surface->format, pixel[0], pixel[1], pixel[2], pixel[3]);
 
713
                break;
 
714
            default:
 
715
                SDL_SetError("surface->format->BytesPerPixel is invalid value");
 
716
                return;
 
717
            }
 
718
        }
 
719
        p_ft += bitmap->pitch;
 
720
        p_sdl += surface->pitch;
 
721
    }
 
722
 
 
723
    SDL_UnlockSurface(surface);
 
724
}
 
725
 
 
726
/*!
 
727
    Create a context which contains Pango objects.
 
728
 
 
729
    @return A pointer to the context as a SDLPango_Context*.
 
730
*/
 
731
SDLPango_Context*
 
732
SDLPango_CreateContext()
 
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(
 
747
        MAKE_FONT_NAME (DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
 
748
 
 
749
    context->layout = pango_layout_new (context->context);
 
750
 
 
751
    SDLPango_SetSurfaceCreateArgs(context, SDL_SWSURFACE | SDL_SRCALPHA, DEFAULT_DEPTH,
 
752
        DEFAULT_RMASK, DEFAULT_GMASK, DEFAULT_BMASK, DEFAULT_AMASK);
 
753
 
 
754
    context->tmp_ftbitmap = NULL;
 
755
 
 
756
    context->color_matrix = *MATRIX_TRANSPARENT_BACK_BLACK_LETTER;
 
757
 
 
758
    context->min_height = 0;
 
759
    context->min_width = 0;
 
760
 
 
761
    return context;
 
762
}
 
763
 
 
764
/*!
 
765
    Free a context.
 
766
 
 
767
    @param *context [i/o] Context to be free
 
768
*/
 
769
void
 
770
SDLPango_FreeContext(SDLPango_Context *context)
 
771
{
 
772
    freeFTBitmap(context->tmp_ftbitmap);
 
773
 
 
774
    g_object_unref (context->layout);
 
775
 
 
776
    pango_font_description_free(context->font_desc);
 
777
 
 
778
    g_object_unref(context->context);
 
779
 
 
780
    g_object_unref(context->font_map);
 
781
 
 
782
    g_free(context);
 
783
}
 
784
 
 
785
/*!
 
786
    Specify Arguments when create a surface.
 
787
    When SDL_Pango creates a surface, the arguments are used.
 
788
 
 
789
    @param *context [i/o] Context
 
790
    @param flags [in] Same as SDL_CreateRGBSurface()
 
791
    @param depth [in] Same as SDL_CreateRGBSurface()
 
792
    @param Rmask [in] Same as SDL_CreateRGBSurface()
 
793
    @param Gmask [in] Same as SDL_CreateRGBSurface()
 
794
    @param Bmask [in] Same as SDL_CreateRGBSurface()
 
795
    @param Amask [in] Same as SDL_CreateRGBSurface()
 
796
*/
 
797
void
 
798
SDLPango_SetSurfaceCreateArgs(
 
799
    SDLPango_Context *context,
 
800
    Uint32 flags,
 
801
    int depth,
 
802
    Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
 
803
{
 
804
    context->surface_args.flags = flags;
 
805
    context->surface_args.depth = depth;
 
806
    context->surface_args.Rmask = Rmask;
 
807
    context->surface_args.Gmask = Gmask;
 
808
    context->surface_args.Bmask = Bmask;
 
809
    context->surface_args.Amask = Amask;
 
810
}
 
811
 
 
812
/*!
 
813
    Create a surface and draw text on it.
 
814
    The size of surface is same as lauout size.
 
815
 
 
816
    @param *context [in] Context
 
817
    @return A newly created surface
 
818
*/
 
819
SDL_Surface * SDLPango_CreateSurfaceDraw(
 
820
    SDLPango_Context *context)
 
821
{
 
822
    PangoRectangle logical_rect;
 
823
    SDL_Surface *surface;
 
824
    int width, height;
 
825
 
 
826
    pango_layout_get_extents (context->layout, NULL, &logical_rect);
 
827
    width = PANGO_PIXELS (logical_rect.width);
 
828
    height = PANGO_PIXELS (logical_rect.height);
 
829
    if(width < context->min_width)
 
830
        width = context->min_width;
 
831
    if(height < context->min_height)
 
832
        height = context->min_height;
 
833
 
 
834
    surface = SDL_CreateRGBSurface(
 
835
        context->surface_args.flags,
 
836
        width, height, context->surface_args.depth,
 
837
        context->surface_args.Rmask,
 
838
        context->surface_args.Gmask,
 
839
        context->surface_args.Bmask,
 
840
        context->surface_args.Amask);
 
841
 
 
842
    SDLPango_Draw(context, surface, 0, 0);
 
843
 
 
844
    return surface;
 
845
}
 
846
 
 
847
/*!
 
848
    Draw text on a existing surface.
 
849
 
 
850
    @param *context [in] Context
 
851
    @param *surface [i/o] Surface to draw on it
 
852
    @param x [in] X of left-top of drawing area
 
853
    @param y [in] Y of left-top of drawing area
 
854
*/
 
855
void
 
856
SDLPango_Draw(
 
857
    SDLPango_Context *context,
 
858
    SDL_Surface *surface,
 
859
    int x, int y)
 
860
{
 
861
    PangoLayoutIter *iter;
 
862
    PangoRectangle logical_rect;
 
863
    int width, height;
 
864
 
 
865
    if(! surface) {
 
866
        SDL_SetError("surface is NULL");
 
867
        return;
 
868
    }
 
869
 
 
870
    iter = pango_layout_get_iter (context->layout);
 
871
 
 
872
    pango_layout_get_extents (context->layout, NULL, &logical_rect);
 
873
    width = PANGO_PIXELS (logical_rect.width);
 
874
    height = PANGO_PIXELS (logical_rect.height);
 
875
 
 
876
    SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, 0));
 
877
 
 
878
    if((! context->tmp_ftbitmap) || context->tmp_ftbitmap->width < width
 
879
        || context->tmp_ftbitmap->rows < height)
 
880
    {
 
881
        freeFTBitmap(context->tmp_ftbitmap);
 
882
        context->tmp_ftbitmap = createFTBitmap(width, height);
 
883
    }
 
884
 
 
885
    do {
 
886
        PangoLayoutLine *line;
 
887
        int baseline;
 
888
 
 
889
        line = pango_layout_iter_get_line (iter);
 
890
 
 
891
        pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
 
892
        baseline = pango_layout_iter_get_baseline (iter);
 
893
 
 
894
        drawLine(
 
895
            context,
 
896
            surface,
 
897
            line,
 
898
            x + PANGO_PIXELS (logical_rect.x),
 
899
            y + PANGO_PIXELS (logical_rect.y),
 
900
            PANGO_PIXELS (logical_rect.height),
 
901
            PANGO_PIXELS (baseline - logical_rect.y));
 
902
    } while (pango_layout_iter_next_line (iter));
 
903
 
 
904
    pango_layout_iter_free (iter);
 
905
}
 
906
 
 
907
/*!
 
908
    Allocate buffer and create a FTBitmap object.
 
909
 
 
910
    @param width [in] Width
 
911
    @param height [in] Height
 
912
    @return FTBitmap object
 
913
*/
 
914
static FT_Bitmap *
 
915
createFTBitmap(
 
916
    int width, int height)
 
917
{
 
918
    FT_Bitmap *bitmap;
 
919
    guchar *buf;
 
920
 
 
921
    bitmap = g_malloc(sizeof(FT_Bitmap));
 
922
    bitmap->width = width;
 
923
    bitmap->rows = height;
 
924
    bitmap->pitch = (width + 3) & ~3;
 
925
    bitmap->num_grays = 256;
 
926
    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
 
927
    buf = g_malloc (bitmap->pitch * bitmap->rows);
 
928
    memset (buf, 0x00, bitmap->pitch * bitmap->rows);
 
929
    bitmap->buffer = buf;
 
930
 
 
931
    return bitmap;
 
932
}
 
933
 
 
934
/*!
 
935
    Free a FTBitmap object.
 
936
 
 
937
    @param *bitmap [i/o] FTbitmap to be free
 
938
*/
 
939
static void
 
940
freeFTBitmap(
 
941
    FT_Bitmap *bitmap)
 
942
{
 
943
    if(bitmap) {
 
944
        g_free(bitmap->buffer);
 
945
        g_free(bitmap);
 
946
    }
 
947
}
 
948
 
 
949
/*!
 
950
    Clear a FTBitmap object.
 
951
 
 
952
    @param *bitmap [i/o] FTbitmap to be clear
 
953
*/
 
954
static void
 
955
clearFTBitmap(
 
956
    FT_Bitmap *bitmap)
 
957
{
 
958
    Uint8 *p = (Uint8 *)bitmap->buffer;
 
959
    int length = bitmap->pitch * bitmap->rows;
 
960
 
 
961
    memset(p, 0, length);
 
962
}
 
963
 
 
964
/*!
 
965
    Specify minimum size of drawing rect.
 
966
 
 
967
    @param *context [i/o] Context
 
968
    @param width [in] Width. -1 means no wrapping mode.
 
969
    @param height [in] Height. zero/minus value means non-specified.
 
970
*/
 
971
void
 
972
SDLPango_SetMinimumSize(
 
973
    SDLPango_Context *context,
 
974
    int width, int height)
 
975
{
 
976
    int pango_width;
 
977
    if(width > 0)
 
978
        pango_width = width * PANGO_SCALE;
 
979
    else
 
980
        pango_width = -1;
 
981
    pango_layout_set_width(context->layout, pango_width);
 
982
 
 
983
    context->min_width = width;
 
984
    context->min_height = height;
 
985
}
 
986
 
 
987
/*!
 
988
    Specify default color.
 
989
 
 
990
    @param *context [i/o] Context
 
991
    @param *color_matrix [in] Foreground and background color
 
992
*/
 
993
void
 
994
SDLPango_SetDefaultColor(
 
995
    SDLPango_Context *context,
 
996
    const SDLPango_Matrix *color_matrix)
 
997
{
 
998
    context->color_matrix = *color_matrix;
 
999
}
 
1000
 
 
1001
/*!
 
1002
    Get layout width.
 
1003
 
 
1004
    @param *context [in] Context
 
1005
    @return Width
 
1006
*/
 
1007
int
 
1008
SDLPango_GetLayoutWidth(
 
1009
    SDLPango_Context *context)
 
1010
{
 
1011
    PangoRectangle logical_rect;
 
1012
 
 
1013
    pango_layout_get_extents (context->layout, NULL, &logical_rect);
 
1014
 
 
1015
    return PANGO_PIXELS (logical_rect.width);
 
1016
}
 
1017
 
 
1018
/*!
 
1019
    Get layout height.
 
1020
 
 
1021
    @param *context [in] Context
 
1022
    @return Height
 
1023
*/
 
1024
int
 
1025
SDLPango_GetLayoutHeight(
 
1026
    SDLPango_Context *context)
 
1027
{
 
1028
    PangoRectangle logical_rect;
 
1029
 
 
1030
    pango_layout_get_extents (context->layout, NULL, &logical_rect);
 
1031
 
 
1032
    return PANGO_PIXELS (logical_rect.height);
 
1033
}
 
1034
 
 
1035
/*!
 
1036
    Set markup text to context.
 
1037
    Text must be utf-8.
 
1038
    Markup format is same as pango.
 
1039
 
 
1040
    @param *context [i/o] Context
 
1041
    @param *markup [in] Markup text
 
1042
    @param length [in] Text length. -1 means NULL-terminated text.
 
1043
*/
 
1044
void
 
1045
SDLPango_SetMarkup(
 
1046
    SDLPango_Context *context,
 
1047
    const char *markup,
 
1048
    int length)
 
1049
{
 
1050
    pango_layout_set_markup (context->layout, markup, length);
 
1051
    pango_layout_set_auto_dir (context->layout, TRUE);
 
1052
    pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
 
1053
    pango_layout_set_font_description (context->layout, context->font_desc);
 
1054
}
 
1055
 
 
1056
/*!
 
1057
    Set plain text to context.
 
1058
    Text must be utf-8.
 
1059
 
 
1060
    @param *context [i/o] Context
 
1061
    @param *text [in] Plain text
 
1062
    @param length [in] Text length. -1 means NULL-terminated text.
 
1063
*/
 
1064
void
 
1065
SDLPango_SetText(
 
1066
    SDLPango_Context *context,
 
1067
    const char *text,
 
1068
    int length)
 
1069
{
 
1070
    pango_layout_set_attributes(context->layout, NULL);
 
1071
    pango_layout_set_text (context->layout, text, length);
 
1072
    pango_layout_set_auto_dir (context->layout, TRUE);
 
1073
    pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
 
1074
    pango_layout_set_font_description (context->layout, context->font_desc);
 
1075
}
 
1076
 
 
1077
/*!
 
1078
    Set DPI to context.
 
1079
 
 
1080
    @param *context [i/o] Context
 
1081
    @param dpi_x [in] X dpi
 
1082
    @param dpi_y [in] Y dpi
 
1083
*/
 
1084
void
 
1085
SDLPango_SetDpi(
 
1086
    SDLPango_Context *context,
 
1087
    double dpi_x, double dpi_y)
 
1088
{
 
1089
    pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), dpi_x, dpi_y);
 
1090
}
 
1091
 
 
1092
/*!
 
1093
    Set language to context.
 
1094
 
 
1095
    @param *context [i/o] Context
 
1096
    @param *language_tag [in] A RFC-3066 format language tag 
 
1097
*/
 
1098
void SDLCALL SDLPango_SetLanguage(
 
1099
    SDLPango_Context *context,
 
1100
    const char *language_tag)
 
1101
{
 
1102
    pango_context_set_language (context->context, pango_language_from_string (language_tag));
 
1103
}
 
1104
 
 
1105
/*!
 
1106
    Set base direction to context.
 
1107
 
 
1108
    @param *context [i/o] Context
 
1109
    @param direction [in] Direction
 
1110
*/
 
1111
void SDLCALL SDLPango_SetBaseDirection(
 
1112
    SDLPango_Context *context,
 
1113
    SDLPango_Direction direction)
 
1114
{
 
1115
    PangoDirection pango_dir;
 
1116
 
 
1117
    switch(direction) {
 
1118
    case SDLPANGO_DIRECTION_LTR:
 
1119
        pango_dir = PANGO_DIRECTION_LTR;
 
1120
        break;
 
1121
    case SDLPANGO_DIRECTION_RTL:
 
1122
        pango_dir = PANGO_DIRECTION_RTL;
 
1123
        break;
 
1124
    case SDLPANGO_DIRECTION_WEAK_LTR:
 
1125
        pango_dir = PANGO_DIRECTION_WEAK_LTR;
 
1126
        break;
 
1127
    case SDLPANGO_DIRECTION_WEAK_RTL:
 
1128
        pango_dir = PANGO_DIRECTION_WEAK_RTL;
 
1129
        break;
 
1130
    case SDLPANGO_DIRECTION_NEUTRAL:
 
1131
        pango_dir = PANGO_DIRECTION_NEUTRAL;
 
1132
        break;
 
1133
    default:
 
1134
        SDL_SetError("unknown direction value");
 
1135
        return;
 
1136
    }
 
1137
 
 
1138
    pango_context_set_base_dir (context->context, pango_dir);
 
1139
}
 
1140
 
 
1141
/*!
 
1142
    Get font map from context.
 
1143
 
 
1144
    @param *context [in] Context
 
1145
    @return Font map
 
1146
*/
 
1147
PangoFontMap* SDLCALL SDLPango_GetPangoFontMap(
 
1148
    SDLPango_Context *context)
 
1149
{
 
1150
    return context->font_map;
 
1151
}
 
1152
 
 
1153
/*!
 
1154
    Get font description from context.
 
1155
 
 
1156
    @param *context [in] Context
 
1157
    @return Font description
 
1158
*/
 
1159
PangoFontDescription* SDLCALL SDLPango_GetPangoFontDescription(
 
1160
    SDLPango_Context *context)
 
1161
{
 
1162
    return context->font_desc;
 
1163
}
 
1164
 
 
1165
/*!
 
1166
    Get layout from context.
 
1167
 
 
1168
    @param *context [in] Context
 
1169
    @return Layout
 
1170
*/
 
1171
PangoLayout* SDLCALL SDLPango_GetPangoLayout(
 
1172
    SDLPango_Context *context)
 
1173
{
 
1174
    return context->layout;
 
1175
}