Commit 007c5d82 authored by John Ellson's avatar John Ellson

Merge pull request #9 from pixelglow/improve_quartz

Quartz improvements
parents 970d3879 176b8c46
......@@ -23,7 +23,7 @@
#include "gvplugin_quartz.h"
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000 && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 30200
#import "GVTextLayout.h"
......@@ -76,18 +76,14 @@ static NSString* _defaultFontName = @"TimesNewRomanPSMT";
*yoffset = ascender;
}
- (void)drawAtPoint:(CGPoint)point inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
[_text drawAtPoint:point withFont:_font];
UIGraphicsPopContext();
}
- (void)drawInContext:(CGContextRef)context atPosition:(CGPoint)position
{
UIGraphicsPushContext(context);
[_text drawAtPoint:position withFont:_font];
UIGraphicsPopContext();
CGContextSaveGState(context);
CGContextScaleCTM(context, 1.0, -1.0);
[_text drawAtPoint:CGPointMake(position.x, -position.y - _font.ascender) withFont:_font];
CGContextRestoreGState(context);
UIGraphicsPopContext();
}
- (void)dealloc
......
......@@ -39,7 +39,7 @@ static void quartz_format(GVJ_t *job)
/* image destination -> data consumer -> job's gvdevice */
/* data provider <- job's imagedata */
CGDataConsumerRef data_consumer = CGDataConsumerCreate(job, &device_data_consumer_callbacks);
CGImageDestinationRef image_destination = CGImageDestinationCreateWithDataConsumer(data_consumer, format_uti[job->device.id], 1, NULL);
CGImageDestinationRef image_destination = CGImageDestinationCreateWithDataConsumer(data_consumer, format_to_uti(job->device.id), 1, NULL);
CGDataProviderRef data_provider = CGDataProviderCreateDirect(job->imagedata, BYTES_PER_PIXEL * job->width * job->height, &memory_data_provider_callbacks);
/* add the bitmap image to the destination and save it */
......@@ -87,6 +87,8 @@ gvplugin_installed_t gvdevice_quartz_types_for_cairo[] = {
{FORMAT_BMP, "bmp:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_GIF, "gif:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_EXR, "exr:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_ICNS, "icns:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_ICO, "ico:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_JPEG, "jpe:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_JPEG, "jpeg:cairo", 9, &quartz_engine, &device_features_quartz},
{FORMAT_JPEG, "jpg:cairo", 9, &quartz_engine, &device_features_quartz},
......
......@@ -122,7 +122,7 @@ static CGImageRef quartz_loadimage(GVJ_t * job, usershape_t *us)
CFDictionaryRef options = hint_format_type == FORMAT_NONE ? NULL : CFDictionaryCreate(
kCFAllocatorDefault,
(const void **)&kCGImageSourceTypeIdentifierHint,
(const void **)(format_uti + hint_format_type),
(const void **)format_to_uti(hint_format_type),
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
......
......@@ -27,25 +27,6 @@ extern gvplugin_installed_t gvdevice_quartz_types;
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
extern gvplugin_installed_t gvdevice_quartz_types_for_cairo;
/* Uniform Type Identifiers corresponding to each format_type */
CFStringRef format_uti [] = {
NULL,
NULL,
CFSTR("com.microsoft.bmp"),
CFSTR("com.ilm.openexr-image"),
CFSTR("com.compuserve.gif"),
CFSTR("public.jpeg"),
CFSTR("public.jpeg-2000"),
CFSTR("com.adobe.pdf"),
CFSTR("com.apple.pict"),
CFSTR("public.png"),
CFSTR("com.adobe.photoshop-image"),
CFSTR("com.sgi.sgi-image"),
CFSTR("public.tiff"),
CFSTR("com.truevision.tga-image")
};
#endif
/* data consumer backed by the gvdevice */
......@@ -59,6 +40,44 @@ CGDataConsumerCallbacks device_data_consumer_callbacks = {
NULL
};
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000
CFStringRef format_to_uti(format_type format)
{
switch (format) {
case FORMAT_BMP:
return CFSTR("com.microsoft.bmp");
case FORMAT_EXR:
return CFSTR("com.ilm.openexr-image");
case FORMAT_GIF:
return CFSTR("com.compuserve.gif");
case FORMAT_ICNS:
return CFSTR("com.apple.icns");
case FORMAT_ICO:
return CFSTR("com.microsoft.ico");
case FORMAT_JPEG:
return CFSTR("public.jpeg");
case FORMAT_JPEG2000:
return CFSTR("public.jpeg-2000");
case FORMAT_PICT:
return CFSTR("com.apple.pict");
case FORMAT_PNG:
return CFSTR("public.png");
case FORMAT_PSD:
return CFSTR("com.adobe.photoshop-image");
case FORMAT_SGI:
return CFSTR("com.sgi.sgi-image");
case FORMAT_TIFF:
return CFSTR("public.tiff");
case FORMAT_TGA:
return CFSTR("com.truevision.tga-image");
default:
return NULL;
}
}
#endif
static gvplugin_api_t apis[] = {
{API_render, &gvrender_quartz_types},
{API_textlayout, &gvtextlayout_quartz_types},
......
......@@ -32,6 +32,8 @@ typedef enum {
FORMAT_BMP,
FORMAT_EXR,
FORMAT_GIF,
FORMAT_ICNS,
FORMAT_ICO,
FORMAT_JPEG,
FORMAT_JPEG2000,
FORMAT_PDF,
......@@ -47,8 +49,8 @@ static const int BYTE_ALIGN = 15; /* align to 16 bytes */
static const int BITS_PER_COMPONENT = 8; /* bits per color component */
static const int BYTES_PER_PIXEL = 4; /* bytes per pixel */
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
extern CFStringRef format_uti [];
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000
CFStringRef format_to_uti(format_type format);
#endif
extern CGDataConsumerCallbacks device_data_consumer_callbacks;
......
......@@ -34,20 +34,38 @@ static CGFloat dotted[] = { 2.0, 6.0 };
static void quartzgen_begin_job(GVJ_t * job)
{
if (!job->external_context)
job->context = NULL;
else if (job->device.id == FORMAT_CGIMAGE) {
/* save the passed-in context in the window field, so we can create a CGContext in the context field later on */
job->window = job->context;
*((CGImageRef *) job->window) = NULL;
switch (job->device.id) {
case FORMAT_CGIMAGE:
/* save the passed-in context in the window field, so we can create a CGContext in the context field later on */
job->window = job->context;
*((CGImageRef *) job->window) = NULL;
}
job->context = NULL;
}
}
static void quartzgen_end_job(GVJ_t * job)
{
CGContextRef context = (CGContextRef) job->context;
if (!job->external_context) {
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
void* context_data;
size_t context_datalen;
switch (job->device.id) {
case FORMAT_PDF:
context_data = NULL;
context_datalen = 0;
break;
default:
context_data = CGBitmapContextGetData(context);
context_datalen = CGBitmapContextGetBytesPerRow(context) * CGBitmapContextGetHeight(context);
break;
}
#endif
switch (job->device.id) {
case FORMAT_PDF:
......@@ -56,9 +74,11 @@ static void quartzgen_end_job(GVJ_t * job)
break;
case FORMAT_CGIMAGE:
/* create an image and save it where the window field is, which was set to the passed-in context at begin job */
*((CGImageRef *) job->window) = CGBitmapContextCreateImage(context);
break;
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000
default: /* bitmap formats */
{
/* create an image destination */
......@@ -67,9 +87,8 @@ static void quartzgen_end_job(GVJ_t * job)
&device_data_consumer_callbacks);
CGImageDestinationRef image_destination =
CGImageDestinationCreateWithDataConsumer(data_consumer,
format_uti
[job->device.
id], 1,
format_to_uti(job->device.id),
1,
NULL);
/* add the bitmap image to the destination and save it */
......@@ -86,22 +105,13 @@ static void quartzgen_end_job(GVJ_t * job)
break;
#endif
}
CGContextRelease(context);
} else if (job->device.id == FORMAT_CGIMAGE) {
/* create an image and save it where the window field is, which was set to the passed-in context at begin job */
*((CGImageRef *) job->window) =
CGBitmapContextCreateImage(context);
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
void *context_data = CGBitmapContextGetData(context);
size_t context_datalen =
CGBitmapContextGetBytesPerRow(context) *
CGBitmapContextGetHeight(context);
#endif
CGContextRelease(context);
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
munmap(context_data, context_datalen);
if (context_data && context_datalen)
munmap(context_data, context_datalen);
#endif
}
}
static void quartzgen_begin_page(GVJ_t * job)
......@@ -350,21 +360,12 @@ void quartzgen_textspan(GVJ_t * job, pointf p, textspan_t * span)
layout =
quartz_new_layout(span->font->name, span->font->size, span->str);
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
CGContextSaveGState(context);
CGContextScaleCTM(context, 1.0, -1.0);
p.y = -p.y - span->yoffset_layout;
#endif
CGContextSetRGBFillColor(context, job->obj->pencolor.u.RGBA[0],
job->obj->pencolor.u.RGBA[1],
job->obj->pencolor.u.RGBA[2],
job->obj->pencolor.u.RGBA[3]);
quartz_draw_layout(layout, context, CGPointMake(p.x, p.y));
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
CGContextRestoreGState(context);
#endif
if (span->free_layout != &quartz_free_layout)
quartz_free_layout(layout);
}
......@@ -493,22 +494,26 @@ gvplugin_installed_t gvdevice_quartz_types[] = {
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 20000
{FORMAT_CGIMAGE, "cgimage:quartz", 8, NULL, &device_features_quartz},
#endif
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000
{FORMAT_BMP, "bmp:quartz", 8, NULL, &device_features_quartz},
{FORMAT_GIF, "gif:quartz", 8, NULL, &device_features_quartz},
{FORMAT_EXR, "exr:quartz", 8, NULL, &device_features_quartz},
{FORMAT_ICO, "ico:quartz", 8, NULL, &device_features_quartz},
{FORMAT_JPEG, "jpe:quartz", 8, NULL, &device_features_quartz},
{FORMAT_JPEG, "jpeg:quartz", 8, NULL, &device_features_quartz},
{FORMAT_JPEG, "jpg:quartz", 8, NULL, &device_features_quartz},
{FORMAT_JPEG2000, "jp2:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PICT, "pct:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PICT, "pict:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PNG, "png:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PSD, "psd:quartz", 8, NULL, &device_features_quartz},
{FORMAT_SGI, "sgi:quartz", 8, NULL, &device_features_quartz},
{FORMAT_TIFF, "tif:quartz", 8, NULL, &device_features_quartz},
{FORMAT_TIFF, "tiff:quartz", 8, NULL, &device_features_quartz},
{FORMAT_TGA, "tga:quartz", 8, NULL, &device_features_quartz},
#endif
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1040
{FORMAT_EXR, "exr:quartz", 8, NULL, &device_features_quartz},
{FORMAT_ICNS, "icns:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PICT, "pct:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PICT, "pict:quartz", 8, NULL, &device_features_quartz},
{FORMAT_PSD, "psd:quartz", 8, NULL, &device_features_quartz},
{FORMAT_SGI, "sgi:quartz", 8, NULL, &device_features_quartz},
#endif
{0, NULL, 0, NULL, NULL}
};
......@@ -21,7 +21,11 @@
#include "gvplugin_textlayout.h"
#include "gvplugin_quartz.h"
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 30200
#include <CoreText/CoreText.h>
#endif
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 || __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 30200
void *quartz_new_layout(char* fontname, double fontsize, char* text)
{
......@@ -32,12 +36,13 @@ void *quartz_new_layout(char* fontname, double fontsize, char* text)
if (fontnameref && textref) {
/* set up the Core Text line */
CTFontRef font = CTFontCreateWithName(fontnameref, fontsize, NULL);
CFTypeRef attributeNames[] = { kCTFontAttributeName, kCTForegroundColorFromContextAttributeName };
CFTypeRef attributeValues[] = { font, kCFBooleanTrue };
CFDictionaryRef attributes = CFDictionaryCreate(
kCFAllocatorDefault,
(const void**)&kCTFontAttributeName,
(const void**)&font,
1,
(const void**)attributeNames,
(const void**)attributeValues,
2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFAttributedStringRef attributed = CFAttributedStringCreate(kCFAllocatorDefault, textref, attributes);
......@@ -61,39 +66,16 @@ void quartz_size_layout(void *layout, double* width, double* height, double* yof
CGFloat ascent = 0.0;
CGFloat descent = 0.0;
CGFloat leading = 0.0;
double typowidth = CTLineGetTypographicBounds((CTLineRef)layout, &ascent, &descent, &leading);
CGFloat typoheight = ascent + descent;
*width = typowidth;
*height = leading == 0.0 ? typoheight * 1.2 : typoheight + leading; /* if no leading, use 20% of height */
*width = CTLineGetTypographicBounds((CTLineRef)layout, &ascent, &descent, &leading);
*height = ascent + descent + leading;
*yoffset_layout = ascent;
}
void quartz_draw_layout(void *layout, CGContextRef context, CGPoint position)
{
CGContextSetTextPosition(context, position.x, position.y);
CFArrayRef runs = CTLineGetGlyphRuns((CTLineRef)layout);
CFIndex run_count = CFArrayGetCount(runs);
CFIndex run_index;
for (run_index = 0; run_index < run_count; ++run_index)
{
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, run_index);
CTFontRef run_font = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
CGFontRef glyph_font = CTFontCopyGraphicsFont(run_font, NULL);
CFIndex glyph_count = CTRunGetGlyphCount(run);
CGGlyph glyphs[glyph_count];
CGPoint positions[glyph_count];
CFRange everything = CFRangeMake(0, 0);
CTRunGetGlyphs(run, everything, glyphs);
CTRunGetPositions(run, everything, positions);
CGContextSetFont(context, glyph_font);
CGContextSetFontSize(context, CTFontGetSize(run_font));
CGContextShowGlyphsAtPositions(context, glyphs, positions, glyph_count);
CGFontRelease(glyph_font);
}
CTLineDraw((CTLineRef)layout, context);
}
void quartz_free_layout(void *layout)
......@@ -112,8 +94,8 @@ boolean quartz_textlayout(textspan_t *para, char **fontpath)
/* report the layout */
para->layout = (void*)line;
para->free_layout = &quartz_free_layout;
para->yoffset_centerline = 0;
quartz_size_layout((void*)line, &para->size.x, &para->size.y, &para->yoffset_layout);
para->yoffset_centerline = 0.2 * para->font->size;
return TRUE;
}
else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment