bool coretext_font_get_metrics(void *p_font, float& r_ascent, float& r_descent) { r_ascent = CTFontGetAscent((CTFontRef) p_font); r_descent = CTFontGetDescent((CTFontRef) p_font); return true; }
static PangoFontMetrics * pango_cairo_core_text_font_create_base_metrics_for_context (PangoCairoFont *font, PangoContext *context) { PangoCoreTextFont *cfont = (PangoCoreTextFont *) font; PangoFontMetrics *metrics; PangoFontDescription *font_desc; PangoLayout *layout; PangoRectangle extents; PangoLanguage *language = pango_context_get_language (context); const char *sample_str = pango_language_get_sample_string (language); CTFontRef ctfont; metrics = pango_font_metrics_new (); ctfont = pango_core_text_font_get_ctfont (cfont); metrics->ascent = CTFontGetAscent (ctfont) * PANGO_SCALE; metrics->descent = CTFontGetDescent (ctfont) * PANGO_SCALE; metrics->underline_position = CTFontGetUnderlinePosition (ctfont) * PANGO_SCALE; metrics->underline_thickness = CTFontGetUnderlineThickness (ctfont) * PANGO_SCALE; metrics->strikethrough_position = metrics->ascent / 3; metrics->strikethrough_thickness = CTFontGetUnderlineThickness (ctfont) * PANGO_SCALE; layout = pango_layout_new (context); font_desc = pango_font_describe_with_absolute_size ((PangoFont *) font); pango_layout_set_font_description (layout, font_desc); pango_layout_set_text (layout, sample_str, -1); pango_layout_get_extents (layout, NULL, &extents); metrics->approximate_char_width = extents.width / pango_utf8_strwidth (sample_str); pango_layout_set_text (layout, "0123456789", -1); metrics->approximate_digit_width = max_glyph_width (layout); pango_font_description_free (font_desc); g_object_unref (layout); return metrics; }
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(); }
void sdl_osd_interface::init(running_machine &machine) { // call our parent osd_interface::init(machine); sdl_options &options = downcast<sdl_options &>(machine.options()); const char *stemp; // Switchres if (machine.options().modeline()) switchres_modeline_setup(machine); // determine if we are benchmarking, and adjust options appropriately int bench = options.bench(); astring error_string; if (bench > 0) { options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(OPTION_SOUND, false, OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(SDLOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string); options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string); assert(!error_string); } // Some driver options - must be before audio init! stemp = options.audio_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp); osd_setenv(SDLENV_AUDIODRIVER, stemp, 1); } stemp = options.video_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp); osd_setenv(SDLENV_VIDEODRIVER, stemp, 1); } #if (SDLMAME_SDL2) stemp = options.render_driver(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { mame_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp); //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1); SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp); } #endif /* Set the SDL environment variable for drivers wanting to load the * lib at startup. */ #if USE_OPENGL /* FIXME: move lib loading code from drawogl.c here */ stemp = options.gl_lib(); if (stemp != NULL && strcmp(stemp, SDLOPTVAL_AUTO) != 0) { osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1); mame_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp); } #endif /* get number of processors */ stemp = options.numprocessors(); osd_num_processors = 0; if (strcmp(stemp, "auto") != 0) { osd_num_processors = atoi(stemp); if (osd_num_processors < 1) { mame_printf_warning("Warning: numprocessors < 1 doesn't make much sense. Assuming auto ...\n"); osd_num_processors = 0; } } /* Initialize SDL */ if (!SDLMAME_INIT_IN_WORKER_THREAD) { #if (SDLMAME_SDL2) if (SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE)) { #else if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE)) { #endif mame_printf_error("Could not initialize SDL %s\n", SDL_GetError()); exit(-1); } osd_sdl_info(); } // must be before sdlvideo_init! machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(osd_exit), &machine)); defines_verbose(); if (!SDLMAME_HAS_DEBUGGER) if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED) { mame_printf_error("sdlmame: -debug not supported on X11-less builds\n\n"); osd_exit(machine); exit(-1); } if (sdlvideo_init(machine)) { osd_exit(machine); mame_printf_error("sdlvideo_init: Initialization failed!\n\n\n"); fflush(stderr); fflush(stdout); exit(-1); } sdlinput_init(machine); sdlaudio_init(machine); sdloutput_init(machine); #ifdef SDLMAME_NETWORK sdlnetdev_init(machine); #endif if (options.oslog()) machine.add_logerror_callback(output_oslog); /* now setup watchdog */ int watchdog_timeout = options.watchdog(); int str = options.seconds_to_run(); /* only enable watchdog if seconds_to_run is enabled *and* relatively short (time taken from ui.c) */ if ((watchdog_timeout != 0) && (str > 0) && (str < 60*5 )) { m_watchdog = auto_alloc(machine, watchdog); m_watchdog->setTimeout(watchdog_timeout); } #if (SDLMAME_SDL2) SDL_EventState(SDL_TEXTINPUT, SDL_TRUE); #else SDL_EnableUNICODE(SDL_TRUE); #endif } #ifdef SDLMAME_UNIX #define POINT_SIZE 144.0 #ifdef SDLMAME_MACOSX #define EXTRA_HEIGHT 1.0 #define EXTRA_WIDTH 1.15 //------------------------------------------------- // font_open - attempt to "open" a handle to the // font with the given name //------------------------------------------------- osd_font sdl_osd_interface::font_open(const char *_name, int &height) { CFStringRef font_name = NULL; CTFontRef ct_font = NULL; CTFontDescriptorRef font_descriptor; CGAffineTransform affine_transform = CGAffineTransformIdentity; astring name(_name); if (name == "default") { name = "LucidaGrande"; } /* handle bdf fonts in the core */ if (name.len() > 4) if (name.makeupper().substr(name.len()-4,4) == ".BDF" ) return NULL; font_name = CFStringCreateWithCString( NULL, _name, kCFStringEncodingUTF8 ); if( font_name != NULL ) { font_descriptor = CTFontDescriptorCreateWithNameAndSize( font_name, POINT_SIZE ); if( font_descriptor != NULL ) { ct_font = CTFontCreateWithFontDescriptor( font_descriptor, POINT_SIZE, &affine_transform ); CFRelease( font_descriptor ); } } CFRelease( font_name ); if (!ct_font) { printf("WARNING: Couldn't find/open font %s, using MAME default\n", name.cstr()); return NULL; } CFStringRef real_name = CTFontCopyPostScriptName( ct_font ); char real_name_c_string[255]; CFStringGetCString ( real_name, real_name_c_string, 255, kCFStringEncodingUTF8 ); mame_printf_verbose("Matching font: %s\n", real_name_c_string); CFRelease( real_name ); CGFloat line_height = 0.0; line_height += CTFontGetAscent(ct_font); line_height += CTFontGetDescent(ct_font); line_height += CTFontGetLeading(ct_font); height = ceilf(line_height * EXTRA_HEIGHT); return (osd_font)ct_font; }
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; }
CPDF_Font* CPDF_Document::AddMacFont(CTFontRef pFont, FX_BOOL bVert, FX_BOOL bTranslateName) { CTFontRef font = (CTFontRef)pFont; CTFontDescriptorRef descriptor = CTFontCopyFontDescriptor(font); if (descriptor == NULL) { return NULL; } CFX_ByteString basefont; FX_BOOL bCJK = FALSE; int flags = 0, italicangle = 0, ascend = 0, descend = 0, capheight = 0, bbox[4]; FXSYS_memset32(bbox, 0, sizeof(int) * 4); CFArrayRef languages = (CFArrayRef)CTFontDescriptorCopyAttribute(descriptor, kCTFontLanguagesAttribute); if (languages == NULL) { CFRelease(descriptor); return NULL; } CFX_DWordArray charSets; charSets.Add(FXFONT_CHINESEBIG5_CHARSET); charSets.Add(FXFONT_GB2312_CHARSET); charSets.Add(FXFONT_HANGEUL_CHARSET); charSets.Add(FXFONT_SHIFTJIS_CHARSET); if (IsHasCharSet(languages, charSets)) { bCJK = TRUE; } CFRelease(descriptor); CFDictionaryRef traits = (CFDictionaryRef)CTFontCopyTraits(font); if (traits == NULL) { CFRelease(languages); return NULL; } CFNumberRef sybolicTrait = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait); CTFontSymbolicTraits trait = 0; CFNumberGetValue(sybolicTrait, kCFNumberSInt32Type, &trait); if (trait & kCTFontItalicTrait) { flags |= PDFFONT_ITALIC; } if (trait & kCTFontMonoSpaceTrait) { flags |= PDFFONT_FIXEDPITCH; } if (trait & kCTFontModernSerifsClass) { flags |= PDFFONT_SERIF; } if (trait & kCTFontScriptsClass) { flags |= PDFFONT_SCRIPT; } CFNumberRef weightTrait = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontWeightTrait); Float32 weight = 0; CFNumberGetValue(weightTrait, kCFNumberFloat32Type, &weight); italicangle = CTFontGetSlantAngle(font); ascend = CTFontGetAscent(font); descend = CTFontGetDescent(font); capheight = CTFontGetCapHeight(font); CGRect box = CTFontGetBoundingBox(font); bbox[0] = box.origin.x; bbox[1] = box.origin.y; bbox[2] = box.origin.x + box.size.width; bbox[3] = box.origin.y + box.size.height; if (bTranslateName && bCJK) { CFStringRef postName = CTFontCopyPostScriptName(font); _CFString2CFXByteString(postName, basefont); CFRelease(postName); } if (basefont.IsEmpty()) { CFStringRef fullName = CTFontCopyFullName(font); _CFString2CFXByteString(fullName, basefont); CFRelease(fullName); } basefont.Replace(" ", ""); CPDF_Dictionary* pFontDict = NULL; CPDF_Dictionary* pBaseDict = FX_NEW CPDF_Dictionary; pFontDict = pBaseDict; if (!bCJK) { charSets.RemoveAll(); charSets.Add(FXFONT_ANSI_CHARSET); charSets.Add(FXFONT_DEFAULT_CHARSET); charSets.Add(FXFONT_SYMBOL_CHARSET); if (IsHasCharSet(languages, charSets)) { charSets.RemoveAll(); charSets.Add(FXFONT_SYMBOL_CHARSET); if (IsHasCharSet(languages, charSets)) { flags |= PDFFONT_SYMBOLIC; } else { flags |= PDFFONT_NONSYMBOLIC; } pBaseDict->SetAtName(FX_BSTRC("Encoding"), "WinAnsiEncoding"); } else { flags |= PDFFONT_NONSYMBOLIC; int i; for (i = 0; i < sizeof g_FX_CharsetUnicodes / sizeof(FX_CharsetUnicodes); i ++) { charSets.RemoveAll(); charSets.Add(g_FX_CharsetUnicodes[i].m_Charset); if (IsHasCharSet(languages, charSets)) { break; } } if (i < sizeof g_FX_CharsetUnicodes / sizeof(FX_CharsetUnicodes)) { CPDF_Dictionary* pEncoding = FX_NEW CPDF_Dictionary; pEncoding->SetAtName(FX_BSTRC("BaseEncoding"), "WinAnsiEncoding"); CPDF_Array* pArray = FX_NEW CPDF_Array; pArray->AddInteger(128); const FX_WCHAR* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j ++) { CFX_ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); if (name.IsEmpty()) { pArray->AddName(FX_BSTRC(".notdef")); } else { pArray->AddName(name); } } pEncoding->SetAt(FX_BSTRC("Differences"), pArray); AddIndirectObject(pEncoding); pBaseDict->SetAtReference(FX_BSTRC("Encoding"), this, pEncoding); } } if (weight > 0.0 && trait & kCTFontItalicTrait) { basefont += ",BoldItalic"; } else if (weight > 0.0) { basefont += ",Bold"; } else if (trait & kCTFontItalicTrait) { basefont += ",Italic"; } pBaseDict->SetAtName("Subtype", "TrueType"); pBaseDict->SetAtName("BaseFont", basefont); pBaseDict->SetAtNumber("FirstChar", 32); pBaseDict->SetAtNumber("LastChar", 255); int char_widths[224]; FX_GetCharWidth(font, 32, 255, char_widths); CPDF_Array* pWidths = FX_NEW CPDF_Array; for (int i = 0; i < 224; i ++) { pWidths->AddInteger(char_widths[i]); } pBaseDict->SetAt("Widths", pWidths); } else { flags |= PDFFONT_NONSYMBOLIC; CPDF_Array* pArray = NULL; pFontDict = FX_NEW CPDF_Dictionary; CFX_ByteString cmap; CFX_ByteString ordering; int supplement; FX_BOOL bFound = FALSE; CPDF_Array* pWidthArray = FX_NEW CPDF_Array; charSets.RemoveAll(); charSets.Add(FXFONT_CHINESEBIG5_CHARSET); if (IsHasCharSet(languages, charSets)) { cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; pWidthArray->AddInteger(1); _InsertWidthArray(font, 0x20, 0x7e, pWidthArray); bFound = TRUE; } charSets.RemoveAll(); charSets.Add(FXFONT_GB2312_CHARSET); if (!bFound && IsHasCharSet(languages, charSets)) { cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H"; ordering = "GB1", supplement = 2; pWidthArray->AddInteger(7716); _InsertWidthArray(font, 0x20, 0x20, pWidthArray); pWidthArray->AddInteger(814); _InsertWidthArray(font, 0x21, 0x7e, pWidthArray); bFound = TRUE; } charSets.RemoveAll(); charSets.Add(FXFONT_HANGEUL_CHARSET); if (!bFound && IsHasCharSet(languages, charSets)) { cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; pWidthArray->AddInteger(1); _InsertWidthArray(font, 0x20, 0x7e, pWidthArray); bFound = TRUE; } charSets.RemoveAll(); charSets.Add(FXFONT_SHIFTJIS_CHARSET); if (!bFound && IsHasCharSet(languages, charSets)) { cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; pWidthArray->AddInteger(231); _InsertWidthArray(font, 0x20, 0x7d, pWidthArray); pWidthArray->AddInteger(326); _InsertWidthArray(font, 0xa0, 0xa0, pWidthArray); pWidthArray->AddInteger(327); _InsertWidthArray(font, 0xa1, 0xdf, pWidthArray); pWidthArray->AddInteger(631); _InsertWidthArray(font, 0x7e, 0x7e, pWidthArray); } pBaseDict->SetAtName("Subtype", "Type0"); pBaseDict->SetAtName("BaseFont", basefont); pBaseDict->SetAtName("Encoding", cmap); pFontDict->SetAt("W", pWidthArray); pFontDict->SetAtName("Type", "Font"); pFontDict->SetAtName("Subtype", "CIDFontType2"); pFontDict->SetAtName("BaseFont", basefont); CPDF_Dictionary* pCIDSysInfo = FX_NEW CPDF_Dictionary; pCIDSysInfo->SetAtString("Registry", "Adobe"); pCIDSysInfo->SetAtString("Ordering", ordering); pCIDSysInfo->SetAtInteger("Supplement", supplement); pFontDict->SetAt("CIDSystemInfo", pCIDSysInfo); pArray = FX_NEW CPDF_Array; pBaseDict->SetAt("DescendantFonts", pArray); AddIndirectObject(pFontDict); pArray->AddReference(this, pFontDict); } AddIndirectObject(pBaseDict); CPDF_Dictionary* pFontDesc = FX_NEW CPDF_Dictionary; pFontDesc->SetAtName("Type", "FontDescriptor"); pFontDesc->SetAtName("FontName", basefont); pFontDesc->SetAtInteger("Flags", flags); CPDF_Array* pBBox = FX_NEW CPDF_Array; for (int i = 0; i < 4; i ++) { pBBox->AddInteger(bbox[i]); } pFontDesc->SetAt("FontBBox", pBBox); pFontDesc->SetAtInteger("ItalicAngle", italicangle); pFontDesc->SetAtInteger("Ascent", ascend); pFontDesc->SetAtInteger("Descent", descend); pFontDesc->SetAtInteger("CapHeight", capheight); CGFloat fStemV = 0; int16_t min_width = SHRT_MAX; static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); CGGlyph glyphs[count]; CGRect boundingRects[count]; if (CTFontGetGlyphsForCharacters(font, stem_chars, glyphs, count)) { CTFontGetBoundingRectsForGlyphs(font, kCTFontHorizontalOrientation, glyphs, boundingRects, count); for (size_t i = 0; i < count; i++) { int16_t width = boundingRects[i].size.width; if (width > 0 && width < min_width) { min_width = width; fStemV = min_width; } } } pFontDesc->SetAtInteger("StemV", fStemV); AddIndirectObject(pFontDesc); pFontDict->SetAtReference("FontDescriptor", this, pFontDesc); CFRelease(traits); CFRelease(languages); return LoadFont(pBaseDict); }
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; }