12 #include "../../stdafx.h" 14 #include "../../string_func.h" 15 #include "../../strings_func.h" 16 #include "../../table/control_codes.h" 17 #include "../../fontcache.h" 20 #include <CoreFoundation/CoreFoundation.h> 23 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 39 CTTypesetterRef typesetter;
47 std::vector<GlyphID> glyphs;
48 std::vector<float> positions;
49 std::vector<int> glyph_to_char;
51 int total_advance = 0;
57 virtual const GlyphID *GetGlyphs()
const {
return &this->glyphs[0]; }
58 virtual const float *GetPositions()
const {
return &this->positions[0]; }
59 virtual const int *GetGlyphToCharMap()
const {
return &this->glyph_to_char[0]; }
61 virtual const Font *GetFont()
const {
return this->font; }
62 virtual int GetLeading()
const {
return this->font->fc->GetHeight(); }
63 virtual int GetGlyphCount()
const {
return (
int)this->glyphs.size(); }
64 int GetAdvance()
const {
return this->total_advance; }
72 CFArrayRef runs = CTLineGetGlyphRuns(line);
73 for (CFIndex i = 0; i < CFArrayGetCount(runs); i++) {
74 CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, i);
77 CFRange chars = CTRunGetStringRange(run);
79 while (map < fontMapping.
End() - 1 && map->first <= chars.location) map++;
86 virtual int GetLeading()
const;
87 virtual int GetWidth()
const;
88 virtual int CountRuns()
const {
return this->Length(); }
89 virtual const VisualRun *GetVisualRun(
int run)
const {
return *this->Get(run); }
91 int GetInternalCharLength(
WChar c)
const 94 return c >= 0x010000U ? 2 : 1;
105 CFRelease(this->typesetter);
108 virtual void Reflow()
110 this->cur_offset = 0;
113 virtual const Line *NextLine(
int max_width);
121 WChar c = (
WChar)((
size_t)ref_con & 0xFFFFFF);
126 static CTRunDelegateCallbacks _sprite_font_callback = {
127 kCTRunDelegateCurrentVersion, NULL, NULL, NULL,
136 ptrdiff_t length = buff_end - buff;
137 if (length == 0)
return NULL;
141 if (i->second->fc->IsBuiltInFont())
return NULL;
145 CFMutableAttributedStringRef str = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
146 CFAttributedStringBeginEditing(str);
148 CFStringRef base = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buff, length, kCFAllocatorNull);
149 CFAttributedStringReplaceString(str, CFRangeMake(0, 0), base);
156 if (i->first - last == 0)
continue;
158 if (
_font_cache[i->second->fc->GetSize()] == NULL) {
160 CFStringRef font_name = CFStringCreateWithCString(kCFAllocatorDefault, i->second->fc->GetFontName(), kCFStringEncodingUTF8);
161 _font_cache[i->second->fc->GetSize()] = CTFontCreateWithName(font_name, i->second->fc->GetFontSize(), NULL);
162 CFRelease(font_name);
164 CFAttributedStringSetAttribute(str, CFRangeMake(last, i->first - last), kCTFontAttributeName,
_font_cache[i->second->fc->GetSize()]);
166 CGColorRef color = CGColorCreateGenericGray((uint8)i->second->colour / 255.0f, 1.0f);
167 CFAttributedStringSetAttribute(str, CFRangeMake(last, i->first - last), kCTForegroundColorAttributeName, color);
168 CGColorRelease(color);
171 for (ssize_t c = last; c < i->first; c++) {
172 if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) {
173 CTRunDelegateRef del = CTRunDelegateCreate(&_sprite_font_callback, (
void *)(
size_t)(buff[c] | (i->second->fc->GetSize() << 24)));
174 CFAttributedStringSetAttribute(str, CFRangeMake(c, 1), kCTRunDelegateAttributeName, del);
181 CFAttributedStringEndEditing(str);
184 CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString(str);
192 if (this->
cur_offset >= this->length)
return NULL;
195 CFIndex len = CTTypesetterSuggestLineBreak(this->typesetter, this->
cur_offset, max_width);
196 if (len <= 0) len = CTTypesetterSuggestClusterBreak(this->typesetter, this->
cur_offset, max_width);
199 CTLineRef line = CTTypesetterCreateLine(this->typesetter, CFRangeMake(this->
cur_offset, len));
202 return line != NULL ?
new CoreTextLine(line, this->font_map, this->text_buffer) : NULL;
207 this->glyphs.resize(CTRunGetGlyphCount(run));
210 CFIndex map[this->glyphs.size()];
211 CTRunGetStringIndices(run, CFRangeMake(0, 0), map);
213 this->glyph_to_char.resize(this->glyphs.size());
214 for (
size_t i = 0; i < this->glyph_to_char.size(); i++) this->glyph_to_char[i] = (
int)map[i];
216 CGPoint pts[this->glyphs.size()];
217 CTRunGetPositions(run, CFRangeMake(0, 0), pts);
218 this->positions.resize(this->glyphs.size() * 2 + 2);
222 CGGlyph gl[this->glyphs.size()];
223 CTRunGetGlyphs(run, CFRangeMake(0, 0), gl);
224 for (
size_t i = 0; i < this->glyphs.size(); i++) {
225 if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END) {
226 this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]);
227 this->positions[i * 2 + 0] = pts[i].x;
228 this->positions[i * 2 + 1] = font->fc->GetAscender() - font->fc->GetGlyph(this->glyphs[i])->height - 1;
230 this->glyphs[i] = gl[i];
231 this->positions[i * 2 + 0] = pts[i].x;
232 this->positions[i * 2 + 1] = pts[i].y;
235 this->total_advance = (int)CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL);
236 this->positions[this->glyphs.size() * 2] = this->positions[0] + this->total_advance;
246 for (
const CoreTextVisualRun *
const *run = this->Begin(); run != this->End(); run++) {
247 leading =
max(leading, (*run)->GetLeading());
259 if (this->Length() == 0)
return 0;
262 for (
const CoreTextVisualRun *
const *run = this->Begin(); run != this->End(); run++) {
263 total_width += (*run)->GetAdvance();
286 CFStringRef iso = CFStringCreateWithCString(kCFAllocatorNull, iso_code, kCFStringEncodingUTF8);
287 _osx_locale = CFLocaleCreate(kCFAllocatorDefault, iso);
301 if (!supported)
return 0;
303 CFStringCompareFlags flags = kCFCompareCaseInsensitive | kCFCompareNumerically | kCFCompareLocalized | kCFCompareWidthInsensitive | kCFCompareForcedOrdering;
305 CFStringRef cf1 = CFStringCreateWithCString(kCFAllocatorDefault, s1, kCFStringEncodingUTF8);
306 CFStringRef cf2 = CFStringCreateWithCString(kCFAllocatorDefault, s2, kCFStringEncodingUTF8);
309 if (cf1 ==
nullptr || cf2 ==
nullptr) {
310 if (cf1 !=
nullptr) CFRelease(cf1);
311 if (cf2 !=
nullptr) CFRelease(cf2);
315 CFComparisonResult res = CFStringCompareWithOptionsAndLocale(cf1, cf2, CFRangeMake(0, CFStringGetLength(cf1)), flags,
_osx_locale);
326 const char *string_base = s;
328 this->utf16_to_utf8.clear();
329 this->str_info.clear();
334 std::vector<UniChar> utf16_str;
336 size_t idx = s - string_base;
338 WChar c = Utf8Consume(&s);
340 utf16_str.push_back((UniChar)c);
343 utf16_str.push_back((UniChar)(0xD800 + ((c - 0x10000) >> 10)));
344 utf16_str.push_back((UniChar)(0xDC00 + ((c - 0x10000) & 0x3FF)));
345 this->utf16_to_utf8.push_back(idx);
347 this->utf16_to_utf8.push_back(idx);
349 this->utf16_to_utf8.push_back(s - string_base);
352 this->str_info.resize(utf16_to_utf8.size());
354 if (utf16_str.size() > 0) {
355 CFStringRef str = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &utf16_str[0], utf16_str.size(), kCFAllocatorNull);
358 for (CFIndex i = 0; i < CFStringGetLength(str); ) {
359 CFRange r = CFStringGetRangeOfComposedCharactersAtIndex(str, i);
360 this->str_info[r.location].char_stop =
true;
366 CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, str, CFRangeMake(0, CFStringGetLength(str)), kCFStringTokenizerUnitWordBoundary,
_osx_locale);
368 CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone;
369 while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) != kCFStringTokenizerTokenNone) {
371 if ((tokenType & kCFStringTokenizerTokenHasNonLettersMask) != kCFStringTokenizerTokenHasNonLettersMask) {
372 CFRange r = CFStringTokenizerGetCurrentTokenRange(tokenizer);
373 this->str_info[r.location].word_stop =
true;
377 CFRelease(tokenizer);
382 this->str_info.back().char_stop =
true;
383 this->str_info.back().word_stop =
true;
389 size_t utf16_pos = 0;
390 for (
size_t i = 0; i < this->utf16_to_utf8.size(); i++) {
391 if (this->utf16_to_utf8[i] == pos) {
398 while (utf16_pos > 0 && !this->str_info[utf16_pos].char_stop) utf16_pos--;
399 this->cur_pos = utf16_pos;
401 return this->utf16_to_utf8[this->cur_pos];
406 assert(this->cur_pos <= this->utf16_to_utf8.size());
409 if (this->cur_pos == this->utf16_to_utf8.size())
return END;
413 }
while (this->cur_pos < this->utf16_to_utf8.size() && (what == ITER_WORD ? !this->str_info[this->cur_pos].word_stop : !this->str_info[this->cur_pos].char_stop));
415 return this->cur_pos == this->utf16_to_utf8.size() ? END : this->utf16_to_utf8[this->cur_pos];
420 assert(this->cur_pos <= this->utf16_to_utf8.size());
423 if (this->cur_pos == 0)
return END;
427 }
while (this->cur_pos > 0 && (what == ITER_WORD ? !this->str_info[this->cur_pos].word_stop : !this->str_info[this->cur_pos].char_stop));
429 return this->utf16_to_utf8[this->cur_pos];
Wrapper for doing layouts with CoreText.
int MacOSStringCompare(const char *s1, const char *s2)
Compares two strings using case insensitive natural sort.
Implementation of simple mapping class.
String iterator using CoreText as a backend.
static bool MacOSVersionIsAtLeast(long major, long minor, long bugfix)
Check if we are at least running on the specified version of Mac OS.
const T * Begin() const
Get the pointer to the first item (const)
Visual run contains data about the bit of text with the same font.
void MacOSResetScriptCache(FontSize size)
Delete CoreText font reference for a specific font size.
static T max(const T a, const T b)
Returns the maximum of two values.
const T * End() const
Get the pointer behind the last valid item (const)
static uint GetGlyphWidth(FontSize size, WChar key)
Get the width of a glyph.
virtual int GetLeading() const
Get the height of the line.
Iterate over characters (or more exactly grapheme clusters).
Visual run contains data about the bit of text with the same font.
A single line worth of VisualRuns.
virtual void SetString(const char *s)
Set a new iteration string.
static CTFontRef _font_cache[FS_END]
CoreText cache for font information, cleared when OTTD changes fonts.
A single line worth of VisualRuns.
Interface to glue fallback and normal layouter into one.
Simple vector template class, with automatic delete.
CFIndex cur_offset
Offset from the start of the current run from where to output.
IterType
Type of the iterator.
Functions related to localized text support on OSX.
virtual size_t Next(IterType what)
Advance the cursor by one iteration unit.
static CFLocaleRef _osx_locale
Cached current locale.
virtual int GetWidth() const
Get the width of this line.
FontSize
Available font sizes.
Functions related to MacOS support.
virtual size_t SetCurPosition(size_t pos)
Change the current string cursor.
Class for iterating over different kind of parts of a string.
static ParagraphLayouter * GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping)
Get the actual ParagraphLayout for the given buffer.
UniChar CharType
Helper for GetLayouter, to get the right type.
static CGFloat SpriteFontGetWidth(void *ref_con)
Get the width of an encoded sprite font character.
uint32 GlyphID
Glyphs are characters from a font.
virtual size_t Prev(IterType what)
Move the cursor back by one iteration unit.
uint32 WChar
Type for wide characters, i.e.
void MacOSSetCurrentLocaleName(const char *iso_code)
Store current language locale as a CoreFounation locale.