Пример #1
0
//------------------------------------------------------------------------
bool font_engine_freetype_base::add_kerning(unsigned first, unsigned second,
        double* x, double* y)
{
    if(m_cur_face && first && second && FT_HAS_KERNING(m_cur_face))
    {
        FT_Vector delta;

        FT_Get_Kerning(m_cur_face, first, second,
                       FT_KERNING_DEFAULT, &delta);

        double dx = int26p6_to_dbl(delta.x);
        double dy = int26p6_to_dbl(delta.y);
        if(m_glyph_rendering == glyph_ren_outline ||
                m_glyph_rendering == glyph_ren_agg_mono ||
                m_glyph_rendering == glyph_ren_agg_gray8)
        {
            m_affine.transform_2x2(&dx, &dy);
        }
        *x += dx;
        *y += dy;

        return true;
    }
    return false;
}
Пример #2
0
    bool decompose_ft_outline(const FT_Outline& outline,
                              bool flip_y,
                              const mapserver::trans_affine& mtx,
                              PathStorage& path)
    {
        FT_Vector   v_last;
        FT_Vector   v_control;
        FT_Vector   v_start;
        double x1, y1, x2, y2, x3, y3;

        FT_Vector*  point;
        FT_Vector*  limit;
        char*       tags;

        int   n;         // index of contour in outline
        int   first;     // index of first point in contour
        char  tag;       // current point's state

        first = 0;

        for(n = 0; n < outline.n_contours; n++)
        {
            int  last;  // index of last point in contour

            last  = outline.contours[n];
            limit = outline.points + last;

            v_start = outline.points[first];
            v_last  = outline.points[last];

            v_control = v_start;

            point = outline.points + first;
            tags  = outline.tags  + first;
            tag   = FT_CURVE_TAG(tags[0]);

            // A contour cannot start with a cubic control point!
            if(tag == FT_CURVE_TAG_CUBIC) return false;

            // check first point to determine origin
            if( tag == FT_CURVE_TAG_CONIC)
            {
                // first point is conic control.  Yes, this happens.
                if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
                {
                    // start at last point if it is on the curve
                    v_start = v_last;
                    limit--;
                }
                else
                {
                    // if both first and last points are conic,
                    // start at their middle and record its position
                    // for closure
                    v_start.x = (v_start.x + v_last.x) / 2;
                    v_start.y = (v_start.y + v_last.y) / 2;

                    v_last = v_start;
                }
                point--;
                tags--;
            }

            x1 = int26p6_to_dbl(v_start.x);
            y1 = int26p6_to_dbl(v_start.y);
            if(flip_y) y1 = -y1;
            mtx.transform(&x1, &y1);
            path.move_to(x1,y1);

            while(point < limit)
            {
                point++;
                tags++;

                tag = FT_CURVE_TAG(tags[0]);
                switch(tag)
                {
                    case FT_CURVE_TAG_ON:  // emit a single line_to
                    {
                        x1 = int26p6_to_dbl(point->x);
                        y1 = int26p6_to_dbl(point->y);
                        if(flip_y) y1 = -y1;
                        mtx.transform(&x1, &y1);
                        path.line_to(x1,y1);
                        //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y));
                        continue;
                    }

                    case FT_CURVE_TAG_CONIC:  // consume conic arcs
                    {
                        v_control.x = point->x;
                        v_control.y = point->y;

                    Do_Conic:
                        if(point < limit)
                        {
                            FT_Vector vec;
                            FT_Vector v_middle;

                            point++;
                            tags++;
                            tag = FT_CURVE_TAG(tags[0]);

                            vec.x = point->x;
                            vec.y = point->y;

                            if(tag == FT_CURVE_TAG_ON)
                            {
                                x1 = int26p6_to_dbl(v_control.x);
                                y1 = int26p6_to_dbl(v_control.y);
                                x2 = int26p6_to_dbl(vec.x);
                                y2 = int26p6_to_dbl(vec.y);
                                if(flip_y) { y1 = -y1; y2 = -y2; }
                                mtx.transform(&x1, &y1);
                                mtx.transform(&x2, &y2);
                                path.curve3(x1,y1,x2,y2);
                                continue;
                            }

                            if(tag != FT_CURVE_TAG_CONIC) return false;

                            v_middle.x = (v_control.x + vec.x) / 2;
                            v_middle.y = (v_control.y + vec.y) / 2;

                            x1 = int26p6_to_dbl(v_control.x);
                            y1 = int26p6_to_dbl(v_control.y);
                            x2 = int26p6_to_dbl(v_middle.x);
                            y2 = int26p6_to_dbl(v_middle.y);
                            if(flip_y) { y1 = -y1; y2 = -y2; }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            path.curve3(x1,y1,x2,y2);

                            //path.curve3(conv(v_control.x),
                            //            flip_y ? -conv(v_control.y) : conv(v_control.y),
                            //            conv(v_middle.x),
                            //            flip_y ? -conv(v_middle.y) : conv(v_middle.y));

                            v_control = vec;
                            goto Do_Conic;
                        }

                        x1 = int26p6_to_dbl(v_control.x);
                        y1 = int26p6_to_dbl(v_control.y);
                        x2 = int26p6_to_dbl(v_start.x);
                        y2 = int26p6_to_dbl(v_start.y);
                        if(flip_y) { y1 = -y1; y2 = -y2; }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        path.curve3(x1,y1,x2,y2);

                        //path.curve3(conv(v_control.x),
                        //            flip_y ? -conv(v_control.y) : conv(v_control.y),
                        //            conv(v_start.x),
                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
                        goto Close;
                    }

                    default:  // FT_CURVE_TAG_CUBIC
                    {
                        FT_Vector vec1, vec2;

                        if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
                        {
                            return false;
                        }

                        vec1.x = point[0].x;
                        vec1.y = point[0].y;
                        vec2.x = point[1].x;
                        vec2.y = point[1].y;

                        point += 2;
                        tags  += 2;

                        if(point <= limit)
                        {
                            FT_Vector vec;

                            vec.x = point->x;
                            vec.y = point->y;

                            x1 = int26p6_to_dbl(vec1.x);
                            y1 = int26p6_to_dbl(vec1.y);
                            x2 = int26p6_to_dbl(vec2.x);
                            y2 = int26p6_to_dbl(vec2.y);
                            x3 = int26p6_to_dbl(vec.x);
                            y3 = int26p6_to_dbl(vec.y);
                            if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            mtx.transform(&x3, &y3);
                            path.curve4(x1,y1,x2,y2,x3,y3);

                            //path.curve4(conv(vec1.x),
                            //            flip_y ? -conv(vec1.y) : conv(vec1.y),
                            //            conv(vec2.x),
                            //            flip_y ? -conv(vec2.y) : conv(vec2.y),
                            //            conv(vec.x),
                            //            flip_y ? -conv(vec.y) : conv(vec.y));
                            continue;
                        }

                        x1 = int26p6_to_dbl(vec1.x);
                        y1 = int26p6_to_dbl(vec1.y);
                        x2 = int26p6_to_dbl(vec2.x);
                        y2 = int26p6_to_dbl(vec2.y);
                        x3 = int26p6_to_dbl(v_start.x);
                        y3 = int26p6_to_dbl(v_start.y);
                        if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        mtx.transform(&x3, &y3);
                        path.curve4(x1,y1,x2,y2,x3,y3);

                        //path.curve4(conv(vec1.x),
                        //            flip_y ? -conv(vec1.y) : conv(vec1.y),
                        //            conv(vec2.x),
                        //            flip_y ? -conv(vec2.y) : conv(vec2.y),
                        //            conv(v_start.x),
                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
                        goto Close;
                    }
                }
            }

            path.close_polygon();

       Close:
            first = last + 1;
        }

        return true;
    }
Пример #3
0
    //------------------------------------------------------------------------
    bool font_engine_freetype_base::prepare_glyph(unsigned glyph_code)
    {
        m_glyph_index = FT_Get_Char_Index(m_cur_face, glyph_code);
        m_last_error = FT_Load_Glyph(m_cur_face, 
                                     m_glyph_index, 
                                     m_hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);
//                                     m_hinting ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_NO_HINTING);
        if(m_last_error == 0)
        {
            switch(m_glyph_rendering)
            {
            case glyph_ren_native_mono:
                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_MONO);
                if(m_last_error == 0)
                {
                    decompose_ft_bitmap_mono(m_cur_face->glyph->bitmap, 
                                             m_cur_face->glyph->bitmap_left,
                                             m_flip_y ? -m_cur_face->glyph->bitmap_top : 
                                                         m_cur_face->glyph->bitmap_top,
                                             m_flip_y,
                                             m_scanline_bin,
                                             m_scanlines_bin);
                    m_bounds.x1 = m_scanlines_bin.min_x();
                    m_bounds.y1 = m_scanlines_bin.min_y();
                    m_bounds.x2 = m_scanlines_bin.max_x();
                    m_bounds.y2 = m_scanlines_bin.max_y();
                    m_data_size = m_scanlines_bin.byte_size(); 
                    m_data_type = glyph_data_mono;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    return true;
                }
                break;


            case glyph_ren_native_gray8:
                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL);
                if(m_last_error == 0)
                {
                    decompose_ft_bitmap_gray8(m_cur_face->glyph->bitmap, 
                                              m_cur_face->glyph->bitmap_left,
                                              m_flip_y ? -m_cur_face->glyph->bitmap_top : 
                                                          m_cur_face->glyph->bitmap_top,
                                              m_flip_y,
                                              m_rasterizer,
                                              m_scanline_aa,
                                              m_scanlines_aa);
                    m_bounds.x1 = m_scanlines_aa.min_x();
                    m_bounds.y1 = m_scanlines_aa.min_y();
                    m_bounds.x2 = m_scanlines_aa.max_x();
                    m_bounds.y2 = m_scanlines_aa.max_y();
                    m_data_size = m_scanlines_aa.byte_size(); 
                    m_data_type = glyph_data_gray8;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    return true;
                }
                break;


            case glyph_ren_outline:
                if(m_last_error == 0)
                {
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        if(decompose_ft_outline(m_cur_face->glyph->outline,
                                                m_flip_y, 
                                                m_affine,
                                                m_path32))
                        {
                            rect_d bnd  = m_path32.bounding_rect();
                            m_data_size = m_path32.byte_size();
                            m_data_type = glyph_data_outline;
                            m_bounds.x1 = int(floor(bnd.x1));
                            m_bounds.y1 = int(floor(bnd.y1));
                            m_bounds.x2 = int(ceil(bnd.x2));
                            m_bounds.y2 = int(ceil(bnd.y2));
                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                            m_affine.transform(&m_advance_x, &m_advance_y);
                            return true;
                        }
                    }
                    else
                    {
                        m_path16.remove_all();
                        if(decompose_ft_outline(m_cur_face->glyph->outline,
                                                m_flip_y, 
                                                m_affine,
                                                m_path16))
                        {
                            rect_d bnd  = m_path16.bounding_rect();
                            m_data_size = m_path16.byte_size();
                            m_data_type = glyph_data_outline;
                            m_bounds.x1 = int(floor(bnd.x1));
                            m_bounds.y1 = int(floor(bnd.y1));
                            m_bounds.x2 = int(ceil(bnd.x2));
                            m_bounds.y2 = int(ceil(bnd.y2));
                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                            m_affine.transform(&m_advance_x, &m_advance_y);
                            return true;
                        }
                    }
                }
                return false;

            case glyph_ren_agg_mono:
                if(m_last_error == 0)
                {
                    m_rasterizer.reset();
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path32);
                        m_rasterizer.add_path(m_curves32);
                    }
                    else
                    {
                        m_path16.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path16);
                        m_rasterizer.add_path(m_curves16);
                    }
                    m_scanlines_bin.prepare(1); // Remove all 
                    render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin);
                    m_bounds.x1 = m_scanlines_bin.min_x();
                    m_bounds.y1 = m_scanlines_bin.min_y();
                    m_bounds.x2 = m_scanlines_bin.max_x();
                    m_bounds.y2 = m_scanlines_bin.max_y();
                    m_data_size = m_scanlines_bin.byte_size(); 
                    m_data_type = glyph_data_mono;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    m_affine.transform(&m_advance_x, &m_advance_y);
                    return true;
                }
                return false;


            case glyph_ren_agg_gray8:
                if(m_last_error == 0)
                {
                    m_rasterizer.reset();
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path32);
                        m_rasterizer.add_path(m_curves32);
                    }
                    else
                    {
                        m_path16.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path16);
                        m_rasterizer.add_path(m_curves16);
                    }
                    m_scanlines_aa.prepare(1); // Remove all 
                    render_scanlines(m_rasterizer, m_scanline_aa, m_scanlines_aa);
                    m_bounds.x1 = m_scanlines_aa.min_x();
                    m_bounds.y1 = m_scanlines_aa.min_y();
                    m_bounds.x2 = m_scanlines_aa.max_x();
                    m_bounds.y2 = m_scanlines_aa.max_y();
                    m_data_size = m_scanlines_aa.byte_size(); 
                    m_data_type = glyph_data_gray8;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    m_affine.transform(&m_advance_x, &m_advance_y);
                    return true;
                }
                return false;
            }
        }
        return false;
    }
Пример #4
0
    //------------------------------------------------------------------------
    bool font_engine_freetype_base::prepare_glyph(unsigned glyph_code)
    {
        /* FT_ENCODING_MS_SYMBOL hack inspired from GD's gdft.c:  */
        /* I do not know the significance of the constant 0xf000. */
        /* It was determined by inspection of the character codes */
        /* stored in Microsoft font symbol.ttf                    */
        if (m_cur_face->charmap &&
            m_cur_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
            glyph_code |= 0xf000;

        m_glyph_index = FT_Get_Char_Index(m_cur_face, glyph_code);
        m_last_error = FT_Load_Glyph(m_cur_face, 
                                     m_glyph_index, 
                                     m_hinting ? FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP : FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP);
//                                     m_hinting ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_NO_HINTING);
        if(m_last_error == 0)
        {
            switch(m_glyph_rendering)
            {
            case glyph_ren_native_mono:
                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_MONO);
                if(m_last_error == 0)
                {
                    decompose_ft_bitmap_mono(m_cur_face->glyph->bitmap, 
                                             m_cur_face->glyph->bitmap_left,
                                             m_flip_y ? -m_cur_face->glyph->bitmap_top : 
                                                         m_cur_face->glyph->bitmap_top,
                                             m_flip_y,
                                             m_scanline_bin,
                                             m_scanlines_bin);
                    m_bounds.x1 = m_scanlines_bin.min_x();
                    m_bounds.y1 = m_scanlines_bin.min_y();
                    m_bounds.x2 = m_scanlines_bin.max_x() + 1;
                    m_bounds.y2 = m_scanlines_bin.max_y() + 1;
                    m_data_size = m_scanlines_bin.byte_size(); 
                    m_data_type = glyph_data_mono;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    return true;
                }
                break;


            case glyph_ren_native_gray8:
                m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL);
                if(m_last_error == 0)
                {
                    decompose_ft_bitmap_gray8(m_cur_face->glyph->bitmap, 
                                              m_cur_face->glyph->bitmap_left,
                                              m_flip_y ? -m_cur_face->glyph->bitmap_top : 
                                                          m_cur_face->glyph->bitmap_top,
                                              m_flip_y,
                                              m_rasterizer,
                                              m_scanline_aa,
                                              m_scanlines_aa);
                    m_bounds.x1 = m_scanlines_aa.min_x();
                    m_bounds.y1 = m_scanlines_aa.min_y();
                    m_bounds.x2 = m_scanlines_aa.max_x() + 1;
                    m_bounds.y2 = m_scanlines_aa.max_y() + 1;
                    m_data_size = m_scanlines_aa.byte_size(); 
                    m_data_type = glyph_data_gray8;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    return true;
                }
                break;


            case glyph_ren_outline:
                if(m_last_error == 0)
                {
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        if(decompose_ft_outline(m_cur_face->glyph->outline,
                                                m_flip_y, 
                                                m_affine,
                                                m_path32))
                        {
                            rect_d bnd  = m_path32.bounding_rect();
                            m_data_size = m_path32.byte_size();
                            m_data_type = glyph_data_outline;
                            m_bounds.x1 = int(floor(bnd.x1));
                            m_bounds.y1 = int(floor(bnd.y1));
                            m_bounds.x2 = int(ceil(bnd.x2));
                            m_bounds.y2 = int(ceil(bnd.y2));
                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                            m_affine.transform(&m_advance_x, &m_advance_y);
                            return true;
                        }
                    }
                    else
                    {
                        m_path16.remove_all();
                        if(decompose_ft_outline(m_cur_face->glyph->outline,
                                                m_flip_y, 
                                                m_affine,
                                                m_path16))
                        {
                            rect_d bnd  = m_path16.bounding_rect();
                            m_data_size = m_path16.byte_size();
                            m_data_type = glyph_data_outline;
                            m_bounds.x1 = int(floor(bnd.x1));
                            m_bounds.y1 = int(floor(bnd.y1));
                            m_bounds.x2 = int(ceil(bnd.x2));
                            m_bounds.y2 = int(ceil(bnd.y2));
                            m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                            m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                            m_affine.transform(&m_advance_x, &m_advance_y);
                            return true;
                        }
                    }
                }
                return false;

            case glyph_ren_agg_mono:
                if(m_last_error == 0)
                {
                    m_rasterizer.reset();
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path32);
                        m_rasterizer.add_path(m_curves32);
                    }
                    else
                    {
                        m_path16.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path16);
                        m_rasterizer.add_path(m_curves16);
                    }
                    m_scanlines_bin.prepare(); // Remove all 
                    render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin);
                    m_bounds.x1 = m_scanlines_bin.min_x();
                    m_bounds.y1 = m_scanlines_bin.min_y();
                    m_bounds.x2 = m_scanlines_bin.max_x() + 1;
                    m_bounds.y2 = m_scanlines_bin.max_y() + 1;
                    m_data_size = m_scanlines_bin.byte_size(); 
                    m_data_type = glyph_data_mono;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    m_affine.transform(&m_advance_x, &m_advance_y);
                    return true;
                }
                return false;


            case glyph_ren_agg_gray8:
                if(m_last_error == 0)
                {
                    m_rasterizer.reset();
                    if(m_flag32)
                    {
                        m_path32.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path32);
                        m_rasterizer.add_path(m_curves32);
                    }
                    else
                    {
                        m_path16.remove_all();
                        decompose_ft_outline(m_cur_face->glyph->outline,
                                             m_flip_y, 
                                             m_affine,
                                             m_path16);
                        m_rasterizer.add_path(m_curves16);
                    }
                    m_scanlines_aa.prepare(); // Remove all 
                    render_scanlines(m_rasterizer, m_scanline_aa, m_scanlines_aa);
                    m_bounds.x1 = m_scanlines_aa.min_x();
                    m_bounds.y1 = m_scanlines_aa.min_y();
                    m_bounds.x2 = m_scanlines_aa.max_x() + 1;
                    m_bounds.y2 = m_scanlines_aa.max_y() + 1;
                    m_data_size = m_scanlines_aa.byte_size(); 
                    m_data_type = glyph_data_gray8;
                    m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
                    m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
                    m_affine.transform(&m_advance_x, &m_advance_y);
                    return true;
                }
                return false;
            }
        }
        return false;
    }