/* Copyright (C) 2003-2013 Runtime Revolution Ltd.
This file is part of LiveCode.
LiveCode is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License v3 as published by the Free
Software Foundation.
LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with LiveCode. If not see . */
#include "globdefs.h"
#include "filedefs.h"
#include "parsedef.h"
#include "objdefs.h"
#include "execpt.h"
#include "util.h"
#include "globals.h"
#include "osspec.h"
#include "prefix.h"
#ifdef TARGET_SUBPLATFORM_IPHONE
#import
#else
#import
#endif
#ifdef TARGET_SUBPLATFORM_IPHONE
// Stored as a global variable
static MCArrayRef s_font_map = nil;
// Populate the VariableArray s_font_map
// from the input mapping list (=).
// Each is storred keyed as
void add_ios_fontmap(const char* p_mapping)
{
if (s_font_map == nil)
{
if (!MCArrayCreateMutable(s_font_map))
return;
}
MCAutoStringRef t_mapping;
if (!MCStringCreateWithCString(p_mapping, &t_mapping))
return;
uindex_t t_separator;
if (!MCStringFirstIndexOfChar(*t_mapping, '=', 0, kMCStringOptionCompareExact, t_separator))
return;
MCAutoStringRef t_from, t_to;
MCNewAutoNameRef t_from_as_name;
if (!MCStringCopySubstring(*t_mapping, MCRangeMake(0, t_separator), &t_from)
|| !MCNameCreate(*t_from, &t_from_as_name)
|| !MCStringCopySubstring(*t_mapping, MCRangeMake(t_separator + 1, UINDEX_MAX), &t_to))
return;
MCArrayStoreValue(s_font_map, false, *t_from_as_name, *t_to);
}
void ios_clear_font_mapping(void)
{
if (s_font_map != nil)
{
MCValueRelease(s_font_map);
s_font_map = nil;
}
}
#endif
static void *coretext_font_create_with_name_and_size(MCStringRef p_name, uint32_t p_size)
{
/*CFStringRef t_name;
t_name = CFStringCreateWithCString(NULL, p_name, kCFStringEncodingMacRoman);
CTFontRef t_font;
t_font = NULL;
if (t_name != NULL)
{
t_font = CTFontCreateWithName(t_name, p_size, NULL);
CFRelease(t_name);
}
return (void *)t_font;*/
bool t_success;
t_success = true;
// SN-2015-02-16: [[ iOS Font mapping ]] On iOS, try to fetch the mapped
// if one exists.
// Defaults to the given name if no one matches, or on MacOS
MCAutoStringRef t_mapped_name;
#ifdef TARGET_SUBPLATFORM_IPHONE
if (t_success && s_font_map != nil)
{
MCValueRef t_entry;
MCNewAutoNameRef t_mapped_name_as_name;
// SN-2015-04-29: [[ iOS Fontmap ]] Use the given name, if we can't
// fetch it from the font mappings.
if (MCNameCreate(p_name, &t_mapped_name_as_name)
&& MCArrayFetchValue(s_font_map, false, *t_mapped_name_as_name, t_entry))
// We only store strings in s_font_map
t_mapped_name = (MCStringRef)t_entry;
else
t_mapped_name = p_name;
}
else
#endif
t_mapped_name = p_name;
MCAutoStringRefAsCFString t_cf_name;
t_success = t_cf_name . Lock(*t_mapped_name);
CFDictionaryRef t_attributes;
t_attributes = NULL;
if (t_success)
{
// MW-2014-07-23: [[ Bug 12426 ]] Only specify the 'name' attribute in the font descriptor
// otherwise things don't work correctly on iOS. It seems going via a descriptor stops
// the warning on 10.9.
//
// Updated the font creation routine to use font descriptors. Though CTFontCreateWithName worked,
// it logged warnings (on 10.9) whenever it was passed a non-postscript font name. Hopefully using
// the display name first in the descriptor will remove the warnings but still keep the fall back behaviour.
CFStringRef t_keys[] =
{
// kCTFontDisplayNameAttribute,
kCTFontNameAttribute,
// kCTFontFamilyNameAttribute,
};
CFTypeRef t_values[] = {
//*t_cf_name,
*t_cf_name,
//*t_cf_name,
};
t_attributes = CFDictionaryCreate(NULL,
(const void **)&t_keys, (const void **)&t_values,
sizeof(t_keys) / sizeof(t_keys[0]),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
t_success = t_attributes != NULL;
}
CTFontDescriptorRef t_descriptor;
t_descriptor = NULL;
if (t_success)
{
t_descriptor = CTFontDescriptorCreateWithAttributes(t_attributes);
t_success = t_descriptor != NULL;
}
CTFontRef t_font;
t_font = NULL;
if (t_success)
t_font = CTFontCreateWithFontDescriptor(t_descriptor, p_size, NULL);
if (t_descriptor != NULL)
CFRelease(t_descriptor);
if (t_attributes != NULL)
CFRelease(t_attributes);
return (void *)t_font;
}
void *coretext_font_create_with_name_size_and_style(MCStringRef p_name, uint32_t p_size, bool p_bold, bool p_italic)
{
/*bool t_success;
t_success = true;
CFStringRef t_name;
t_name = NULL;
if (t_success)
{
t_name = CFStringCreateWithCString(NULL, p_name, kCFStringEncodingMacRoman);
t_success = t_name != NULL;
}
CFDictionaryRef t_styles;
t_styles = NULL;
if (t_success)
{
CTFontSymbolicTraits t_symbolic_traits;
t_symbolic_traits = 0;
if (p_bold)
t_symbolic_traits |= kCTFontBoldTrait;
if (p_italic)
t_symbolic_traits |= kCTFontItalicTrait;
CFNumberRef t_cfnumber_symbolic_traits;
t_cfnumber_symbolic_traits = NULL;
t_cfnumber_symbolic_traits = CFNumberCreate(NULL, kCFNumberIntType, &t_symbolic_traits);
if (t_cfnumber_symbolic_traits != NULL)
{
CFStringRef t_keys[] =
{
kCTFontSymbolicTrait,
};
CFTypeRef t_values[] = {
t_cfnumber_symbolic_traits,
};
t_styles = CFDictionaryCreate(NULL,
(const void **)&t_keys, (const void **)&t_values,
sizeof(t_keys) / sizeof(t_keys[0]),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(t_cfnumber_symbolic_traits);
}
t_success = t_styles != NULL;
}
CFDictionaryRef t_attributes;
t_attributes = NULL;
if (t_success)
{
CFStringRef t_keys[] =
{
kCTFontNameAttribute,
kCTFontTraitsAttribute,
};
CFTypeRef t_values[] = {
t_name,
t_styles,
};
t_attributes = CFDictionaryCreate(NULL,
(const void **)&t_keys, (const void **)&t_values,
sizeof(t_keys) / sizeof(t_keys[0]),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
t_success = t_attributes != NULL;
}
CTFontDescriptorRef t_descriptor;
t_descriptor = NULL;
if (t_success)
{
t_descriptor = CTFontDescriptorCreateWithAttributes(t_attributes);
t_success = t_descriptor != NULL;
}
CTFontRef t_font;
t_font = NULL;
if (t_success)
t_font = CTFontCreateWithFontDescriptor(t_descriptor, p_size, NULL);
if (t_descriptor != NULL)
CFRelease(t_descriptor);
if (t_attributes != NULL)
CFRelease(t_attributes);
if (t_styles != NULL)
CFRelease(t_styles);
if (t_name != NULL)
CFRelease(t_name);
return (void *)t_font;*/
CTFontRef t_base_font;
t_base_font = (CTFontRef)coretext_font_create_with_name_and_size(p_name, p_size);
CTFontRef t_font;
t_font = NULL;
if (p_bold && p_italic)
t_font = CTFontCreateCopyWithSymbolicTraits(t_base_font, p_size, NULL, kCTFontBoldTrait | kCTFontItalicTrait, kCTFontBoldTrait | kCTFontItalicTrait);
if (t_font == NULL && p_bold)
t_font = CTFontCreateCopyWithSymbolicTraits(t_base_font, p_size, NULL, kCTFontBoldTrait, kCTFontBoldTrait);
if (t_font == NULL && p_italic)
t_font = CTFontCreateCopyWithSymbolicTraits(t_base_font, p_size, NULL, kCTFontItalicTrait, kCTFontItalicTrait);
if (t_font == NULL)
t_font = t_base_font;
if (t_font != t_base_font && t_base_font != NULL)
CFRelease(t_base_font);
return (void *)t_font;
}
bool coretext_font_destroy(void *p_font)
{
if (p_font != NULL)
CFRelease((CTFontRef) p_font);
return true;
}
bool coretext_font_get_metrics(void *p_font, float& r_ascent, float& r_descent, float& r_leading, float& r_xheight)
{
r_ascent = CTFontGetAscent((CTFontRef) p_font);
r_descent = CTFontGetDescent((CTFontRef) p_font);
r_leading = CTFontGetLeading((CTFontRef) p_font);
r_xheight = CTFontGetXHeight((CTFontRef) p_font);
return true;
}
bool coretext_get_font_names(MCListRef &r_names)
{
CTFontCollectionRef t_fonts;
t_fonts = CTFontCollectionCreateFromAvailableFonts(NULL);
CFArrayRef t_descriptors;
t_descriptors = CTFontCollectionCreateMatchingFontDescriptors(t_fonts);
MCAutoListRef t_names;
MCListCreateMutable('\n', &t_names);
char t_cstring_font_name[256];
bool t_success;
t_success = true;
for(CFIndex i = 0; t_success && i < CFArrayGetCount(t_descriptors); i++)
{
CTFontDescriptorRef t_font;
t_font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(t_descriptors, i);
CFStringRef t_font_name;
t_font_name = (CFStringRef)CTFontDescriptorCopyAttribute(t_font, kCTFontDisplayNameAttribute);
if (t_font_name != NULL && CFStringGetCString(t_font_name, t_cstring_font_name, 256, kCFStringEncodingMacRoman) &&
t_cstring_font_name[0] != '%' && t_cstring_font_name[0] != '.')
t_success = MCListAppendCString(*t_names, t_cstring_font_name);
if (t_font_name != NULL)
CFRelease(t_font_name);
}
if (t_descriptors != NULL)
CFRelease(t_descriptors);
if (t_fonts != NULL)
CFRelease(t_fonts);
if (t_success)
t_success = MCListCopy(*t_names, r_names);
return t_success;
}
bool core_text_get_font_styles(MCStringRef p_name, uint32_t p_size, MCListRef &r_styles)
{
CTFontRef t_font_family;
t_font_family = (CTFontRef)coretext_font_create_with_name_and_size(p_name, p_size);
MCAutoListRef t_styles;
/* UNCHECKED */ MCListCreateMutable('\n', &t_styles);
bool t_success;
t_success = true;
if (t_font_family != NULL)
{
CTFontSymbolicTraits t_traits;
t_traits = CTFontGetSymbolicTraits(t_font_family);
t_success = MCListAppendCString(*t_styles, "plain");
if (t_success && t_traits & kCTFontBoldTrait)
t_success = MCListAppendCString(*t_styles, "bold");
if (t_success && t_traits & kCTFontItalicTrait)
t_success = MCListAppendCString(*t_styles, "italic");
if (t_success && t_traits & kCTFontBoldTrait && t_traits & kCTFontItalicTrait)
t_success = MCListAppendCString(*t_styles, "bold-italic");
}
if (t_font_family != NULL)
CFRelease(t_font_family);
if (t_success)
t_success = MCListCopy(*t_styles, r_styles);
return t_success;
}
bool coretext_font_load_from_path(MCStringRef p_path, bool p_globally)
{
bool t_success;
t_success = true;
MCAutoStringRefAsCFString t_cf_path;
t_success = t_cf_path . Lock(p_path);
CFURLRef t_font_url;
t_font_url = NULL;
if (t_success)
{
t_font_url = CFURLCreateWithFileSystemPath(NULL, *t_cf_path, kCFURLPOSIXPathStyle, false);
t_success = t_font_url != NULL;
}
if (t_success)
{
CTFontManagerScope t_scope;
if (p_globally)
t_scope = kCTFontManagerScopeUser;
else
t_scope = kCTFontManagerScopeProcess;
t_success = CTFontManagerRegisterFontsForURL(t_font_url, t_scope, NULL);
}
if (t_font_url != NULL)
CFRelease(t_font_url);
return t_success;
}
bool coretext_font_unload(MCStringRef p_path, bool p_globally)
{
bool t_success;
t_success = true;
MCAutoStringRefAsCFString t_cf_path;
t_success = t_cf_path . Lock(p_path);
CFURLRef t_font_url;
t_font_url = NULL;
if (t_success)
{
t_font_url = CFURLCreateWithFileSystemPath(NULL, *t_cf_path, kCFURLPOSIXPathStyle, false);
t_success = t_font_url != NULL;
}
if (t_success)
{
CTFontManagerScope t_scope;
if (p_globally)
t_scope = kCTFontManagerScopeUser;
else
t_scope = kCTFontManagerScopeProcess;
t_success = CTFontManagerUnregisterFontsForURL(t_font_url, t_scope, NULL);
}
if (t_font_url != NULL)
CFRelease(t_font_url);
return t_success;
}
void coretext_get_font_name(void *p_font, MCNameRef& r_name)
{
CFStringRef t_font_name;
t_font_name = CTFontCopyDisplayName((CTFontRef)p_font);
MCAutoStringRef t_font_name_string;
MCStringCreateWithCFString(t_font_name, &t_font_name_string);
MCNameCreate(*t_font_name_string, r_name);
}
uint32_t coretext_get_font_size(void *p_font)
{
return CTFontGetSize((CTFontRef)p_font);
}
#ifdef _MACOSX
ATSUFontID coretext_font_to_atsufontid(void *p_font)
{
bool t_success;
t_success = true;
CTFontRef t_ctfont;
t_ctfont = NULL;
if (t_success)
{
t_ctfont = (CTFontRef)p_font;
t_success = t_ctfont != NULL;
}
char t_name[256];
if (t_success)
{
CFStringRef t_cfname;
t_cfname = CTFontCopyPostScriptName(t_ctfont);
t_success = t_cfname != NULL && CFStringGetCString(t_cfname, t_name, 256, kCFStringEncodingMacRoman);
if (t_cfname != NULL)
CFRelease(t_cfname);
}
ATSUFontID t_font_id;
t_font_id = 0;
if (t_success)
{
uint32_t t_name_length;
t_name_length = MCCStringLength(t_name);
t_success = ATSUFindFontFromName(t_name, t_name_length, kFontPostscriptName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr;
}
return t_font_id;
}
#endif