CTTypesetter 在奇怪的 Unicode 字符上崩溃
我正在使用 CTTypesetter 来布局从服务器的 JSON 读取的消息。然而,对于某些特定的消息,它会崩溃,即那些具有不常见 Unicode 字符的消息,如下所示。
CFAttributedStringRef attrString = CFAttributedStringCreate(NULL, @"❝We must learn to live together as brothers or perish together as fools❞ ~Martin Luther King Jr. #HappyMLKDay", nil);
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString(attrString);
这会因下面的堆栈跟踪而崩溃。
#0 0x33a4684e in TBaseFont::CopyCharacterSet() const ()
#1 0x33a2c0d4 in CompareCharSet(__CFCharacterSet const*, TBaseFont const*) ()
#2 0x33a2f03e in TDescriptorSource::CopyDescriptorsForRequestFromArray(__CFArray const*, __CFDictionary const*, long (*)(void const*, void const*, void*), void*, unsigned long, bool) const ()
#3 0x33a2ead0 in TDescriptorSource::CopyDescriptorsForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const ()
#4 0x33a2e624 in TDescriptorSource::CopyDescriptorForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const ()
#5 0x33a2e532 in TDescriptorSource::CopySystemWideFallbackDescriptor(CGFont*, unsigned short const*, long) const ()
#6 0x33a2e79c in TDescriptorSource::CopySystemWideFallbackDescriptor(CGFont*, __CFString const*, CFRange) const ()
#7 0x33a27c78 in TFontCascade::CreateSystemWideFallback(__CTFont const*, __CFString const*, CFRange) const ()
#8 0x33a27b28 in TFontCascade::CreateFallback(__CTFont const*, __CFString const*, CFRange) const ()
#9 0x33a185ec in TGlyphEncoder::AppendUnmappedCharRun(CTRun*, CFRange, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, bool) ()
#10 0x33a184b8 in TGlyphEncoder::RunUnicodeEncoderRecursively(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, bool) ()
#11 0x33a186e4 in TGlyphEncoder::AppendUnmappedCharRun(CTRun*, CFRange, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, bool) ()
#12 0x33a184b8 in TGlyphEncoder::RunUnicodeEncoderRecursively(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, bool) ()
#13 0x33a1824c in TGlyphEncoder::RunUnicodeEncoder(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*) ()
#14 0x33a07a1a in TGlyphEncoder::EncodeChars(CFRange, TAttributes const&, TGlyphList<TDeletedGlyphIndex>&, TGlyphEncoder::Fallbacks) ()
#15 0x33a0665c in TTypesetterAttrString::Initialize(__CFAttributedString const*) ()
#16 0x33a064a4 in TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) ()
#17 0x33a06418 in TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) ()
#18 0x33a1e78c in CTTypesetterCreateWithAttributedString ()
我创建了一个空项目来尝试重现崩溃,但是在这种环境中它工作正常。
该文档是这样说的:
多核注意事项:Core Text 中的所有单独函数都是 线程安全。字体对象(CTFont、CTFontDescriptor 和关联的 对象)可以同时被多个操作、工作使用 队列,或者线程。但是,布局对象(CTTypesetter、 CTFramesetter、CTRun、CTLine、CTFrame 和关联对象)应该 可在单个操作、工作队列或线程中使用。
为此,我删除了所有类型的线程,即一些 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ...)
,试图解决此问题。除了破坏>20 KSLOC 项目之外,我不知道还能尝试解决什么问题。
它只会使实际的 iPad 崩溃(所有 3 个型号均使用 5.0 和 5.1 进行测试),而不会使模拟器崩溃。
我可以尝试什么来解决这个问题?我打算嵌入 Helvetica 的修改版本,并尽可能多地合并后备字体,但这远非最佳解决方案。
任何意见都将非常感激,因为你可以看到,自一月份以来这一直让我发疯!
I'm using CTTypesetter to layout messages read in from JSON from a server. However, on certain particular messages it crashes, namely those with unusual Unicode characters like the one below.
CFAttributedStringRef attrString = CFAttributedStringCreate(NULL, @"❝We must learn to live together as brothers or perish together as fools❞ ~Martin Luther King Jr. #HappyMLKDay", nil);
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString(attrString);
That crashes with the below stack trace.
#0 0x33a4684e in TBaseFont::CopyCharacterSet() const ()
#1 0x33a2c0d4 in CompareCharSet(__CFCharacterSet const*, TBaseFont const*) ()
#2 0x33a2f03e in TDescriptorSource::CopyDescriptorsForRequestFromArray(__CFArray const*, __CFDictionary const*, long (*)(void const*, void const*, void*), void*, unsigned long, bool) const ()
#3 0x33a2ead0 in TDescriptorSource::CopyDescriptorsForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const ()
#4 0x33a2e624 in TDescriptorSource::CopyDescriptorForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const ()
#5 0x33a2e532 in TDescriptorSource::CopySystemWideFallbackDescriptor(CGFont*, unsigned short const*, long) const ()
#6 0x33a2e79c in TDescriptorSource::CopySystemWideFallbackDescriptor(CGFont*, __CFString const*, CFRange) const ()
#7 0x33a27c78 in TFontCascade::CreateSystemWideFallback(__CTFont const*, __CFString const*, CFRange) const ()
#8 0x33a27b28 in TFontCascade::CreateFallback(__CTFont const*, __CFString const*, CFRange) const ()
#9 0x33a185ec in TGlyphEncoder::AppendUnmappedCharRun(CTRun*, CFRange, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, bool) ()
#10 0x33a184b8 in TGlyphEncoder::RunUnicodeEncoderRecursively(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, bool) ()
#11 0x33a186e4 in TGlyphEncoder::AppendUnmappedCharRun(CTRun*, CFRange, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, bool) ()
#12 0x33a184b8 in TGlyphEncoder::RunUnicodeEncoderRecursively(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, bool) ()
#13 0x33a1824c in TGlyphEncoder::RunUnicodeEncoder(CTRun*, adopted_t const&, CFRange, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*) ()
#14 0x33a07a1a in TGlyphEncoder::EncodeChars(CFRange, TAttributes const&, TGlyphList<TDeletedGlyphIndex>&, TGlyphEncoder::Fallbacks) ()
#15 0x33a0665c in TTypesetterAttrString::Initialize(__CFAttributedString const*) ()
#16 0x33a064a4 in TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) ()
#17 0x33a06418 in TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) ()
#18 0x33a1e78c in CTTypesetterCreateWithAttributedString ()
I created an empty project to try and reproduce the crash, however in this environment it works fine.
The documentation has this to say:
Multicore Considerations: All individual functions in Core Text are
thread safe. Font objects (CTFont, CTFontDescriptor, and associated
objects) can be used by simultaneously by multiple operations, work
queues, or threads. However, the layout objects (CTTypesetter,
CTFramesetter, CTRun, CTLine, CTFrame, and associated objects) should
be used in a single operation, work queue, or thread.
To this end I've taken out all kind of threading, namely a few dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ...)
, in an attempt to resolve this. I don't know what else I can try to solve it besides gutting what is a >20 KSLOC project.
It only crashes the actual iPad (all 3 models tested with both 5.0 and 5.1), not the simulator.
What can I try to solve this? I'm about to resort to embedding modified versions of Helvetica with as many fallback fonts merged into them as possible, but that's a far from optimal solution.
Any input at all would be incredibly appreciated, as you can see this has been driving me insane since January!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我刚刚解决了。
我在 info.plist 中引用了 43 种字体。所有这些都是有效的,所有都是我的资源包中的 otf 或 ttf。我刚刚删除了一些,它就开始工作了。
该死的苹果bug。
I just solved it.
I was referencing 43 fonts in my info.plist. All were valid, all were otf's or ttf's in my resource bundle. I just removed a few and it started working.
Damn Apple bug.