bug 642589 - expose prefs for tweaking DirectWrite/D2D antialiasing behavior. r=jdaggett
authorJonathan Kew <jfkthame@gmail.com>
Thu, 21 Apr 2011 07:29:50 +0100
changeset 68380 fd8e217b2c84e199e1c1a4a6c6c74368812c154b
parent 68379 0c3bd5909e79ba1e313443397d15ac4ed294c3c1
child 68381 46fdf12082d48475b66c42491a1a73e4d0cf0f31
push id19616
push userjkew@mozilla.com
push dateThu, 21 Apr 2011 06:42:37 +0000
treeherdermozilla-central@46fdf12082d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs642589
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 642589 - expose prefs for tweaking DirectWrite/D2D antialiasing behavior. r=jdaggett
gfx/cairo/cairo/src/cairo-d2d-private.h
gfx/cairo/cairo/src/cairo-d2d-surface.cpp
gfx/cairo/cairo/src/cairo-dwrite-font.cpp
gfx/cairo/cairo/src/cairo-dwrite-private.h
gfx/cairo/cairo/src/cairo-win32.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxDWriteFonts.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
modules/libpref/src/init/all.js
--- a/gfx/cairo/cairo/src/cairo-d2d-private.h
+++ b/gfx/cairo/cairo/src/cairo-d2d-private.h
@@ -75,17 +75,17 @@ struct _cairo_d2d_device
 };
 
 const unsigned int TEXT_TEXTURE_WIDTH = 2048;
 const unsigned int TEXT_TEXTURE_HEIGHT = 512;
 typedef struct _cairo_d2d_device cairo_d2d_device_t;
 
 struct _cairo_d2d_surface {
     _cairo_d2d_surface() : d2d_clip(NULL), clipping(false), isDrawing(false),
-	textRenderingInit(true)
+	textRenderingInit(false)
     {
 	_cairo_clip_init (&this->clip);
     }
 
     cairo_surface_t base;
     /* Device used by this surface 
      * NOTE: In upstream cairo this is in the surface base class */
     cairo_d2d_device_t *device;
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -171,17 +171,17 @@ cairo_d2d_create_device_from_d3d10device
 	{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
     };
     D3D10_PASS_DESC passDesc;
     ID3D10EffectTechnique *technique;
     Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
     CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
     D3D10_SUBRESOURCE_DATA data;
     CD3D10_TEXTURE2D_DESC textDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
-	                           TEXT_TEXTURE_WIDTH,
+				   TEXT_TEXTURE_WIDTH,
 				   TEXT_TEXTURE_HEIGHT,
 				   1, 1);
 
     cairo_d2d_device_t *device = new cairo_d2d_device_t;
 
     device->mD3D10Device = d3d10device;
 
     device->mD3D10_1 = LoadLibraryA("d3d10_1.dll");
@@ -347,20 +347,20 @@ cairo_d2d_create_device()
 
 int
 cairo_release_device(cairo_device_t *device)
 {
     int newrefcnt = --device->refcount;
     if (!newrefcnt) {
 	// Call the correct destructor
 	cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
-        HMODULE d3d10_1 = d2d_device->mD3D10_1;
+	HMODULE d3d10_1 = d2d_device->mD3D10_1;
 	delete d2d_device;
 	_cairo_d2d_release_factory();
-        FreeLibrary(d3d10_1);
+	FreeLibrary(d3d10_1);
     }
     return newrefcnt;
 }
 
 int
 cairo_addref_device(cairo_device_t *device)
 {
     return ++device->refcount;
@@ -774,17 +774,17 @@ static ID3D10Texture2D*
 _cairo_d2d_get_buffer_texture(cairo_d2d_surface_t *surface) 
 {
     if (!surface->bufferTexture) {
 	RefPtr<IDXGISurface> surf;
 	DXGI_SURFACE_DESC surfDesc;
 	surface->surface->QueryInterface(&surf);
 	surf->GetDesc(&surfDesc);
 	CD3D10_TEXTURE2D_DESC softDesc(surfDesc.Format, surfDesc.Width, surfDesc.Height);
-        softDesc.MipLevels = 1;
+	softDesc.MipLevels = 1;
 	softDesc.Usage = D3D10_USAGE_DEFAULT;
 	softDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
 	surface->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &surface->bufferTexture);
 	surface->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(surface);
     }
     return surface->bufferTexture;
 }
 
@@ -1153,19 +1153,19 @@ static RefPtr<ID2D1StrokeStyle>
     RefPtr<ID2D1StrokeStyle> strokeStyle;
     sD2DFactory->CreateStrokeStyle(D2D1::StrokeStyleProperties(line_cap, 
 							       line_cap,
 							       line_cap, 
 							       line_join, 
 							       (FLOAT)style->miter_limit,
 							       dashStyle,
 							       (FLOAT)style->dash_offset),
-							        dashes,
-							        style->num_dashes,
-							        &strokeStyle);
+							       dashes,
+							       style->num_dashes,
+							       &strokeStyle);
     delete [] dashes;
     return strokeStyle;
 }
 
 static int _d2d_compute_bitmap_mem_size(ID2D1Bitmap *bitmap)
 {
     D2D1_SIZE_U size = bitmap->GetPixelSize();
     int bytes_per_pixel = bitmap->GetPixelFormat().format == DXGI_FORMAT_A8_UNORM ? 1 : 4;
@@ -1220,17 +1220,17 @@ static void _d2d_release_bitmap(void *bi
 static void _d2d_snapshot_detached(cairo_surface_t *surface)
 {
     cached_bitmap *existingBitmap = (cached_bitmap*)cairo_surface_get_user_data(surface, &bitmap_key_snapshot);
     if (existingBitmap) {
 	existingBitmap->dirty = true;
     }
     if (!--existingBitmap->refs) {
 	cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
-        delete existingBitmap;
+	delete existingBitmap;
     }
     cairo_surface_destroy(surface);
 }
 
 /**
  * This function will calculate the part of srcSurf which will possibly be used within
  * the boundaries of d2dsurf given the current transformation mat. This is used to
  * determine what the minimal part of a surface is that needs to be uploaded.
@@ -1458,18 +1458,18 @@ static RefPtr<ID2D1Brush>
 	for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) {
 	    cairo_gradient_stop_t *stop = &source_pattern->base.stops[i];
 	    stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor);
 	    stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
 	}
     } else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
 	float offset_factor = (outer_radius - inner_radius) / outer_radius;
 	float global_offset = inner_radius / outer_radius;
-        
-        num_stops++; // Add a stop on the outer radius.
+
+	num_stops++; // Add a stop on the outer radius.
 	if (inner_radius != 0) {
 	    num_stops++; // Add a stop on the inner radius.
 	}
 
 	stops = new D2D1_GRADIENT_STOP[num_stops];
 
 	// If the inner radius is not 0 we need to scale and offset the stops and put a stop before the inner_radius
 	// of a transparent color.
@@ -1567,21 +1567,21 @@ static RefPtr<ID2D1Brush>
 
 	// (corner - p1) . u = |corner - p1| cos(a) where a is the angle between the two vectors.
 	// Coincidentally |corner - p1| cos(a) is actually also the distance our gradient needs to cover since
 	// at this point on the gradient line it will be perpendicular to the line running from the gradient
 	// line through the corner.
 
 	double max_dist, min_dist;
 	max_dist = MAX(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
-	               _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
+		       _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
 	max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
 	max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
 	min_dist = MIN(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
-	               _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
+		       _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
 	min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
 	min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
 
 	min_dist = MAX(-min_dist, 0);
 
 	// Repeats after gradient start.
 	int after_repeat = (int)ceil(max_dist / gradient_length);
 	int before_repeat = (int)ceil(min_dist / gradient_length);
@@ -1753,17 +1753,17 @@ static RefPtr<ID2D1Brush>
 	    
 	    if (srcSurf == d2dsurf) {
 		/* D2D cannot deal with self-copy. We should add an optimized
 		 * codepath for self-copy in the easy cases that does ping-pong like
 		 * scroll does. See bug 579215. For now fallback.
 		 */
 		return NULL;
 	    }
-            if (srcSurf->device != d2dsurf->device) {
+	    if (srcSurf->device != d2dsurf->device) {
 		/* This code does not work if the source surface does not use
 		 * the same device. Some work could be done to do something
 		 * fairly efficient here, for now, fallback.
 		 */
 		return NULL;
 	    }
 
 	    _cairo_d2d_update_surface_bitmap(srcSurf);
@@ -1825,31 +1825,31 @@ static RefPtr<ID2D1Brush>
 		}
 
 		/* We cannot fit this image directly into a texture, start doing tricks to draw correctly anyway. */
 		partial = true;
 
 		/* First we check which part of the image is inside the viewable area. */
   		_cairo_d2d_calculate_visible_rect(d2dsurf, srcSurf, &mat, &xoffset, &yoffset, &width, &height);
 
-	        cairo_matrix_translate(&mat, xoffset, yoffset);
+		cairo_matrix_translate(&mat, xoffset, yoffset);
 
 		if (width > maxSize || height > maxSize) {
 		    /*
 		     * We cannot upload the required part of the surface directly, we're going to create
 		     * a version which is downsampled to a smaller size by pixman and then uploaded.
 		     *
 		     * We need to size it to at least the diagonal size of this surface, in order to prevent ever
 		     * upsampling this again when drawing it to the surface. We want the resized surface
 		     * to be as small as possible to limit pixman required fill rate.
-                     *
-                     * Note this isn't necessarily perfect. Imagine having a 5x5 pixel destination and
-                     * a 10x5 image containing a line of blackpixels, white pixels, black pixels, if you rotate
-                     * this by 45 degrees and scale it to a size of 5x5 pixels and composite it to the destination,
-                     * the composition will require all 10 original columns to do the best possible sampling.
+		     *
+		     * Note this isn't necessarily perfect. Imagine having a 5x5 pixel destination and
+		     * a 10x5 image containing a line of blackpixels, white pixels, black pixels, if you rotate
+		     * this by 45 degrees and scale it to a size of 5x5 pixels and composite it to the destination,
+		     * the composition will require all 10 original columns to do the best possible sampling.
 		     */
 		    RefPtr<IDXGISurface> surf;
 		    d2dsurf->surface->QueryInterface(&surf);
 		    DXGI_SURFACE_DESC desc;
 		    surf->GetDesc(&desc);
 
 		    unsigned int minSize = (unsigned int)ceil(sqrt(pow((float)desc.Width, 2) + pow((float)desc.Height, 2)));
 		    
@@ -1973,20 +1973,20 @@ static RefPtr<ID2D1Brush>
 		}
 
 		if (!partial) {
 		    cached_bitmap *cachebitmap = new cached_bitmap;
 		    /* We can cache it if it isn't a partial bitmap */
 		    cachebitmap->dirty = false;
 		    cachebitmap->bitmap = sourceBitmap;
 		    cachebitmap->device = d2dsurf->device;
-                    /*
-                     * This will start out with two references, one on the snapshot
-                     * and one more in the user data structure.
-                     */
+		    /*
+		     * This will start out with two references, one on the snapshot
+		     * and one more in the user data structure.
+		     */
 		    cachebitmap->refs = 2;
 		    cairo_surface_set_user_data(surfacePattern->surface,
 						key,
 						cachebitmap,
 						_d2d_release_bitmap);
 		    cairo_surface_t *nullSurf =
 			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
 		    cairo_surface_set_user_data(nullSurf,
@@ -2267,33 +2267,33 @@ static cairo_int_status_t
 
 	for (i = 0; i < num_rects; i++) {
 	    cairo_rectangle_int_t rect;
 
 	    cairo_region_get_rectangle (region, i, &rect);
 
 	    d2dsurf->rt->PushAxisAlignedClip(
 		    D2D1::RectF((FLOAT)rect.x,
-			        (FLOAT)rect.y,
+				(FLOAT)rect.y,
 				(FLOAT)rect.x + rect.width,
 				(FLOAT)rect.y + rect.height),
 		    D2D1_ANTIALIAS_MODE_ALIASED);
 
 	    d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
 
 	    d2dsurf->rt->PopAxisAlignedClip();
 	}
 
     }
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
 static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op,
-					             const cairo_pattern_t *source)
+						     const cairo_pattern_t *source)
 {
     if (op == CAIRO_OPERATOR_SOURCE) {
 	/** Operator over is easier for D2D! If the source if opaque, change */
 	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	    const cairo_surface_pattern_t *surfpattern =
 		reinterpret_cast<const cairo_surface_pattern_t*>(source);
 	    if (surfpattern->surface->content == CAIRO_CONTENT_COLOR) {
 		return CAIRO_OPERATOR_OVER;
@@ -2650,17 +2650,17 @@ static cairo_int_status_t
     _cairo_d2d_flush(dst);
     ID3D10Resource *srcResource = src->surface;
     if (src->surface.get() == dst->surface.get()) {
 	// Self-copy
 	srcResource = _cairo_d2d_get_buffer_texture(dst);
 	src->device->mD3D10Device->CopyResource(srcResource, src->surface);
     } else {
 	// Need to flush the source too if it's a different surface.
-        _cairo_d2d_flush(src);
+	_cairo_d2d_flush(src);
     }
 
     // One copy for each rectangle in the final clipping region.
     for (int i = 0; i < cairo_region_num_rectangles(region); i++) {
 	D3D10_BOX rect;
 	cairo_rectangle_int_t area_to_copy;
 
 	cairo_region_get_rectangle(region, i, &area_to_copy);
@@ -2700,17 +2700,17 @@ static cairo_int_status_t
 }
 
 static cairo_int_status_t
 _cairo_d2d_blend_surface(cairo_d2d_surface_t *dst,
 			 cairo_d2d_surface_t *src,
 		 	 const cairo_matrix_t *transform,
 			 cairo_box_t *box,
 			 cairo_clip_t *clip,
-                         cairo_filter_t filter,
+			 cairo_filter_t filter,
 			 float opacity)
 {
     if (dst == src) {
 	// We cannot do self-blend.
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
     cairo_int_status_t rv = CAIRO_INT_STATUS_SUCCESS;
 
@@ -2799,22 +2799,22 @@ static cairo_int_status_t
     return rv;
 }
 /**
  * This function will text if we can use GPU mem cpy to execute an operation with
  * a surface pattern. If box is NULL it will operate on the entire dst surface.
  */
 static cairo_int_status_t
 _cairo_d2d_try_fastblit(cairo_d2d_surface_t *dst,
-		        cairo_surface_t *src,
-		        cairo_box_t *box,
-		        const cairo_matrix_t *matrix,
-		        cairo_clip_t *clip,
-		        cairo_operator_t op,
-                        cairo_filter_t filter,
+			cairo_surface_t *src,
+			cairo_box_t *box,
+			const cairo_matrix_t *matrix,
+			cairo_clip_t *clip,
+			cairo_operator_t op,
+			cairo_filter_t filter,
 			float opacity = 1.0f)
 {
     if (op == CAIRO_OPERATOR_OVER && src->content == CAIRO_CONTENT_COLOR) {
 	op = CAIRO_OPERATOR_SOURCE;
     }
     if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3097,18 +3097,18 @@ static cairo_int_status_t
 	return _cairo_d2d_clear(d2dsurf, clip);
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	const cairo_surface_pattern_t *surf_pattern = 
 	    reinterpret_cast<const cairo_surface_pattern_t*>(source);
 
 	status = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
-				         NULL, &source->matrix, clip,
-                                         op, source->filter);
+					 NULL, &source->matrix, clip,
+					 op, source->filter);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	    return status;
 	}
     }
     RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
 #ifndef ALWAYS_MANUAL_COMPOSITE
     if (op != CAIRO_OPERATOR_OVER) {
@@ -3225,17 +3225,17 @@ static cairo_int_status_t
 	    const cairo_surface_pattern_t *surf_pattern = 
 		reinterpret_cast<const cairo_surface_pattern_t*>(source);
 	    cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf,
 							    surf_pattern->surface,
 							    &box,
 							    &source->matrix,
 							    clip,
 							    op,
-                                                            source->filter,
+							    source->filter,
 							    solidAlphaValue);
 	    if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
 		return rv;
 	    }
 	}
     }
 
     RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source);
@@ -3427,18 +3427,18 @@ static cairo_int_status_t
     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
     cairo_box_t box;
     bool is_box = _cairo_path_fixed_is_box(path, &box);
 
     if (is_box && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	const cairo_surface_pattern_t *surf_pattern = 
 	    reinterpret_cast<const cairo_surface_pattern_t*>(source);
 	cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
-						        &box, &source->matrix, clip, op,
-                                                        source->filter);
+							&box, &source->matrix, clip, op,
+							source->filter);
 
 	if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
 	    return rv;
 	}
     }
 
     op = _cairo_d2d_simplify_operator(op, source);
 
@@ -3578,33 +3578,46 @@ cairo_int_status_t
 						      &renderMode);
 	if (FAILED(hr)) {
 	    // this probably never happens, but let's play it safe
 	    renderMode = DWRITE_RENDERING_MODE_DEFAULT;
 	}
     }
 
     // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept.
-    if (renderMode == DWRITE_RENDERING_MODE_DEFAULT) {
+    switch (renderMode) {
+    case DWRITE_RENDERING_MODE_ALIASED:
+	// ClearType texture creation will fail in this mode, so bail out
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    case DWRITE_RENDERING_MODE_DEFAULT:
 	// As per DWRITE_RENDERING_MODE documentation, pick Natural for font
 	// sizes under 16 ppem
 	if (scaled_font->base.font_matrix.yy < 16.0f) {
 	    renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
 	} else {
 	    renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
 	}
-    } else if (renderMode == DWRITE_RENDERING_MODE_OUTLINE) {
+	break;
+    case DWRITE_RENDERING_MODE_OUTLINE:
 	renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+	break;
+    default:
+	break;
     }
 
+    DWRITE_MEASURING_MODE measureMode =
+	renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
+	renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
+	DWRITE_MEASURING_MODE_NATURAL;
+
     hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
 						      1.0f,
 						      transform ? &dwmat : 0,
 						      renderMode,
-						      DWRITE_MEASURING_MODE_NATURAL,
+						      measureMode,
 						      0,
 						      0,
 						      &analysis);
     delete [] run.glyphIndices;
     delete [] run.glyphAdvances;
     delete [] run.glyphOffsets;
     if (FAILED(hr)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -3794,17 +3807,17 @@ cairo_int_status_t
 
     ID3D10EffectTechnique *technique = effect->GetTechniqueByName("SampleTextTexture");
 
     ID3D10EffectVectorVariable *quadDesc = effect->GetVariableByName("QuadDesc")->AsVector();
     ID3D10EffectVectorVariable *texCoords = effect->GetVariableByName("TexCoords")->AsVector();
     ID3D10EffectVectorVariable *textColor = effect->GetVariableByName("TextColor")->AsVector();
 
     float colorVal[] = { float(source->color.red   * source->color.alpha),
-	                 float(source->color.green * source->color.alpha),
+			 float(source->color.green * source->color.alpha),
 			 float(source->color.blue  * source->color.alpha),
 			 float(source->color.alpha) };
     textColor->SetFloatVector(colorVal);
 
     float quadDescVal[4];
     float texCoordsVal[4];
 
     // Draw a quad for each rectangle in the intersection of the clip and the
@@ -3914,28 +3927,72 @@ static cairo_int_status_t
 
     D2D1_TEXT_ANTIALIAS_MODE cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
 
     // If we're rendering to a temporary surface we cannot do sub-pixel AA.
     if (dst->base.content != CAIRO_CONTENT_COLOR || dst->rt.get() != target_rt.get()) {
 	cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
     }
 
+    RefPtr<IDWriteRenderingParams> params;
+    target_rt->GetTextRenderingParams(&params);
+
+    DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
+    if (params) {
+	HRESULT hr = dwriteff->dwriteface->GetRecommendedRenderingMode(
+						      (FLOAT)dwritesf->base.font_matrix.yy,
+						      1.0f,
+						      DWRITE_MEASURING_MODE_NATURAL,
+						      params,
+						      &renderMode);
+	if (FAILED(hr)) {
+	    // this probably never happens, but let's play it safe
+	    renderMode = DWRITE_RENDERING_MODE_DEFAULT;
+	}
+    }
+
+    // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept
+    switch (renderMode) {
+    case DWRITE_RENDERING_MODE_DEFAULT:
+	// As per DWRITE_RENDERING_MODE documentation, pick Natural for font
+	// sizes under 16 ppem
+  	if (dwritesf->base.font_matrix.yy < 16.0f) {
+	    renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
+	} else {
+	    renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+	}
+	break;
+    case DWRITE_RENDERING_MODE_OUTLINE:
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    default:
+	break;
+    }
+
     switch (dwritesf->antialias_mode) {
-	case CAIRO_ANTIALIAS_NONE:
-	    target_rt->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
-	    break;
-	case CAIRO_ANTIALIAS_GRAY:
-	    target_rt->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
-	    break;
-	case CAIRO_ANTIALIAS_SUBPIXEL:
-	    target_rt->SetTextAntialiasMode(cleartype_quality);
-	    break;
+    case CAIRO_ANTIALIAS_NONE:
+	cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+	break;
+    case CAIRO_ANTIALIAS_GRAY:
+	cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+	break;
+    case CAIRO_ANTIALIAS_SUBPIXEL:
+	break;
     }
 
+    if (renderMode == DWRITE_RENDERING_MODE_ALIASED) {
+	cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+    }
+
+    target_rt->SetTextAntialiasMode(cleartype_quality);
+
+    DWRITE_MEASURING_MODE measureMode =
+	renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
+	renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
+	DWRITE_MEASURING_MODE_NATURAL;
+
     cairo_bool_t transform = FALSE;
 
     DWRITE_GLYPH_RUN run;
     
     _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
 
     D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(&dwritesf->mat);
 	
@@ -3944,18 +4001,18 @@ static cairo_int_status_t
     }
 
     if (dst->rt.get() != target_rt.get()) {
 	RefPtr<IDWriteGlyphRunAnalysis> analysis;
 	DWRITE_MATRIX dwmat = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);
 	DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
 							  1.0f,
 							  transform ? &dwmat : 0,
-							  DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
-							  DWRITE_MEASURING_MODE_NATURAL,
+							  renderMode,
+							  measureMode,
 							  0,
 							  0,
 							  &analysis);
 
 	RECT bounds;
 	analysis->GetAlphaTextureBounds(scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE ?
 					DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1,
 					&bounds);
@@ -3982,17 +4039,17 @@ static cairo_int_status_t
 	// The brush matrix needs to be multiplied with the inverted matrix
 	// as well, to move the brush into the space of the glyphs. Before
 	// the render target transformation.
 	brush->GetTransform(&mat_brush);
 	mat_brush = mat_brush * mat_inverse;
 	brush->SetTransform(&mat_brush);
     }
     
-    target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, dwritesf->measuring_mode);
+    target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, measureMode);
     
     if (transform) {
 	target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
     }
 
     delete [] run.glyphIndices;
     delete [] run.glyphOffsets;
     delete [] run.glyphAdvances;
@@ -4014,24 +4071,23 @@ static cairo_int_status_t
 			cairo_clip_t            *clip,
 			int			*remaining_glyphs)
 {
     if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
     if (!d2dsurf->textRenderingInit) {
-	RefPtr<IDWriteRenderingParams> params;
-	DWriteFactory::Instance()->CreateRenderingParams(&params);
+	RefPtr<IDWriteRenderingParams> params = DWriteFactory::RenderingParams();
 	d2dsurf->rt->SetTextRenderingParams(params);
 	d2dsurf->textRenderingInit = true;
     }
     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
-        status = (cairo_int_status_t)
+	status = (cairo_int_status_t)
 	    _cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
     }
 
     return status;
 }
 
 
 static cairo_bool_t
@@ -4126,17 +4182,17 @@ cairo_d2d_surface_create_for_hwnd(cairo_
      */
     dxgiFactory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
 
     if (FAILED(hr)) {
 	goto FAIL_HWND;
     }
     /** Get the backbuffer surface from the swap chain */
     hr = newSurf->dxgiChain->GetBuffer(0,
-	                               IID_PPV_ARGS(&newSurf->surface));
+				       IID_PPV_ARGS(&newSurf->surface));
 
     if (FAILED(hr)) {
 	goto FAIL_HWND;
     }
 
     newSurf->surface->QueryInterface(&newSurf->backBuf);
 
     size.width = sizePixels.width * dpiX;
@@ -4171,18 +4227,18 @@ FAIL_HWND:
     newSurf->~cairo_d2d_surface_t();
     free(newSurf);
     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
 }
 
 cairo_surface_t *
 cairo_d2d_surface_create(cairo_device_t *device,
 			 cairo_format_t format,
-                         int width,
-                         int height)
+			 int width,
+			 int height)
 {
     if (width == 0 || height == 0) {
 	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE));
     }
 
     cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
     cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
     new (newSurf) cairo_d2d_surface_t();
@@ -4469,17 +4525,17 @@ FAIL_CREATE:
     newSurf->~cairo_d2d_surface_t();
     free(newSurf);
     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
 }
 
 void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip)
 {
     if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
-        return;
+	return;
     }
     cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
 
     /** For now, we invalidate our storing texture with this operation. */
     D2D1_POINT_2U point;
     D3D10_BOX rect;
     rect.front = 0;
     rect.back = 1;
@@ -4532,17 +4588,17 @@ void cairo_d2d_scroll(cairo_surface_t *s
 						  &rect);
 
 }
 
 HDC
 cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents)
 {
     if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
-        return NULL;
+	return NULL;
     }
     cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
 
     /* We'll pop the clip here manually so that we'll stay in drawing state if we
      * already are, we need to ensure d2dsurf->isDrawing manually then though 
      */
 
     /* Clips aren't allowed as per MSDN docs */
@@ -4573,17 +4629,17 @@ cairo_d2d_get_dc(cairo_surface_t *surfac
 
     return dc;
 }
 
 void
 cairo_d2d_release_dc(cairo_surface_t *surface, const cairo_rectangle_int_t *updated_rect)
 {
     if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
-        return;
+	return;
     }
     cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
 
     RefPtr<ID2D1GdiInteropRenderTarget> interopRT;
 
     d2dsurf->rt->QueryInterface(&interopRT);
 
     if (!updated_rect) {
--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
@@ -114,16 +114,23 @@ public:
 
 private:
     static ID2D1Factory *mFactoryInstance;
     static ID2D1DCRenderTarget *mRenderTarget;
 };
 
 IDWriteFactory *DWriteFactory::mFactoryInstance = NULL;
 IDWriteFontCollection *DWriteFactory::mSystemCollection = NULL;
+IDWriteRenderingParams *DWriteFactory::mRenderingParams = NULL;
+FLOAT DWriteFactory::mGamma = -1.0;
+FLOAT DWriteFactory::mEnhancedContrast = -1.0;
+FLOAT DWriteFactory::mClearTypeLevel = -1.0;
+int DWriteFactory::mPixelGeometry = -1;
+int DWriteFactory::mRenderingMode = -1;
+
 ID2D1Factory *D2DFactory::mFactoryInstance = NULL;
 ID2D1DCRenderTarget *D2DFactory::mRenderTarget = NULL;
 
 /* Functions cairo_font_face_backend_t */
 static cairo_status_t
 _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
 					cairo_font_face_t      **font_face);
 static void
@@ -293,17 +300,16 @@ static cairo_status_t
 	break;
     }
 
     cairo_dwrite_font_face_t *face = (cairo_dwrite_font_face_t*)malloc(sizeof(cairo_dwrite_font_face_t));
     HRESULT hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &face->font);
     if (SUCCEEDED(hr)) {
 	// Cannot use C++ style new since cairo deallocates this.
 	*font_face = (cairo_font_face_t*)face;
-        
 	_cairo_font_face_init (&(*(_cairo_dwrite_font_face**)font_face)->base, &_cairo_dwrite_font_face_backend);
     } else {
 	free(face);
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -344,17 +350,17 @@ void
     run->glyphIndices = indices;
     run->glyphOffsets = offsets;
     run->glyphAdvances = advances;
 
     if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 &&
 	scaled_font->mat.xx == scaled_font->base.font_matrix.xx && 
 	scaled_font->mat.yy == scaled_font->base.font_matrix.yy) {
 	// Fast route, don't actually use a transform but just
-        // set the correct font size.
+	// set the correct font size.
 	*transformed = 0;
 
 	run->fontEmSize = (FLOAT)scaled_font->base.font_matrix.yy;
 
 	for (int i = 0; i < num_glyphs; i++) {
 	    indices[i] = (WORD) glyphs[i].index;
 
 	    offsets[i].ascenderOffset = -(FLOAT)(glyphs[i].y);
@@ -366,24 +372,24 @@ void
 
 	for (int i = 0; i < num_glyphs; i++) {
 	    indices[i] = (WORD) glyphs[i].index;
 	    double x = glyphs[i].x;
 	    double y = glyphs[i].y;
 	    cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
 	    // Since we will multiply by our ctm matrix later for rotation effects
 	    // and such, adjust positions by the inverse matrix now. Y-axis is
-            // inverted! Therefor the offset is -y.
+	    // inverted! Therefor the offset is -y.
 	    offsets[i].ascenderOffset = -(FLOAT)y;
 	    offsets[i].advanceOffset = (FLOAT)x;
 	    advances[i] = 0.0;
 	}
 	// The font matrix takes care of the scaling if we have a transform,
 	// emSize should be 1.
-        run->fontEmSize = 1.0f;
+	run->fontEmSize = 1.0f;
     }
 }
 
 #define GASP_TAG 0x70736167
 #define GASP_DOGRAY 0x2
 
 static cairo_bool_t
 do_grayscale(IDWriteFontFace *dwface, unsigned int ppem)
@@ -710,32 +716,32 @@ cairo_int_status_t
     font_face->dwriteface->GetMetrics(&fontMetrics);
     HRESULT hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
     if (FAILED(hr)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     // TODO: Treat swap_xy.
     extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) /
-        fontMetrics.designUnitsPerEm;
+	fontMetrics.designUnitsPerEm;
     extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) /
-        fontMetrics.designUnitsPerEm;
+	fontMetrics.designUnitsPerEm;
     extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
     extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
     extents.y_advance = 0.0;
     extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) /
-        fontMetrics.designUnitsPerEm;
+	fontMetrics.designUnitsPerEm;
 
     // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
     // for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
     // and therefore it does not always cover all pixels that will actually be touched.
     if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
-        extents.width > 0 && extents.height > 0) {
-        extents.width += scaled_font->mat_inverse.xx * 2;
-        extents.x_bearing -= scaled_font->mat_inverse.xx;
+	extents.width > 0 && extents.height > 0) {
+	extents.width += scaled_font->mat_inverse.xx * 2;
+	extents.x_bearing -= scaled_font->mat_inverse.xx;
     }
 
     _cairo_scaled_glyph_set_metrics (scaled_glyph,
 				     &scaled_font->base,
 				     &extents);
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
@@ -748,32 +754,32 @@ class GeometryRecorder : public IDWriteG
 {
 public:
     GeometryRecorder(cairo_path_fixed_t *aCairoPath) 
 	: mCairoPath(aCairoPath) {}
 
     // IUnknown interface
     IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
     {
-        if (iid != __uuidof(IDWriteGeometrySink))
-            return E_NOINTERFACE;
+	if (iid != __uuidof(IDWriteGeometrySink))
+	    return E_NOINTERFACE;
 
 	*ppObject = static_cast<IDWriteGeometrySink*>(this);
 
-        return S_OK;
+	return S_OK;
     }
 
     IFACEMETHOD_(ULONG, AddRef)()
     {
-        return 1;
+	return 1;
     }
 
     IFACEMETHOD_(ULONG, Release)()
     {
-        return 1;
+	return 1;
     }
 
     IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
     {
 	return;
     }
 
     STDMETHODIMP Close()
@@ -817,48 +823,48 @@ public:
 	    cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
 							      GetFixedX(mStartPoint), 
 							      GetFixedY(mStartPoint));
 	}
     }
 
     IFACEMETHODIMP_(void) AddBeziers(
 	const D2D1_BEZIER_SEGMENT *beziers,
-        UINT beziersCount)
+	UINT beziersCount)
     {
 	for (unsigned int i = 0; i < beziersCount; i++) {
 	    cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
 							       GetFixedX(beziers[i].point1),
 							       GetFixedY(beziers[i].point1),
 							       GetFixedX(beziers[i].point2),
 							       GetFixedY(beziers[i].point2),
 							       GetFixedX(beziers[i].point3),
 							       GetFixedY(beziers[i].point3));
 	}	
     }
 
     IFACEMETHODIMP_(void) AddLines(
 	const D2D1_POINT_2F *points,
-        UINT pointsCount)
+	UINT pointsCount)
     {
 	for (unsigned int i = 0; i < pointsCount; i++) {
 	    cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath, 
 		GetFixedX(points[i]), 
 		GetFixedY(points[i]));
 	}
     }
 
 private:
     cairo_path_fixed_t *mCairoPath;
     D2D1_POINT_2F mStartPoint;
 };
 
 cairo_int_status_t 
 _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_font, 
-				          cairo_scaled_glyph_t *scaled_glyph)
+					  cairo_scaled_glyph_t *scaled_glyph)
 {
     cairo_path_fixed_t *path;
     path = _cairo_path_fixed_create();
     GeometryRecorder recorder(path);
 
     DWRITE_GLYPH_OFFSET offset;
     offset.advanceOffset = 0;
     offset.ascenderOffset = 0;
@@ -994,27 +1000,27 @@ cairo_int_status_t
 
     image = _compute_a8_mask (surface);
     status = (cairo_int_status_t)image->status;
     if (status)
 	goto FAIL;
 
     cairo_surface_set_device_offset (image, -x1, -y1);
     _cairo_scaled_glyph_set_surface (scaled_glyph,
-                                     &scaled_font->base,
-                                     (cairo_image_surface_t *) image);
+				     &scaled_font->base,
+				     (cairo_image_surface_t *) image);
 
   FAIL:
     cairo_surface_destroy (&surface->base);
 
     return status;
 }
 
 cairo_int_status_t
-_cairo_dwrite_load_truetype_table(void		   *scaled_font,
+_cairo_dwrite_load_truetype_table(void                 *scaled_font,
 				  unsigned long         tag,
 				  long                  offset,
 				  unsigned char        *buffer,
 				  unsigned long        *length)
 {
     cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
     cairo_dwrite_font_face_t *face = reinterpret_cast<cairo_dwrite_font_face_t*>(dwritesf->base.font_face);
 
@@ -1065,29 +1071,35 @@ cairo_dwrite_font_face_create_for_dwrite
 
 void
 cairo_dwrite_scaled_font_allow_manual_show_glyphs(void* dwrite_scaled_font, cairo_bool_t allowed)
 {
     cairo_dwrite_scaled_font_t *font = static_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
     font->manual_show_glyphs_allowed = allowed;
 }
 
+void
+cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
+				  int geometry, int mode)
+{
+    DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
+}
+
 cairo_int_status_t
 _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
 				       DWRITE_MATRIX *transform,
 				       DWRITE_GLYPH_RUN *run,
 				       COLORREF color,
 				       const RECT &area)
 {
     IDWriteGdiInterop *gdiInterop;
     DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
     IDWriteBitmapRenderTarget *rt;
 
-    IDWriteRenderingParams *params;
-    DWriteFactory::Instance()->CreateRenderingParams(&params);
+    IDWriteRenderingParams *params = DWriteFactory::RenderingParams();
 
     gdiInterop->CreateBitmapRenderTarget(surface->dc, 
 					 area.right - area.left, 
 					 area.bottom - area.top, 
 					 &rt);
 
     /**
      * We set the number of pixels per DIP to 1.0. This is because we always want
@@ -1299,30 +1311,30 @@ cairo_int_status_t
 	for (int i = 0; i < num_glyphs; i++) {
 	    indices[i] = (WORD) glyphs[i].index;
 	    // Since we will multiply by our ctm matrix later for rotation effects
 	    // and such, adjust positions by the inverse matrix now.
 	    offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y);
 	    offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
 	    advances[i] = 0.0;
 	}
-        run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
+	run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
     } else {
 	transform = TRUE;
 
 	for (int i = 0; i < num_glyphs; i++) {
 	    indices[i] = (WORD) glyphs[i].index;
 	    double x = glyphs[i].x - fontArea.left;
 	    double y = glyphs[i].y - fontArea.top;
 	    cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
 	    /**
-             * Since we will multiply by our ctm matrix later for rotation effects
+	     * Since we will multiply by our ctm matrix later for rotation effects
 	     * and such, adjust positions by the inverse matrix now. The Y-axis
-             * is inverted so the offset becomes negative.
-             */
+	     * is inverted so the offset becomes negative.
+	     */
 	    offsets[i].ascenderOffset = -(FLOAT)y;
 	    offsets[i].advanceOffset = (FLOAT)x;
 	    advances[i] = 0.0;
 	}
 	run.fontEmSize = 1.0f;
     }
     
     cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
@@ -1365,16 +1377,59 @@ cairo_int_status_t
 
     delete [] indices;
     delete [] offsets;
     delete [] advances;
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
+#define ENHANCED_CONTRAST_REGISTRY_KEY \
+    HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
+
+void
+DWriteFactory::CreateRenderingParams()
+{
+    if (!Instance()) {
+	return;
+    }
+
+    RefPtr<IDWriteRenderingParams> defaultParams;
+    Instance()->CreateRenderingParams(&defaultParams);
+
+    // For EnhancedContrast, we override the default if the user has not set it
+    // in the registry (by using the ClearType Tuner).
+    FLOAT contrast;
+    if (mEnhancedContrast >= 0.0 && mEnhancedContrast <= 10.0) {
+	contrast = mEnhancedContrast;
+    } else {
+	HKEY hKey;
+	if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
+			  0, KEY_READ, &hKey) == ERROR_SUCCESS)
+	{
+	    contrast = defaultParams->GetEnhancedContrast();
+	    RegCloseKey(hKey);
+	} else {
+	    contrast = 1.0;
+	}
+    }
+
+    // For parameters that have not been explicitly set via the SetRenderingParams API,
+    // we copy values from default params (or our overridden value for contrast)
+    Instance()->CreateCustomRenderingParams(
+	mGamma >= 1.0 && mGamma <= 2.2 ? mGamma : defaultParams->GetGamma(),
+	contrast,
+	mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ? mClearTypeLevel : defaultParams->GetClearTypeLevel(),
+	mPixelGeometry >= DWRITE_PIXEL_GEOMETRY_FLAT && mPixelGeometry <= DWRITE_PIXEL_GEOMETRY_BGR ?
+	    (DWRITE_PIXEL_GEOMETRY)mPixelGeometry : defaultParams->GetPixelGeometry(),
+	mRenderingMode >= DWRITE_RENDERING_MODE_DEFAULT && mRenderingMode <= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ?
+	    (DWRITE_RENDERING_MODE)mRenderingMode : defaultParams->GetRenderingMode(), 
+	&mRenderingParams);
+}
+
 // Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
 // of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
 // paths or blitting glyph bitmaps.
 cairo_int_status_t
 _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font,
                                                     cairo_scaled_font_t **new_font)
 {
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) {
--- a/gfx/cairo/cairo/src/cairo-dwrite-private.h
+++ b/gfx/cairo/cairo/src/cairo-dwrite-private.h
@@ -87,19 +87,56 @@ public:
 	    return NULL;
 	}
 
 	IDWriteFontFamily *family;
 	SystemCollection()->GetFontFamily(idx, &family);
 	return family;
     }
 
+    static IDWriteRenderingParams *RenderingParams()
+    {
+	if (!mRenderingParams) {
+	    CreateRenderingParams();
+	}
+	if (mRenderingParams) {
+	    mRenderingParams->AddRef();
+	}
+	return mRenderingParams;
+    }
+
+    static void SetRenderingParams(FLOAT aGamma,
+				   FLOAT aEnhancedContrast,
+				   FLOAT aClearTypeLevel,
+				   int aPixelGeometry,
+				   int aRenderingMode)
+    {
+	mGamma = aGamma;
+	mEnhancedContrast = aEnhancedContrast;
+	mClearTypeLevel = aClearTypeLevel;
+        mPixelGeometry = aPixelGeometry;
+        mRenderingMode = aRenderingMode;
+	// discard any current RenderingParams object
+	if (mRenderingParams) {
+	    mRenderingParams->Release();
+	    mRenderingParams = NULL;
+	}
+    }
+
 private:
+    static void CreateRenderingParams();
+
     static IDWriteFactory *mFactoryInstance;
     static IDWriteFontCollection *mSystemCollection;
+    static IDWriteRenderingParams *mRenderingParams;
+    static FLOAT mGamma;
+    static FLOAT mEnhancedContrast;
+    static FLOAT mClearTypeLevel;
+    static int mPixelGeometry;
+    static int mRenderingMode;
 };
 
 /* cairo_font_face_t implementation */
 struct _cairo_dwrite_font_face {
     cairo_font_face_t base;
     IDWriteFont *font;
     IDWriteFontFace *dwriteface;
 };
--- a/gfx/cairo/cairo/src/cairo-win32.h
+++ b/gfx/cairo/cairo/src/cairo-win32.h
@@ -121,16 +121,19 @@ cairo_win32_scaled_font_get_device_to_lo
  * Win32 DirectWrite font support
  */
 cairo_public cairo_font_face_t *
 cairo_dwrite_font_face_create_for_dwrite_fontface(void *dwrite_font, void *dwrite_font_face);
 
 void
 cairo_dwrite_scaled_font_allow_manual_show_glyphs(void *dwrite_scaled_font, cairo_bool_t allowed);
 
+void
+cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level, int geometry, int mode);
+
 #endif /* CAIRO_HAS_DWRITE_FONT */
 
 #if CAIRO_HAS_D2D_SURFACE
 
 struct _cairo_device
 {
     int type;
     int refcount;
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -144,17 +144,20 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr
 
     rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
 
     if (NS_FAILED(rv)) {
         mIsValid = PR_FALSE;
         return;
     }
 
-    if ((anAAOption == gfxFont::kAntialiasDefault && UsingClearType()) ||
+    if ((anAAOption == gfxFont::kAntialiasDefault &&
+         UsingClearType() &&
+         (gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
+          DWRITE_MEASURING_MODE_NATURAL)) ||
         anAAOption == gfxFont::kAntialiasSubpixel)
     {
         mUseSubpixelPositions = PR_TRUE;
         // note that this may be reset to FALSE if we determine that a bitmap
         // strike is going to be used
     }
 
     ComputeMetrics();
@@ -243,26 +246,22 @@ gfxDWriteFont::ComputeMetrics()
         // This option will be passed to the cairo_dwrite_scaled_font_t
         // after creation.
         mAllowManualShowGlyphs = PR_FALSE;
     }
 
     mMetrics = new gfxFont::Metrics;
     ::memset(mMetrics, 0, sizeof(*mMetrics));
 
-    mMetrics->xHeight =
-        ((gfxFloat)fontMetrics.xHeight /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
+    mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
 
-    mMetrics->maxAscent = 
-        ceil(((gfxFloat)fontMetrics.ascent /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize);
-    mMetrics->maxDescent = 
-        ceil(((gfxFloat)fontMetrics.descent /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize);
+    mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
+
+    mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor);
+    mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor);
     mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
 
     mMetrics->emHeight = mAdjustedSize;
     mMetrics->emAscent = mMetrics->emHeight *
         mMetrics->maxAscent / mMetrics->maxHeight;
     mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
 
     mMetrics->maxAdvance = mAdjustedSize;
@@ -277,98 +276,82 @@ gfxDWriteFont::ComputeMetrics()
                                    (const void**)&tableData,
                                    &len,
                                    &tableContext,
                                    &exists);
     if (SUCCEEDED(hr)) {
         if (exists && len >= sizeof(mozilla::HheaTable)) {
             const mozilla::HheaTable* hhea =
                 reinterpret_cast<const mozilla::HheaTable*>(tableData);
-            mMetrics->maxAdvance = ((gfxFloat)PRUint16(hhea->advanceWidthMax) /
-                       fontMetrics.designUnitsPerEm) * mAdjustedSize;
+            mMetrics->maxAdvance =
+                PRUint16(hhea->advanceWidthMax) * mFUnitsConvFactor;
         }
         mFontFace->ReleaseFontTable(tableContext);
     }
 
     mMetrics->internalLeading = NS_MAX(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
-    mMetrics->externalLeading = 
-        ceil(((gfxFloat)fontMetrics.lineGap /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize);
+    mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
 
     UINT16 glyph = (PRUint16)GetSpaceGlyph();
-    DWRITE_GLYPH_METRICS metrics;
-    mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics);
-    mMetrics->spaceWidth = 
-        ((gfxFloat)metrics.advanceWidth /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
+    mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
 
     // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
-    // if the table is not available
-    mMetrics->aveCharWidth = 0;
-    hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
-                                    (const void**)&tableData,
-                                    &len,
-                                    &tableContext,
-                                    &exists);
-    if (SUCCEEDED(hr)) {
-        if (exists && len >= 4) {
-            // Not checking against sizeof(mozilla::OS2Table) here because older
-            // versions of the table have different sizes; we only need the first
-            // two 16-bit fields here.
-            const mozilla::OS2Table* os2 =
-                reinterpret_cast<const mozilla::OS2Table*>(tableData);
-            mMetrics->aveCharWidth = ((gfxFloat)PRInt16(os2->xAvgCharWidth) /
-                       fontMetrics.designUnitsPerEm) * mAdjustedSize;
+    // if the table is not available or if using hinted/pixel-snapped widths
+    if (mUseSubpixelPositions) {
+        mMetrics->aveCharWidth = 0;
+        hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
+                                        (const void**)&tableData,
+                                        &len,
+                                        &tableContext,
+                                        &exists);
+        if (SUCCEEDED(hr)) {
+            if (exists && len >= 4) {
+                // Not checking against sizeof(mozilla::OS2Table) here because older
+                // versions of the table have different sizes; we only need the first
+                // two 16-bit fields here.
+                const mozilla::OS2Table* os2 =
+                    reinterpret_cast<const mozilla::OS2Table*>(tableData);
+                mMetrics->aveCharWidth =
+                    PRInt16(os2->xAvgCharWidth) * mFUnitsConvFactor;
+            }
+            mFontFace->ReleaseFontTable(tableContext);
         }
-        mFontFace->ReleaseFontTable(tableContext);
     }
 
     UINT32 ucs;
     if (mMetrics->aveCharWidth < 1) {
         ucs = L'x';
-        if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
-            SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {    
-            mMetrics->aveCharWidth = 
-                ((gfxFloat)metrics.advanceWidth /
-                           fontMetrics.designUnitsPerEm) * mAdjustedSize;
-        } else {
+        if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
+            mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
+        }
+        if (mMetrics->aveCharWidth < 1) {
             // Let's just assume the X is square.
-            mMetrics->aveCharWidth = 
-                ((gfxFloat)fontMetrics.xHeight /
-                           fontMetrics.designUnitsPerEm) * mAdjustedSize;
+            mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
         }
     }
 
     ucs = L'0';
-    if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
-        SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {
-        mMetrics->zeroOrAveCharWidth = 
-            ((gfxFloat)metrics.advanceWidth /
-                       fontMetrics.designUnitsPerEm) * mAdjustedSize;
-    } else {
+    if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
+        mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph);
+    }
+    if (mMetrics->zeroOrAveCharWidth < 1) {
         mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
     }
 
-    mMetrics->underlineOffset = 
-        ((gfxFloat)fontMetrics.underlinePosition /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
+    mMetrics->underlineOffset =
+        fontMetrics.underlinePosition * mFUnitsConvFactor;
     mMetrics->underlineSize = 
-        ((gfxFloat)fontMetrics.underlineThickness /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
-    mMetrics->strikeoutOffset = 
-        ((gfxFloat)fontMetrics.strikethroughPosition /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
-    mMetrics->strikeoutSize = 
-        ((gfxFloat)fontMetrics.strikethroughThickness /
-                   fontMetrics.designUnitsPerEm) * mAdjustedSize;
+        fontMetrics.underlineThickness * mFUnitsConvFactor;
+    mMetrics->strikeoutOffset =
+        fontMetrics.strikethroughPosition * mFUnitsConvFactor;
+    mMetrics->strikeoutSize =
+        fontMetrics.strikethroughThickness * mFUnitsConvFactor;
     mMetrics->superscriptOffset = 0;
     mMetrics->subscriptOffset = 0;
 
-    mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
-
     SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
 
 #if 0
     printf("Font: %p (%s) size: %f\n", this,
            NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
     printf("    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
     printf("    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
     printf("    internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
@@ -692,31 +675,35 @@ gfxDWriteFont::GetGlyphWidth(gfxContext 
         mGlyphWidths.Init(200);
     }
 
     PRInt32 width = -1;
     if (mGlyphWidths.Get(aGID, &width)) {
         return width;
     }
 
-    DWRITE_GLYPH_METRICS glyphMetrics;
+    width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0);
+    mGlyphWidths.Put(aGID, width);
+    return width;
+}
+
+gfxFloat
+gfxDWriteFont::MeasureGlyphWidth(PRUint16 aGlyph)
+{
+    DWRITE_GLYPH_METRICS metrics;
     HRESULT hr;
     if (mUseSubpixelPositions) {
-        hr = mFontFace->GetDesignGlyphMetrics(
-                  &aGID, 1, &glyphMetrics, FALSE);
+        hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE);
         if (SUCCEEDED(hr)) {
-            width =
-                NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor *
-                          65536.0);
+            return metrics.advanceWidth * mFUnitsConvFactor;
         }
     } else {
         hr = mFontFace->GetGdiCompatibleGlyphMetrics(
-                  FLOAT(mAdjustedSize), 1.0f, nsnull, FALSE,
-                  &aGID, 1, &glyphMetrics, FALSE);
+                  FLOAT(mAdjustedSize), 1.0f, nsnull,
+                  gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
+                      DWRITE_MEASURING_MODE_GDI_NATURAL,
+                  &aGlyph, 1, &metrics, FALSE);
         if (SUCCEEDED(hr)) {
-            width =
-                NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor) << 16;
+            return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
         }
     }
-
-    mGlyphWidths.Put(aGID, width);
-    return width;
+    return 0;
 }
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -93,16 +93,18 @@ protected:
     void ComputeMetrics();
 
     PRBool HasBitmapStrikeForSize(PRUint32 aSize);
 
     cairo_font_face_t *CairoFontFace();
 
     cairo_scaled_font_t *CairoScaledFont();
 
+    gfxFloat MeasureGlyphWidth(PRUint16 aGlyph);
+
     static void DestroyBlobFunc(void* userArg);
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
     cairo_scaled_font_t *mCairoScaledFont;
 
     gfxFont::Metrics          *mMetrics;
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2661,17 +2661,16 @@ gfxFontGroup::GetGeneration()
     if (!mUserFontSet)
         return 0;
     return mUserFontSet->GetGeneration();
 }
 
 void
 gfxFontGroup::UpdateFontList()
 {
-    // if user font set is set, check to see if font list needs updating
     if (mUserFontSet && mCurrGeneration != GetGeneration()) {
         // xxx - can probably improve this to detect when all fonts were found, so no need to update list
         mFonts.Clear();
         mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
         mSkipDrawing = PR_FALSE;
 
         // bug 548184 - need to clean up FT2, OS/2 platform code to use BuildFontList
 #if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(WINCE)) || defined(ANDROID)
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -53,16 +53,20 @@
 #include "harfbuzz/hb-unicode.h"
 #include "harfbuzz/hb-ot.h"
 
 #include "cairo.h"
 
 #include "nsUnicodeRange.h"
 #include "nsCRT.h"
 
+#if defined(XP_WIN)
+#include "gfxWindowsPlatform.h"
+#endif
+
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
 // Right shifts of negative (signed) integers are undefined, as are overflows
 // when converting unsigned to negative signed integers.
 // (If speed were an issue we could make some 2's complement assumptions.)
 #define FixedToIntRound(f) ((f) > 0 ?  ((32768 + (f)) >> 16) \
                                     : -((32767 - (f)) >> 16))
 
@@ -941,18 +945,22 @@ GetRoundOffsetsToPixels(gfxContext *aCon
         // surfaces have already been handled by hint_metrics.  The
         // fallback show_glyphs implementation composites pixel-aligned
         // glyph surfaces, so we just pick surface/font combinations that
         // override this.
         switch (cairo_scaled_font_get_type(scaled_font)) {
 #if CAIRO_HAS_DWRITE_FONT // dwrite backend is not in std cairo releases yet
         case CAIRO_FONT_TYPE_DWRITE:
             // show_glyphs is implemented on the font and so is used for
-            // all surface types.
-            return;
+            // all surface types; however, it may pixel-snap depending on
+            // the dwrite rendering mode
+            if (gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
+                DWRITE_MEASURING_MODE_NATURAL) {
+                return;
+            }
 #endif
         case CAIRO_FONT_TYPE_QUARTZ:
             // Quartz surfaces implement show_glyphs for Quartz fonts
             if (cairo_surface_get_type(cairo_get_target(cr)) ==
                 CAIRO_SURFACE_TYPE_QUARTZ) {
                 return;
             }
         default:
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -153,16 +153,23 @@ NS_IMPL_ISUPPORTS1(D2DVRAMReporter, nsIM
 
 #include "gfxUserFontSet.h"
 
 #include <string>
 
 #define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content"
 #define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts"
 
+#define GFX_CLEARTYPE_PARAMS           "gfx.font_rendering.cleartype_params."
+#define GFX_CLEARTYPE_PARAMS_GAMMA     "gfx.font_rendering.cleartype_params.gamma"
+#define GFX_CLEARTYPE_PARAMS_CONTRAST  "gfx.font_rendering.cleartype_params.enhanced_contrast"
+#define GFX_CLEARTYPE_PARAMS_LEVEL     "gfx.font_rendering.cleartype_params.cleartype_level"
+#define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure"
+#define GFX_CLEARTYPE_PARAMS_MODE      "gfx.font_rendering.cleartype_params.rendering_mode"
+
 #ifdef MOZ_FT2_FONTS
 static FT_Library gPlatformFTLibrary = NULL;
 #endif
 
 #ifdef CAIRO_HAS_DWRITE_FONT
 // DirectWrite is not available on all platforms, we need to use the function
 // pointer.
 typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
@@ -338,16 +345,18 @@ gfxWindowsPlatform::UpdateRenderMode()
             IDWriteFactory *factory;
             HRESULT hr = createDWriteFactory(
                 DWRITE_FACTORY_TYPE_SHARED,
                 __uuidof(IDWriteFactory),
                 reinterpret_cast<IUnknown**>(&factory));
             mDWriteFactory = factory;
             factory->Release();
 
+            SetupClearTypeParams(pref);
+
             if (hr == S_OK)
               reporter.SetSuccessful();
         }
     }
 #endif
 }
 
 void
@@ -785,26 +794,89 @@ gfxWindowsPlatform::FontsPrefsChanged(ns
 
     if (!aPref) {
         mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
         mUseClearTypeAlways = UNINITIALIZED_VALUE;
     } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) {
         mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) {
         mUseClearTypeAlways = UNINITIALIZED_VALUE;
+    } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
+        SetupClearTypeParams(aPrefBranch);
     } else {
         clearTextFontCaches = PR_FALSE;
     }
 
     if (clearTextFontCaches) {    
         gfxFontCache *fc = gfxFontCache::GetCache();
         if (fc) {
             fc->Flush();
         }
         gfxTextRunWordCache::Flush();
     }
 }
 
+void
+gfxWindowsPlatform::SetupClearTypeParams(nsIPrefBranch *aPrefBranch)
+{
+#if CAIRO_HAS_DWRITE_FONT
+    if (GetDWriteFactory()) {
+        // any missing prefs will default to invalid (-1) and be ignored;
+        // out-of-range values will also be ignored
+        FLOAT gamma = -1.0;
+        FLOAT contrast = -1.0;
+        FLOAT level = -1.0;
+        int geometry = -1;
+        int mode = -1;
+        PRInt32 value;
+        if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_GAMMA,
+                                                 &value))) {
+            if (value >= 1000 && value <= 2200) {
+                gamma = (FLOAT)value / 1000.0;
+            }
+        }
+        if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_CONTRAST,
+                                                 &value))) {
+            if (value >= 0 && value <= 1000) {
+                contrast = (FLOAT)value / 100.0;
+            }
+        }
+        if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_LEVEL,
+                                                 &value))) {
+            if (value >= 0 && value <= 100) {
+                level = (FLOAT)value / 100.0;
+            }
+        }
+        if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_STRUCTURE,
+                                                 &value))) {
+            if (value >= 0 && value <= 2) {
+                geometry = value;
+            }
+        }
+        if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_MODE,
+                                                 &value))) {
+            if (value >= 0 && value <= 5) {
+                mode = value;
+            }
+        }
+        cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode);
+
+        switch (mode) {
+        case DWRITE_RENDERING_MODE_ALIASED:
+        case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
+            mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
+            break;
+        case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
+            mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL;
+            break;
+        default:
+            mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
+            break;
+        }
+    }
+#endif
+}
+
 bool
 gfxWindowsPlatform::IsOptimus()
 {
   return GetModuleHandleA("nvumdshim.dll");
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -233,19 +233,22 @@ public:
     };
 
     static PRInt32 WindowsOSVersion(PRInt32 *aBuildNum = nsnull);
 
     static void GetDLLVersion(const PRUnichar *aDLLPath, nsAString& aVersion);
 
     virtual void FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aPref);
 
+    void SetupClearTypeParams(nsIPrefBranch *aPrefBranch);
+
 #ifdef CAIRO_HAS_DWRITE_FONT
     IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
     inline PRBool DWriteEnabled() { return mUseDirectWrite; }
+    inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
 #else
     inline PRBool DWriteEnabled() { return PR_FALSE; }
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nsnull; }
 #endif
 
@@ -265,16 +268,17 @@ protected:
 private:
     void Init();
 
     PRBool mUseDirectWrite;
     PRBool mUsingGDIFonts;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
+    DWRITE_MEASURING_MODE mMeasuringMode;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1748,16 +1748,49 @@ pref("font.mathfont-family", "STIXNonUni
 // cleartype settings - false implies default system settings 
 
 // use cleartype rendering for downloadable fonts (win xp only)
 pref("gfx.font_rendering.cleartype.use_for_downloadable_fonts", true);
 
 // use cleartype rendering for all fonts always (win xp only)
 pref("gfx.font_rendering.cleartype.always_use_for_content", false);
 
+// ClearType tuning parameters for directwrite/d2d.
+//
+// Allows overriding of underlying registry values in:
+//   HKCU/Software/Microsoft/Avalon.Graphics/<display> (contrast and level)
+//   HKLM/Software/Microsoft/Avalon.Graphics/<display> (gamma, pixel structure)
+// and selection of the ClearType/antialiasing mode.
+//
+// A value of -1 implies use the default value, otherwise value ranges 
+// follow registry settings:
+//   gamma [1000, 2200]  default: based on screen, typically 2200 (== 2.2)
+//   enhanced contrast [0, 1000] default: 50
+//   cleartype level [0, 100] default: 100
+//   pixel structure [0, 2] default: 0 (flat/RGB/BGR)
+//   rendering mode [0, 5] default: 0
+//     0 = use default for font & size;
+//     1 = aliased;
+//     2 = GDI Classic;
+//     3 = GDI Natural Widths;
+//     4 = Natural;
+//     5 = Natural Symmetric
+//
+// See:
+//   http://msdn.microsoft.com/en-us/library/aa970267.aspx
+//   http://msdn.microsoft.com/en-us/library/dd368190%28v=VS.85%29.aspx
+// Note: DirectWrite uses the "Enhanced Contrast Level" value rather than the 
+// "Text Contrast Level" value
+
+pref("gfx.font_rendering.cleartype_params.gamma", -1);
+pref("gfx.font_rendering.cleartype_params.enhanced_contrast", -1);
+pref("gfx.font_rendering.cleartype_params.cleartype_level", -1);
+pref("gfx.font_rendering.cleartype_params.pixel_structure", -1);
+pref("gfx.font_rendering.cleartype_params.rendering_mode", -1);
+
 pref("ui.key.menuAccessKeyFocuses", true);
 
 // override double-click word selection behavior.
 pref("layout.word_select.eat_space_to_next_word", true);
 
 // scrollbar snapping region
 pref("slider.snapMultiplier", 6);