/*
 * File      : font.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date           Author       Notes
 * 2010-09-15     Bernard      first version
 */
#include <rtgui/font.h>
#include <rtgui/dc.h>

/* bitmap font private data */

static void rtgui_bitmap_font_draw_text(struct rtgui_font *font, struct rtgui_dc *dc, const char *text, rt_ubase_t len, struct rtgui_rect *rect);
static void rtgui_bitmap_font_get_metrics(struct rtgui_font *font, const char *text, rtgui_rect_t *rect);
const struct rtgui_font_engine bmp_font_engine =
{
    RT_NULL,
    RT_NULL,
    rtgui_bitmap_font_draw_text,
    rtgui_bitmap_font_get_metrics
};

void rtgui_bitmap_font_draw_char(struct rtgui_font_bitmap *font, struct rtgui_dc *dc, const char ch,
                                 rtgui_rect_t *rect)
{
    rtgui_color_t bc;
    const rt_uint8_t *font_ptr;
    rt_uint16_t x, y, w, h, style;
    register rt_base_t i, j, /*k,*/ word_bytes;

    /* check first and last char */
    if (ch < font->first_char || ch > font->last_char) return;

    /* get text style */
    style = rtgui_dc_get_gc(dc)->textstyle;
    bc = rtgui_dc_get_gc(dc)->background;

    x = rect->x1;
    y = rect->y1;
    /* get width */
    if (font->char_width == RT_NULL)
    {
        word_bytes = (((font->width - 1) / 8) + 1);
        font_ptr = font->bmp + (ch - font->first_char) * word_bytes * font->height;
    }
    else
    {
        word_bytes = ((font->char_width[ch - font->first_char] - 1) / 8) + 1;
        font_ptr = font->bmp + font->offset[ch - font->first_char];
    }
    w = (font->width  + x > rect->x2) ? rect->x2 - rect->x1 : font->width;
    h = (font->height + y > rect->y2) ? rect->y2 - rect->y1 : font->height;

    for (i = 0; i < h; i++)
    {
        rt_uint8_t chr = 0;
        const rt_uint8_t *ptr = font_ptr + i * word_bytes;
        for (j = 0; j < w; j++)
        {
            if (j % 8 == 0)
                chr = *ptr++;
            if (chr & 0x80)
                rtgui_dc_draw_point(dc, j + x, i + y);
            else if (style & RTGUI_TEXTSTYLE_DRAW_BACKGROUND)
                rtgui_dc_draw_color_point(dc, j + x, i + y, bc);
            chr <<= 1;
        }
    }
}

static void rtgui_bitmap_font_draw_text(struct rtgui_font *font, struct rtgui_dc *dc,
                                        const char *text, rt_ubase_t len, struct rtgui_rect *rect)
{
    rt_uint32_t length;
    struct rtgui_font_bitmap *bmp_font = (struct rtgui_font_bitmap *)(font->data);
#ifdef RTGUI_USING_FONTHZ
    struct rtgui_font *hz_font;

    RT_ASSERT(bmp_font != RT_NULL);

    if (rect->y1 > rect->y2) return;

    hz_font = rtgui_font_refer("hz", font->height);
    while ((rect->x1 < rect->x2) && len)
    {
        length = 0;
        while ((rt_uint8_t) * (text + length) >= 0x80) length ++; /* it's not a ascii character */
        if (length > 0)
        {
            if (hz_font != RT_NULL) rtgui_font_draw(hz_font, dc, text, length, rect);
            text += length;
            len -= length;
        }

        length = 0;
        while (((rt_uint8_t) * (text + length) < 0x80) && *(text + length)) length ++;
        if (length > 0)
        {
            len -= length;
            while (length-- && rect->x1 < rect->x2)
            {
                rtgui_bitmap_font_draw_char(bmp_font, dc, *text, rect);

                /* move x to next character */
                if (bmp_font->char_width == RT_NULL)
                    rect->x1 += bmp_font->width;
                else
                    rect->x1 += bmp_font->char_width[*text - bmp_font->first_char];
                text ++;
            }
        }
    }

    if (hz_font != RT_NULL) rtgui_font_derefer(hz_font);

#else
    if (rect->y1 > rect->y2) return;

    while ((rect->x1 < rect->x2) && len)
    {
        length = 0;
        while (((rt_uint8_t) * (text + length) < 0x80) && *(text + length)) length ++;
        if (length > 0)
        {
            len -= length;
            while (length-- && rect->x1 < rect->x2)
            {
                rtgui_bitmap_font_draw_char(bmp_font, dc, *text, rect);

                /* move x to next character */
                if (bmp_font->char_width == RT_NULL)
                    rect->x1 += bmp_font->width;
                else
                    rect->x1 += bmp_font->char_width[*text - bmp_font->first_char];
                text ++;
            }
        }
    }
#endif
}

static void rtgui_bitmap_font_get_metrics(struct rtgui_font *font, const char *text, rtgui_rect_t *rect)
{
    rt_uint32_t length;
    struct rtgui_font_bitmap *bmp_font = (struct rtgui_font_bitmap *)(font->data);

    RT_ASSERT(bmp_font != RT_NULL);

    /* set init metrics rect */
    rect->x1 = rect->y1 = 0;
    rect->x2 = 0;
    rect->y2 = bmp_font->height;

    while (*text)
    {
        length = 0;
        while ((rt_uint8_t) * (text + length) >= 0x80) length ++; /* it's not a ascii character */
        rect->x2 += (font->height / 2) * length;
        text += length;

        length = 0;
        while (((rt_uint8_t) * (text + length) < 0x80) && *(text + length)) length ++;
        if (bmp_font->char_width != NULL)
        {
            /* get width for each character */
            while (*text && ((rt_uint8_t)*text < 0x80))
            {
                rect->x2 += bmp_font->char_width[*text - bmp_font->first_char];
                text ++;
            }
        }
        else
        {
            /* set metrics rect */
            rect->x2 += bmp_font->width * length;
            text += length;
        }
    }
}
