2016-12-03 19:01:45 -06:00
|
|
|
// 3 december 2016
|
|
|
|
#import "uipriv_darwin.h"
|
|
|
|
|
|
|
|
// CFStringGetRangeOfComposedCharactersAtIndex() is the function for grapheme clusters
|
|
|
|
// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/stringsClusters.html says that this does work on all multi-codepoint graphemes (despite the name), and that this is the preferred function for this particular job anyway
|
|
|
|
|
|
|
|
int graphemesTakesUTF16(void)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct graphemes *graphemes(void *s, size_t len)
|
|
|
|
{
|
|
|
|
struct graphemes *g;
|
|
|
|
UniChar *str = (UniChar *) s;
|
2017-01-17 12:05:40 -06:00
|
|
|
CFStringRef cfstr;
|
2016-12-03 19:01:45 -06:00
|
|
|
size_t ppos, gpos;
|
|
|
|
CFRange range;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
g = uiNew(struct graphemes);
|
|
|
|
|
|
|
|
cfstr = CFStringCreateWithCharactersNoCopy(NULL, str, len, kCFAllocatorNull);
|
|
|
|
if (cfstr == NULL) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
// first figure out how many graphemes there are
|
|
|
|
g->len = 0;
|
|
|
|
ppos = 0;
|
|
|
|
while (ppos < len) {
|
|
|
|
range = CFStringGetRangeOfComposedCharactersAtIndex(cfstr, ppos);
|
|
|
|
g->len++;
|
|
|
|
ppos = range.location + range.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
g->pointsToGraphemes = (size_t *) uiAlloc((len + 1) * sizeof (size_t), "size_t[] (graphemes)");
|
|
|
|
g->graphemesToPoints = (size_t *) uiAlloc((g->len + 1) * sizeof (size_t), "size_t[] (graphemes)");
|
|
|
|
|
|
|
|
// now calculate everything
|
|
|
|
// fortunately due to the use of CFRange we can do this in one loop trivially!
|
|
|
|
ppos = 0;
|
|
|
|
gpos = 0;
|
|
|
|
while (ppos < len) {
|
|
|
|
range = CFStringGetRangeOfComposedCharactersAtIndex(cfstr, ppos);
|
|
|
|
for (i = 0; i < range.length; i++)
|
|
|
|
g->pointsToGraphemes[range.location + i] = gpos;
|
|
|
|
g->graphemesToPoints[gpos] = range.location;
|
|
|
|
gpos++;
|
|
|
|
ppos = range.location + range.length;
|
|
|
|
}
|
|
|
|
// and set the last one
|
|
|
|
g->pointsToGraphemes[ppos] = gpos;
|
|
|
|
g->graphemesToPoints[gpos] = ppos;
|
|
|
|
|
|
|
|
CFRelease(cfstr);
|
|
|
|
return g;
|
|
|
|
}
|