void QFontEngineMac::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) { QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; QTransform matrix; matrix.translate(x, y); getGlyphPositions(ti.glyphs, ti.num_glyphs, matrix, ti.flags, glyphs, positions); if (glyphs.size() == 0) return; CGContextSetFontSize(ctx, fontDef.pixelSize); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight); CGAffineTransformConcat(cgMatrix, oldTextMatrix); if (synthesisFlags & QFontEngine::SynthesizedItalic) cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0)); cgMatrix = CGAffineTransformConcat(cgMatrix, multiEngine->transform); CGContextSetTextMatrix(ctx, cgMatrix); CGContextSetTextDrawingMode(ctx, kCGTextFill); QVarLengthArray<CGSize> advances(glyphs.size()); QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size()); for (int i = 0; i < glyphs.size() - 1; ++i) { advances[i].width = (positions[i + 1].x - positions[i].x).toReal(); advances[i].height = (positions[i + 1].y - positions[i].y).toReal(); cgGlyphs[i] = glyphs[i]; } advances[glyphs.size() - 1].width = 0; advances[glyphs.size() - 1].height = 0; cgGlyphs[glyphs.size() - 1] = glyphs[glyphs.size() - 1]; CGContextSetFont(ctx, cgFont); CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal()); CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size()); if (synthesisFlags & QFontEngine::SynthesizedBold) { CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(), positions[0].y.toReal()); CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size()); } CGContextSetTextMatrix(ctx, oldTextMatrix); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = graphicsContext->platformContext(); uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext); const FontPlatformData& platformData = font->platformData(); //NSFont* drawFont; //if ([gContext isDrawingToScreen]) { // drawFont = [platformData.font screenFont]; // if (drawFont != platformData.font) // // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually). // LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen. Using screen font anyway, may result in incorrect metrics.", // [[[platformData.font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]); //} else { // drawFont = [platformData.font printerFont]; // if (drawFont != platformData.font) // NSLog(@"Attempting to set non-printer font (%@) when printing. Using printer font anyway, may result in incorrect metrics.", // [[[platformData.font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]); //} CGContextSetFont(cgContext, platformData.cgFont()); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; if (platformData.syntheticOblique()) { static float skew = -tanf(syntheticObliqueAngle * acosf(0) / 90); matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); } // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) CGAffineTransformTranslate(matrix, translation.width(), translation.height()); CGContextSetTextMatrix(cgContext, matrix); //wkSetCGFontRenderingMode(cgContext, drawFont); CGContextSetFontSize(cgContext, platformData.size()); CGContextSetTextPosition(cgContext, point.x(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->m_syntheticBoldOffset) { CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); }
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); } }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { graphicsContext->save(); wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); wxFont* wxfont = font->getWxFont(); graphicsContext->setFillColor(graphicsContext->fillColor(), ColorSpaceDeviceRGB); CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext()); CGFontRef cgFont = font->platformData().cgFont(); CGContextSetFont(cgContext, cgFont); CGContextSetFontSize(cgContext, wxfont->GetPointSize()); CGFloat red, green, blue, alpha; graphicsContext->fillColor().getRGBA(red, green, blue, alpha); CGContextSetRGBFillColor(cgContext, red, green, blue, alpha); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; CGContextSetTextMatrix(cgContext, matrix); CGContextSetTextPosition(cgContext, point.x(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (cgFont) CGFontRelease(cgFont); graphicsContext->restore(); }
void QuartzWindow::draw_text(const char* text, int x, int y) { int len = strlen(text); int h = font_height(); clear_rectangle(x, y-h, len * font_width(), h); CGContextSetTextPosition(myContext, x, y); CGContextShowText(myContext, text, len); }
void drawTextWithFeature(CGContextRef context, CTFontDescriptorRef fontDescriptor, CFStringRef feature, int value, CGPoint location) { CGFloat fontSize = 25; CGContextSetTextMatrix(context, CGAffineTransformScale(CGAffineTransformIdentity, 1, 1)); CGContextSetTextPosition(context, location.x, location.y); CFNumberRef featureValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value); CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue }; CFTypeRef featureDictionaryValues[] = { feature, featureValue }; CFDictionaryRef featureDictionary = CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(featureValue); CFTypeRef featureSettingsValues[] = { featureDictionary }; CFArrayRef fontFeatureSettings = CFArrayCreate(kCFAllocatorDefault, featureSettingsValues, 1, &kCFTypeArrayCallBacks); CFRelease(featureDictionary); CFTypeRef fontDescriptorKeys[] = { kCTFontFeatureSettingsAttribute }; CFTypeRef fontDescriptorValues[] = { fontFeatureSettings }; CFDictionaryRef fontDescriptorAttributes = CFDictionaryCreate(kCFAllocatorDefault, fontDescriptorKeys, fontDescriptorValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(fontFeatureSettings); CTFontDescriptorRef modifiedFontDescriptor = CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fontDescriptorAttributes); CFRelease(fontDescriptorAttributes); CTFontRef font = CTFontCreateWithFontDescriptor(modifiedFontDescriptor, fontSize, nullptr); CFRelease(modifiedFontDescriptor); CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0); CFStringAppend(string, feature); CFStringAppend(string, value ? CFSTR(" (on)") : CFSTR(" (off)")); CFStringAppend(string, CFSTR(": ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")); CGColorRef red = CGColorCreateGenericRGB(1, 0, 0, 1); CFTypeRef lineKeys[] = { kCTForegroundColorAttributeName }; CFTypeRef lineValues[] = { red }; CFDictionaryRef lineAttributes = CFDictionaryCreate(kCFAllocatorDefault, lineKeys, lineValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CGColorRelease(red); CFAttributedStringRef attributedString = CFAttributedStringCreate(kCFAllocatorDefault, string, lineAttributes); CFRelease(lineAttributes); CFRelease(string); CFMutableAttributedStringRef mutableAttributedString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, attributedString); CFRelease(attributedString); CTFontRef monospaceFont = CTFontCreateWithName(CFSTR("Courier"), fontSize, nullptr); CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(0, 12), kCTFontAttributeName, monospaceFont); CFRelease(monospaceFont); CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(12, 52), kCTFontAttributeName, font); CFRelease(font); CTLineRef line = CTLineCreateWithAttributedString(mutableAttributedString); CFRelease(mutableAttributedString); CTLineDraw(line, context); CFRelease(line); }
// This function is needed to work around a bug in Windows CG <rdar://problem/22703470> void PlatformCALayer::drawTextAtPoint(CGContextRef context, CGFloat x, CGFloat y, CGSize scale, CGFloat fontSize, const char* text, size_t length) const { auto matrix = CGAffineTransformMakeScale(scale.width, scale.height); auto font = adoptCF(CTFontCreateWithName(CFSTR("Helvetica"), fontSize, &matrix)); CFTypeRef keys[] = { kCTFontAttributeName, kCTForegroundColorFromContextAttributeName }; CFTypeRef values[] = { font.get(), kCFBooleanTrue }; auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); auto string = adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(text), length, kCFStringEncodingUTF8, false, kCFAllocatorNull)); auto attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), attributes.get())); auto line = adoptCF(CTLineCreateWithAttributedString(attributedString.get())); CGContextSetTextPosition(context, x, y); CTLineDraw(line.get(), context); }
xy__Float draw__string(const char *s, int x, int y, int w, float pos) { CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingUTF8); if (font == NULL || font_color == NULL) { fprintf(stderr, "Error in %s: need both font & font_color to be non-NULL.\n", __FUNCTION__); return x; } CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; CFTypeRef values[] = { font, font_color }; CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); CFRelease(string); CFRelease(attributes); CTLineRef line = CTLineCreateWithAttributedString(attrString); // This position set is needed to get a useful x_pos value on the next line. CGContextSetTextPosition(ctx, x, y); double x_pos = CTLineGetPenOffsetForFlush(line, pos, w); CGFloat descent; double line_width = CTLineGetTypographicBounds(line, NULL, &descent, NULL); CGContextSetTextPosition(ctx, x + x_pos, y + descent); CTLineDraw(line, ctx); CFRelease(line); return x + x_pos + line_width; }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = graphicsContext->platformContext(); bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); switch(fontDescription().fontSmoothing()) { case Antialiased: { graphicsContext->setShouldAntialias(true); shouldUseFontSmoothing = false; break; } case SubpixelAntialiased: { graphicsContext->setShouldAntialias(true); shouldUseFontSmoothing = true; break; } case NoSmoothing: { graphicsContext->setShouldAntialias(false); shouldUseFontSmoothing = false; break; } case AutoSmoothing: { // For the AutoSmooth case, don't do anything! Keep the default settings. break; } default: ASSERT_NOT_REACHED(); } if (font->platformData().useGDI() && !shouldUseFontSmoothing) { drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); return; } uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); const FontPlatformData& platformData = font->platformData(); CGContextSetFont(cgContext, platformData.cgFont()); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; if (platformData.syntheticOblique()) { static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f); matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); } CGContextSetTextMatrix(cgContext, matrix); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); CGContextSetFontSize(cgContext, platformData.size()); wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI()); FloatSize shadowOffset; float shadowBlur; Color shadowColor; ColorSpace shadowColorSpace; graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped()); if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB); float shadowTextX = point.x() + translation.width() + shadowOffset.width(); // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative. float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1); CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } if (hasSimpleShadow) graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { graphicsContext->save(); wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); wxFont* wxfont = font->getWxFont(); graphicsContext->setFillColor(graphicsContext->fillColor(), DeviceColorSpace); CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext()); CGFontRef cgFont; #ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT cgFont = CTFontCopyGraphicsFont((CTFontRef)wxfont->OSXGetCTFont(), NULL); #else ATSFontRef fontRef; fontRef = FMGetATSFontRefFromFont(wxfont->MacGetATSUFontID()); if (fontRef) cgFont = CGFontCreateWithPlatformFont((void*)&fontRef); #endif CGContextSetFont(cgContext, cgFont); CGContextSetFontSize(cgContext, wxfont->GetPointSize()); CGFloat red, green, blue, alpha; graphicsContext->fillColor().getRGBA(red, green, blue, alpha); CGContextSetRGBFillColor(cgContext, red, green, blue, alpha); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; CGContextSetTextMatrix(cgContext, matrix); CGContextSetTextPosition(cgContext, point.x(), point.y()); const FloatSize* advanceSizes = static_cast<const FloatSize*>(glyphBuffer.advances(from)); int size = glyphBuffer.size() - from; CGSize sizes[size]; CGGlyph glyphs[numGlyphs]; // if the function doesn't exist, we're probably on tiger and need to grab the // function under its old name, CGFontGetGlyphsForUnicodes if (!CGFontGetGlyphsForUnichars) CGFontGetGlyphsForUnichars = (CGFontGetGlyphsForUnicharsPtr)dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes"); // Let's make sure we got the function under one name or another! ASSERT(CGFontGetGlyphsForUnichars); CGFontGetGlyphsForUnichars(cgFont, glyphBuffer.glyphs(from), glyphs, numGlyphs); for (int i = 0; i < size; i++) { FloatSize fsize = advanceSizes[i]; sizes[i] = CGSizeMake(fsize.width(), fsize.height()); } CGContextShowGlyphsWithAdvances(cgContext, glyphs, sizes, numGlyphs); if (cgFont) CGFontRelease(cgFont); graphicsContext->restore(); }
static OSStatus local_CoreTR(CGContextRef ctx, CGRect r, CFStringRef string, CFStringRef fontName, CGFloat fontSize, TRFallbackBehavior fallbackBehavior, Boolean render, CGFloat baseline, TRInfo* oInfo) { if (!ctx || !string || !fontName) return paramErr; CGContextSaveGState(ctx); CGContextSetTextMatrix(ctx, CGAffineTransformIdentity); CTFontDescriptorRef fdesc = CTFontDescriptorCreateWithNameAndSize(fontName, fontSize); CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFIndex slen = CFStringGetLength(string); CFRange range = CFRangeMake(0L,slen); UniChar* buff = calloc(slen, sizeof(UniChar)); CFStringGetCharacters(string, range, buff); CGGlyph* glyphs = calloc(slen, sizeof(CGGlyph)); Boolean supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen); //NSLog(@"%@ supported for '%@'? %d", fontName, string, supported); CFRelease(fdesc); if (!supported) { if (fallbackBehavior == TRLastResortFallbackBehavior) { CFRelease(font); fdesc = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), fontSize); font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFRelease(fdesc); supported = true; } else { CFRange rng = CFRangeMake(0L, CFStringGetLength(string)); CTFontRef font2 = CTFontCreateForString(font, string, rng); CFRelease(font); CFStringRef fontName2 = CTFontCopyName(font2, kCTFontFullNameKey); fdesc = CTFontDescriptorCreateWithNameAndSize(fontName2, fontSize); //NSLog(@"falling back to %@ from %@ : %@", fontName2, fontName, fdesc); CFRelease(fontName2); font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL); CFRelease(fdesc); supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen); } } free(buff); free(glyphs); CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1L, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(attrs, kCTFontAttributeName, font); CFAttributedStringRef attrStr = CFAttributedStringCreate(kCFAllocatorDefault, string, attrs); CFRelease(attrs); CTLineRef line = CTLineCreateWithAttributedString(attrStr); CFRelease(attrStr); CGRect bounds = CTLineGetImageBounds(line, ctx); CGFloat descent = CTFontGetDescent(font); CGFloat ascent = CTFontGetAscent(font); CFRelease(font); if (baseline < 0.0L) baseline = ((r.size.height - bounds.size.height + descent)/2.0L); if (render && (supported || fallbackBehavior != TRNoRenderFallbackBehavior)) { CGFloat x = r.origin.x + (r.size.width/2.0L) - (bounds.size.width/2.0L) - bounds.origin.x; CGFloat y = r.origin.y + baseline; CGPoint where = CGPointMake(x, y); CGContextSetTextPosition(ctx, where.x, where.y); CTLineDraw(line, ctx); } CFRelease(line); if (oInfo) { oInfo->height = bounds.size.height + descent; oInfo->width = bounds.size.width; oInfo->ascent = ascent; oInfo->descent = descent; oInfo->baseline = baseline; oInfo->fontSupported = supported; } CGContextRestoreGState(ctx); return (supported)? noErr:kATSUFontsNotMatched; }
static bool font_renderer_create_atlas(CTFontRef face, ct_font_renderer_t *handle) { int max_width, max_height; unsigned i; size_t bytesPerRow; CGGlyph glyphs[CT_ATLAS_SIZE]; CGRect bounds[CT_ATLAS_SIZE]; CGSize advances[CT_ATLAS_SIZE]; float ascent, descent; CGContextRef offscreen; CFDictionaryRef attr; CFTypeRef values[1]; CFStringRef keys[1]; void *bitmapData = NULL; bool ret = true; size_t bitsPerComponent = 8; UniChar characters[CT_ATLAS_SIZE] = {0}; values[0] = face; keys[0] = kCTFontAttributeName; for (i = 0; i < CT_ATLAS_SIZE; i++) characters[i] = (UniChar)i; CTFontGetGlyphsForCharacters(face, characters, glyphs, CT_ATLAS_SIZE); CTFontGetBoundingRectsForGlyphs(face, #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 kCTFontOrientationDefault, #else kCTFontDefaultOrientation, #endif glyphs, bounds, CT_ATLAS_SIZE); CTFontGetAdvancesForGlyphs(face, #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 kCTFontOrientationDefault, #else kCTFontDefaultOrientation, #endif glyphs, advances, CT_ATLAS_SIZE); ascent = CTFontGetAscent(face); descent = CTFontGetDescent(face); max_width = 0; max_height = 0; for (i = 0; i < CT_ATLAS_SIZE; i++) { int origin_x, origin_y; struct font_glyph *glyph = &handle->glyphs[i]; if (!glyph) continue; origin_x = ceil(bounds[i].origin.x); origin_y = ceil(bounds[i].origin.y); glyph->draw_offset_x = 0; glyph->draw_offset_y = -ascent; glyph->width = ceil(bounds[i].size.width); glyph->height = ceil(bounds[i].size.height); glyph->advance_x = ceil(advances[i].width); glyph->advance_y = ceil(advances[i].height); max_width = MAX(max_width, (origin_x + glyph->width)); max_height = MAX(max_height, (origin_y + glyph->height)); } max_height = MAX(max_height, ceil(ascent+descent)); handle->atlas.width = max_width * CT_ATLAS_COLS; handle->atlas.height = max_height * CT_ATLAS_ROWS; handle->atlas.buffer = (uint8_t*) calloc(handle->atlas.width * handle->atlas.height, 1); if (!handle->atlas.buffer) { ret = false; goto end; } bytesPerRow = max_width; bitmapData = calloc(max_height, bytesPerRow); offscreen = CGBitmapContextCreate(bitmapData, max_width, max_height, bitsPerComponent, bytesPerRow, NULL, kCGImageAlphaOnly); CGContextSetTextMatrix(offscreen, CGAffineTransformIdentity); attr = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); for (i = 0; i < CT_ATLAS_SIZE; i++) { char glyph_cstr[2]; const uint8_t *src; uint8_t *dst; unsigned offset_x, offset_y, r, c; CFStringRef glyph_cfstr; CFAttributedStringRef attrString; CTLineRef line; struct font_glyph *glyph = &handle->glyphs[i]; if (!glyph) continue; glyph->width = max_width; glyph->height = max_height; offset_x = (i % CT_ATLAS_COLS) * max_width; offset_y = (i / CT_ATLAS_COLS) * max_height; glyph->atlas_offset_x = offset_x; glyph->atlas_offset_y = offset_y; glyph_cstr[0] = i; glyph_cstr[1] = 0; glyph_cfstr = CFStringCreateWithCString( NULL, glyph_cstr, kCFStringEncodingASCII ); attrString = CFAttributedStringCreate(NULL, glyph_cfstr, attr); CFRelease(glyph_cfstr); glyph_cfstr = NULL; line = CTLineCreateWithAttributedString(attrString); CFRelease(attrString); attrString = NULL; memset( bitmapData, 0, max_height * bytesPerRow ); CGContextSetTextPosition(offscreen, 0, descent); CTLineDraw(line, offscreen); CGContextFlush( offscreen ); CFRelease( line ); line = NULL; dst = (uint8_t*)handle->atlas.buffer; src = (const uint8_t*)bitmapData; for (r = 0; r < max_height; r++ ) { for (c = 0; c < max_width; c++) { unsigned src_idx = r * bytesPerRow + c; unsigned dest_idx = (r + offset_y) * (CT_ATLAS_COLS * max_width) + (c + offset_x); uint8_t v = src[src_idx]; dst[dest_idx] = v; } } } CFRelease(attr); CGContextRelease(offscreen); attr = NULL; offscreen = NULL; free(bitmapData); end: return ret; }
Memsubfont* mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias) { CFStringRef s; CGColorSpaceRef color; CGContextRef ctxt; CTFontRef font; CTFontDescriptorRef desc; CGRect bbox; Memimage *m, *mc, *m1; int x, y, y0; int i, height, ascent; Fontchar *fc, *fc0; Memsubfont *sf; CGFloat whitef[] = { 1.0, 1.0 }; CGColorRef white; s = c2mac(name); desc = CTFontDescriptorCreateWithNameAndSize(s, size); CFRelease(s); if(desc == nil) return nil; font = CTFontCreateWithFontDescriptor(desc, 0, nil); CFRelease(desc); if(font == nil) return nil; bbox = CTFontGetBoundingBox(font); x = (int)(bbox.size.width*2 + 0.99999999); fontheight(f, size, &height, &ascent); y = height; y0 = height - ascent; m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), GREY8); if(m == nil) return nil; mc = allocmemimage(Rect(0, 0, x+1, y+1), GREY8); if(mc == nil){ freememimage(m); return nil; } memfillcolor(m, DBlack); memfillcolor(mc, DBlack); fc = malloc((hi+2 - lo) * sizeof fc[0]); sf = malloc(sizeof *sf); if(fc == nil || sf == nil) { freememimage(m); freememimage(mc); free(fc); free(sf); return nil; } fc0 = fc; color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8, mc->width*sizeof(u32int), color, kCGImageAlphaNone); white = CGColorCreate(color, whitef); CGColorSpaceRelease(color); if(ctxt == nil) { freememimage(m); freememimage(mc); free(fc); free(sf); return nil; } CGContextSetAllowsAntialiasing(ctxt, antialias); CGContextSetTextPosition(ctxt, 0, 0); // XXX #if OSX_VERSION >= 101400 CGContextSetAllowsFontSmoothing(ctxt, false); #endif x = 0; for(i=lo; i<=hi; i++, fc++) { char buf[20]; CFStringRef str; CFDictionaryRef attrs; CFAttributedStringRef attrString; CTLineRef line; CGRect r; CGPoint p1; CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; CFTypeRef values[] = { font, white }; sprint(buf, "%C", (Rune)mapUnicode(name, i)); str = c2mac(buf); // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs); CFRelease(str); CFRelease(attrs); line = CTLineCreateWithAttributedString(attrString); CGContextSetTextPosition(ctxt, 0, y0); r = CTLineGetImageBounds(line, ctxt); memfillcolor(mc, DBlack); CTLineDraw(line, ctxt); CFRelease(line); fc->x = x; fc->top = 0; fc->bottom = Dy(m->r); // fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y); p1 = CGContextGetTextPosition(ctxt); if(p1.x <= 0 || mapUnicode(name, i) == 0xfffd) { fc->width = 0; fc->left = 0; if(i == 0) { drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0); x += fc->width; } continue; } memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S); fc->width = p1.x; fc->left = 0; x += p1.x; } fc->x = x; // round up to 32-bit boundary // so that in-memory data is same // layout as in-file data. if(x == 0) x = 1; if(y == 0) y = 1; if(antialias) x += -x & 3; else x += -x & 31; m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1); memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S); freememimage(m); freememimage(mc); sf->name = nil; sf->n = hi+1 - lo; sf->height = Dy(m1->r); sf->ascent = Dy(m1->r) - y0; sf->info = fc0; sf->bits = m1; return sf; }
QImage QFontEngineMac::alphaMapForGlyph(glyph_t glyph) { const glyph_metrics_t br = boundingBox(glyph); QImage im(qRound(br.width)+2, qRound(br.height)+2, QImage::Format_RGB32); im.fill(0); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) uint cgflags = kCGImageAlphaNoneSkipFirst; #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version if(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) cgflags |= kCGBitmapByteOrder32Host; #endif #else CGImageAlphaInfo cgflags = kCGImageAlphaNoneSkipFirst; #endif CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(), 8, im.bytesPerLine(), colorspace, cgflags); CGColorSpaceRelease(colorspace); CGContextSetFontSize(ctx, fontDef.pixelSize); CGContextSetShouldAntialias(ctx, fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias)); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0); CGAffineTransformConcat(cgMatrix, oldTextMatrix); if (synthesisFlags & QFontEngine::SynthesizedItalic) cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0)); cgMatrix = CGAffineTransformConcat(cgMatrix, multiEngine->transform); CGContextSetTextMatrix(ctx, cgMatrix); CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); CGContextSetTextDrawingMode(ctx, kCGTextFill); CGContextSetFont(ctx, cgFont); qreal pos_x = -br.x.toReal()+1, pos_y = im.height()+br.y.toReal(); CGContextSetTextPosition(ctx, pos_x, pos_y); CGSize advance; advance.width = 0; advance.height = 0; CGGlyph cgGlyph = glyph; CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1); if (synthesisFlags & QFontEngine::SynthesizedBold) { CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y); CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1); } CGContextRelease(ctx); QImage indexed(im.width(), im.height(), QImage::Format_Indexed8); QVector<QRgb> colors(256); for (int i=0; i<256; ++i) colors[i] = qRgba(0, 0, 0, i); indexed.setColorTable(colors); for (int y=0; y<im.height(); ++y) { uint *src = (uint*) im.scanLine(y); uchar *dst = indexed.scanLine(y); for (int x=0; x<im.width(); ++x) { *dst = qGray(*src); ++dst; ++src; } } return indexed; }
void map_text(MapGC *mgc, MapSettings *settings, int x, int y, const char *text, int style) { if (FALSE); #ifdef HAVE_CAIRO else if (mgc->cairo_cr) { int xpos = x; int ypos = y; cairo_text_extents_t extents; cairo_select_font_face(mgc->cairo_cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); if (style & 0x800) { if (settings->pdamode) cairo_set_font_size(mgc->cairo_cr, 9); else cairo_set_font_size(mgc->cairo_cr, 14); } else { if (settings->pdamode) cairo_set_font_size(mgc->cairo_cr, 8); else cairo_set_font_size(mgc->cairo_cr, 11); } cairo_text_extents(mgc->cairo_cr, text, &extents); if ((style & 0x300) == 0x100) { xpos -= extents.width; } else if ((style & 0x300) == 0x200) { xpos -= extents.width / 2; } else if ((style & 0x300) == 0x300) { xpos -= extents.width / 2; ypos -= extents.height / 2; } if (style & 0x400) map_bkg_rectangle(mgc, settings, xpos, ypos, extents.width, extents.height); if (style & 1) cairo_set_source_rgb(mgc->cairo_cr, 0, 0, 1); else cairo_set_source_rgb(mgc->cairo_cr, 0, 0, 0); cairo_move_to(mgc->cairo_cr, xpos, ypos + extents.height); cairo_show_text(mgc->cairo_cr, text); } #endif #ifdef HAVE_GTK else if (mgc->gtk_drawable) { int xpos = x; int ypos = y; int width; int height; PangoFontDescription *fd; PangoLayout *layout = gtk_widget_create_pango_layout(mgc->gtk_widget, text); if (style & 0x800) { if (settings->pdamode) fd = pango_font_description_from_string("Sans 9"); else fd = pango_font_description_from_string("Sans 14"); } else { if (settings->pdamode) fd = pango_font_description_from_string("Sans 8"); else fd = pango_font_description_from_string("Sans 11"); } pango_layout_set_font_description(layout, fd); pango_layout_get_pixel_size(layout, &width, &height); if ((style & 0x300) == 0x100) { xpos -= width; } else if ((style & 0x300) == 0x200) { xpos -= width / 2; } else if ((style & 0x300) == 0x300) { xpos -= width / 2; ypos -= height / 2; } if (style & 0x400) map_bkg_rectangle(mgc, settings, xpos, ypos, width, height); if (style & 1) gdk_draw_layout_with_colors(mgc->gtk_drawable, mgc->gtk_gc, xpos, ypos, layout, &settings->blue, NULL); else gdk_draw_layout_with_colors(mgc->gtk_drawable, mgc->gtk_gc, xpos, ypos, layout, &settings->black, NULL); if (layout != NULL) g_object_unref(G_OBJECT(layout)); pango_font_description_free(fd); } #endif #ifdef HAVE_QT else if (mgc->qt_painter) { qt_text(mgc->qt_painter, settings, x, y, text, style); } #endif #ifdef HAVE_QUARTZ else if (mgc->quartz_gc) { int xpos = x; int ypos = y; int width; int height; CGContextSelectFont(mgc->quartz_gc, "Verdana", 8, kCGEncodingMacRoman); if (style & 0x800) { if (settings->pdamode) CGContextSetFontSize(mgc->quartz_gc, 9); else CGContextSetFontSize(mgc->quartz_gc, 14); } else { if (settings->pdamode) CGContextSetFontSize(mgc->quartz_gc, 8); else CGContextSetFontSize(mgc->quartz_gc, 11); } { CGPoint oldPos = CGContextGetTextPosition(mgc->quartz_gc); CGContextSetTextDrawingMode(mgc->quartz_gc, kCGTextInvisible); CGContextShowText(mgc->quartz_gc, text, strlen(text)); CGPoint newPos = CGContextGetTextPosition(mgc->quartz_gc); CGContextSetTextDrawingMode(mgc->quartz_gc, kCGTextFill); CGContextSetTextPosition(mgc->quartz_gc, oldPos.x, oldPos.y); width = newPos.x - oldPos.x; } if ((style & 0x300) == 0x100) { xpos -= width; } else if ((style & 0x300) == 0x200) { xpos -= width / 2; } else if ((style & 0x300) == 0x300) { xpos -= width / 2; ypos -= height / 2; } if (style & 0x400) map_bkg_rectangle(mgc, settings, xpos, ypos, width, height); if (style & 1) CGContextSetRGBStrokeColor(mgc->quartz_gc, 0, 0, 1, 1); else CGContextSetRGBStrokeColor(mgc->quartz_gc, 0, 0, 0, 1); CGContextSetTextPosition(mgc->quartz_gc, xpos, ypos); CGContextShowText(mgc->quartz_gc, text, strlen(text)); } #endif #ifdef WIN32 else if (mgc->win_dc) { int xpos = x; int ypos = y; int fontSize; HFONT oldFont; HFONT font; SIZE textSize; if (style & 0x800) { if (settings->pdamode) fontSize = 9; else fontSize = 14; } else { if (settings->pdamode) fontSize = 8; else fontSize = 11; } fontSize = fontSize * 3 / 2; font = CreateFont(fontSize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "MSSansSerif"); oldFont = SelectObject(mgc->win_dc, font); GetTextExtentPoint32(mgc->win_dc, text, strlen(text), &textSize); if ((style & 0x300) == 0x100) { xpos -= textSize.cx; } else if ((style & 0x300) == 0x200) { xpos -= textSize.cx / 2; } else if ((style & 0x300) == 0x300) { xpos -= textSize.cx / 2; ypos -= textSize.cy / 2; } if (style & 0x400) map_bkg_rectangle(mgc, settings, xpos, ypos, textSize.cx, textSize.cy); if (style & 1) SetTextColor(mgc->win_dc, RGB(0x00, 0x00, 0xff)); else SetTextColor(mgc->win_dc, RGB(0x00, 0x00, 0x00)); SetBkMode(mgc->win_dc, TRANSPARENT); TextOut(mgc->win_dc, xpos, ypos, text, strlen(text)); SelectObject(mgc->win_dc, oldFont); DeleteObject(font); } #endif }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = graphicsContext->platformContext(); bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); if (font->platformData().useGDI()) { static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs(); if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) { drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); return; } } uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); const FontPlatformData& platformData = font->platformData(); CGContextSetFont(cgContext, platformData.cgFont()); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; if (platformData.syntheticOblique()) { static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f); matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); } CGContextSetTextMatrix(cgContext, matrix); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); CGContextSetFontSize(cgContext, platformData.size()); wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI()); IntSize shadowSize; int shadowBlur; Color shadowColor; graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor); bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); graphicsContext->setFillColor(shadowFillColor); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->m_syntheticBoldOffset) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } graphicsContext->setFillColor(fillColor); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->m_syntheticBoldOffset) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } if (hasSimpleShadow) graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); }
bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) { UniChar uni_char; CGGlyph glyph; CTFontRef ct_font = (CTFontRef)font; const CFIndex count = 1; CGRect bounding_rect, success_rect; CGContextRef context_ref; if( chnum == ' ' ) { uni_char = 'n'; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); uni_char = chnum; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); } else { uni_char = chnum; CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); } if( CGRectEqualToRect( success_rect, CGRectNull ) == false ) { size_t bitmap_width; size_t bitmap_height; bitmap_width = ceilf(bounding_rect.size.width * EXTRA_WIDTH); bitmap_width = bitmap_width == 0 ? 1 : bitmap_width; bitmap_height = ceilf( (CTFontGetAscent(ct_font) + CTFontGetDescent(ct_font) + CTFontGetLeading(ct_font)) * EXTRA_HEIGHT); xoffs = yoffs = 0; width = bitmap_width; size_t bits_per_component; CGColorSpaceRef color_space; CGBitmapInfo bitmap_info = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; color_space = CGColorSpaceCreateDeviceRGB(); bits_per_component = 8; bitmap.allocate(bitmap_width, bitmap_height); context_ref = CGBitmapContextCreate( bitmap.raw_pixptr(0), bitmap_width, bitmap_height, bits_per_component, bitmap.rowpixels()*4, color_space, bitmap_info ); if( context_ref != NULL ) { CGFontRef font_ref; font_ref = CTFontCopyGraphicsFont( ct_font, NULL ); CGContextSetTextPosition(context_ref, -bounding_rect.origin.x*EXTRA_WIDTH, CTFontGetDescent(ct_font)+CTFontGetLeading(ct_font) ); CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0); CGContextSetFont( context_ref, font_ref ); CGContextSetFontSize( context_ref, POINT_SIZE ); CGContextShowGlyphs( context_ref, &glyph, count ); CGFontRelease( font_ref ); CGContextRelease( context_ref ); } CGColorSpaceRelease( color_space ); } return bitmap.valid(); }
static void fontheight(XFont *f, int size, int *height, int *ascent) { int i; CFStringRef s; CGRect bbox; CTFontRef font; CTFontDescriptorRef desc; CGContextRef ctxt; CGColorSpaceRef color; s = c2mac(f->name); desc = CTFontDescriptorCreateWithNameAndSize(s, size); CFRelease(s); if(desc == nil) return; font = CTFontCreateWithFontDescriptor(desc, 0, nil); CFRelease(desc); if(font == nil) return; color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone); CGColorSpaceRelease(color); CGContextSetTextPosition(ctxt, 0, 0); for(i=0; i<nelem(lines); i++) { CFStringRef keys[] = { kCTFontAttributeName }; CFTypeRef values[] = { font }; CFStringRef str; CFDictionaryRef attrs; CFAttributedStringRef attrString; CGRect r; CTLineRef line; str = c2mac(lines[i]); // See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2 attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs); CFRelease(str); CFRelease(attrs); line = CTLineCreateWithAttributedString(attrString); r = CTLineGetImageBounds(line, ctxt); r.size.width += r.origin.x; r.size.height += r.origin.y; CFRelease(line); // fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height); if(i == 0) bbox = r; if(bbox.origin.x > r.origin.x) bbox.origin.x = r.origin.x; if(bbox.origin.y > r.origin.y) bbox.origin.y = r.origin.y; if(bbox.size.width < r.size.width) bbox.size.width = r.size.width; if(bbox.size.height < r.size.height) bbox.size.height = r.size.height; } bbox.size.width -= bbox.origin.x; bbox.size.height -= bbox.origin.y; *height = bbox.size.height + 0.999999; *ascent = *height - (-bbox.origin.y + 0.999999); CGContextRelease(ctxt); CFRelease(font); }