--- qt-x11-opensource-src-4.4.0/src/gui/text/qfontengine_ft.cpp 2008-07-27 22:59:35.000000000 +0800 +++ qt-x11-opensource-src-4.4.0n/src/gui/text/qfontengine_ft.cpp 2008-07-27 23:22:12.000000000 +0800 @@ -66,6 +66,8 @@ #include FT_TYPE1_TABLES_H #include FT_GLYPH_H +#include FT_LCD_FILTER_H + QT_BEGIN_NAMESPACE /* @@ -100,6 +102,296 @@ return (HB_Error)error; } +// ------------- copied from David Turner's lcd patches ----------------------- + +/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot + * into a different format. For example, we want to convert a + * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit + * ARGB or ABGR bitmap. + * + * this function prepares a target descriptor for this operation. + * + * input :: target bitmap descriptor. The function will set its + * 'width', 'rows' and 'pitch' fields, and only these + * + * slot :: the glyph slot containing the source bitmap. this + * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP + * + * mode :: the requested final rendering mode. supported values are + * MONO, NORMAL (i.e. gray), LCD and LCD_V + * + * the function returns the size in bytes of the corresponding buffer, + * it's up to the caller to allocate the corresponding memory block + * before calling _fill_xrender_bitmap + * + * it also returns -1 in case of error (e.g. incompatible arguments, + * like trying to convert a gray bitmap into a monochrome one) + */ +static int +_compute_xrender_bitmap_size( FT_Bitmap* target, + FT_GlyphSlot slot, + FT_Render_Mode mode ) +{ + FT_Bitmap* ftbit; + int width, height, pitch; + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + return -1; + + // compute the size of the final bitmap + ftbit = &slot->bitmap; + + width = ftbit->width; + height = ftbit->rows; + pitch = (width+3) & ~3; + + switch ( ftbit->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + if ( mode == FT_RENDER_MODE_MONO ) + { + pitch = (((width+31) & ~31) >> 3); + break; + } + /* fall-through */ + + case FT_PIXEL_MODE_GRAY: + if ( mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V ) + { + /* each pixel is replicated into a 32-bit ARGB value */ + pitch = width*4; + } + break; + + case FT_PIXEL_MODE_LCD: + if ( mode != FT_RENDER_MODE_LCD ) + return -1; + + /* horz pixel triplets are packed into 32-bit ARGB values */ + width /= 3; + pitch = width*4; + break; + + case FT_PIXEL_MODE_LCD_V: + if ( mode != FT_RENDER_MODE_LCD_V ) + return -1; + + /* vert pixel triplets are packed into 32-bit ARGB values */ + height /= 3; + pitch = width*4; + break; + + default: /* unsupported source format */ + return -1; + } + + target->width = width; + target->rows = height; + target->pitch = pitch; + target->buffer = NULL; + + return pitch * height; +} + +/* this functions converts the glyph bitmap found in a FT_GlyphSlot + * into a different format (see _compute_xrender_bitmap_size) + * + * you should call this function after _compute_xrender_bitmap_size + * + * target :: target bitmap descriptor. Note that its 'buffer' pointer + * must point to memory allocated by the caller + * + * slot :: the glyph slot containing the source bitmap + * + * mode :: the requested final rendering mode + * + * bgr :: boolean, set if BGR or VBGR pixel ordering is needed + */ +static void +_fill_xrender_bitmap( FT_Bitmap* target, + FT_GlyphSlot slot, + FT_Render_Mode mode, + int bgr ) +{ + FT_Bitmap* ftbit = &slot->bitmap; + + { + unsigned char* srcLine = ftbit->buffer; + unsigned char* dstLine = target->buffer; + int src_pitch = ftbit->pitch; + int width = target->width; + int height = target->rows; + int pitch = target->pitch; + int subpixel; + int h; + + subpixel = ( mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V ); + + if ( src_pitch < 0 ) + srcLine -= src_pitch*(ftbit->rows-1); + + switch ( ftbit->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + if ( subpixel ) /* convert mono to ARGB32 values */ + { + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + { + int x; + + for ( x = 0; x < width; x++ ) + { + if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) + ((unsigned int*)dstLine)[x] = 0xffffffffU; + } + } + } + else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ + { + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + { + int x; + + for ( x = 0; x < width; x++ ) + { + if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) + dstLine[x] = 0xff; + } + } + } + else /* copy mono to mono */ + { + int bytes = (width+7) >> 3; + + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + memcpy( dstLine, srcLine, bytes ); + } + break; + + case FT_PIXEL_MODE_GRAY: + if ( subpixel ) /* convert gray to ARGB32 values */ + { + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + { + int x; + unsigned int* dst = (unsigned int*)dstLine; + + for ( x = 0; x < width; x++ ) + { + unsigned int pix = srcLine[x]; + + pix |= (pix << 8); + pix |= (pix << 16); + + dst[x] = pix; + } + } + } + else /* copy gray into gray */ + { + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + memcpy( dstLine, srcLine, width ); + } + break; + + case FT_PIXEL_MODE_LCD: + if ( !bgr ) + { + /* convert horizontal RGB into ARGB32 */ + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int*)dstLine; + + for ( x = 0; x < width; x++, src += 3 ) + { + unsigned int pix; + + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[2] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } + else + { + /* convert horizontal BGR into ARGB32 */ + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int*)dstLine; + + for ( x = 0; x < width; x++, src += 3 ) + { + unsigned int pix; + + pix = ((unsigned int)src[2] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } + break; + + default: /* FT_PIXEL_MODE_LCD_V */ + /* convert vertical RGB into ARGB32 */ + if ( !bgr ) + { + for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) + { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int*)dstLine; + + for ( x = 0; x < width; x++, src += 1 ) + { + unsigned int pix; + + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[src_pitch*2] ) | + ((unsigned int)src[src_pitch] << 24) ; + + dst[x] = pix; + } + } + } + else + { + for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) + { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int*)dstLine; + + for ( x = 0; x < width; x++, src += 1 ) + { + unsigned int pix; + + pix = ((unsigned int)src[src_pitch*2] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[src_pitch] << 24) ; + + dst[x] = pix; + } + } + } + } + } +} + + // -------------------------- Freetype support ------------------------------ class QtFreetypeData @@ -499,12 +791,6 @@ delete [] data; } -static const uint subpixel_filter[3][3] = { - { 180, 60, 16 }, - { 38, 180, 38 }, - { 16, 60, 180 } -}; - QFontEngineFT::QFontEngineFT(const QFontDef &fd) { fontDef = fd; @@ -631,16 +917,17 @@ QFontEngineFT::GlyphInfo info; Q_ASSERT(format != Format_None); - bool hsubpixel = false; - int vfactor = 1; int load_flags = FT_LOAD_DEFAULT | default_load_flags; + FT_Render_Mode mode = FT_RENDER_MODE_NORMAL; if (outline_drawing) { load_flags = FT_LOAD_NO_BITMAP; + } else if (format == Format_Mono) { + mode = FT_RENDER_MODE_MONO; } else if (format == Format_A32) { if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) { - hsubpixel = true; + mode = FT_RENDER_MODE_LCD; } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) { - vfactor = 3; + mode = FT_RENDER_MODE_LCD_V; } } @@ -677,235 +964,31 @@ FT_GlyphSlot slot = face->glyph; - int left = slot->metrics.horiBearingX; - int right = slot->metrics.horiBearingX + slot->metrics.width; - int top = slot->metrics.horiBearingY; - int bottom = slot->metrics.horiBearingY - slot->metrics.height; - if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { - int l, r, t, b; - FT_Vector vector; - vector.x = left; - vector.y = top; - FT_Vector_Transform(&vector, &matrix); - l = r = vector.x; - t = b = vector.y; - vector.x = right; - vector.y = top; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = right; - vector.y = bottom; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = left; - vector.y = bottom; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - left = l; - right = r; - top = t; - bottom = b; - } - left = FLOOR(left); - right = CEIL(right); - bottom = FLOOR(bottom); - top = CEIL(top); - - int hpixels = TRUNC(right - left); - if (hsubpixel) - hpixels = hpixels*3 + 8; - info.width = hpixels; - info.height = TRUNC(top - bottom); - info.x = -TRUNC(left); - info.y = TRUNC(top); + if (slot->format != FT_GLYPH_FORMAT_BITMAP) { + FT_Library library = slot->library; + FT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT ); + FT_Render_Glyph( slot, mode ); + FT_Library_SetLcdFilter( library, FT_LCD_FILTER_NONE ); + } + + FT_Bitmap bitmap; + int size = _compute_xrender_bitmap_size( &bitmap, slot, mode ); + if (size < 0) + return 0; + + info.width = bitmap.width; + info.height = bitmap.rows; + info.x = - slot->bitmap_left; + info.y = slot->bitmap_top; info.xOff = TRUNC(ROUND(slot->advance.x)); info.yOff = 0; - if (hsubpixel) { - info.width /= 3; - info.x += 1; - } - int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 : - (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4)); - int size = pitch * info.height; uchar *glyph_buffer = new uchar[size]; - - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - FT_Bitmap bitmap; - bitmap.rows = info.height*vfactor; - bitmap.width = hpixels; - bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3); - if (!hsubpixel && vfactor == 1) - bitmap.buffer = glyph_buffer; - else - bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch]; - memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch); - bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays; - FT_Matrix matrix; - matrix.xx = (hsubpixel ? 3 : 1) << 16; - matrix.yy = vfactor << 16; - matrix.yx = matrix.xy = 0; - - FT_Outline_Transform(&slot->outline, &matrix); - FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor); - FT_Outline_Get_Bitmap(qt_getFreetype(), &slot->outline, &bitmap); - if (hsubpixel) { - Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); - Q_ASSERT(antialias); - const uchar *src = bitmap.buffer; - uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch]; - uchar *c = convoluted; - // convolute the bitmap with a triangle filter to get rid of color fringes - // If we take account for a gamma value of 2, we end up with - // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here, - // as this nicely sums up to 16 :) - int h = info.height; - while (h--) { - c[0] = c[1] = 0; - // - for (int x = 2; x < bitmap.width - 2; ++x) { - uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2]; - c[x] = (uchar) (sum >> 4); - } - c[bitmap.width - 2] = c[bitmap.width -1] = 0; - src += bitmap.pitch; - c += bitmap.pitch; - } - - uint *dst = (uint *)glyph_buffer; - src = convoluted; - h = info.height; - if (subpixelType == QFontEngineFT::Subpixel_RGB) { - while (h--) { - uint *dd = dst; - for (int x = 1; x < bitmap.width - 1; x += 3) { - uint red = src[x]; - uint green = src[x+1]; - uint blue = src[x+2]; - uint alpha = green; - uint res = (alpha << 24) + (red << 16) + (green << 8) + blue; - *dd = res; - ++dd; - } - dst += info.width; - src += bitmap.pitch; - } - } else { - while (h--) { - uint *dd = dst; - for (int x = 1; x < bitmap.width - 1; x += 3) { - uint blue = src[x]; - uint green = src[x+1]; - uint red = src[x+2]; - uint alpha = green; - uint res = (alpha << 24) + (red << 16) + (green << 8) + blue; - *dd = res; - ++dd; - } - dst += info.width; - src += bitmap.pitch; - } - } - delete [] convoluted; - delete [] bitmap.buffer; - } else if (vfactor != 1) { - uchar *src = bitmap.buffer; - size = info.width * 4 * info.height; - uint *dst = (uint *)glyph_buffer; - int h = info.height; - if (subpixelType == QFontEngineFT::Subpixel_VRGB) { - while (h--) { - for (int x = 0; x < info.width; x++) { - uint red = src[x]; - uint green = src[x+bitmap.pitch]; - uint blue = src[x+2*bitmap.pitch]; - uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8; - uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8; - uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8; - uint res = (mid << 24) + (high << 16) + (mid << 8) + low; - dst[x] = res; - } - dst += info.width; - src += 3*bitmap.pitch; - } - } else { - while (h--) { - for (int x = 0; x < info.width; x++) { - uint blue = src[x]; - uint green = src[x+bitmap.pitch]; - uint red = src[x+2*bitmap.pitch]; - uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8; - uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8; - uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8; - uint res = (mid << 24) + (high << 16) + (mid << 8) + low; - dst[x] = res; - } - dst += info.width; - src += 3*bitmap.pitch; - } - } - delete [] bitmap.buffer; - } - } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) { - Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO); - uchar *src = slot->bitmap.buffer; - uchar *dst = glyph_buffer; - int h = slot->bitmap.rows; - if (format == Format_Mono) { - int bytes = ((info.width + 7) & ~7) >> 3; - while (h--) { - memcpy (dst, src, bytes); - dst += pitch; - src += slot->bitmap.pitch; - } - } else { - if (hsubpixel) { - while (h--) { - uint *dd = (uint *)dst; - *dd++ = 0; - for (int x = 0; x < slot->bitmap.width; x++) { - uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000); - *dd++ = a; - } - *dd++ = 0; - dst += pitch; - src += slot->bitmap.pitch; - } - } else if (vfactor != 1) { - while (h--) { - uint *dd = (uint *)dst; - for (int x = 0; x < slot->bitmap.width; x++) { - uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000); - *dd++ = a; - } - dst += pitch; - src += slot->bitmap.pitch; - } - } else { - while (h--) { - for (int x = 0; x < slot->bitmap.width; x++) { - unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00); - dst[x] = a; - } - dst += pitch; - src += slot->bitmap.pitch; - } - } - } - } else { - qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format); - delete [] glyph_buffer; - return 0; - } + memset(glyph_buffer, 0, size); + bitmap.buffer = glyph_buffer; + _fill_xrender_bitmap(&bitmap, slot, mode, + (subpixelType == QFontEngineFT::Subpixel_BGR || + subpixelType == QFontEngineFT::Subpixel_VBGR)); bool large_glyph = (((signed char)(slot->linearHoriAdvance>>16) != slot->linearHoriAdvance>>16) || ((uchar)(info.width) != info.width) @@ -928,9 +1011,9 @@ g->linearAdvance = slot->linearHoriAdvance >> 10; g->width = info.width; - g->height = TRUNC(top - bottom); + g->height = info.height; g->x = -info.x; - g->y = TRUNC(top); + g->y = info.y; g->advance = TRUNC(ROUND(slot->advance.x)); g->format = format; delete [] g->data;