139241fe2SDarkWyrm//----------------------------------------------------------------------------
2e39da397SStephan Aßmus// Anti-Grain Geometry - Version 2.4
3e39da397SStephan Aßmus// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
439241fe2SDarkWyrm//
539241fe2SDarkWyrm// Permission to copy, use, modify, sell and distribute this software
639241fe2SDarkWyrm// is granted provided this copyright notice appears in all copies.
739241fe2SDarkWyrm// This software is provided "as is" without express or implied
839241fe2SDarkWyrm// warranty, and with no claim as to its suitability for any purpose.
939241fe2SDarkWyrm//
1039241fe2SDarkWyrm//----------------------------------------------------------------------------
1139241fe2SDarkWyrm// Contact: mcseem@antigrain.com
1239241fe2SDarkWyrm//          mcseemagg@yahoo.com
1339241fe2SDarkWyrm//          http://www.antigrain.com
1439241fe2SDarkWyrm//----------------------------------------------------------------------------
1539241fe2SDarkWyrm
1639241fe2SDarkWyrm
1739241fe2SDarkWyrm#include <stdio.h>
1839241fe2SDarkWyrm#include "agg_font_freetype.h"
1939241fe2SDarkWyrm#include "agg_bitset_iterator.h"
2039241fe2SDarkWyrm#include "agg_renderer_scanline.h"
2139241fe2SDarkWyrm
2239241fe2SDarkWyrm
2339241fe2SDarkWyrmnamespace agg
2439241fe2SDarkWyrm{
2539241fe2SDarkWyrm
2639241fe2SDarkWyrm    //------------------------------------------------------------------------------
2739241fe2SDarkWyrm    //
2839241fe2SDarkWyrm    // This code implements the AUTODIN II polynomial
2939241fe2SDarkWyrm    // The variable corresponding to the macro argument "crc" should
3039241fe2SDarkWyrm    // be an unsigned long.
3139241fe2SDarkWyrm    // Oroginal code  by Spencer Garrett <srg@quick.com>
3239241fe2SDarkWyrm    //
3339241fe2SDarkWyrm
3439241fe2SDarkWyrm    // generated using the AUTODIN II polynomial
3539241fe2SDarkWyrm    //   x^32 + x^26 + x^23 + x^22 + x^16 +
3639241fe2SDarkWyrm    //   x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
3739241fe2SDarkWyrm    //
3839241fe2SDarkWyrm    //------------------------------------------------------------------------------
3939241fe2SDarkWyrm
4039241fe2SDarkWyrm    static const unsigned crc32tab[256] =
4139241fe2SDarkWyrm    {
4239241fe2SDarkWyrm       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
4339241fe2SDarkWyrm       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
4439241fe2SDarkWyrm       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
4539241fe2SDarkWyrm       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
4639241fe2SDarkWyrm       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
4739241fe2SDarkWyrm       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
4839241fe2SDarkWyrm       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
4939241fe2SDarkWyrm       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
5039241fe2SDarkWyrm       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
5139241fe2SDarkWyrm       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
5239241fe2SDarkWyrm       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
5339241fe2SDarkWyrm       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
5439241fe2SDarkWyrm       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
5539241fe2SDarkWyrm       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
5639241fe2SDarkWyrm       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
5739241fe2SDarkWyrm       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
5839241fe2SDarkWyrm       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
5939241fe2SDarkWyrm       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
6039241fe2SDarkWyrm       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
6139241fe2SDarkWyrm       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
6239241fe2SDarkWyrm       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
6339241fe2SDarkWyrm       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
6439241fe2SDarkWyrm       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
6539241fe2SDarkWyrm       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
6639241fe2SDarkWyrm       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
6739241fe2SDarkWyrm       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
6839241fe2SDarkWyrm       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
6939241fe2SDarkWyrm       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
7039241fe2SDarkWyrm       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
7139241fe2SDarkWyrm       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
7239241fe2SDarkWyrm       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
7339241fe2SDarkWyrm       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
7439241fe2SDarkWyrm       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
7539241fe2SDarkWyrm       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
7639241fe2SDarkWyrm       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
7739241fe2SDarkWyrm       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
7839241fe2SDarkWyrm       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
7939241fe2SDarkWyrm       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
8039241fe2SDarkWyrm       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
8139241fe2SDarkWyrm       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
8239241fe2SDarkWyrm       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
8339241fe2SDarkWyrm       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
8439241fe2SDarkWyrm       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
8539241fe2SDarkWyrm       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
8639241fe2SDarkWyrm       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
8739241fe2SDarkWyrm       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
8839241fe2SDarkWyrm       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
8939241fe2SDarkWyrm       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
9039241fe2SDarkWyrm       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
9139241fe2SDarkWyrm       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
9239241fe2SDarkWyrm       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
9339241fe2SDarkWyrm       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
9439241fe2SDarkWyrm       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
9539241fe2SDarkWyrm       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
9639241fe2SDarkWyrm       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
9739241fe2SDarkWyrm       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
9839241fe2SDarkWyrm       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
9939241fe2SDarkWyrm       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
10039241fe2SDarkWyrm       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
10139241fe2SDarkWyrm       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
10239241fe2SDarkWyrm       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
10339241fe2SDarkWyrm       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
10439241fe2SDarkWyrm       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
10539241fe2SDarkWyrm       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
10639241fe2SDarkWyrm    };
10739241fe2SDarkWyrm
10839241fe2SDarkWyrm
10939241fe2SDarkWyrm    //------------------------------------------------------------------------------
11039241fe2SDarkWyrm
11139241fe2SDarkWyrm    static unsigned calc_crc32(const unsigned char* buf, unsigned size)
11239241fe2SDarkWyrm    {
11339241fe2SDarkWyrm        unsigned crc = (unsigned)~0;
11439241fe2SDarkWyrm        const unsigned char* p;
11539241fe2SDarkWyrm        unsigned len = 0;
11639241fe2SDarkWyrm        unsigned nr = size;
11739241fe2SDarkWyrm
11839241fe2SDarkWyrm        for (len += nr, p = buf; nr--; ++p)
11939241fe2SDarkWyrm        {
12039241fe2SDarkWyrm            crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
12139241fe2SDarkWyrm        }
12239241fe2SDarkWyrm        return ~crc;
12339241fe2SDarkWyrm    }
12439241fe2SDarkWyrm
12539241fe2SDarkWyrm    //------------------------------------------------------------------------
126e39da397SStephan Aßmus    static inline int dbl_to_plain_fx(double d)
12739241fe2SDarkWyrm    {
128e39da397SStephan Aßmus        return int(d * 65536.0);
12939241fe2SDarkWyrm    }
13039241fe2SDarkWyrm
131e39da397SStephan Aßmus    //------------------------------------------------------------------------
132e39da397SStephan Aßmus    static inline double int26p6_to_dbl(int p)
133e39da397SStephan Aßmus    {
134e39da397SStephan Aßmus        return double(p) / 64.0;
135e39da397SStephan Aßmus    }
13639241fe2SDarkWyrm
13739241fe2SDarkWyrm    //------------------------------------------------------------------------
138e39da397SStephan Aßmus    static inline int dbl_to_int26p6(double p)
13939241fe2SDarkWyrm    {
140e39da397SStephan Aßmus        return int(p * 64.0 + 0.5);
14139241fe2SDarkWyrm    }
14239241fe2SDarkWyrm
14339241fe2SDarkWyrm
14439241fe2SDarkWyrm    //------------------------------------------------------------------------
145e39da397SStephan Aßmus    template<class PathStorage>
14639241fe2SDarkWyrm    bool decompose_ft_outline(const FT_Outline& outline,
14739241fe2SDarkWyrm                              bool flip_y,
148e39da397SStephan Aßmus                              const trans_affine& mtx,
149e39da397SStephan Aßmus                              PathStorage& path)
15039241fe2SDarkWyrm    {
151e39da397SStephan Aßmus        typedef typename PathStorage::value_type value_type;
152e39da397SStephan Aßmus
15339241fe2SDarkWyrm        FT_Vector   v_last;
15439241fe2SDarkWyrm        FT_Vector   v_control;
15539241fe2SDarkWyrm        FT_Vector   v_start;
156e39da397SStephan Aßmus        double x1, y1, x2, y2, x3, y3;
15739241fe2SDarkWyrm
15839241fe2SDarkWyrm        FT_Vector*  point;
15939241fe2SDarkWyrm        FT_Vector*  limit;
16039241fe2SDarkWyrm        char*       tags;
16139241fe2SDarkWyrm
16239241fe2SDarkWyrm        int   n;         // index of contour in outline
16339241fe2SDarkWyrm        int   first;     // index of first point in contour
16439241fe2SDarkWyrm        char  tag;       // current point's state
16539241fe2SDarkWyrm
16639241fe2SDarkWyrm        first = 0;
16739241fe2SDarkWyrm
16839241fe2SDarkWyrm        for(n = 0; n < outline.n_contours; n++)
16939241fe2SDarkWyrm        {
17039241fe2SDarkWyrm            int  last;  // index of last point in contour
17139241fe2SDarkWyrm
17239241fe2SDarkWyrm            last  = outline.contours[n];
17339241fe2SDarkWyrm            limit = outline.points + last;
17439241fe2SDarkWyrm
17539241fe2SDarkWyrm            v_start = outline.points[first];
17639241fe2SDarkWyrm            v_last  = outline.points[last];
17739241fe2SDarkWyrm
17839241fe2SDarkWyrm            v_control = v_start;
17939241fe2SDarkWyrm
18039241fe2SDarkWyrm            point = outline.points + first;
18139241fe2SDarkWyrm            tags  = outline.tags  + first;
18239241fe2SDarkWyrm            tag   = FT_CURVE_TAG(tags[0]);
18339241fe2SDarkWyrm
18439241fe2SDarkWyrm            // A contour cannot start with a cubic control point!
18539241fe2SDarkWyrm            if(tag == FT_CURVE_TAG_CUBIC) return false;
18639241fe2SDarkWyrm
18739241fe2SDarkWyrm            // check first point to determine origin
18839241fe2SDarkWyrm            if( tag == FT_CURVE_TAG_CONIC)
18939241fe2SDarkWyrm            {
19039241fe2SDarkWyrm                // first point is conic control.  Yes, this happens.
19139241fe2SDarkWyrm                if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
19239241fe2SDarkWyrm                {
19339241fe2SDarkWyrm                    // start at last point if it is on the curve
19439241fe2SDarkWyrm                    v_start = v_last;
19539241fe2SDarkWyrm                    limit--;
19639241fe2SDarkWyrm                }
19739241fe2SDarkWyrm                else
19839241fe2SDarkWyrm                {
19939241fe2SDarkWyrm                    // if both first and last points are conic,
20039241fe2SDarkWyrm                    // start at their middle and record its position
20139241fe2SDarkWyrm                    // for closure
20239241fe2SDarkWyrm                    v_start.x = (v_start.x + v_last.x) / 2;
20339241fe2SDarkWyrm                    v_start.y = (v_start.y + v_last.y) / 2;
20439241fe2SDarkWyrm
20539241fe2SDarkWyrm                    v_last = v_start;
20639241fe2SDarkWyrm                }
20739241fe2SDarkWyrm                point--;
20839241fe2SDarkWyrm                tags--;
20939241fe2SDarkWyrm            }
21039241fe2SDarkWyrm
211e39da397SStephan Aßmus            x1 = int26p6_to_dbl(v_start.x);
212e39da397SStephan Aßmus            y1 = int26p6_to_dbl(v_start.y);
213e39da397SStephan Aßmus            if(flip_y) y1 = -y1;
214e39da397SStephan Aßmus            mtx.transform(&x1, &y1);
215e39da397SStephan Aßmus            path.move_to(value_type(dbl_to_int26p6(x1)),
216e39da397SStephan Aßmus                         value_type(dbl_to_int26p6(y1)));
21739241fe2SDarkWyrm
21839241fe2SDarkWyrm            while(point < limit)
21939241fe2SDarkWyrm            {
22039241fe2SDarkWyrm                point++;
22139241fe2SDarkWyrm                tags++;
22239241fe2SDarkWyrm
22339241fe2SDarkWyrm                tag = FT_CURVE_TAG(tags[0]);
22439241fe2SDarkWyrm                switch(tag)
22539241fe2SDarkWyrm                {
22639241fe2SDarkWyrm                    case FT_CURVE_TAG_ON:  // emit a single line_to
22739241fe2SDarkWyrm                    {
228e39da397SStephan Aßmus                        x1 = int26p6_to_dbl(point->x);
229e39da397SStephan Aßmus                        y1 = int26p6_to_dbl(point->y);
230e39da397SStephan Aßmus                        if(flip_y) y1 = -y1;
231e39da397SStephan Aßmus                        mtx.transform(&x1, &y1);
232e39da397SStephan Aßmus                        path.line_to(value_type(dbl_to_int26p6(x1)),
233e39da397SStephan Aßmus                                     value_type(dbl_to_int26p6(y1)));
234e39da397SStephan Aßmus                        //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y));
23539241fe2SDarkWyrm                        continue;
23639241fe2SDarkWyrm                    }
23739241fe2SDarkWyrm
23839241fe2SDarkWyrm                    case FT_CURVE_TAG_CONIC:  // consume conic arcs
23939241fe2SDarkWyrm                    {
24039241fe2SDarkWyrm                        v_control.x = point->x;
24139241fe2SDarkWyrm                        v_control.y = point->y;
24239241fe2SDarkWyrm
24339241fe2SDarkWyrm                    Do_Conic:
24439241fe2SDarkWyrm                        if(point < limit)
24539241fe2SDarkWyrm                        {
24639241fe2SDarkWyrm                            FT_Vector vec;
24739241fe2SDarkWyrm                            FT_Vector v_middle;
24839241fe2SDarkWyrm
24939241fe2SDarkWyrm                            point++;
25039241fe2SDarkWyrm                            tags++;
25139241fe2SDarkWyrm                            tag = FT_CURVE_TAG(tags[0]);
25239241fe2SDarkWyrm
25339241fe2SDarkWyrm                            vec.x = point->x;
25439241fe2SDarkWyrm                            vec.y = point->y;
25539241fe2SDarkWyrm
25639241fe2SDarkWyrm                            if(tag == FT_CURVE_TAG_ON)
25739241fe2SDarkWyrm                            {
258e39da397SStephan Aßmus                                x1 = int26p6_to_dbl(v_control.x);
259e39da397SStephan Aßmus                                y1 = int26p6_to_dbl(v_control.y);
260e39da397SStephan Aßmus                                x2 = int26p6_to_dbl(vec.x);
261e39da397SStephan Aßmus                                y2 = int26p6_to_dbl(vec.y);
262e39da397SStephan Aßmus                                if(flip_y) { y1 = -y1; y2 = -y2; }
263e39da397SStephan Aßmus                                mtx.transform(&x1, &y1);
264e39da397SStephan Aßmus                                mtx.transform(&x2, &y2);
265e39da397SStephan Aßmus                                path.curve3(value_type(dbl_to_int26p6(x1)),
266e39da397SStephan Aßmus                                            value_type(dbl_to_int26p6(y1)),
267e39da397SStephan Aßmus                                            value_type(dbl_to_int26p6(x2)),
268e39da397SStephan Aßmus                                            value_type(dbl_to_int26p6(y2)));
26939241fe2SDarkWyrm                                continue;
27039241fe2SDarkWyrm                            }
27139241fe2SDarkWyrm
27239241fe2SDarkWyrm                            if(tag != FT_CURVE_TAG_CONIC) return false;
27339241fe2SDarkWyrm
27439241fe2SDarkWyrm                            v_middle.x = (v_control.x + vec.x) / 2;
27539241fe2SDarkWyrm                            v_middle.y = (v_control.y + vec.y) / 2;
27639241fe2SDarkWyrm
277e39da397SStephan Aßmus                            x1 = int26p6_to_dbl(v_control.x);
278e39da397SStephan Aßmus                            y1 = int26p6_to_dbl(v_control.y);
279e39da397SStephan Aßmus                            x2 = int26p6_to_dbl(v_middle.x);
280e39da397SStephan Aßmus                            y2 = int26p6_to_dbl(v_middle.y);
281e39da397SStephan Aßmus                            if(flip_y) { y1 = -y1; y2 = -y2; }
282e39da397SStephan Aßmus                            mtx.transform(&x1, &y1);
283e39da397SStephan Aßmus                            mtx.transform(&x2, &y2);
284e39da397SStephan Aßmus                            path.curve3(value_type(dbl_to_int26p6(x1)),
285e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(y1)),
286e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(x2)),
287e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(y2)));
288e39da397SStephan Aßmus
289e39da397SStephan Aßmus                            //path.curve3(conv(v_control.x),
290e39da397SStephan Aßmus                            //            flip_y ? -conv(v_control.y) : conv(v_control.y),
291e39da397SStephan Aßmus                            //            conv(v_middle.x),
292e39da397SStephan Aßmus                            //            flip_y ? -conv(v_middle.y) : conv(v_middle.y));
29339241fe2SDarkWyrm
29439241fe2SDarkWyrm                            v_control = vec;
29539241fe2SDarkWyrm                            goto Do_Conic;
29639241fe2SDarkWyrm                        }
297e39da397SStephan Aßmus
298e39da397SStephan Aßmus                        x1 = int26p6_to_dbl(v_control.x);
299e39da397SStephan Aßmus                        y1 = int26p6_to_dbl(v_control.y);
300e39da397SStephan Aßmus                        x2 = int26p6_to_dbl(v_start.x);
301e39da397SStephan Aßmus                        y2 = int26p6_to_dbl(v_start.y);
302e39da397SStephan Aßmus                        if(flip_y) { y1 = -y1; y2 = -y2; }
303e39da397SStephan Aßmus                        mtx.transform(&x1, &y1);
304e39da397SStephan Aßmus                        mtx.transform(&x2, &y2);
305e39da397SStephan Aßmus                        path.curve3(value_type(dbl_to_int26p6(x1)),
306e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(y1)),
307e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(x2)),
308e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(y2)));
309e39da397SStephan Aßmus
310e39da397SStephan Aßmus                        //path.curve3(conv(v_control.x),
311e39da397SStephan Aßmus                        //            flip_y ? -conv(v_control.y) : conv(v_control.y),
312e39da397SStephan Aßmus                        //            conv(v_start.x),
313e39da397SStephan Aßmus                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
31439241fe2SDarkWyrm                        goto Close;
31539241fe2SDarkWyrm                    }
31639241fe2SDarkWyrm
31739241fe2SDarkWyrm                    default:  // FT_CURVE_TAG_CUBIC
31839241fe2SDarkWyrm                    {
31939241fe2SDarkWyrm                        FT_Vector vec1, vec2;
32039241fe2SDarkWyrm
32139241fe2SDarkWyrm                        if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
32239241fe2SDarkWyrm                        {
32339241fe2SDarkWyrm                            return false;
32439241fe2SDarkWyrm                        }
32539241fe2SDarkWyrm
32639241fe2SDarkWyrm                        vec1.x = point[0].x;
32739241fe2SDarkWyrm                        vec1.y = point[0].y;
32839241fe2SDarkWyrm                        vec2.x = point[1].x;
32939241fe2SDarkWyrm                        vec2.y = point[1].y;
33039241fe2SDarkWyrm
33139241fe2SDarkWyrm                        point += 2;
33239241fe2SDarkWyrm                        tags  += 2;
33339241fe2SDarkWyrm
33439241fe2SDarkWyrm                        if(point <= limit)
33539241fe2SDarkWyrm                        {
33639241fe2SDarkWyrm                            FT_Vector vec;
33739241fe2SDarkWyrm
33839241fe2SDarkWyrm                            vec.x = point->x;
33939241fe2SDarkWyrm                            vec.y = point->y;
34039241fe2SDarkWyrm
341e39da397SStephan Aßmus                            x1 = int26p6_to_dbl(vec1.x);
342e39da397SStephan Aßmus                            y1 = int26p6_to_dbl(vec1.y);
343e39da397SStephan Aßmus                            x2 = int26p6_to_dbl(vec2.x);
344e39da397SStephan Aßmus                            y2 = int26p6_to_dbl(vec2.y);
345e39da397SStephan Aßmus                            x3 = int26p6_to_dbl(vec.x);
346e39da397SStephan Aßmus                            y3 = int26p6_to_dbl(vec.y);
347e39da397SStephan Aßmus                            if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
348e39da397SStephan Aßmus                            mtx.transform(&x1, &y1);
349e39da397SStephan Aßmus                            mtx.transform(&x2, &y2);
350e39da397SStephan Aßmus                            mtx.transform(&x3, &y3);
351e39da397SStephan Aßmus                            path.curve4(value_type(dbl_to_int26p6(x1)),
352e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(y1)),
353e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(x2)),
354e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(y2)),
355e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(x3)),
356e39da397SStephan Aßmus                                        value_type(dbl_to_int26p6(y3)));
357e39da397SStephan Aßmus
358e39da397SStephan Aßmus                            //path.curve4(conv(vec1.x),
359e39da397SStephan Aßmus                            //            flip_y ? -conv(vec1.y) : conv(vec1.y),
360e39da397SStephan Aßmus                            //            conv(vec2.x),
361e39da397SStephan Aßmus                            //            flip_y ? -conv(vec2.y) : conv(vec2.y),
362e39da397SStephan Aßmus                            //            conv(vec.x),
363e39da397SStephan Aßmus                            //            flip_y ? -conv(vec.y) : conv(vec.y));
36439241fe2SDarkWyrm                            continue;
36539241fe2SDarkWyrm                        }
36639241fe2SDarkWyrm
367e39da397SStephan Aßmus                        x1 = int26p6_to_dbl(vec1.x);
368e39da397SStephan Aßmus                        y1 = int26p6_to_dbl(vec1.y);
369e39da397SStephan Aßmus                        x2 = int26p6_to_dbl(vec2.x);
370e39da397SStephan Aßmus                        y2 = int26p6_to_dbl(vec2.y);
371e39da397SStephan Aßmus                        x3 = int26p6_to_dbl(v_start.x);
372e39da397SStephan Aßmus                        y3 = int26p6_to_dbl(v_start.y);
373e39da397SStephan Aßmus                        if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
374e39da397SStephan Aßmus                        mtx.transform(&x1, &y1);
375e39da397SStephan Aßmus                        mtx.transform(&x2, &y2);
376e39da397SStephan Aßmus                        mtx.transform(&x3, &y3);
377e39da397SStephan Aßmus                        path.curve4(value_type(dbl_to_int26p6(x1)),
378e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(y1)),
379e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(x2)),
380e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(y2)),
381e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(x3)),
382e39da397SStephan Aßmus                                    value_type(dbl_to_int26p6(y3)));
383e39da397SStephan Aßmus
384e39da397SStephan Aßmus                        //path.curve4(conv(vec1.x),
385e39da397SStephan Aßmus                        //            flip_y ? -conv(vec1.y) : conv(vec1.y),
386e39da397SStephan Aßmus                        //            conv(vec2.x),
387e39da397SStephan Aßmus                        //            flip_y ? -conv(vec2.y) : conv(vec2.y),
388e39da397SStephan Aßmus                        //            conv(v_start.x),
389e39da397SStephan Aßmus                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
39039241fe2SDarkWyrm                        goto Close;
39139241fe2SDarkWyrm                    }
39239241fe2SDarkWyrm                }
39339241fe2SDarkWyrm            }
39439241fe2SDarkWyrm
39539241fe2SDarkWyrm            path.close_polygon();
39639241fe2SDarkWyrm
39739241fe2SDarkWyrm       Close:
39839241fe2SDarkWyrm            first = last + 1;
39939241fe2SDarkWyrm        }
40039241fe2SDarkWyrm
40139241fe2SDarkWyrm        return true;
40239241fe2SDarkWyrm    }
40339241fe2SDarkWyrm
40439241fe2SDarkWyrm
40539241fe2SDarkWyrm
40639241fe2SDarkWyrm    //------------------------------------------------------------------------
40739241fe2SDarkWyrm    template<class Scanline, class ScanlineStorage>
40839241fe2SDarkWyrm    void decompose_ft_bitmap_mono(const FT_Bitmap& bitmap,
40939241fe2SDarkWyrm                                  int x, int y,
41039241fe2SDarkWyrm                                  bool flip_y,
41139241fe2SDarkWyrm                                  Scanline& sl,
41239241fe2SDarkWyrm                                  ScanlineStorage& storage)
41339241fe2SDarkWyrm    {
41439241fe2SDarkWyrm        int i;
41539241fe2SDarkWyrm        const int8u* buf = (const int8u*)bitmap.buffer;
41639241fe2SDarkWyrm        int pitch = bitmap.pitch;
41739241fe2SDarkWyrm        sl.reset(x, x + bitmap.width);
418e39da397SStephan Aßmus        storage.prepare();
41939241fe2SDarkWyrm        if(flip_y)
42039241fe2SDarkWyrm        {
42139241fe2SDarkWyrm            buf += bitmap.pitch * (bitmap.rows - 1);
42239241fe2SDarkWyrm            y += bitmap.rows;
42339241fe2SDarkWyrm            pitch = -pitch;
42439241fe2SDarkWyrm        }
42539241fe2SDarkWyrm        for(i = 0; i < bitmap.rows; i++)
42639241fe2SDarkWyrm        {
42739241fe2SDarkWyrm            sl.reset_spans();
42839241fe2SDarkWyrm            bitset_iterator bits(buf, 0);
42939241fe2SDarkWyrm            int j;
43039241fe2SDarkWyrm            for(j = 0; j < bitmap.width; j++)
43139241fe2SDarkWyrm            {
43239241fe2SDarkWyrm                if(bits.bit()) sl.add_cell(x + j, cover_full);
43339241fe2SDarkWyrm                ++bits;
43439241fe2SDarkWyrm            }
43539241fe2SDarkWyrm            buf += pitch;
43639241fe2SDarkWyrm            if(sl.num_spans())
43739241fe2SDarkWyrm            {
43839241fe2SDarkWyrm                sl.finalize(y - i - 1);
43939241fe2SDarkWyrm                storage.render(sl);
44039241fe2SDarkWyrm            }
44139241fe2SDarkWyrm        }
44239241fe2SDarkWyrm    }
44339241fe2SDarkWyrm
44439241fe2SDarkWyrm
44539241fe2SDarkWyrm
44639241fe2SDarkWyrm    //------------------------------------------------------------------------
44739241fe2SDarkWyrm    template<class Rasterizer, class Scanline, class ScanlineStorage>
44839241fe2SDarkWyrm    void decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap,
44939241fe2SDarkWyrm                                   int x, int y,
45039241fe2SDarkWyrm                                   bool flip_y,
45139241fe2SDarkWyrm                                   Rasterizer& ras,
45239241fe2SDarkWyrm                                   Scanline& sl,
45339241fe2SDarkWyrm                                   ScanlineStorage& storage)
45439241fe2SDarkWyrm    {
45539241fe2SDarkWyrm        int i, j;
45639241fe2SDarkWyrm        const int8u* buf = (const int8u*)bitmap.buffer;
45739241fe2SDarkWyrm        int pitch = bitmap.pitch;
45839241fe2SDarkWyrm        sl.reset(x, x + bitmap.width);
459e39da397SStephan Aßmus        storage.prepare();
46039241fe2SDarkWyrm        if(flip_y)
46139241fe2SDarkWyrm        {
46239241fe2SDarkWyrm            buf += bitmap.pitch * (bitmap.rows - 1);
46339241fe2SDarkWyrm            y += bitmap.rows;
46439241fe2SDarkWyrm            pitch = -pitch;
46539241fe2SDarkWyrm        }
46639241fe2SDarkWyrm        for(i = 0; i < bitmap.rows; i++)
46739241fe2SDarkWyrm        {
46839241fe2SDarkWyrm            sl.reset_spans();
46939241fe2SDarkWyrm            const int8u* p = buf;
47039241fe2SDarkWyrm            for(j = 0; j < bitmap.width; j++)
47139241fe2SDarkWyrm            {
47239241fe2SDarkWyrm                if(*p) sl.add_cell(x + j, ras.apply_gamma(*p));
47339241fe2SDarkWyrm                ++p;
47439241fe2SDarkWyrm            }
47539241fe2SDarkWyrm            buf += pitch;
47639241fe2SDarkWyrm            if(sl.num_spans())
47739241fe2SDarkWyrm            {
47839241fe2SDarkWyrm                sl.finalize(y - i - 1);
47939241fe2SDarkWyrm                storage.render(sl);
48039241fe2SDarkWyrm            }
48139241fe2SDarkWyrm        }
48239241fe2SDarkWyrm    }
48339241fe2SDarkWyrm
48439241fe2SDarkWyrm
48539241fe2SDarkWyrm
48639241fe2SDarkWyrm
48739241fe2SDarkWyrm
48839241fe2SDarkWyrm
48939241fe2SDarkWyrm
49039241fe2SDarkWyrm
49139241fe2SDarkWyrm
49239241fe2SDarkWyrm
49339241fe2SDarkWyrm
49439241fe2SDarkWyrm
49539241fe2SDarkWyrm
49639241fe2SDarkWyrm    //------------------------------------------------------------------------
49739241fe2SDarkWyrm    font_engine_freetype_base::~font_engine_freetype_base()
49839241fe2SDarkWyrm    {
49939241fe2SDarkWyrm        unsigned i;
50039241fe2SDarkWyrm        for(i = 0; i < m_num_faces; ++i)
50139241fe2SDarkWyrm        {
50239241fe2SDarkWyrm            delete [] m_face_names[i];
50339241fe2SDarkWyrm            FT_Done_Face(m_faces[i]);
50439241fe2SDarkWyrm        }
50539241fe2SDarkWyrm        delete [] m_face_names;
50639241fe2SDarkWyrm        delete [] m_faces;
50739241fe2SDarkWyrm        delete [] m_signature;
50839241fe2SDarkWyrm        if(m_library_initialized) FT_Done_FreeType(m_library);
50939241fe2SDarkWyrm    }
51039241fe2SDarkWyrm
51139241fe2SDarkWyrm
51239241fe2SDarkWyrm    //------------------------------------------------------------------------
51339241fe2SDarkWyrm    font_engine_freetype_base::font_engine_freetype_base(bool flag32,
51439241fe2SDarkWyrm                                                         unsigned max_faces) :
51539241fe2SDarkWyrm        m_flag32(flag32),
51639241fe2SDarkWyrm        m_change_stamp(0),
51739241fe2SDarkWyrm        m_last_error(0),
51839241fe2SDarkWyrm        m_name(0),
51939241fe2SDarkWyrm        m_name_len(256-16-1),
52039241fe2SDarkWyrm        m_face_index(0),
52139241fe2SDarkWyrm        m_char_map(FT_ENCODING_NONE),
52239241fe2SDarkWyrm        m_signature(new char [256+256-16]),
52339241fe2SDarkWyrm        m_height(0),
52439241fe2SDarkWyrm        m_width(0),
52539241fe2SDarkWyrm        m_hinting(true),
52639241fe2SDarkWyrm        m_flip_y(false),
52739241fe2SDarkWyrm        m_library_initialized(false),
52839241fe2SDarkWyrm        m_library(0),
52939241fe2SDarkWyrm        m_faces(new FT_Face [max_faces]),
53039241fe2SDarkWyrm        m_face_names(new char* [max_faces]),
53139241fe2SDarkWyrm        m_num_faces(0),
53239241fe2SDarkWyrm        m_max_faces(max_faces),
53339241fe2SDarkWyrm        m_cur_face(0),
53439241fe2SDarkWyrm        m_resolution(0),
53539241fe2SDarkWyrm        m_glyph_rendering(glyph_ren_native_gray8),
53639241fe2SDarkWyrm        m_glyph_index(0),
53739241fe2SDarkWyrm        m_data_size(0),
53839241fe2SDarkWyrm        m_data_type(glyph_data_invalid),
53939241fe2SDarkWyrm        m_bounds(1,1,0,0),
54039241fe2SDarkWyrm        m_advance_x(0.0),
54139241fe2SDarkWyrm        m_advance_y(0.0),
54239241fe2SDarkWyrm
54339241fe2SDarkWyrm        m_path16(),
54439241fe2SDarkWyrm        m_path32(),
54539241fe2SDarkWyrm        m_curves16(m_path16),
54639241fe2SDarkWyrm        m_curves32(m_path32),
54739241fe2SDarkWyrm        m_scanline_aa(),
54839241fe2SDarkWyrm        m_scanline_bin(),
54939241fe2SDarkWyrm        m_scanlines_aa(),
55039241fe2SDarkWyrm        m_scanlines_bin(),
55139241fe2SDarkWyrm        m_rasterizer()
55239241fe2SDarkWyrm    {
55339241fe2SDarkWyrm        m_curves16.approximation_scale(4.0);
55439241fe2SDarkWyrm        m_curves32.approximation_scale(4.0);
55539241fe2SDarkWyrm        m_last_error = FT_Init_FreeType(&m_library);
55639241fe2SDarkWyrm        if(m_last_error == 0) m_library_initialized = true;
55739241fe2SDarkWyrm    }
55839241fe2SDarkWyrm
55939241fe2SDarkWyrm
56039241fe2SDarkWyrm
56139241fe2SDarkWyrm    //------------------------------------------------------------------------
56239241fe2SDarkWyrm    void font_engine_freetype_base::resolution(unsigned dpi)
56339241fe2SDarkWyrm    {
56439241fe2SDarkWyrm        m_resolution = dpi;
56539241fe2SDarkWyrm        update_char_size();
56639241fe2SDarkWyrm    }
56739241fe2SDarkWyrm
56839241fe2SDarkWyrm
56939241fe2SDarkWyrm    //------------------------------------------------------------------------
57039241fe2SDarkWyrm    int font_engine_freetype_base::find_face(const char* face_name) const
57139241fe2SDarkWyrm    {
57239241fe2SDarkWyrm        unsigned i;
57339241fe2SDarkWyrm        for(i = 0; i < m_num_faces; ++i)
57439241fe2SDarkWyrm        {
57539241fe2SDarkWyrm            if(strcmp(face_name, m_face_names[i]) == 0) return i;
57639241fe2SDarkWyrm        }
57739241fe2SDarkWyrm        return -1;
57839241fe2SDarkWyrm    }
57939241fe2SDarkWyrm
58039241fe2SDarkWyrm
581e39da397SStephan Aßmus    //------------------------------------------------------------------------
582e39da397SStephan Aßmus    double font_engine_freetype_base::ascender() const
583e39da397SStephan Aßmus    {
584e39da397SStephan Aßmus        if(m_cur_face)
585e39da397SStephan Aßmus        {
586e39da397SStephan Aßmus            return m_cur_face->ascender * height() / m_cur_face->height;
587e39da397SStephan Aßmus        }
588e39da397SStephan Aßmus        return 0.0;
589e39da397SStephan Aßmus    }
590e39da397SStephan Aßmus
591e39da397SStephan Aßmus    //------------------------------------------------------------------------
592e39da397SStephan Aßmus    double font_engine_freetype_base::descender() const
593e39da397SStephan Aßmus    {
594e39da397SStephan Aßmus        if(m_cur_face)
595e39da397SStephan Aßmus        {
596e39da397SStephan Aßmus            return m_cur_face->descender * height() / m_cur_face->height;
597e39da397SStephan Aßmus        }
598e39da397SStephan Aßmus        return 0.0;
599e39da397SStephan Aßmus    }
600e39da397SStephan Aßmus
601e39da397SStephan Aßmus
60239241fe2SDarkWyrm    //------------------------------------------------------------------------
60339241fe2SDarkWyrm    bool font_engine_freetype_base::load_font(const char* font_name,
60439241fe2SDarkWyrm                                              unsigned face_index,
605e39da397SStephan Aßmus                                              glyph_rendering ren_type,
606e39da397SStephan Aßmus                                              const char* font_mem,
607e39da397SStephan Aßmus                                              const long font_mem_size)
60839241fe2SDarkWyrm    {
60939241fe2SDarkWyrm        bool ret = false;
61039241fe2SDarkWyrm
61139241fe2SDarkWyrm        if(m_library_initialized)
61239241fe2SDarkWyrm        {
61339241fe2SDarkWyrm            m_last_error = 0;
61439241fe2SDarkWyrm
61539241fe2SDarkWyrm            int idx = find_face(font_name);
61639241fe2SDarkWyrm            if(idx >= 0)
61739241fe2SDarkWyrm            {
61839241fe2SDarkWyrm                m_cur_face = m_faces[idx];
61939241fe2SDarkWyrm                m_name     = m_face_names[idx];
62039241fe2SDarkWyrm            }
62139241fe2SDarkWyrm            else
62239241fe2SDarkWyrm            {
62339241fe2SDarkWyrm                if(m_num_faces >= m_max_faces)
62439241fe2SDarkWyrm                {
62539241fe2SDarkWyrm                    delete [] m_face_names[0];
62639241fe2SDarkWyrm                    FT_Done_Face(m_faces[0]);
62739241fe2SDarkWyrm                    memcpy(m_faces,
62839241fe2SDarkWyrm                           m_faces + 1,
62939241fe2SDarkWyrm                           (m_max_faces - 1) * sizeof(FT_Face));
63039241fe2SDarkWyrm                    memcpy(m_face_names,
63139241fe2SDarkWyrm                           m_face_names + 1,
63239241fe2SDarkWyrm                           (m_max_faces - 1) * sizeof(char*));
63339241fe2SDarkWyrm                    m_num_faces = m_max_faces - 1;
63439241fe2SDarkWyrm                }
63539241fe2SDarkWyrm
636e39da397SStephan Aßmus                if (font_mem && font_mem_size)
637e39da397SStephan Aßmus                {
638e39da397SStephan Aßmus                    m_last_error = FT_New_Memory_Face(m_library,
639e39da397SStephan Aßmus                                                      (const FT_Byte*)font_mem,
640e39da397SStephan Aßmus                                                      font_mem_size,
641e39da397SStephan Aßmus                                                      face_index,
642e39da397SStephan Aßmus                                                      &m_faces[m_num_faces]);
643e39da397SStephan Aßmus                }
644e39da397SStephan Aßmus                else
645e39da397SStephan Aßmus                {
646e39da397SStephan Aßmus                    m_last_error = FT_New_Face(m_library,
647e39da397SStephan Aßmus                                               font_name,
648e39da397SStephan Aßmus                                               face_index,
649e39da397SStephan Aßmus                                               &m_faces[m_num_faces]);
650e39da397SStephan Aßmus                }
651e39da397SStephan Aßmus
65239241fe2SDarkWyrm                if(m_last_error == 0)
65339241fe2SDarkWyrm                {
65439241fe2SDarkWyrm                    m_face_names[m_num_faces] = new char [strlen(font_name) + 1];
65539241fe2SDarkWyrm                    strcpy(m_face_names[m_num_faces], font_name);
65639241fe2SDarkWyrm                    m_cur_face = m_faces[m_num_faces];
65739241fe2SDarkWyrm                    m_name     = m_face_names[m_num_faces];
65839241fe2SDarkWyrm                    ++m_num_faces;
65939241fe2SDarkWyrm                }
66039241fe2SDarkWyrm                else
66139241fe2SDarkWyrm                {
66239241fe2SDarkWyrm                    m_face_names[m_num_faces] = 0;
66339241fe2SDarkWyrm                    m_cur_face = 0;
66439241fe2SDarkWyrm                    m_name = 0;
66539241fe2SDarkWyrm                }
66639241fe2SDarkWyrm            }
66739241fe2SDarkWyrm
66839241fe2SDarkWyrm
66939241fe2SDarkWyrm            if(m_last_error == 0)
67039241fe2SDarkWyrm            {
67139241fe2SDarkWyrm                ret = true;
672e39da397SStephan Aßmus
67339241fe2SDarkWyrm                switch(ren_type)
67439241fe2SDarkWyrm                {
67539241fe2SDarkWyrm                case glyph_ren_native_mono:
67639241fe2SDarkWyrm                    m_glyph_rendering = glyph_ren_native_mono;
67739241fe2SDarkWyrm                    break;
67839241fe2SDarkWyrm
67939241fe2SDarkWyrm                case glyph_ren_native_gray8:
68039241fe2SDarkWyrm                    m_glyph_rendering = glyph_ren_native_gray8;
68139241fe2SDarkWyrm                    break;
68239241fe2SDarkWyrm
68339241fe2SDarkWyrm                case glyph_ren_outline:
68439241fe2SDarkWyrm                    if(FT_IS_SCALABLE(m_cur_face))
68539241fe2SDarkWyrm                    {
68639241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_outline;
68739241fe2SDarkWyrm                    }
68839241fe2SDarkWyrm                    else
68939241fe2SDarkWyrm                    {
69039241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_native_gray8;
69139241fe2SDarkWyrm                    }
69239241fe2SDarkWyrm                    break;
69339241fe2SDarkWyrm
69439241fe2SDarkWyrm                case glyph_ren_agg_mono:
69539241fe2SDarkWyrm                    if(FT_IS_SCALABLE(m_cur_face))
69639241fe2SDarkWyrm                    {
69739241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_agg_mono;
69839241fe2SDarkWyrm                    }
69939241fe2SDarkWyrm                    else
70039241fe2SDarkWyrm                    {
70139241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_native_mono;
70239241fe2SDarkWyrm                    }
70339241fe2SDarkWyrm                    break;
70439241fe2SDarkWyrm
70539241fe2SDarkWyrm                case glyph_ren_agg_gray8:
70639241fe2SDarkWyrm                    if(FT_IS_SCALABLE(m_cur_face))
70739241fe2SDarkWyrm                    {
70839241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_agg_gray8;
70939241fe2SDarkWyrm                    }
71039241fe2SDarkWyrm                    else
71139241fe2SDarkWyrm                    {
71239241fe2SDarkWyrm                        m_glyph_rendering = glyph_ren_native_gray8;
71339241fe2SDarkWyrm                    }
71439241fe2SDarkWyrm                    break;
71539241fe2SDarkWyrm                }
716e39da397SStephan Aßmus                update_signature();
71739241fe2SDarkWyrm            }
71839241fe2SDarkWyrm        }
71939241fe2SDarkWyrm        return ret;
72039241fe2SDarkWyrm    }
72139241fe2SDarkWyrm
72239241fe2SDarkWyrm
72339241fe2SDarkWyrm    //------------------------------------------------------------------------
72439241fe2SDarkWyrm    bool font_engine_freetype_base::attach(const char* file_name)
72539241fe2SDarkWyrm    {
72639241fe2SDarkWyrm        if(m_cur_face)
72739241fe2SDarkWyrm        {
72839241fe2SDarkWyrm            m_last_error = FT_Attach_File(m_cur_face, file_name);
72939241fe2SDarkWyrm            return m_last_error == 0;
73039241fe2SDarkWyrm        }
73139241fe2SDarkWyrm        return false;
73239241fe2SDarkWyrm    }
73339241fe2SDarkWyrm
73439241fe2SDarkWyrm    //------------------------------------------------------------------------
73539241fe2SDarkWyrm    unsigned font_engine_freetype_base::num_faces() const
73639241fe2SDarkWyrm    {
73739241fe2SDarkWyrm        if(m_cur_face)
73839241fe2SDarkWyrm        {
73939241fe2SDarkWyrm            return m_cur_face->num_faces;
74039241fe2SDarkWyrm        }
74139241fe2SDarkWyrm        return 0;
74239241fe2SDarkWyrm    }
74339241fe2SDarkWyrm
74439241fe2SDarkWyrm    //------------------------------------------------------------------------
74539241fe2SDarkWyrm    bool font_engine_freetype_base::char_map(FT_Encoding char_map)
74639241fe2SDarkWyrm    {
74739241fe2SDarkWyrm        if(m_cur_face)
74839241fe2SDarkWyrm        {
749ba62028dSJim Barry            m_last_error = FT_Select_Charmap(m_cur_face, char_map);
75039241fe2SDarkWyrm            if(m_last_error == 0)
75139241fe2SDarkWyrm            {
752ba62028dSJim Barry                m_char_map = char_map;
75339241fe2SDarkWyrm                update_signature();
75439241fe2SDarkWyrm                return true;
75539241fe2SDarkWyrm            }
75639241fe2SDarkWyrm        }
75739241fe2SDarkWyrm        return false;
75839241fe2SDarkWyrm    }
75939241fe2SDarkWyrm
76039241fe2SDarkWyrm    //------------------------------------------------------------------------
76139241fe2SDarkWyrm    bool font_engine_freetype_base::height(double h)
76239241fe2SDarkWyrm    {
76339241fe2SDarkWyrm        m_height = int(h * 64.0);
76439241fe2SDarkWyrm        if(m_cur_face)
76539241fe2SDarkWyrm        {
76639241fe2SDarkWyrm            update_char_size();
76739241fe2SDarkWyrm            return true;
76839241fe2SDarkWyrm        }
76939241fe2SDarkWyrm        return false;
77039241fe2SDarkWyrm    }
77139241fe2SDarkWyrm
77239241fe2SDarkWyrm    //------------------------------------------------------------------------
77339241fe2SDarkWyrm    bool font_engine_freetype_base::width(double w)
77439241fe2SDarkWyrm    {
77539241fe2SDarkWyrm        m_width = int(w * 64.0);
77639241fe2SDarkWyrm        if(m_cur_face)
77739241fe2SDarkWyrm        {
77839241fe2SDarkWyrm            update_char_size();
77939241fe2SDarkWyrm            return true;
78039241fe2SDarkWyrm        }
78139241fe2SDarkWyrm        return false;
78239241fe2SDarkWyrm    }
78339241fe2SDarkWyrm
78439241fe2SDarkWyrm    //------------------------------------------------------------------------
785e39da397SStephan Aßmus    void font_engine_freetype_base::hinting(bool h)
786e39da397SStephan Aßmus    {
787e39da397SStephan Aßmus        m_hinting = h;
78839241fe2SDarkWyrm        if(m_cur_face)
78939241fe2SDarkWyrm        {
79039241fe2SDarkWyrm            update_signature();
79139241fe2SDarkWyrm        }
79239241fe2SDarkWyrm    }
79339241fe2SDarkWyrm
79439241fe2SDarkWyrm    //------------------------------------------------------------------------
795e39da397SStephan Aßmus    void font_engine_freetype_base::flip_y(bool f)
79639241fe2SDarkWyrm    {
797e39da397SStephan Aßmus        m_flip_y = f;
79839241fe2SDarkWyrm        if(m_cur_face)
79939241fe2SDarkWyrm        {
80039241fe2SDarkWyrm            update_signature();
80139241fe2SDarkWyrm        }
80239241fe2SDarkWyrm    }
80339241fe2SDarkWyrm
80439241fe2SDarkWyrm    //------------------------------------------------------------------------
805e39da397SStephan Aßmus    void font_engine_freetype_base::transform(const trans_affine& affine)
806e39da397SStephan Aßmus    {
807e39da397SStephan Aßmus        m_affine = affine;
80839241fe2SDarkWyrm        if(m_cur_face)
80939241fe2SDarkWyrm        {
810e39da397SStephan Aßmus            update_signature();
81139241fe2SDarkWyrm        }
81239241fe2SDarkWyrm    }
81339241fe2SDarkWyrm
81439241fe2SDarkWyrm    //------------------------------------------------------------------------
81539241fe2SDarkWyrm    void font_engine_freetype_base::update_signature()
81639241fe2SDarkWyrm    {
81739241fe2SDarkWyrm        if(m_cur_face && m_name)
81839241fe2SDarkWyrm        {
81939241fe2SDarkWyrm            unsigned name_len = strlen(m_name);
82039241fe2SDarkWyrm            if(name_len > m_name_len)
82139241fe2SDarkWyrm            {
82239241fe2SDarkWyrm                delete [] m_signature;
82339241fe2SDarkWyrm                m_signature = new char [name_len + 32 + 256];
82439241fe2SDarkWyrm                m_name_len = name_len + 32 - 1;
82539241fe2SDarkWyrm            }
82639241fe2SDarkWyrm
82739241fe2SDarkWyrm            unsigned gamma_hash = 0;
82839241fe2SDarkWyrm            if(m_glyph_rendering == glyph_ren_native_gray8 ||
82939241fe2SDarkWyrm               m_glyph_rendering == glyph_ren_agg_mono ||
83039241fe2SDarkWyrm               m_glyph_rendering == glyph_ren_agg_gray8)
83139241fe2SDarkWyrm            {
832e39da397SStephan Aßmus                unsigned char gamma_table[rasterizer_scanline_aa<>::aa_scale];
83339241fe2SDarkWyrm                unsigned i;
834e39da397SStephan Aßmus                for(i = 0; i < rasterizer_scanline_aa<>::aa_scale; ++i)
83539241fe2SDarkWyrm                {
83639241fe2SDarkWyrm                    gamma_table[i] = m_rasterizer.apply_gamma(i);
83739241fe2SDarkWyrm                }
83839241fe2SDarkWyrm                gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table));
83939241fe2SDarkWyrm            }
84039241fe2SDarkWyrm
84139241fe2SDarkWyrm            sprintf(m_signature,
842e39da397SStephan Aßmus                    "%s,%u,%d,%d,%d:%dx%d,%d,%d,%08X",
84339241fe2SDarkWyrm                    m_name,
84439241fe2SDarkWyrm                    m_char_map,
84539241fe2SDarkWyrm                    m_face_index,
84639241fe2SDarkWyrm                    int(m_glyph_rendering),
84739241fe2SDarkWyrm                    m_resolution,
84839241fe2SDarkWyrm                    m_height,
84939241fe2SDarkWyrm                    m_width,
85039241fe2SDarkWyrm                    int(m_hinting),
85139241fe2SDarkWyrm                    int(m_flip_y),
85239241fe2SDarkWyrm                    gamma_hash);
853e39da397SStephan Aßmus            if(m_glyph_rendering == glyph_ren_outline ||
854e39da397SStephan Aßmus               m_glyph_rendering == glyph_ren_agg_mono ||
855e39da397SStephan Aßmus               m_glyph_rendering == glyph_ren_agg_gray8)
856e39da397SStephan Aßmus            {
857e39da397SStephan Aßmus                double mtx[6];
858e39da397SStephan Aßmus                char buf[100];
859e39da397SStephan Aßmus                m_affine.store_to(mtx);
860e39da397SStephan Aßmus                sprintf(buf, ",%08X%08X%08X%08X%08X%08X",
861e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[0]),
862e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[1]),
863e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[2]),
864e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[3]),
865e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[4]),
866e39da397SStephan Aßmus                    dbl_to_plain_fx(mtx[5]));
867e39da397SStephan Aßmus                strcat(m_signature, buf);
868e39da397SStephan Aßmus            }
86939241fe2SDarkWyrm            ++m_change_stamp;
87039241fe2SDarkWyrm        }
87139241fe2SDarkWyrm    }
87239241fe2SDarkWyrm
87339241fe2SDarkWyrm
87439241fe2SDarkWyrm    //------------------------------------------------------------------------
87539241fe2SDarkWyrm    void font_engine_freetype_base::update_char_size()
87639241fe2SDarkWyrm    {
87739241fe2SDarkWyrm        if(m_cur_face)
87839241fe2SDarkWyrm        {
87939241fe2SDarkWyrm            if(m_resolution)
88039241fe2SDarkWyrm            {
88139241fe2SDarkWyrm                FT_Set_Char_Size(m_cur_face,
88239241fe2SDarkWyrm                                 m_width,       // char_width in 1/64th of points
88339241fe2SDarkWyrm                                 m_height,      // char_height in 1/64th of points
88439241fe2SDarkWyrm                                 m_resolution,  // horizontal device resolution
88539241fe2SDarkWyrm                                 m_resolution); // vertical device resolution
88639241fe2SDarkWyrm            }
88739241fe2SDarkWyrm            else
88839241fe2SDarkWyrm            {
88939241fe2SDarkWyrm                FT_Set_Pixel_Sizes(m_cur_face,
89039241fe2SDarkWyrm                                   m_width >> 6,    // pixel_width
89139241fe2SDarkWyrm                                   m_height >> 6);  // pixel_height
89239241fe2SDarkWyrm            }
89339241fe2SDarkWyrm            update_signature();
89439241fe2SDarkWyrm        }
89539241fe2SDarkWyrm    }
89639241fe2SDarkWyrm
89739241fe2SDarkWyrm
89839241fe2SDarkWyrm
89939241fe2SDarkWyrm
90039241fe2SDarkWyrm
90139241fe2SDarkWyrm    //------------------------------------------------------------------------
90239241fe2SDarkWyrm    bool font_engine_freetype_base::prepare_glyph(unsigned glyph_code)
90339241fe2SDarkWyrm    {
90439241fe2SDarkWyrm        m_glyph_index = FT_Get_Char_Index(m_cur_face, glyph_code);
90539241fe2SDarkWyrm        m_last_error = FT_Load_Glyph(m_cur_face,
90639241fe2SDarkWyrm                                     m_glyph_index,
90739241fe2SDarkWyrm                                     m_hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);
90839241fe2SDarkWyrm//                                     m_hinting ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_NO_HINTING);
90939241fe2SDarkWyrm        if(m_last_error == 0)
91039241fe2SDarkWyrm        {
91139241fe2SDarkWyrm            switch(m_glyph_rendering)
91239241fe2SDarkWyrm            {
91339241fe2SDarkWyrm            case glyph_ren_native_mono:
91439241fe2SDarkWyrm                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_MONO);
91539241fe2SDarkWyrm                if(m_last_error == 0)
91639241fe2SDarkWyrm                {
91739241fe2SDarkWyrm                    decompose_ft_bitmap_mono(m_cur_face->glyph->bitmap,
91839241fe2SDarkWyrm                                             m_cur_face->glyph->bitmap_left,
919e39da397SStephan Aßmus                                             m_flip_y ? -m_cur_face->glyph->bitmap_top :
920e39da397SStephan Aßmus                                                         m_cur_face->glyph->bitmap_top,
921e39da397SStephan Aßmus                                             m_flip_y,
92239241fe2SDarkWyrm                                             m_scanline_bin,
92339241fe2SDarkWyrm                                             m_scanlines_bin);
92439241fe2SDarkWyrm                    m_bounds.x1 = m_scanlines_bin.min_x();
92539241fe2SDarkWyrm                    m_bounds.y1 = m_scanlines_bin.min_y();
926e39da397SStephan Aßmus                    m_bounds.x2 = m_scanlines_bin.max_x() + 1;
927e39da397SStephan Aßmus                    m_bounds.y2 = m_scanlines_bin.max_y() + 1;
92839241fe2SDarkWyrm                    m_data_size = m_scanlines_bin.byte_size();
92939241fe2SDarkWyrm                    m_data_type = glyph_data_mono;
930e39da397SStephan Aßmus                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
931e39da397SStephan Aßmus                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
93239241fe2SDarkWyrm                    return true;
93339241fe2SDarkWyrm                }
93439241fe2SDarkWyrm                break;
93539241fe2SDarkWyrm
93639241fe2SDarkWyrm
93739241fe2SDarkWyrm            case glyph_ren_native_gray8:
93839241fe2SDarkWyrm                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL);
93939241fe2SDarkWyrm                if(m_last_error == 0)
94039241fe2SDarkWyrm                {
94139241fe2SDarkWyrm                    decompose_ft_bitmap_gray8(m_cur_face->glyph->bitmap,
94239241fe2SDarkWyrm                                              m_cur_face->glyph->bitmap_left,
943e39da397SStephan Aßmus                                              m_flip_y ? -m_cur_face->glyph->bitmap_top :
944e39da397SStephan Aßmus                                                          m_cur_face->glyph->bitmap_top,
945e39da397SStephan Aßmus                                              m_flip_y,
94639241fe2SDarkWyrm                                              m_rasterizer,
94739241fe2SDarkWyrm                                              m_scanline_aa,
94839241fe2SDarkWyrm                                              m_scanlines_aa);
94939241fe2SDarkWyrm                    m_bounds.x1 = m_scanlines_aa.min_x();
95039241fe2SDarkWyrm                    m_bounds.y1 = m_scanlines_aa.min_y();
951e39da397SStephan Aßmus                    m_bounds.x2 = m_scanlines_aa.max_x() + 1;
952e39da397SStephan Aßmus                    m_bounds.y2 = m_scanlines_aa.max_y() + 1;
95339241fe2SDarkWyrm                    m_data_size = m_scanlines_aa.byte_size();
95439241fe2SDarkWyrm                    m_data_type = glyph_data_gray8;
955e39da397SStephan Aßmus                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
956e39da397SStephan Aßmus                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
95739241fe2SDarkWyrm                    return true;
95839241fe2SDarkWyrm                }
95939241fe2SDarkWyrm                break;
96039241fe2SDarkWyrm
96139241fe2SDarkWyrm
96239241fe2SDarkWyrm            case glyph_ren_outline:
96339241fe2SDarkWyrm                if(m_last_error == 0)
96439241fe2SDarkWyrm                {
96539241fe2SDarkWyrm                    if(m_flag32)
96639241fe2SDarkWyrm                    {
96739241fe2SDarkWyrm                        m_path32.remove_all();
96839241fe2SDarkWyrm                        if(decompose_ft_outline(m_cur_face->glyph->outline,
969e39da397SStephan Aßmus                                                m_flip_y,
970e39da397SStephan Aßmus                                                m_affine,
971e39da397SStephan Aßmus                                                m_path32))
97239241fe2SDarkWyrm                        {
97339241fe2SDarkWyrm                            rect_d bnd  = m_path32.bounding_rect();
97439241fe2SDarkWyrm                            m_data_size = m_path32.byte_size();
97539241fe2SDarkWyrm                            m_data_type = glyph_data_outline;
97639241fe2SDarkWyrm                            m_bounds.x1 = int(floor(bnd.x1));
97739241fe2SDarkWyrm                            m_bounds.y1 = int(floor(bnd.y1));
97839241fe2SDarkWyrm                            m_bounds.x2 = int(ceil(bnd.x2));
97939241fe2SDarkWyrm                            m_bounds.y2 = int(ceil(bnd.y2));
980e39da397SStephan Aßmus                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
981e39da397SStephan Aßmus                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
982e39da397SStephan Aßmus                            m_affine.transform(&m_advance_x, &m_advance_y);
98339241fe2SDarkWyrm                            return true;
98439241fe2SDarkWyrm                        }
98539241fe2SDarkWyrm                    }
98639241fe2SDarkWyrm                    else
98739241fe2SDarkWyrm                    {
98839241fe2SDarkWyrm                        m_path16.remove_all();
98939241fe2SDarkWyrm                        if(decompose_ft_outline(m_cur_face->glyph->outline,
990e39da397SStephan Aßmus                                                m_flip_y,
991e39da397SStephan Aßmus                                                m_affine,
992e39da397SStephan Aßmus                                                m_path16))
99339241fe2SDarkWyrm                        {
99439241fe2SDarkWyrm                            rect_d bnd  = m_path16.bounding_rect();
99539241fe2SDarkWyrm                            m_data_size = m_path16.byte_size();
99639241fe2SDarkWyrm                            m_data_type = glyph_data_outline;
99739241fe2SDarkWyrm                            m_bounds.x1 = int(floor(bnd.x1));
99839241fe2SDarkWyrm                            m_bounds.y1 = int(floor(bnd.y1));
99939241fe2SDarkWyrm                            m_bounds.x2 = int(ceil(bnd.x2));
100039241fe2SDarkWyrm                            m_bounds.y2 = int(ceil(bnd.y2));
1001e39da397SStephan Aßmus                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
1002e39da397SStephan Aßmus                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
1003e39da397SStephan Aßmus                            m_affine.transform(&m_advance_x, &m_advance_y);
100439241fe2SDarkWyrm                            return true;
100539241fe2SDarkWyrm                        }
100639241fe2SDarkWyrm                    }
100739241fe2SDarkWyrm                }
100839241fe2SDarkWyrm                return false;
100939241fe2SDarkWyrm
101039241fe2SDarkWyrm            case glyph_ren_agg_mono:
101139241fe2SDarkWyrm                if(m_last_error == 0)
101239241fe2SDarkWyrm                {
101339241fe2SDarkWyrm                    m_rasterizer.reset();
101439241fe2SDarkWyrm                    if(m_flag32)
101539241fe2SDarkWyrm                    {
101639241fe2SDarkWyrm                        m_path32.remove_all();
101739241fe2SDarkWyrm                        decompose_ft_outline(m_cur_face->glyph->outline,
1018e39da397SStephan Aßmus                                             m_flip_y,
1019e39da397SStephan Aßmus                                             m_affine,
1020e39da397SStephan Aßmus                                             m_path32);
102139241fe2SDarkWyrm                        m_rasterizer.add_path(m_curves32);
102239241fe2SDarkWyrm                    }
102339241fe2SDarkWyrm                    else
102439241fe2SDarkWyrm                    {
102539241fe2SDarkWyrm                        m_path16.remove_all();
102639241fe2SDarkWyrm                        decompose_ft_outline(m_cur_face->glyph->outline,
1027e39da397SStephan Aßmus                                             m_flip_y,
1028e39da397SStephan Aßmus                                             m_affine,
1029e39da397SStephan Aßmus                                             m_path16);
103039241fe2SDarkWyrm                        m_rasterizer.add_path(m_curves16);
103139241fe2SDarkWyrm                    }
1032e39da397SStephan Aßmus                    m_scanlines_bin.prepare(); // Remove all
103339241fe2SDarkWyrm                    render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin);
103439241fe2SDarkWyrm                    m_bounds.x1 = m_scanlines_bin.min_x();
103539241fe2SDarkWyrm                    m_bounds.y1 = m_scanlines_bin.min_y();
1036e39da397SStephan Aßmus                    m_bounds.x2 = m_scanlines_bin.max_x() + 1;
1037e39da397SStephan Aßmus                    m_bounds.y2 = m_scanlines_bin.max_y() + 1;
103839241fe2SDarkWyrm                    m_data_size = m_scanlines_bin.byte_size();
103939241fe2SDarkWyrm                    m_data_type = glyph_data_mono;
1040