diff options
Diffstat (limited to 'src/cairo-atsui-font.c')
-rw-r--r-- | src/cairo-atsui-font.c | 1215 |
1 files changed, 549 insertions, 666 deletions
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c index cb4b1c5d7..a279956df 100644 --- a/src/cairo-atsui-font.c +++ b/src/cairo-atsui-font.c @@ -30,778 +30,661 @@ * The Initial Developer of the Original Code is Calum Robinson * * Contributor(s): - * Calum Robinson <calumr@mac.com> + * Calum Robinson <calumr@mac.com> */ #include <stdlib.h> #include <math.h> - #include "cairo-atsui.h" #include "cairoint.h" +#include "cairo.h" +#include <iconv.h> +typedef struct { + cairo_scaled_font_t base; + cairo_matrix_t scale; + ATSUStyle style; + ATSUStyle unscaled_style; + ATSUFontID fontID; +} cairo_atsui_font_t; +typedef struct cairo_ATSUI_glyph_path_callback_info_t { + cairo_path_fixed_t *path; + cairo_matrix_t scale; +} cairo_ATSUI_glyph_path_callback_info_t; +const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend; -#pragma mark Types +static CGAffineTransform +CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale) +{ + return CGAffineTransformMake(scale->xx, scale->yx, + scale->xy, scale->yy, + 0, 0); +} +static ATSUStyle +CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale) +{ + ATSUStyle style; + OSStatus err; -typedef struct { - cairo_unscaled_font_t base; - - ATSUStyle style; - ATSUFontID fontID; -} cairo_atsui_font_t; + // Set the style's size + CGAffineTransform theTransform = + CGAffineTransformMakeWithCairoFontScale(scale); + Fixed theSize = + FloatToFixed(CGSizeApplyAffineTransform + (CGSizeMake(1.0, 1.0), theTransform).height); + const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag }; + const ByteCount theFontStyleSizes[] = { sizeof(Fixed) }; + ATSUAttributeValuePtr theFontStyleValues[] = { &theSize }; + err = ATSUCreateAndCopyStyle(inStyle, &style); -typedef struct cairo_ATSUI_glyph_path_callback_info_t { - cairo_path_t *path; - cairo_matrix_t scale; -} cairo_ATSUI_glyph_path_callback_info_t; + err = ATSUSetAttributes(style, + sizeof(theFontStyleTags) / + sizeof(ATSUAttributeTag), theFontStyleTags, + theFontStyleSizes, theFontStyleValues); + return style; +} +static cairo_status_t +_cairo_atsui_font_create(const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + cairo_scaled_font_t **font_out) +{ + cairo_atsui_font_t *font = NULL; + ATSUStyle style; + ATSUFontID fontID; + OSStatus err; + Boolean isItalic, isBold; + cairo_matrix_t scale; + + err = ATSUCreateStyle(&style); + + + switch (weight) { + case CAIRO_FONT_WEIGHT_BOLD: + isBold = true; + break; + case CAIRO_FONT_WEIGHT_NORMAL: + default: + isBold = false; + break; + } + + switch (slant) { + case CAIRO_FONT_SLANT_ITALIC: + isItalic = true; + break; + case CAIRO_FONT_SLANT_OBLIQUE: + isItalic = false; + break; + case CAIRO_FONT_SLANT_NORMAL: + default: + isItalic = false; + break; + } + + err = ATSUFindFontFromName(family, strlen(family), + kFontFamilyName, + kFontNoPlatformCode, + kFontRomanScript, + kFontNoLanguageCode, &fontID); + + if (err != noErr) { + // couldn't get the font - remap css names and try again + + if (!strcmp(family, "serif")) + family = "Times"; + else if (!strcmp(family, "sans-serif")) + family = "Helvetica"; + else if (!strcmp(family, "cursive")) + family = "Apple Chancery"; + else if (!strcmp(family, "fantasy")) + family = "Gadget"; + else if (!strcmp(family, "monospace")) + family = "Courier"; + else // anything else - return error instead? + family = "Courier"; + + err = ATSUFindFontFromName(family, strlen(family), + kFontFamilyName, + kFontNoPlatformCode, + kFontRomanScript, + kFontNoLanguageCode, &fontID); + } + + + ATSUAttributeTag styleTags[] = + { kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag }; + ATSUAttributeValuePtr styleValues[] = { &isItalic, &isBold, &fontID }; + ByteCount styleSizes[] = + { sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID) }; + + + err = ATSUSetAttributes(style, + sizeof(styleTags) / sizeof(styleTags[0]), + styleTags, styleSizes, styleValues); + + font = malloc(sizeof(cairo_atsui_font_t)); + + _cairo_scaled_font_init(&font->base, font_matrix, ctm, + &cairo_atsui_scaled_font_backend); + + cairo_matrix_multiply(&scale, font_matrix, ctm); + font->style = CreateSizedCopyOfStyle(style, &scale); + + Fixed theSize = FloatToFixed(1.0); + const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag }; + const ByteCount theFontStyleSizes[] = { sizeof(Fixed) }; + ATSUAttributeValuePtr theFontStyleValues[] = { &theSize }; + err = ATSUSetAttributes(style, + sizeof(theFontStyleTags) / + sizeof(ATSUAttributeTag), theFontStyleTags, + theFontStyleSizes, theFontStyleValues); + + font->unscaled_style = style; + + font->fontID = fontID; + font->scale = scale; + + *font_out = &font->base; + + return CAIRO_STATUS_SUCCESS; +} -#pragma mark Private Functions +static void +_cairo_atsui_font_destroy_font(void *abstract_font) +{ + cairo_atsui_font_t *font = abstract_font; + if (font == NULL) + return; + if (font->style) + ATSUDisposeStyle(font->style); + if (font->unscaled_style) + ATSUDisposeStyle(font->unscaled_style); +} -static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale) +static void +_cairo_atsui_font_get_glyph_cache_key(void *abstract_font, + cairo_glyph_cache_key_t *key) { - return CGAffineTransformMake( scale.matrix[0][0], scale.matrix[0][1], - scale.matrix[1][0], scale.matrix[1][1], - 0, 0); } -static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_font_scale_t *scale) +static cairo_status_t +_cairo_atsui_font_text_to_glyphs(void *abstract_font, + const char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) { - ATSUStyle style; - OSStatus err; - - - // Set the style's size - CGAffineTransform theTransform = CGAffineTransformMakeWithCairoFontScale(*scale); - Fixed theSize = FloatToFixed(CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), theTransform).height); - const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag }; - const ByteCount theFontStyleSizes[] = { sizeof(Fixed) }; - ATSUAttributeValuePtr theFontStyleValues[] = { &theSize }; - - err = ATSUCreateAndCopyStyle(inStyle, &style); - - err = ATSUSetAttributes( style, - sizeof(theFontStyleTags) / sizeof(ATSUAttributeTag), - theFontStyleTags, theFontStyleSizes, theFontStyleValues); - - - return style; -} + cairo_atsui_font_t *font = abstract_font; + size_t i; + OSStatus err; + ATSUTextLayout textLayout; + ATSLayoutRecord *layoutRecords; + ItemCount glyphCount, charCount; + UniChar *theText; + err = ATSUCreateTextLayout(&textLayout); +#if 1 + charCount = strlen(utf8); + // Set the text in the text layout object, so we can measure it + theText = (UniChar *) malloc(charCount * sizeof(UniChar)); + for (i = 0; i < charCount; i++) { + theText[i] = utf8[i]; + } +#endif -#pragma mark Public Functions +#if 0 + // Set the text in the text layout object, so we can measure it + charCount = strlen(utf8); + theText = (UniChar *) malloc(charCount * sizeof(UniChar)); + size_t inBytes = charCount, outBytes = charCount; + iconv_t converter = iconv_open("UTF-8", "UTF-16"); + charCount = iconv(converter, utf8, &inBytes, theText, &outBytes); +#endif + err = ATSUSetTextPointerLocation(textLayout, + theText, 0, charCount, charCount); + // Set the style for all of the text + err = ATSUSetRunStyle(textLayout, + font->unscaled_style, kATSUFromTextBeginning, kATSUToTextEnd); -static cairo_unscaled_font_t * -_cairo_atsui_font_create( const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) -{ - cairo_atsui_font_t *font = NULL; - ATSUStyle style; - ATSUFontID fontID; - OSStatus err; - Boolean isItalic, isBold; - - - err = ATSUCreateStyle(&style); - - - switch (weight) - { - case CAIRO_FONT_WEIGHT_BOLD: - isBold = true; - break; - case CAIRO_FONT_WEIGHT_NORMAL: - default: - isBold = false; - break; - } - - switch (slant) - { - case CAIRO_FONT_SLANT_ITALIC: - isItalic = true; - break; - case CAIRO_FONT_SLANT_OBLIQUE: - isItalic = false; - break; - case CAIRO_FONT_SLANT_NORMAL: - default: - isItalic = false; - break; - } - - err = ATSUFindFontFromName( family, strlen(family), - kFontFamilyName, - kFontNoPlatformCode, - kFontRomanScript, - kFontNoLanguageCode, - &fontID); - - - ATSUAttributeTag styleTags[] = {kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag}; - ATSUAttributeValuePtr styleValues[] = {&isItalic, &isBold, &fontID}; - ByteCount styleSizes[] = {sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID)}; - - - err = ATSUSetAttributes( style, - sizeof(styleTags) / sizeof(styleTags[0]), - styleTags, - styleSizes, - styleValues); - - - - font = malloc(sizeof(cairo_atsui_font_t)); - - if (_cairo_unscaled_font_init(&font->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS) - { - font->style = style; - font->fontID = fontID; - - - return &font->base; - } - - - free(font); - - return NULL; -} + // Get the glyphs from the text layout object + err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, + 0, + kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, + (void *) + &layoutRecords, + &glyphCount); + *num_glyphs = glyphCount - 1; -static void -_cairo_atsui_font_destroy(void *abstract_font) -{ - cairo_atsui_font_t *font = abstract_font; - - - if (font == NULL) - return; - - if (font->style) - ATSUDisposeStyle(font->style); - - free(font); -} + *glyphs = + (cairo_glyph_t *) malloc(*num_glyphs * (sizeof(cairo_glyph_t))); + if (*glyphs == NULL) { + return CAIRO_STATUS_NO_MEMORY; + } -static cairo_status_t -_cairo_atsui_font_text_to_glyphs( void *abstract_font, - cairo_font_scale_t *sc, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - int *nglyphs) -{ - cairo_atsui_font_t *font = abstract_font; - size_t i; - OSStatus err; - ATSUTextLayout textLayout; - ATSLayoutRecord *layoutRecords; - ItemCount glyphCount, charCount; - UniChar *theText; - ATSUStyle style; - - - charCount = strlen(utf8); - - - err = ATSUCreateTextLayout(&textLayout); - - - // Set the text in the text layout object, so we can measure it - theText = (UniChar *)malloc(charCount * sizeof(UniChar)); - - for (i = 0; i < charCount; i++) - { - theText[i] = utf8[i]; - } - - err = ATSUSetTextPointerLocation( textLayout, - theText, - 0, - charCount, - charCount); - - - style = CreateSizedCopyOfStyle(font->style, sc); - - - // Set the style for all of the text - err = ATSUSetRunStyle( textLayout, - style, - kATSUFromTextBeginning, - kATSUToTextEnd); - - - - // Get the glyphs from the text layout object - err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout( textLayout, - 0, - kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, - (void *)&layoutRecords, - &glyphCount); - - *nglyphs = glyphCount; - - - *glyphs = (cairo_glyph_t *)malloc(glyphCount * (sizeof(cairo_glyph_t))); - if (*glyphs == NULL) - { - return CAIRO_STATUS_NO_MEMORY; - } - - for (i = 0; i < glyphCount; i++) - { - (*glyphs)[i].index = layoutRecords[i].glyphID; - (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos); - (*glyphs)[i].y = 0; - } - - - free(theText); - - ATSUDirectReleaseLayoutDataArrayPtr( NULL, - kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, - (void *)&layoutRecords); - - ATSUDisposeTextLayout(textLayout); - - ATSUDisposeStyle(style); - - - return CAIRO_STATUS_SUCCESS; + for (i = 0; i < *num_glyphs; i++) { + (*glyphs)[i].index = layoutRecords[i].glyphID; + (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos); + (*glyphs)[i].y = 0; + } + + + free(theText); + + ATSUDirectReleaseLayoutDataArrayPtr(NULL, + kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, + (void *) &layoutRecords); + + ATSUDisposeTextLayout(textLayout); + + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_atsui_font_font_extents( void *abstract_font, - cairo_font_scale_t *sc, - cairo_font_extents_t *extents) +static cairo_status_t +_cairo_atsui_font_font_extents(void *abstract_font, + cairo_font_extents_t * extents) { - cairo_atsui_font_t *font = abstract_font; - ATSFontRef atsFont; - ATSFontMetrics metrics; - OSStatus err; - - - // TODO - test this - - atsFont = FMGetATSFontRefFromFont(font->fontID); - - if (atsFont) - { - err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics); - - if (err == noErr) - { - extents->ascent = metrics.ascent; - extents->descent = metrics.descent; - extents->height = metrics.capHeight; - extents->max_x_advance = metrics.maxAdvanceWidth; - - // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now. - extents->max_y_advance = 0.0; - - - return CAIRO_STATUS_SUCCESS; - } - } - - - return CAIRO_STATUS_NULL_POINTER; + cairo_atsui_font_t *font = abstract_font; + ATSFontRef atsFont; + ATSFontMetrics metrics; + OSStatus err; + + // TODO - test this + + atsFont = FMGetATSFontRefFromFont(font->fontID); + + if (atsFont) { + err = + ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, + &metrics); + + if (err == noErr) { + extents->ascent = metrics.ascent; + extents->descent = metrics.descent; + extents->height = metrics.capHeight; + extents->max_x_advance = metrics.maxAdvanceWidth; + + // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now. + extents->max_y_advance = 0.0; + + return CAIRO_STATUS_SUCCESS; + } + } + + + return CAIRO_STATUS_NULL_POINTER; } -static cairo_status_t -_cairo_atsui_font_glyph_extents( void *abstract_font, - cairo_font_scale_t *sc, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +static cairo_status_t +_cairo_atsui_font_glyph_extents(void *abstract_font, + cairo_glyph_t * glyphs, + int num_glyphs, + cairo_text_extents_t * extents) { - cairo_atsui_font_t *font = abstract_font; - cairo_point_double_t origin; - cairo_point_double_t glyph_min, glyph_max; - cairo_point_double_t total_min, total_max; - OSStatus err; - ATSUStyle style; - int i; - - - if (num_glyphs == 0) - { - extents->x_bearing = 0.0; - extents->y_bearing = 0.0; - extents->width = 0.0; - extents->height = 0.0; - extents->x_advance = 0.0; - extents->y_advance = 0.0; - - return CAIRO_STATUS_SUCCESS; - } - - origin.x = glyphs[0].x; - origin.y = glyphs[0].y; - - - style = CreateSizedCopyOfStyle(font->style, sc); - - - for (i = 0; i < num_glyphs; i++) - { - GlyphID theGlyph = glyphs[i].index; - double minX, maxX, ascent, descent; - ATSGlyphIdealMetrics metricsH, metricsV; - - - err = ATSUGlyphGetIdealMetrics( style, - 1, - &theGlyph, - 0, - &metricsH); - - - ATSUVerticalCharacterType verticalType = kATSUStronglyVertical; - ATSUAttributeTag theTag = kATSUVerticalCharacterTag; - ByteCount theSize = sizeof(ATSUVerticalCharacterType); - - err = ATSUSetAttributes(style, 1, &theTag, &theSize, (ATSUAttributeValuePtr)&verticalType); - - err = ATSUGlyphGetIdealMetrics( style, - 1, - &theGlyph, - 0, - &metricsV); - - minX = metricsH.otherSideBearing.x; - maxX = metricsH.advance.x; - - ascent = metricsV.advance.x; - descent = metricsV.otherSideBearing.x; - - glyph_min.x = glyphs[i].x + minX; - glyph_min.y = glyphs[i].y + descent; - glyph_max.x = glyphs[i].x + maxX; - glyph_max.y = glyphs[i].y + ascent; - - if (i==0) - { - total_min = glyph_min; - total_max = glyph_max; - } - else - { - if (glyph_min.x < total_min.x) - total_min.x = glyph_min.x; - if (glyph_min.y < total_min.y) - total_min.y = glyph_min.y; - - if (glyph_max.x > total_max.x) - total_max.x = glyph_max.x; - if (glyph_max.y > total_max.y) - total_max.y = glyph_max.y; - } - } - - - extents->x_bearing = total_min.x - origin.x; - extents->y_bearing = total_min.y - origin.y; - extents->width = total_max.x - total_min.x; - extents->height = total_max.y - total_min.y; - extents->x_advance = glyphs[i-1].x - origin.x; - extents->y_advance = glyphs[i-1].y - origin.y; - - - return CAIRO_STATUS_SUCCESS; + cairo_atsui_font_t *font = abstract_font; + OSStatus err; + + assert(num_glyphs == 1); + + GlyphID theGlyph = glyphs[0].index; + + ATSGlyphIdealMetrics metricsH, metricsV; + ATSUStyle style; + + ATSUCreateAndCopyStyle(font->unscaled_style, &style); + + err = ATSUGlyphGetIdealMetrics(style, + 1, &theGlyph, 0, &metricsH); + + ATSUVerticalCharacterType verticalType = kATSUStronglyVertical; + const ATSUAttributeTag theTag[] = { kATSUVerticalCharacterTag }; + const ByteCount theSizes[] = { sizeof(verticalType) }; + ATSUAttributeValuePtr theValues[] = { &verticalType }; + + err = ATSUSetAttributes(style, 1, theTag, theSizes, theValues); + + err = ATSUGlyphGetIdealMetrics(style, + 1, &theGlyph, 0, &metricsV); + + extents->x_bearing = metricsH.sideBearing.x; + extents->y_bearing = metricsV.advance.y; + extents->width = + metricsH.advance.x - metricsH.sideBearing.x - metricsH.otherSideBearing.x; + extents->height = + -metricsV.advance.y - metricsV.sideBearing.y - metricsV.otherSideBearing.y; + extents->x_advance = metricsH.advance.x; + extents->y_advance = 0; + + ATSUDisposeStyle(style); + + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_atsui_font_glyph_bbox( void *abstract_font, - cairo_font_scale_t *sc, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +static cairo_status_t +_cairo_atsui_font_glyph_bbox(void *abstract_font, + const cairo_glyph_t *glyphs, + int num_glyphs, cairo_box_t *bbox) { - cairo_atsui_font_t *font = abstract_font; - cairo_fixed_t x1, y1, x2, y2; - int i; - OSStatus err; - ATSUStyle style; - - - bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; - bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; - - - style = CreateSizedCopyOfStyle(font->style, sc); - - - for (i = 0; i < num_glyphs; i++) - { - GlyphID theGlyph = glyphs[i].index; - ATSGlyphIdealMetrics metrics; - - - err = ATSUGlyphGetIdealMetrics( style, - 1, - &theGlyph, - 0, - &metrics); - - x1 = _cairo_fixed_from_double(glyphs[i].x); - y1 = _cairo_fixed_from_double(glyphs[i].y); - x2 = x1 + _cairo_fixed_from_double(metrics.advance.x); - y2 = y1 + _cairo_fixed_from_double(metrics.advance.y); - - if (x1 < bbox->p1.x) - bbox->p1.x = x1; - - if (y1 < bbox->p1.y) - bbox->p1.y = y1; - - if (x2 > bbox->p2.x) - bbox->p2.x = x2; - - if (y2 > bbox->p2.y) - bbox->p2.y = y2; - } - - - ATSUDisposeStyle(style); - - - return CAIRO_STATUS_SUCCESS; + cairo_atsui_font_t *font = abstract_font; + cairo_fixed_t x1, y1, x2, y2; + int i; + + bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; + bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; + + + for (i = 0; i < num_glyphs; i++) { + GlyphID theGlyph = glyphs[i].index; + + ATSGlyphScreenMetrics metrics; + ATSUGlyphGetScreenMetrics(font->style, + 1, &theGlyph, 0, true, true, &metrics); + + x1 = _cairo_fixed_from_double(glyphs[i].x + metrics.topLeft.x); + y1 = _cairo_fixed_from_double(glyphs[i].y - metrics.topLeft.y); + x2 = x1 + _cairo_fixed_from_double(metrics.height); + y2 = y1 + _cairo_fixed_from_double(metrics.width); + + if (x1 < bbox->p1.x) + bbox->p1.x = x1; + + if (y1 < bbox->p1.y) + bbox->p1.y = y1; + + if (x2 > bbox->p2.x) + bbox->p2.x = x2; + + if (y2 > bbox->p2.y) + bbox->p2.y = y2; + } + + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_atsui_font_show_glyphs( void *abstract_font, - cairo_font_scale_t *sc, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +static cairo_status_t +_cairo_atsui_font_show_glyphs(void *abstract_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *generic_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) { - cairo_atsui_font_t *font = abstract_font; - CGContextRef myBitmapContext; - CGColorSpaceRef colorSpace; - cairo_image_surface_t *destImageSurface; - int i; - - - destImageSurface = _cairo_surface_get_image(surface); - - - // Create a CGBitmapContext for the dest surface for drawing into + cairo_atsui_font_t *font = abstract_font; + CGContextRef myBitmapContext; + CGColorSpaceRef colorSpace; + cairo_image_surface_t *destImageSurface; + int i; + + cairo_rectangle_t rect = {dest_x, dest_y, width, height}; + _cairo_surface_acquire_dest_image(generic_surface, + &rect, + &destImageSurface, + &rect, + NULL); + + // Create a CGBitmapContext for the dest surface for drawing into colorSpace = CGColorSpaceCreateDeviceRGB(); - - myBitmapContext = CGBitmapContextCreate( destImageSurface->data, - destImageSurface->width, - destImageSurface->height, - destImageSurface->depth / 4, - destImageSurface->stride, - colorSpace, - kCGImageAlphaPremultipliedFirst); - - - ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID); - CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont); - - CGContextSetFont(myBitmapContext, cgFont); - - - CGAffineTransform textTransform = CGAffineTransformMakeWithCairoFontScale(*sc); - CGSize textSize = CGSizeMake(1.0, 1.0); - - textSize = CGSizeApplyAffineTransform(textSize, textTransform); - - CGContextSetFontSize(myBitmapContext, textSize.width); - - - // TODO - bold and italic text - // - // We could draw the text using ATSUI and get bold, italics - // etc. for free, but ATSUI does a lot of text layout work - // that we don't really need... - - - for (i = 0; i < num_glyphs; i++) - { - CGGlyph theGlyph = glyphs[i].index; - - CGContextShowGlyphsAtPoint(myBitmapContext, source_x + glyphs[i].x, destImageSurface->height - (source_y + glyphs[i].y), &theGlyph, 1); - } - - - CGColorSpaceRelease(colorSpace); - CGContextRelease(myBitmapContext); - - - return CAIRO_STATUS_SUCCESS; -} + myBitmapContext = CGBitmapContextCreate(destImageSurface->data, + destImageSurface->width, + destImageSurface->height, + destImageSurface->depth / 4, + destImageSurface->stride, + colorSpace, + kCGImageAlphaPremultipliedFirst); + CGContextTranslateCTM(myBitmapContext, 0, destImageSurface->height); + CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f); + + ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID); + CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont); + + CGContextSetFont(myBitmapContext, cgFont); + + CGAffineTransform textTransform = + CGAffineTransformMakeWithCairoFontScale(&font->scale); + + textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f); + + CGContextSetFontSize(myBitmapContext, 1.0); + CGContextSetTextMatrix(myBitmapContext, textTransform); + + if (pattern->type == CAIRO_PATTERN_SOLID && + _cairo_pattern_is_opaque_solid(pattern)) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern; + CGContextSetRGBFillColor(myBitmapContext, + solid->color.red, + solid->color.green, + solid->color.blue, 1.0f); + } else + CGContextSetRGBFillColor(myBitmapContext, 0.0f, 0.0f, 0.0f, 0.0f); + + // TODO - bold and italic text + // + // We could draw the text using ATSUI and get bold, italics + // etc. for free, but ATSUI does a lot of text layout work + // that we don't really need... + + + for (i = 0; i < num_glyphs; i++) { + CGGlyph theGlyph = glyphs[i].index; + + CGContextShowGlyphsAtPoint(myBitmapContext, + glyphs[i].x, + glyphs[i].y, + &theGlyph, 1); + } + + + CGColorSpaceRelease(colorSpace); + CGContextRelease(myBitmapContext); -#pragma mark - + _cairo_surface_release_dest_image(generic_surface, + &rect, + destImageSurface, + &rect, + NULL); + + return CAIRO_STATUS_SUCCESS; +} -static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr) +static OSStatus MyATSCubicMoveToCallback(const Float32Point * pt, + void *callBackDataPtr) { - cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; - double scaledPt[2]; - cairo_point_t point; - - - scaledPt[0] = pt->x; - scaledPt[1] = pt->y; - - cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); - - point.x = _cairo_fixed_from_double(scaledPt[0]); - point.y = _cairo_fixed_from_double(scaledPt[1]); - - _cairo_path_move_to(info->path, &point); - - + cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; + double scaledPt[2]; + cairo_fixed_t x, y; + + scaledPt[0] = pt->x; + scaledPt[1] = pt->y; + + cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + + x = _cairo_fixed_from_double(scaledPt[0]); + y = _cairo_fixed_from_double(scaledPt[1]); + + _cairo_path_fixed_close_path(info->path); + _cairo_path_fixed_move_to(info->path, x, y); + return noErr; } -static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr) +static OSStatus MyATSCubicLineToCallback(const Float32Point * pt, + void *callBackDataPtr) { - cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; - cairo_point_t point; - double scaledPt[2]; - - - scaledPt[0] = pt->x; - scaledPt[1] = pt->y; - - cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); - - point.x = _cairo_fixed_from_double(scaledPt[0]); - point.y = _cairo_fixed_from_double(scaledPt[1]); - - _cairo_path_line_to(info->path, &point); - - - return noErr; + cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; + double scaledPt[2]; + cairo_fixed_t x, y; + + scaledPt[0] = pt->x; + scaledPt[1] = pt->y; + + cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + + x = _cairo_fixed_from_double(scaledPt[0]); + y = _cairo_fixed_from_double(scaledPt[1]); + + _cairo_path_fixed_line_to(info->path, x, y); + + + return noErr; } -static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1, - const Float32Point *pt2, - const Float32Point *pt3, - void *callBackDataPtr) +static OSStatus MyATSCubicCurveToCallback(const Float32Point * pt1, + const Float32Point * pt2, + const Float32Point * pt3, + void *callBackDataPtr) { - cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; - cairo_point_t p0, p1, p2; - double scaledPt[2]; - - - scaledPt[0] = pt1->x; - scaledPt[1] = pt1->y; - - cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); - - p0.x = _cairo_fixed_from_double(scaledPt[0]); - p0.y = _cairo_fixed_from_double(scaledPt[1]); - + cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; + double scaledPt[2]; + cairo_fixed_t x0, y0; + cairo_fixed_t x1, y1; + cairo_fixed_t x2, y2; + + + scaledPt[0] = pt1->x; + scaledPt[1] = pt1->y; + + cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + + x0 = _cairo_fixed_from_double(scaledPt[0]); + y0 = _cairo_fixed_from_double(scaledPt[1]); + scaledPt[0] = pt2->x; - scaledPt[1] = pt2->y; - - cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + scaledPt[1] = pt2->y; + + cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + + x1 = _cairo_fixed_from_double(scaledPt[0]); + y1 = _cairo_fixed_from_double(scaledPt[1]); - p1.x = _cairo_fixed_from_double(scaledPt[0]); - p1.y = _cairo_fixed_from_double(scaledPt[1]); - scaledPt[0] = pt3->x; - scaledPt[1] = pt3->y; - - cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); + scaledPt[1] = pt3->y; - p2.x = _cairo_fixed_from_double(scaledPt[0]); - p2.y = _cairo_fixed_from_double(scaledPt[1]); - + cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]); - _cairo_path_curve_to(info->path, &p0, &p1, &p2); - - - return noErr; -} + x2 = _cairo_fixed_from_double(scaledPt[0]); + y2 = _cairo_fixed_from_double(scaledPt[1]); -static OSStatus MyCubicClosePathProc(void * callBackDataPtr) -{ - cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; - - - _cairo_path_close_path(info->path); - - - return noErr; + _cairo_path_fixed_curve_to(info->path, x0, y0, x1, y1, x2, y2); + + + return noErr; } -static cairo_status_t -_cairo_atsui_font_glyph_path( void *abstract_font, - cairo_font_scale_t *sc, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +static OSStatus MyCubicClosePathProc(void *callBackDataPtr) { - int i; - cairo_atsui_font_t *font = abstract_font; - OSStatus err; - cairo_ATSUI_glyph_path_callback_info_t info; - ATSUStyle style; - - - static ATSCubicMoveToUPP moveProc = NULL; - static ATSCubicLineToUPP lineProc = NULL; - static ATSCubicCurveToUPP curveProc = NULL; - static ATSCubicClosePathUPP closePathProc = NULL; - - - if (moveProc == NULL) - { - moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback); - lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback); - curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback); - closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc); - } - - - info.path = path; - - - style = CreateSizedCopyOfStyle(font->style, sc); - - - for (i = 0; i < num_glyphs; i++) - { - GlyphID theGlyph = glyphs[i].index; - - - cairo_matrix_set_affine( &info.scale, - 1.0, 0.0, - 0.0, 1.0, - glyphs[i].x, glyphs[i].y); - - - err = ATSUGlyphGetCubicPaths( style, - theGlyph, - moveProc, - lineProc, - curveProc, - closePathProc, - (void *)&info, - &err); - } - - - err = ATSUDisposeStyle(style); - - - return CAIRO_STATUS_SUCCESS; -} + cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr; -#pragma mark - + _cairo_path_fixed_close_path(info->path); -static cairo_status_t -_cairo_atsui_font_create_glyph(cairo_image_glyph_cache_entry_t *val) -{ - // TODO - printf("_cairo_atsui_font_create_glyph is unimplemented\n"); - - // I'm not sure if we need this, given that the ATSUI backend does no caching(?) - - - return CAIRO_STATUS_SUCCESS; + return noErr; } -cairo_font_t * -cairo_atsui_font_create(ATSUStyle style) -{ - cairo_font_scale_t scale; - cairo_font_t *scaled; - cairo_atsui_font_t *f = NULL; - - - scaled = malloc(sizeof(cairo_font_t)); - if (scaled == NULL) - return NULL; - - - f = malloc(sizeof(cairo_atsui_font_t)); - if (f) - { - if (_cairo_unscaled_font_init(&f->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS) - { - f->style = style; - - _cairo_font_init(scaled, &scale, &f->base); - - return scaled; - } - } - - - free(scaled); - - - return NULL; -} +static cairo_status_t +_cairo_atsui_font_glyph_path(void *abstract_font, + cairo_glyph_t *glyphs, int num_glyphs, + cairo_path_fixed_t *path) +{ + int i; + cairo_atsui_font_t *font = abstract_font; + OSStatus err; + cairo_ATSUI_glyph_path_callback_info_t info; + static ATSCubicMoveToUPP moveProc = NULL; + static ATSCubicLineToUPP lineProc = NULL; + static ATSCubicCurveToUPP curveProc = NULL; + static ATSCubicClosePathUPP closePathProc = NULL; + if (moveProc == NULL) { + moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback); + lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback); + curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback); + closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc); + } -#pragma mark Backend + info.path = path; + for (i = 0; i < num_glyphs; i++) { + GlyphID theGlyph = glyphs[i].index; -const cairo_font_backend_t cairo_atsui_font_backend = { - _cairo_atsui_font_create, - _cairo_atsui_font_destroy, - _cairo_atsui_font_font_extents, - _cairo_atsui_font_text_to_glyphs, - _cairo_atsui_font_glyph_extents, - _cairo_atsui_font_glyph_bbox, - _cairo_atsui_font_show_glyphs, - _cairo_atsui_font_glyph_path, - _cairo_atsui_font_create_glyph + cairo_matrix_init(&info.scale, + 1.0, 0.0, + 0.0, 1.0, glyphs[i].x, glyphs[i].y); + + + err = ATSUGlyphGetCubicPaths(font->style, + theGlyph, + moveProc, + lineProc, + curveProc, + closePathProc, (void *) &info, &err); + } + + return CAIRO_STATUS_SUCCESS; +} + + +const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { + _cairo_atsui_font_create, + _cairo_atsui_font_destroy_font, + _cairo_atsui_font_font_extents, + _cairo_atsui_font_text_to_glyphs, + _cairo_atsui_font_glyph_extents, + _cairo_atsui_font_glyph_bbox, + _cairo_atsui_font_show_glyphs, + _cairo_atsui_font_glyph_path, + _cairo_atsui_font_get_glyph_cache_key, }; + |