Example #1
0
/* callers: gk_rend_set_keeper */
static GLYPH_INDEX* _gk_glyph_index_create(GLYPH_KEEP* const keeper,
    GLYPH_REND* const rend)
{
    GLYPH_INDEX* index;
    funcname = "_gk_glyph_index_create()";

    CARE(keeper);
    CARE(rend);

    if (!_gk_keeper_make_space(keeper,sizeof(GLYPH_INDEX))) return 0;

    index = (GLYPH_INDEX*)_gk_malloc(sizeof(GLYPH_INDEX));
    if (!index) return 0;

    index->pages = 0;
    _gk_glyph_index_init(index,rend);

    index->keeper = keeper;
    index->prev = 0;
    index->next = keeper->first_index;
    if (keeper->first_index) keeper->first_index->prev = index;
    if (!keeper->last_index) keeper->last_index = index;
    keeper->first_index = index;

    index->first_renderer = 0;
    index->last_renderer = 0;

    keeper->allocated += sizeof(GLYPH_INDEX);
    return index;
}
Example #2
0
GLYPH_KEEP* gk_create_keeper(const unsigned max_glyphs,const unsigned max_memory)
{
    GLYPH_KEEP *keeper;
    funcname = "gk_create_keeper()";

    keeper = (GLYPH_KEEP*)_gk_malloc(sizeof(GLYPH_KEEP));
    if (!keeper) return 0;

    keeper->head = 0;
    keeper->tail = 0;
    keeper->num_glyphs = 0;
    keeper->allocated = sizeof(GLYPH_KEEP);

    keeper->max_glyphs = max_glyphs;
    keeper->max_memory = max_memory;

    keeper->first_index = 0;
    keeper->last_index = 0;

    keeper->next = 0;
    keeper->prev = last_keeper;
    if (last_keeper) last_keeper->next = keeper;
    if (!first_keeper) first_keeper = keeper;
    last_keeper = keeper;

    _gk_install_exit_handler();

    _gk_msg("glyph keeper created\n");
    return keeper;
}
static unsigned _gk_make_RLE7(const unsigned char* const src,const int width,const int height,const int pitch)
{
    unsigned char *rlepos;
    int x, y;
    unsigned max_rlesize = width*height+1;

    if (rle_buffer_size < max_rlesize)
    {
        if (rle_buffer) { _gk_free(rle_buffer); rle_buffer = 0; }
        rle_buffer_size = 0;
        rle_buffer = (unsigned char*)_gk_malloc(max_rlesize*2);
        if (!rle_buffer) return 0;
        rle_buffer_size = max_rlesize*2;
    }
    rlepos = rle_buffer;
    *rlepos++ = GLYPH_MONO_RLE7;

    for (y=0; y<height; y++)
    {
        const unsigned char* s = src + y*pitch;
        unsigned char mask = 64;
        unsigned char run = 1;
        unsigned char color = ((*s)>>7) ? 255 : 0;
        for (x=1; x<width; x++)
        {
            unsigned char a = (*s&mask) ? 255 : 0;
            if (color==a && run<126) { run++; }
            else { *rlepos++ = (color&128)|run; color = a; run = 1; }
            mask >>= 1;
            if (!mask) { mask = 128; s++; }
        }
        *rlepos++ = (color&128)|run;
    }
    return rlepos - rle_buffer;
}
static unsigned _gk_make_RLEAA(const unsigned char* const src,const int width,const int height)
{
    unsigned char *rlepos;
    const unsigned char *srcpos, *srcend;
    unsigned max_rlesize = 1+2*width*height;

    if (rle_buffer_size < max_rlesize)
    {
        if (rle_buffer) { _gk_free(rle_buffer); rle_buffer = 0; }
        rle_buffer_size = 0;
        rle_buffer = (unsigned char*)_gk_malloc(max_rlesize*2);
        if (!rle_buffer) return 0;
        rle_buffer_size = max_rlesize*2;
    }

    rlepos = rle_buffer;
    *rlepos++ = GLYPH_RLEAA;
    srcpos = src;
    srcend = src + width*height;

    while (srcpos < srcend)
    {
        const unsigned char *lineend = srcpos + width;
        while (srcpos < lineend)
        {
            if (*srcpos>0 && *srcpos<255) { *rlepos++ = *srcpos++; }
            else
            {
                int n = 1, c = *srcpos++;
                *rlepos++ = c;
                while (srcpos<lineend && *srcpos==c && n<255) { n++; srcpos++; }
                *rlepos++ = n;
            }
        }
    }

    return rlepos - rle_buffer;
}
Example #5
0
/* Callers: rend_workout. */
static int _gk_glyph_index_add_glyph(GLYPH_INDEX* const index,GLYPH* const glyph)
{
    GLYPH_KEEP *keeper;
    GLYPH ***page_b,**page_c;
    int a_index,b_index,c_index;
    int bytes;
    funcname = "_gk_glyph_index_add_glyph()";

    CARE(index);
    CARE(glyph);

    keeper = index->keeper;

    /* If the keeper has limitation on number of glyphs, */
    /* make sure to not exceed the limit, by removing most long-ago-used glyphs. */
    if (keeper->max_glyphs)
    {
        while ((keeper->num_glyphs >= keeper->max_glyphs) && keeper->tail)
            _gk_unload_glyph(keeper->tail);
        if (keeper->num_glyphs >= keeper->max_glyphs) return 0;
    }

    /* Asking for memory */
    bytes = glyph_size_in_bytes(glyph);
    if (!_gk_keeper_make_space(keeper,bytes+(129+129+69)*sizeof(void*))) return 0;

    /* creating root directory, if not exist */
    if (!index->pages)
    {
        index->pages = (GLYPH****)_gk_malloc(69*sizeof(void*));
        if (!index->pages) return 0;
        memset(index->pages,0,69*sizeof(void*));
        keeper->allocated += 69*sizeof(void*);
    }

    a_index = glyph->unicode/16384;
    c_index = glyph->unicode - a_index*16384;

    if (!index->pages[a_index])
    {
        index->pages[a_index] = (GLYPH***)_gk_malloc(129*sizeof(void*));
        if (!index->pages[a_index]) return 0;
        (*(long*)(index->pages+68))++;
        memset(index->pages[a_index],0,129*sizeof(void*));
        keeper->allocated += 129*sizeof(void*);
    }

    page_b = index->pages[a_index];
    b_index = c_index/128;

    if (!page_b[b_index])
    {
        page_b[b_index] = (GLYPH**)_gk_malloc(129*sizeof(void*));
        if (!page_b[b_index]) return 0;
        (*(long*)(page_b+128))++;
        memset(page_b[b_index],0,129*sizeof(void*));
        keeper->allocated += 129*sizeof(void*);
    }

    page_c = page_b[b_index];
    c_index -= b_index*128;

    /* There should be NO glyph at this place at this moment */
    CARE(page_c[c_index]==0);

    page_c[c_index] = glyph;
    (*(int*)(page_c+128))++;
    glyph->index = index;

    glyph->prev = 0;
    glyph->next = keeper->head;
    if (keeper->head) keeper->head->prev = glyph;
    if (!keeper->tail) keeper->tail = glyph;
    keeper->head = glyph;

    keeper->allocated += bytes;
    keeper->num_glyphs++;
    return 1;
}
/*
 * Renders a glyph immediately, then tries to puts it into cache.
 * rend and rend->face must be not 0
 */
static GLYPH* _gk_rend_workout(GLYPH_REND* const rend,const unsigned unicode)
{
    unsigned glyph_index;
    int bmp_size;
    int error;
    int center_x = 0,center_y = 0;
    FT_Glyph ft_glyph = 0;
    GLYPH* glyph;
    GLYPH_FACE* actual_face;
    unsigned actual_code;

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) begin\n",(void*)rend,unicode);
#endif

    CARE(rend && rend->face);
    CARE(unicode > 0);
    CARE(unicode <= GK_MAX_UNICODE);

    funcname = "_gk_rend_workout()";

    _gk_find_mapping(rend->face,unicode,&actual_face,&actual_code);
    if (!actual_face || !actual_code) return 0;
    if (!actual_face->face) return 0;

    glyph_index = FT_Get_Char_Index(actual_face->face,actual_code);
    if (!glyph_index)
    {
        if (unicode==rend->undefined_char || unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->undefined_char);
    }

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"    glyph_index is %u\n",glyph_index);
#endif

    /* Preparing for glyph loading: setting size */
    /*FT_Activate_Size(size);*/
    if (actual_face == rend->face)
    {
        error = (rend->size == 0);
        if (!error) actual_face->face->size = rend->size;
    }
    else
    {
        error = (actual_face->own_size == 0);
        if (!error)
        {
            actual_face->face->size = actual_face->own_size;
            error = FT_Set_Char_Size(actual_face->face,rend->hsize,rend->vsize,72,72);
        }
    }

#ifdef GLYPH_LOG
    if (error)
    {
        if (glyph_log) fprintf(glyph_log,"    Failed to select size\n");
    }
    else
    {
        if (glyph_log) fprintf(glyph_log,"    Size selected successfully\n");
    }
#endif

    /* Loading a glyph with FreeType */
    if (!error)
    {
        error = FT_Load_Glyph(actual_face->face,glyph_index,rend->load_flags);
        if (error)
            _gk_msg("Error: %s: FT_Load_Glyph() bugs on glyph (#%d) for character U+%04X\n",funcname,glyph_index,unicode);
        else
        {
            error = (actual_face->face->glyph == 0);
            if (error) _gk_msg("Error: %s: Empty glyph slot after FT_Load_Glyph()\n",funcname);
        }

/*#ifdef GLYPH_LOG
        if (error)
        {
            if (glyph_log) fprintf(glyph_log,"    Could not load a glyph with FT_Load_Glyph()\n");
        }
        else
        {
            if (glyph_log) fprintf(glyph_log,"    Loaded a glyph with FT_Load_Glyph()\n");
        }
#endif*/
    }


    /* Getting center coordinates (MEGA-HACK) */
    /* This whole idea should be re-made in more optimal way */
    if (!error)
    {
/*#ifdef GLYPH_LOG
        if (glyph_log) fprintf(glyph_log,"    Getting a center point\n");
#endif*/
        FT_Glyph g = 0;
        error = FT_Get_Glyph(actual_face->face->glyph, &g);
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    FT_Get_Glyph() failed\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() succeeded\n");
            if (g)
                fprintf(glyph_log,"    FT_Get_Glyph() returned not 0\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() returned 0\n");
        }
#endif*/

        error = error || !g;
        if (!error && g->format==FT_GLYPH_FORMAT_OUTLINE)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Glyph_To_Bitmap()\n");
#endif*/
            error = FT_Glyph_To_Bitmap(&g,rend->render_mode,0,1);
/*#ifdef GLYPH_LOG
            if (glyph_log)
            {
                if (error)
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() failed\n");
                else
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() succeeded\n");
            }
#endif*/
            if (!error)
            {
                center_x = 64 * ((FT_BitmapGlyph)g)->left + 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = 64 * ((FT_BitmapGlyph)g)->top - 64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;
                /*center_x = 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = -64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;*/
            }
        }
        if (g)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Done_Glyph()\n");
#endif*/
            FT_Done_Glyph(g);
        }
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    Could not find a center point\n");
            else
                fprintf(glyph_log,"    Computed a center point\n");
        }
#endif*/
    }




    /* Emboldening the glyph */
    if (!error)
    {
        if (rend->bold_strength && actual_face->face->glyph->format==FT_GLYPH_FORMAT_OUTLINE)
        {
            int xstr, ystr, xstr2, ystr2;
            int xmin,xmax,ymin,ymax;
            int center_dx, center_dy;
            FT_GlyphSlot slot = actual_face->face->glyph;

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"        Emboldening the glyph by %d\n",rend->bold_strength);
#endif

            xstr = rend->bold_strength * 
                   FT_MulFix( actual_face->face->units_per_EM, actual_face->face->size->metrics.y_scale ) / 2400;
            ystr = xstr;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif
            GK_Outline_Embolden(&slot->outline,xstr,&xmin,&xmax,&ymin,&ymax);
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xmin = %d, xmax = %d\n",xmin,xmax);
            if (glyph_log) fprintf(glyph_log,"            ymin = %d, ymax = %d\n",ymin,ymax);
#endif
            /*xstr = xstr * 2;
            ystr = xstr;*/
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif

            xstr2 = xmin+xmax;
            ystr2 = ymin+ymax;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr2 = %d, ystr2 = %d\n",xstr2,ystr2);
            if (glyph_log) fprintf(glyph_log,"            xscale = %.5f\n",((double)actual_face->face->size->metrics.x_scale)/65536);
            if (glyph_log) fprintf(glyph_log,"            yscale = %.5f\n",((double)actual_face->face->size->metrics.y_scale)/65536);
#endif

            if (slot->advance.x) slot->advance.x += xstr;
            if (slot->advance.y) slot->advance.y += ystr;

            slot->metrics.width        += xstr * 2;
            slot->metrics.height       += ystr * 2;
            /*slot->metrics.horiBearingX -= xmin;*/
            slot->metrics.horiBearingY += ystr * 2;
            slot->metrics.horiAdvance  += xstr * 2;
            slot->metrics.vertBearingX -= xstr;
            slot->metrics.vertBearingY += ystr * 2;
            slot->metrics.vertAdvance  += ystr * 2;

            /*center_dx = (int)( (double)xstr / 2 * (double)actual_face->face->size->metrics.x_scale / (80000) );
            center_dy = (int)( (double)ystr / 2 * (double)actual_face->face->size->metrics.y_scale / (65536) );*/

            center_dx = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.x_ppem / 80);
            center_dy = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.y_ppem / 80);

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            center_x += %.1f\n",((double)center_dx)/64);
            if (glyph_log) fprintf(glyph_log,"            center_y += %.1f\n",((double)center_dx)/64);
#endif

            center_x += center_dx;
            center_y += center_dy;

            /*center_x += xstr;*/
            /*center_y += ymin;*/

            /*FT_GlyphSlot_Embolden(slot);*/
        }
    }

    /* Getting a glyph from FreeType */
    if (!error)
    {
        error = FT_Get_Glyph(actual_face->face->glyph, &ft_glyph);
        error = error || !ft_glyph;
        if (error)
            _gk_msg("Error: %s: Can't get a glyph with FT_Get_Glyph() call. Glyph (#%d) for character U+%04X\n",
            funcname,glyph_index,unicode);
    }

    /* Transforming the glyph to apply rotation and italics */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE && rend->do_matrix_transform)
    {
        error = FT_Glyph_Transform(ft_glyph,&rend->matrix,0);
        if (!error)
        {
            FT_Vector c;
            c.x = center_x;
            c.y = center_y;
            FT_Vector_Transform(&c,&rend->matrix);
            center_x = c.x;
            center_y = c.y;
        }
    }

    /* Converting glyph to bitmap */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
    {
        error = FT_Glyph_To_Bitmap(&ft_glyph,rend->render_mode,0,1);
        if (error) _gk_msg("Error: %s: FT_Glyph_To_Bitmap() bugs on character U+%04X\n",funcname,unicode);
    }

    /* Checking if we have bitmap now */
    if (!error)
    {
        error = (ft_glyph->format!=FT_GLYPH_FORMAT_BITMAP);
        if (error) _gk_msg("Error: %s: Glyph is not FT_GLYPH_FORMAT_BITMAP after rendering with FT_Glyph_To_Bitmap()\n",funcname);
    }

#ifdef GLYPH_LOG
/*    {
        if (glyph_log)
        {
            fprintf(glyph_log,"    We got a bitmap glyph from FreeType!\n");
            if (ft_glyph->format==FT_GLYPH_FORMAT_BITMAP)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_BITMAP\n");
                fprintf(glyph_log,"        Size: %dx%d, pitch: %d\n",
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.width,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.rows,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);
                if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_MONO)
                {
                    int x,y;
                    int pitch = ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_MONO\n");
                    fprintf(glyph_log,"        Buffer:\n");
                    for (y=0; y < ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; y++)
                    {
                        fprintf(glyph_log,"            ");
                        for (x=0; x < ((FT_BitmapGlyph)ft_glyph)->bitmap.width; x++)
                        {
                            unsigned char byte = ((unsigned char*)((FT_BitmapGlyph)ft_glyph)->bitmap.buffer)[y*pitch+x];
                            unsigned char mask = 128 >> (x%8);
                            fprintf(glyph_log,"%s",(byte&mask)?" *":" .");
                        }
                        fprintf(glyph_log,"\n");
                    }
                }
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY2)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY2\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY4)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY4\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD_V)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD_V\n");
            }
            else if (ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_OUTLINE\n");
            }
            fprintf(glyph_log,"        Advance: ( %.1f , %.1f ) pixels\n",
                    ((double)ft_glyph->advance.x)/0x10000,((double)ft_glyph->advance.y)/0x10000);
        }
    }*/
#endif

    if (!error)
    {
        error = ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch < 0 );
        if (error) _gk_msg("Error: rend_workout(): Rendered glyph has negative pitch value, can't handle\n"); /* FIXME */
    }

    if (!error)
    {
        glyph = (GLYPH*)_gk_malloc(sizeof(GLYPH));
        error = (glyph == 0);
    }

    if (error || !ft_glyph)
    {
        if (ft_glyph) FT_Done_Glyph(ft_glyph);

        if (unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->error_char);
    }

    glyph->unicode = unicode;
    glyph->width = ((FT_BitmapGlyph)ft_glyph)->bitmap.width;
    glyph->height = ((FT_BitmapGlyph)ft_glyph)->bitmap.rows;
    glyph->left = ((FT_BitmapGlyph)ft_glyph)->left;
    glyph->top = ((FT_BitmapGlyph)ft_glyph)->top;
    glyph->advance_x = ft_glyph->advance.x >> 10;
    glyph->advance_y = ft_glyph->advance.y >> 10;
    glyph->center_x = (center_x + 31) / 64;
    glyph->center_y = (center_y + 31) / 64;

    glyph->index = 0;
    glyph->prev = 0;
    glyph->next = 0;
    glyph->bmp = 0;
    glyph->bmpsize = 0;

    _gk_msg("rendering character '%c'\n",unicode);

    bmp_size = glyph->width*glyph->height;
    if (!bmp_size) /* empty glyph, like space (' ') character */
    {
        if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph);
        FT_Done_Glyph(ft_glyph);
        return glyph;
    }

    if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
    {
#ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK
        int pitch1 = (glyph->width+7)>>3;
        int bitpack_size = glyph->height*pitch1;

#ifdef GLYPH_TARGET_KNOWS_MONO_RLE7
        int rle_size = 0;

        if (rend->index)
              rle_size = _gk_make_RLE7( ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer,
                         glyph->width, glyph->height, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);

        if (rle_size>0 && rle_size<=bitpack_size)
        {
            glyph->bmp = (unsigned char*)_gk_malloc(rle_size);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            memcpy(glyph->bmp,rle_buffer,rle_size);
            glyph->bmpsize = rle_size;
        }
        else
#endif  /* GLYPH_TARGET_KNOWS_MONO_RLE7 */
        {
            glyph->bmp = (unsigned char*)_gk_malloc(bitpack_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_MONO_BITPACK;
            if ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch == pitch1 )
                memcpy( glyph->bmp+1, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, bitpack_size );
            else
            {
                unsigned char *d = glyph->bmp+1;
                int y = 0;
                for (; y<glyph->height; y++,d+=pitch1)
                    memcpy( d, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch, pitch1 );
            }
            glyph->bmpsize = bitpack_size+1;
        }
#else  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
        {
            int y = 0;
            unsigned char* b;

            glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_UNCOMPRESSED;
            glyph->bmpsize = bmp_size+1;
            b = glyph->bmp + 1;

            for (; y<glyph->height; y++)
            {
                int x = 0;
                unsigned char* a = ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                while (x<glyph->width)
                {
                    if (x < glyph->width) { *b++ = *a&0x80 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x40 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x20 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x10 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x08 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x04 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x02 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x01 ? 255 : 0; x++; }
                    a++;
                }
            }
        }
#endif  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
    }