MozillaFirefox/mozilla-cairo-lcd.patch

1334 lines
38 KiB
Diff

Description: Add a Cairo LCD filter to use FreeType LCD colour filtering features
Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=404637
Bug-Cairo: http://bugs.freedesktop.org/show_bug.cgi?id=10301
diff --git a/config/system-headers b/config/system-headers
--- a/config/system-headers
+++ b/config/system-headers
@@ -267,16 +267,17 @@ Font.h
Fonts.h
fp.h
fpieee.h
frame/log.h
frame/req.h
freetype/freetype.h
freetype/ftcache.h
freetype/ftglyph.h
+freetype/ftlcdfil.h
freetype/ftsynth.h
freetype/ftoutln.h
freetype/ttnameid.h
freetype/tttables.h
freetype/t1tables.h
fribidi/fribidi.h
FSp_fopen.h
fstream
diff --git a/gfx/cairo/cairo/src/cairo-font-options.c b/gfx/cairo/cairo/src/cairo-font-options.c
--- a/gfx/cairo/cairo/src/cairo-font-options.c
+++ b/gfx/cairo/cairo/src/cairo-font-options.c
@@ -34,41 +34,44 @@
* Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
+ CAIRO_LCD_FILTER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
};
/**
* _cairo_font_options_init_default:
* @options: a #cairo_font_options_t
*
* Initializes all fields of the font options object to default values.
**/
void
_cairo_font_options_init_default (cairo_font_options_t *options)
{
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+ options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
}
void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
options->antialias = other->antialias;
options->subpixel_order = other->subpixel_order;
+ options->lcd_filter = other->lcd_filter;
options->hint_style = other->hint_style;
options->hint_metrics = other->hint_metrics;
}
/**
* cairo_font_options_create:
*
* Allocates a new font options object with all options initialized
@@ -184,16 +187,18 @@ cairo_font_options_merge (cairo_font_opt
if (cairo_font_options_status ((cairo_font_options_t *) other))
return;
if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
+ if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
+ options->lcd_filter = other->lcd_filter;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
options->hint_style = other->hint_style;
if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
options->hint_metrics = other->hint_metrics;
}
slim_hidden_def (cairo_font_options_merge);
/**
@@ -216,16 +221,17 @@ cairo_font_options_equal (const cairo_fo
if (cairo_font_options_status ((cairo_font_options_t *) other))
return FALSE;
if (options == other)
return TRUE;
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
+ options->lcd_filter == other->lcd_filter &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics);
}
slim_hidden_def (cairo_font_options_equal);
/**
* cairo_font_options_hash:
* @options: a #cairo_font_options_t
@@ -241,17 +247,18 @@ slim_hidden_def (cairo_font_options_equa
unsigned long
cairo_font_options_hash (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
options = &_cairo_font_options_nil; /* force default values */
return ((options->antialias) |
(options->subpixel_order << 4) |
- (options->hint_style << 8) |
+ (options->lcd_filter << 8) |
+ (options->hint_style << 12) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
/**
* cairo_font_options_set_antialias:
* @options: a #cairo_font_options_t
* @antialias: the new antialiasing mode
@@ -323,16 +330,58 @@ cairo_font_options_get_subpixel_order (c
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
return options->subpixel_order;
}
/**
+ * _cairo_font_options_set_lcd_filter:
+ * @options: a #cairo_font_options_t
+ * @lcd_filter: the new LCD filter
+ *
+ * Sets the LCD filter for the font options object. The LCD filter
+ * specifies how pixels are filtered when rendered with an antialiasing
+ * mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
+ * #cairo_lcd_filter_t for full details.
+ *
+ * Since: 1.8
+ **/
+void
+_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
+ cairo_lcd_filter_t lcd_filter)
+{
+ if (cairo_font_options_status (options))
+ return;
+
+ options->lcd_filter = lcd_filter;
+}
+
+/**
+ * _cairo_font_options_get_lcd_filter:
+ * @options: a #cairo_font_options_t
+ *
+ * Gets the LCD filter for the font options object.
+ * See the documentation for #cairo_lcd_filter_t for full details.
+ *
+ * Return value: the LCD filter for the font options object
+ *
+ * Since: 1.8
+ **/
+cairo_lcd_filter_t
+_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options)
+{
+ if (cairo_font_options_status ((cairo_font_options_t *) options))
+ return CAIRO_LCD_FILTER_DEFAULT;
+
+ return options->lcd_filter;
+}
+
+/**
* cairo_font_options_set_hint_style:
* @options: a #cairo_font_options_t
* @hint_style: the new hint style
*
* Sets the hint style for font outlines for the font options object.
* This controls whether to fit font outlines to the pixel grid,
* and if so, whether to optimize for fidelity or contrast.
* See the documentation for #cairo_hint_style_t for full details.
diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -54,16 +54,38 @@
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_IMAGE_H
#include FT_TRUETYPE_TABLES_H
#if HAVE_FT_GLYPHSLOT_EMBOLDEN
#include FT_SYNTHESIS_H
#endif
+#include FT_LCD_FILTER_H
+
+/* Fontconfig version older than 2.6 didn't have these options */
+#ifndef FC_LCD_FILTER
+#define FC_LCD_FILTER "lcdfilter"
+#endif
+/* Some Ubuntu versions defined FC_LCD_FILTER without defining the following */
+#ifndef FC_LCD_NONE
+#define FC_LCD_NONE 0
+#define FC_LCD_DEFAULT 1
+#define FC_LCD_LIGHT 2
+#define FC_LCD_LEGACY 3
+#endif
+
+/* FreeType version older than 2.3.5(?) didn't have these options */
+#ifndef FT_LCD_FILTER_NONE
+#define FT_LCD_FILTER_NONE 0
+#define FT_LCD_FILTER_DEFAULT 1
+#define FT_LCD_FILTER_LIGHT 2
+#define FT_LCD_FILTER_LEGACY 16
+#endif
+
#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
/* This is the max number of FT_face objects we keep open at once
*/
#define MAX_OPEN_FACES 10
@@ -774,45 +796,309 @@ _cairo_ft_unscaled_font_set_scale (cairo
unscaled->face->available_sizes[best_i].height);
if (error)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}
-/* Empirically-derived subpixel filtering values thanks to Keith
- * Packard and libXft. */
-static const int filters[3][3] = {
- /* red */
-#if 0
- { 65538*4/7,65538*2/7,65538*1/7 },
- /* green */
- { 65536*1/4, 65536*2/4, 65537*1/4 },
- /* blue */
- { 65538*1/7,65538*2/7,65538*4/7 },
+/* 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);
+
+ target->pixel_mode = ftbit->pixel_mode;
+
+ 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;
+ }
+ }
+ target->pixel_mode = FT_PIXEL_MODE_LCD;
+
+ } 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;
+ }
+ }
+ target->pixel_mode = FT_PIXEL_MODE_GRAY;
+
+ } 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;
+ }
+ }
+ target->pixel_mode = FT_PIXEL_MODE_LCD;
+ } 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;
+#if 1
+ pix = ((unsigned int)src[0] << 16) |
+ ((unsigned int)src[src_pitch] << 8) |
+ ((unsigned int)src[src_pitch*2] ) |
+ 0xFF000000 ;
+#else
+ pix = ((unsigned int)src[0] << 16) |
+ ((unsigned int)src[src_pitch] << 8) |
+ ((unsigned int)src[src_pitch*2] ) |
+ ((unsigned int)src[src_pitch] << 24) ;
#endif
- { 65538*9/13,65538*3/13,65538*1/13 },
- /* green */
- { 65538*1/6, 65538*4/6, 65538*1/6 },
- /* blue */
- { 65538*1/13,65538*3/13,65538*9/13 },
-};
+ 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;
+ }
+ }
+ }
+ }
+}
+
/* Fills in val->image with an image surface created from @bitmap
*/
static cairo_status_t
_get_bitmap_surface (FT_Bitmap *bitmap,
cairo_bool_t own_buffer,
cairo_font_options_t *font_options,
cairo_image_surface_t **surface)
{
int width, height, stride;
unsigned char *data;
int format = CAIRO_FORMAT_A8;
+ cairo_image_surface_t *image;
width = bitmap->width;
height = bitmap->rows;
if (width == 0 || height == 0) {
*surface = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
return (*surface)->base.status;
@@ -859,150 +1145,63 @@ _get_bitmap_surface (FT_Bitmap *bi
}
#endif
format = CAIRO_FORMAT_A1;
break;
case FT_PIXEL_MODE_LCD:
case FT_PIXEL_MODE_LCD_V:
case FT_PIXEL_MODE_GRAY:
- switch (font_options->antialias) {
- case CAIRO_ANTIALIAS_DEFAULT:
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_NONE:
- default:
+ if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) {
stride = bitmap->pitch;
if (own_buffer) {
data = bitmap->buffer;
} else {
data = _cairo_malloc_ab (height, stride);
if (!data)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (data, bitmap->buffer, stride * height);
}
format = CAIRO_FORMAT_A8;
- break;
- case CAIRO_ANTIALIAS_SUBPIXEL: {
- int x, y;
- unsigned char *in_line, *out_line, *in;
- unsigned int *out;
- unsigned int red, green, blue;
- int rf, gf, bf;
- int s;
- int o, os;
- unsigned char *data_rgba;
- unsigned int width_rgba, stride_rgba;
- int vmul = 1;
- int hmul = 1;
-
- switch (font_options->subpixel_order) {
- case CAIRO_SUBPIXEL_ORDER_DEFAULT:
- case CAIRO_SUBPIXEL_ORDER_RGB:
- case CAIRO_SUBPIXEL_ORDER_BGR:
- default:
- width /= 3;
- hmul = 3;
- break;
- case CAIRO_SUBPIXEL_ORDER_VRGB:
- case CAIRO_SUBPIXEL_ORDER_VBGR:
- vmul = 3;
- height /= 3;
- break;
- }
- /*
- * Filter the glyph to soften the color fringes
- */
- width_rgba = width;
+ } else {
+ /* if we get there, the data from the source bitmap
+ * really comes from _fill_xrender_bitmap, and is
+ * made of 32-bit ARGB or ABGR values */
+ assert (own_buffer != 0);
+ assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY);
+
+ data = bitmap->buffer;
stride = bitmap->pitch;
- stride_rgba = (width_rgba * 4 + 3) & ~3;
- data_rgba = calloc (stride_rgba, height);
- if (unlikely (data_rgba == NULL)) {
- if (own_buffer)
- free (bitmap->buffer);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- os = 1;
- switch (font_options->subpixel_order) {
- case CAIRO_SUBPIXEL_ORDER_VRGB:
- os = stride;
- case CAIRO_SUBPIXEL_ORDER_DEFAULT:
- case CAIRO_SUBPIXEL_ORDER_RGB:
- default:
- rf = 0;
- gf = 1;
- bf = 2;
- break;
- case CAIRO_SUBPIXEL_ORDER_VBGR:
- os = stride;
- case CAIRO_SUBPIXEL_ORDER_BGR:
- bf = 0;
- gf = 1;
- rf = 2;
- break;
- }
- in_line = bitmap->buffer;
- out_line = data_rgba;
- for (y = 0; y < height; y++)
- {
- in = in_line;
- out = (unsigned int *) out_line;
- in_line += stride * vmul;
- out_line += stride_rgba;
- for (x = 0; x < width * hmul; x += hmul)
- {
- red = green = blue = 0;
- o = 0;
- for (s = 0; s < 3; s++)
- {
- red += filters[rf][s]*in[x+o];
- green += filters[gf][s]*in[x+o];
- blue += filters[bf][s]*in[x+o];
- o += os;
- }
- red = red / 65536;
- green = green / 65536;
- blue = blue / 65536;
- *out++ = (green << 24) | (red << 16) | (green << 8) | blue;
- }
- }
-
- /* Images here are stored in native format. The
- * backend must convert to its own format as needed
- */
-
- if (own_buffer)
- free (bitmap->buffer);
- data = data_rgba;
- stride = stride_rgba;
format = CAIRO_FORMAT_ARGB32;
- break;
- }
}
break;
case FT_PIXEL_MODE_GRAY2:
case FT_PIXEL_MODE_GRAY4:
/* These could be triggered by very rare types of TrueType fonts */
default:
if (own_buffer)
free (bitmap->buffer);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- *surface = (cairo_image_surface_t *)
+ /* XXX */
+ *surface = image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (data,
format,
width, height, stride);
- if ((*surface)->base.status) {
+ if (image->base.status) {
free (data);
return (*surface)->base.status;
}
- _cairo_image_surface_assume_ownership_of_data ((*surface));
+ if (font_options->antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+ pixman_image_set_component_alpha (image->pixman_image, TRUE);
+
+ _cairo_image_surface_assume_ownership_of_data ((image));
_cairo_debug_check_image_surface_is_defined (&(*surface)->base);
return CAIRO_STATUS_SUCCESS;
}
/* Converts an outline FT_GlyphSlot into an image
*
@@ -1019,129 +1218,169 @@ _get_bitmap_surface (FT_Bitmap *bi
* when we add subpixel support. If so, we may want to eliminate
* this version of the code path entirely.
*/
static cairo_status_t
_render_glyph_outline (FT_Face face,
cairo_font_options_t *font_options,
cairo_image_surface_t **surface)
{
+ int rgba = FC_RGBA_UNKNOWN;
+ int lcd_filter = FT_LCD_FILTER_LEGACY;
FT_GlyphSlot glyphslot = face->glyph;
FT_Outline *outline = &glyphslot->outline;
FT_Bitmap bitmap;
FT_BBox cbox;
- FT_Matrix matrix;
- int hmul = 1;
- int vmul = 1;
- unsigned int width, height, stride;
- cairo_bool_t subpixel = FALSE;
+ unsigned int width, height;
cairo_status_t status;
+ FT_Error fterror;
+ FT_Library library = glyphslot->library;
+ FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
+
+ switch (font_options->antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ render_mode = FT_RENDER_MODE_MONO;
+ break;
+
+ case CAIRO_ANTIALIAS_SUBPIXEL:
+ switch (font_options->subpixel_order) {
+ case CAIRO_SUBPIXEL_ORDER_DEFAULT:
+ case CAIRO_SUBPIXEL_ORDER_RGB:
+ case CAIRO_SUBPIXEL_ORDER_BGR:
+ render_mode = FT_RENDER_MODE_LCD;
+ break;
+
+ case CAIRO_SUBPIXEL_ORDER_VRGB:
+ case CAIRO_SUBPIXEL_ORDER_VBGR:
+ render_mode = FT_RENDER_MODE_LCD_V;
+ break;
+ }
+
+ switch (font_options->lcd_filter) {
+ case CAIRO_LCD_FILTER_NONE:
+ lcd_filter = FT_LCD_FILTER_NONE;
+ break;
+ case CAIRO_LCD_FILTER_DEFAULT:
+ case CAIRO_LCD_FILTER_INTRA_PIXEL:
+ lcd_filter = FT_LCD_FILTER_LEGACY;
+ break;
+ case CAIRO_LCD_FILTER_FIR3:
+ lcd_filter = FT_LCD_FILTER_LIGHT;
+ break;
+ case CAIRO_LCD_FILTER_FIR5:
+ lcd_filter = FT_LCD_FILTER_DEFAULT;
+ break;
+ }
+
+ break;
+
+ case CAIRO_ANTIALIAS_DEFAULT:
+ case CAIRO_ANTIALIAS_GRAY:
+ render_mode = FT_RENDER_MODE_NORMAL;
+ }
FT_Outline_Get_CBox (outline, &cbox);
cbox.xMin &= -64;
cbox.yMin &= -64;
cbox.xMax = (cbox.xMax + 63) & -64;
cbox.yMax = (cbox.yMax + 63) & -64;
width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
- stride = (width * hmul + 3) & ~3;
if (width * height == 0) {
cairo_format_t format;
/* Looks like fb handles zero-sized images just fine */
- switch (font_options->antialias) {
- case CAIRO_ANTIALIAS_NONE:
+ switch (render_mode) {
+ case FT_RENDER_MODE_MONO:
format = CAIRO_FORMAT_A1;
break;
- case CAIRO_ANTIALIAS_SUBPIXEL:
+ case FT_RENDER_MODE_LCD:
+ case FT_RENDER_MODE_LCD_V:
format= CAIRO_FORMAT_ARGB32;
break;
- case CAIRO_ANTIALIAS_DEFAULT:
- case CAIRO_ANTIALIAS_GRAY:
+ case FT_RENDER_MODE_LIGHT:
+ case FT_RENDER_MODE_NORMAL:
+ case FT_RENDER_MODE_MAX:
default:
format = CAIRO_FORMAT_A8;
break;
}
(*surface) = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
if ((*surface)->base.status)
return (*surface)->base.status;
} else {
- matrix.xx = matrix.yy = 0x10000L;
- matrix.xy = matrix.yx = 0;
-
- switch (font_options->antialias) {
- case CAIRO_ANTIALIAS_NONE:
- bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
- bitmap.num_grays = 1;
- stride = ((width + 31) & -32) >> 3;
+ int bitmap_size;
+
+ switch (render_mode) {
+ case FT_RENDER_MODE_LCD:
+ if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) {
+ rgba = FC_RGBA_BGR;
+ } else {
+ rgba = FC_RGBA_RGB;
+ }
break;
- case CAIRO_ANTIALIAS_DEFAULT:
- case CAIRO_ANTIALIAS_GRAY:
- bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
- bitmap.num_grays = 256;
- stride = (width + 3) & -4;
+ case FT_RENDER_MODE_LCD_V:
+ if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) {
+ rgba = FC_RGBA_VBGR;
+ } else {
+ rgba = FC_RGBA_VRGB;
+ }
break;
- case CAIRO_ANTIALIAS_SUBPIXEL:
- switch (font_options->subpixel_order) {
- case CAIRO_SUBPIXEL_ORDER_RGB:
- case CAIRO_SUBPIXEL_ORDER_BGR:
- case CAIRO_SUBPIXEL_ORDER_DEFAULT:
- default:
- matrix.xx *= 3;
- hmul = 3;
- subpixel = TRUE;
- break;
- case CAIRO_SUBPIXEL_ORDER_VRGB:
- case CAIRO_SUBPIXEL_ORDER_VBGR:
- matrix.yy *= 3;
- vmul = 3;
- subpixel = TRUE;
- break;
- }
- FT_Outline_Transform (outline, &matrix);
-
- bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
- bitmap.num_grays = 256;
- stride = (width * hmul + 3) & -4;
+ case FT_RENDER_MODE_MONO:
+ case FT_RENDER_MODE_LIGHT:
+ case FT_RENDER_MODE_NORMAL:
+ case FT_RENDER_MODE_MAX:
+ default:
+ break;
}
- bitmap.pitch = stride;
- bitmap.width = width * hmul;
- bitmap.rows = height * vmul;
- bitmap.buffer = calloc (stride, bitmap.rows);
+ FT_Library_SetLcdFilter (library, lcd_filter);
+
+ fterror = FT_Render_Glyph (face->glyph, render_mode);
+
+ FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE);
+
+ if (fterror != 0)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ bitmap_size = _compute_xrender_bitmap_size (&bitmap,
+ face->glyph,
+ render_mode);
+ if (bitmap_size < 0)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ bitmap.buffer = calloc (1, bitmap_size);
if (unlikely (bitmap.buffer == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
-
- if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
- free (bitmap.buffer);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
+ _fill_xrender_bitmap (&bitmap, face->glyph, render_mode,
+ (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR));
+
+ /* Note:
+ * _get_bitmap_surface will free bitmap.buffer if there is an error
+ */
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
if (unlikely (status))
return status;
+
+ /* Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinate of the control box needs to be negated. Moreover, device
+ * offsets are position of glyph origin relative to top left while xMin
+ * and yMax are offsets of top left relative to origin. Another negation.
+ */
+ cairo_surface_set_device_offset (&(*surface)->base,
+ (double)-glyphslot->bitmap_left,
+ (double)+glyphslot->bitmap_top);
}
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinate of the control box needs to be negated. Moreover, device
- * offsets are position of glyph origin relative to top left while xMin
- * and yMax are offsets of top left relative to origin. Another negation.
- */
- cairo_surface_set_device_offset (&(*surface)->base,
- floor (-(double) cbox.xMin / 64.0),
- floor (+(double) cbox.yMax / 64.0));
-
return CAIRO_STATUS_SUCCESS;
}
/* Converts a bitmap (or other) FT_GlyphSlot into an image */
static cairo_status_t
_render_glyph_bitmap (FT_Face face,
cairo_font_options_t *font_options,
cairo_image_surface_t **surface)
@@ -1350,16 +1589,17 @@ _get_pattern_ft_options (FcPattern *patt
/* disable antialiasing if requested */
if (FcPatternGetBool (pattern,
FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
antialias = FcTrue;
if (antialias) {
cairo_subpixel_order_t subpixel_order;
+ int lcd_filter;
/* disable hinting if requested */
if (FcPatternGetBool (pattern,
FC_HINTING, 0, &hinting) != FcResultMatch)
hinting = FcTrue;
if (FcPatternGetInteger (pattern,
FC_RGBA, 0, &rgba) != FcResultMatch)
@@ -1385,16 +1625,35 @@ _get_pattern_ft_options (FcPattern *patt
break;
}
if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
ft_options.base.subpixel_order = subpixel_order;
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
}
+ if (FcPatternGetInteger (pattern,
+ FC_LCD_FILTER, 0, &lcd_filter) == FcResultMatch)
+ {
+ switch (lcd_filter) {
+ case FC_LCD_NONE:
+ ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE;
+ break;
+ case FC_LCD_DEFAULT:
+ ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5;
+ break;
+ case FC_LCD_LIGHT:
+ ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3;
+ break;
+ case FC_LCD_LEGACY:
+ ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
+ break;
+ }
+ }
+
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
hintstyle = FC_HINT_FULL;
if (!hinting)
hintstyle = FC_HINT_NONE;
@@ -1486,16 +1745,22 @@ _cairo_ft_options_merge (cairo_ft_option
}
if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT)
options->base.hint_style = other->base.hint_style;
if (other->base.hint_style == CAIRO_HINT_STYLE_NONE)
options->base.hint_style = CAIRO_HINT_STYLE_NONE;
+ if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT)
+ options->base.lcd_filter = other->base.lcd_filter;
+
+ if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE)
+ options->base.lcd_filter = CAIRO_LCD_FILTER_NONE;
+
if (options->base.antialias == CAIRO_ANTIALIAS_NONE) {
if (options->base.hint_style == CAIRO_HINT_STYLE_NONE)
load_flags |= FT_LOAD_NO_HINTING;
else
load_target = FT_LOAD_TARGET_MONO;
load_flags |= FT_LOAD_MONOCHROME;
} else {
switch (options->base.hint_style) {
@@ -1509,21 +1774,21 @@ _cairo_ft_options_merge (cairo_ft_option
break;
case CAIRO_HINT_STYLE_FULL:
case CAIRO_HINT_STYLE_DEFAULT:
if (options->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
switch (options->base.subpixel_order) {
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
case CAIRO_SUBPIXEL_ORDER_RGB:
case CAIRO_SUBPIXEL_ORDER_BGR:
- load_target |= FT_LOAD_TARGET_LCD;
+ load_target = FT_LOAD_TARGET_LCD;
break;
case CAIRO_SUBPIXEL_ORDER_VRGB:
case CAIRO_SUBPIXEL_ORDER_VBGR:
- load_target |= FT_LOAD_TARGET_LCD_V;
+ load_target = FT_LOAD_TARGET_LCD_V;
break;
}
}
break;
}
}
options->load_flags = load_flags | load_target;
@@ -2512,16 +2777,44 @@ _cairo_ft_font_options_substitute (const
rgba = FC_RGBA_NONE;
}
if (! FcPatternAddInteger (pattern, FC_RGBA, rgba))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
+ if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
+ {
+ if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
+ {
+ int lcd_filter;
+
+ switch (options->lcd_filter) {
+ case CAIRO_LCD_FILTER_NONE:
+ lcd_filter = FT_LCD_FILTER_NONE;
+ break;
+ case CAIRO_LCD_FILTER_DEFAULT:
+ case CAIRO_LCD_FILTER_INTRA_PIXEL:
+ lcd_filter = FT_LCD_FILTER_LEGACY;
+ break;
+ case CAIRO_LCD_FILTER_FIR3:
+ lcd_filter = FT_LCD_FILTER_LIGHT;
+ break;
+ default:
+ case CAIRO_LCD_FILTER_FIR5:
+ lcd_filter = FT_LCD_FILTER_DEFAULT;
+ break;
+ }
+
+ if (! FcPatternAddInteger (pattern, FC_LCD_FILTER, lcd_filter))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ }
+
if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT)
{
if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
{
if (! FcPatternAddBool (pattern,
FC_HINTING,
options->hint_style != CAIRO_HINT_STYLE_NONE))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -68,16 +68,17 @@ const cairo_surface_t name = { \
NULL, /* snapshot_detach */ \
{ 0, /* size */ \
0, /* num_elements */ \
0, /* element_size */ \
NULL, /* elements */ \
}, /* snapshots */ \
{ CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \
+ CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
CAIRO_HINT_METRICS_DEFAULT /* hint_metrics */ \
} /* font_options */ \
}
/* XXX error object! */
static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil);
diff --git a/gfx/cairo/cairo/src/cairo-types-private.h b/gfx/cairo/cairo/src/cairo-types-private.h
--- a/gfx/cairo/cairo/src/cairo-types-private.h
+++ b/gfx/cairo/cairo/src/cairo-types-private.h
@@ -112,19 +112,45 @@ struct _cairo_array {
unsigned int size;
unsigned int num_elements;
unsigned int element_size;
char **elements;
cairo_bool_t is_snapshot;
};
+
+/**
+ * cairo_lcd_filter_t:
+ * @CAIRO_LCD_FILTER_DEFAULT: Use the default LCD filter for
+ * font backend and target device
+ * @CAIRO_LCD_FILTER_NONE: Do not perform LCD filtering
+ * @CAIRO_LCD_FILTER_INTRA_PIXEL: Intra-pixel filter
+ * @CAIRO_LCD_FILTER_FIR3: FIR filter with a 3x3 kernel
+ * @CAIRO_LCD_FILTER_FIR5: FIR filter with a 5x5 kernel
+ *
+ * The LCD filter specifies the low-pass filter applied to LCD-optimized
+ * bitmaps generated with an antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
+ *
+ * Note: This API was temporarily made available in the public
+ * interface during the 1.7.x development series, but was made private
+ * before 1.8.
+ **/
+typedef enum _cairo_lcd_filter {
+ CAIRO_LCD_FILTER_DEFAULT,
+ CAIRO_LCD_FILTER_NONE,
+ CAIRO_LCD_FILTER_INTRA_PIXEL,
+ CAIRO_LCD_FILTER_FIR3,
+ CAIRO_LCD_FILTER_FIR5
+} cairo_lcd_filter_t;
+
struct _cairo_font_options {
cairo_antialias_t antialias;
cairo_subpixel_order_t subpixel_order;
+ cairo_lcd_filter_t lcd_filter;
cairo_hint_style_t hint_style;
cairo_hint_metrics_t hint_metrics;
};
/* XXX: Right now, the _cairo_color structure puts unpremultiplied
color in the doubles and premultiplied color in the shorts. Yes,
this is crazy insane, (but at least we don't export this
madness). I'm still working on a cleaner API, but in the meantime,
diff --git a/gfx/cairo/cairo/src/cairo-xlib-screen.c b/gfx/cairo/cairo/src/cairo-xlib-screen.c
--- a/gfx/cairo/cairo/src/cairo-xlib-screen.c
+++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c
@@ -56,16 +56,23 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-xrender-private.h"
#include "cairo-xlib-surface-private.h"
#include <fontconfig/fontconfig.h>
+#ifndef FC_LCD_NONE
+#define FC_LCD_NONE 0
+#define FC_LCD_DEFAULT 1
+#define FC_LCD_LIGHT 2
+#define FC_LCD_LEGACY 3
+#endif
+
static int
parse_boolean (const char *v)
{
char c0, c1;
c0 = *v;
if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
return 1;
@@ -145,23 +152,32 @@ get_integer_default (Display *dpy,
static void
_cairo_xlib_init_screen_font_options (Display *dpy,
cairo_xlib_screen_t *info)
{
cairo_bool_t xft_hinting;
cairo_bool_t xft_antialias;
int xft_hintstyle;
int xft_rgba;
+ int xft_lcdfilter;
cairo_antialias_t antialias;
cairo_subpixel_order_t subpixel_order;
+ cairo_lcd_filter_t lcd_filter;
cairo_hint_style_t hint_style;
if (!get_boolean_default (dpy, "antialias", &xft_antialias))
xft_antialias = TRUE;
+ if (!get_integer_default (dpy, "lcdfilter", &xft_lcdfilter)) {
+ /* -1 is an non-existant Fontconfig constant used to differentiate
+ * the case when no lcdfilter property is available.
+ */
+ xft_lcdfilter = -1;
+ }
+
if (!get_boolean_default (dpy, "hinting", &xft_hinting))
xft_hinting = TRUE;
if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle))
xft_hintstyle = FC_HINT_FULL;
if (!get_integer_default (dpy, "rgba", &xft_rgba))
{
@@ -234,28 +250,47 @@ _cairo_xlib_init_screen_font_options (Di
subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
break;
case FC_RGBA_UNKNOWN:
case FC_RGBA_NONE:
default:
subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
}
+ switch (xft_lcdfilter) {
+ case FC_LCD_NONE:
+ lcd_filter = CAIRO_LCD_FILTER_NONE;
+ break;
+ case FC_LCD_DEFAULT:
+ lcd_filter = CAIRO_LCD_FILTER_FIR5;
+ break;
+ case FC_LCD_LIGHT:
+ lcd_filter = CAIRO_LCD_FILTER_FIR3;
+ break;
+ case FC_LCD_LEGACY:
+ lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
+ break;
+ default:
+ lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
+ break;
+ }
+
if (xft_antialias) {
if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
antialias = CAIRO_ANTIALIAS_GRAY;
else
antialias = CAIRO_ANTIALIAS_SUBPIXEL;
} else {
antialias = CAIRO_ANTIALIAS_NONE;
}
cairo_font_options_set_hint_style (&info->font_options, hint_style);
cairo_font_options_set_antialias (&info->font_options, antialias);
cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order);
+ _cairo_font_options_set_lcd_filter (&info->font_options, lcd_filter);
cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON);
}
cairo_xlib_screen_t *
_cairo_xlib_screen_reference (cairo_xlib_screen_t *info)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -1400,16 +1400,23 @@ extern const cairo_private uint16_t _cai
cairo_private void
_cairo_font_options_init_default (cairo_font_options_t *options);
cairo_private void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other);
+cairo_private void
+_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
+ cairo_lcd_filter_t lcd_filter);
+
+cairo_private cairo_lcd_filter_t
+_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options);
+
/* cairo-hull.c */
cairo_private cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
/* cairo-lzw.c */
cairo_private unsigned char *
_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out);
diff --git a/js/src/config/system-headers b/js/src/config/system-headers
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -267,16 +267,17 @@ Font.h
Fonts.h
fp.h
fpieee.h
frame/log.h
frame/req.h
freetype/freetype.h
freetype/ftcache.h
freetype/ftglyph.h
+freetype/ftlcdfil.h
freetype/ftsynth.h
freetype/ftoutln.h
freetype/ttnameid.h
freetype/tttables.h
freetype/t1tables.h
fribidi/fribidi.h
FSp_fopen.h
fstream