Skip to content

Commit 0cc272e

Browse files
[[ iOS Font mapping ]] Added engine-side for font mapping on iOS
Providing the parameters in the standalone settings allow the engine to map custom font names to the PostScript fontnames. PostScript fontnames are needed on iOS 8.1, since loading a font may take up to 0.5 second otherwise
1 parent 0a4995c commit 0cc272e

File tree

7 files changed

+123
-9
lines changed

7 files changed

+123
-9
lines changed

engine/src/capsule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ enum MCCapsuleSectionType
9797
// Startup script to be executed after all stacks have loaded but before
9898
// the main stack is opened.
9999
kMCCapsuleSectionTypeStartupScript,
100+
101+
// Font mapping sections contain a mapping from a font name to another font
102+
// name (usually PostScript name). Whenever a font name is looked up it is
103+
// indirected through the font map first (and only once - not iteratively).
104+
kMCCapsuleSectionTypeFontmap,
100105
};
101106

102107
// Each section begins with a header that defines its type and length. This is

engine/src/coretextfonts.cpp

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "util.h"
2424
#include "globals.h"
2525
#include "osspec.h"
26+
#include "variable.h"
2627

2728
#include "prefix.h"
2829

@@ -32,6 +33,53 @@
3233
#import <ApplicationServices/ApplicationServices.h>
3334
#endif
3435

36+
#ifdef TARGET_SUBPLATFORM_IPHONE
37+
// Stored as a global variable
38+
static MCVariableArray *s_font_map = nil;
39+
40+
// Populate the VariableArray s_font_map
41+
// from the input mapping list (<mapped name>=<PostScript name>).
42+
// Each <PostScript name> is storred keyed as <mapped name>
43+
void add_ios_fontmap(const char *p_mapping)
44+
{
45+
if (s_font_map == nil)
46+
{
47+
s_font_map = new MCVariableArray;
48+
if (s_font_map == nil)
49+
return;
50+
s_font_map -> presethash(8);
51+
}
52+
53+
const char *t_separator;
54+
t_separator = strchr(p_mapping, '=');
55+
if (t_separator == nil)
56+
return;
57+
58+
MCString t_from, t_to;
59+
t_from . set(p_mapping, (uint4)(t_separator - p_mapping));
60+
61+
// Make sure we make the 'to' string a C-string (including the NUL terminator
62+
// in the size of the MCString).
63+
t_to . set(t_separator + 1, (uint4)strlen(t_separator + 1) + 1);
64+
65+
MCHashentry *t_entry;
66+
t_entry = s_font_map -> lookuphash(t_from, False, True);
67+
if (t_entry == nil)
68+
return;
69+
70+
t_entry -> value . assign_string(t_to);
71+
}
72+
73+
void ios_clear_font_mapping(void)
74+
{
75+
if (s_font_map != nil)
76+
{
77+
s_font_map -> freehash();
78+
delete s_font_map;
79+
}
80+
}
81+
#endif
82+
3583
static void *coretext_font_create_with_name_and_size(const char *p_name, uint32_t p_size)
3684
{
3785
/*CFStringRef t_name;
@@ -50,12 +98,32 @@ static void *coretext_font_create_with_name_and_size(const char *p_name, uint32_
5098

5199
bool t_success;
52100
t_success = true;
101+
102+
// SN-2015-02-16: [[ iOS Font mapping ]] On iOS, try to fetch the mapped
103+
// if one exists.
104+
// Defaults to the given name if no one matches, or on MacOS
105+
const char *t_mapped_name;
106+
t_mapped_name = p_name;
107+
108+
#ifdef TARGET_SUBPLATFORM_IPHONE
109+
if (t_success && s_font_map != nil)
110+
{
111+
MCHashentry *t_entry;
112+
t_entry = s_font_map -> lookuphash(p_name, False, False);
113+
114+
// We have constructed the s_font_map so that the values are C-strings,
115+
// thus we are okay to just used the 'getstring()' ptr here.
116+
if (t_entry != NULL)
117+
t_mapped_name = t_entry -> value . get_string() . getstring();
118+
}
119+
#endif
53120

54121
CFStringRef t_name;
55122
t_name = NULL;
56123
if (t_success)
57124
{
58-
t_name = CFStringCreateWithCString(NULL, p_name, kCFStringEncodingMacRoman);
125+
// SN-2015-02-16: [[ iOS Font mapping ]] Use the (maybe) mapped font name
126+
t_name = CFStringCreateWithCString(NULL, t_mapped_name, kCFStringEncodingMacRoman);
59127
t_success = t_name != NULL;
60128
}
61129

@@ -77,9 +145,9 @@ static void *coretext_font_create_with_name_and_size(const char *p_name, uint32_
77145
// kCTFontFamilyNameAttribute,
78146
};
79147
CFTypeRef t_values[] = {
148+
//t_name,
80149
t_name,
81-
t_name,
82-
t_name,
150+
// t_name,
83151
};
84152
t_attributes = CFDictionaryCreate(NULL,
85153
(const void **)&t_keys, (const void **)&t_values,
@@ -95,14 +163,12 @@ static void *coretext_font_create_with_name_and_size(const char *p_name, uint32_
95163
t_descriptor = CTFontDescriptorCreateWithAttributes(t_attributes);
96164
t_success = t_descriptor != NULL;
97165
}
98-
166+
99167
CTFontRef t_font;
100168
t_font = NULL;
101169
if (t_success)
102170
t_font = CTFontCreateWithFontDescriptor(t_descriptor, p_size, NULL);
103-
104-
CFStringRef t_font_name = CTFontCopyFullName(t_font);
105-
171+
106172
if (t_descriptor != NULL)
107173
CFRelease(t_descriptor);
108174
if (t_attributes != NULL)

engine/src/deploy.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ bool MCDeployWriteCapsule(const MCDeployParameters& p_params, MCDeployFileRef p_
143143
if (t_success)
144144
for(uint32_t i = 0; i < p_params . redirect_count && t_success; i++)
145145
t_success = MCDeployCapsuleDefine(t_capsule, kMCCapsuleSectionTypeRedirect, p_params . redirects[i], MCCStringLength(p_params . redirects[i]) + 1);
146+
147+
// Add any font mappings
148+
if (t_success)
149+
for(uint32_t i = 0; i < p_params . fontmapping_count && t_success; i++)
150+
t_success = MCDeployCapsuleDefine(t_capsule, kMCCapsuleSectionTypeFontmap, p_params . fontmappings[i], MCCStringLength(p_params . fontmappings[i]) + 1);
146151

147152
// Now we add the main stack
148153
if (t_success)
@@ -506,7 +511,10 @@ Exec_stat MCIdeDeploy::exec(MCExecPoint& ep)
506511
if (t_stat == ES_NORMAL)
507512
t_stat = fetch_opt_cstring(ep2, t_array, "startup_script", t_params . startup_script);
508513
if (t_stat == ES_NORMAL)
509-
t_stat = fetch_cstring_array(ep2, t_array, "redirects", t_params . redirects, t_params . redirect_count);
514+
t_stat = fetch_cstring_array(ep2, t_array, "redirects", t_params . redirects, t_params . redirect_count);
515+
// SN-2015-02-16: [[ iOS Font mapping ]] Read the fontmappings options from the deploy parameters.
516+
if (t_stat == ES_NORMAL)
517+
t_stat = fetch_cstring_array(ep2, t_array, "fontmappings", t_params . fontmappings, t_params . fontmapping_count);
510518

511519
if (t_stat == ES_NORMAL)
512520
t_stat = fetch_opt_filepath(ep2, t_array, "appicon", t_params . app_icon);

engine/src/deploy.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ struct MCDeployParameters
4949
// The list of redirection mappings
5050
char **redirects;
5151
uint32_t redirect_count;
52+
53+
// The list of font mappings
54+
char **fontmappings;
55+
uint32_t fontmapping_count;
5256

5357
// On Windows, the icon files to be inserted into the resource directory.
5458
char *app_icon;

engine/src/mbliphonedc.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@
6969
extern CGBitmapInfo MCGPixelFormatToCGBitmapInfo(uint32_t p_pixel_format, bool p_alpha);
7070
extern bool MCImageGetCGColorSpace(CGColorSpaceRef &r_colorspace);
7171

72+
// SN-2015-02-16: [[ iOS Font mapping ]] We want to clean the generated font map
73+
// when closing the engine.
74+
extern void ios_clear_font_mapping(void);
75+
7276
////////////////////////////////////////////////////////////////////////////////
7377

7478
Boolean tripleclick = False;
@@ -224,6 +228,8 @@ void MCIPhoneCallOnMainFiber(void (*handler)(void *), void *context)
224228

225229
Boolean MCScreenDC::close(Boolean p_force)
226230
{
231+
// SN-2015-02-16: [[ iOS Font Name ]] Clear the font mapping array.
232+
ios_clear_font_mapping();
227233
return True;
228234
}
229235

engine/src/mode_standalone.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ extern IO_stat readheader(IO_handle& stream, char *version);
120120
extern void send_startup_message(bool p_do_relaunch = true);
121121

122122
extern void add_simulator_redirect(const char *);
123+
extern void add_ios_fontmap(const char *);
123124

124125
// This structure contains the information we collect from reading in the
125126
// project.
@@ -177,7 +178,26 @@ bool MCStandaloneCapsuleCallback(void *p_self, const uint8_t *p_digest, MCCapsul
177178
delete t_redirect;
178179
}
179180
break;
180-
181+
182+
case kMCCapsuleSectionTypeFontmap:
183+
{
184+
char *t_fontmap;
185+
t_fontmap = new char[p_length];
186+
if (IO_read_bytes(t_fontmap, p_length, p_stream) != IO_NORMAL)
187+
{
188+
MCresult -> sets("failed to read fontmap");
189+
return false;
190+
}
191+
192+
#ifdef TARGET_SUBPLATFORM_IPHONE
193+
// The font mapping is only viable (and needed) on iOS
194+
add_ios_fontmap(t_fontmap);
195+
#endif
196+
197+
delete[] t_fontmap;
198+
}
199+
break;
200+
181201
case kMCCapsuleSectionTypeStack:
182202
if (MCdispatcher -> readstartupstack(p_stream, self -> stack) != IO_NORMAL)
183203
{

ide-support/revsaveasiosstandalone.livecodescript

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ private command revSaveAsMobileStandaloneMain pStack, pAppBundle, pTarget
499499
end if
500500
end if
501501

502+
-- SN-2015-02-16: [[ iOS Font Mapping ]] Set the font mapping list
503+
if tSettings["ios,font mapping file"] is not empty then
504+
put tSettings["ios,font mapping file"] into tDeploy["fontmappings"]
505+
end if
506+
502507
try
503508
_internal deploy ios tDeploy
504509
if the result is not empty then

0 commit comments

Comments
 (0)