commit 3779c70afe31b2e3580ed113c779901b206bbd4a Author: Brian Ewins Date: Thu Jan 4 05:24:37 2007 +0000 [ATSUI] correct use of device/user units throughout. Fixes text-pattern test. The code previously assumed that device units were the same as user units. diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c index b359b2e..49b44c8 100644 --- a/src/cairo-atsui-font.c +++ b/src/cairo-atsui-font.c @@ -79,6 +79,13 @@ struct _cairo_atsui_font { ATSUStyle style; ATSUStyle unscaled_style; ATSUFontID fontID; + + CGAffineTransform font_to_device; + CGAffineTransform font_to_device_scale; + CGAffineTransform device_to_font_scale; + CGAffineTransform device_to_user_scale; + CGAffineTransform quartz_font_to_cairo_device; + CGAffineTransform quartz_user_to_cairo_device; }; struct _cairo_atsui_font_face { @@ -204,17 +211,16 @@ CGAffineTransformMakeWithCairoScaleFactors(const cairo_matrix_t *scale) } static ATSUStyle -CreateSizedCopyOfStyle(ATSUStyle inStyle, const cairo_matrix_t *scale) +CreateSizedCopyOfStyle (ATSUStyle inStyle, const CGAffineTransform *theTransform) { ATSUStyle style; OSStatus err; /* Set the style's size */ Fixed theSize = FloatToFixed(1.0); - CGAffineTransform theTransform = CGAffineTransformMakeWithCairoScaleFactors(scale); const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, kATSUFontMatrixTag }; const ByteCount theFontStyleSizes[] = { sizeof(Fixed), sizeof(CGAffineTransform) }; - ATSUAttributeValuePtr theFontStyleValues[] = { &theSize, &theTransform }; + ATSUAttributeValuePtr theFontStyleValues[] = { &theSize, (CGAffineTransform *)theTransform }; err = ATSUCreateAndCopyStyle(inStyle, &style); @@ -278,7 +284,30 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, _cairo_scaled_font_init(&font->base, font_face, font_matrix, ctm, options, &cairo_atsui_scaled_font_backend); - font->style = CreateSizedCopyOfStyle(style, &font->base.scale); + font->font_to_device = CGAffineTransformMakeWithCairoFontScale (&font->base.scale); + font->device_to_user_scale = CGAffineTransformInvert (CGAffineTransformMakeWithCairoScaleFactors (ctm)); + font->font_to_device_scale = CGAffineTransformMakeWithCairoScaleFactors (&font->base.scale); + font->device_to_font_scale = CGAffineTransformInvert (font->font_to_device_scale); + + /* The xy and yx components are negated because the y-axis + * is flipped into the cairo system then flipped back, ie: + * [1 0][xx yx][1 0] + * [0 -1][xy yy][0 -1] + */ + font->quartz_font_to_cairo_device = + CGAffineTransformMake (font->base.scale.xx, + -font->base.scale.yx, + -font->base.scale.xy, + font->base.scale.yy, + 0., 0.); + font->quartz_user_to_cairo_device = + CGAffineTransformMake (font->base.ctm.xx, + -font->base.ctm.yx, + -font->base.ctm.xy, + font->base.ctm.yy, + 0., 0.); + + font->style = CreateSizedCopyOfStyle (style, &font->font_to_device_scale); { Fixed theSize = FloatToFixed(1.0); @@ -490,7 +519,7 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, static ATSCubicClosePathUPP closePathProc = NULL; CGMutablePathRef path; GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph); - double xscale, yscale; + CGPoint device_advance, font_advance; CGRect rect; /* We calculate the advance from the screen metrics. We @@ -502,15 +531,6 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, if (err != noErr) return CAIRO_INT_STATUS_UNSUPPORTED; - /* Scale down to font units.*/ - _cairo_matrix_compute_scale_factors (&scaled_font->base.scale, - &xscale, &yscale, 1); - xscale = 1.0/xscale; - yscale = 1.0/yscale; - - extents.x_advance = metricsH.deviceAdvance.x * xscale; - extents.y_advance = 0; - if (moveProc == NULL) { moveProc = NewATSCubicMoveToUPP (_move_to_for_metrics); lineProc = NewATSCubicLineToUPP (_line_to_for_metrics); @@ -536,13 +556,23 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, return CAIRO_INT_STATUS_UNSUPPORTED; } + /* The bounding box in device units */ rect = CGPathGetBoundingBox (path); - extents.x_bearing = rect.origin.x * xscale; - extents.y_bearing = rect.origin.y * yscale; - extents.width = rect.size.width * xscale; - extents.height = rect.size.height * yscale; + /* Scale down to font units.*/ + rect = CGRectApplyAffineTransform (rect, scaled_font->device_to_font_scale); + + device_advance = CGPointMake (metricsH.deviceAdvance.x, metricsH.deviceAdvance.y); + font_advance = CGPointApplyAffineTransform (device_advance, scaled_font->device_to_font_scale); + + extents.x_advance = font_advance.x; + extents.y_advance = 0; + extents.x_bearing = CGRectGetMinX (rect); + extents.y_bearing = CGRectGetMinY (rect); + extents.width = rect.size.width; + extents.height = rect.size.height; + _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); @@ -690,20 +720,11 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph); ATSGlyphScreenMetrics metricsH; - double left, bottom, width, height; - double xscale, yscale; + double left, bottom; CGRect bbox; - CGAffineTransform transform; - - /* Compute a box to contain the glyph mask. The vertical - * sizes come from the font extents; extra pixels are - * added to account for fractional sizes. - */ - height = extents.ascent + extents.descent + 2.0; - bottom = -extents.descent - 1.0; - - /* Horizontal sizes come from the glyph typographic metrics. + /* Compute a box to contain the glyph mask. + * Horizontal sizes come from the glyph typographic metrics. * It is possible that this might result in clipped text * in fonts where the typographic bounds don't cover the ink. * The width is recalculated, since metricsH.width is rounded. @@ -711,31 +732,21 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, err = ATSUGlyphGetScreenMetrics (scaled_font->style, 1, &theGlyph, 0, false, false, &metricsH); - left = metricsH.sideBearing.x - 1.0; - width = metricsH.deviceAdvance.x - - metricsH.sideBearing.x - + metricsH.otherSideBearing.x + 2.0; - /* The xy and yx components are negated because the y-axis - * is flipped into the cairo system then flipped back, ie: - * [1 0][xx yx][1 0] - * [0 -1][xy yy][0 -1] - */ - transform = CGAffineTransformMake (base.scale.xx, - -base.scale.yx, - -base.scale.xy, - base.scale.yy, - 0., 0.); - _cairo_matrix_compute_scale_factors (&base.scale, - &xscale, &yscale, 1); - transform = CGAffineTransformScale (transform, 1.0/xscale, 1.0/yscale); + bbox = CGRectMake (metricsH.sideBearing.x - 2.0, 1.0, + metricsH.deviceAdvance.x - metricsH.sideBearing.x + + metricsH.otherSideBearing.x + 4.0, 1.0); + bbox = CGRectApplyAffineTransform (bbox, scaled_font->device_to_user_scale); + /* vertical extents in user units. */ + bbox = CGRectMake (CGRectGetMinX (bbox), -extents.descent, bbox.size.width, extents.ascent + extents.descent); + /* Rotate the bounding box. This computes the smallest CGRect * that would contain the bounding box after rotation. */ - bbox = CGRectApplyAffineTransform (CGRectMake (left, bottom, - width, height), transform); - /* Compute the smallest CGRect with integer coordinates + bbox = CGRectApplyAffineTransform (bbox, scaled_font->quartz_user_to_cairo_device); + + /* Compute the smallest CGRect with integer coordinates * that contains the bounding box. */ bbox = CGRectIntegral (bbox); @@ -771,8 +782,8 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, CGContextSetFontSize (drawingContext, 1.0); CGContextTranslateCTM (drawingContext, -left, -bottom); - CGContextScaleCTM (drawingContext, xscale, yscale); - CGContextSetTextMatrix (drawingContext, transform); + CGContextSetTextMatrix (drawingContext, + scaled_font->quartz_font_to_cairo_device); CGContextShowGlyphsAtPoint (drawingContext, 0, 0, &theGlyph, 1); @@ -836,6 +847,7 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font, cairo_atsui_font_t *font = abstract_font; ItemCount glyphCount; int i; + CGPoint point; status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16); if (status) @@ -864,7 +876,11 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font, for (i = 0; i < *num_glyphs; i++) { (*glyphs)[i].index = layoutRecords[i].glyphID; - (*glyphs)[i].x = x + FixedToFloat(layoutRecords[i].realPos); + /* ATSLayoutRecord.realPos is in device units, convert to user units */ + point = CGPointMake (FixedToFloat (layoutRecords[i].realPos), 0); + point = CGPointApplyAffineTransform (point, font->device_to_user_scale); + + (*glyphs)[i].x = x + point.x; (*glyphs)[i].y = y; } @@ -944,7 +960,7 @@ _cairo_atsui_font_old_show_glyphs (void *abstract_font, CGContextSetShouldAntialias (drawingContext, false); } - textTransform = CGAffineTransformMakeWithCairoFontScale(&font->base.scale); + textTransform = font->font_to_device; textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f); CGContextSetFontSize(drawingContext, 1.0);