10 #include "../../stdafx.h" 12 #include "../../string_func.h" 13 #include "../../strings_func.h" 14 #include "../../table/control_codes.h" 15 #include "../../fontcache.h" 18 #include <CoreFoundation/CoreFoundation.h> 21 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 45 std::vector<GlyphID> glyphs;
46 std::vector<float> positions;
47 std::vector<int> glyph_to_char;
49 int total_advance = 0;
56 const GlyphID *GetGlyphs()
const override {
return &this->glyphs[0]; }
57 const float *GetPositions()
const override {
return &this->positions[0]; }
58 const int *GetGlyphToCharMap()
const override {
return &this->glyph_to_char[0]; }
60 const Font *GetFont()
const override {
return this->font; }
61 int GetLeading()
const override {
return this->font->fc->GetHeight(); }
62 int GetGlyphCount()
const override {
return (
int)this->glyphs.size(); }
63 int GetAdvance()
const {
return this->total_advance; }
71 CFArrayRef runs = CTLineGetGlyphRuns(line.get());
72 for (CFIndex i = 0; i < CFArrayGetCount(runs); i++) {
73 CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, i);
76 CFRange chars = CTRunGetStringRange(run);
77 auto map = fontMapping.begin();
78 while (map < fontMapping.end() - 1 && map->first <= chars.location) map++;
80 this->emplace_back(run, map->second, buff);
84 int GetLeading()
const override;
85 int GetWidth()
const override;
86 int CountRuns()
const override {
return this->size(); }
87 const VisualRun &GetVisualRun(
int run)
const override {
return this->at(run); }
89 int GetInternalCharLength(
WChar c)
const override 92 return c >= 0x010000U ? 2 : 1;
101 void Reflow()
override 103 this->cur_offset = 0;
106 std::unique_ptr<const Line> NextLine(
int max_width)
override;
114 WChar c = (
WChar)((
size_t)ref_con & 0xFFFFFF);
119 static CTRunDelegateCallbacks _sprite_font_callback = {
120 kCTRunDelegateCurrentVersion,
nullptr,
nullptr,
nullptr,
129 ptrdiff_t length = buff_end - buff;
130 if (length == 0)
return nullptr;
133 for (
const auto &i : fontMapping) {
134 if (i.second->fc->IsBuiltInFont())
return nullptr;
139 CFAttributedStringBeginEditing(str.get());
142 CFAttributedStringReplaceString(str.get(), CFRangeMake(0, 0), base.get());
147 for (
const auto &i : fontMapping) {
148 if (i.first - last == 0)
continue;
152 CFAutoRelease<CFStringRef> font_name(CFStringCreateWithCString(kCFAllocatorDefault, i.second->fc->GetFontName(), kCFStringEncodingUTF8));
153 _font_cache[i.second->fc->GetSize()].reset(CTFontCreateWithName(font_name.get(), i.second->fc->GetFontSize(),
nullptr));
155 CFAttributedStringSetAttribute(str.get(), CFRangeMake(last, i.first - last), kCTFontAttributeName,
_font_cache[i.second->fc->GetSize()].get());
157 CGColorRef color = CGColorCreateGenericGray((uint8)i.second->colour / 255.0f, 1.0f);
158 CFAttributedStringSetAttribute(str.get(), CFRangeMake(last, i.first - last), kCTForegroundColorAttributeName, color);
159 CGColorRelease(color);
162 for (ssize_t c = last; c < i.first; c++) {
163 if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) {
165 CFAttributedStringSetAttribute(str.get(), CFRangeMake(c, 1), kCTRunDelegateAttributeName, del.get());
171 CFAttributedStringEndEditing(str.get());
179 std::unique_ptr<const ParagraphLayouter::Line> CoreTextParagraphLayout::NextLine(
int max_width)
181 if (this->
cur_offset >= this->length)
return nullptr;
184 CFIndex len = CTTypesetterSuggestLineBreak(this->typesetter.get(), this->
cur_offset, max_width);
185 if (len <= 0) len = CTTypesetterSuggestClusterBreak(this->typesetter.get(), this->
cur_offset, max_width);
191 return std::unique_ptr<const Line>(line ?
new CoreTextLine(std::move(line), this->font_map, this->text_buffer) :
nullptr);
196 this->glyphs.resize(CTRunGetGlyphCount(run));
199 CFIndex map[this->glyphs.size()];
200 CTRunGetStringIndices(run, CFRangeMake(0, 0), map);
202 this->glyph_to_char.resize(this->glyphs.size());
203 for (
size_t i = 0; i < this->glyph_to_char.size(); i++) this->glyph_to_char[i] = (
int)map[i];
205 CGPoint pts[this->glyphs.size()];
206 CTRunGetPositions(run, CFRangeMake(0, 0), pts);
207 this->positions.resize(this->glyphs.size() * 2 + 2);
211 CGGlyph gl[this->glyphs.size()];
212 CTRunGetGlyphs(run, CFRangeMake(0, 0), gl);
213 for (
size_t i = 0; i < this->glyphs.size(); i++) {
214 if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END) {
215 this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]);
216 this->positions[i * 2 + 0] = pts[i].x;
217 this->positions[i * 2 + 1] = font->fc->GetAscender() - font->fc->GetGlyph(this->glyphs[i])->height - 1;
219 this->glyphs[i] = gl[i];
220 this->positions[i * 2 + 0] = pts[i].x;
221 this->positions[i * 2 + 1] = pts[i].y;
224 this->total_advance = (int)CTRunGetTypographicBounds(run, CFRangeMake(0, 0),
nullptr,
nullptr,
nullptr);
225 this->positions[this->glyphs.size() * 2] = this->positions[0] + this->total_advance;
235 for (
const auto &run : *
this) {
236 leading =
max(leading, run.GetLeading());
248 if (this->size() == 0)
return 0;
251 for (
const auto &run : *
this) {
252 total_width += run.GetAdvance();
271 _osx_locale.reset(CFLocaleCreate(kCFAllocatorDefault, iso.get()));
284 if (!supported)
return 0;
286 CFStringCompareFlags flags = kCFCompareCaseInsensitive | kCFCompareNumerically | kCFCompareLocalized | kCFCompareWidthInsensitive | kCFCompareForcedOrdering;
292 if (cf1 ==
nullptr || cf2 ==
nullptr)
return 0;
294 return (
int)CFStringCompareWithOptionsAndLocale(cf1.get(), cf2.get(), CFRangeMake(0, CFStringGetLength(cf1.get())), flags,
_osx_locale.get()) + 2;
300 const char *string_base = s;
302 this->utf16_to_utf8.clear();
303 this->str_info.clear();
308 std::vector<UniChar> utf16_str;
310 size_t idx = s - string_base;
312 WChar c = Utf8Consume(&s);
314 utf16_str.push_back((UniChar)c);
317 utf16_str.push_back((UniChar)(0xD800 + ((c - 0x10000) >> 10)));
318 utf16_str.push_back((UniChar)(0xDC00 + ((c - 0x10000) & 0x3FF)));
319 this->utf16_to_utf8.push_back(idx);
321 this->utf16_to_utf8.push_back(idx);
323 this->utf16_to_utf8.push_back(s - string_base);
326 this->str_info.resize(utf16_to_utf8.size());
328 if (utf16_str.size() > 0) {
329 CFAutoRelease<CFStringRef> str(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &utf16_str[0], utf16_str.size(), kCFAllocatorNull));
332 for (CFIndex i = 0; i < CFStringGetLength(str.get()); ) {
333 CFRange r = CFStringGetRangeOfComposedCharactersAtIndex(str.get(), i);
334 this->str_info[r.location].char_stop =
true;
342 CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone;
343 while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer.get())) != kCFStringTokenizerTokenNone) {
345 if ((tokenType & kCFStringTokenizerTokenHasNonLettersMask) != kCFStringTokenizerTokenHasNonLettersMask) {
346 CFRange r = CFStringTokenizerGetCurrentTokenRange(tokenizer.get());
347 this->str_info[r.location].word_stop =
true;
353 this->str_info.back().char_stop =
true;
354 this->str_info.back().word_stop =
true;
360 size_t utf16_pos = 0;
361 for (
size_t i = 0; i < this->utf16_to_utf8.size(); i++) {
362 if (this->utf16_to_utf8[i] == pos) {
369 while (utf16_pos > 0 && !this->str_info[utf16_pos].char_stop) utf16_pos--;
370 this->cur_pos = utf16_pos;
372 return this->utf16_to_utf8[this->cur_pos];
377 assert(this->cur_pos <= this->utf16_to_utf8.size());
380 if (this->cur_pos == this->utf16_to_utf8.size())
return END;
384 }
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));
386 return this->cur_pos == this->utf16_to_utf8.size() ? END : this->utf16_to_utf8[this->cur_pos];
391 assert(this->cur_pos <= this->utf16_to_utf8.size());
394 if (this->cur_pos == 0)
return END;
398 }
while (this->cur_pos > 0 && (what == ITER_WORD ? !this->str_info[this->cur_pos].word_stop : !this->str_info[this->cur_pos].char_stop));
400 return this->utf16_to_utf8[this->cur_pos];
void SetString(const char *s) override
Set a new iteration string.
Wrapper for doing layouts with CoreText.
int GetLeading() const override
Get the height of the line.
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.
static CFAutoRelease< CTFontRef > _font_cache[FS_END]
CoreText cache for font information, cleared when OTTD changes fonts.
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.
static uint GetGlyphWidth(FontSize size, WChar key)
Get the width of a glyph.
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.
static CFAutoRelease< CFLocaleRef > _osx_locale
Cached current locale.
A single line worth of VisualRuns.
Interface to glue fallback and normal layouter into one.
size_t Prev(IterType what) override
Move the cursor back by one iteration unit.
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.
size_t Next(IterType what) override
Advance the cursor by one iteration unit.
std::unique_ptr< typename std::remove_pointer< T >::type, CFDeleter< typename std::remove_pointer< T >::type > > CFAutoRelease
Specialisation of std::unique_ptr for CoreFoundation objects.
FontSize
Available font sizes.
Functions related to MacOS support.
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.
int GetWidth() const override
Get the width of this line.
static CGFloat SpriteFontGetWidth(void *ref_con)
Get the width of an encoded sprite font character.
uint32 GlyphID
Glyphs are characters from a font.
size_t SetCurPosition(size_t pos) override
Change the current string cursor.
uint32 WChar
Type for wide characters, i.e.
void MacOSSetCurrentLocaleName(const char *iso_code)
Store current language locale as a CoreFounation locale.